-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Flag non-nullable functions in if
statements as errors (tree walk version)
#33178
Flag non-nullable functions in if
statements as errors (tree walk version)
#33178
Conversation
@@ -1362,18 +1362,16 @@ namespace ts { | |||
// try to verify results of module resolution | |||
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) { | |||
const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.originalFileName, currentDirectory); | |||
if (resolveModuleNamesWorker) { |
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.
Looks like resolveModuleNamesWorker
is always assigned above, so this was a dead check
@@ -1653,7 +1653,7 @@ namespace ts { | |||
*/ | |||
export function compose<T>(...args: ((t: T) => T)[]): (t: T) => T; | |||
export function compose<T>(a: (t: T) => T, b: (t: T) => T, c: (t: T) => T, d: (t: T) => T, e: (t: T) => T): (t: T) => T { | |||
if (e) { | |||
if (!!e) { |
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 is a pretty good example of what TS would now consider suspicious-enough code to error on. Making e
optional would also have fixed this.
@typescript-bot test this |
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
The RWC diff is unrelated. The User Test Suite diff is a false positive, but not a bad one: https://github.com/npm/cli/blob/latest/test/tap/check-permissions.js#L27 |
@typescript-bot perf test this |
Heya @RyanCavanaugh, I've started to run the perf test suite on this PR at 3c9e338. You can monitor the build here. It should now contribute to this PR's status checks. Update: The results are in! |
@RyanCavanaugh Here they are:Comparison Report - master..33178
System
Hosts
Scenarios
|
Hrm, none of these builds have accessible logs. I bet it's likely that community projects will need changes like: - if (e) {
+ if (!!e) { Will re-run and take a look. @typescript-bot test this |
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
…nonNullableCallSignaturesTreeWalk 🤖 User test baselines have changed for nonNullableCallSignaturesTreeWalk
OK, perf looks acceptable to me. The idea is a good one, and I feel good about the implementation - thanks @jwbay! |
@jwbay
|
@user753 a few major problems appeared when we tried that approach. Array access is optimistically assumed to be in-bounds, so code like this gets incorrectly flagged as an error. The same thing happens for const arr = [rec, rec, rec];
const el = arr[someIndex];
if (el) {
// do something
} Separately, many definition files were written prior to the introduction of Ultimately the very narrow check implemented here was the only one that didn't generate a huge amount of false positives. |
@RyanCavanaugh Thanks.
|
Normally if that does happen, a call to |
@jwbay this might be my favorite check this release. https://github.com/microsoft/vscode/blob/ecba37c6ef3aab85b7a9b15afb3610bbe4eaac8c/extensions/css-language-features/server/src/cssServerMain.ts#L78 |
It would be great if this was extended to functions that return promises as well. In the announcement for 3.7 (which I'm thrilled about!!!), you include this code example. function doAdminThing(user: User) {
if (user.isAdministrator) {
// ~~~~~~~~~~~~~~~~~~~~
// error! This condition will always return true since the function is always defined.
// Did you mean to call it instead?t It would be incredible if this was also extended to raise an error when the function returns a promise and it's not awaited before using it in a condition (I've personally been bitten by this exact bug before). class User {
// ...
async isAdministrator() { /* ... */ }
}
function doAdminThing(user: User) {
if (user.isAdministrator()) {
// ~~~~~~~~~~~~~~~~~~~~~~
// error! This condition will always return true since a promise is always truthy.
// Did you mean to await it instead? I tried searching for issues related to this but couldn't find any (it's possible that I just missed it because there are so many issues and I'm not sure what keywords to search). I've definitely been bitten by a bug where I did something like this: async function passwordMatches(email: string, password: string) {
/* return true if the password matches the result in the database */
}
if (passwordMatches("foo@bar.gov", "passw0rd")) {
/* issue auth token */
} |
Regarding Uncalled Function Checks, I think it'd be pretty safe to also error on this: function process() {
console.log('Processing...');
}
process; |
BTW this is breaking all of my polyfills, like checks for |
The problem with this is, it's not allowing any of the valid ways to pass. As @nebrelbug pointed above.
We had to adapt to this, which passes
|
This is an alternate version of #32802 -- see that one for context.
This version attempts to prevent false positives by doing a syntax walk to see if the checked function is used, as opposed to relying on a heuristic where the function returns a boolean. The first commit is the same for both PR; the second adds filtering that differs.
Opened as a separate PR by request (cc @RyanCavanaugh)
Notably, this change flagged a couple things in the compiler itself. Commented below for both.