-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Add inference for 'Promise' based on call to 'resolve' #40466
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
@typescript-bot perf test |
Heya @rbuckton, I've started to run the perf test suite on this PR at 56a9871. You can monitor the build here. Update: The results are in! |
@rbuckton Here they are:Comparison Report - master..40466
System
Hosts
Scenarios
|
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
From the user test baselines:
|
For our RWC test suite, this fixes (and thus removes) a number of errors due to the improved inference. |
DT Tests passed, and the perf tests show no major perf regressions (numbers look about the same). |
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 kind of uncomfortable with a change like this given how hyper-specific it is. To be honest, I'm not even sure whether removing the optionality of the resolve
parameter is worth the cumulative changes so far.
@@ -6903,4 +6903,77 @@ namespace ts { | |||
return bindParentToChildIgnoringJSDoc(child, parent) || bindJSDoc(child); | |||
} | |||
} | |||
|
|||
export function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile) { |
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 won't work on something with Unicode escapes. It's not a blocker, but it'd be very strange.
new Promise(resolve => {
\u0072\u0065\u0073\u006f\u006c\u0076\u0065(100);
})
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.
True, and that's documented in the find-all-references code where this function originally came from. Its unfortunate, but this heuristic is intended to improve inference in a very specific case. It might be feasible to rewrite the function to be a bit smarter (though possibly slower), by scanning the text instead of using .indexOf
. That would likely help with find-all-references as well.
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.
(Though I'm not sure a reasonable change based on scanning could be made prior to 4.1-beta)
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.
Actually, scratch that. Its feasible to do. The implementation that supports unicode escapes depends on using a regular expression, so is costlier. I have a version I can push that actually tracks on the source file whether it contains identifiers with unicode escapes, and if it doesn't then it can use the existing indexOf
logic, which should be faster:
I might wait on that until after this PR, however, as I'd need to also add fourslash tests for find-all-references which could be time consuming and could possibly wait until after 4.1-beta.
With my limited insight, this heuristic seems similar to what I requested in #36456. Would that be feasible if this PR is the way to go forward? |
This experiment is pretty old, so I'm going to close it to reduce the number of open PRs. |
In #39817, we introduced a breaking change in the signature of
PromiseConstructor
to ensure it is more type-safe. This unfortunately results in new errors. One class of these errors relates to code like the following:This is now an error due to the fact the type we infer for an untyped
Promise
with no contextual type isunknown
. While this can be addressed by annotatingPromise
with the typevoid
(i.e.,new Promise<void>(resolve => ...)
), this PR looks to address this case by introducing an inference heuristic around the "revealing constructor" pattern used by thePromise
constructor.A "revealing constructor" is a class that accepts a callback in its constructor that the constructor then invokes, providing access to one or more privileged callbacks passed as arguments:
When you create a new
Promise
, the constructor will invoke theexecutor
callback with two callbacks of its own:resolve
andreject
.This PR introduces inference for this very specific heuristic, such that:
The specific heuristic used for inference is as follows:
Attempt to solve for
T
innew C<T>(f => f(t))
:NewExpression
T
must only accept a single parameter (pA)executor: (resolve: (value: T | PromiseLike<T>) => void) => void
)resolve: (value: T | PromiseLike<T>) => void
)value: T | PromiseLike<T>
)If the above conditions are met then:
These inferences are given a very low priority so that inference from contextual types will have a higher priority.
Related #40231, #39817