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
Update: Fix && vs || short-circuiting false negatives (fixes #13634) #13769
Conversation
When `constructor-super`, `no-throw-literal`, and `prefer-promise-reject-errors` are looking for plausible constructor or error values, they fail to consider the short-circuiting behavior differences between the `&&` and `||` operators. This results in a false negative where these rules allow `foo && 42` when that expression cannot be a constructor or error. If the left side is falsy, the expression short-circuits with the falsy value. If the left side is truthy, the result of the expression is the right side value. All three rules already report the right side value in isolation but currently incorrectly allow it when on the right side of an `&&` expression. When @mdjermanovic added support for logical assignment operators, we decided to ship with the corrected behavior for `&&=` by only checking the right side of the expression, accepting that treatment of `&&=` would be inconsistent with existing treatment of `&&`. This PR then fixes the `&&` treatment in what we believe can be a semver-minor bug fix. A future improvement could detect statically falsy values on the left side of `&&` expressions and report those as well. Such a change could also update the `||` treatment to ignore plausibly-(constructor|error) values on the right side if the left side is statically truthy but not plausibly a constructor or error, so `42 || foo` should fail.
// A future improvement could detect the left side as statically falsy, making this false. | ||
"false && foo": 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.
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.
LGTM, thanks!
Co-authored-by: Nicholas C. Zakas <nicholas@nczconsulting.com>
There were no concerns expressed, so marking as accepted and merging for a minor version. |
Prerequisites checklist
What is the purpose of this pull request? (put an "X" next to an item)
[ ] Documentation update
[x] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:
Bug report copied from #13634.
Tell us about your environment
What parser (default,
@babel/eslint-parser
,@typescript-eslint/parser
, etc.) are you using?default
Please show your full configuration:
Configuration
What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.
Demo
What did you expect to happen?
We should report errors in each of the above cases. All three are looking for a specific type of truthy value from the expression. Because the expression uses
&&
, any possibly-valid value would evaluate to the right side of the expression, which would not be a valid value in these examples.This was originally discovered in #13618 (comment). Because it relates to existing behavior that existed prior to that pull request, we decided to split it into its own issue that can be fixed after the pull request is merged. This bug is a false negative in the 3 rules above, and fixing it would cause them to report more errors. Does anyone object to fixing this in a semver-minor change as allowed by our semver policy?
The fix would update both
astUtils.couldBeError()
andconstructor-super
'sisPossibleConstructor()
to only check the right side of&&
LogicalExpression
s.What actually happened? Please include the actual, raw output from ESLint.
No errors are reported.
What changes did you make? (Give an overview)
When
constructor-super
,no-throw-literal
, andprefer-promise-reject-errors
are looking for plausible constructor or error values, they fail to consider the short-circuiting behavior differences between the&&
and||
operators. This results in a false negative where these rules allowfoo && 42
when that expression cannot be a constructor or error. If the left side is falsy, the expression short-circuits with the falsy value. If the left side is truthy, the result of the expression is the right side value. All three rules already report the right side value in isolation but currently incorrectly allow it when on the right side of an&&
expression.When @mdjermanovic added support for logical assignment operators in #13618, we decided to ship with the corrected behavior for
&&=
by only checking the right side of the expression, accepting that treatment of&&=
would be inconsistent with existing treatment of&&
. This PR then fixes the&&
treatment in what we believe can be a semver-minor bug fix.Is there anything you'd like reviewers to focus on?
Does everyone else agree with @mdjermanovic and me that this is can be a semver-minor bug fix?
A future improvement could detect statically falsy values on the left side of
&&
expressions and report those as well. Such a change could also update the||
treatment to ignore plausibly-(constructor|error) values on the right side if the left side is statically truthy but not plausibly a constructor or error, so42 || foo
should fail.