mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-12 12:57:11 -06:00
Merge pull request #5895 from Microsoft/unionTypeParameterInference
Fix union type parameter inference Conflicts: src/compiler/checker.ts
This commit is contained in:
parent
b022893fd8
commit
ccb4326cce
@ -4940,9 +4940,6 @@ namespace ts {
|
||||
}
|
||||
return objectTypeRelatedTo(<ObjectType>source, <ObjectType>target, /*reportErrors*/ false);
|
||||
}
|
||||
if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
|
||||
return typeParameterIdenticalTo(<TypeParameter>source, <TypeParameter>target);
|
||||
}
|
||||
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
|
||||
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
|
||||
if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target)) {
|
||||
@ -5073,20 +5070,6 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function typeParameterIdenticalTo(source: TypeParameter, target: TypeParameter): Ternary {
|
||||
if (source.symbol.name !== target.symbol.name) {
|
||||
return Ternary.False;
|
||||
}
|
||||
// covers case when both type parameters does not have constraint (both equal to noConstraintType)
|
||||
if (source.constraint === target.constraint) {
|
||||
return Ternary.True;
|
||||
}
|
||||
if (source.constraint === noConstraintType || target.constraint === noConstraintType) {
|
||||
return Ternary.False;
|
||||
}
|
||||
return isIdenticalTo(source.constraint, target.constraint);
|
||||
}
|
||||
|
||||
// Determine if two object types are related by structure. First, check if the result is already available in the global cache.
|
||||
// Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
|
||||
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
|
||||
@ -5609,27 +5592,20 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
let result = Ternary.True;
|
||||
if (source.typeParameters && target.typeParameters) {
|
||||
if (source.typeParameters.length !== target.typeParameters.length) {
|
||||
return Ternary.False;
|
||||
}
|
||||
for (let i = 0, len = source.typeParameters.length; i < len; ++i) {
|
||||
let related = compareTypes(source.typeParameters[i], target.typeParameters[i]);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
}
|
||||
result &= related;
|
||||
}
|
||||
}
|
||||
else if (source.typeParameters || target.typeParameters) {
|
||||
// Check that the two signatures have the same number of type parameters. We might consider
|
||||
// also checking that any type parameter constraints match, but that would require instantiating
|
||||
// the constraints with a common set of type arguments to get relatable entities in places where
|
||||
// type parameters occur in the constraints. The complexity of doing that doesn't seem worthwhile,
|
||||
// particularly as we're comparing erased versions of the signatures below.
|
||||
if ((source.typeParameters ? source.typeParameters.length : 0) !== (target.typeParameters ? target.typeParameters.length : 0)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
// Spec 1.0 Section 3.8.3 & 3.8.4:
|
||||
// M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
|
||||
source = getErasedSignature(source);
|
||||
target = getErasedSignature(target);
|
||||
let targetLen = target.parameters.length;
|
||||
let result = Ternary.True;
|
||||
const targetLen = target.parameters.length;
|
||||
for (let i = 0; i < targetLen; i++) {
|
||||
let s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
|
||||
let t = isRestParameterIndex(target, i) ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
|
||||
|
||||
32
tests/baselines/reference/genericSignatureIdentity.js
Normal file
32
tests/baselines/reference/genericSignatureIdentity.js
Normal file
@ -0,0 +1,32 @@
|
||||
//// [genericSignatureIdentity.ts]
|
||||
// This test is here to remind us of our current limits of type identity checking.
|
||||
// Ideally all of the below declarations would be considered different (and thus errors)
|
||||
// but they aren't because we erase type parameters to type any and don't check that
|
||||
// constraints are identical.
|
||||
|
||||
var x: {
|
||||
<T extends Date>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T extends number>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T>(x: any): any;
|
||||
};
|
||||
|
||||
|
||||
//// [genericSignatureIdentity.js]
|
||||
// This test is here to remind us of our current limits of type identity checking.
|
||||
// Ideally all of the below declarations would be considered different (and thus errors)
|
||||
// but they aren't because we erase type parameters to type any and don't check that
|
||||
// constraints are identical.
|
||||
var x;
|
||||
var x;
|
||||
var x;
|
||||
var x;
|
||||
49
tests/baselines/reference/genericSignatureIdentity.symbols
Normal file
49
tests/baselines/reference/genericSignatureIdentity.symbols
Normal file
@ -0,0 +1,49 @@
|
||||
=== tests/cases/compiler/genericSignatureIdentity.ts ===
|
||||
// This test is here to remind us of our current limits of type identity checking.
|
||||
// Ideally all of the below declarations would be considered different (and thus errors)
|
||||
// but they aren't because we erase type parameters to type any and don't check that
|
||||
// constraints are identical.
|
||||
|
||||
var x: {
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 5, 3), Decl(genericSignatureIdentity.ts, 9, 3), Decl(genericSignatureIdentity.ts, 13, 3), Decl(genericSignatureIdentity.ts, 17, 3))
|
||||
|
||||
<T extends Date>(x: T): T;
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 6, 5))
|
||||
>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 6, 21))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 6, 5))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 6, 5))
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 5, 3), Decl(genericSignatureIdentity.ts, 9, 3), Decl(genericSignatureIdentity.ts, 13, 3), Decl(genericSignatureIdentity.ts, 17, 3))
|
||||
|
||||
<T extends number>(x: T): T;
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 10, 5))
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 10, 23))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 10, 5))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 10, 5))
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 5, 3), Decl(genericSignatureIdentity.ts, 9, 3), Decl(genericSignatureIdentity.ts, 13, 3), Decl(genericSignatureIdentity.ts, 17, 3))
|
||||
|
||||
<T>(x: T): T;
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 14, 5))
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 14, 8))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 14, 5))
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 14, 5))
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 5, 3), Decl(genericSignatureIdentity.ts, 9, 3), Decl(genericSignatureIdentity.ts, 13, 3), Decl(genericSignatureIdentity.ts, 17, 3))
|
||||
|
||||
<T>(x: any): any;
|
||||
>T : Symbol(T, Decl(genericSignatureIdentity.ts, 18, 5))
|
||||
>x : Symbol(x, Decl(genericSignatureIdentity.ts, 18, 8))
|
||||
|
||||
};
|
||||
|
||||
49
tests/baselines/reference/genericSignatureIdentity.types
Normal file
49
tests/baselines/reference/genericSignatureIdentity.types
Normal file
@ -0,0 +1,49 @@
|
||||
=== tests/cases/compiler/genericSignatureIdentity.ts ===
|
||||
// This test is here to remind us of our current limits of type identity checking.
|
||||
// Ideally all of the below declarations would be considered different (and thus errors)
|
||||
// but they aren't because we erase type parameters to type any and don't check that
|
||||
// constraints are identical.
|
||||
|
||||
var x: {
|
||||
>x : <T extends Date>(x: T) => T
|
||||
|
||||
<T extends Date>(x: T): T;
|
||||
>T : T
|
||||
>Date : Date
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : <T extends Date>(x: T) => T
|
||||
|
||||
<T extends number>(x: T): T;
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : <T extends Date>(x: T) => T
|
||||
|
||||
<T>(x: T): T;
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
};
|
||||
|
||||
var x: {
|
||||
>x : <T extends Date>(x: T) => T
|
||||
|
||||
<T>(x: any): any;
|
||||
>T : T
|
||||
>x : any
|
||||
|
||||
};
|
||||
|
||||
17
tests/baselines/reference/unionTypeParameterInference.js
Normal file
17
tests/baselines/reference/unionTypeParameterInference.js
Normal file
@ -0,0 +1,17 @@
|
||||
//// [unionTypeParameterInference.ts]
|
||||
// Regression test for #5861
|
||||
|
||||
interface Foo<T> { prop: T; }
|
||||
|
||||
declare function lift<U>(value: U | Foo<U>): Foo<U>;
|
||||
|
||||
function unlift<U>(value: U | Foo<U>): U {
|
||||
return lift(value).prop;
|
||||
}
|
||||
|
||||
|
||||
//// [unionTypeParameterInference.js]
|
||||
// Regression test for #5861
|
||||
function unlift(value) {
|
||||
return lift(value).prop;
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
=== tests/cases/compiler/unionTypeParameterInference.ts ===
|
||||
// Regression test for #5861
|
||||
|
||||
interface Foo<T> { prop: T; }
|
||||
>Foo : Symbol(Foo, Decl(unionTypeParameterInference.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(unionTypeParameterInference.ts, 2, 14))
|
||||
>prop : Symbol(prop, Decl(unionTypeParameterInference.ts, 2, 18))
|
||||
>T : Symbol(T, Decl(unionTypeParameterInference.ts, 2, 14))
|
||||
|
||||
declare function lift<U>(value: U | Foo<U>): Foo<U>;
|
||||
>lift : Symbol(lift, Decl(unionTypeParameterInference.ts, 2, 29))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 4, 22))
|
||||
>value : Symbol(value, Decl(unionTypeParameterInference.ts, 4, 25))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 4, 22))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeParameterInference.ts, 0, 0))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 4, 22))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeParameterInference.ts, 0, 0))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 4, 22))
|
||||
|
||||
function unlift<U>(value: U | Foo<U>): U {
|
||||
>unlift : Symbol(unlift, Decl(unionTypeParameterInference.ts, 4, 52))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 6, 16))
|
||||
>value : Symbol(value, Decl(unionTypeParameterInference.ts, 6, 19))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 6, 16))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeParameterInference.ts, 0, 0))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 6, 16))
|
||||
>U : Symbol(U, Decl(unionTypeParameterInference.ts, 6, 16))
|
||||
|
||||
return lift(value).prop;
|
||||
>lift(value).prop : Symbol(Foo.prop, Decl(unionTypeParameterInference.ts, 2, 18))
|
||||
>lift : Symbol(lift, Decl(unionTypeParameterInference.ts, 2, 29))
|
||||
>value : Symbol(value, Decl(unionTypeParameterInference.ts, 6, 19))
|
||||
>prop : Symbol(Foo.prop, Decl(unionTypeParameterInference.ts, 2, 18))
|
||||
}
|
||||
|
||||
36
tests/baselines/reference/unionTypeParameterInference.types
Normal file
36
tests/baselines/reference/unionTypeParameterInference.types
Normal file
@ -0,0 +1,36 @@
|
||||
=== tests/cases/compiler/unionTypeParameterInference.ts ===
|
||||
// Regression test for #5861
|
||||
|
||||
interface Foo<T> { prop: T; }
|
||||
>Foo : Foo<T>
|
||||
>T : T
|
||||
>prop : T
|
||||
>T : T
|
||||
|
||||
declare function lift<U>(value: U | Foo<U>): Foo<U>;
|
||||
>lift : <U>(value: U | Foo<U>) => Foo<U>
|
||||
>U : U
|
||||
>value : U | Foo<U>
|
||||
>U : U
|
||||
>Foo : Foo<T>
|
||||
>U : U
|
||||
>Foo : Foo<T>
|
||||
>U : U
|
||||
|
||||
function unlift<U>(value: U | Foo<U>): U {
|
||||
>unlift : <U>(value: U | Foo<U>) => U
|
||||
>U : U
|
||||
>value : U | Foo<U>
|
||||
>U : U
|
||||
>Foo : Foo<T>
|
||||
>U : U
|
||||
>U : U
|
||||
|
||||
return lift(value).prop;
|
||||
>lift(value).prop : U
|
||||
>lift(value) : Foo<U>
|
||||
>lift : <U>(value: U | Foo<U>) => Foo<U>
|
||||
>value : U | Foo<U>
|
||||
>prop : U
|
||||
}
|
||||
|
||||
20
tests/cases/compiler/genericSignatureIdentity.ts
Normal file
20
tests/cases/compiler/genericSignatureIdentity.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// This test is here to remind us of our current limits of type identity checking.
|
||||
// Ideally all of the below declarations would be considered different (and thus errors)
|
||||
// but they aren't because we erase type parameters to type any and don't check that
|
||||
// constraints are identical.
|
||||
|
||||
var x: {
|
||||
<T extends Date>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T extends number>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T>(x: T): T;
|
||||
};
|
||||
|
||||
var x: {
|
||||
<T>(x: any): any;
|
||||
};
|
||||
9
tests/cases/compiler/unionTypeParameterInference.ts
Normal file
9
tests/cases/compiler/unionTypeParameterInference.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// Regression test for #5861
|
||||
|
||||
interface Foo<T> { prop: T; }
|
||||
|
||||
declare function lift<U>(value: U | Foo<U>): Foo<U>;
|
||||
|
||||
function unlift<U>(value: U | Foo<U>): U {
|
||||
return lift(value).prop;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user