Skip to content

Commit c79e70d

Browse files
committed
Fix small error made during merge, further optimize for cases involving any
1 parent f4d1289 commit c79e70d

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

src/compiler/checker.ts

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15581,29 +15581,44 @@ namespace ts {
1558115581
// is some specialization or subtype of Q
1558215582
// This is difficult to detect generally, so we scan for prior comparisons of the same instantiated type, and match up matching
1558315583
// type arguments into sets to create a canonicalization based on those matches
15584-
if (relation !== identityRelation && ((source.aliasSymbol && !source.aliasTypeArgumentsContainsMarker && source.aliasTypeArguments) || (getObjectFlags(source) & ObjectFlags.Reference && !!(<TypeReference>source).node && !(getObjectFlags(source) & ObjectFlags.MarkerType))) &&
15585-
((target.aliasSymbol && !target.aliasTypeArgumentsContainsMarker && target.aliasTypeArguments) || (getObjectFlags(target) & ObjectFlags.Reference && !!(<TypeReference>target).node && !(getObjectFlags(target) & ObjectFlags.MarkerType)))) {
15584+
if (relation !== identityRelation && ((source.aliasSymbol && !source.aliasTypeArgumentsContainsMarker && source.aliasTypeArguments) || (getObjectFlags(source) & ObjectFlags.Reference && !!getTypeArguments(<TypeReference>source).length && !(getObjectFlags(source) & ObjectFlags.MarkerType))) &&
15585+
((target.aliasSymbol && !target.aliasTypeArgumentsContainsMarker && target.aliasTypeArguments) || (getObjectFlags(target) & ObjectFlags.Reference && !!getTypeArguments(<TypeReference>target).length && !(getObjectFlags(target) & ObjectFlags.MarkerType)))) {
1558615586
if (source.aliasSymbol || target.aliasSymbol || (<TypeReference>source).target !== (<TypeReference>target).target) { // ensure like symbols are just handled by standard variance analysis
15587-
const originalKey = getRelationKey(source, target, intersectionState, relation);
1558815587
const sourceTypeArguments = source.aliasTypeArguments || getTypeArguments(<TypeReference>source);
15588+
const sourceHasMarker = some(sourceTypeArguments, a => a === markerOtherType);
1558915589
const targetTypeArguments = target.aliasTypeArguments || getTypeArguments(<TypeReference>target);
15590-
for (let i = 0; i < sourceTypeArguments.length; i++) {
15591-
for (let j = 0; j < targetTypeArguments.length; j++) {
15592-
if (!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && isTypeIdenticalTo(sourceTypeArguments[i], targetTypeArguments[j])) {
15593-
const sourceClone = sourceTypeArguments.slice();
15594-
sourceClone[i] = markerOtherType;
15595-
const s = getInstanceOfAliasOrReferenceWithMarker(source, sourceClone);
15596-
const targetClone = targetTypeArguments.slice();
15597-
targetClone[j] = markerOtherType;
15598-
const t = getInstanceOfAliasOrReferenceWithMarker(target, targetClone);
15599-
// If the marker-instantiated form looks "the same" as the type we already have (eg,
15600-
// because we replace unconstrained generics with unconstrained generics), skip the check
15601-
// since we'll otherwise deliver a spurious `Maybe` result from the key _just_ set upon
15602-
// entry into `recursiveTypeRelatedTo`
15603-
if (getRelationKey(s, t, intersectionState, relation) !== originalKey) {
15604-
const result = isRelatedTo(s, t, /*reportErrors*/ false);
15605-
if (result) {
15606-
return result;
15590+
const targetHasMarker = some(targetTypeArguments, a => a === markerOtherType);
15591+
// We're using `markerOtherType` as an existential, so we can't use it again if it's already in use,
15592+
// as we'd get spurious equivalencies - we'd need to use a second existential type, and once we're doing
15593+
// that we lose a lot of the benefit of canonicalizing back to a single-existential comparison, since then
15594+
// we'd need to manufacture new type identities for every new existential we make
15595+
// The above checks don't catch all cases this can occur, as they can only detect when the containing type
15596+
// was flagged during construction as containing a marker; however if a marker enters a type through instantiation
15597+
// we need to catch that here.
15598+
if (!sourceHasMarker && !targetHasMarker) {
15599+
const originalKey = getRelationKey(source, target, intersectionState, relation);
15600+
for (let i = 0; i < sourceTypeArguments.length; i++) {
15601+
for (let j = 0; j < targetTypeArguments.length; j++) {
15602+
if ((!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && !isTypeAny(sourceTypeArguments[i]) && isTypeIdenticalTo(sourceTypeArguments[i], targetTypeArguments[j])) ||
15603+
// Similarly, if we're comparing X<Q> to Z<any>, X<Q> is assignable to Z<any> trivially if X<?> is assignable to Z<?>
15604+
(!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && isTypeAny(targetTypeArguments[j])) ||
15605+
// Again, but for `X<any>` vs `Z<Q>`
15606+
(isTypeAny(sourceTypeArguments[i]) && !(targetTypeArguments[j].flags & TypeFlags.TypeParameter))) {
15607+
const sourceClone = sourceTypeArguments.slice();
15608+
sourceClone[i] = markerOtherType;
15609+
const s = getInstanceOfAliasOrReferenceWithMarker(source, sourceClone);
15610+
const targetClone = targetTypeArguments.slice();
15611+
targetClone[j] = markerOtherType;
15612+
const t = getInstanceOfAliasOrReferenceWithMarker(target, targetClone);
15613+
// If the marker-instantiated form looks "the same" as the type we already have (eg,
15614+
// because we replace unconstrained generics with unconstrained generics), skip the check
15615+
// since we'll otherwise deliver a spurious `Maybe` result from the key _just_ set upon
15616+
// entry into `recursiveTypeRelatedTo`
15617+
if (getRelationKey(s, t, intersectionState, relation) !== originalKey) {
15618+
const result = isRelatedTo(s, t, /*reportErrors*/ false);
15619+
if (result) {
15620+
return result;
15621+
}
1560715622
}
1560815623
}
1560915624
}

0 commit comments

Comments
 (0)