Compute dervied generic-ness for substitutions and create lower priority inferences for substitutes (#43765)

This commit is contained in:
Wesley Wigham
2021-04-23 15:51:05 -07:00
committed by GitHub
parent bd7d0f26b2
commit dee4903f45
8 changed files with 84 additions and 30 deletions
+21
View File
@@ -14720,6 +14720,13 @@ namespace ts {
}
return !!((<UnionOrIntersectionType>type).objectFlags & ObjectFlags.IsGenericObjectType);
}
if (type.flags & TypeFlags.Substitution) {
if (!((<SubstitutionType>type).objectFlags & ObjectFlags.IsGenericObjectTypeComputed)) {
(<SubstitutionType>type).objectFlags |= ObjectFlags.IsGenericObjectTypeComputed |
(isGenericObjectType((<SubstitutionType>type).substitute) || isGenericObjectType((<SubstitutionType>type).baseType) ? ObjectFlags.IsGenericObjectType : 0);
}
return !!((<SubstitutionType>type).objectFlags & ObjectFlags.IsGenericObjectType);
}
return !!(type.flags & TypeFlags.InstantiableNonPrimitive) || isGenericMappedType(type) || isGenericTupleType(type);
}
@@ -14731,6 +14738,13 @@ namespace ts {
}
return !!((<UnionOrIntersectionType>type).objectFlags & ObjectFlags.IsGenericIndexType);
}
if (type.flags & TypeFlags.Substitution) {
if (!((<SubstitutionType>type).objectFlags & ObjectFlags.IsGenericIndexTypeComputed)) {
(<SubstitutionType>type).objectFlags |= ObjectFlags.IsGenericIndexTypeComputed |
(isGenericIndexType((<SubstitutionType>type).substitute) || isGenericIndexType((<SubstitutionType>type).baseType) ? ObjectFlags.IsGenericIndexType : 0);
}
return !!((<SubstitutionType>type).objectFlags & ObjectFlags.IsGenericIndexType);
}
return !!(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)) && !isPatternLiteralType(type);
}
@@ -21128,6 +21142,13 @@ namespace ts {
inferFromTypes((<StringMappingType>source).type, (<StringMappingType>target).type);
}
}
else if (source.flags & TypeFlags.Substitution) {
inferFromTypes((source as SubstitutionType).baseType, target);
const oldPriority = priority;
priority |= InferencePriority.SubstituteSource;
inferFromTypes((source as SubstitutionType).substitute, target); // Make substitute inference at a lower priority
priority = oldPriority;
}
else if (target.flags & TypeFlags.Conditional) {
invokeOnce(source, target, inferToConditionalType);
}
+12 -10
View File
@@ -5201,7 +5201,7 @@ namespace ts {
/* @internal */
IsClassInstanceClone = 1 << 24, // Type is a clone of a class instance type
// Flags that require TypeFlags.UnionOrIntersection
// Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution
/* @internal */
IsGenericObjectTypeComputed = 1 << 22, // IsGenericObjectType flag has been computed
/* @internal */
@@ -5553,6 +5553,7 @@ namespace ts {
// Thus, if Foo has a 'string' constraint on its type parameter, T will satisfy it. Substitution
// types disappear upon instantiation (just like type parameters).
export interface SubstitutionType extends InstantiableType {
objectFlags: ObjectFlags;
baseType: Type; // Target type
substitute: Type; // Type to substitute for type parameter
}
@@ -5663,15 +5664,16 @@ namespace ts {
export const enum InferencePriority {
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
SpeculativeTuple = 1 << 1, // Speculative tuple inference
HomomorphicMappedType = 1 << 2, // Reverse inference for homomorphic mapped type
PartialHomomorphicMappedType = 1 << 3, // Partial reverse inference for homomorphic mapped type
MappedTypeConstraint = 1 << 4, // Reverse inference for mapped type
ContravariantConditional = 1 << 5, // Conditional type in contravariant position
ReturnType = 1 << 6, // Inference made from return type of generic function
LiteralKeyof = 1 << 7, // Inference made from a string literal to a keyof T
NoConstraints = 1 << 8, // Don't infer from constraints of instantiable types
AlwaysStrict = 1 << 9, // Always use strict rules for contravariant inferences
MaxValue = 1 << 10, // Seed for inference priority tracking
SubstituteSource = 1 << 2, // Source of inference originated within a substitution type's substitute
HomomorphicMappedType = 1 << 3, // Reverse inference for homomorphic mapped type
PartialHomomorphicMappedType = 1 << 4, // Partial reverse inference for homomorphic mapped type
MappedTypeConstraint = 1 << 5, // Reverse inference for mapped type
ContravariantConditional = 1 << 6, // Conditional type in contravariant position
ReturnType = 1 << 7, // Inference made from return type of generic function
LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T
NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types
AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences
MaxValue = 1 << 11, // Seed for inference priority tracking
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
Circularity = -1, // Inference circularity (value less than all other priorities)
+12 -10
View File
@@ -2681,6 +2681,7 @@ declare namespace ts {
type: Type;
}
export interface SubstitutionType extends InstantiableType {
objectFlags: ObjectFlags;
baseType: Type;
substitute: Type;
}
@@ -2705,16 +2706,17 @@ declare namespace ts {
export enum InferencePriority {
NakedTypeVariable = 1,
SpeculativeTuple = 2,
HomomorphicMappedType = 4,
PartialHomomorphicMappedType = 8,
MappedTypeConstraint = 16,
ContravariantConditional = 32,
ReturnType = 64,
LiteralKeyof = 128,
NoConstraints = 256,
AlwaysStrict = 512,
MaxValue = 1024,
PriorityImpliesCombination = 208,
SubstituteSource = 4,
HomomorphicMappedType = 8,
PartialHomomorphicMappedType = 16,
MappedTypeConstraint = 32,
ContravariantConditional = 64,
ReturnType = 128,
LiteralKeyof = 256,
NoConstraints = 512,
AlwaysStrict = 1024,
MaxValue = 2048,
PriorityImpliesCombination = 416,
Circularity = -1
}
/** @deprecated Use FileExtensionInfo instead. */
+12 -10
View File
@@ -2681,6 +2681,7 @@ declare namespace ts {
type: Type;
}
export interface SubstitutionType extends InstantiableType {
objectFlags: ObjectFlags;
baseType: Type;
substitute: Type;
}
@@ -2705,16 +2706,17 @@ declare namespace ts {
export enum InferencePriority {
NakedTypeVariable = 1,
SpeculativeTuple = 2,
HomomorphicMappedType = 4,
PartialHomomorphicMappedType = 8,
MappedTypeConstraint = 16,
ContravariantConditional = 32,
ReturnType = 64,
LiteralKeyof = 128,
NoConstraints = 256,
AlwaysStrict = 512,
MaxValue = 1024,
PriorityImpliesCombination = 208,
SubstituteSource = 4,
HomomorphicMappedType = 8,
PartialHomomorphicMappedType = 16,
MappedTypeConstraint = 32,
ContravariantConditional = 64,
ReturnType = 128,
LiteralKeyof = 256,
NoConstraints = 512,
AlwaysStrict = 1024,
MaxValue = 2048,
PriorityImpliesCombination = 416,
Circularity = -1
}
/** @deprecated Use FileExtensionInfo instead. */
@@ -0,0 +1,6 @@
//// [nongenericConditionalNotPartiallyComputed.ts]
// Expected: type A = number
// Got: type A = number[] extends (infer T)[] ? T : never
type A = Array<number> extends Array<any> ? Array<number> extends Array<infer T> ? T : never : never
//// [nongenericConditionalNotPartiallyComputed.js]
@@ -0,0 +1,12 @@
=== tests/cases/compiler/nongenericConditionalNotPartiallyComputed.ts ===
// Expected: type A = number
// Got: type A = number[] extends (infer T)[] ? T : never
type A = Array<number> extends Array<any> ? Array<number> extends Array<infer T> ? T : never : never
>A : Symbol(A, Decl(nongenericConditionalNotPartiallyComputed.ts, 0, 0))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(nongenericConditionalNotPartiallyComputed.ts, 2, 77))
>T : Symbol(T, Decl(nongenericConditionalNotPartiallyComputed.ts, 2, 77))
@@ -0,0 +1,6 @@
=== tests/cases/compiler/nongenericConditionalNotPartiallyComputed.ts ===
// Expected: type A = number
// Got: type A = number[] extends (infer T)[] ? T : never
type A = Array<number> extends Array<any> ? Array<number> extends Array<infer T> ? T : never : never
>A : number
@@ -0,0 +1,3 @@
// Expected: type A = number
// Got: type A = number[] extends (infer T)[] ? T : never
type A = Array<number> extends Array<any> ? Array<number> extends Array<infer T> ? T : never : never