@@ -40,9 +40,9 @@ use thin_vec::ThinVec;
40
40
use tracing:: { debug, instrument, trace} ;
41
41
42
42
use crate :: {
43
- BindingError , BindingKey , Finalize , LexicalScopeBinding , Module , ModuleOrUniformRoot ,
44
- NameBinding , ParentScope , PathResult , ResolutionError , Resolver , Segment , TyCtxt , UseError ,
45
- Used , errors, path_names_to_string, rustdoc,
43
+ BindingError , BindingKey , Finalize , LexicalScopeBinding , LookaheadItemInBlock , Module ,
44
+ ModuleOrUniformRoot , NameBinding , ParentScope , PathResult , ResolutionError , Resolver , Segment ,
45
+ TyCtxt , UseError , Used , errors, path_names_to_string, rustdoc,
46
46
} ;
47
47
48
48
mod diagnostics;
@@ -193,6 +193,26 @@ pub(crate) enum RibKind<'ra> {
193
193
/// No restriction needs to be applied.
194
194
Normal ,
195
195
196
+ /// During resolving an item in a block, we had records all bindings defined
197
+ /// in this local scope, for these features:
198
+ ///
199
+ /// - Forward reference detection:
200
+ ///
201
+ /// ```ignore (illustrative)
202
+ /// let a = b; // displays '`b` is defined at <span>' instead of ''b' not found'
203
+ /// let b = 42;
204
+ /// ```
205
+ ///
206
+ /// - Correctly resolves the hoisting bindings within macro expand:
207
+ ///
208
+ /// ```ignore (illustrative)
209
+ /// let f = || -> i16 { 42 };
210
+ /// let a: i16 = m!(); // use the local `f` rather than throw an error
211
+ /// macro_rules! m {() => ( f() )}
212
+ /// use m;
213
+ /// ```
214
+ BlockItem { block : NodeId , resolving : NodeId } ,
215
+
196
216
/// We passed through an impl or trait and are now in one of its
197
217
/// methods or associated types. Allow references to ty params that impl or trait
198
218
/// binds. Disallow any other upvars (including other ty params that are
@@ -217,41 +237,6 @@ pub(crate) enum RibKind<'ra> {
217
237
/// We passed through a `macro_rules!` statement
218
238
MacroDefinition ( DefId ) ,
219
239
220
- /// Collects `macro_rules!` statements prior to resolution.
221
- /// For example:
222
- ///
223
- /// ```ignore (illustrative)
224
- /// let f = || -> i16 { 42 }; // <1>
225
- /// let a: i16 = m!(); // <2>
226
- /// macro_rules! m {() => ( f() )} // <3>
227
- /// use m; // <4>
228
- /// ```
229
- ///
230
- /// We record `<1>` when resolving the value of `<2>` (the expansion
231
- /// result of `<3>`), enabling the system to recognize that `<1>` is
232
- /// referenced in `<3>`.
233
- ///
234
- /// ### Why Not Use `MacroDefinition` Directly?
235
- ///
236
- /// This prevents edge cases like:
237
- ///
238
- /// ```ignore (illustrative)
239
- /// fn f() {
240
- /// let x = 0; // <1>
241
- /// macro_rules! foo {
242
- /// () => {
243
- /// assert_eq!(x, 0);
244
- /// }
245
- /// }
246
- /// let x = 1; // <2>
247
- /// foo!();
248
- /// }
249
- /// ```
250
- ///
251
- /// Using `MacroDefinition` would incorrectly record both `<1>` and `<2>` as
252
- /// potential resolutions for `x` within the macro, leading to assertion failed.
253
- LookAheadMacroDefinition ( DefId ) ,
254
-
255
240
/// All bindings in this rib are generic parameters that can't be used
256
241
/// from the default of a generic parameter because they're not declared
257
242
/// before said generic parameter. Also see the `visit_generics` override.
@@ -278,11 +263,11 @@ impl RibKind<'_> {
278
263
pub ( crate ) fn contains_params ( & self ) -> bool {
279
264
match self {
280
265
RibKind :: Normal
266
+ | RibKind :: BlockItem { .. }
281
267
| RibKind :: FnOrCoroutine
282
268
| RibKind :: ConstantItem ( ..)
283
269
| RibKind :: Module ( _)
284
270
| RibKind :: MacroDefinition ( _)
285
- | RibKind :: LookAheadMacroDefinition ( _)
286
271
| RibKind :: InlineAsmSym => false ,
287
272
RibKind :: ConstParamTy
288
273
| RibKind :: AssocItem
@@ -294,9 +279,7 @@ impl RibKind<'_> {
294
279
/// This rib forbids referring to labels defined in upwards ribs.
295
280
fn is_label_barrier ( self ) -> bool {
296
281
match self {
297
- RibKind :: Normal
298
- | RibKind :: MacroDefinition ( ..)
299
- | RibKind :: LookAheadMacroDefinition ( ..) => false ,
282
+ RibKind :: Normal | RibKind :: BlockItem { .. } | RibKind :: MacroDefinition ( ..) => false ,
300
283
301
284
RibKind :: AssocItem
302
285
| RibKind :: FnOrCoroutine
@@ -3818,21 +3801,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
3818
3801
3819
3802
/// Apply the bindings from a pattern to the innermost rib of the current scope.
3820
3803
fn apply_pattern_bindings ( & mut self , mut pat_bindings : PatternBindings ) {
3804
+ let rib_bindings = self . innermost_rib_bindings ( ValueNS ) ;
3821
3805
let Some ( ( _, pat_bindings) ) = pat_bindings. pop ( ) else {
3822
3806
bug ! ( "tried applying nonexistent bindings from pattern" ) ;
3823
3807
} ;
3824
- for rib in self . ribs [ ValueNS ] . iter_mut ( ) . rev ( ) {
3825
- let stop = !matches ! ( rib. kind, RibKind :: LookAheadMacroDefinition ( _) ) ;
3826
- if rib. bindings . is_empty ( ) {
3827
- // Often, such as for match arms, the bindings are introduced into a new rib.
3828
- // In this case, we can move the bindings over directly.
3829
- rib. bindings = pat_bindings. clone ( ) ;
3830
- } else {
3831
- rib. bindings . extend ( pat_bindings. clone ( ) ) ;
3832
- }
3833
- if stop {
3834
- break ;
3835
- }
3808
+ if rib_bindings. is_empty ( ) {
3809
+ // Often, such as for match arms, the bindings are introduced into a new rib.
3810
+ // In this case, we can move the bindings over directly.
3811
+ * rib_bindings = pat_bindings;
3812
+ } else {
3813
+ rib_bindings. extend ( pat_bindings) ;
3836
3814
}
3837
3815
}
3838
3816
@@ -3888,9 +3866,20 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
3888
3866
// First try to resolve the identifier as some existing entity,
3889
3867
// then fall back to a fresh binding.
3890
3868
let has_sub = sub. is_some ( ) ;
3869
+ if let Some ( RibKind :: BlockItem { resolving, .. } ) =
3870
+ self . label_ribs . last_mut ( ) . map ( |rib| & mut rib. kind )
3871
+ {
3872
+ debug_assert_eq ! ( * resolving, DUMMY_NODE_ID ) ;
3873
+ * resolving = pat. id ;
3874
+ }
3891
3875
let res = self
3892
3876
. try_resolve_as_non_binding ( pat_src, bmode, ident, has_sub)
3893
3877
. unwrap_or_else ( || self . fresh_binding ( ident, pat. id , pat_src, bindings) ) ;
3878
+ if let Some ( RibKind :: BlockItem { resolving, .. } ) =
3879
+ self . label_ribs . last_mut ( ) . map ( |rib| & mut rib. kind )
3880
+ {
3881
+ * resolving = DUMMY_NODE_ID ;
3882
+ }
3894
3883
self . r . record_partial_res ( pat. id , PartialRes :: new ( res) ) ;
3895
3884
self . r . record_pat_span ( pat. id , pat. span ) ;
3896
3885
}
@@ -4712,15 +4701,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
4712
4701
}
4713
4702
4714
4703
// Descend into the block.
4715
- for stmt in & block. stmts {
4716
- if let StmtKind :: Item ( ref item) = stmt. kind
4717
- && let ItemKind :: MacroDef ( ..) = item. kind
4718
- {
4719
- let res = self . r . local_def_id ( item. id ) . to_def_id ( ) ;
4720
- self . ribs [ ValueNS ] . push ( Rib :: new ( RibKind :: LookAheadMacroDefinition ( res) ) ) ;
4721
- }
4722
- }
4723
-
4724
4704
for stmt in & block. stmts {
4725
4705
if let StmtKind :: Item ( ref item) = stmt. kind
4726
4706
&& let ItemKind :: MacroDef ( ..) = item. kind
@@ -4731,14 +4711,22 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
4731
4711
self . label_ribs . push ( Rib :: new ( RibKind :: MacroDefinition ( res) ) ) ;
4732
4712
}
4733
4713
4714
+
4715
+ self . with_rib (
4716
+ ValueNS ,
4717
+ RibKind :: BlockItem { block : block. id , resolving : DUMMY_NODE_ID } ,
4718
+ |this| {
4719
+ this. visit_stmt ( stmt) ;
4720
+ } ,
4721
+ ) ;
4722
+
4734
4723
self . visit_stmt ( stmt) ;
4735
4724
}
4736
4725
4737
4726
// Move back up.
4738
4727
self . parent_scope . module = orig_module;
4739
4728
for _ in 0 ..num_macro_definition_ribs {
4740
- // pop `LookAheadMacroDefinition` and `MacroDefinition`
4741
- self . ribs [ ValueNS ] . pop ( ) ;
4729
+ // pop `MacroDefinition`
4742
4730
self . ribs [ ValueNS ] . pop ( ) ;
4743
4731
self . label_ribs . pop ( ) ;
4744
4732
}
@@ -5199,6 +5187,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
5199
5187
/// lifetime generic parameters and function parameters.
5200
5188
struct ItemInfoCollector < ' a , ' ra , ' tcx > {
5201
5189
r : & ' a mut Resolver < ' ra , ' tcx > ,
5190
+ current_block : Option < NodeId > ,
5202
5191
}
5203
5192
5204
5193
impl ItemInfoCollector < ' _ , ' _ , ' _ > {
@@ -5218,6 +5207,26 @@ impl ItemInfoCollector<'_, '_, '_> {
5218
5207
} ;
5219
5208
self . r . delegation_fn_sigs . insert ( self . r . local_def_id ( id) , sig) ;
5220
5209
}
5210
+
5211
+ fn collect_fresh_binding ( & mut self , binding : NodeId , name : Ident ) {
5212
+ let block_id = self . current_block . unwrap ( ) ;
5213
+ let items = self . r . lookahead_items_in_block . entry ( block_id) . or_default ( ) ;
5214
+ items. insert ( binding, LookaheadItemInBlock :: Binding { name } ) ;
5215
+ }
5216
+
5217
+ fn collect_macro_def_in_block ( & mut self , block_id : NodeId , node_id : NodeId , name : Symbol ) {
5218
+ let items = self . r . lookahead_items_in_block . entry ( block_id) . or_default ( ) ;
5219
+ items. insert ( node_id, LookaheadItemInBlock :: MacroDef { name } ) ;
5220
+ }
5221
+
5222
+ fn collect_fresh_binding_in_pat ( & mut self , pat : & ast:: Pat ) {
5223
+ pat. walk ( & mut |pat| {
5224
+ if let PatKind :: Ident ( _, name, _) = & pat. kind {
5225
+ self . collect_fresh_binding ( pat. id , * name) ;
5226
+ }
5227
+ true
5228
+ } ) ;
5229
+ }
5221
5230
}
5222
5231
5223
5232
impl < ' ast > Visitor < ' ast > for ItemInfoCollector < ' _ , ' _ , ' _ > {
@@ -5255,11 +5264,15 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
5255
5264
}
5256
5265
}
5257
5266
5267
+ ItemKind :: MacroDef ( m, _) => {
5268
+ if let Some ( block_id) = self . current_block {
5269
+ self . collect_macro_def_in_block ( block_id, item. id , m. name ) ;
5270
+ }
5271
+ }
5258
5272
ItemKind :: Mod ( ..)
5259
5273
| ItemKind :: Static ( ..)
5260
5274
| ItemKind :: Use ( ..)
5261
5275
| ItemKind :: ExternCrate ( ..)
5262
- | ItemKind :: MacroDef ( ..)
5263
5276
| ItemKind :: GlobalAsm ( ..)
5264
5277
| ItemKind :: MacCall ( ..)
5265
5278
| ItemKind :: DelegationMac ( ..) => { }
@@ -5279,11 +5292,22 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
5279
5292
}
5280
5293
visit:: walk_assoc_item ( self , item, ctxt) ;
5281
5294
}
5295
+
5296
+ fn visit_local ( & mut self , node : & ' ast Local ) -> Self :: Result {
5297
+ self . collect_fresh_binding_in_pat ( & node. pat ) ;
5298
+ visit:: walk_local ( self , node)
5299
+ }
5300
+
5301
+ fn visit_block ( & mut self , node : & ' ast Block ) -> Self :: Result {
5302
+ let saved_block_id = self . current_block . replace ( node. id ) ;
5303
+ visit:: walk_block ( self , node) ;
5304
+ self . current_block = saved_block_id;
5305
+ }
5282
5306
}
5283
5307
5284
5308
impl < ' ra , ' tcx > Resolver < ' ra , ' tcx > {
5285
5309
pub ( crate ) fn late_resolve_crate ( & mut self , krate : & Crate ) {
5286
- visit:: walk_crate ( & mut ItemInfoCollector { r : self } , krate) ;
5310
+ visit:: walk_crate ( & mut ItemInfoCollector { r : self , current_block : None } , krate) ;
5287
5311
let mut late_resolution_visitor = LateResolutionVisitor :: new ( self ) ;
5288
5312
late_resolution_visitor. resolve_doc_links ( & krate. attrs , MaybeExported :: Ok ( CRATE_NODE_ID ) ) ;
5289
5313
visit:: walk_crate ( & mut late_resolution_visitor, krate) ;
0 commit comments