-
-
Notifications
You must be signed in to change notification settings - Fork 186
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
Fix js2-node-get-enclosing-scope on a statement function's name #474
Conversation
Any concerns about performance?
|
@dgutov it's just an initial extra-check, it's outside the loop, so I wouldn't worry about it. Besides, correctness is more important. ;-) |
It's outside the loop, but the function itself is called a lot. |
I was hoping you could so some benchmarking. |
Sorry, I won't bother. I seriously doubt it can add any measurable impact. But, I now realize the description from my commit message could make one think that this is a hack needed for js2-refactor. That's not the case. Just to make it more clear that it's a bug, here's the example I used above, before my modification, with Because of this bug in get-enclosing-scope, it produces that incorrect warning; |
I added a couple of commits to this branch (enable lexical scope, and some cleanups). Here's some benchmarking before and after these commits (I still didn't benchmark js2-node-get-enclosing-scope, because I'm not sure how; besides, that is a bug, performance should simply not matter more than correctness). These timings are for parsing a buffer of about 1700 lines (this file).
Feel free to take whatever you want from this. I live in js2-mode many hours a day, and when I fix or improve something, I do it for purley selfish reasons. :-) I'm happy to live on my fork if you don't want to include these in the official repo. OTOH, if you feel you can trust me (and you should) then you can give me push rights to this repository. I'm using Emacs since '98, I'm a fairly competent Lisp programmer and somewhat of an authority on parsing JavaScript. I won't be able to put much time into it, but I need to fix bugs as I find them, because I need to trust my tools. ;-) Have a great weekend! |
"remove unused properties from js2-script-node" looks definitely valuable (I mean to write it even before looking at the benchmarks), but orthogonal to this fix, isn't it? The switch to lexical binding is discussed at #426. |
I'm not saying this is not a bug, but what about this example: var f = function foo() {
var foo = 4;
return foo;
} How does js2-refactor behave in this case? |
This is the example that might demonstrate the problem better instead, I think: function foo() {
}
foo(); // <-- try to rename foo |
@dgutov your last example works perfectly here, what's the issue? About the one in this comment, there's a bug there — js2-refactor should not rename all 3 occurrences, because |
RE lexical binding: I wasn't aware of existing discussion. While not exaustive, I believe my benchmark was done correctly (recompiled bytecode, restarted emacs, before testing). Lexical binding must be faster, any compiler expert would say this (disclaimer: I'm no expert, but I know a thing or two). |
But how? I don't have js2-refactor installed, but one would assume that, if |
Sorry, I don't understand what you mean here.. Renaming should replace both occurrences in your example, and it works as expected. |
To my mind, this sounds like building with a bug on top of a bug. js2-refactor should deal with shadowing, no matter the function name's scope, I think. But ok, that's not the problem here. |
I'm asking how can a reasonable implementation of this work, given the current behavior reported in this issue. |
Seems so. And here lexical-binding is slower, as you can observe.
"The leading experts" on Emacs Lisp compiler agree that it can be faster, but not every possible optimizations are in place, for this to happen consistently. Anyway, let's move that discussion into the issue where it belongs. Could you remove the unrelated commits from this branch? |
OK, if I understand correctly hope this explains. Here's the code that js2-refactor uses to get a variable's defining scope: (defun js2r--name-node-defining-scope (name-node)
(unless (js2r--local-name-node-p name-node)
(error "Node is not on a local identifier"))
(js2-get-defining-scope
(js2-node-get-enclosing-scope name-node)
(js2-name-node-name name-node))) If there is no
I could, but I believe it would be easier for you to just cherry-pick the commit you need, and close this PR. I'm staying on my fork anyway, I feel it's snappier with lexical-binding on (will notify you if I encounter any issues with it). |
@dgutov alright, I moved the other two commits on another branch in my repo ( |
Okay, let me address this now:
Exercising the features which call it should be enough. Another would be to enable If both (or at least the later) don't show a significant change, the performance is fine.
There's no reason why it shouldn't inform the implementation of the fix, though. Anyway, I'll need some time to think about the problem. |
Are you sure that's not just because of |
@mishoo Apology accepted, and of course you have reasons to be proud. Unfortunately, by itself, that doesn't help me much when reviewing patches: like many programmers, I trust the process better than people. Not only would I be happy to share commit access, but to even pass on the maintainership to someone else (@felipeochoa has been the prime candidate until now, if he's interested). For that, though, I'd like to see certain compatibility in the development practice. Caring about performance and writing tests are the primary things, I guess. |
@mishoo So, the patch looks good, and the performance effects on Could you add a test, then? See the references to |
Re: maintainership, thanks @dgutov but I don't think I can commit to that responsibility right now. If it lessens your burden I'd accept commit access for my own PRs, though |
@felipeochoa Only if you really want to. Your PRs are basically the easiest. :) |
@mishoo To repeat: the patch looks good, and the performance effects on js2-highlight-unused-variables-mode seems to be within the margin of error. Could you add a test? See the references to js2-test-scope-of-nth-variable-satisifies-predicate in existing examples. |
When called with a statement function's name node, js2-node-get-enclosing-scope would errorneously return the function itself. That's not really the scope where this name is defined (it should be the function's parent scope). This bug affects js2-refactor's rename variable functionality. Example: (function(){ function |foo() { var |foo = 5; console.log(|foo); } foo(); })(); (where '|' marks possible cursor position). Type M-x js2r-rename-var with the cursor on one of the marked positions, and it'll offer to rename the following occurrences (marked with underscores): (function(){ function _foo_() { var _foo_ = 5; console.log(_foo_); } foo(); })(); This is incorrect, as the name is shadowed inside the function. It should instead rename these two: (function(){ function _foo_() { var foo = 5; console.log(foo); } _foo_(); })(); This patch fixes this.
@dgutov I added a test. Sorry for the several years delay :)) I completely forgot about it. |
Not a problem, thanks for getting around to it. :) |
When called with a statement function's name node,
js2-node-get-enclosing-scope would errorneously return the function itself.
That's not really the scope where this name is defined (it should be the
function's parent scope).
This bug affects js2-refactor's rename variable functionality. Example:
(where '|' marks possible cursor position). Type M-x js2r-rename-var with
the cursor on one of the marked positions, and it'll offer to rename the
following occurrences (marked with underscores):
This is incorrect, as the name is shadowed inside the function. It should
instead rename these two:
This patch fixes this.