-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Get constraint with this argument of the type parameter for comparisons #21210
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
Conversation
@@ -39,7 +38,6 @@ tests/cases/compiler/fuzzy.ts(25,20): error TS2352: Type '{ oneI: this; }' canno | |||
!!! error TS2322: Types of property 'oneI' are incompatible. | |||
!!! error TS2322: Type 'this' is not assignable to type 'I'. | |||
!!! error TS2322: Type 'C' is not assignable to type 'I'. | |||
!!! error TS2322: Property 'alsoWorks' is missing in type 'C'. |
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 elaboration disappears as the comparison is now cached correctly and is the same comparison done above for the implements constraint check.
@ahejlsberg As mentioned in-person, I've also added the instantiation to the indexed access branch as discussed because it aught to be required, but there's a soundness issue which prevents the error from occurring in the test without the change: function swap<
T,
TContainer extends { member: T }
>(a: T, b: TContainer): TContainer {
const tmp = b.member;
b.member = a; // This is allowed because we check:
// T -> TContainer["member"]
// T -> T
// Assignment of T to TContainer["member"] erroneously permitted
// because TContainer["member"] is simplified to a constraint of T
// The constraint _should_ be "some (unknown) P which extends T"
// In fact, if you annotate an extra dummy generic that is just that,
// you'd see the assignment prevented.
a = tmp;
return b;
}
const obj = { member: { x: "", y: "" } };
swap({ x: "" }, obj).member.y; // Surprise! It doesn't exist! This hole prevents the same issue from appearing verbatim with indexed accesses; but because I suspect it could matter in the future I've included the fix anyway. I think #8474 is actually all about this hole. We could probably fix it nowadays, too (fix element access constraints/assignability with marker type variables, make initialized properties become invariant positions), but it'd likely be a bit breaky. In any case, I think the equivalent fix for indexed accesses is warranted, since diverging behavior between type variable kinds is undesirable, at least. |
506eeb1
to
7f49c62
Compare
@mhegazy asked for the perf data for this PR to ensure there's no perf regressions, so here's a 10 iteration comparison from my machine:
I don't see much of a difference, so I don't think this'll cause a blanket perf regression. |
LGTM, @ahejlsberg any comments? |
7f49c62
to
e43e1f8
Compare
@ahejlsberg We had a new report of the same bug with a much simpler test case: #24151 I've added it here and synced the branch - we really should accept this. |
Fixes #21117
Without doing so, in the given test case, when we check if our inference is assignable to the inference constraint, we get to comparing the methods and see
() => MessageList<T>
->() => U
, which is not assignable. By getting the constraint with thethis
type correctly set, we now check() => U
->() => U
, which works as expected.