Skip to content
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: handle block-level function declaration (#10046) #11801

Merged
merged 5 commits into from Dec 15, 2020

Conversation

vitorveiga
Copy link
Contributor

@vitorveiga vitorveiga commented Jul 7, 2020

Q                       A
Fixed Issues? Fixes #10046, resolves #10050
Patch: Bug Fix? Yes
Major: Breaking Change? No
Minor: New Feature? No
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes? No
License MIT

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 7, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 627fdcb:

Sandbox Source
babel-repl-custom-plugin Configuration
babel-plugin-multi-config Configuration

@babel-bot
Copy link
Collaborator

babel-bot commented Jul 7, 2020

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/32208/

@nicolo-ribaudo nicolo-ribaudo added the PR: Bug Fix 🐛 A type of pull request used for our changelog categories label Jul 7, 2020
@JLHwung JLHwung self-requested a review July 16, 2020 21:35
@vitorveiga
Copy link
Contributor Author

Hello.

@JLHwung did you have a chance to review this PR?

Best Regards

Copy link
Contributor

@JLHwung JLHwung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it suffices to check if the following conditions are both true.

  1. binding.kind is "hoisted"
  2. key is not defined in parent scope
const binding = scope.getOwnBinding(key);
if (binding) {
  if (binding.kind === "hoisted" && !scope.parent.hasOwnBinding(key)) {
    continue;
  }
  scope.rename(ref.name);
}

The first condition is actually a shortcut for (binding && binding.path && !binding.path.isFunctionDeclaration()). As of the second condition, we don't have to check isVar because the fact that it is one of letRefs implies there must be a let/const binding in current scope chain. Since the binding.kind is "hoisted", it must be defined in upper scope so we can simply check whether an upper scope own a binding named as key.

@vitorveiga
Copy link
Contributor Author

vitorveiga commented Nov 9, 2020

Thanks for your review :)

Oh ok.. didn't know that binding.kind === 'hoisted' is in fact a shortcut for checking if its a function declaration.
On the other hand, I think we should keep the isVar condition because we need to rename the variable if the upper scope has a const or let variable with the same name. However, if its a var we should skip the renaming operation.

The conditions were updated!

@JLHwung
Copy link
Contributor

JLHwung commented Nov 12, 2020

I think we should keep the isVar condition because we need to rename the variable if the upper scope has a const or let variable with the same name. However, if its a var we should skip the renaming operation.

Note that the renaming is nested in for (const key of letRefs.keys()) loop. In this loop, if !parentBinding is false, which means key is owned in parent scope, then isVar(parentBinding.path.parent) must be false otherwise it contradicts with the fact that key is of letRefs.

(You can also click on "Details" to see my implementation in #11801 (review))

@vitorveiga
Copy link
Contributor Author

vitorveiga commented Nov 21, 2020

Note that the implementation in #11801, fails on the unit-test issue-10046-collision-var due to the variable declaration on the program node.

In that particular unit test, the !parentBinding is false and without isVar condition the rename will happen turning the function declaration into to var _run = function() {}.

if !parentBinding is false, which means key is owned in parent scope, then isVar(parentBinding.path.parent) must be false otherwise it contradicts with the fact that key is of letRefs.

Maybe there is some implementation bug on letRefs map, but it seems that isVar(parentBinding.path.parent) is true on that use case.

@vitorveiga
Copy link
Contributor Author

Hello @JLHwung did you have a chance to read my last comment? Thanks

@nicolo-ribaudo nicolo-ribaudo merged commit 90fb8d2 into babel:main Dec 15, 2020
@nicolo-ribaudo
Copy link
Member

This PR caused some regressions: https://app.circleci.com/pipelines/github/babel/babel/4967/workflows/27043ada-f8d2-482e-810b-2593a17cf087/jobs/35381

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Mar 17, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

plugin-transform-block-scoping renames function declaration
4 participants