-
-
Notifications
You must be signed in to change notification settings - Fork 645
Description
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:
oxc/crates/oxc_semantic/src/builder.rs
Lines 414 to 440 in 9e148e9
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;
}
}