-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Fix flow node improper reuse #60662
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 flow node improper reuse #60662
Conversation
src/compiler/binder.ts
Outdated
if ((node as HasFlowNode).flowNode) { | ||
(node as HasFlowNode).flowNode = undefined; | ||
} |
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.
if ((node as HasFlowNode).flowNode) { | |
(node as HasFlowNode).flowNode = undefined; | |
} | |
if (canHaveFlowNode(node)) { | |
node.flowNode = undefined; | |
} |
To avoid casting, but also because I think it'll prevent negative perf effects from speculatively trying to access flowNode
on all nodes?
Then again, the binder does not currently import this function at all, and it's not used below where flowNode
is set, so maybe not.
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.
Calling canHaveFlowNode
is better than the cast as it accesses a property that is always present (kind
), vs. a property that may not be defined (flowNode
). The latter results in eager deoptimizations as a result of the missing property.
@typescript-bot perf test this |
@typescript-bot perf test this faster |
@gabritto Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
tsserverComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
startupComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@gabritto Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@typescript-bot perf test this faster |
@gabritto Here they are:
tscComparison Report - baseline..pr
System info unknown
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.
This looks good to me, though I am still on the fence about canHaveFlowNode
a bit. Maybe it was a bad suggestion.
Well, it at least prevents us from tacking |
I think it probably doesn't matter a lot? I think accesses to node properties in |
Fixes #60597.
The problem is caused by improper handling of node reuse across different versions of a source file. Say we have the following program:
We'll get a compiler error saying
returnabc
could not be found. And, when we bind the source file,return
will have its flow node set to a flow call node (corresponding toreturnabc()
).If we then edit the file to this:
We will reuse the node for
return
. However, because that node is unreachable, the binder will not assign a new flow node to that node, and it will preserve its old flow node. Now, when we check the source file, we expect it to have no errors, but thereturn
node will have a flow node for the old file, and that flow node will have a node that corresponds to thereturnabc()
call, and the checker will error on it when it visits that node.What this PR does is clean up the old flow node in the binder when a node is unreachable, because otherwise the flow node would not be updated.