Skip to content

Commit 2c0a21b

Browse files
committed
fix scope hoisting for non-hoisted self-references
1 parent 4c76550 commit 2c0a21b

File tree

1 file changed

+60
-53
lines changed

1 file changed

+60
-53
lines changed

turbopack/crates/turbopack-core/src/module_graph/merged_modules.rs

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ pub async fn compute_merged_modules(module_graph: Vc<ModuleGraph>) -> Result<Vc<
179179
.collect::<Result<Vec<_>>>()?,
180180
&mut (),
181181
|parent_info: Option<(ResolvedVc<Box<dyn Module>>, &'_ RefData, _)>,
182-
node: ResolvedVc<Box<dyn Module>>,
182+
module: ResolvedVc<Box<dyn Module>>,
183183
_,
184184
_|
185185
-> Result<GraphTraversalAction> {
@@ -195,63 +195,70 @@ pub async fn compute_merged_modules(module_graph: Vc<ModuleGraph>) -> Result<Vc<
195195
},
196196
)
197197
});
198-
let module = node;
199198

200-
Ok(if parent_module.is_some_and(|p| p == module) {
201-
// A self-reference
202-
GraphTraversalAction::Skip
203-
} else if hoisted
204-
&& let Some(parent_module) = parent_module
205-
&& mergeable.contains(&parent_module)
206-
&& mergeable.contains(&module)
207-
&& !async_modules.contains(&parent_module)
208-
&& !async_modules.contains(&module)
209-
{
210-
// ^ TODO technically we could merge a sync child into an async parent
211-
212-
// A hoisted reference from a mergeable module to a non-async mergeable
213-
// module, inherit bitmaps from parent.
214-
module_merged_groups.entry(node).or_default();
215-
let [Some(parent_merged_groups), Some(current_merged_groups)] =
216-
module_merged_groups.get_disjoint_mut([&parent_module, &node])
217-
else {
218-
// All modules are inserted in the previous iteration
219-
bail!("unreachable except for eventual consistency");
220-
};
221-
222-
if current_merged_groups.is_empty() {
223-
// Initial visit, clone instead of merging
224-
*current_merged_groups = parent_merged_groups.clone();
225-
GraphTraversalAction::Continue
226-
} else if parent_merged_groups.is_proper_superset(current_merged_groups) {
227-
// Add bits from parent, and continue traversal because changed
228-
**current_merged_groups |= &**parent_merged_groups;
229-
GraphTraversalAction::Continue
199+
Ok(
200+
if hoisted
201+
&& let Some(parent_module) = parent_module
202+
&& mergeable.contains(&parent_module)
203+
&& mergeable.contains(&module)
204+
&& !async_modules.contains(&parent_module)
205+
&& !async_modules.contains(&module)
206+
{
207+
// ^ TODO technically we could merge a sync child into an async parent
208+
if parent_module == module {
209+
// A hoisted self-reference, no need to update bitmaps and don't recurse
210+
GraphTraversalAction::Skip
211+
} else {
212+
// A hoisted reference from a mergeable module to a non-async mergeable
213+
// module, inherit bitmaps from parent.
214+
module_merged_groups.entry(module).or_default();
215+
let [Some(parent_merged_groups), Some(current_merged_groups)] =
216+
module_merged_groups.get_disjoint_mut([&parent_module, &module])
217+
else {
218+
// All modules are inserted in the previous iteration
219+
bail!("unreachable except for eventual consistency");
220+
};
221+
222+
if current_merged_groups.is_empty() {
223+
// Initial visit, clone instead of merging
224+
*current_merged_groups = parent_merged_groups.clone();
225+
GraphTraversalAction::Continue
226+
} else if parent_merged_groups.is_proper_superset(current_merged_groups)
227+
{
228+
// Add bits from parent, and continue traversal because changed
229+
**current_merged_groups |= &**parent_merged_groups;
230+
GraphTraversalAction::Continue
231+
} else {
232+
// Unchanged, no need to forward to children
233+
GraphTraversalAction::Skip
234+
}
235+
}
230236
} else {
231-
// Unchanged, no need to forward to children
232-
GraphTraversalAction::Skip
233-
}
234-
} else {
235-
// Either a non-hoisted reference or an incompatible parent or child module
236-
237-
if entry_modules.insert(module) {
238-
// Not assigned a new group before, create a new one.
239-
let idx = next_index;
240-
next_index += 1;
241-
242-
if module_merged_groups.entry(module).or_default().insert(idx) {
243-
// Mark and continue traversal because modified (or first visit)
244-
GraphTraversalAction::Continue
237+
// Either a non-hoisted reference or an incompatible parent or child module
238+
if entry_modules.insert(module) {
239+
// Not assigned a new group before, create a new one.
240+
let idx = next_index;
241+
next_index += 1;
242+
243+
if module_merged_groups.entry(module).or_default().insert(idx) {
244+
if parent_module.is_some_and(|p| p == module) {
245+
// A hoisted self-reference, don't recurse
246+
GraphTraversalAction::Skip
247+
} else {
248+
// Mark and continue traversal because modified (or first visit)
249+
GraphTraversalAction::Continue
250+
}
251+
} else {
252+
// Unchanged, no need to forward to children
253+
GraphTraversalAction::Skip
254+
}
245255
} else {
246-
// Unchanged, no need to forward to children
256+
// Already visited and assigned a new group, no need to forward to
257+
// children.
247258
GraphTraversalAction::Skip
248259
}
249-
} else {
250-
// Already visited and assigned a new group, no need to forward to
251-
// children.
252-
GraphTraversalAction::Skip
253-
}
254-
})
260+
},
261+
)
255262
},
256263
|successor, _| {
257264
// Invert the ordering here. High priority values get visited first, and we want to

0 commit comments

Comments
 (0)