@@ -13,7 +13,6 @@ use crate::{ResolutionError, Resolver, Segment, UseError};
13
13
14
14
use rustc_ast:: ast:: * ;
15
15
use rustc_ast:: ptr:: P ;
16
- use rustc_ast:: util:: lev_distance:: find_best_match_for_name;
17
16
use rustc_ast:: visit:: { self , AssocCtxt , FnCtxt , FnKind , Visitor } ;
18
17
use rustc_ast:: { unwrap_or, walk_list} ;
19
18
use rustc_ast_lowering:: ResolverAstLowering ;
@@ -101,6 +100,9 @@ crate enum RibKind<'a> {
101
100
/// upvars).
102
101
AssocItemRibKind ,
103
102
103
+ /// We passed through a closure. Disallow labels.
104
+ ClosureOrAsyncRibKind ,
105
+
104
106
/// We passed through a function definition. Disallow upvars.
105
107
/// Permit only those const parameters that are specified in the function's generics.
106
108
FnItemRibKind ,
@@ -124,11 +126,15 @@ crate enum RibKind<'a> {
124
126
}
125
127
126
128
impl RibKind < ' _ > {
127
- // Whether this rib kind contains generic parameters, as opposed to local
128
- // variables.
129
+ /// Whether this rib kind contains generic parameters, as opposed to local
130
+ /// variables.
129
131
crate fn contains_params ( & self ) -> bool {
130
132
match self {
131
- NormalRibKind | FnItemRibKind | ConstantItemRibKind | ModuleRibKind ( _)
133
+ NormalRibKind
134
+ | ClosureOrAsyncRibKind
135
+ | FnItemRibKind
136
+ | ConstantItemRibKind
137
+ | ModuleRibKind ( _)
132
138
| MacroDefinition ( _) => false ,
133
139
AssocItemRibKind | ItemRibKind ( _) | ForwardTyParamBanRibKind => true ,
134
140
}
@@ -474,7 +480,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
474
480
// Bail if there's no body.
475
481
FnKind :: Fn ( .., None ) => return visit:: walk_fn ( self , fn_kind, sp) ,
476
482
FnKind :: Fn ( FnCtxt :: Free | FnCtxt :: Foreign , ..) => FnItemRibKind ,
477
- FnKind :: Fn ( FnCtxt :: Assoc ( _) , ..) | FnKind :: Closure ( ..) => NormalRibKind ,
483
+ FnKind :: Fn ( FnCtxt :: Assoc ( _) , ..) => NormalRibKind ,
484
+ FnKind :: Closure ( ..) => ClosureOrAsyncRibKind ,
478
485
} ;
479
486
let previous_value =
480
487
replace ( & mut self . diagnostic_metadata . current_function , Some ( ( fn_kind, sp) ) ) ;
@@ -725,37 +732,81 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
725
732
}
726
733
}
727
734
728
- /// Searches the current set of local scopes for labels. Returns the first non-`None` label that
729
- /// is returned by the given predicate function
730
- ///
731
- /// Stops after meeting a closure.
732
- fn search_label < P , R > ( & self , mut ident : Ident , pred : P ) -> Option < R >
733
- where
734
- P : Fn ( & Rib < ' _ , NodeId > , Ident ) -> Option < R > ,
735
- {
736
- for rib in self . label_ribs . iter ( ) . rev ( ) {
737
- match rib. kind {
738
- NormalRibKind => { }
735
+ /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
736
+ /// label and reports an error if the label is not found or is unreachable.
737
+ fn resolve_label ( & self , mut label : Ident ) -> Option < NodeId > {
738
+ let mut suggestion = None ;
739
+
740
+ // Preserve the original span so that errors contain "in this macro invocation"
741
+ // information.
742
+ let original_span = label. span ;
743
+
744
+ for i in ( 0 ..self . label_ribs . len ( ) ) . rev ( ) {
745
+ let rib = & self . label_ribs [ i] ;
746
+
747
+ if let MacroDefinition ( def) = rib. kind {
739
748
// If an invocation of this macro created `ident`, give up on `ident`
740
749
// and switch to `ident`'s source from the macro definition.
741
- MacroDefinition ( def) => {
742
- if def == self . r . macro_def ( ident. span . ctxt ( ) ) {
743
- ident. span . remove_mark ( ) ;
744
- }
745
- }
746
- _ => {
747
- // Do not resolve labels across function boundary
748
- return None ;
750
+ if def == self . r . macro_def ( label. span . ctxt ( ) ) {
751
+ label. span . remove_mark ( ) ;
749
752
}
750
753
}
751
- let r = pred ( rib, ident) ;
752
- if r. is_some ( ) {
753
- return r;
754
+
755
+ let ident = label. normalize_to_macro_rules ( ) ;
756
+ if let Some ( ( ident, id) ) = rib. bindings . get_key_value ( & ident) {
757
+ return if self . is_label_valid_from_rib ( i) {
758
+ Some ( * id)
759
+ } else {
760
+ self . r . report_error (
761
+ original_span,
762
+ ResolutionError :: UnreachableLabel {
763
+ name : & label. name . as_str ( ) ,
764
+ definition_span : ident. span ,
765
+ suggestion,
766
+ } ,
767
+ ) ;
768
+
769
+ None
770
+ } ;
754
771
}
772
+
773
+ // Diagnostics: Check if this rib contains a label with a similar name, keep track of
774
+ // the first such label that is encountered.
775
+ suggestion = suggestion. or_else ( || self . suggestion_for_label_in_rib ( i, label) ) ;
755
776
}
777
+
778
+ self . r . report_error (
779
+ original_span,
780
+ ResolutionError :: UndeclaredLabel { name : & label. name . as_str ( ) , suggestion } ,
781
+ ) ;
756
782
None
757
783
}
758
784
785
+ /// Determine whether or not a label from the `rib_index`th label rib is reachable.
786
+ fn is_label_valid_from_rib ( & self , rib_index : usize ) -> bool {
787
+ let ribs = & self . label_ribs [ rib_index + 1 ..] ;
788
+
789
+ for rib in ribs {
790
+ match rib. kind {
791
+ NormalRibKind | MacroDefinition ( ..) => {
792
+ // Nothing to do. Continue.
793
+ }
794
+
795
+ AssocItemRibKind
796
+ | ClosureOrAsyncRibKind
797
+ | FnItemRibKind
798
+ | ItemRibKind ( ..)
799
+ | ConstantItemRibKind
800
+ | ModuleRibKind ( ..)
801
+ | ForwardTyParamBanRibKind => {
802
+ return false ;
803
+ }
804
+ }
805
+ }
806
+
807
+ true
808
+ }
809
+
759
810
fn resolve_adt ( & mut self , item : & ' ast Item , generics : & ' ast Generics ) {
760
811
debug ! ( "resolve_adt" ) ;
761
812
self . with_current_self_item ( item, |this| {
@@ -2044,35 +2095,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
2044
2095
}
2045
2096
2046
2097
ExprKind :: Break ( Some ( label) , _) | ExprKind :: Continue ( Some ( label) ) => {
2047
- let node_id = self . search_label ( label. ident , |rib, ident| {
2048
- rib. bindings . get ( & ident. normalize_to_macro_rules ( ) ) . cloned ( )
2049
- } ) ;
2050
- match node_id {
2051
- None => {
2052
- // Search again for close matches...
2053
- // Picks the first label that is "close enough", which is not necessarily
2054
- // the closest match
2055
- let close_match = self . search_label ( label. ident , |rib, ident| {
2056
- let names = rib. bindings . iter ( ) . filter_map ( |( id, _) | {
2057
- if id. span . ctxt ( ) == label. ident . span . ctxt ( ) {
2058
- Some ( & id. name )
2059
- } else {
2060
- None
2061
- }
2062
- } ) ;
2063
- find_best_match_for_name ( names, & ident. as_str ( ) , None )
2064
- } ) ;
2065
- self . r . record_partial_res ( expr. id , PartialRes :: new ( Res :: Err ) ) ;
2066
- self . r . report_error (
2067
- label. ident . span ,
2068
- ResolutionError :: UndeclaredLabel ( & label. ident . as_str ( ) , close_match) ,
2069
- ) ;
2070
- }
2071
- Some ( node_id) => {
2072
- // Since this res is a label, it is never read.
2073
- self . r . label_res_map . insert ( expr. id , node_id) ;
2074
- self . diagnostic_metadata . unused_labels . remove ( & node_id) ;
2075
- }
2098
+ if let Some ( node_id) = self . resolve_label ( label. ident ) {
2099
+ // Since this res is a label, it is never read.
2100
+ self . r . label_res_map . insert ( expr. id , node_id) ;
2101
+ self . diagnostic_metadata . unused_labels . remove ( & node_id) ;
2076
2102
}
2077
2103
2078
2104
// visit `break` argument if any
@@ -2144,21 +2170,26 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
2144
2170
// closure are detected as upvars rather than normal closure arg usages.
2145
2171
ExprKind :: Closure ( _, Async :: Yes { .. } , _, ref fn_decl, ref body, _span) => {
2146
2172
self . with_rib ( ValueNS , NormalRibKind , |this| {
2147
- // Resolve arguments:
2148
- this. resolve_params ( & fn_decl. inputs ) ;
2149
- // No need to resolve return type --
2150
- // the outer closure return type is `FnRetTy::Default`.
2173
+ this. with_label_rib ( ClosureOrAsyncRibKind , |this| {
2174
+ // Resolve arguments:
2175
+ this. resolve_params ( & fn_decl. inputs ) ;
2176
+ // No need to resolve return type --
2177
+ // the outer closure return type is `FnRetTy::Default`.
2151
2178
2152
- // Now resolve the inner closure
2153
- {
2154
- // No need to resolve arguments: the inner closure has none.
2155
- // Resolve the return type:
2156
- visit:: walk_fn_ret_ty ( this, & fn_decl. output ) ;
2157
- // Resolve the body
2158
- this. visit_expr ( body) ;
2159
- }
2179
+ // Now resolve the inner closure
2180
+ {
2181
+ // No need to resolve arguments: the inner closure has none.
2182
+ // Resolve the return type:
2183
+ visit:: walk_fn_ret_ty ( this, & fn_decl. output ) ;
2184
+ // Resolve the body
2185
+ this. visit_expr ( body) ;
2186
+ }
2187
+ } )
2160
2188
} ) ;
2161
2189
}
2190
+ ExprKind :: Async ( ..) | ExprKind :: Closure ( ..) => {
2191
+ self . with_label_rib ( ClosureOrAsyncRibKind , |this| visit:: walk_expr ( this, expr) ) ;
2192
+ }
2162
2193
_ => {
2163
2194
visit:: walk_expr ( self , expr) ;
2164
2195
}
0 commit comments