From a16e00b166b407afaeb692fbef69494b8555d102 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 31 Jan 2022 10:28:37 -0800 Subject: [PATCH 1/3] Compute write type from set accessors for union and intersection properties --- src/compiler/checker.ts | 49 +++++- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 4 + .../reference/divergentAccessorsTypes3.js | 108 ++++++++++++++ .../divergentAccessorsTypes3.symbols | 116 ++++++++++++++ .../reference/divergentAccessorsTypes3.types | 141 ++++++++++++++++++ .../divergentAccessorsTypes4.errors.txt | 36 +++++ .../reference/divergentAccessorsTypes4.js | 71 +++++++++ .../divergentAccessorsTypes4.symbols | 73 +++++++++ .../reference/divergentAccessorsTypes4.types | 82 ++++++++++ .../compiler/divergentAccessorsTypes3.ts | 44 ++++++ .../compiler/divergentAccessorsTypes4.ts | 31 ++++ 12 files changed, 755 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/divergentAccessorsTypes3.js create mode 100644 tests/baselines/reference/divergentAccessorsTypes3.symbols create mode 100644 tests/baselines/reference/divergentAccessorsTypes3.types create mode 100644 tests/baselines/reference/divergentAccessorsTypes4.errors.txt create mode 100644 tests/baselines/reference/divergentAccessorsTypes4.js create mode 100644 tests/baselines/reference/divergentAccessorsTypes4.symbols create mode 100644 tests/baselines/reference/divergentAccessorsTypes4.types create mode 100644 tests/cases/compiler/divergentAccessorsTypes3.ts create mode 100644 tests/cases/compiler/divergentAccessorsTypes4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 11ed55a2c79d2..52ffeebce773e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9702,6 +9702,41 @@ namespace ts { return links.type; } + function getWriteTypeOfSymbolWithDeferredType(symbol: Symbol): Type | undefined { + const links = getSymbolLinks(symbol); + if (!links.writeType && links.deferralWriteConstituents) { + Debug.assertIsDefined(links.deferralParent); + Debug.assertIsDefined(links.deferralConstituents); + links.writeType = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); + } + return links.writeType; + } + + /** + * Distinct write types come only from set accessors, but union and intersection + * properties deriving from set accessors will either pre-compute or defer the + * union or intersection of the writeTypes of their constituents. To account for + * this, we will assume that any deferred type or transient symbol may have a + * `writeType` (or a deferred write type ready to be computed) that should be + * used before looking for set accessor declarations. + */ + function getWriteTypeOfSymbol(symbol: Symbol): Type { + const checkFlags = getCheckFlags(symbol); + if (checkFlags & CheckFlags.DeferredType) { + const writeType = getWriteTypeOfSymbolWithDeferredType(symbol); + if (writeType) { + return writeType; + } + } + if (symbol.flags & SymbolFlags.Transient) { + const { writeType } = symbol as TransientSymbol; + if (writeType) { + return writeType; + } + } + return getSetAccessorTypeOfSymbol(symbol); + } + function getSetAccessorTypeOfSymbol(symbol: Symbol): Type { if (symbol.flags & SymbolFlags.Accessor) { const type = getTypeOfSetAccessor(symbol); @@ -12111,6 +12146,7 @@ namespace ts { let optionalFlag = isUnion ? SymbolFlags.None : SymbolFlags.Optional; let syntheticFlag = CheckFlags.SyntheticMethod; let checkFlags = isUnion ? 0 : CheckFlags.Readonly; + let containsSetAccessor = false; let mergedInstantiations = false; for (const current of containingType.types) { const type = getApparentType(current); @@ -12149,6 +12185,9 @@ namespace ts { } } } + if (prop.flags & SymbolFlags.SetAccessor) { + containsSetAccessor = true; + } if (isUnion && isReadonlySymbol(prop)) { checkFlags |= CheckFlags.Readonly; } @@ -12204,6 +12243,7 @@ namespace ts { let firstType: Type | undefined; let nameType: Type | undefined; const propTypes: Type[] = []; + let writeTypes: Type[] | undefined; let firstValueDeclaration: Declaration | undefined; let hasNonUniformValueDeclaration = false; for (const prop of props) { @@ -12219,6 +12259,9 @@ namespace ts { firstType = type; nameType = getSymbolLinks(prop).nameType; } + if (containsSetAccessor) { + writeTypes = append(writeTypes, getSetAccessorTypeOfSymbol(prop)); + } else if (type !== firstType) { checkFlags |= CheckFlags.HasNonUniformType; } @@ -12249,9 +12292,13 @@ namespace ts { result.checkFlags |= CheckFlags.DeferredType; result.deferralParent = containingType; result.deferralConstituents = propTypes; + result.deferralWriteConstituents = writeTypes; } else { result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes); + if (writeTypes) { + result.writeType = isUnion ? getUnionType(writeTypes) : getIntersectionType(writeTypes); + } } return result; } @@ -28530,7 +28577,7 @@ namespace ts { return errorType; } - propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writing ? getSetAccessorTypeOfSymbol(prop) : getTypeOfSymbol(prop); + propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writing ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); } return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8a67511208893..ab1f5d9d6600e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4952,6 +4952,7 @@ namespace ts { extendedContainersByFile?: ESMap; // Containers (other than the parent) which this symbol is aliased in variances?: VarianceFlags[]; // Alias symbol type argument variance cache deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type + deferralWriteConstituents?: Type[]; // Constituents of a deferred `writeType` deferralParent?: Type; // Source union/intersection of a deferred type cjsExportMerged?: Symbol; // Version of the symbol with all non export= exports merged with the export= target typeOnlyDeclaration?: TypeOnlyAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e20193dc59a4a..3b0a31356148d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -20,6 +20,10 @@ namespace ts { return undefined; } + export function getDeclarationsOfKind(symbol: Symbol, kind: T["kind"]): T[] { + return filter(symbol.declarations || emptyArray, d => d.kind === kind) as T[]; + } + export function createSymbolTable(symbols?: readonly Symbol[]): SymbolTable { const result = new Map<__String, Symbol>(); if (symbols) { diff --git a/tests/baselines/reference/divergentAccessorsTypes3.js b/tests/baselines/reference/divergentAccessorsTypes3.js new file mode 100644 index 0000000000000..775474f088f2e --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes3.js @@ -0,0 +1,108 @@ +//// [divergentAccessorsTypes3.ts] +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | number) { } + + prop3: number; + + get prop4(): string { return ""; } + set prop4(s: string | number) { } +} + +class Two { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + get prop2(): string { return ""; } + set prop2(s: string) { } + + get prop3(): string { return ""; } + set prop3(s: string | boolean) { } + + get prop4(): string { return ""; } + set prop4(s: string | boolean) { } +} + +declare const u1: One|Two; + +u1.prop1 = 42; +u1.prop1 = "hello"; + +u1.prop2 = 42; +u1.prop2 = "hello"; + +u1.prop3 = 42; +u1.prop3 = "hello"; +u1.prop3 = true; + +u1.prop4 = 42; +u1.prop4 = "hello"; +u1.prop4 = true; + + +//// [divergentAccessorsTypes3.js] +var One = /** @class */ (function () { + function One() { + } + Object.defineProperty(One.prototype, "prop1", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(One.prototype, "prop2", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(One.prototype, "prop4", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return One; +}()); +var Two = /** @class */ (function () { + function Two() { + } + Object.defineProperty(Two.prototype, "prop1", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Two.prototype, "prop2", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Two.prototype, "prop3", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Two.prototype, "prop4", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return Two; +}()); +u1.prop1 = 42; +u1.prop1 = "hello"; +u1.prop2 = 42; +u1.prop2 = "hello"; +u1.prop3 = 42; +u1.prop3 = "hello"; +u1.prop3 = true; +u1.prop4 = 42; +u1.prop4 = "hello"; +u1.prop4 = true; diff --git a/tests/baselines/reference/divergentAccessorsTypes3.symbols b/tests/baselines/reference/divergentAccessorsTypes3.symbols new file mode 100644 index 0000000000000..6b754eada400d --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes3.symbols @@ -0,0 +1,116 @@ +=== tests/cases/compiler/divergentAccessorsTypes3.ts === +class One { +>One : Symbol(One, Decl(divergentAccessorsTypes3.ts, 0, 0)) + + get prop1(): string { return ""; } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36)) + + set prop1(s: string | number) { } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 2, 12)) + + get prop2(): string { return ""; } +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36)) + + set prop2(s: string | number) { } +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 5, 12)) + + prop3: number; +>prop3 : Symbol(One.prop3, Decl(divergentAccessorsTypes3.ts, 5, 35)) + + get prop4(): string { return ""; } +>prop4 : Symbol(One.prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36)) + + set prop4(s: string | number) { } +>prop4 : Symbol(One.prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 10, 12)) +} + +class Two { +>Two : Symbol(Two, Decl(divergentAccessorsTypes3.ts, 11, 1)) + + get prop1(): string { return ""; } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) + + set prop1(s: string | number) { } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 15, 12)) + + get prop2(): string { return ""; } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) + + set prop2(s: string) { } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 18, 12)) + + get prop3(): string { return ""; } +>prop3 : Symbol(Two.prop3, Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) + + set prop3(s: string | boolean) { } +>prop3 : Symbol(Two.prop3, Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 21, 12)) + + get prop4(): string { return ""; } +>prop4 : Symbol(Two.prop4, Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) + + set prop4(s: string | boolean) { } +>prop4 : Symbol(Two.prop4, Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes3.ts, 24, 12)) +} + +declare const u1: One|Two; +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>One : Symbol(One, Decl(divergentAccessorsTypes3.ts, 0, 0)) +>Two : Symbol(Two, Decl(divergentAccessorsTypes3.ts, 11, 1)) + +u1.prop1 = 42; +>u1.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36), Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36), Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) + +u1.prop1 = "hello"; +>u1.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36), Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes3.ts, 0, 11), Decl(divergentAccessorsTypes3.ts, 1, 36), Decl(divergentAccessorsTypes3.ts, 13, 11), Decl(divergentAccessorsTypes3.ts, 14, 36)) + +u1.prop2 = 42; +>u1.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36), Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36), Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) + +u1.prop2 = "hello"; +>u1.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36), Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes3.ts, 2, 35), Decl(divergentAccessorsTypes3.ts, 4, 36), Decl(divergentAccessorsTypes3.ts, 15, 35), Decl(divergentAccessorsTypes3.ts, 17, 36)) + +u1.prop3 = 42; +>u1.prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) + +u1.prop3 = "hello"; +>u1.prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) + +u1.prop3 = true; +>u1.prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop3 : Symbol(prop3, Decl(divergentAccessorsTypes3.ts, 5, 35), Decl(divergentAccessorsTypes3.ts, 18, 26), Decl(divergentAccessorsTypes3.ts, 20, 36)) + +u1.prop4 = 42; +>u1.prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) + +u1.prop4 = "hello"; +>u1.prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) + +u1.prop4 = true; +>u1.prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) +>u1 : Symbol(u1, Decl(divergentAccessorsTypes3.ts, 27, 13)) +>prop4 : Symbol(prop4, Decl(divergentAccessorsTypes3.ts, 7, 16), Decl(divergentAccessorsTypes3.ts, 9, 36), Decl(divergentAccessorsTypes3.ts, 21, 36), Decl(divergentAccessorsTypes3.ts, 23, 36)) + diff --git a/tests/baselines/reference/divergentAccessorsTypes3.types b/tests/baselines/reference/divergentAccessorsTypes3.types new file mode 100644 index 0000000000000..3f59e2c146323 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes3.types @@ -0,0 +1,141 @@ +=== tests/cases/compiler/divergentAccessorsTypes3.ts === +class One { +>One : One + + get prop1(): string { return ""; } +>prop1 : string +>"" : "" + + set prop1(s: string | number) { } +>prop1 : string +>s : string | number + + get prop2(): string { return ""; } +>prop2 : string +>"" : "" + + set prop2(s: string | number) { } +>prop2 : string +>s : string | number + + prop3: number; +>prop3 : number + + get prop4(): string { return ""; } +>prop4 : string +>"" : "" + + set prop4(s: string | number) { } +>prop4 : string +>s : string | number +} + +class Two { +>Two : Two + + get prop1(): string { return ""; } +>prop1 : string +>"" : "" + + set prop1(s: string | number) { } +>prop1 : string +>s : string | number + + get prop2(): string { return ""; } +>prop2 : string +>"" : "" + + set prop2(s: string) { } +>prop2 : string +>s : string + + get prop3(): string { return ""; } +>prop3 : string +>"" : "" + + set prop3(s: string | boolean) { } +>prop3 : string +>s : string | boolean + + get prop4(): string { return ""; } +>prop4 : string +>"" : "" + + set prop4(s: string | boolean) { } +>prop4 : string +>s : string | boolean +} + +declare const u1: One|Two; +>u1 : One | Two + +u1.prop1 = 42; +>u1.prop1 = 42 : 42 +>u1.prop1 : string | number +>u1 : One | Two +>prop1 : string | number +>42 : 42 + +u1.prop1 = "hello"; +>u1.prop1 = "hello" : "hello" +>u1.prop1 : string | number +>u1 : One | Two +>prop1 : string | number +>"hello" : "hello" + +u1.prop2 = 42; +>u1.prop2 = 42 : 42 +>u1.prop2 : string | number +>u1 : One | Two +>prop2 : string | number +>42 : 42 + +u1.prop2 = "hello"; +>u1.prop2 = "hello" : "hello" +>u1.prop2 : string | number +>u1 : One | Two +>prop2 : string | number +>"hello" : "hello" + +u1.prop3 = 42; +>u1.prop3 = 42 : 42 +>u1.prop3 : string | number | boolean +>u1 : One | Two +>prop3 : string | number | boolean +>42 : 42 + +u1.prop3 = "hello"; +>u1.prop3 = "hello" : "hello" +>u1.prop3 : string | number | boolean +>u1 : One | Two +>prop3 : string | number | boolean +>"hello" : "hello" + +u1.prop3 = true; +>u1.prop3 = true : true +>u1.prop3 : string | number | boolean +>u1 : One | Two +>prop3 : string | number | boolean +>true : true + +u1.prop4 = 42; +>u1.prop4 = 42 : 42 +>u1.prop4 : string | number | boolean +>u1 : One | Two +>prop4 : string | number | boolean +>42 : 42 + +u1.prop4 = "hello"; +>u1.prop4 = "hello" : "hello" +>u1.prop4 : string | number | boolean +>u1 : One | Two +>prop4 : string | number | boolean +>"hello" : "hello" + +u1.prop4 = true; +>u1.prop4 = true : true +>u1.prop4 : string | number | boolean +>u1 : One | Two +>prop4 : string | number | boolean +>true : true + diff --git a/tests/baselines/reference/divergentAccessorsTypes4.errors.txt b/tests/baselines/reference/divergentAccessorsTypes4.errors.txt new file mode 100644 index 0000000000000..496e9e2f397de --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes4.errors.txt @@ -0,0 +1,36 @@ +tests/cases/compiler/divergentAccessorsTypes4.ts(29,1): error TS2322: Type '"hello"' is not assignable to type '42'. + + +==== tests/cases/compiler/divergentAccessorsTypes4.ts (1 errors) ==== + class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; + } + + class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + + } + + declare const i: One & Two; + + // "hello" + i.prop1; + // number | "hello" + i.prop1 = 42; + i.prop1 = "hello"; + + // never + i.prop2; + // 42 + i.prop2 = 42; + i.prop2 = "hello"; // error + ~~~~~~~ +!!! error TS2322: Type '"hello"' is not assignable to type '42'. + \ No newline at end of file diff --git a/tests/baselines/reference/divergentAccessorsTypes4.js b/tests/baselines/reference/divergentAccessorsTypes4.js new file mode 100644 index 0000000000000..74df41f5ef235 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes4.js @@ -0,0 +1,71 @@ +//// [divergentAccessorsTypes4.ts] +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; +} + +class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + +} + +declare const i: One & Two; + +// "hello" +i.prop1; +// number | "hello" +i.prop1 = 42; +i.prop1 = "hello"; + +// never +i.prop2; +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error + + +//// [divergentAccessorsTypes4.js] +var One = /** @class */ (function () { + function One() { + } + Object.defineProperty(One.prototype, "prop1", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return One; +}()); +var Two = /** @class */ (function () { + function Two() { + } + Object.defineProperty(Two.prototype, "prop1", { + get: function () { return "hello"; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Two.prototype, "prop2", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return Two; +}()); +// "hello" +i.prop1; +// number | "hello" +i.prop1 = 42; +i.prop1 = "hello"; +// never +i.prop2; +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error diff --git a/tests/baselines/reference/divergentAccessorsTypes4.symbols b/tests/baselines/reference/divergentAccessorsTypes4.symbols new file mode 100644 index 0000000000000..263274063ed22 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes4.symbols @@ -0,0 +1,73 @@ +=== tests/cases/compiler/divergentAccessorsTypes4.ts === +class One { +>One : Symbol(One, Decl(divergentAccessorsTypes4.ts, 0, 0)) + + get prop1(): string { return ""; } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36)) + + set prop1(s: string | number) { } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes4.ts, 2, 12)) + + prop2: number; +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes4.ts, 2, 35)) +} + +class Two { +>Two : Symbol(Two, Decl(divergentAccessorsTypes4.ts, 5, 1)) + + get prop1(): "hello" { return "hello"; } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) + + set prop1(s: "hello" | number) { } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) +>s : Symbol(s, Decl(divergentAccessorsTypes4.ts, 9, 12)) + + get prop2(): string { return ""; } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) + + set prop2(s: string | 42) { } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes4.ts, 12, 12)) + +} + +declare const i: One & Two; +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>One : Symbol(One, Decl(divergentAccessorsTypes4.ts, 0, 0)) +>Two : Symbol(Two, Decl(divergentAccessorsTypes4.ts, 5, 1)) + +// "hello" +i.prop1; +>i.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) + +// number | "hello" +i.prop1 = 42; +>i.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) + +i.prop1 = "hello"; +>i.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes4.ts, 0, 11), Decl(divergentAccessorsTypes4.ts, 1, 36), Decl(divergentAccessorsTypes4.ts, 7, 11), Decl(divergentAccessorsTypes4.ts, 8, 42)) + +// never +i.prop2; +>i.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) + +// 42 +i.prop2 = 42; +>i.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) + +i.prop2 = "hello"; // error +>i.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) +>i : Symbol(i, Decl(divergentAccessorsTypes4.ts, 16, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes4.ts, 2, 35), Decl(divergentAccessorsTypes4.ts, 9, 36), Decl(divergentAccessorsTypes4.ts, 11, 36)) + diff --git a/tests/baselines/reference/divergentAccessorsTypes4.types b/tests/baselines/reference/divergentAccessorsTypes4.types new file mode 100644 index 0000000000000..eb3784b451dac --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes4.types @@ -0,0 +1,82 @@ +=== tests/cases/compiler/divergentAccessorsTypes4.ts === +class One { +>One : One + + get prop1(): string { return ""; } +>prop1 : string +>"" : "" + + set prop1(s: string | number) { } +>prop1 : string +>s : string | number + + prop2: number; +>prop2 : number +} + +class Two { +>Two : Two + + get prop1(): "hello" { return "hello"; } +>prop1 : "hello" +>"hello" : "hello" + + set prop1(s: "hello" | number) { } +>prop1 : "hello" +>s : number | "hello" + + get prop2(): string { return ""; } +>prop2 : string +>"" : "" + + set prop2(s: string | 42) { } +>prop2 : string +>s : string | 42 + +} + +declare const i: One & Two; +>i : One & Two + +// "hello" +i.prop1; +>i.prop1 : "hello" +>i : One & Two +>prop1 : "hello" + +// number | "hello" +i.prop1 = 42; +>i.prop1 = 42 : 42 +>i.prop1 : number | "hello" +>i : One & Two +>prop1 : number | "hello" +>42 : 42 + +i.prop1 = "hello"; +>i.prop1 = "hello" : "hello" +>i.prop1 : number | "hello" +>i : One & Two +>prop1 : number | "hello" +>"hello" : "hello" + +// never +i.prop2; +>i.prop2 : never +>i : One & Two +>prop2 : never + +// 42 +i.prop2 = 42; +>i.prop2 = 42 : 42 +>i.prop2 : 42 +>i : One & Two +>prop2 : 42 +>42 : 42 + +i.prop2 = "hello"; // error +>i.prop2 = "hello" : "hello" +>i.prop2 : 42 +>i : One & Two +>prop2 : 42 +>"hello" : "hello" + diff --git a/tests/cases/compiler/divergentAccessorsTypes3.ts b/tests/cases/compiler/divergentAccessorsTypes3.ts new file mode 100644 index 0000000000000..557c73153ce90 --- /dev/null +++ b/tests/cases/compiler/divergentAccessorsTypes3.ts @@ -0,0 +1,44 @@ +// @target: es5 + +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | number) { } + + prop3: number; + + get prop4(): string { return ""; } + set prop4(s: string | number) { } +} + +class Two { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + get prop2(): string { return ""; } + set prop2(s: string) { } + + get prop3(): string { return ""; } + set prop3(s: string | boolean) { } + + get prop4(): string { return ""; } + set prop4(s: string | boolean) { } +} + +declare const u1: One|Two; + +u1.prop1 = 42; +u1.prop1 = "hello"; + +u1.prop2 = 42; +u1.prop2 = "hello"; + +u1.prop3 = 42; +u1.prop3 = "hello"; +u1.prop3 = true; + +u1.prop4 = 42; +u1.prop4 = "hello"; +u1.prop4 = true; diff --git a/tests/cases/compiler/divergentAccessorsTypes4.ts b/tests/cases/compiler/divergentAccessorsTypes4.ts new file mode 100644 index 0000000000000..802a1b4d2c63c --- /dev/null +++ b/tests/cases/compiler/divergentAccessorsTypes4.ts @@ -0,0 +1,31 @@ +// @target: es5 + +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; +} + +class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + +} + +declare const i: One & Two; + +// "hello" +i.prop1; +// number | "hello" +i.prop1 = 42; +i.prop1 = "hello"; + +// never +i.prop2; +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error From 91997ff28ba0b8beead6e61a294381e78aa820ba Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 31 Jan 2022 10:34:52 -0800 Subject: [PATCH 2/3] Add test for deferred writeType --- .../divergentAccessorsTypes5.errors.txt | 46 +++++++++ .../reference/divergentAccessorsTypes5.js | 93 +++++++++++++++++++ .../divergentAccessorsTypes5.symbols | 83 +++++++++++++++++ .../reference/divergentAccessorsTypes5.types | 93 +++++++++++++++++++ .../compiler/divergentAccessorsTypes5.ts | 38 ++++++++ 5 files changed, 353 insertions(+) create mode 100644 tests/baselines/reference/divergentAccessorsTypes5.errors.txt create mode 100644 tests/baselines/reference/divergentAccessorsTypes5.js create mode 100644 tests/baselines/reference/divergentAccessorsTypes5.symbols create mode 100644 tests/baselines/reference/divergentAccessorsTypes5.types create mode 100644 tests/cases/compiler/divergentAccessorsTypes5.ts diff --git a/tests/baselines/reference/divergentAccessorsTypes5.errors.txt b/tests/baselines/reference/divergentAccessorsTypes5.errors.txt new file mode 100644 index 0000000000000..5f163a9b62ef1 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes5.errors.txt @@ -0,0 +1,46 @@ +tests/cases/compiler/divergentAccessorsTypes5.ts(31,1): error TS2322: Type '42' is not assignable to type '"hello"'. +tests/cases/compiler/divergentAccessorsTypes5.ts(36,1): error TS2322: Type '"hello"' is not assignable to type '42'. + + +==== tests/cases/compiler/divergentAccessorsTypes5.ts (2 errors) ==== + // Not really different from divergentAccessorsTypes4.ts, + // but goes through the deferred type code + + class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; + } + + class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + + } + + class Three { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | boolean) { } + + get prop2(): string { return ""; } + set prop2(s: string | number | boolean) { } + } + + declare const i: One & Two & Three; + + // "hello" + i.prop1 = 42; // error + ~~~~~~~ +!!! error TS2322: Type '42' is not assignable to type '"hello"'. + i.prop1 = "hello"; + + // 42 + i.prop2 = 42; + i.prop2 = "hello"; // error + ~~~~~~~ +!!! error TS2322: Type '"hello"' is not assignable to type '42'. + \ No newline at end of file diff --git a/tests/baselines/reference/divergentAccessorsTypes5.js b/tests/baselines/reference/divergentAccessorsTypes5.js new file mode 100644 index 0000000000000..773289d1ddb06 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes5.js @@ -0,0 +1,93 @@ +//// [divergentAccessorsTypes5.ts] +// Not really different from divergentAccessorsTypes4.ts, +// but goes through the deferred type code + +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; +} + +class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + +} + +class Three { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | boolean) { } + + get prop2(): string { return ""; } + set prop2(s: string | number | boolean) { } +} + +declare const i: One & Two & Three; + +// "hello" +i.prop1 = 42; // error +i.prop1 = "hello"; + +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error + + +//// [divergentAccessorsTypes5.js] +// Not really different from divergentAccessorsTypes4.ts, +// but goes through the deferred type code +var One = /** @class */ (function () { + function One() { + } + Object.defineProperty(One.prototype, "prop1", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return One; +}()); +var Two = /** @class */ (function () { + function Two() { + } + Object.defineProperty(Two.prototype, "prop1", { + get: function () { return "hello"; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Two.prototype, "prop2", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return Two; +}()); +var Three = /** @class */ (function () { + function Three() { + } + Object.defineProperty(Three.prototype, "prop1", { + get: function () { return "hello"; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Three.prototype, "prop2", { + get: function () { return ""; }, + set: function (s) { }, + enumerable: false, + configurable: true + }); + return Three; +}()); +// "hello" +i.prop1 = 42; // error +i.prop1 = "hello"; +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error diff --git a/tests/baselines/reference/divergentAccessorsTypes5.symbols b/tests/baselines/reference/divergentAccessorsTypes5.symbols new file mode 100644 index 0000000000000..c698c9235bfe9 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes5.symbols @@ -0,0 +1,83 @@ +=== tests/cases/compiler/divergentAccessorsTypes5.ts === +// Not really different from divergentAccessorsTypes4.ts, +// but goes through the deferred type code + +class One { +>One : Symbol(One, Decl(divergentAccessorsTypes5.ts, 0, 0)) + + get prop1(): string { return ""; } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36)) + + set prop1(s: string | number) { } +>prop1 : Symbol(One.prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes5.ts, 5, 12)) + + prop2: number; +>prop2 : Symbol(One.prop2, Decl(divergentAccessorsTypes5.ts, 5, 35)) +} + +class Two { +>Two : Symbol(Two, Decl(divergentAccessorsTypes5.ts, 8, 1)) + + get prop1(): "hello" { return "hello"; } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42)) + + set prop1(s: "hello" | number) { } +>prop1 : Symbol(Two.prop1, Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42)) +>s : Symbol(s, Decl(divergentAccessorsTypes5.ts, 12, 12)) + + get prop2(): string { return ""; } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36)) + + set prop2(s: string | 42) { } +>prop2 : Symbol(Two.prop2, Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes5.ts, 15, 12)) + +} + +class Three { +>Three : Symbol(Three, Decl(divergentAccessorsTypes5.ts, 17, 1)) + + get prop1(): "hello" { return "hello"; } +>prop1 : Symbol(Three.prop1, Decl(divergentAccessorsTypes5.ts, 19, 13), Decl(divergentAccessorsTypes5.ts, 20, 42)) + + set prop1(s: "hello" | boolean) { } +>prop1 : Symbol(Three.prop1, Decl(divergentAccessorsTypes5.ts, 19, 13), Decl(divergentAccessorsTypes5.ts, 20, 42)) +>s : Symbol(s, Decl(divergentAccessorsTypes5.ts, 21, 12)) + + get prop2(): string { return ""; } +>prop2 : Symbol(Three.prop2, Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) + + set prop2(s: string | number | boolean) { } +>prop2 : Symbol(Three.prop2, Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) +>s : Symbol(s, Decl(divergentAccessorsTypes5.ts, 24, 12)) +} + +declare const i: One & Two & Three; +>i : Symbol(i, Decl(divergentAccessorsTypes5.ts, 27, 13)) +>One : Symbol(One, Decl(divergentAccessorsTypes5.ts, 0, 0)) +>Two : Symbol(Two, Decl(divergentAccessorsTypes5.ts, 8, 1)) +>Three : Symbol(Three, Decl(divergentAccessorsTypes5.ts, 17, 1)) + +// "hello" +i.prop1 = 42; // error +>i.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36), Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42), Decl(divergentAccessorsTypes5.ts, 19, 13) ... and 1 more) +>i : Symbol(i, Decl(divergentAccessorsTypes5.ts, 27, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36), Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42), Decl(divergentAccessorsTypes5.ts, 19, 13) ... and 1 more) + +i.prop1 = "hello"; +>i.prop1 : Symbol(prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36), Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42), Decl(divergentAccessorsTypes5.ts, 19, 13) ... and 1 more) +>i : Symbol(i, Decl(divergentAccessorsTypes5.ts, 27, 13)) +>prop1 : Symbol(prop1, Decl(divergentAccessorsTypes5.ts, 3, 11), Decl(divergentAccessorsTypes5.ts, 4, 36), Decl(divergentAccessorsTypes5.ts, 10, 11), Decl(divergentAccessorsTypes5.ts, 11, 42), Decl(divergentAccessorsTypes5.ts, 19, 13) ... and 1 more) + +// 42 +i.prop2 = 42; +>i.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes5.ts, 5, 35), Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36), Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) +>i : Symbol(i, Decl(divergentAccessorsTypes5.ts, 27, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes5.ts, 5, 35), Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36), Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) + +i.prop2 = "hello"; // error +>i.prop2 : Symbol(prop2, Decl(divergentAccessorsTypes5.ts, 5, 35), Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36), Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) +>i : Symbol(i, Decl(divergentAccessorsTypes5.ts, 27, 13)) +>prop2 : Symbol(prop2, Decl(divergentAccessorsTypes5.ts, 5, 35), Decl(divergentAccessorsTypes5.ts, 12, 36), Decl(divergentAccessorsTypes5.ts, 14, 36), Decl(divergentAccessorsTypes5.ts, 21, 37), Decl(divergentAccessorsTypes5.ts, 23, 36)) + diff --git a/tests/baselines/reference/divergentAccessorsTypes5.types b/tests/baselines/reference/divergentAccessorsTypes5.types new file mode 100644 index 0000000000000..5341163c3f808 --- /dev/null +++ b/tests/baselines/reference/divergentAccessorsTypes5.types @@ -0,0 +1,93 @@ +=== tests/cases/compiler/divergentAccessorsTypes5.ts === +// Not really different from divergentAccessorsTypes4.ts, +// but goes through the deferred type code + +class One { +>One : One + + get prop1(): string { return ""; } +>prop1 : string +>"" : "" + + set prop1(s: string | number) { } +>prop1 : string +>s : string | number + + prop2: number; +>prop2 : number +} + +class Two { +>Two : Two + + get prop1(): "hello" { return "hello"; } +>prop1 : "hello" +>"hello" : "hello" + + set prop1(s: "hello" | number) { } +>prop1 : "hello" +>s : number | "hello" + + get prop2(): string { return ""; } +>prop2 : string +>"" : "" + + set prop2(s: string | 42) { } +>prop2 : string +>s : string | 42 + +} + +class Three { +>Three : Three + + get prop1(): "hello" { return "hello"; } +>prop1 : "hello" +>"hello" : "hello" + + set prop1(s: "hello" | boolean) { } +>prop1 : "hello" +>s : boolean | "hello" + + get prop2(): string { return ""; } +>prop2 : string +>"" : "" + + set prop2(s: string | number | boolean) { } +>prop2 : string +>s : string | number | boolean +} + +declare const i: One & Two & Three; +>i : One & Two & Three + +// "hello" +i.prop1 = 42; // error +>i.prop1 = 42 : 42 +>i.prop1 : "hello" +>i : One & Two & Three +>prop1 : "hello" +>42 : 42 + +i.prop1 = "hello"; +>i.prop1 = "hello" : "hello" +>i.prop1 : "hello" +>i : One & Two & Three +>prop1 : "hello" +>"hello" : "hello" + +// 42 +i.prop2 = 42; +>i.prop2 = 42 : 42 +>i.prop2 : 42 +>i : One & Two & Three +>prop2 : 42 +>42 : 42 + +i.prop2 = "hello"; // error +>i.prop2 = "hello" : "hello" +>i.prop2 : 42 +>i : One & Two & Three +>prop2 : 42 +>"hello" : "hello" + diff --git a/tests/cases/compiler/divergentAccessorsTypes5.ts b/tests/cases/compiler/divergentAccessorsTypes5.ts new file mode 100644 index 0000000000000..54d1099004a17 --- /dev/null +++ b/tests/cases/compiler/divergentAccessorsTypes5.ts @@ -0,0 +1,38 @@ +// @target: es5 + +// Not really different from divergentAccessorsTypes4.ts, +// but goes through the deferred type code + +class One { + get prop1(): string { return ""; } + set prop1(s: string | number) { } + + prop2: number; +} + +class Two { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | number) { } + + get prop2(): string { return ""; } + set prop2(s: string | 42) { } + +} + +class Three { + get prop1(): "hello" { return "hello"; } + set prop1(s: "hello" | boolean) { } + + get prop2(): string { return ""; } + set prop2(s: string | number | boolean) { } +} + +declare const i: One & Two & Three; + +// "hello" +i.prop1 = 42; // error +i.prop1 = "hello"; + +// 42 +i.prop2 = 42; +i.prop2 = "hello"; // error From 03ec07bc559d92f8b816b64d9df29f7ea89805c5 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 3 Feb 2022 16:45:10 -0800 Subject: [PATCH 3/3] Always check for writeType of symbol --- src/compiler/checker.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 52ffeebce773e..96f6cba4d2781 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12146,7 +12146,6 @@ namespace ts { let optionalFlag = isUnion ? SymbolFlags.None : SymbolFlags.Optional; let syntheticFlag = CheckFlags.SyntheticMethod; let checkFlags = isUnion ? 0 : CheckFlags.Readonly; - let containsSetAccessor = false; let mergedInstantiations = false; for (const current of containingType.types) { const type = getApparentType(current); @@ -12185,9 +12184,6 @@ namespace ts { } } } - if (prop.flags & SymbolFlags.SetAccessor) { - containsSetAccessor = true; - } if (isUnion && isReadonlySymbol(prop)) { checkFlags |= CheckFlags.Readonly; } @@ -12259,8 +12255,9 @@ namespace ts { firstType = type; nameType = getSymbolLinks(prop).nameType; } - if (containsSetAccessor) { - writeTypes = append(writeTypes, getSetAccessorTypeOfSymbol(prop)); + const writeType = getWriteTypeOfSymbol(prop); + if (writeTypes || writeType !== type) { + writeTypes = append(!writeTypes ? propTypes.slice() : writeTypes, writeType); } else if (type !== firstType) { checkFlags |= CheckFlags.HasNonUniformType;