-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Improve excess property checking for intersections #32582
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
Improve excess property checking for intersections #32582
Conversation
Still a draft, the implementation needs improvement
This makes parameter lists a lot shorter. Seems like a slight improvement, although I can revert if I change my mind.
I think that using a mutable isIntersection in checkTypeRelatedTo is easier to read than extending the parameter lists yet again, but I can revert that commit if needed. (Assigned to @weswigham instead of requesting since the requested reviewers list is broken.) |
src/compiler/checker.ts
Outdated
@@ -29587,7 +29602,7 @@ namespace ts { | |||
} | |||
else { | |||
// Only here do we need to check that the initializer is assignable to the enum type. | |||
checkTypeAssignableTo(checkExpression(initializer), getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), initializer, /*headMessage*/ undefined); | |||
checkTypeAssignableTo(checkExpression(initializer), getDeclaredTypeOfSymbol(getSymbolOfNode(member.parent)), initializer); |
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.
??? Why was the parameter removed here? AFAIK passing /*headMessage*/ undefined
disables error reporting, no?
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.
not passing it also disables error reporting. I ran a cleanup regex and it applied to this usage too. If you want to keep it to help readability, I can put it back.
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.
Nah, it's fine.
src/compiler/checker.ts
Outdated
@@ -12849,13 +12849,15 @@ namespace ts { | |||
} | |||
} | |||
else if (target.flags & TypeFlags.Intersection) { | |||
isIntersectionConstituent = true; // set here to affect the following trio of checks |
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.
So this affected the recursiveTypeRelatedTo
call after this else if
block (if the contents of the block did not cause a return) before (the third check of the trio
referenced in the comment), but now nothing does. Was the change intentional?
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.
I think so (the intervening vacation makes things a bit fuzzy). I think I decided it could be dispensed with entirely because isIntersectionConstituent is now set in typeRelatedToEachType (line 13152) instead of here. But it may be there is a difference and that our tests just don't catch it.
In any case, after leaving this PR for a while, I kind of like the threaded-parameter approach. I'm going to measure performance on both commits to make sure that there are no weird limits on parameter count in the VM and go back to explicit parameters if there's no perf difference.
@typescript-bot perf test this |
Heya @sandersn, I've started to run the perf test suite on this PR at 74113b3. You can monitor the build here. It should now contribute to this PR's status checks. Update: The results are in! |
@sandersn Here they are:Comparison Report - master..32582
System
Hosts
Scenarios
|
This reverts commit b8dccff.
OK, I reverted the use of a mutable variable to track isIntersectionConstituent. Now it's back to being a parameter threaded through various functions. @typescript-bot perf test this |
Heya @sandersn, I've started to run the perf test suite on this PR at b8507d2. You can monitor the build here. It should now contribute to this PR's status checks. Update: The results are in! |
@sandersn Here they are:Comparison Report - master..32582
System
Hosts
Scenarios
|
Perf numbers are about the same both ways. @weswigham can you take a look at the parameter-threaded management of |
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.
I'm still concerned that isIntersectionConstituent
needs to somehow be included in the relation cache ID - but I had that concern before this PR (and nobody's yet submitted a bug making that concern real), so I suppose nothing has changed.
@@ -13584,7 +13584,7 @@ namespace ts { | |||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) { | |||
// Report structural errors only if we haven't reported any errors yet | |||
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !sourceIsPrimitive; | |||
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined); | |||
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, isIntersectionConstituent); |
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.
Yep, seeing this change here, I have a vague memory of thinking that I didn't need to pass it thru here before because we didn't do deep excess property checking - now that we do, we should.
Excess property checking incorrectly applies to half of an intersection when nested deeply enough because
isIntersectionConstituent
is not sufficiently threaded through thecheckTypeRelatedTo
code. This PR threadsisIntersectionConstituent
through several more places.I may scope
isIntersectionConstituent
to the entirety ofcheckTypeRelatedTo
and mutate it in a dynamically scoped way. The fix works as-is, but I think it would be simpler to mutate a variable instead of adding parameters.Fixes #30715