Skip to content

Commit 43d3dc8

Browse files
committed
Make lower priority inference when entire source is matched in target
1 parent 9920da2 commit 43d3dc8

File tree

1 file changed

+24
-32
lines changed

1 file changed

+24
-32
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15568,42 +15568,45 @@ namespace ts {
1556815568
return;
1556915569
}
1557015570
if (target.flags & TypeFlags.Union) {
15571-
if (source.flags & TypeFlags.Union) {
15572-
// First, infer between identically matching source and target constituents and remove the
15573-
// matching types.
15574-
const [tempSources, tempTargets] = inferFromMatchingTypes((<UnionType>source).types, (<UnionType>target).types, isTypeOrBaseIdenticalTo);
15575-
// Next, infer between closely matching source and target constituents and remove
15576-
// the matching types. Types closely match when they are instantiations of the same
15577-
// object type or instantiations of the same type alias.
15578-
const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy);
15579-
if (sources.length === 0 || targets.length === 0) {
15580-
return;
15581-
}
15582-
source = getUnionType(sources);
15583-
target = getUnionType(targets);
15571+
// First, infer between identically matching source and target constituents and remove the
15572+
// matching types.
15573+
const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (<UnionType>source).types : [source], (<UnionType>target).types, isTypeOrBaseIdenticalTo);
15574+
// Next, infer between closely matching source and target constituents and remove
15575+
// the matching types. Types closely match when they are instantiations of the same
15576+
// object type or instantiations of the same type alias.
15577+
const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy);
15578+
if (targets.length === 0) {
15579+
return;
1558415580
}
15585-
else {
15586-
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeOrBaseIdenticalTo)) return;
15587-
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeCloselyMatchedBy)) return;
15581+
target = getUnionType(targets);
15582+
if (sources.length === 0) {
15583+
// All source constituents have been matched and there is nothing further to infer from.
15584+
// However, simply making no inferences is undesirable because it could ultimately mean
15585+
// inferring a type parameter constraint. Instead, make a lower priority inference from
15586+
// the full source to whatever remains in the target. For example, when inferring from
15587+
// string to 'string | T', make a lower priority inference of string for T.
15588+
const savePriority = priority;
15589+
priority |= InferencePriority.NakedTypeVariable;
15590+
inferFromTypes(source, target);
15591+
priority = savePriority;
15592+
return;
1558815593
}
15594+
source = getUnionType(sources);
1558915595
}
1559015596
else if (target.flags & TypeFlags.Intersection && some((<IntersectionType>target).types, t => !!getInferenceInfoForType(t))) {
1559115597
// We reduce intersection types only when they contain naked type parameters. For example, when
1559215598
// inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
1559315599
// infer { extra: any } for T. But when inferring to 'string[] & Iterable<T>' we want to keep the
1559415600
// string[] on the source side and infer string for T.
15595-
if (source.flags & TypeFlags.Intersection) {
15601+
if (!(source.flags & TypeFlags.Union)) {
1559615602
// Infer between identically matching source and target constituents and remove the matching types.
15597-
const [sources, targets] = inferFromMatchingTypes((<IntersectionType>source).types, (<IntersectionType>target).types, isTypeIdenticalTo);
15603+
const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (<IntersectionType>source).types : [source], (<IntersectionType>target).types, isTypeIdenticalTo);
1559815604
if (sources.length === 0 || targets.length === 0) {
1559915605
return;
1560015606
}
1560115607
source = getIntersectionType(sources);
1560215608
target = getIntersectionType(targets);
1560315609
}
15604-
else if (!(source.flags & TypeFlags.Union)) {
15605-
if (inferFromMatchingType(source, (<IntersectionType>target).types, isTypeIdenticalTo)) return;
15606-
}
1560715610
}
1560815611
else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
1560915612
target = getActualTypeVariable(target);
@@ -15753,17 +15756,6 @@ namespace ts {
1575315756
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
1575415757
}
1575515758

15756-
function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean) {
15757-
let matched = false;
15758-
for (const t of targets) {
15759-
if (matches(source, t)) {
15760-
inferFromTypes(source, t);
15761-
matched = true;
15762-
}
15763-
}
15764-
return matched;
15765-
}
15766-
1576715759
function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] {
1576815760
let matchedSources: Type[] | undefined;
1576915761
let matchedTargets: Type[] | undefined;

0 commit comments

Comments
 (0)