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

[Bug]: Function declarations not hoisted to upper scope in sloppy mode code #13549

Open
1 task done
overlookmotel opened this issue Jul 11, 2021 · 2 comments · May be fixed by #14203
Open
1 task done

[Bug]: Function declarations not hoisted to upper scope in sloppy mode code #13549

overlookmotel opened this issue Jul 11, 2021 · 2 comments · May be fixed by #14203

Comments

@overlookmotel
Copy link
Contributor

overlookmotel commented Jul 11, 2021

💻

  • Would you like to work on a fix?

How are you using Babel?

Programmatic API (babel.transform, babel.parse)

Input code

{
  function f() {}
}
f();

Configuration file name

babel.config.json

Configuration

n/a

Current and expected behavior

In strict mode, function declarations are scoped to the statement block in which they're defined (i.e. behave like let). In sloppy mode they are scoped to the next enclosing function / top-level (i.e. behave like var).

This code is valid in sloppy mode and will execute without an error:

{
  function f() {}
}
f();

Babel appears not to take strict/sloppy mode into account, and applies the strict mode behavior regardless.

const srcCode = `
  {
    function f() {}
  }
  f();
`;

const { code } = transformSync( srcCode, {
  sourceType: 'script',
  plugins: [
    () => ( {
      visitor: {
        Identifier( path ) {
          const binding = path.scope.getBinding( path.node.name );
          if ( !binding ) path.node.name = `unreferenced_${ path.node.name }`;
        }
      }
    } )
  ]
} );
console.log(code);

This outputs:

{
  function f() {}
}
unreferenced_f();

i.e. path.scope.getBinding('f') did not identify that function f is in scope of f().

NB As far as I can see from testing in NodeJS, the function declaration's scope is hoisted up to enclosing function's scope/top-level scope if its surrounding environment is sloppy mode, regardless of whether the function itself is strict. i.e. f is still defined in top level scope in this case:

// Sloppy mode
{
  function f() {
    'use strict';
  }
}
f();

Environment

System:
  OS: macOS 10.15.7
Binaries:
  Node: 16.4.2 - ~/.nvm/versions/node/v16.4.2/bin/node
  Yarn: 1.22.10 - ~/.nvm/versions/node/v16.4.2/bin/yarn
  npm: 7.18.1 - ~/.nvm/versions/node/v16.4.2/bin/npm
npmPackages:
  @babel/core: ^7.14.6 => 7.14.6 
  @babel/generator: ^7.14.5 => 7.14.5 
  @babel/helper-module-transforms: ^7.14.5 => 7.14.5 
  @babel/parser: ^7.14.7 => 7.14.7 
  @babel/plugin-transform-arrow-functions: ^7.14.5 => 7.14.5 
  @babel/plugin-transform-modules-commonjs: ^7.14.5 => 7.14.5 
  @babel/plugin-transform-react-jsx: ^7.14.5 => 7.14.5 
  @babel/plugin-transform-strict-mode: ^7.14.5 => 7.14.5 
  @babel/register: ^7.14.5 => 7.14.5 
  @babel/traverse: ^7.14.7 => 7.14.7 
  @babel/types: ^7.14.5 => 7.14.5 
  babel-jest: ^27.0.6 => 27.0.6 
  babel-plugin-dynamic-import-node: ^2.3.3 => 2.3.3 
  eslint: ^7.30.0 => 7.30.0 
  jest: ^27.0.6 => 27.0.6 

Possible solution

No response

Additional context

I'm happy to work on a fix but would appreciate it if someone can point me in right direction. Last time I looked at the scope logic in Babel, I had trouble getting my head around it.

@babel-bot
Copy link
Collaborator

Hey @overlookmotel! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack community that typically always has someone willing to help. You can sign-up here for an invite."

@overlookmotel
Copy link
Contributor Author

Does traverse() have a concept of/track whether it's currently in a strict mode context or not? I can't see anything obvious recording this on path or state when traversing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants