diff --git a/crates/oxc_ecmascript/src/side_effects/context.rs b/crates/oxc_ecmascript/src/side_effects/context.rs index 8910e5d436087..79aa099f90be9 100644 --- a/crates/oxc_ecmascript/src/side_effects/context.rs +++ b/crates/oxc_ecmascript/src/side_effects/context.rs @@ -29,4 +29,10 @@ pub trait MayHaveSideEffectsContext: IsGlobalReference { /// Whether property read accesses have side effects. fn property_read_side_effects(&self) -> PropertyReadSideEffects; + + /// Whether accessing a global variable has side effects. + /// + /// Accessing a non-existing global variable will throw an error. + /// Global variable may be a getter that has side effects. + fn unknown_global_side_effects(&self) -> bool; } diff --git a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs index 2bc08672491b6..12c39a12a05a0 100644 --- a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs +++ b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs @@ -75,7 +75,7 @@ impl MayHaveSideEffects for IdentifierReference<'_> { // Reading global variables may have a side effect. // NOTE: It should also return true when the reference might refer to a reference value created by a with statement // NOTE: we ignore TDZ errors - _ => ctx.is_global_reference(self) != Some(false), + _ => ctx.unknown_global_side_effects() && ctx.is_global_reference(self) != Some(false), } } } diff --git a/crates/oxc_minifier/src/ctx.rs b/crates/oxc_minifier/src/ctx.rs index 0c38b906c6496..b408d5407b778 100644 --- a/crates/oxc_minifier/src/ctx.rs +++ b/crates/oxc_minifier/src/ctx.rs @@ -37,6 +37,10 @@ impl oxc_ecmascript::side_effects::MayHaveSideEffectsContext for Ctx<'_, '_> { fn property_read_side_effects(&self) -> PropertyReadSideEffects { PropertyReadSideEffects::All } + + fn unknown_global_side_effects(&self) -> bool { + true + } } impl<'a> ConstantEvaluationCtx<'a> for Ctx<'a, '_> { diff --git a/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs b/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs index c4b1287a4a71f..ca617aa2137bf 100644 --- a/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs +++ b/crates/oxc_minifier/tests/ecmascript/may_have_side_effects.rs @@ -12,6 +12,7 @@ struct Ctx { annotation: bool, pure_function_names: Vec, property_read_side_effects: PropertyReadSideEffects, + unknown_global_side_effects: bool, } impl Default for Ctx { fn default() -> Self { @@ -20,6 +21,7 @@ impl Default for Ctx { annotation: true, pure_function_names: vec![], property_read_side_effects: PropertyReadSideEffects::All, + unknown_global_side_effects: true, } } } @@ -44,6 +46,10 @@ impl MayHaveSideEffectsContext for Ctx { fn property_read_side_effects(&self) -> PropertyReadSideEffects { self.property_read_side_effects } + + fn unknown_global_side_effects(&self) -> bool { + self.unknown_global_side_effects + } } fn test(source_text: &str, expected: bool) { @@ -785,6 +791,22 @@ fn test_property_read_side_effects_support() { // test_with_ctx("({ bar } = foo)", &none_ctx, false); } +#[test] +fn test_unknown_global_side_effects_support() { + let true_ctx = Ctx { + unknown_global_side_effects: true, + global_variable_names: vec!["foo".to_string()], + ..Default::default() + }; + let false_ctx = Ctx { + unknown_global_side_effects: false, + global_variable_names: vec!["foo".to_string()], + ..Default::default() + }; + test_with_ctx("foo", &true_ctx, true); + test_with_ctx("foo", &false_ctx, false); +} + #[test] fn test_object_with_to_primitive_related_properties_overridden() { test("+{}", false);