@@ -62,6 +62,7 @@ impl PartialEq for MatchImportKindNormal {
6262}
6363
6464#[ derive( Debug , PartialEq , Eq ) ]
65+ #[ expect( clippy:: box_collection) ]
6566pub enum MatchImportKind {
6667 /// The import is either external or not defined.
6768 _Ignore,
@@ -81,7 +82,7 @@ pub enum MatchImportKind {
8182 // The import resolved to multiple symbols via "export * from"
8283 Ambiguous {
8384 symbol_ref : SymbolRef ,
84- potentially_ambiguous_symbol_refs : Vec < SymbolRef > ,
85+ potentially_ambiguous_symbol_refs : Box < Vec < SymbolRef > > ,
8586 } ,
8687 NoMatch ,
8788}
@@ -145,12 +146,7 @@ impl LinkStage<'_> {
145146 . named_exports
146147 . iter ( )
147148 . map ( |( name, local) | {
148- let resolved_export = ResolvedExport {
149- symbol_ref : local. referenced ,
150- potentially_ambiguous_symbol_refs : None ,
151- came_from_cjs : local. came_from_commonjs ,
152- } ;
153- ( name. clone ( ) , resolved_export)
149+ ( name. clone ( ) , ResolvedExport :: new ( local. referenced , local. came_from_commonjs ) )
154150 } )
155151 . collect :: < FxHashMap < _ , _ > > ( ) ;
156152
@@ -222,15 +218,15 @@ impl LinkStage<'_> {
222218 {
223219 let main_ref = self . symbols . canonical_ref_for ( resolved_export. symbol_ref ) ;
224220
225- for ambiguous_ref in potentially_ambiguous_symbol_refs {
221+ for ambiguous_ref in potentially_ambiguous_symbol_refs. iter ( ) {
226222 let ambiguous_ref = self . symbols . canonical_ref_for ( * ambiguous_ref) ;
227223 if main_ref != ambiguous_ref {
228224 continue ' next_export;
229225 }
230226 }
231227 }
232228 sorted_and_non_ambiguous_resolved_exports
233- . push ( ( exported_name. clone ( ) , resolved_export. came_from_cjs ) ) ;
229+ . push ( ( exported_name. clone ( ) , resolved_export. came_from_commonjs ) ) ;
234230 }
235231 sorted_and_non_ambiguous_resolved_exports. sort_unstable ( ) ;
236232 meta. sorted_and_non_ambiguous_resolved_exports =
@@ -319,12 +315,19 @@ impl LinkStage<'_> {
319315 return ;
320316 } ;
321317
322- let is_cjsreexports = module. ast_usage . contains ( EcmaModuleAstUsage :: IsCjsReexport ) ;
323-
324- let cjs_reexport_module =
325- is_cjsreexports. then ( || module. import_records . first ( ) . unwrap ( ) . into_resolved_module ( ) ) ;
318+ let cjs_reexport_modules: Vec < ModuleIdx > =
319+ if module. ast_usage . contains ( EcmaModuleAstUsage :: IsCjsReexport ) {
320+ module
321+ . ecma_view
322+ . cjs_reexport_import_record_ids
323+ . iter ( )
324+ . filter_map ( |& rec_idx| module. import_records [ rec_idx] . resolved_module )
325+ . collect ( )
326+ } else {
327+ vec ! [ ]
328+ } ;
326329
327- for dep_id in module. star_export_module_ids ( ) . chain ( cjs_reexport_module ) {
330+ for dep_id in module. star_export_module_ids ( ) . chain ( cjs_reexport_modules ) {
328331 let Module :: Normal ( dep_module) = & normal_modules[ dep_id] else {
329332 continue ;
330333 } ;
@@ -348,20 +351,27 @@ impl LinkStage<'_> {
348351 // We have filled `resolve_exports` with `named_exports`. If the export is already exists, it means that the importer
349352 // has a named export with the same name. So the export from dep module is shadowed.
350353 if let Some ( resolved_export) = resolve_exports. get_mut ( exported_name) {
351- if named_export. referenced != resolved_export. symbol_ref && !resolved_export. came_from_cjs
352- {
353- resolved_export
354- . potentially_ambiguous_symbol_refs
355- . get_or_insert ( Vec :: default ( ) )
356- . push ( named_export. referenced ) ;
354+ if named_export. referenced != resolved_export. symbol_ref {
355+ if resolved_export. came_from_commonjs || named_export. came_from_commonjs {
356+ // CJS conflict: at least one side came from CJS (e.g., conditional re-exports
357+ // mixing ESM and CJS targets). Track these separately — they're expected runtime
358+ // branches, not static ambiguity errors.
359+ resolved_export
360+ . cjs_conflicting_symbol_refs
361+ . get_or_insert ( Box :: default ( ) )
362+ . push ( named_export. referenced ) ;
363+ } else {
364+ resolved_export
365+ . potentially_ambiguous_symbol_refs
366+ . get_or_insert ( Box :: default ( ) )
367+ . push ( named_export. referenced ) ;
368+ }
357369 }
358370 } else {
359- let resolved_export = ResolvedExport {
360- symbol_ref : named_export. referenced ,
361- potentially_ambiguous_symbol_refs : None ,
362- came_from_cjs : named_export. came_from_commonjs ,
363- } ;
364- resolve_exports. insert ( exported_name. clone ( ) , resolved_export) ;
371+ resolve_exports. insert (
372+ exported_name. clone ( ) ,
373+ ResolvedExport :: new ( named_export. referenced , named_export. came_from_commonjs ) ,
374+ ) ;
365375 }
366376 }
367377
@@ -422,7 +432,7 @@ impl LinkStage<'_> {
422432 let name = & prop. name ;
423433 let meta = & self . metas [ canonical_ref_owner. idx ] ;
424434 let export_symbol = meta. resolved_exports . get ( name) . and_then ( |resolved_export| {
425- ( !resolved_export. came_from_cjs ) . then_some ( resolved_export)
435+ ( !resolved_export. came_from_commonjs ) . then_some ( resolved_export)
426436 } ) ;
427437 let Some ( export_symbol) = export_symbol else {
428438 // when we try to resolve `a.b.c`, and found that `b` is not exported by module
@@ -539,7 +549,7 @@ impl LinkStage<'_> {
539549 . resolved_exports
540550 . get ( & member_expr_ref. prop_and_span_list [ cursor] . name )
541551 . and_then ( |resolved_export| {
542- resolved_export. came_from_cjs . then_some ( resolved_export)
552+ resolved_export. came_from_commonjs . then_some ( resolved_export)
543553 } )
544554 } )
545555 {
@@ -611,7 +621,7 @@ impl LinkStage<'_> {
611621 self . metas [ * cjs_module_idx]
612622 . resolved_exports
613623 . values ( )
614- . filter ( |e| e. came_from_cjs )
624+ . filter ( |e| e. came_from_commonjs )
615625 . map ( |e| e. symbol_ref ) ,
616626 ) ;
617627 }
@@ -842,7 +852,7 @@ impl BindImportsAndExportsContext<'_> {
842852 Specifier :: Literal ( literal_imported) => {
843853 match self . metas [ importee_id] . resolved_exports . get ( literal_imported) {
844854 Some ( export) => {
845- if export. came_from_cjs {
855+ if export. came_from_commonjs {
846856 ImportStatus :: DynamicFallbackWithCommonjsReference {
847857 namespace_ref : importee. namespace_object_ref ,
848858 commonjs_symbol : export. symbol_ref ,
@@ -853,7 +863,8 @@ impl BindImportsAndExportsContext<'_> {
853863 symbol : export. symbol_ref ,
854864 potentially_ambiguous_export_star_refs : export
855865 . potentially_ambiguous_symbol_refs
856- . clone ( )
866+ . as_deref ( )
867+ . cloned ( )
857868 . unwrap_or_default ( ) ,
858869 }
859870 }
@@ -1023,15 +1034,19 @@ impl BindImportsAndExportsContext<'_> {
10231034 if let MatchImportKind :: Normal ( MatchImportKindNormal { symbol, .. } ) = ret {
10241035 return MatchImportKind :: Ambiguous {
10251036 symbol_ref : symbol,
1026- potentially_ambiguous_symbol_refs : ambiguous_results
1027- . iter ( )
1028- . filter_map ( |kind| match * kind {
1029- MatchImportKind :: Normal ( MatchImportKindNormal { symbol, .. } ) => Some ( symbol) ,
1030- MatchImportKind :: Namespace { namespace_ref }
1031- | MatchImportKind :: NormalAndNamespace { namespace_ref, .. } => Some ( namespace_ref) ,
1032- _ => None ,
1033- } )
1034- . collect ( ) ,
1037+ potentially_ambiguous_symbol_refs : Box :: new (
1038+ ambiguous_results
1039+ . iter ( )
1040+ . filter_map ( |kind| match * kind {
1041+ MatchImportKind :: Normal ( MatchImportKindNormal { symbol, .. } ) => Some ( symbol) ,
1042+ MatchImportKind :: Namespace { namespace_ref }
1043+ | MatchImportKind :: NormalAndNamespace { namespace_ref, .. } => {
1044+ Some ( namespace_ref)
1045+ }
1046+ _ => None ,
1047+ } )
1048+ . collect ( ) ,
1049+ ) ,
10351050 } ;
10361051 }
10371052
0 commit comments