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
no-unused-vars reports warning at incorrect position for recursive functions #13807
Comments
Demo link for anyone else who wants to try this. Thanks for the tip on the v7.1-v7.2 regression - that made it easy to track down. In #13354 and #13181, we intentionally changed I'm wondering if this is perhaps an unintended side effect of that change. Even in the primary motivating example (demo from the original issue), we report the last reference but not the last assignment. If I were to remove the assignment, the warning would disappear from the reference. I think the fix here might be to report the last assignment reference instead of just the last reference of any kind. (If there are no assignments, we'd still report the declaration.) Thus in Tagging @anikethsaha who made the original improvement. What do you think of my proposed change? |
I think we had a issue to reconsider the position again to declaration but not sure whether we reached a decision of not.
This seems much better than the current implement. +1 for this |
I'm unfamiliar with the way eslint works so pardon me if I'm suggesting something wild here, but wouldn't it possible to warn on every assignment where the variable goes unused before the end of the scope or the next assignment? eg: function test() {
let a = 5;
console.log(a);
a = 7; // warn here
a = 2;
console.log(a);
a = 9; // warn here too
} This is could be achieved by converting to SSA form, as all of these assignments would then be treated as "new" variables and it becomes obvious which ones are actually used and which ones are not. Although if we're not already converting to SSA at some point in the pipeline I guess it would add quite a bit of overhead. |
It's certainly doable, but I think out of scope for this rule. It could be a separate rule, like |
This also looks wrong: /* eslint no-unused-vars: error */
let a;
reset();
a = foo(a);
a = foo(a);
reset();
a = foo(a);
a = foo(a); // should report here?
function reset() {
a = 0; // reports here
} The reported location should probably never be inside an inner function, since we can't know if it's really the last assignment. |
I'm not sure I understand why it would be out of scope. If what I described is not the expected behaviour, then what exactly is the expected behaviour? Clearly, in all these examples, the variables are used, they're just not used after being reassigned. If we take the description of the rule from the documentation:
Most of the examples in this thread and in the issues linked to the original fix should report no error at all. |
This rule isn't intended to detect dead stores, but just variables that are never read. We did add some enhancements like #6348, which is to not count reads used to update the variable. Maybe we shouldn't have done that as it makes the scope unclear and causes confusion. Simply said, the purpose of this rule is to detect variables with zero read references. A few exceptions to this logic are documented as examples of incorrect code: // A read for a modification of itself is not considered as used.
var z = 0;
z = z + 1;
// Unused recursive functions also cause warnings.
function fact(n) {
if (n < 2) return 1;
return n * fact(n - 1);
} |
@mdjermanovic yes, I agree with your example there as well. So at least don't cross function boundaries. What about other scope boundaries? Example: /* eslint no-unused-vars: error */
let a;
reset();
a = foo(a);
a = foo(a);
reset();
a = foo(a);
a = foo(a); // should report here?
for(;;) {
a = 0;
}
if (foo()) {
a = 0; // or here?
} I think in this case I'd be fine warning inside of loops/conditionals and other block-like scopes since flow still proceeds roughly linearly from declaration to their entrance. Functions don't behave like that, so we shouldn't warn across function scopes. |
Agreed. While this makes sense if the right-hand of the assignment has no side effect, it causes confusing results with function calls: let a;
a = console.log(a); // Reports unused a
let b;
console.log(b); // Doesn't report unused b This behaviour is what caused me to believe that the intended effect of the rule was to report dead-stores. Maybe the scope of this rule should be reduced to match its description more strictly (only report if the variable is only ever declared or assigned but never read, always report at declaration, consider that being used in own right-hand of assignment is used), and make a separate rule for dead-stores that would catch a lot of the other issues that are discussed in this thread. The original improvement that you linked (#6348) would also be covered by a |
Unfortunately, it looks like there wasn't enough interest from the team Thanks for contributing to ESLint and we appreciate your understanding. |
environment
Node version: v14.4.0
npm version: v6.14.5
Local ESLint version: v7.12.1 (Currently used)
Global ESLint version: v7.8.1
parser
default
Configuration
Code being linted:
command used to lint the code
What did you expect to happen?
no-unused-var is triggered on the function declaration:
What actually happened? Please include the actual, raw output from ESLint.
no-unused-var is triggered on the last internal self-reference of the function:
Are you willing to submit a pull request to fix this bug?
I have never touched eslint's code but if someone would like to point me in the right direction I'm willing to submit a PR for this.
I would also like to note that this is a regression as eslint 7.1 correctly reports the warning at 1:10, it starts reporting the warning at 2:15 in version 7.2
The text was updated successfully, but these errors were encountered: