@@ -13,7 +13,6 @@ use crate::{ResolutionError, Resolver, Segment, UseError};
1313
1414use rustc_ast:: ast:: * ;
1515use rustc_ast:: ptr:: P ;
16- use rustc_ast:: util:: lev_distance:: find_best_match_for_name;
1716use rustc_ast:: visit:: { self , AssocCtxt , FnCtxt , FnKind , Visitor } ;
1817use rustc_ast:: { unwrap_or, walk_list} ;
1918use rustc_ast_lowering:: ResolverAstLowering ;
@@ -101,6 +100,9 @@ crate enum RibKind<'a> {
101100 /// upvars).
102101 AssocItemRibKind ,
103102
103+ /// We passed through a closure. Disallow labels.
104+ ClosureOrAsyncRibKind ,
105+
104106 /// We passed through a function definition. Disallow upvars.
105107 /// Permit only those const parameters that are specified in the function's generics.
106108 FnItemRibKind ,
@@ -124,11 +126,15 @@ crate enum RibKind<'a> {
124126}
125127
126128impl 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.
129131 crate fn contains_params ( & self ) -> bool {
130132 match self {
131- NormalRibKind | FnItemRibKind | ConstantItemRibKind | ModuleRibKind ( _)
133+ NormalRibKind
134+ | ClosureOrAsyncRibKind
135+ | FnItemRibKind
136+ | ConstantItemRibKind
137+ | ModuleRibKind ( _)
132138 | MacroDefinition ( _) => false ,
133139 AssocItemRibKind | ItemRibKind ( _) | ForwardTyParamBanRibKind => true ,
134140 }
@@ -474,7 +480,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
474480 // Bail if there's no body.
475481 FnKind :: Fn ( .., None ) => return visit:: walk_fn ( self , fn_kind, sp) ,
476482 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 ,
478485 } ;
479486 let previous_value =
480487 replace ( & mut self . diagnostic_metadata . current_function , Some ( ( fn_kind, sp) ) ) ;
@@ -725,37 +732,81 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
725732 }
726733 }
727734
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 {
739748 // If an invocation of this macro created `ident`, give up on `ident`
740749 // 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 ( ) ;
749752 }
750753 }
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+ } ;
754771 }
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) ) ;
755776 }
777+
778+ self . r . report_error (
779+ original_span,
780+ ResolutionError :: UndeclaredLabel { name : & label. name . as_str ( ) , suggestion } ,
781+ ) ;
756782 None
757783 }
758784
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+
759810 fn resolve_adt ( & mut self , item : & ' ast Item , generics : & ' ast Generics ) {
760811 debug ! ( "resolve_adt" ) ;
761812 self . with_current_self_item ( item, |this| {
@@ -2044,35 +2095,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
20442095 }
20452096
20462097 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) ;
20762102 }
20772103
20782104 // visit `break` argument if any
@@ -2144,21 +2170,26 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
21442170 // closure are detected as upvars rather than normal closure arg usages.
21452171 ExprKind :: Closure ( _, Async :: Yes { .. } , _, ref fn_decl, ref body, _span) => {
21462172 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`.
21512178
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+ } )
21602188 } ) ;
21612189 }
2190+ ExprKind :: Async ( ..) | ExprKind :: Closure ( ..) => {
2191+ self . with_label_rib ( ClosureOrAsyncRibKind , |this| visit:: walk_expr ( this, expr) ) ;
2192+ }
21622193 _ => {
21632194 visit:: walk_expr ( self , expr) ;
21642195 }
0 commit comments