Skip to content

Inherit ScopeFlags::StrictMode from parent scope #3862

@overlookmotel

Description

@overlookmotel

There appear to be some discrepancies in when ScopeFlags::StrictMode is applied by semantic.

enter_scope looks like its logic is that StrictMode should be set on any scope which is strict mode (including from a 'use strict' directive somewhere above it). But this doesn't appear to be what it actually does, because it only sets StrictMode flag if the direct parent is a function with a 'use strict' directive, or if the entire program is strict mode:

impl<'a> Visit<'a> for SemanticBuilder<'a> {
fn enter_scope(&mut self, flags: ScopeFlags) {
let parent_scope_id =
if flags.contains(ScopeFlags::Top) { None } else { Some(self.current_scope_id) };
let mut flags = flags;
// Inherit strict mode for functions
// https://tc39.es/ecma262/#sec-strict-mode-code
if let Some(parent_scope_id) = parent_scope_id {
let mut strict_mode = self.scope.root_flags().is_strict_mode();
let parent_scope_flags = self.scope.get_flags(parent_scope_id);
if !strict_mode
&& parent_scope_flags.is_function()
&& parent_scope_flags.is_strict_mode()
{
strict_mode = true;
}
// inherit flags for non-function scopes
if !flags.contains(ScopeFlags::Function) {
flags |= parent_scope_flags & ScopeFlags::Modifiers;
};
if strict_mode {
flags |= ScopeFlags::StrictMode;
}

A couple of examples of weirdness:

// Script - sloppy mode
function foo() {
  'use strict';
  {
    // Scope flags for this block include `StrictMode`
    {
      // Scope flags for this block do NOT include `StrictMode`
    }
  }
}
// Script - sloppy mode
class X {
  foo() {
    // Scope flags for this method do NOT include `StrictMode`
  }
}

When is StrictMode flag meant to be set?

If intended behavior is that StrictMode flag should be set for any scope which runs in strict context, we can simplify the above logic to:

if let Some(parent_scope_id) = parent_scope_id {
    let parent_scope_flags = self.scope.get_flags(parent_scope_id);
    flags |= parent_scope_flags & ScopeFlags::StrictMode;

    // inherit flags for non-function scopes
    if !flags.contains(ScopeFlags::Function) {
        flags |= parent_scope_flags & ScopeFlags::Modifiers;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory - Bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions