@@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate {
131131}
132132
133133/// Only used for diagnostics.
134+ #[ derive( Debug ) ]
134135struct BaseError {
135136 msg : String ,
136137 fallback_label : String ,
@@ -140,6 +141,22 @@ struct BaseError {
140141 suggestion : Option < ( Span , & ' static str , String ) > ,
141142}
142143
144+ #[ derive( Debug ) ]
145+ enum TypoCandidate {
146+ Typo ( TypoSuggestion ) ,
147+ Shadowed ( Res ) ,
148+ None ,
149+ }
150+
151+ impl TypoCandidate {
152+ fn to_opt_suggestion ( self ) -> Option < TypoSuggestion > {
153+ match self {
154+ TypoCandidate :: Typo ( sugg) => Some ( sugg) ,
155+ TypoCandidate :: Shadowed ( _) | TypoCandidate :: None => None ,
156+ }
157+ }
158+ }
159+
143160impl < ' a : ' ast , ' ast > LateResolutionVisitor < ' a , ' _ , ' ast > {
144161 fn def_span ( & self , def_id : DefId ) -> Option < Span > {
145162 match def_id. krate {
@@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
496513 }
497514
498515 // Try Levenshtein algorithm.
499- let typo_sugg = self . lookup_typo_candidate ( path, source. namespace ( ) , is_expected) ;
516+ let typo_sugg =
517+ self . lookup_typo_candidate ( path, source. namespace ( ) , is_expected) . to_opt_suggestion ( ) ;
500518 if path. len ( ) == 1 && self . self_type_is_available ( ) {
501519 if let Some ( candidate) = self . lookup_assoc_candidate ( ident, ns, is_expected) {
502520 let self_is_available = self . self_value_is_available ( path[ 0 ] . ident . span ) ;
@@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
660678 let is_expected = & |res| source. is_expected ( res) ;
661679 let ident_span = path. last ( ) . map_or ( span, |ident| ident. ident . span ) ;
662680 let typo_sugg = self . lookup_typo_candidate ( path, source. namespace ( ) , is_expected) ;
681+ if let TypoCandidate :: Shadowed ( res) = typo_sugg
682+ && let Some ( id) = res. opt_def_id ( )
683+ && let Some ( sugg_span) = self . r . opt_span ( id)
684+ {
685+ err. span_label (
686+ sugg_span,
687+ format ! ( "you might have meant to refer to this {}" , res. descr( ) ) ,
688+ ) ;
689+ return true ;
690+ }
663691 let mut fallback = false ;
692+ let typo_sugg = typo_sugg. to_opt_suggestion ( ) ;
664693 if !self . r . add_typo_suggestion ( err, typo_sugg, ident_span) {
665694 fallback = true ;
666695 match self . diagnostic_metadata . current_let_binding {
@@ -1581,22 +1610,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
15811610 path : & [ Segment ] ,
15821611 ns : Namespace ,
15831612 filter_fn : & impl Fn ( Res ) -> bool ,
1584- ) -> Option < TypoSuggestion > {
1613+ ) -> TypoCandidate {
15851614 let mut names = Vec :: new ( ) ;
15861615 if path. len ( ) == 1 {
1616+ let mut ctxt = path. last ( ) . unwrap ( ) . ident . span . ctxt ( ) ;
1617+
15871618 // Search in lexical scope.
15881619 // Walk backwards up the ribs in scope and collect candidates.
15891620 for rib in self . ribs [ ns] . iter ( ) . rev ( ) {
1621+ let rib_ctxt = if rib. kind . contains_params ( ) {
1622+ ctxt. normalize_to_macros_2_0 ( )
1623+ } else {
1624+ ctxt. normalize_to_macro_rules ( )
1625+ } ;
1626+
15901627 // Locals and type parameters
15911628 for ( ident, & res) in & rib. bindings {
1592- if filter_fn ( res) {
1629+ if filter_fn ( res) && ident . span . ctxt ( ) == rib_ctxt {
15931630 names. push ( TypoSuggestion :: typo_from_res ( ident. name , res) ) ;
15941631 }
15951632 }
1633+
1634+ if let RibKind :: MacroDefinition ( def) = rib. kind && def == self . r . macro_def ( ctxt) {
1635+ // If an invocation of this macro created `ident`, give up on `ident`
1636+ // and switch to `ident`'s source from the macro definition.
1637+ ctxt. remove_mark ( ) ;
1638+ continue ;
1639+ }
1640+
15961641 // Items in scope
15971642 if let RibKind :: ModuleRibKind ( module) = rib. kind {
15981643 // Items from this module
1599- self . r . add_module_candidates ( module, & mut names, & filter_fn) ;
1644+ self . r . add_module_candidates ( module, & mut names, & filter_fn, Some ( ctxt ) ) ;
16001645
16011646 if let ModuleKind :: Block = module. kind {
16021647 // We can see through blocks
@@ -1622,7 +1667,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16221667 } ) ) ;
16231668
16241669 if let Some ( prelude) = self . r . prelude {
1625- self . r . add_module_candidates ( prelude, & mut names, & filter_fn) ;
1670+ self . r . add_module_candidates ( prelude, & mut names, & filter_fn, None ) ;
16261671 }
16271672 }
16281673 break ;
@@ -1641,7 +1686,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16411686 if let PathResult :: Module ( ModuleOrUniformRoot :: Module ( module) ) =
16421687 self . resolve_path ( mod_path, Some ( TypeNS ) , None )
16431688 {
1644- self . r . add_module_candidates ( module, & mut names, & filter_fn) ;
1689+ self . r . add_module_candidates ( module, & mut names, & filter_fn, None ) ;
16451690 }
16461691 }
16471692
@@ -1654,10 +1699,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16541699 name,
16551700 None ,
16561701 ) {
1657- Some ( found) if found != name => {
1658- names. into_iter ( ) . find ( |suggestion| suggestion. candidate == found)
1702+ Some ( found) => {
1703+ let Some ( sugg) = names. into_iter ( ) . find ( |suggestion| suggestion. candidate == found) else {
1704+ return TypoCandidate :: None ;
1705+ } ;
1706+ if found == name {
1707+ TypoCandidate :: Shadowed ( sugg. res )
1708+ } else {
1709+ TypoCandidate :: Typo ( sugg)
1710+ }
16591711 }
1660- _ => None ,
1712+ _ => TypoCandidate :: None ,
16611713 }
16621714 }
16631715
0 commit comments