@@ -15463,7 +15463,7 @@ namespace ts {
1546315463 let bivariant = false;
1546415464 let propagationType: Type;
1546515465 let inferenceCount = 0;
15466- let inferenceBlocked = false;
15466+ let inferenceIncomplete = false;
1546715467 let allowComplexConstraintInference = true;
1546815468 inferFromTypes(originalSource, originalTarget);
1546915469
@@ -15710,14 +15710,16 @@ namespace ts {
1571015710 function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) {
1571115711 let typeVariableCount = 0;
1571215712 if (targetFlags & TypeFlags.Union) {
15713+ let nakedTypeVariable: Type | undefined;
1571315714 const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
1571415715 const matched = new Array<boolean>(sources.length);
15715- const saveInferenceBlocked = inferenceBlocked ;
15716- inferenceBlocked = false;
15716+ const saveInferenceIncomplete = inferenceIncomplete ;
15717+ inferenceIncomplete = false;
1571715718 // First infer to types that are not naked type variables. For each source type we
1571815719 // track whether inferences were made from that particular type to some target.
1571915720 for (const t of targets) {
1572015721 if (getInferenceInfoForType(t)) {
15722+ nakedTypeVariable = t;
1572115723 typeVariableCount++;
1572215724 }
1572315725 else {
@@ -15728,21 +15730,18 @@ namespace ts {
1572815730 }
1572915731 }
1573015732 }
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+ const inferenceComplete = !inferenceIncomplete;
15734+ inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
15735+ // If the target has a single naked type variable and inference completed (meaning we
15736+ // explored the types fully), create a union of the source types from which no inferences
1573315737 // have been made so far and infer from that union to the naked type variable.
15734- if (typeVariableCount === 1 && !inferenceBlocked ) {
15738+ if (typeVariableCount === 1 && inferenceComplete ) {
1573515739 const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
1573615740 if (unmatched.length) {
15737- const s = getUnionType(unmatched);
15738- for (const t of targets) {
15739- if (getInferenceInfoForType(t)) {
15740- inferFromTypes(s, t);
15741- }
15742- }
15741+ inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
15742+ return;
1574315743 }
1574415744 }
15745- inferenceBlocked = inferenceBlocked || saveInferenceBlocked;
1574615745 }
1574715746 else {
1574815747 // We infer from types that are not naked type variables first so that inferences we
@@ -15839,7 +15838,7 @@ namespace ts {
1583915838 const symbol = isNonConstructorObject ? target.symbol : undefined;
1584015839 if (symbol) {
1584115840 if (contains(symbolStack, symbol)) {
15842- inferenceBlocked = true;
15841+ inferenceIncomplete = true;
1584315842 return;
1584415843 }
1584515844 (symbolStack || (symbolStack = [])).push(symbol);
@@ -15955,10 +15954,13 @@ namespace ts {
1595515954 }
1595615955
1595715956 function isMatchableType(type: Type) {
15957+ // We exclude non-anonymous object types because some frameworks (e.g. Ember) rely on the ability to
15958+ // infer between types that don't witness their type variables. Such types would otherwise be eliminated
15959+ // because they appear identical.
1595815960 return !(type.flags & TypeFlags.Object) || !!(getObjectFlags(type) & ObjectFlags.Anonymous);
1595915961 }
1596015962
15961- function typeIdenticalToSomeType (type: Type, types: Type[]): boolean {
15963+ function typeMatchedBySomeType (type: Type, types: Type[]): boolean {
1596215964 for (const t of types) {
1596315965 if (t === type || isMatchableType(t) && isMatchableType(type) && isTypeIdenticalTo(t, type)) {
1596415966 return true;
@@ -15968,12 +15970,12 @@ namespace ts {
1596815970 }
1596915971
1597015972 function findMatchedType(type: Type, target: UnionOrIntersectionType) {
15971- if (typeIdenticalToSomeType (type, target.types)) {
15973+ if (typeMatchedBySomeType (type, target.types)) {
1597215974 return type;
1597315975 }
1597415976 if (type.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral) && target.flags & TypeFlags.Union) {
1597515977 const base = getBaseTypeOfLiteralType(type);
15976- if (typeIdenticalToSomeType (base, target.types)) {
15978+ if (typeMatchedBySomeType (base, target.types)) {
1597715979 return base;
1597815980 }
1597915981 }
@@ -15987,7 +15989,7 @@ namespace ts {
1598715989 function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) {
1598815990 const reducedTypes: Type[] = [];
1598915991 for (const t of type.types) {
15990- if (!typeIdenticalToSomeType (t, typesToRemove)) {
15992+ if (!typeMatchedBySomeType (t, typesToRemove)) {
1599115993 reducedTypes.push(t);
1599215994 }
1599315995 }
0 commit comments