Skip to content

semantic: var hoisting #4323

@Boshen

Description

@Boshen

Several attempts was made to pass all tests in test262 + babel + typescript regarding var hoisting in strict / non-strict mode.

Scope tree ended up with a var binding everywhere:

{
  {
    var x
  } 
}

x = 1

produces

Scope1 (ScopeFlags(StrictMode | Top)) {
  Bindings: {
    x (SymbolFlags(FunctionScopedVariable))
  }
  Scope2 (ScopeFlags(StrictMode)) {
    Bindings: {
      x (SymbolFlags(FunctionScopedVariable))
    }
    Scope3 (ScopeFlags(StrictMode)) {
      Bindings: {
        x (SymbolFlags(FunctionScopedVariable))
      }
    }
  }
}

The consequence of this is:

  • unintuitive
  • performance killer
  • breaks mangler
    // omit var hoisting because var symbols are added to every parent scope
    if symbol_table.get_flag(*symbol_id).is_function_scoped_declaration()
    && parent_bindings.is_none()
    {
    parent_bindings = scope_tree
    .get_parent_id(scope_id)
    .map(|parent_scope_id| scope_tree.get_bindings(parent_scope_id));
    }
    if let Some(parent_bindings) = &parent_bindings {
    if parent_bindings.values().contains(symbol_id) {
    continue;
    }
    }

To understand the test cases, try different strategies in

let mut var_scope_ids = vec![];
if !builder.current_scope_flags().is_var() {
for scope_id in builder.scope.ancestors(current_scope_id).skip(1) {
var_scope_ids.push(scope_id);
if builder.scope.get_flags(scope_id).is_var() {
break;
}
}
}

and run just c to see changes in snapshot.

Metadata

Metadata

Assignees

Labels

C-bugCategory - Bug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions