@@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate {
131
131
}
132
132
133
133
/// Only used for diagnostics.
134
+ #[ derive( Debug ) ]
134
135
struct BaseError {
135
136
msg : String ,
136
137
fallback_label : String ,
@@ -140,6 +141,22 @@ struct BaseError {
140
141
suggestion : Option < ( Span , & ' static str , String ) > ,
141
142
}
142
143
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
+
143
160
impl < ' a : ' ast , ' ast > LateResolutionVisitor < ' a , ' _ , ' ast > {
144
161
fn def_span ( & self , def_id : DefId ) -> Option < Span > {
145
162
match def_id. krate {
@@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
496
513
}
497
514
498
515
// 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 ( ) ;
500
518
if path. len ( ) == 1 && self . self_type_is_available ( ) {
501
519
if let Some ( candidate) = self . lookup_assoc_candidate ( ident, ns, is_expected) {
502
520
let self_is_available = self . self_value_is_available ( path[ 0 ] . ident . span ) ;
@@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
660
678
let is_expected = & |res| source. is_expected ( res) ;
661
679
let ident_span = path. last ( ) . map_or ( span, |ident| ident. ident . span ) ;
662
680
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
+ }
663
691
let mut fallback = false ;
692
+ let typo_sugg = typo_sugg. to_opt_suggestion ( ) ;
664
693
if !self . r . add_typo_suggestion ( err, typo_sugg, ident_span) {
665
694
fallback = true ;
666
695
match self . diagnostic_metadata . current_let_binding {
@@ -1581,22 +1610,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
1581
1610
path : & [ Segment ] ,
1582
1611
ns : Namespace ,
1583
1612
filter_fn : & impl Fn ( Res ) -> bool ,
1584
- ) -> Option < TypoSuggestion > {
1613
+ ) -> TypoCandidate {
1585
1614
let mut names = Vec :: new ( ) ;
1586
1615
if path. len ( ) == 1 {
1616
+ let mut ctxt = path. last ( ) . unwrap ( ) . ident . span . ctxt ( ) ;
1617
+
1587
1618
// Search in lexical scope.
1588
1619
// Walk backwards up the ribs in scope and collect candidates.
1589
1620
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
+
1590
1627
// Locals and type parameters
1591
1628
for ( ident, & res) in & rib. bindings {
1592
- if filter_fn ( res) {
1629
+ if filter_fn ( res) && ident . span . ctxt ( ) == rib_ctxt {
1593
1630
names. push ( TypoSuggestion :: typo_from_res ( ident. name , res) ) ;
1594
1631
}
1595
1632
}
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
+
1596
1641
// Items in scope
1597
1642
if let RibKind :: ModuleRibKind ( module) = rib. kind {
1598
1643
// 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 ) ) ;
1600
1645
1601
1646
if let ModuleKind :: Block = module. kind {
1602
1647
// We can see through blocks
@@ -1622,7 +1667,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
1622
1667
} ) ) ;
1623
1668
1624
1669
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 ) ;
1626
1671
}
1627
1672
}
1628
1673
break ;
@@ -1641,7 +1686,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
1641
1686
if let PathResult :: Module ( ModuleOrUniformRoot :: Module ( module) ) =
1642
1687
self . resolve_path ( mod_path, Some ( TypeNS ) , None )
1643
1688
{
1644
- self . r . add_module_candidates ( module, & mut names, & filter_fn) ;
1689
+ self . r . add_module_candidates ( module, & mut names, & filter_fn, None ) ;
1645
1690
}
1646
1691
}
1647
1692
@@ -1654,10 +1699,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
1654
1699
name,
1655
1700
None ,
1656
1701
) {
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
+ }
1659
1711
}
1660
- _ => None ,
1712
+ _ => TypoCandidate :: None ,
1661
1713
}
1662
1714
}
1663
1715
0 commit comments