Skip to content

Commit 137ce23

Browse files
committed
fix(strict-execution-order): don't mark pure-annotated local calls as execution-order-sensitive
Pure-annotated calls to local functions (e.g. `/*#__PURE__*/ foo()`) should not trigger `ExecutionOrderSensitive`, since the annotation is a developer contract that the call is side-effect-free. Only `Unknown` and `GlobalVarAccess` flags should trigger wrapping. This also removes the now-unused `SideEffectDetail::PureAnnotation` flag.
1 parent eec7d73 commit 137ce23

File tree

4 files changed

+11
-22
lines changed

4 files changed

+11
-22
lines changed

crates/rolldown/src/ast_scanner/impl_visit.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ impl<'me, 'ast: 'me> Visit<'ast> for AstScanner<'me, 'ast> {
125125
}
126126

127127
self.visit_statement(stmt);
128-
if self.current_stmt_info.side_effect.intersects(
129-
SideEffectDetail::Unknown
130-
| SideEffectDetail::GlobalVarAccess
131-
| SideEffectDetail::PureAnnotation,
132-
) {
128+
if self
129+
.current_stmt_info
130+
.side_effect
131+
.intersects(SideEffectDetail::Unknown | SideEffectDetail::GlobalVarAccess)
132+
{
133133
self.result.ecma_view_meta.insert(EcmaViewMeta::ExecutionOrderSensitive);
134134
}
135135
self.result.stmt_infos.add_stmt_info(std::mem::take(&mut self.current_stmt_info));

crates/rolldown/src/ast_scanner/side_effect_detector/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ impl<'a> SideEffectDetector<'a> {
117117
&& matches!(&expr.callee, Expression::Identifier(id) if self.is_unresolved_reference(id));
118118

119119
let mut detail = SideEffectDetail::from(has_side_effect);
120-
detail.set(SideEffectDetail::PureAnnotation, is_pure_annotated);
121120
detail.set(SideEffectDetail::GlobalVarAccess, is_global_call);
122121

123122
if !has_side_effect {
@@ -202,12 +201,8 @@ impl<'a> SideEffectDetector<'a> {
202201
// METADATA: GlobalVarAccess — constructor is a known global
203202
let is_global_constructor = !has_side_effect
204203
&& matches!(&expr.callee, Expression::Identifier(id) if self.is_unresolved_reference(id));
205-
// METADATA: PureAnnotation — marked with /*@__PURE__*/
206-
let is_pure_annotated = !self.flat_options.ignore_annotations() && expr.pure;
207-
208204
let mut detail = SideEffectDetail::from(has_side_effect);
209205
detail.set(SideEffectDetail::GlobalVarAccess, is_global_constructor);
210-
detail.set(SideEffectDetail::PureAnnotation, is_pure_annotated);
211206

212207
if !has_side_effect {
213208
// Oxc already verified args are side-effect-free; only collect metadata flags.
@@ -1086,7 +1081,7 @@ mod test {
10861081
// sideEffectful Global variable access with pure annotation
10871082
assert_eq!(
10881083
get_statements_side_effect_details("let a = /*@__PURE__ */ Reflect.something()"),
1089-
vec![SideEffectDetail::GlobalVarAccess | SideEffectDetail::PureAnnotation]
1084+
vec![SideEffectDetail::GlobalVarAccess]
10901085
);
10911086
}
10921087

crates/rolldown/tests/rolldown/function/experimental/strict_execution_order/issue_4920/artifacts.snap

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,9 @@ import nodeAssert from "node:assert";
3838
function foo() {
3939
globalThis.value = 1;
4040
}
41-
var dep_default;
42-
var init_dep = __esmMin((() => {
43-
dep_default = /* @__PURE__ */ foo();
44-
}));
41+
var dep_default = /* @__PURE__ */ foo();
4542
//#endregion
4643
__esmMin((() => {
47-
init_dep();
4844
nodeAssert.strictEqual(globalThis.value, 1);
4945
}))();
5046
export { dep_default as dep };

crates/rolldown_common/src/types/side_effect_detail.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
use bitflags::bitflags;
22
bitflags! {
33
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
4-
/// Some statement is mark as side effects free via `Pure`, but we need to know
5-
/// the original statement side effects when do some runtime wrapper optimization.
6-
/// A global variable access with `pure` annotation, it could be eliminated when unused,
7-
/// but If we can't remove it's wrapper safely,because runtime behavior of global variable access maybe execution
8-
/// order aware
4+
/// Metadata flags describing a statement's side effects.
5+
/// Used to determine execution-order sensitivity for runtime wrapper optimization.
6+
/// e.g. a global variable access may require preserving execution order even if the
7+
/// statement is otherwise side-effect-free.
98
pub struct SideEffectDetail: u8 {
109
const GlobalVarAccess = 1;
1110
const PureCjs = 1 << 1;
1211
const Unknown = 1 << 2;
13-
const PureAnnotation = 1 << 3;
1412
}
1513
}
1614

0 commit comments

Comments
 (0)