Intersect 'this' types in union signatures (#32538)

* Intersect this types in union signatures

* Actually update baselines
This commit is contained in:
Andrew Branch 2019-07-26 14:56:03 -07:00 committed by GitHub
parent 2a4930f4ec
commit 3d09010dc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 626 additions and 13 deletions

View File

@ -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);
}

View File

@ -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'.
}

View File

@ -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
}

View File

@ -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))

View File

@ -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)

View File

@ -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'.

View File

@ -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

View File

@ -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'.

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -7,5 +7,5 @@ interface Fake {
data: number;
}
function test(r: Real | Fake) {
r.method(12);
r.method(12); // error
}

View File

@ -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