Skip to content

Commit dc40484

Browse files
committed
All Unmeasurable variances to still shortcut structural comparisons in some cases
1 parent 15f8c10 commit dc40484

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12842,6 +12842,22 @@ namespace ts {
1284212842
related = isRelatedTo(s, t, reportErrors);
1284312843
}
1284412844
}
12845+
else if (variance === Variance.Unmeasurable) {
12846+
if (isTypeAny(s) || isTypeAny(t)) {
12847+
// If the `s` or `t` type is `any`, even if the structural desugaring says that the types _shouldn't_
12848+
// be relatable, it's very surprising if they're not - take `Component<Foo, any>` to `Component<Foo, Foo>` - even
12849+
// if the `any` position is unmeasurable, it's incredibly surprising that such a reference wouldn't check out.
12850+
// (In fact, any nonlinear relation involving `any` is usually surprising) Even if it's potentially not correct
12851+
// according to our underlying structural rules, we persist that assumption here.
12852+
related = Ternary.True;
12853+
}
12854+
else {
12855+
// Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_.
12856+
// We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by
12857+
// the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be)
12858+
related = relation === identityRelation ? isRelatedTo(s, t, /*reportErrors*/ false) : compareTypesIdentical(s, t);
12859+
}
12860+
}
1284512861
else {
1284612862
// In the invariant case we first compare covariantly, and only when that
1284712863
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
@@ -13200,12 +13216,18 @@ namespace ts {
1320013216
return Ternary.False;
1320113217

1320213218
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: Variance[]) {
13203-
if (some(variances, v => v === Variance.Unmeasurable)) {
13204-
return undefined;
13205-
}
1320613219
if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) {
1320713220
return result;
1320813221
}
13222+
if (some(variances, v => v === Variance.Unmeasurable)) {
13223+
// If some type parameter was `Unmeasurable`, and we couldn't pass by assuming it was invariant, then we
13224+
// have to allow a structural fallback check
13225+
// We elide the variance-based error elaborations, since those might not be too helpful, since we'll potentially
13226+
// be assuming identity of the type parameter.
13227+
originalErrorInfo = undefined;
13228+
errorInfo = saveErrorInfo;
13229+
return undefined;
13230+
}
1320913231
const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances);
1321013232
varianceCheckFailed = !allowStructuralFallback;
1321113233
// The type arguments did not relate appropriately, but it may be because we have no variance

0 commit comments

Comments
 (0)