about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-07-10 12:01:32 +0200
committerGitHub <noreply@github.com>2023-07-10 12:01:32 +0200
commit70c637808fdf43f5baf3e2359f3a0113d8f814fd (patch)
treeeb57078e645c0b4e2685d18194027e76219e2f3b /compiler/rustc_resolve/src
parent743333f3dd90721461c09387ec73d09c080d5f5f (diff)
parent37b40e592a71ce5c0af7901857f4123f6ff410f3 (diff)
downloadrust-70c637808fdf43f5baf3e2359f3a0113d8f814fd.tar.gz
rust-70c637808fdf43f5baf3e2359f3a0113d8f814fd.zip
Rollup merge of #113331 - chenyukang:yukang-fix-112590-false-positive, r=estebank
Add filter with following segment while lookup typo for path

From the discussion: https://github.com/rust-lang/rust/pull/112917#discussion_r1239150173

Seems we can not get the assoc items for `Struct`, `Enum` in the resolving phase.
A obvious filter is avoid suggesting the same name with the following segment path.

Use `following_seg` can extend the function `smart_resolve_partial_mod_path_errors` for more scenarios, such as `std::sync_error::atomic::AtomicBool` in test case.

r? `@estebank`
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs66
2 files changed, 51 insertions, 23 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 90cb312edd2..f6c7aecf8b0 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let report_errors = |this: &mut Self, res: Option<Res>| {
             if this.should_report_errs() {
                 let (err, candidates) =
-                    this.smart_resolve_report_errors(path, path, path_span, source, res);
+                    this.smart_resolve_report_errors(path, None, path_span, source, res);
 
                 let def_id = this.parent_scope.module.nearest_parent_mod();
                 let instead = res.is_some();
@@ -3555,14 +3555,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             // Before we start looking for candidates, we have to get our hands
             // on the type user is trying to perform invocation on; basically:
             // we're transforming `HashMap::new` into just `HashMap`.
-            let prefix_path = match path.split_last() {
-                Some((_, path)) if !path.is_empty() => path,
+            let (following_seg, prefix_path) = match path.split_last() {
+                Some((last, path)) if !path.is_empty() => (Some(last), path),
                 _ => return Some(parent_err),
             };
 
             let (mut err, candidates) = this.smart_resolve_report_errors(
                 prefix_path,
-                path,
+                following_seg,
                 path_span,
                 PathSource::Type,
                 None,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c0e3f1aaf01..78ef72a7e34 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -332,15 +332,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
     pub(crate) fn smart_resolve_partial_mod_path_errors(
         &mut self,
         prefix_path: &[Segment],
-        path: &[Segment],
+        following_seg: Option<&Segment>,
     ) -> Vec<ImportSuggestion> {
-        let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
-            path.get(prefix_path.len())
-        } else {
-            None
-        };
         if let Some(segment) = prefix_path.last() &&
-            let Some(next_seg) = next_seg {
+            let Some(following_seg) = following_seg
+        {
             let candidates = self.r.lookup_import_candidates(
                 segment.ident,
                 Namespace::TypeNS,
@@ -353,9 +349,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 .filter(|candidate| {
                     if let Some(def_id) = candidate.did &&
                         let Some(module) = self.r.get_module(def_id) {
-                            self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
-                                key.ident.name == next_seg.ident.name
-                            })
+                                Some(def_id) != self.parent_scope.module.opt_def_id() &&
+                                self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
+                                    key.ident.name == following_seg.ident.name
+                                })
                     } else {
                         false
                     }
@@ -371,7 +368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
     pub(crate) fn smart_resolve_report_errors(
         &mut self,
         path: &[Segment],
-        full_path: &[Segment],
+        following_seg: Option<&Segment>,
         span: Span,
         source: PathSource<'_>,
         res: Option<Res>,
@@ -412,8 +409,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             return (err, Vec::new());
         }
 
-        let (found, candidates) =
-            self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
+        let (found, candidates) = self.try_lookup_name_relaxed(
+            &mut err,
+            source,
+            path,
+            following_seg,
+            span,
+            res,
+            &base_error,
+        );
         if found {
             return (err, candidates);
         }
@@ -422,7 +426,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
         // if we have suggested using pattern matching, then don't add needless suggestions
         // for typos.
-        fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
+        fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error);
 
         if fallback {
             // Fallback label.
@@ -519,7 +523,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         err: &mut Diagnostic,
         source: PathSource<'_>,
         path: &[Segment],
-        full_path: &[Segment],
+        following_seg: Option<&Segment>,
         span: Span,
         res: Option<Res>,
         base_error: &BaseError,
@@ -590,8 +594,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         }
 
         // Try finding a suitable replacement.
-        let typo_sugg =
-            self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
+        let typo_sugg = self
+            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
+            .to_opt_suggestion();
         if path.len() == 1 && self.self_type_is_available() {
             if let Some(candidate) =
                 self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
@@ -690,7 +695,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         }
 
         if candidates.is_empty() {
-            candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
+            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
         }
 
         return (false, candidates);
@@ -776,12 +781,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         err: &mut Diagnostic,
         source: PathSource<'_>,
         path: &[Segment],
+        following_seg: Option<&Segment>,
         span: Span,
         base_error: &BaseError,
     ) -> bool {
         let is_expected = &|res| source.is_expected(res);
         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
-        let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+        let typo_sugg =
+            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
         let is_in_same_file = &|sp1, sp2| {
             let source_map = self.r.tcx.sess.source_map();
             let file1 = source_map.span_to_filename(sp1);
@@ -1715,6 +1722,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
     fn lookup_typo_candidate(
         &mut self,
         path: &[Segment],
+        following_seg: Option<&Segment>,
         ns: Namespace,
         filter_fn: &impl Fn(Res) -> bool,
     ) -> TypoCandidate {
@@ -1793,6 +1801,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
         }
 
+        // if next_seg is present, let's filter everything that does not continue the path
+        if let Some(following_seg) = following_seg {
+            names.retain(|suggestion| match suggestion.res {
+                Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
+                    // FIXME: this is not totally accurate, but mostly works
+                    suggestion.candidate != following_seg.ident.name
+                }
+                Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
+                    || false,
+                    |module| {
+                        self.r
+                            .resolutions(module)
+                            .borrow()
+                            .iter()
+                            .any(|(key, _)| key.ident.name == following_seg.ident.name)
+                    },
+                ),
+                _ => true,
+            });
+        }
         let name = path[path.len() - 1].ident.name;
         // Make sure error reporting is deterministic.
         names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));