@@ -41,125 +41,30 @@ use crate::{
41
41
42
42
type Res = def:: Res < NodeId > ;
43
43
44
+ /// The the side effect made when resolving the bindings for an underterminate import.
44
45
enum SideEffectBindings < ' ra > {
45
46
None ,
46
- Single { import_bindings : PerNS < PendingBinding < ' ra > > } ,
47
- Glob { import_bindings : Vec < ( NameBinding < ' ra > , BindingKey , bool /* warn_ambiguity */ ) > } ,
47
+ /// Side effect that should be applied to the field `bindings` of `ImportKind::Single`.
48
+ ///
49
+ /// The inner `Option` is the actual side effect, it tells us wether we found a binding
50
+ /// when resolving the import in this particular namespace.
51
+ /// The outer `Option` tells us if this side effect is present.
52
+ Single {
53
+ import_bindings : PerNS < Option < Option < NameBinding < ' ra > > > > ,
54
+ } ,
55
+ Glob {
56
+ import_bindings : Vec < ( NameBinding < ' ra > , BindingKey , bool /* warn_ambiguity */ ) > ,
57
+ } ,
48
58
}
49
59
60
+ /// The side effect made when resolving an undeterminate import.
50
61
struct SideEffect < ' ra > {
51
62
imported_module : ModuleOrUniformRoot < ' ra > ,
52
63
bindings : SideEffectBindings < ' ra > ,
53
64
}
54
65
55
- #[ derive( Default ) ]
56
- struct ImportResolutionOutputs < ' ra > {
57
- indeterminate_imports : Vec < Import < ' ra > > ,
58
- determined_imports : Vec < ( Import < ' ra > , Option < SideEffect < ' ra > > ) > ,
59
- }
60
-
61
- impl < ' ra > ImportResolutionOutputs < ' ra > {
62
- fn new ( ) -> Self {
63
- Default :: default ( )
64
- }
65
-
66
- fn commit < ' tcx > ( self , r : & mut Resolver < ' ra , ' tcx > ) {
67
- r. indeterminate_imports = self . indeterminate_imports ;
68
- r. determined_imports . reserve ( self . determined_imports . len ( ) ) ;
69
-
70
- for ( import, side_effect) in self . determined_imports {
71
- r. determined_imports . push ( import) ;
72
-
73
- let Some ( SideEffect { imported_module, bindings : side_effect_bindings } ) = side_effect
74
- else {
75
- return ;
76
- } ;
77
- import. imported_module . set ( Some ( imported_module) ) ;
78
- let parent = import. parent_scope . module ;
79
-
80
- match ( & import. kind , side_effect_bindings) {
81
- (
82
- ImportKind :: Single { target, bindings, .. } ,
83
- SideEffectBindings :: Single { import_bindings } ,
84
- ) => {
85
- r. per_ns ( |this, ns| {
86
- match import_bindings[ ns] {
87
- PendingBinding :: Ready ( Some ( binding) ) => {
88
- if binding. is_assoc_item ( )
89
- && !this. tcx . features ( ) . import_trait_associated_functions ( )
90
- {
91
- feature_err (
92
- this. tcx . sess ,
93
- sym:: import_trait_associated_functions,
94
- import. span ,
95
- "`use` associated items of traits is unstable" ,
96
- )
97
- . emit ( ) ;
98
- }
99
- this. define_binding_local ( parent, * target, ns, binding) ;
100
- }
101
- PendingBinding :: Ready ( None ) => {
102
- // Don't remove underscores from `single_imports`, they were never added.
103
- if target. name != kw:: Underscore {
104
- let key = BindingKey :: new ( * target, ns) ;
105
- this. update_local_resolution (
106
- parent,
107
- key,
108
- false ,
109
- |_, resolution| {
110
- resolution. single_imports . swap_remove ( & import) ;
111
- } ,
112
- ) ;
113
- }
114
- }
115
- _ => { }
116
- }
117
- bindings[ ns] . set ( import_bindings[ ns] ) ;
118
- } ) ;
119
- }
120
- ( ImportKind :: Glob { id, .. } , SideEffectBindings :: Glob { import_bindings } ) => {
121
- let ModuleOrUniformRoot :: Module ( module) = import. imported_module . get ( ) . unwrap ( )
122
- else {
123
- r. dcx ( ) . emit_err ( CannotGlobImportAllCrates { span : import. span } ) ;
124
- continue ;
125
- } ;
126
-
127
- if module. is_trait ( ) && !r. tcx . features ( ) . import_trait_associated_functions ( ) {
128
- feature_err (
129
- r. tcx . sess ,
130
- sym:: import_trait_associated_functions,
131
- import. span ,
132
- "`use` associated items of traits is unstable" ,
133
- )
134
- . emit ( ) ;
135
- }
136
-
137
- module. glob_importers . borrow_mut ( ) . push ( import) ;
138
-
139
- for ( binding, key, warn_ambiguity) in import_bindings {
140
- let _ = r. try_define_local (
141
- parent,
142
- key. ident . 0 ,
143
- key. ns ,
144
- binding,
145
- warn_ambiguity,
146
- ) ;
147
- }
148
-
149
- r. record_partial_res ( * id, PartialRes :: new ( module. res ( ) . unwrap ( ) ) ) ;
150
- }
151
-
152
- ( _, SideEffectBindings :: None ) => { }
153
-
154
- // Something weird happened, which shouldn't have happened.
155
- _ => unreachable ! ( "Mismatched import kind and side effect" ) ,
156
- }
157
- }
158
- }
159
- }
160
-
161
66
/// A [`NameBinding`] in the process of being resolved.
162
- #[ derive( Clone , Copy , Default , PartialEq ) ]
67
+ #[ derive( Clone , Copy , Default , PartialEq , Debug ) ]
163
68
pub ( crate ) enum PendingBinding < ' ra > {
164
69
Ready ( Option < NameBinding < ' ra > > ) ,
165
70
#[ default]
@@ -659,11 +564,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
659
564
660
565
// Import resolution
661
566
//
662
- // This is a fixed-point algorithm. We resolve imports until our efforts
663
- // are stymied by an unresolved import; then we bail out of the current
664
- // module and continue. We terminate successfully once no more imports
665
- // remain or unsuccessfully when no forward progress in resolving imports
666
- // is made.
567
+ // This is a batched fixed-point algorithm. Each import is resolved in
568
+ // isolation, with any side effects collected for later.
569
+ // After a full pass over the current set of `indeterminate_imports`,
570
+ // the collected side effects are committed together. The process
571
+ // repeats until either no imports remain or no further progress can
572
+ // be made.
667
573
668
574
/// Resolves all imports for the crate. This method performs the fixed-
669
575
/// point iteration.
@@ -672,18 +578,116 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
672
578
let mut indeterminate_count = self . indeterminate_imports . len ( ) * 3 ;
673
579
while indeterminate_count < prev_indeterminate_count {
674
580
prev_indeterminate_count = indeterminate_count;
675
- let mut outputs = ImportResolutionOutputs :: new ( ) ;
581
+ indeterminate_count = 0 ;
582
+ let mut import_resolutions = Vec :: new ( ) ;
676
583
self . assert_speculative = true ;
677
584
for import in mem:: take ( & mut self . indeterminate_imports ) {
678
585
let ( side_effect, import_indeterminate_count) = self . cm ( ) . resolve_import ( import) ;
679
586
indeterminate_count += import_indeterminate_count;
680
587
match import_indeterminate_count {
681
- 0 => outputs . determined_imports . push ( ( import, side_effect) ) ,
682
- _ => outputs . indeterminate_imports . push ( import) ,
588
+ 0 => import_resolutions . push ( ( import, side_effect) ) ,
589
+ _ => self . indeterminate_imports . push ( import) ,
683
590
}
684
591
}
685
592
self . assert_speculative = false ;
686
- outputs. commit ( self ) ;
593
+ self . commit_import_resolutions ( import_resolutions) ;
594
+ }
595
+ }
596
+
597
+ fn commit_import_resolutions (
598
+ & mut self ,
599
+ import_resolutions : Vec < ( Import < ' ra > , Option < SideEffect < ' ra > > ) > ,
600
+ ) {
601
+ self . determined_imports . reserve ( self . determined_imports . len ( ) ) ;
602
+
603
+ for ( import, side_effect) in import_resolutions {
604
+ self . determined_imports . push ( import) ;
605
+
606
+ let Some ( SideEffect { imported_module, bindings : side_effect_bindings } ) = side_effect
607
+ else {
608
+ return ;
609
+ } ;
610
+ import. imported_module . set ( Some ( imported_module) ) ;
611
+ let parent = import. parent_scope . module ;
612
+
613
+ match ( & import. kind , side_effect_bindings) {
614
+ (
615
+ ImportKind :: Single { target, bindings, .. } ,
616
+ SideEffectBindings :: Single { import_bindings } ,
617
+ ) => {
618
+ self . per_ns ( |this, ns| {
619
+ match import_bindings[ ns] {
620
+ Some ( Some ( binding) ) => {
621
+ if binding. is_assoc_item ( )
622
+ && !this. tcx . features ( ) . import_trait_associated_functions ( )
623
+ {
624
+ feature_err (
625
+ this. tcx . sess ,
626
+ sym:: import_trait_associated_functions,
627
+ import. span ,
628
+ "`use` associated items of traits is unstable" ,
629
+ )
630
+ . emit ( ) ;
631
+ }
632
+ this. define_binding_local ( parent, * target, ns, binding) ;
633
+ bindings[ ns] . set ( PendingBinding :: Ready ( Some ( binding) ) ) ;
634
+ }
635
+ Some ( None ) => {
636
+ // Don't remove underscores from `single_imports`, they were never added.
637
+ if target. name != kw:: Underscore {
638
+ let key = BindingKey :: new ( * target, ns) ;
639
+ this. update_local_resolution (
640
+ parent,
641
+ key,
642
+ false ,
643
+ |_, resolution| {
644
+ resolution. single_imports . swap_remove ( & import) ;
645
+ } ,
646
+ ) ;
647
+ }
648
+ bindings[ ns] . set ( PendingBinding :: Ready ( None ) ) ;
649
+ }
650
+ None => return ,
651
+ }
652
+ } ) ;
653
+ }
654
+ ( ImportKind :: Glob { id, .. } , SideEffectBindings :: Glob { import_bindings } ) => {
655
+ let ModuleOrUniformRoot :: Module ( module) = imported_module else {
656
+ self . dcx ( ) . emit_err ( CannotGlobImportAllCrates { span : import. span } ) ;
657
+ continue ;
658
+ } ;
659
+
660
+ if module. is_trait ( ) && !self . tcx . features ( ) . import_trait_associated_functions ( )
661
+ {
662
+ feature_err (
663
+ self . tcx . sess ,
664
+ sym:: import_trait_associated_functions,
665
+ import. span ,
666
+ "`use` associated items of traits is unstable" ,
667
+ )
668
+ . emit ( ) ;
669
+ }
670
+
671
+ module. glob_importers . borrow_mut ( ) . push ( import) ;
672
+
673
+ for ( binding, key, warn_ambiguity) in import_bindings {
674
+ let _ = self . try_define_local (
675
+ parent,
676
+ key. ident . 0 ,
677
+ key. ns ,
678
+ binding,
679
+ warn_ambiguity,
680
+ ) ;
681
+ }
682
+
683
+ self . record_partial_res ( * id, PartialRes :: new ( module. res ( ) . unwrap ( ) ) ) ;
684
+ }
685
+
686
+ ( _, SideEffectBindings :: None ) => { }
687
+
688
+ // Something weird happened, which shouldn't have happened.
689
+ _ => unreachable ! ( "Mismatched import kind and side effect" ) ,
690
+ }
687
691
}
688
692
}
689
693
@@ -1000,7 +1004,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1000
1004
_ => unreachable ! ( ) ,
1001
1005
} ;
1002
1006
1003
- let mut import_bindings = bindings . clone ( ) . map ( |b| b . get ( ) ) ;
1007
+ let mut import_bindings = PerNS :: default ( ) ;
1004
1008
let mut indeterminate_count = 0 ;
1005
1009
self . reborrow ( ) . per_ns_cm ( |this, ns| {
1006
1010
if !type_ns_only || ns == TypeNS {
@@ -1018,12 +1022,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1018
1022
Ok ( binding) => {
1019
1023
// We need the `target`, `source` can be extracted.
1020
1024
let imported_binding = this. import ( binding, import) ;
1021
- PendingBinding :: Ready ( Some ( imported_binding) )
1025
+ Some ( Some ( imported_binding) )
1022
1026
}
1023
- Err ( Determinacy :: Determined ) => PendingBinding :: Ready ( None ) ,
1027
+ Err ( Determinacy :: Determined ) => Some ( None ) ,
1024
1028
Err ( Determinacy :: Undetermined ) => {
1025
1029
indeterminate_count += 1 ;
1026
- PendingBinding :: Pending
1030
+ None
1027
1031
}
1028
1032
} ;
1029
1033
import_bindings[ ns] = pending_binding;
@@ -1595,34 +1599,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1595
1599
return SideEffectBindings :: None ;
1596
1600
}
1597
1601
1598
- // Ensure that `resolutions` isn't borrowed during `try_define`,
1599
- // since it might get updated via a glob cycle.
1600
- let bindings = self
1602
+ let import_bindings = self
1601
1603
. resolutions ( module)
1602
1604
. borrow ( )
1603
1605
. iter ( )
1604
1606
. filter_map ( |( key, resolution) | {
1605
- resolution. borrow ( ) . binding ( ) . map ( |binding| ( * key, binding) )
1607
+ let binding = resolution. borrow ( ) . binding ( ) ?;
1608
+ let mut key = * key;
1609
+ let scope =
1610
+ match key. ident . 0 . span . reverse_glob_adjust ( module. expansion , import. span ) {
1611
+ Some ( Some ( def) ) => self . expn_def_scope ( def) ,
1612
+ Some ( None ) => import. parent_scope . module ,
1613
+ None => return None ,
1614
+ } ;
1615
+ self . is_accessible_from ( binding. vis , scope) . then ( || {
1616
+ let imported_binding = self . import ( binding, import) ;
1617
+ let warn_ambiguity = self
1618
+ . resolution ( import. parent_scope . module , key)
1619
+ . and_then ( |r| r. binding ( ) )
1620
+ . is_some_and ( |binding| binding. warn_ambiguity_recursive ( ) ) ;
1621
+ ( imported_binding, key, warn_ambiguity)
1622
+ } )
1606
1623
} )
1607
1624
. collect :: < Vec < _ > > ( ) ;
1608
- let mut import_bindings = Vec :: with_capacity ( bindings. len ( ) ) ;
1609
- for ( mut key, binding) in bindings {
1610
- let scope = match key. ident . 0 . span . reverse_glob_adjust ( module. expansion , import. span ) {
1611
- Some ( Some ( def) ) => self . expn_def_scope ( def) ,
1612
- Some ( None ) => import. parent_scope . module ,
1613
- None => continue ,
1614
- } ;
1615
- if self . is_accessible_from ( binding. vis , scope) {
1616
- let imported_binding = self . import ( binding, import) ;
1617
- let warn_ambiguity = self
1618
- . resolution ( import. parent_scope . module , key)
1619
- . and_then ( |r| r. binding ( ) )
1620
- . is_some_and ( |binding| binding. warn_ambiguity_recursive ( ) ) ;
1621
- import_bindings. push ( ( imported_binding, key, warn_ambiguity) ) ;
1622
- }
1623
- }
1624
1625
1625
- // Record the destination of this import
1626
1626
SideEffectBindings :: Glob { import_bindings }
1627
1627
}
1628
1628
0 commit comments