-
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
[WIP] Support condition always true in prefix unary expression #60068
base: main
Are you sure you want to change the base?
[WIP] Support condition always true in prefix unary expression #60068
Conversation
…lways-true-in-prefix-unary-expression
@typescript-bot test it |
Hey @gabritto, the results of running the DT tests are ready. There were interesting changes: Branch only errors:Package: js-fixtures
Package: xdate
Package: activex-excel
Package: morgan
Package: yandex-maps
Package: bluebird
|
@gabritto Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
@gabritto Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@gabritto Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
@tjenkinson I think both the function and promise cases will require some extra work for avoiding most of the false errors. Let me know if you'd still like to keep working on it, I think it's a very good feature since we had at least 3 bugs detected in the extended tests. |
hey @gabritto thanks for looking through them super promising it found some actual issues. Do you think we'll need to handle cases like this one where the usage happens later and is not part of the Happy to continue digging but I think that will be a bit more complex looking at how things are structured at the moment as |
Actually maybe this is a different kind of check. If there's an
I'm not sure if (2) will happen much in the wild so maybe the 1st will be enough |
Also not sure https://github.com/microsoft/vscode/blob/f71675cbd9ba6aef444321cbe5faf8dd81340e3b/extensions/emmet/src/test/abbreviationAction.test.ts#L223 is a false error? Looking at the types |
I think you are right in this case. However, I think we should still support that case to avoid false errors in code written in a similar way. |
d2604e2
to
8715473
Compare
4e7fe97
to
8f8b45c
Compare
|
||
function next() { | ||
let task = tasks[index] | ||
if (!task) { |
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 might also have to bail if the source is accessing something from an array 🤔
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 case looks like a bug in your PR code: we should not be erroring because task
is used inside the else
block.
Hey @gabritto I've pushed some changes so that now it should only apply if there's a single Still need to add tests, but would be great if you could run the run the extended tests again and we could see if this reduces the false positives? Also might need to add some logic to bail if it's accessing an item from an array |
@typescript-bot test it |
instead of just `if (!object.fnOrPromise)`
@gabritto Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
Hey @gabritto, the results of running the DT tests are ready. There were interesting changes: Branch only errors:Package: morgan
Package: activex-excel
Package: activex-shell
Package: xdate
Package: js-fixtures
Package: yandex-maps
|
@gabritto Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@gabritto Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
@gabritto Here are some more interesting changes from running the top 400 repos suite Details
|
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 left some questions, but also, can you add some tests so we can track which cases are currently supported and which are not, and which are potential false errors? Otherwise, it's hard for me to remember in between reviews.
@@ -44588,8 +44593,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||
return; | |||
} | |||
|
|||
const isUsedInBody = inverted && isIfStatement(condExpr.parent) ? testedSymbol && isSymbolUsedInConditionBody(location, condExpr.parent.parent, testedNode, testedSymbol, /*checkForAssignment*/ true) : testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol, /*checkForAssignment*/ false); |
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 do we call isSymbolUsedInConditionBody
with location
instead of condExpr
, in the first case?
|
||
function next() { | ||
let task = tasks[index] | ||
if (!task) { |
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 case looks like a bug in your PR code: we should not be erroring because task
is used inside the else
block.
@@ -44606,15 +44613,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||
} | |||
} | |||
|
|||
function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean { | |||
function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression | Node, testedNode: Node, testedSymbol: Symbol, checkForAssignment: boolean): boolean { |
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.
What's the idea here behind checkForAssignment
? Why were the previous checks being done here in isSymbolUsedInConditionBody
not enough?
const location = isLogicalOrCoalescingBinaryExpression(condExpr) ? skipParentheses(condExpr.right) : condExpr; | ||
let location = condExpr; | ||
let inverted = false; | ||
if (isPrefixUnaryExpression(location)) { |
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 you also need to check that the operator is the exclamation token. Otherwise location
could be another kind of expression, e.g. ++a
.
let inverted = false; | ||
if (isPrefixUnaryExpression(location)) { | ||
location = skipParentheses(location.operand); | ||
inverted = true; |
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.
Another thing to consider (and probably add a test) is that we can have an expression that flips between the negative and positive case, if we have nested negation expressions, e.g.: if (a && !(b || !c)) ...
Opening as draft for now so we can run the extended tests and see how much breakage there is. See #46140 (comment)
cc @gabritto
Fixes #46140