Get constraint with this argument of the type parameter for comparisons#21210
Conversation
| !!! 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.
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 thethistype correctly set, we now check() => U->() => U, which works as expected.