@@ -15577,7 +15577,7 @@ namespace ts {
1557715577 // Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine
1557815578 const simplified = getSimplifiedType(target, /*writing*/ false);
1557915579 if (simplified !== target) {
15580- inferFromTypesOnce (source, simplified);
15580+ invokeOnce (source, simplified, inferFromTypes );
1558115581 }
1558215582 else if (target.flags & TypeFlags.IndexedAccess) {
1558315583 const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false);
@@ -15586,7 +15586,7 @@ namespace ts {
1558615586 if (indexType.flags & TypeFlags.Instantiable) {
1558715587 const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false);
1558815588 if (simplified && simplified !== target) {
15589- inferFromTypesOnce (source, simplified);
15589+ invokeOnce (source, simplified, inferFromTypes );
1559015590 }
1559115591 }
1559215592 }
@@ -15621,15 +15621,12 @@ namespace ts {
1562115621 inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
1562215622 inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
1562315623 }
15624- else if (target.flags & TypeFlags.Union) {
15625- inferToUnionType(source, <UnionType>target);
15626- }
15627- else if (target.flags & TypeFlags.Intersection) {
15628- inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, /*isIntersection*/ true);
15629- }
1563015624 else if (target.flags & TypeFlags.Conditional && !contravariant) {
1563115625 const targetTypes = [getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)];
15632- inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false);
15626+ inferToMultipleTypes(source, targetTypes, target.flags);
15627+ }
15628+ else if (target.flags & TypeFlags.UnionOrIntersection) {
15629+ inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, target.flags);
1563315630 }
1563415631 else if (source.flags & TypeFlags.Union) {
1563515632 // Source is a union or intersection type, infer from each constituent type
@@ -15658,50 +15655,22 @@ namespace ts {
1565815655 source = apparentSource;
1565915656 }
1566015657 if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
15661- const key = source.id + "," + target.id;
15662- const visitCount = visited && visited.get(key);
15663- if (visitCount !== undefined) {
15664- inferenceCount += visitCount;
15665- return;
15666- }
15667- (visited || (visited = createMap<number>())).set(key, 0);
15668- // If we are already processing another target type with the same associated symbol (such as
15669- // an instantiation of the same generic type), we do not explore this target as it would yield
15670- // no further inferences. We exclude the static side of classes from this check since it shares
15671- // its symbol with the instance side which would lead to false positives.
15672- const startCount = inferenceCount;
15673- const isNonConstructorObject = target.flags & TypeFlags.Object &&
15674- !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
15675- const symbol = isNonConstructorObject ? target.symbol : undefined;
15676- if (symbol) {
15677- if (contains(symbolStack, symbol)) {
15678- inferenceBlocked = true;
15679- return;
15680- }
15681- (symbolStack || (symbolStack = [])).push(symbol);
15682- inferFromObjectTypes(source, target);
15683- symbolStack.pop();
15684- }
15685- else {
15686- inferFromObjectTypes(source, target);
15687- }
15688- visited.set(key, inferenceCount - startCount);
15658+ invokeOnce(source, target, inferFromObjectTypes);
1568915659 }
1569015660 }
15661+ }
1569115662
15692- function inferFromTypesOnce(source: Type, target: Type) {
15693- const key = source.id + "," + target.id;
15694- const count = visited && visited.get(key);
15695- if (count !== undefined) {
15696- inferenceCount += count;
15697- }
15698- else {
15699- (visited || (visited = createMap<number>())).set(key, 0);
15700- const startCount = inferenceCount;
15701- inferFromTypes(source, target);
15702- visited.set(key, inferenceCount - startCount);
15703- }
15663+ function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) {
15664+ const key = source.id + "," + target.id;
15665+ const count = visited && visited.get(key);
15666+ if (count !== undefined) {
15667+ inferenceCount += count;
15668+ return;
1570415669 }
15670+ (visited || (visited = createMap<number>())).set(key, 0);
15671+ const startCount = inferenceCount;
15672+ action(source, target);
15673+ visited.set(key, inferenceCount - startCount);
1570515674 }
1570615675
1570715676 function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) {
@@ -15738,76 +15707,64 @@ namespace ts {
1573815707 return undefined;
1573915708 }
1574015709
15741- function inferToMultipleTypes(source: Type, targets: Type[], isIntersection: boolean) {
15742- // We infer from types that are not naked type variables first so that inferences we
15743- // make from nested naked type variables and given slightly higher priority by virtue
15744- // of being first in the candidates array.
15710+ function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) {
1574515711 let typeVariableCount = 0;
15746- for (const t of targets) {
15747- if (getInferenceInfoForType(t)) {
15748- typeVariableCount++;
15712+ if (targetFlags & TypeFlags.Union) {
15713+ const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
15714+ const matched = new Array<boolean>(sources.length);
15715+ const saveInferenceBlocked = inferenceBlocked;
15716+ inferenceBlocked = false;
15717+ // First infer to types that are not naked type variables. For each source type we
15718+ // track whether inferences were made from that particular type to some target.
15719+ for (const t of targets) {
15720+ if (getInferenceInfoForType(t)) {
15721+ typeVariableCount++;
15722+ }
15723+ else {
15724+ for (let i = 0; i < sources.length; i++) {
15725+ const count = inferenceCount;
15726+ inferFromTypes(sources[i], t);
15727+ if (count !== inferenceCount) matched[i] = true;
15728+ }
15729+ }
1574915730 }
15750- else {
15751- inferFromTypes(source, t);
15731+ // If the target has a single naked type variable and inference wasn't blocked (meaning
15732+ // we explored the types fully), create a union of the source types from which no inferences
15733+ // have been made so far and infer from that union to the naked type variable.
15734+ if (typeVariableCount === 1 && !inferenceBlocked) {
15735+ const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
15736+ if (unmatched.length) {
15737+ const s = getUnionType(unmatched);
15738+ for (const t of targets) {
15739+ if (getInferenceInfoForType(t)) {
15740+ inferFromTypes(s, t);
15741+ }
15742+ }
15743+ }
1575215744 }
15745+ inferenceBlocked = inferenceBlocked || saveInferenceBlocked;
1575315746 }
15754- // Inferences directly to naked type variables are given lower priority as they are
15755- // less specific. For example, when inferring from Promise<string> to T | Promise<T>,
15756- // we want to infer string for T, not Promise<string> | string. For intersection types
15757- // we only infer to single naked type variables.
15758- if (isIntersection ? typeVariableCount === 1 : typeVariableCount !== 0) {
15759- const savePriority = priority;
15760- priority |= InferencePriority.NakedTypeVariable;
15747+ else {
15748+ // We infer from types that are not naked type variables first so that inferences we
15749+ // make from nested naked type variables and given slightly higher priority by virtue
15750+ // of being first in the candidates array.
1576115751 for (const t of targets) {
1576215752 if (getInferenceInfoForType(t)) {
15763- inferFromTypes(source, t) ;
15753+ typeVariableCount++ ;
1576415754 }
15765- }
15766- priority = savePriority;
15767- }
15768- }
15769-
15770- function inferToUnionType(source: Type, target: UnionType) {
15771- const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
15772- const matched = new Array<boolean>(sources.length);
15773- let typeVariableCount = 0;
15774- const saveInferenceBlocked = inferenceBlocked;
15775- inferenceBlocked = false;
15776- // First infer to types that are not naked type variables. For each source type we
15777- // track whether inferences were made from that particular type to some target.
15778- for (const t of target.types) {
15779- if (getInferenceInfoForType(t)) {
15780- typeVariableCount++;
15781- }
15782- else {
15783- for (let i = 0; i < sources.length; i++) {
15784- const count = inferenceCount;
15785- inferFromTypes(sources[i], t);
15786- if (count !== inferenceCount) matched[i] = true;
15787- }
15788- }
15789- }
15790- // If there are naked type variables in the target, create a union of the source types
15791- // from which no inferences have been made so far and infer from that union to each naked
15792- // type variable. If there is more than one naked type variable, or if inference was blocked
15793- // (meaning we didn't explore the types fully), give lower priority to the inferences as
15794- // they are less specific.
15795- if (typeVariableCount === 1 && !inferenceBlocked) {
15796- const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
15797- if (unmatched.length) {
15798- const s = getUnionType(unmatched);
15799- for (const t of target.types) {
15800- if (getInferenceInfoForType(t)) {
15801- inferFromTypes(s, t);
15802- }
15755+ else {
15756+ inferFromTypes(source, t);
1580315757 }
1580415758 }
1580515759 }
15806- inferenceBlocked = inferenceBlocked || saveInferenceBlocked;
15807- if (typeVariableCount > 0) {
15760+ // Inferences directly to naked type variables are given lower priority as they are
15761+ // less specific. For example, when inferring from Promise<string> to T | Promise<T>,
15762+ // we want to infer string for T, not Promise<string> | string. For intersection types
15763+ // we only infer to single naked type variables.
15764+ if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) {
1580815765 const savePriority = priority;
1580915766 priority |= InferencePriority.NakedTypeVariable;
15810- for (const t of target.types ) {
15767+ for (const t of targets ) {
1581115768 if (getInferenceInfoForType(t)) {
1581215769 inferFromTypes(source, t);
1581315770 }
@@ -15873,6 +15830,28 @@ namespace ts {
1587315830 }
1587415831
1587515832 function inferFromObjectTypes(source: Type, target: Type) {
15833+ // If we are already processing another target type with the same associated symbol (such as
15834+ // an instantiation of the same generic type), we do not explore this target as it would yield
15835+ // no further inferences. We exclude the static side of classes from this check since it shares
15836+ // its symbol with the instance side which would lead to false positives.
15837+ const isNonConstructorObject = target.flags & TypeFlags.Object &&
15838+ !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
15839+ const symbol = isNonConstructorObject ? target.symbol : undefined;
15840+ if (symbol) {
15841+ if (contains(symbolStack, symbol)) {
15842+ inferenceBlocked = true;
15843+ return;
15844+ }
15845+ (symbolStack || (symbolStack = [])).push(symbol);
15846+ inferFromObjectTypesWorker(source, target);
15847+ symbolStack.pop();
15848+ }
15849+ else {
15850+ inferFromObjectTypesWorker(source, target);
15851+ }
15852+ }
15853+
15854+ function inferFromObjectTypesWorker(source: Type, target: Type) {
1587615855 if (isGenericMappedType(source) && isGenericMappedType(target)) {
1587715856 // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer
1587815857 // from S to T and from X to Y.
0 commit comments