@@ -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]
@@ -656,11 +561,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
656
561
657
562
// Import resolution
658
563
//
659
- // This is a fixed-point algorithm. We resolve imports until our efforts
660
- // are stymied by an unresolved import; then we bail out of the current
661
- // module and continue. We terminate successfully once no more imports
662
- // remain or unsuccessfully when no forward progress in resolving imports
663
- // is made.
564
+ // This is a batched fixed-point algorithm. Each import is resolved in
565
+ // isolation, with any side effects collected for later.
566
+ // After a full pass over the current set of `indeterminate_imports`,
567
+ // the collected side effects are committed together. The process
568
+ // repeats until either no imports remain or no further progress can
569
+ // be made.
664
570
665
571
/// Resolves all imports for the crate. This method performs the fixed-
666
572
/// point iteration.
@@ -669,18 +575,116 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
669
575
let mut indeterminate_count = self . indeterminate_imports . len ( ) * 3 ;
670
576
while indeterminate_count < prev_indeterminate_count {
671
577
prev_indeterminate_count = indeterminate_count;
672
- let mut outputs = ImportResolutionOutputs :: new ( ) ;
578
+ indeterminate_count = 0 ;
579
+ let mut import_resolutions = Vec :: new ( ) ;
673
580
self . assert_speculative = true ;
674
581
for import in mem:: take ( & mut self . indeterminate_imports ) {
675
582
let ( side_effect, import_indeterminate_count) = self . cm ( ) . resolve_import ( import) ;
676
583
indeterminate_count += import_indeterminate_count;
677
584
match import_indeterminate_count {
678
- 0 => outputs . determined_imports . push ( ( import, side_effect) ) ,
679
- _ => outputs . indeterminate_imports . push ( import) ,
585
+ 0 => import_resolutions . push ( ( import, side_effect) ) ,
586
+ _ => self . indeterminate_imports . push ( import) ,
680
587
}
681
588
}
682
589
self . assert_speculative = false ;
683
- outputs. commit ( self ) ;
590
+ self . commit_import_resolutions ( import_resolutions) ;
591
+ }
592
+ }
593
+
594
+ fn commit_import_resolutions (
595
+ & mut self ,
596
+ import_resolutions : Vec < ( Import < ' ra > , Option < SideEffect < ' ra > > ) > ,
597
+ ) {
598
+ self . determined_imports . reserve ( self . determined_imports . len ( ) ) ;
599
+
600
+ for ( import, side_effect) in import_resolutions {
601
+ self . determined_imports . push ( import) ;
602
+
603
+ let Some ( SideEffect { imported_module, bindings : side_effect_bindings } ) = side_effect
604
+ else {
605
+ return ;
606
+ } ;
607
+ import. imported_module . set ( Some ( imported_module) ) ;
608
+ let parent = import. parent_scope . module ;
609
+
610
+ match ( & import. kind , side_effect_bindings) {
611
+ (
612
+ ImportKind :: Single { target, bindings, .. } ,
613
+ SideEffectBindings :: Single { import_bindings } ,
614
+ ) => {
615
+ self . per_ns ( |this, ns| {
616
+ match import_bindings[ ns] {
617
+ Some ( Some ( binding) ) => {
618
+ if binding. is_assoc_item ( )
619
+ && !this. tcx . features ( ) . import_trait_associated_functions ( )
620
+ {
621
+ feature_err (
622
+ this. tcx . sess ,
623
+ sym:: import_trait_associated_functions,
624
+ import. span ,
625
+ "`use` associated items of traits is unstable" ,
626
+ )
627
+ . emit ( ) ;
628
+ }
629
+ this. define_binding_local ( parent, * target, ns, binding) ;
630
+ bindings[ ns] . set ( PendingBinding :: Ready ( Some ( binding) ) ) ;
631
+ }
632
+ Some ( None ) => {
633
+ // Don't remove underscores from `single_imports`, they were never added.
634
+ if target. name != kw:: Underscore {
635
+ let key = BindingKey :: new ( * target, ns) ;
636
+ this. update_local_resolution (
637
+ parent,
638
+ key,
639
+ false ,
640
+ |_, resolution| {
641
+ resolution. single_imports . swap_remove ( & import) ;
642
+ } ,
643
+ ) ;
644
+ }
645
+ bindings[ ns] . set ( PendingBinding :: Ready ( None ) ) ;
646
+ }
647
+ None => return ,
648
+ }
649
+ } ) ;
650
+ }
651
+ ( ImportKind :: Glob { id, .. } , SideEffectBindings :: Glob { import_bindings } ) => {
652
+ let ModuleOrUniformRoot :: Module ( module) = imported_module else {
653
+ self . dcx ( ) . emit_err ( CannotGlobImportAllCrates { span : import. span } ) ;
654
+ continue ;
655
+ } ;
656
+
657
+ if module. is_trait ( ) && !self . tcx . features ( ) . import_trait_associated_functions ( )
658
+ {
659
+ feature_err (
660
+ self . tcx . sess ,
661
+ sym:: import_trait_associated_functions,
662
+ import. span ,
663
+ "`use` associated items of traits is unstable" ,
664
+ )
665
+ . emit ( ) ;
666
+ }
667
+
668
+ module. glob_importers . borrow_mut ( ) . push ( import) ;
669
+
670
+ for ( binding, key, warn_ambiguity) in import_bindings {
671
+ let _ = self . try_define_local (
672
+ parent,
673
+ key. ident . 0 ,
674
+ key. ns ,
675
+ binding,
676
+ warn_ambiguity,
677
+ ) ;
678
+ }
679
+
680
+ self . record_partial_res ( * id, PartialRes :: new ( module. res ( ) . unwrap ( ) ) ) ;
681
+ }
682
+
683
+ ( _, SideEffectBindings :: None ) => { }
684
+
685
+ // Something weird happened, which shouldn't have happened.
686
+ _ => unreachable ! ( "Mismatched import kind and side effect" ) ,
687
+ }
684
688
}
685
689
}
686
690
@@ -997,7 +1001,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
997
1001
_ => unreachable ! ( ) ,
998
1002
} ;
999
1003
1000
- let mut import_bindings = bindings . clone ( ) . map ( |b| b . get ( ) ) ;
1004
+ let mut import_bindings = PerNS :: default ( ) ;
1001
1005
let mut indeterminate_count = 0 ;
1002
1006
self . reborrow ( ) . per_ns_cm ( |this, ns| {
1003
1007
if !type_ns_only || ns == TypeNS {
@@ -1015,12 +1019,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1015
1019
Ok ( binding) => {
1016
1020
// We need the `target`, `source` can be extracted.
1017
1021
let imported_binding = this. import ( binding, import) ;
1018
- PendingBinding :: Ready ( Some ( imported_binding) )
1022
+ Some ( Some ( imported_binding) )
1019
1023
}
1020
- Err ( Determinacy :: Determined ) => PendingBinding :: Ready ( None ) ,
1024
+ Err ( Determinacy :: Determined ) => Some ( None ) ,
1021
1025
Err ( Determinacy :: Undetermined ) => {
1022
1026
indeterminate_count += 1 ;
1023
- PendingBinding :: Pending
1027
+ None
1024
1028
}
1025
1029
} ;
1026
1030
import_bindings[ ns] = pending_binding;
@@ -1589,34 +1593,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
1589
1593
return SideEffectBindings :: None ;
1590
1594
}
1591
1595
1592
- // Ensure that `resolutions` isn't borrowed during `try_define`,
1593
- // since it might get updated via a glob cycle.
1594
- let bindings = self
1596
+ let import_bindings = self
1595
1597
. resolutions ( module)
1596
1598
. borrow ( )
1597
1599
. iter ( )
1598
1600
. filter_map ( |( key, resolution) | {
1599
- resolution. borrow ( ) . binding ( ) . map ( |binding| ( * key, binding) )
1601
+ let binding = resolution. borrow ( ) . binding ( ) ?;
1602
+ let mut key = * key;
1603
+ let scope =
1604
+ match key. ident . 0 . span . reverse_glob_adjust ( module. expansion , import. span ) {
1605
+ Some ( Some ( def) ) => self . expn_def_scope ( def) ,
1606
+ Some ( None ) => import. parent_scope . module ,
1607
+ None => return None ,
1608
+ } ;
1609
+ self . is_accessible_from ( binding. vis , scope) . then ( || {
1610
+ let imported_binding = self . import ( binding, import) ;
1611
+ let warn_ambiguity = self
1612
+ . resolution ( import. parent_scope . module , key)
1613
+ . and_then ( |r| r. binding ( ) )
1614
+ . is_some_and ( |binding| binding. warn_ambiguity_recursive ( ) ) ;
1615
+ ( imported_binding, key, warn_ambiguity)
1616
+ } )
1600
1617
} )
1601
1618
. collect :: < Vec < _ > > ( ) ;
1602
- let mut import_bindings = Vec :: with_capacity ( bindings. len ( ) ) ;
1603
- for ( mut key, binding) in bindings {
1604
- let scope = match key. ident . 0 . span . reverse_glob_adjust ( module. expansion , import. span ) {
1605
- Some ( Some ( def) ) => self . expn_def_scope ( def) ,
1606
- Some ( None ) => import. parent_scope . module ,
1607
- None => continue ,
1608
- } ;
1609
- if self . is_accessible_from ( binding. vis , scope) {
1610
- let imported_binding = self . import ( binding, import) ;
1611
- let warn_ambiguity = self
1612
- . resolution ( import. parent_scope . module , key)
1613
- . and_then ( |r| r. binding ( ) )
1614
- . is_some_and ( |binding| binding. warn_ambiguity_recursive ( ) ) ;
1615
- import_bindings. push ( ( imported_binding, key, warn_ambiguity) ) ;
1616
- }
1617
- }
1618
1619
1619
- // Record the destination of this import
1620
1620
SideEffectBindings :: Glob { import_bindings }
1621
1621
}
1622
1622
0 commit comments