-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Fix type parameter comparability to consistently allow comparisons on unconstrained type parameters #48861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix type parameter comparability to consistently allow comparisons on unconstrained type parameters #48861
Conversation
… unconstrained type parameters
@typescript-bot pack this |
Heya @weswigham, I've started to run the tarball bundle task on this PR at 57f17bb. You can monitor the build here. |
Heya @weswigham, I've started to run the diff-based community code test suite on this PR at 57f17bb. You can monitor the build here. Update: The results are in! |
Heya @weswigham, I've started to run the extended test suite on this PR at 57f17bb. You can monitor the build here. |
Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at 57f17bb. You can monitor the build here. |
Heya @weswigham, I've started to run the perf test suite on this PR at 57f17bb. You can monitor the build here. Update: The results are in! |
src/compiler/checker.ts
Outdated
@@ -19549,7 +19563,7 @@ namespace ts { | |||
if (sourceFlags & TypeFlags.TypeVariable) { | |||
// IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch | |||
if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { | |||
const constraint = getConstraintOfType(source as TypeVariable); | |||
const constraint = getConstraintOfType(source as TypeVariable) || unknownType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the core of this fix. This is really all we need to make it so T extends unknown
and a bare T
are actually treated identically.
src/compiler/checker.ts
Outdated
@@ -19338,6 +19338,20 @@ namespace ts { | |||
} | |||
} | |||
} | |||
if (relation === comparableRelation && sourceFlags & TypeFlags.TypeParameter) { | |||
// This is a carve-out in comparability to essentially forbid comparing a type parameter | |||
// with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This, meanwhile, is a change to make is slightly more strict in all circumstances involving comparing one type parameter to another (regardless if one or both are constrained) so we still forbid comparing two unrelated type parameters, despite the below change.
|
||
case 2: x; break; // T & 2 | ||
>2 : 2 | ||
>x : T & 2 | ||
>x : (T & 1) | (T & 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fallout from permissive comparability: We use comparability in switch-case narrowing (in narrowTypeBySwitchOnDiscriminant
) and since T
is unconstrained and thus extends unknown
, both the 1
and 2
intersections are considered comparable with both 1
and 2
because of the T
part. Some extra work could possibly be done to prevent this by changing how comparability works over intersections, probably.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(It's likely a similar change occurs in narrowing assignments, since we also use bidirectional comparability there, and maybe in other places more subtly since we use unidirectional comparability in narrowTypeByDiscriminant
)
@weswigham |
Hey @weswigham, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
@weswigham Here they are:Comparison Report - main..48861
System
Hosts
Scenarios
Developer Information: |
@typescript-bot pack this |
Heya @weswigham, I've started to run the diff-based community code test suite on this PR at 4c7e818. You can monitor the build here. Update: The results are in! |
Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at 4c7e818. You can monitor the build here. |
Heya @weswigham, I've started to run the tarball bundle task on this PR at 4c7e818. You can monitor the build here. |
Heya @weswigham, I've started to run the perf test suite on this PR at 4c7e818. You can monitor the build here. Update: The results are in! |
Heya @weswigham, I've started to run the extended test suite on this PR at 4c7e818. You can monitor the build here. |
@weswigham |
Hey @weswigham, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
@weswigham Here they are:Comparison Report - main..48861
System
Hosts
Scenarios
Developer Information: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable from a glance. I'd get another sign off, and I'd be curious to get Ryan's take on this before 4.7 goes out (though I think the new carve-out was the only thing he and I had ever discussed where the more-restrictive behavior was compelling).
@ahejlsberg do you feel comfortable with us bringing this in? |
@DanielRosenwasser do you still want to cherry pick this for 4.7? |
*unless those comparisons to against other unrelated type parameters, since those are a stronger signal that the types are meant to be separate domains.
This is a change in philosophy to the more permissive side in the general case - comparability now consistently succeeds when relating any two types that overlap, unless the two are type parameters that don't extend one another in some way.
Fixes #48680