mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Merge pull request #21157 from Microsoft/fixEmptyArrayInference
Fix empty array inference
This commit is contained in:
commit
64b3086f5e
@ -10917,6 +10917,7 @@ namespace ts {
|
||||
return {
|
||||
typeParameter,
|
||||
candidates: undefined,
|
||||
contraCandidates: undefined,
|
||||
inferredType: undefined,
|
||||
priority: undefined,
|
||||
topLevel: true,
|
||||
@ -10928,6 +10929,7 @@ namespace ts {
|
||||
return {
|
||||
typeParameter: inference.typeParameter,
|
||||
candidates: inference.candidates && inference.candidates.slice(),
|
||||
contraCandidates: inference.contraCandidates && inference.contraCandidates.slice(),
|
||||
inferredType: inference.inferredType,
|
||||
priority: inference.priority,
|
||||
topLevel: inference.topLevel,
|
||||
@ -11041,6 +11043,7 @@ namespace ts {
|
||||
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
|
||||
let symbolStack: Symbol[];
|
||||
let visited: Map<boolean>;
|
||||
let contravariant = false;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
||||
function inferFromTypes(source: Type, target: Type) {
|
||||
@ -11108,18 +11111,20 @@ namespace ts {
|
||||
const inference = getInferenceInfoForType(target);
|
||||
if (inference) {
|
||||
if (!inference.isFixed) {
|
||||
// We give lowest priority to inferences of implicitNeverType (which is used as the
|
||||
// element type for empty array literals). Thus, inferences from empty array literals
|
||||
// only matter when no other inferences are made.
|
||||
const p = priority | (source === implicitNeverType ? InferencePriority.NeverType : 0);
|
||||
if (!inference.candidates || p < inference.priority) {
|
||||
inference.candidates = [source];
|
||||
inference.priority = p;
|
||||
if (inference.priority === undefined || priority < inference.priority) {
|
||||
inference.candidates = undefined;
|
||||
inference.contraCandidates = undefined;
|
||||
inference.priority = priority;
|
||||
}
|
||||
else if (p === inference.priority) {
|
||||
inference.candidates.push(source);
|
||||
if (priority === inference.priority) {
|
||||
if (contravariant) {
|
||||
inference.contraCandidates = append(inference.contraCandidates, source);
|
||||
}
|
||||
else {
|
||||
inference.candidates = append(inference.candidates, source);
|
||||
}
|
||||
}
|
||||
if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
|
||||
if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
|
||||
inference.topLevel = false;
|
||||
}
|
||||
}
|
||||
@ -11142,15 +11147,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) {
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
inferFromTypes((<IndexType>source).type, (<IndexType>target).type);
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
}
|
||||
else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) {
|
||||
const empty = createEmptyObjectTypeFromStringLiteral(source);
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
inferFromTypes(empty, (target as IndexType).type);
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
}
|
||||
else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
|
||||
inferFromTypes((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType);
|
||||
@ -11219,9 +11224,9 @@ namespace ts {
|
||||
|
||||
function inferFromContravariantTypes(source: Type, target: Type) {
|
||||
if (strictFunctionTypes) {
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
inferFromTypes(source, target);
|
||||
priority ^= InferencePriority.Contravariant;
|
||||
contravariant = !contravariant;
|
||||
}
|
||||
else {
|
||||
inferFromTypes(source, target);
|
||||
@ -11400,10 +11405,19 @@ namespace ts {
|
||||
// If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
|
||||
// union types were requested or if all inferences were made from the return type position, infer a
|
||||
// union type. Otherwise, infer a common supertype.
|
||||
const unwidenedType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) :
|
||||
context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, UnionReduction.Subtype) :
|
||||
const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ?
|
||||
getUnionType(baseCandidates, UnionReduction.Subtype) :
|
||||
getCommonSupertype(baseCandidates);
|
||||
inferredType = getWidenedType(unwidenedType);
|
||||
// If we have inferred 'never' but have contravariant candidates. To get a more specific type we
|
||||
// infer from the contravariant candidates instead.
|
||||
if (inferredType.flags & TypeFlags.Never && inference.contraCandidates) {
|
||||
inferredType = getCommonSubtype(inference.contraCandidates);
|
||||
}
|
||||
}
|
||||
else if (inference.contraCandidates) {
|
||||
// We only have contravariant inferences, infer the best common subtype of those
|
||||
inferredType = getCommonSubtype(inference.contraCandidates);
|
||||
}
|
||||
else if (context.flags & InferenceFlags.NoDefault) {
|
||||
// We use silentNeverType as the wildcard that signals no inferences.
|
||||
|
||||
@ -3826,20 +3826,19 @@ namespace ts {
|
||||
export type TypeMapper = (t: TypeParameter) => Type;
|
||||
|
||||
export const enum InferencePriority {
|
||||
Contravariant = 1 << 0, // Inference from contravariant position
|
||||
NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type
|
||||
MappedType = 1 << 2, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 3, // Inference made from return type of generic function
|
||||
NeverType = 1 << 4, // Inference made from the never type
|
||||
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
|
||||
MappedType = 1 << 1, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 2, // Inference made from return type of generic function
|
||||
}
|
||||
|
||||
export interface InferenceInfo {
|
||||
typeParameter: TypeParameter;
|
||||
candidates: Type[];
|
||||
inferredType: Type;
|
||||
priority: InferencePriority;
|
||||
topLevel: boolean;
|
||||
isFixed: boolean;
|
||||
typeParameter: TypeParameter; // Type parameter for which inferences are being made
|
||||
candidates: Type[]; // Candidates in covariant positions (or undefined)
|
||||
contraCandidates: Type[]; // Candidates in contravariant positions (or undefined)
|
||||
inferredType: Type; // Cache for resolved inferred type
|
||||
priority: InferencePriority; // Priority of current inference set
|
||||
topLevel: boolean; // True if all inferences are to top level occurrences
|
||||
isFixed: boolean; // True if inferences are fixed
|
||||
}
|
||||
|
||||
export const enum InferenceFlags {
|
||||
|
||||
@ -2178,15 +2178,14 @@ declare namespace ts {
|
||||
declaration?: SignatureDeclaration;
|
||||
}
|
||||
enum InferencePriority {
|
||||
Contravariant = 1,
|
||||
NakedTypeVariable = 2,
|
||||
MappedType = 4,
|
||||
ReturnType = 8,
|
||||
NeverType = 16,
|
||||
NakedTypeVariable = 1,
|
||||
MappedType = 2,
|
||||
ReturnType = 4,
|
||||
}
|
||||
interface InferenceInfo {
|
||||
typeParameter: TypeParameter;
|
||||
candidates: Type[];
|
||||
contraCandidates: Type[];
|
||||
inferredType: Type;
|
||||
priority: InferencePriority;
|
||||
topLevel: boolean;
|
||||
|
||||
@ -2178,15 +2178,14 @@ declare namespace ts {
|
||||
declaration?: SignatureDeclaration;
|
||||
}
|
||||
enum InferencePriority {
|
||||
Contravariant = 1,
|
||||
NakedTypeVariable = 2,
|
||||
MappedType = 4,
|
||||
ReturnType = 8,
|
||||
NeverType = 16,
|
||||
NakedTypeVariable = 1,
|
||||
MappedType = 2,
|
||||
ReturnType = 4,
|
||||
}
|
||||
interface InferenceInfo {
|
||||
typeParameter: TypeParameter;
|
||||
candidates: Type[];
|
||||
contraCandidates: Type[];
|
||||
inferredType: Type;
|
||||
priority: InferencePriority;
|
||||
topLevel: boolean;
|
||||
|
||||
@ -15,6 +15,16 @@ const x1 = f1(fo, fs); // (x: string) => void
|
||||
const x2 = f2("abc", fo, fs); // "abc"
|
||||
const x3 = f3("abc", fo, fx); // "abc" | "def"
|
||||
const x4 = f4(fo, fs); // Func<string>
|
||||
|
||||
declare const never: never;
|
||||
|
||||
const x10 = f2(never, fo, fs); // string
|
||||
const x11 = f3(never, fo, fx); // "def"
|
||||
|
||||
// Repro from #21112
|
||||
|
||||
declare function foo<T>(a: ReadonlyArray<T>): T;
|
||||
let x = foo([]); // never
|
||||
|
||||
|
||||
//// [strictFunctionTypes1.js]
|
||||
@ -23,6 +33,9 @@ var x1 = f1(fo, fs); // (x: string) => void
|
||||
var x2 = f2("abc", fo, fs); // "abc"
|
||||
var x3 = f3("abc", fo, fx); // "abc" | "def"
|
||||
var x4 = f4(fo, fs); // Func<string>
|
||||
var x10 = f2(never, fo, fs); // string
|
||||
var x11 = f3(never, fo, fx); // "def"
|
||||
var x = foo([]); // never
|
||||
|
||||
|
||||
//// [strictFunctionTypes1.d.ts]
|
||||
@ -40,3 +53,8 @@ declare const x1: (x: string) => void;
|
||||
declare const x2 = "abc";
|
||||
declare const x3: string;
|
||||
declare const x4: Func<string>;
|
||||
declare const never: never;
|
||||
declare const x10: string;
|
||||
declare const x11: "def";
|
||||
declare function foo<T>(a: ReadonlyArray<T>): T;
|
||||
declare let x: never;
|
||||
|
||||
@ -94,3 +94,34 @@ const x4 = f4(fo, fs); // Func<string>
|
||||
>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58))
|
||||
>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37))
|
||||
|
||||
declare const never: never;
|
||||
>never : Symbol(never, Decl(strictFunctionTypes1.ts, 17, 13))
|
||||
|
||||
const x10 = f2(never, fo, fs); // string
|
||||
>x10 : Symbol(x10, Decl(strictFunctionTypes1.ts, 19, 5))
|
||||
>f2 : Symbol(f2, Decl(strictFunctionTypes1.ts, 0, 79))
|
||||
>never : Symbol(never, Decl(strictFunctionTypes1.ts, 17, 13))
|
||||
>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58))
|
||||
>fs : Symbol(fs, Decl(strictFunctionTypes1.ts, 8, 37))
|
||||
|
||||
const x11 = f3(never, fo, fx); // "def"
|
||||
>x11 : Symbol(x11, Decl(strictFunctionTypes1.ts, 20, 5))
|
||||
>f3 : Symbol(f3, Decl(strictFunctionTypes1.ts, 1, 74))
|
||||
>never : Symbol(never, Decl(strictFunctionTypes1.ts, 17, 13))
|
||||
>fo : Symbol(fo, Decl(strictFunctionTypes1.ts, 6, 58))
|
||||
>fx : Symbol(fx, Decl(strictFunctionTypes1.ts, 9, 37))
|
||||
|
||||
// Repro from #21112
|
||||
|
||||
declare function foo<T>(a: ReadonlyArray<T>): T;
|
||||
>foo : Symbol(foo, Decl(strictFunctionTypes1.ts, 20, 30))
|
||||
>T : Symbol(T, Decl(strictFunctionTypes1.ts, 24, 21))
|
||||
>a : Symbol(a, Decl(strictFunctionTypes1.ts, 24, 24))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(strictFunctionTypes1.ts, 24, 21))
|
||||
>T : Symbol(T, Decl(strictFunctionTypes1.ts, 24, 21))
|
||||
|
||||
let x = foo([]); // never
|
||||
>x : Symbol(x, Decl(strictFunctionTypes1.ts, 25, 3))
|
||||
>foo : Symbol(foo, Decl(strictFunctionTypes1.ts, 20, 30))
|
||||
|
||||
|
||||
@ -100,3 +100,38 @@ const x4 = f4(fo, fs); // Func<string>
|
||||
>fo : (x: Object) => void
|
||||
>fs : (x: string) => void
|
||||
|
||||
declare const never: never;
|
||||
>never : never
|
||||
|
||||
const x10 = f2(never, fo, fs); // string
|
||||
>x10 : string
|
||||
>f2(never, fo, fs) : string
|
||||
>f2 : <T>(obj: T, f1: (x: T) => void, f2: (x: T) => void) => T
|
||||
>never : never
|
||||
>fo : (x: Object) => void
|
||||
>fs : (x: string) => void
|
||||
|
||||
const x11 = f3(never, fo, fx); // "def"
|
||||
>x11 : "def"
|
||||
>f3(never, fo, fx) : "def"
|
||||
>f3 : <T>(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void) => T
|
||||
>never : never
|
||||
>fo : (x: Object) => void
|
||||
>fx : (f: (x: "def") => void) => void
|
||||
|
||||
// Repro from #21112
|
||||
|
||||
declare function foo<T>(a: ReadonlyArray<T>): T;
|
||||
>foo : <T>(a: ReadonlyArray<T>) => T
|
||||
>T : T
|
||||
>a : ReadonlyArray<T>
|
||||
>ReadonlyArray : ReadonlyArray<T>
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
let x = foo([]); // never
|
||||
>x : never
|
||||
>foo([]) : never
|
||||
>foo : <T>(a: ReadonlyArray<T>) => T
|
||||
>[] : never[]
|
||||
|
||||
|
||||
@ -17,3 +17,13 @@ const x1 = f1(fo, fs); // (x: string) => void
|
||||
const x2 = f2("abc", fo, fs); // "abc"
|
||||
const x3 = f3("abc", fo, fx); // "abc" | "def"
|
||||
const x4 = f4(fo, fs); // Func<string>
|
||||
|
||||
declare const never: never;
|
||||
|
||||
const x10 = f2(never, fo, fs); // string
|
||||
const x11 = f3(never, fo, fx); // "def"
|
||||
|
||||
// Repro from #21112
|
||||
|
||||
declare function foo<T>(a: ReadonlyArray<T>): T;
|
||||
let x = foo([]); // never
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user