diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 834fb3eccfa..f8242ed6df7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7181,8 +7181,9 @@ namespace ts { } let result: Signature[] | undefined; for (let i = 0; i < signatureLists.length; i++) { - // Allow matching non-generic signatures to have excess parameters and different return types - const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true); + // Allow matching non-generic signatures to have excess parameters and different return types. + // Prefer matching this types if possible. + const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); if (!match) { return undefined; } @@ -7205,7 +7206,7 @@ namespace ts { } for (const signature of signatureLists[i]) { // Only process signatures with parameter lists that aren't already in the result list - if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true)) { + if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { const unionSignatures = findMatchingSignatures(signatureLists, signature, i); if (unionSignatures) { let s = signature; @@ -7214,7 +7215,7 @@ namespace ts { let thisParameter = signature.thisParameter; const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); if (firstThisParameterOfUnionSignatures) { - const thisType = getUnionType(map(unionSignatures, sig => sig.thisParameter ? getTypeOfSymbol(sig.thisParameter) : anyType), UnionReduction.Subtype); + const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); } s = createUnionSignature(signature, unionSignatures); @@ -7253,8 +7254,8 @@ namespace ts { } // A signature `this` type might be a read or a write position... It's very possible that it should be invariant // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be - // permissive when calling, for now, we'll union the `this` types just like the overlapping-union-signature check does - const thisType = getUnionType([getTypeOfSymbol(left), getTypeOfSymbol(right)], UnionReduction.Subtype); + // permissive when calling, for now, we'll intersect the `this` types just like we do for param types in union signatures. + const thisType = getIntersectionType([getTypeOfSymbol(left), getTypeOfSymbol(right)]); return createSymbolWithType(left, thisType); } diff --git a/tests/baselines/reference/unionThisTypeInFunctions.errors.txt b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt new file mode 100644 index 00000000000..db03a5426fb --- /dev/null +++ b/tests/baselines/reference/unionThisTypeInFunctions.errors.txt @@ -0,0 +1,34 @@ +tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts(10,5): error TS2684: The 'this' context of type 'Real | Fake' is not assignable to method's 'this' of type 'Real & Fake'. + Type 'Real' is not assignable to type 'Real & Fake'. + Type 'Real' is not assignable to type 'Fake'. + Types of property 'method' are incompatible. + Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. + The 'this' types of each signature are incompatible. + Type 'Fake' is not assignable to type 'Real'. + Types of property 'data' are incompatible. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts (1 errors) ==== + interface Real { + method(this: this, n: number): void; + data: string; + } + interface Fake { + method(this: this, n: number): void; + data: number; + } + function test(r: Real | Fake) { + r.method(12); // error + ~ +!!! error TS2684: The 'this' context of type 'Real | Fake' is not assignable to method's 'this' of type 'Real & Fake'. +!!! error TS2684: Type 'Real' is not assignable to type 'Real & Fake'. +!!! error TS2684: Type 'Real' is not assignable to type 'Fake'. +!!! error TS2684: Types of property 'method' are incompatible. +!!! error TS2684: Type '(this: Real, n: number) => void' is not assignable to type '(this: Fake, n: number) => void'. +!!! error TS2684: The 'this' types of each signature are incompatible. +!!! error TS2684: Type 'Fake' is not assignable to type 'Real'. +!!! error TS2684: Types of property 'data' are incompatible. +!!! error TS2684: Type 'number' is not assignable to type 'string'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/unionThisTypeInFunctions.js b/tests/baselines/reference/unionThisTypeInFunctions.js index 0d4b535ff8b..dca64b6d893 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.js +++ b/tests/baselines/reference/unionThisTypeInFunctions.js @@ -8,11 +8,11 @@ interface Fake { data: number; } function test(r: Real | Fake) { - r.method(12); + r.method(12); // error } //// [unionThisTypeInFunctions.js] function test(r) { - r.method(12); + r.method(12); // error } diff --git a/tests/baselines/reference/unionThisTypeInFunctions.symbols b/tests/baselines/reference/unionThisTypeInFunctions.symbols index eada1231750..b907519626a 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.symbols +++ b/tests/baselines/reference/unionThisTypeInFunctions.symbols @@ -27,7 +27,7 @@ function test(r: Real | Fake) { >Real : Symbol(Real, Decl(unionThisTypeInFunctions.ts, 0, 0)) >Fake : Symbol(Fake, Decl(unionThisTypeInFunctions.ts, 3, 1)) - r.method(12); + r.method(12); // error >r.method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16)) >r : Symbol(r, Decl(unionThisTypeInFunctions.ts, 8, 14)) >method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16)) diff --git a/tests/baselines/reference/unionThisTypeInFunctions.types b/tests/baselines/reference/unionThisTypeInFunctions.types index 44c03d73a61..af987759a55 100644 --- a/tests/baselines/reference/unionThisTypeInFunctions.types +++ b/tests/baselines/reference/unionThisTypeInFunctions.types @@ -21,8 +21,8 @@ function test(r: Real | Fake) { >test : (r: Real | Fake) => void >r : Real | Fake - r.method(12); ->r.method(12) : void + r.method(12); // error +>r.method(12) : any >r.method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void) >r : Real | Fake >method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void) diff --git a/tests/baselines/reference/unionTypeCallSignatures5.errors.txt b/tests/baselines/reference/unionTypeCallSignatures5.errors.txt new file mode 100644 index 00000000000..2dc6ebb002b --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures5.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/types/union/unionTypeCallSignatures5.ts(12,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'never'. + + +==== tests/cases/conformance/types/union/unionTypeCallSignatures5.ts (1 errors) ==== + // #31485 + interface A { + (this: void, b?: number): void; + } + interface B { + (this: number, b?: number): void; + } + interface C { + (i: number): void; + } + declare const fn: A | B | C; + fn(0); + ~~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'never'. + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures5.types b/tests/baselines/reference/unionTypeCallSignatures5.types index 53ce4ea6550..b9b5a6fbc0d 100644 --- a/tests/baselines/reference/unionTypeCallSignatures5.types +++ b/tests/baselines/reference/unionTypeCallSignatures5.types @@ -18,7 +18,7 @@ declare const fn: A | B | C; >fn : A | B | C fn(0); ->fn(0) : void +>fn(0) : any >fn : A | B | C >0 : 0 diff --git a/tests/baselines/reference/unionTypeCallSignatures6.errors.txt b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt new file mode 100644 index 00000000000..51b18b204a7 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.errors.txt @@ -0,0 +1,98 @@ +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(11,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(13,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(38,4): error TS2349: This expression is not callable. + Each member of the union type 'F3 | F4' has signatures, but none of those signatures are compatible with each other. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(39,1): error TS2684: The 'this' context of type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' is not assignable to method's 'this' of type 'B'. + Property 'b' is missing in type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' but required in type 'B'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(48,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. +tests/cases/conformance/types/union/unionTypeCallSignatures6.ts(55,1): error TS2769: No overload matches this call. + Overload 1 of 2, '(this: A & B & C): void', gave the following error. + The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. + Type 'void' is not assignable to type 'A'. + Overload 2 of 2, '(this: A & B): void', gave the following error. + The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. + Type 'void' is not assignable to type 'A'. + + +==== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts (6 errors) ==== + type A = { a: string }; + type B = { b: number }; + type C = { c: string }; + type D = { d: number }; + type F0 = () => void; + + // #31547 + type F1 = (this: A) => void; + type F2 = (this: B) => void; + declare var f1: F1 | F2; + f1(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2684: Type 'void' is not assignable to type 'A'. + declare var f2: F0 | F1; + f2(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A'. + + interface F3 { + (this: A): void; + (this: B): void; + } + interface F4 { + (this: C): void; + (this: D): void; + } + interface F5 { + (this: C): void; + (this: B): void; + } + + declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; + } + x1.f0(); + x1.f1(); + x1.f2(); + x1.f3(); // error + ~~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Each member of the union type 'F3 | F4' has signatures, but none of those signatures are compatible with each other. + x1.f4(); // error + ~~ +!!! error TS2684: The 'this' context of type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' is not assignable to method's 'this' of type 'B'. +!!! error TS2684: Property 'b' is missing in type 'A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; }' but required in type 'B'. +!!! related TS2728 tests/cases/conformance/types/union/unionTypeCallSignatures6.ts:2:12: 'b' is declared here. + + declare var x2: A & B & { + f4: F3 | F5; + } + x2.f4(); + + type F6 = (this: A & B) => void; + declare var f3: F1 | F6; + f3(); // error + ~~~~ +!!! error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2684: Type 'void' is not assignable to type 'A'. + + interface F7 { + (this: A & B & C): void; + (this: A & B): void; + } + declare var f4: F6 | F7; + f4(); // error + ~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(this: A & B & C): void', gave the following error. +!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B & C'. +!!! error TS2769: Type 'void' is not assignable to type 'A'. +!!! error TS2769: Overload 2 of 2, '(this: A & B): void', gave the following error. +!!! error TS2769: The 'this' context of type 'void' is not assignable to method's 'this' of type 'A & B'. +!!! error TS2769: Type 'void' is not assignable to type 'A'. + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures6.js b/tests/baselines/reference/unionTypeCallSignatures6.js new file mode 100644 index 00000000000..32e0518cbb8 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.js @@ -0,0 +1,69 @@ +//// [unionTypeCallSignatures6.ts] +type A = { a: string }; +type B = { b: number }; +type C = { c: string }; +type D = { d: number }; +type F0 = () => void; + +// #31547 +type F1 = (this: A) => void; +type F2 = (this: B) => void; +declare var f1: F1 | F2; +f1(); // error +declare var f2: F0 | F1; +f2(); // error + +interface F3 { + (this: A): void; + (this: B): void; +} +interface F4 { + (this: C): void; + (this: D): void; +} +interface F5 { + (this: C): void; + (this: B): void; +} + +declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; +} +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error + +declare var x2: A & B & { + f4: F3 | F5; +} +x2.f4(); + +type F6 = (this: A & B) => void; +declare var f3: F1 | F6; +f3(); // error + +interface F7 { + (this: A & B & C): void; + (this: A & B): void; +} +declare var f4: F6 | F7; +f4(); // error + + +//// [unionTypeCallSignatures6.js] +f1(); // error +f2(); // error +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error +x2.f4(); +f3(); // error +f4(); // error diff --git a/tests/baselines/reference/unionTypeCallSignatures6.symbols b/tests/baselines/reference/unionTypeCallSignatures6.symbols new file mode 100644 index 00000000000..87d1928f069 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.symbols @@ -0,0 +1,187 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts === +type A = { a: string }; +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>a : Symbol(a, Decl(unionTypeCallSignatures6.ts, 0, 10)) + +type B = { b: number }; +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +>b : Symbol(b, Decl(unionTypeCallSignatures6.ts, 1, 10)) + +type C = { c: string }; +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) +>c : Symbol(c, Decl(unionTypeCallSignatures6.ts, 2, 10)) + +type D = { d: number }; +>D : Symbol(D, Decl(unionTypeCallSignatures6.ts, 2, 23)) +>d : Symbol(d, Decl(unionTypeCallSignatures6.ts, 3, 10)) + +type F0 = () => void; +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) + +// #31547 +type F1 = (this: A) => void; +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 7, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) + +type F2 = (this: B) => void; +>F2 : Symbol(F2, Decl(unionTypeCallSignatures6.ts, 7, 28)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 8, 11)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + +declare var f1: F1 | F2; +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 9, 11)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F2 : Symbol(F2, Decl(unionTypeCallSignatures6.ts, 7, 28)) + +f1(); // error +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 9, 11)) + +declare var f2: F0 | F1; +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 11, 11)) +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) + +f2(); // error +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 11, 11)) + +interface F3 { +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + (this: A): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 15, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) + + (this: B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 16, 3)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} +interface F4 { +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + (this: C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 19, 3)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: D): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 20, 3)) +>D : Symbol(D, Decl(unionTypeCallSignatures6.ts, 2, 23)) +} +interface F5 { +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) + + (this: C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 23, 3)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 24, 3)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} + +declare var x1: A & C & { +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + f0: F0 | F3; +>f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) +>F0 : Symbol(F0, Decl(unionTypeCallSignatures6.ts, 3, 23)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + f1: F1 | F3; +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) + + f2: F1 | F4; +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + f3: F3 | F4; +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F4 : Symbol(F4, Decl(unionTypeCallSignatures6.ts, 17, 1)) + + f4: F3 | F5; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) +} +x1.f0(); +>x1.f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f0 : Symbol(f0, Decl(unionTypeCallSignatures6.ts, 27, 25)) + +x1.f1(); +>x1.f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f1 : Symbol(f1, Decl(unionTypeCallSignatures6.ts, 28, 14)) + +x1.f2(); +>x1.f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f2 : Symbol(f2, Decl(unionTypeCallSignatures6.ts, 29, 14)) + +x1.f3(); // error +>x1.f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 30, 14)) + +x1.f4(); // error +>x1.f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) +>x1 : Symbol(x1, Decl(unionTypeCallSignatures6.ts, 27, 11)) +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 31, 14)) + +declare var x2: A & B & { +>x2 : Symbol(x2, Decl(unionTypeCallSignatures6.ts, 40, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + + f4: F3 | F5; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) +>F3 : Symbol(F3, Decl(unionTypeCallSignatures6.ts, 12, 5)) +>F5 : Symbol(F5, Decl(unionTypeCallSignatures6.ts, 21, 1)) +} +x2.f4(); +>x2.f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) +>x2 : Symbol(x2, Decl(unionTypeCallSignatures6.ts, 40, 11)) +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 40, 25)) + +type F6 = (this: A & B) => void; +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 45, 11)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) + +declare var f3: F1 | F6; +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 46, 11)) +>F1 : Symbol(F1, Decl(unionTypeCallSignatures6.ts, 4, 21)) +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) + +f3(); // error +>f3 : Symbol(f3, Decl(unionTypeCallSignatures6.ts, 46, 11)) + +interface F7 { +>F7 : Symbol(F7, Decl(unionTypeCallSignatures6.ts, 47, 5)) + + (this: A & B & C): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 50, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +>C : Symbol(C, Decl(unionTypeCallSignatures6.ts, 1, 23)) + + (this: A & B): void; +>this : Symbol(this, Decl(unionTypeCallSignatures6.ts, 51, 3)) +>A : Symbol(A, Decl(unionTypeCallSignatures6.ts, 0, 0)) +>B : Symbol(B, Decl(unionTypeCallSignatures6.ts, 0, 23)) +} +declare var f4: F6 | F7; +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 53, 11)) +>F6 : Symbol(F6, Decl(unionTypeCallSignatures6.ts, 43, 8)) +>F7 : Symbol(F7, Decl(unionTypeCallSignatures6.ts, 47, 5)) + +f4(); // error +>f4 : Symbol(f4, Decl(unionTypeCallSignatures6.ts, 53, 11)) + diff --git a/tests/baselines/reference/unionTypeCallSignatures6.types b/tests/baselines/reference/unionTypeCallSignatures6.types new file mode 100644 index 00000000000..930c91b1109 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures6.types @@ -0,0 +1,150 @@ +=== tests/cases/conformance/types/union/unionTypeCallSignatures6.ts === +type A = { a: string }; +>A : A +>a : string + +type B = { b: number }; +>B : B +>b : number + +type C = { c: string }; +>C : C +>c : string + +type D = { d: number }; +>D : D +>d : number + +type F0 = () => void; +>F0 : F0 + +// #31547 +type F1 = (this: A) => void; +>F1 : F1 +>this : A + +type F2 = (this: B) => void; +>F2 : F2 +>this : B + +declare var f1: F1 | F2; +>f1 : F1 | F2 + +f1(); // error +>f1() : any +>f1 : F1 | F2 + +declare var f2: F0 | F1; +>f2 : F1 | F0 + +f2(); // error +>f2() : any +>f2 : F1 | F0 + +interface F3 { + (this: A): void; +>this : A + + (this: B): void; +>this : B +} +interface F4 { + (this: C): void; +>this : C + + (this: D): void; +>this : D +} +interface F5 { + (this: C): void; +>this : C + + (this: B): void; +>this : B +} + +declare var x1: A & C & { +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } + + f0: F0 | F3; +>f0 : F0 | F3 + + f1: F1 | F3; +>f1 : F1 | F3 + + f2: F1 | F4; +>f2 : F1 | F4 + + f3: F3 | F4; +>f3 : F3 | F4 + + f4: F3 | F5; +>f4 : F3 | F5 +} +x1.f0(); +>x1.f0() : void +>x1.f0 : F0 | F3 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f0 : F0 | F3 + +x1.f1(); +>x1.f1() : void +>x1.f1 : F1 | F3 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f1 : F1 | F3 + +x1.f2(); +>x1.f2() : void +>x1.f2 : F1 | F4 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f2 : F1 | F4 + +x1.f3(); // error +>x1.f3() : any +>x1.f3 : F3 | F4 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f3 : F3 | F4 + +x1.f4(); // error +>x1.f4() : any +>x1.f4 : F3 | F5 +>x1 : A & C & { f0: F0 | F3; f1: F1 | F3; f2: F1 | F4; f3: F3 | F4; f4: F3 | F5; } +>f4 : F3 | F5 + +declare var x2: A & B & { +>x2 : A & B & { f4: F3 | F5; } + + f4: F3 | F5; +>f4 : F3 | F5 +} +x2.f4(); +>x2.f4() : void +>x2.f4 : F3 | F5 +>x2 : A & B & { f4: F3 | F5; } +>f4 : F3 | F5 + +type F6 = (this: A & B) => void; +>F6 : F6 +>this : A & B + +declare var f3: F1 | F6; +>f3 : F1 | F6 + +f3(); // error +>f3() : any +>f3 : F1 | F6 + +interface F7 { + (this: A & B & C): void; +>this : A & B & C + + (this: A & B): void; +>this : A & B +} +declare var f4: F6 | F7; +>f4 : F6 | F7 + +f4(); // error +>f4() : any +>f4 : F6 | F7 + diff --git a/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts b/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts index 4f74058cc48..a35019d372e 100644 --- a/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts +++ b/tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts @@ -7,5 +7,5 @@ interface Fake { data: number; } function test(r: Real | Fake) { - r.method(12); + r.method(12); // error } diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts new file mode 100644 index 00000000000..0fe98847205 --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures6.ts @@ -0,0 +1,55 @@ +type A = { a: string }; +type B = { b: number }; +type C = { c: string }; +type D = { d: number }; +type F0 = () => void; + +// #31547 +type F1 = (this: A) => void; +type F2 = (this: B) => void; +declare var f1: F1 | F2; +f1(); // error +declare var f2: F0 | F1; +f2(); // error + +interface F3 { + (this: A): void; + (this: B): void; +} +interface F4 { + (this: C): void; + (this: D): void; +} +interface F5 { + (this: C): void; + (this: B): void; +} + +declare var x1: A & C & { + f0: F0 | F3; + f1: F1 | F3; + f2: F1 | F4; + f3: F3 | F4; + f4: F3 | F5; +} +x1.f0(); +x1.f1(); +x1.f2(); +x1.f3(); // error +x1.f4(); // error + +declare var x2: A & B & { + f4: F3 | F5; +} +x2.f4(); + +type F6 = (this: A & B) => void; +declare var f3: F1 | F6; +f3(); // error + +interface F7 { + (this: A & B & C): void; + (this: A & B): void; +} +declare var f4: F6 | F7; +f4(); // error