1use std::{
2 hash::Hash,
3 ops::{Deref, DerefMut},
4};
5
6use anyhow::{Context, Result, bail};
7use bincode::{Decode, Encode};
8use either::Either;
9use indexmap::map::Entry;
10use roaring::RoaringBitmap;
11use rustc_hash::FxHashMap;
12use tracing::Instrument;
13use turbo_rcstr::RcStr;
14use turbo_tasks::{
15 FxIndexMap, FxIndexSet, NonLocalValue, ResolvedVc, TaskInput, TryJoinIterExt, ValueToString,
16 Vc, debug::ValueDebugFormat, trace::TraceRawVcs,
17};
18
19use crate::{
20 chunk::ChunkingType,
21 module::Module,
22 module_graph::{GraphTraversalAction, ModuleGraph, RefData},
23};
24
25#[derive(Clone, Debug, Default, PartialEq, TraceRawVcs, ValueDebugFormat, Encode, Decode)]
26#[repr(transparent)]
27pub struct RoaringBitmapWrapper(
28 #[turbo_tasks(trace_ignore)]
29 #[bincode(with_serde)]
30 pub RoaringBitmap,
31);
32
33impl TaskInput for RoaringBitmapWrapper {
34 fn is_transient(&self) -> bool {
35 false
36 }
37}
38
39impl RoaringBitmapWrapper {
40 pub fn is_proper_superset(&self, other: &Self) -> bool {
44 !self.is_subset(other)
45 }
46
47 pub fn into_inner(self) -> RoaringBitmap {
48 self.0
49 }
50}
51unsafe impl NonLocalValue for RoaringBitmapWrapper {}
52
53impl Eq for RoaringBitmapWrapper {}
57
58impl Deref for RoaringBitmapWrapper {
59 type Target = RoaringBitmap;
60 fn deref(&self) -> &Self::Target {
61 &self.0
62 }
63}
64impl DerefMut for RoaringBitmapWrapper {
65 fn deref_mut(&mut self) -> &mut Self::Target {
66 &mut self.0
67 }
68}
69impl Hash for RoaringBitmapWrapper {
70 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
71 struct HasherWriter<'a, H: std::hash::Hasher>(&'a mut H);
72 impl<H: std::hash::Hasher> std::io::Write for HasherWriter<'_, H> {
73 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
74 self.0.write(buf);
75 Ok(buf.len())
76 }
77 fn flush(&mut self) -> std::io::Result<()> {
78 Ok(())
79 }
80 }
81 self.0.serialize_into(HasherWriter(state)).unwrap();
82 }
83}
84
85#[turbo_tasks::value(transparent, cell = "keyed")]
86pub struct ModuleToChunkGroups(FxHashMap<ResolvedVc<Box<dyn Module>>, RoaringBitmapWrapper>);
87
88#[turbo_tasks::value]
89pub struct ChunkGroupInfo {
90 pub module_chunk_groups: ResolvedVc<ModuleToChunkGroups>,
91 #[turbo_tasks(trace_ignore)]
92 #[bincode(with = "turbo_bincode::indexset")]
93 pub chunk_groups: FxIndexSet<ChunkGroup>,
94 #[turbo_tasks(trace_ignore)]
95 #[bincode(with = "turbo_bincode::indexset")]
96 pub chunk_group_keys: FxIndexSet<ChunkGroupKey>,
97}
98
99#[turbo_tasks::value_impl]
100impl ChunkGroupInfo {
101 #[turbo_tasks::function]
102 pub fn module_chunk_groups(&self) -> Vc<ModuleToChunkGroups> {
103 *self.module_chunk_groups
104 }
105
106 #[turbo_tasks::function]
107 pub async fn get_index_of(&self, chunk_group: ChunkGroup) -> Result<Vc<usize>> {
108 if let Some(idx) = self.chunk_groups.get_index_of(&chunk_group) {
109 Ok(Vc::cell(idx))
110 } else {
111 bail!(
112 "Couldn't find chunk group index for {} in {}",
113 chunk_group.debug_str(self).await?,
114 self.chunk_groups
115 .iter()
116 .map(|c| c.debug_str(self))
117 .try_join()
118 .await?
119 .join(", ")
120 );
121 }
122 }
123}
124
125#[derive(
126 Debug, Clone, Hash, TaskInput, PartialEq, Eq, TraceRawVcs, NonLocalValue, Encode, Decode,
127)]
128pub enum ChunkGroupEntry {
129 Entry(Vec<ResolvedVc<Box<dyn Module>>>),
131 Async(ResolvedVc<Box<dyn Module>>),
133 Isolated(ResolvedVc<Box<dyn Module>>),
135 IsolatedMerged {
137 parent: Box<ChunkGroupEntry>,
138 merge_tag: RcStr,
139 entries: Vec<ResolvedVc<Box<dyn Module>>>,
140 },
141 Shared(ResolvedVc<Box<dyn Module>>),
143 SharedMerged {
145 parent: Box<ChunkGroupEntry>,
146 merge_tag: RcStr,
147 entries: Vec<ResolvedVc<Box<dyn Module>>>,
148 },
149}
150impl ChunkGroupEntry {
151 pub fn entries(&self) -> impl Iterator<Item = ResolvedVc<Box<dyn Module>>> + '_ {
152 match self {
153 Self::Async(e) | Self::Isolated(e) | Self::Shared(e) => {
154 Either::Left(std::iter::once(*e))
155 }
156 Self::Entry(entries)
157 | Self::IsolatedMerged { entries, .. }
158 | Self::SharedMerged { entries, .. } => Either::Right(entries.iter().copied()),
159 }
160 }
161}
162
163#[derive(Debug, Clone, Hash, TaskInput, PartialEq, Eq, TraceRawVcs, Encode, Decode)]
164pub enum ChunkGroup {
165 Entry(Vec<ResolvedVc<Box<dyn Module>>>),
167 Async(ResolvedVc<Box<dyn Module>>),
169 Isolated(ResolvedVc<Box<dyn Module>>),
171 IsolatedMerged {
173 parent: usize,
174 merge_tag: RcStr,
175 entries: Vec<ResolvedVc<Box<dyn Module>>>,
176 },
177 Shared(ResolvedVc<Box<dyn Module>>),
179 SharedMerged {
181 parent: usize,
182 merge_tag: RcStr,
183 entries: Vec<ResolvedVc<Box<dyn Module>>>,
184 },
185}
186
187impl ChunkGroup {
188 pub fn get_merged_parent(&self) -> Option<usize> {
191 match self {
192 ChunkGroup::IsolatedMerged { parent, .. } | ChunkGroup::SharedMerged { parent, .. } => {
193 Some(*parent)
194 }
195 _ => None,
196 }
197 }
198
199 pub fn entries(&self) -> impl Iterator<Item = ResolvedVc<Box<dyn Module>>> + Clone + '_ {
202 match self {
203 ChunkGroup::Async(e) | ChunkGroup::Isolated(e) | ChunkGroup::Shared(e) => {
204 Either::Left(std::iter::once(*e))
205 }
206 ChunkGroup::Entry(entries)
207 | ChunkGroup::IsolatedMerged { entries, .. }
208 | ChunkGroup::SharedMerged { entries, .. } => Either::Right(entries.iter().copied()),
209 }
210 }
211
212 pub fn entries_count(&self) -> usize {
213 match self {
214 ChunkGroup::Async(_) | ChunkGroup::Isolated(_) | ChunkGroup::Shared(_) => 1,
215 ChunkGroup::Entry(entries)
216 | ChunkGroup::IsolatedMerged { entries, .. }
217 | ChunkGroup::SharedMerged { entries, .. } => entries.len(),
218 }
219 }
220
221 pub async fn debug_str(&self, chunk_group_info: &ChunkGroupInfo) -> Result<String> {
222 Ok(match self {
223 ChunkGroup::Entry(entries) => format!(
224 "ChunkGroup::Entry({:?})",
225 entries
226 .iter()
227 .map(|m| m.ident().to_string())
228 .try_join()
229 .await?
230 ),
231 ChunkGroup::Async(entry) => {
232 format!("ChunkGroup::Async({:?})", entry.ident().to_string().await?)
233 }
234 ChunkGroup::Isolated(entry) => {
235 format!(
236 "ChunkGroup::Isolated({:?})",
237 entry.ident().to_string().await?
238 )
239 }
240 ChunkGroup::Shared(entry) => {
241 format!("ChunkGroup::Shared({:?})", entry.ident().to_string().await?)
242 }
243 ChunkGroup::IsolatedMerged {
244 parent,
245 merge_tag,
246 entries,
247 } => {
248 format!(
249 "ChunkGroup::IsolatedMerged({}, {}, {:?})",
250 Box::pin(chunk_group_info.chunk_groups[*parent].debug_str(chunk_group_info))
251 .await?,
252 merge_tag,
253 entries
254 .iter()
255 .map(|m| m.ident().to_string())
256 .try_join()
257 .await?
258 )
259 }
260 ChunkGroup::SharedMerged {
261 parent,
262 merge_tag,
263 entries,
264 } => {
265 format!(
266 "ChunkGroup::SharedMerged({}, {}, {:?})",
267 Box::pin(chunk_group_info.chunk_groups[*parent].debug_str(chunk_group_info))
268 .await?,
269 merge_tag,
270 entries
271 .iter()
272 .map(|m| m.ident().to_string())
273 .try_join()
274 .await?
275 )
276 }
277 })
278 }
279}
280
281#[derive(Debug, Clone, Hash, PartialEq, Eq, Encode, Decode)]
282pub enum ChunkGroupKey {
283 Entry(Vec<ResolvedVc<Box<dyn Module>>>),
285 Async(ResolvedVc<Box<dyn Module>>),
287 Isolated(ResolvedVc<Box<dyn Module>>),
289 IsolatedMerged {
291 parent: ChunkGroupId,
292 merge_tag: RcStr,
293 },
294 Shared(ResolvedVc<Box<dyn Module>>),
296 SharedMerged {
298 parent: ChunkGroupId,
299 merge_tag: RcStr,
300 },
301}
302
303impl ChunkGroupKey {
304 pub async fn debug_str(
305 &self,
306 keys: impl std::ops::Index<usize, Output = Self>,
307 ) -> Result<String> {
308 Ok(match self {
309 ChunkGroupKey::Entry(entries) => format!(
310 "Entry({:?})",
311 entries
312 .iter()
313 .map(|m| m.ident().to_string())
314 .try_join()
315 .await?
316 ),
317 ChunkGroupKey::Async(module) => {
318 format!("Async({:?})", module.ident().to_string().await?)
319 }
320 ChunkGroupKey::Isolated(module) => {
321 format!("Isolated({:?})", module.ident().to_string().await?)
322 }
323 ChunkGroupKey::IsolatedMerged { parent, merge_tag } => {
324 format!(
325 "IsolatedMerged {{ parent: {}, merge_tag: {:?} }}",
326 Box::pin(keys.index(parent.0 as usize).clone().debug_str(keys)).await?,
327 merge_tag
328 )
329 }
330 ChunkGroupKey::Shared(module) => {
331 format!("Shared({:?})", module.ident().to_string().await?)
332 }
333 ChunkGroupKey::SharedMerged { parent, merge_tag } => {
334 format!(
335 "SharedMerged {{ parent: {}, merge_tag: {:?} }}",
336 Box::pin(keys.index(parent.0 as usize).clone().debug_str(keys)).await?,
337 merge_tag
338 )
339 }
340 })
341 }
342}
343
344#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encode, Decode)]
345pub struct ChunkGroupId(u32);
346
347impl From<usize> for ChunkGroupId {
348 fn from(id: usize) -> Self {
349 Self(id as u32)
350 }
351}
352
353impl Deref for ChunkGroupId {
354 type Target = u32;
355 fn deref(&self) -> &Self::Target {
356 &self.0
357 }
358}
359
360#[derive(Debug, Clone, PartialEq, Eq)]
361struct TraversalPriority {
362 depth: usize,
363 chunk_group_len: u64,
364}
365impl PartialOrd for TraversalPriority {
366 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
367 Some(self.cmp(other))
368 }
369}
370impl Ord for TraversalPriority {
371 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
372 let depth_order = self.depth.cmp(&other.depth).reverse();
376 let chunk_group_len_order = self.chunk_group_len.cmp(&other.chunk_group_len).reverse();
378
379 depth_order.then(chunk_group_len_order)
380 }
381}
382
383pub async fn compute_chunk_group_info(graph: &ModuleGraph) -> Result<Vc<ChunkGroupInfo>> {
384 let span_outer = tracing::info_span!(
385 "compute chunk group info",
386 module_count = tracing::field::Empty,
387 visit_count = tracing::field::Empty,
388 chunk_group_count = tracing::field::Empty
389 );
390
391 let span = span_outer.clone();
392 async move {
393 #[allow(clippy::type_complexity)]
394 let mut chunk_groups_map: FxIndexMap<
395 ChunkGroupKey,
396 (ChunkGroupId, FxIndexSet<ResolvedVc<Box<dyn Module>>>),
397 > = FxIndexMap::default();
398
399 let mut module_chunk_groups: FxHashMap<ResolvedVc<Box<dyn Module>>, RoaringBitmapWrapper> =
402 FxHashMap::default();
403
404 let module_count = graph
405 .graphs
406 .iter()
407 .map(|g| g.graph.node_count())
408 .sum::<usize>();
409 span.record("module_count", module_count);
410
411 let entries = graph
413 .graphs
414 .iter()
415 .flat_map(|g| g.entries.iter())
416 .collect::<Vec<_>>();
417
418 let module_depth: FxHashMap<ResolvedVc<Box<dyn Module>>, usize> = {
420 let mut module_depth =
421 FxHashMap::with_capacity_and_hasher(module_count, Default::default());
422 graph.traverse_edges_bfs(
423 entries.iter().flat_map(|e| e.entries()),
424 |parent, node| {
425 if let Some((parent, _)) = parent {
426 let parent_depth = *module_depth
427 .get(&parent)
428 .context("Module depth not found")?;
429 module_depth.entry(node).or_insert(parent_depth + 1);
430 } else {
431 module_depth.insert(node, 0);
432 };
433
434 module_chunk_groups.insert(node, RoaringBitmapWrapper::default());
435
436 Ok(GraphTraversalAction::Continue)
437 },
438 )?;
439 module_depth
440 };
441
442 #[allow(clippy::type_complexity)]
445 fn entry_to_chunk_group_id(
446 entry: ChunkGroupEntry,
447 chunk_groups_map: &mut FxIndexMap<
448 ChunkGroupKey,
449 (ChunkGroupId, FxIndexSet<ResolvedVc<Box<dyn Module>>>),
450 >,
451 ) -> ChunkGroupKey {
452 match entry {
453 ChunkGroupEntry::Entry(entries) => ChunkGroupKey::Entry(entries),
454 ChunkGroupEntry::Async(entry) => ChunkGroupKey::Async(entry),
455 ChunkGroupEntry::Isolated(entry) => ChunkGroupKey::Isolated(entry),
456 ChunkGroupEntry::Shared(entry) => ChunkGroupKey::Shared(entry),
457 ChunkGroupEntry::IsolatedMerged {
458 parent,
459 merge_tag,
460 entries: _,
461 } => {
462 let parent = entry_to_chunk_group_id(*parent, chunk_groups_map);
463 let len = chunk_groups_map.len();
464 let parent = chunk_groups_map
465 .entry(parent)
466 .or_insert_with(|| (ChunkGroupId(len as u32), FxIndexSet::default()))
467 .0;
468
469 ChunkGroupKey::IsolatedMerged {
470 parent: ChunkGroupId(*parent as u32),
471 merge_tag,
472 }
473 }
474 ChunkGroupEntry::SharedMerged {
475 parent,
476 merge_tag,
477 entries: _,
478 } => {
479 let parent = entry_to_chunk_group_id(*parent, chunk_groups_map);
480 let len = chunk_groups_map.len();
481 let parent = chunk_groups_map
482 .entry(parent)
483 .or_insert_with(|| (ChunkGroupId(len as u32), FxIndexSet::default()))
484 .0;
485
486 ChunkGroupKey::SharedMerged {
487 parent: ChunkGroupId(*parent as u32),
488 merge_tag,
489 }
490 }
491 }
492 }
493
494 let entry_chunk_group_keys = graph
495 .graphs
496 .iter()
497 .flat_map(|g| g.entries.iter())
498 .flat_map(|chunk_group| {
499 let chunk_group_key =
500 entry_to_chunk_group_id(chunk_group.clone(), &mut chunk_groups_map);
501 chunk_group
502 .entries()
503 .map(move |e| (e, chunk_group_key.clone()))
504 })
505 .collect::<FxHashMap<_, _>>();
506
507 let visit_count = graph.traverse_edges_fixed_point_with_priority(
508 entries
509 .iter()
510 .flat_map(|e| e.entries())
511 .map(|e| {
512 Ok((
513 e,
514 TraversalPriority {
515 depth: *module_depth.get(&e).context("Module depth not found")?,
516 chunk_group_len: 0,
517 },
518 ))
519 })
520 .collect::<Result<Vec<_>>>()?,
521 &mut module_chunk_groups,
522 |parent_info: Option<(ResolvedVc<Box<dyn Module>>, &'_ RefData, _)>,
523 node: ResolvedVc<Box<dyn Module>>,
524 module_chunk_groups: &mut FxHashMap<
525 ResolvedVc<Box<dyn Module>>,
526 RoaringBitmapWrapper,
527 >|
528 -> Result<GraphTraversalAction> {
529 enum ChunkGroupInheritance<It: Iterator<Item = ChunkGroupKey>> {
530 Inherit(ResolvedVc<Box<dyn Module>>),
531 ChunkGroup(It),
532 }
533 let chunk_groups = if let Some((parent, ref_data, _)) = parent_info {
534 match &ref_data.chunking_type {
535 ChunkingType::Parallel { .. } => ChunkGroupInheritance::Inherit(parent),
536 ChunkingType::Async => ChunkGroupInheritance::ChunkGroup(Either::Left(
537 std::iter::once(ChunkGroupKey::Async(node)),
538 )),
539 ChunkingType::Isolated {
540 merge_tag: None, ..
541 } => ChunkGroupInheritance::ChunkGroup(Either::Left(std::iter::once(
542 ChunkGroupKey::Isolated(node),
543 ))),
544 ChunkingType::Shared {
545 merge_tag: None, ..
546 } => ChunkGroupInheritance::ChunkGroup(Either::Left(std::iter::once(
547 ChunkGroupKey::Shared(node),
548 ))),
549 ChunkingType::Isolated {
550 merge_tag: Some(merge_tag),
551 ..
552 } => {
553 let parents = module_chunk_groups
554 .get(&parent)
555 .context("Module chunk group not found")?;
556 let chunk_groups =
557 parents.iter().map(|parent| ChunkGroupKey::IsolatedMerged {
558 parent: ChunkGroupId(parent),
559 merge_tag: merge_tag.clone(),
560 });
561 ChunkGroupInheritance::ChunkGroup(Either::Right(Either::Left(
562 chunk_groups,
563 )))
564 }
565 ChunkingType::Shared {
566 merge_tag: Some(merge_tag),
567 ..
568 } => {
569 let parents = module_chunk_groups
570 .get(&parent)
571 .context("Module chunk group not found")?;
572 let chunk_groups =
573 parents.iter().map(|parent| ChunkGroupKey::SharedMerged {
574 parent: ChunkGroupId(parent),
575 merge_tag: merge_tag.clone(),
576 });
577 ChunkGroupInheritance::ChunkGroup(Either::Right(Either::Right(
578 chunk_groups,
579 )))
580 }
581 ChunkingType::Traced => {
582 return Ok(GraphTraversalAction::Skip);
584 }
585 }
586 } else {
587 ChunkGroupInheritance::ChunkGroup(Either::Left(std::iter::once(
588 entry_chunk_group_keys
590 .get(&node)
591 .context("Module chunk group not found")?
592 .clone(),
593 )))
594 };
595
596 Ok(match chunk_groups {
597 ChunkGroupInheritance::ChunkGroup(chunk_groups) => {
598 let chunk_group_ids = chunk_groups.map(|chunk_group| {
600 let len = chunk_groups_map.len();
601 let is_merged = matches!(
602 chunk_group,
603 ChunkGroupKey::IsolatedMerged { .. }
604 | ChunkGroupKey::SharedMerged { .. }
605 );
606 match chunk_groups_map.entry(chunk_group) {
607 Entry::Occupied(mut e) => {
608 let (id, merged_entries) = e.get_mut();
609 if is_merged {
610 merged_entries.insert(node);
611 }
612 **id
613 }
614 Entry::Vacant(e) => {
615 let chunk_group_id = len as u32;
616 let mut set = FxIndexSet::default();
617 if is_merged {
618 set.insert(node);
619 }
620 e.insert((ChunkGroupId(chunk_group_id), set));
621 chunk_group_id
622 }
623 }
624 });
625
626 let chunk_groups =
627 RoaringBitmapWrapper(RoaringBitmap::from_iter(chunk_group_ids));
628
629 let bitset = module_chunk_groups
631 .get_mut(&node)
632 .context("Module chunk group not found")?;
633 if chunk_groups.is_proper_superset(bitset) {
634 **bitset |= chunk_groups.into_inner();
636
637 GraphTraversalAction::Continue
638 } else {
639 GraphTraversalAction::Skip
641 }
642 }
643 ChunkGroupInheritance::Inherit(parent) => {
644 if parent == node {
648 GraphTraversalAction::Skip
650 } else {
651 let [Some(parent_chunk_groups), Some(current_chunk_groups)] =
652 module_chunk_groups.get_disjoint_mut([&parent, &node])
653 else {
654 bail!("Module chunk groups not found");
658 };
659
660 if current_chunk_groups.is_empty() {
661 *current_chunk_groups = parent_chunk_groups.clone();
663 GraphTraversalAction::Continue
664 } else if parent_chunk_groups.is_proper_superset(current_chunk_groups) {
665 **current_chunk_groups |= &**parent_chunk_groups;
667 GraphTraversalAction::Continue
668 } else {
669 GraphTraversalAction::Skip
671 }
672 }
673 }
674 })
675 },
676 |successor, module_chunk_groups| {
684 Ok(TraversalPriority {
685 depth: *module_depth
686 .get(&successor)
687 .context("Module depth not found")?,
688 chunk_group_len: module_chunk_groups
689 .get(&successor)
690 .context("Module chunk group not found")?
691 .len(),
692 })
693 },
694 )?;
695
696 span.record("visit_count", visit_count);
697 span.record("chunk_group_count", chunk_groups_map.len());
698
699 #[cfg(debug_assertions)]
700 {
701 use once_cell::sync::Lazy;
702 static PRINT_CHUNK_GROUP_INFO: Lazy<bool> =
703 Lazy::new(|| match std::env::var_os("TURBOPACK_PRINT_CHUNK_GROUPS") {
704 Some(v) => v == "1",
705 None => false,
706 });
707 if *PRINT_CHUNK_GROUP_INFO {
708 use std::{
709 collections::{BTreeMap, BTreeSet},
710 path::absolute,
711 };
712
713 let mut buckets = BTreeMap::default();
714 for (module, key) in &module_chunk_groups {
715 if !key.is_empty() {
716 buckets
717 .entry(key.iter().collect::<Vec<_>>())
718 .or_insert(BTreeSet::new())
719 .insert(module.ident().to_string().await?);
720 }
721 }
722
723 let mut result = vec![];
724 result.push("Chunk Groups:".to_string());
725 for (i, (key, _)) in chunk_groups_map.iter().enumerate() {
726 result.push(format!(
727 " {:?}: {}",
728 i,
729 key.debug_str(chunk_groups_map.keys()).await?
730 ));
731 }
732 result.push("# Module buckets:".to_string());
733 for (key, modules) in buckets.iter() {
734 result.push(format!("## {:?}:", key.iter().collect::<Vec<_>>()));
735 for module in modules {
736 result.push(format!(" {module}"));
737 }
738 result.push("".to_string());
739 }
740 let f = absolute("chunk_group_info.log")?;
741 println!("written to {}", f.display());
742 std::fs::write(f, result.join("\n"))?;
743 }
744 }
745
746 Ok(ChunkGroupInfo {
747 module_chunk_groups: ResolvedVc::cell(module_chunk_groups),
748 chunk_group_keys: chunk_groups_map.keys().cloned().collect(),
749 chunk_groups: chunk_groups_map
750 .into_iter()
751 .map(|(k, (_, merged_entries))| match k {
752 ChunkGroupKey::Entry(entries) => ChunkGroup::Entry(entries),
753 ChunkGroupKey::Async(module) => ChunkGroup::Async(module),
754 ChunkGroupKey::Isolated(module) => ChunkGroup::Isolated(module),
755 ChunkGroupKey::IsolatedMerged { parent, merge_tag } => {
756 ChunkGroup::IsolatedMerged {
757 parent: parent.0 as usize,
758 merge_tag,
759 entries: merged_entries.into_iter().collect(),
760 }
761 }
762 ChunkGroupKey::Shared(module) => ChunkGroup::Shared(module),
763 ChunkGroupKey::SharedMerged { parent, merge_tag } => ChunkGroup::SharedMerged {
764 parent: parent.0 as usize,
765 merge_tag,
766 entries: merged_entries.into_iter().collect(),
767 },
768 })
769 .collect(),
770 }
771 .cell())
772 }
773 .instrument(span_outer)
774 .await
775}