about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2022-04-23 16:41:36 -0700
committerEsteban Kuber <esteban@kuber.com.ar>2022-05-03 02:00:38 +0000
commit57967269e9946945dedd360e8e8654f5dd76ebd1 (patch)
tree19a8e48a54cf5ac759a9354027ae8b94e876bf7d
parent3d0ac7ea23888438752957eeeb5aa2b73b4fda72 (diff)
downloadrust-57967269e9946945dedd360e8e8654f5dd76ebd1.tar.gz
rust-57967269e9946945dedd360e8e8654f5dd76ebd1.zip
When suggesting to import an item, also suggest changing the path if appropriate
When we don't find an item we search all of them for an appropriate
import and suggest `use`ing it. This is sometimes done for expressions
that have paths with more than one segment. We now also suggest changing
that path to work with the `use`.

Fix #95413
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs21
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs3
-rw-r--r--src/test/ui/macros/macro-outer-attributes.stderr7
-rw-r--r--src/test/ui/namespace/namespace-mix.stderr28
-rw-r--r--src/test/ui/parser/circular_modules_main.stderr7
-rw-r--r--src/test/ui/resolve/enums-are-namespaced-xc.stderr21
-rw-r--r--src/test/ui/resolve/issue-50599.stderr7
-rw-r--r--src/test/ui/resolve/missing-in-namespace.stderr7
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr7
-rw-r--r--src/test/ui/resolve/resolve-primitive-fallback.stderr7
-rw-r--r--src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed16
-rw-r--r--src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs14
-rw-r--r--src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr19
14 files changed, 149 insertions, 17 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index aef9fb57a6a..f75ea583d85 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -117,7 +117,7 @@ impl<'a> Resolver<'a> {
     }
 
     fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, def_id, instead, suggestion } in
+        for UseError { mut err, candidates, def_id, instead, suggestion, path } in
             self.use_injections.drain(..)
         {
             let (span, found_use) = if let Some(def_id) = def_id.as_local() {
@@ -135,6 +135,7 @@ impl<'a> Resolver<'a> {
                     if instead { Instead::Yes } else { Instead::No },
                     found_use,
                     IsPattern::No,
+                    path,
                 );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
@@ -702,6 +703,7 @@ impl<'a> Resolver<'a> {
                         Instead::No,
                         FoundUse::Yes,
                         IsPattern::Yes,
+                        vec![],
                     );
                 }
                 err
@@ -1482,6 +1484,7 @@ impl<'a> Resolver<'a> {
             Instead::No,
             FoundUse::Yes,
             IsPattern::No,
+            vec![],
         );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -2448,6 +2451,7 @@ fn show_candidates(
     instead: Instead,
     found_use: FoundUse,
     is_pattern: IsPattern,
+    path: Vec<Segment>,
 ) {
     if candidates.is_empty() {
         return;
@@ -2480,14 +2484,15 @@ fn show_candidates(
             ("one of these", "items", String::new())
         };
 
+        let tail = if path.len() > 1 { "..." } else { "" };
         let instead = if let Instead::Yes = instead { " instead" } else { "" };
         let mut msg = if let IsPattern::Yes = is_pattern {
             format!(
-                "if you meant to match on {}{}{}, use the full path in the pattern",
-                kind, instead, name
+                "if you meant to match on {}{}{}, use the full path in the pattern{}",
+                kind, instead, name, tail
             )
         } else {
-            format!("consider importing {} {}{}", determiner, kind, instead)
+            format!("consider importing {} {}{}{}", determiner, kind, instead, tail)
         };
 
         for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
@@ -2515,6 +2520,14 @@ fn show_candidates(
                 accessible_path_strings.into_iter().map(|a| a.0),
                 Applicability::MaybeIncorrect,
             );
+            if let [first, .., last] = &path[..] {
+                err.span_suggestion_verbose(
+                    first.ident.span.until(last.ident.span),
+                    "...and refer to it directly",
+                    String::new(),
+                    Applicability::Unspecified,
+                );
+            }
         } else {
             msg.push(':');
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index b89b9c376af..21c9461a83d 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2682,6 +2682,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     def_id,
                     instead,
                     suggestion,
+                    path: path.into(),
                 });
             }
 
@@ -2745,6 +2746,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     def_id,
                     instead: false,
                     suggestion: None,
+                    path: path.into(),
                 });
             } else {
                 err.cancel();
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f6109b1dc1a..ff11aba49d8 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -696,6 +696,9 @@ struct UseError<'a> {
     instead: bool,
     /// Extra free-form suggestion.
     suggestion: Option<(Span, &'static str, String, Applicability)>,
+    /// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
+    /// the user to import the item directly.
+    path: Vec<Segment>,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
diff --git a/src/test/ui/macros/macro-outer-attributes.stderr b/src/test/ui/macros/macro-outer-attributes.stderr
index 8e064d980af..a9fb79b7b27 100644
--- a/src/test/ui/macros/macro-outer-attributes.stderr
+++ b/src/test/ui/macros/macro-outer-attributes.stderr
@@ -4,10 +4,15 @@ error[E0425]: cannot find function `bar` in module `a`
 LL |     a::bar();
    |        ^^^ not found in `a`
    |
-help: consider importing this function
+help: consider importing this function...
    |
 LL | use b::bar;
    |
+help: ...and refer to it directly
+   |
+LL -     a::bar();
+LL +     bar();
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr
index b6108572292..dd9c969fc82 100644
--- a/src/test/ui/namespace/namespace-mix.stderr
+++ b/src/test/ui/namespace/namespace-mix.stderr
@@ -12,12 +12,17 @@ help: a tuple struct with a similar name exists
    |
 LL |     check(m1::TS);
    |               ~~
-help: consider importing one of these items instead
+help: consider importing one of these items instead...
    |
 LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: ...and refer to it directly
+   |
+LL -     check(m1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found type alias `xm1::S`
   --> $DIR/namespace-mix.rs:40:11
@@ -35,12 +40,17 @@ help: a tuple struct with a similar name exists
    |
 LL |     check(xm1::TS);
    |                ~~
-help: consider importing one of these items instead
+help: consider importing one of these items instead...
    |
 LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: ...and refer to it directly
+   |
+LL -     check(xm1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found struct variant `m7::V`
   --> $DIR/namespace-mix.rs:100:11
@@ -61,12 +71,17 @@ help: a tuple variant with a similar name exists
    |
 LL |     check(m7::TV);
    |               ~~
-help: consider importing one of these items instead
+help: consider importing one of these items instead...
    |
 LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: ...and refer to it directly
+   |
+LL -     check(m7::V);
+LL +     check(V);
+   | 
 
 error[E0423]: expected value, found struct variant `xm7::V`
   --> $DIR/namespace-mix.rs:106:11
@@ -89,12 +104,17 @@ help: a tuple variant with a similar name exists
    |
 LL |     check(xm7::TV);
    |                ~~
-help: consider importing one of these items instead
+help: consider importing one of these items instead...
    |
 LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: ...and refer to it directly
+   |
+LL -     check(xm7::V);
+LL +     check(V);
+   | 
 
 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
   --> $DIR/namespace-mix.rs:33:11
diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr
index ee45f65a3bd..f6f3babc2d5 100644
--- a/src/test/ui/parser/circular_modules_main.stderr
+++ b/src/test/ui/parser/circular_modules_main.stderr
@@ -10,10 +10,15 @@ error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
 LL |     println!("{}", circular_modules_main::hi_str());
    |                                           ^^^^^^ not found in `circular_modules_main`
    |
-help: consider importing this function
+help: consider importing this function...
    |
 LL | use hi_str;
    |
+help: ...and refer to it directly
+   |
+LL -     println!("{}", circular_modules_main::hi_str());
+LL +     println!("{}", hi_str());
+   | 
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr
index 621686dd292..f501683ebc9 100644
--- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr
+++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr
@@ -4,10 +4,15 @@ error[E0425]: cannot find value `A` in crate `namespaced_enums`
 LL |     let _ = namespaced_enums::A;
    |                               ^ not found in `namespaced_enums`
    |
-help: consider importing this unit variant
+help: consider importing this unit variant...
    |
 LL | use namespaced_enums::Foo::A;
    |
+help: ...and refer to it directly
+   |
+LL -     let _ = namespaced_enums::A;
+LL +     let _ = A;
+   | 
 
 error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:7:31
@@ -15,10 +20,15 @@ error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `
 LL |     let _ = namespaced_enums::B(10);
    |                               ^ not found in `namespaced_enums`
    |
-help: consider importing this tuple variant
+help: consider importing this tuple variant...
    |
 LL | use namespaced_enums::Foo::B;
    |
+help: ...and refer to it directly
+   |
+LL -     let _ = namespaced_enums::B(10);
+LL +     let _ = B(10);
+   | 
 
 error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:9:31
@@ -26,10 +36,15 @@ error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced
 LL |     let _ = namespaced_enums::C { a: 10 };
    |                               ^ not found in `namespaced_enums`
    |
-help: consider importing this variant
+help: consider importing this variant...
    |
 LL | use namespaced_enums::Foo::C;
    |
+help: ...and refer to it directly
+   |
+LL -     let _ = namespaced_enums::C { a: 10 };
+LL +     let _ = C { a: 10 };
+   | 
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/resolve/issue-50599.stderr b/src/test/ui/resolve/issue-50599.stderr
index 7ec567a06f0..ef0b30d98d8 100644
--- a/src/test/ui/resolve/issue-50599.stderr
+++ b/src/test/ui/resolve/issue-50599.stderr
@@ -4,12 +4,17 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64`
 LL |     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
    |                                                ^^^^^^^ not found in `std::f64`
    |
-help: consider importing one of these items
+help: consider importing one of these items...
    |
 LL | use std::f32::consts::LOG10_2;
    |
 LL | use std::f64::consts::LOG10_2;
    |
+help: ...and refer to it directly
+   |
+LL -     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
+LL +     const M: usize = (f64::from(N) * LOG10_2) as usize;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/missing-in-namespace.stderr b/src/test/ui/resolve/missing-in-namespace.stderr
index 8b292aeda50..265f370494a 100644
--- a/src/test/ui/resolve/missing-in-namespace.stderr
+++ b/src/test/ui/resolve/missing-in-namespace.stderr
@@ -4,10 +4,15 @@ error[E0433]: failed to resolve: could not find `hahmap` in `std`
 LL |     let _map = std::hahmap::HashMap::new();
    |                             ^^^^^^^ not found in `std::hahmap`
    |
-help: consider importing this struct
+help: consider importing this struct...
    |
 LL | use std::collections::HashMap;
    |
+help: ...and refer to it directly
+   |
+LL -     let _map = std::hahmap::HashMap::new();
+LL +     let _map = HashMap::new();
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index c93ba915efb..4ac18c0e795 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -99,12 +99,17 @@ help: a function with a similar name exists
    |
 LL |     let _: E = m::f;
    |                   ~
-help: consider importing one of these items instead
+help: consider importing one of these items instead...
    |
 LL | use std::f32::consts::E;
    |
 LL | use std::f64::consts::E;
    |
+help: ...and refer to it directly
+   |
+LL -     let _: E = m::E;
+LL +     let _: E = E;
+   | 
 
 error[E0423]: expected value, found struct variant `m::E::Struct`
   --> $DIR/privacy-enum-ctor.rs:45:16
diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr
index 44631f954df..3db3706ecf5 100644
--- a/src/test/ui/resolve/resolve-primitive-fallback.stderr
+++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr
@@ -10,10 +10,15 @@ error[E0412]: cannot find type `u8` in the crate root
 LL |     let _: ::u8;
    |              ^^ not found in the crate root
    |
-help: consider importing this builtin type
+help: consider importing this builtin type...
    |
 LL | use std::primitive::u8;
    |
+help: ...and refer to it directly
+   |
+LL -     let _: ::u8;
+LL +     let _: u8;
+   | 
 
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/resolve-primitive-fallback.rs:3:5
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
new file mode 100644
index 00000000000..39e90d7a3f7
--- /dev/null
+++ b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    use A::Trait;
+
+pub struct A<H: Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
new file mode 100644
index 00000000000..ee6ed0cae67
--- /dev/null
+++ b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    pub struct A<H: A::Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
new file mode 100644
index 00000000000..413a0c8d60e
--- /dev/null
+++ b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
@@ -0,0 +1,19 @@
+error[E0405]: cannot find trait `Trait` in `A`
+  --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24
+   |
+LL |     pub struct A<H: A::Trait>(pub H);
+   |                        ^^^^^ not found in `A`
+   |
+help: consider importing this trait...
+   |
+LL |     use A::Trait;
+   |
+help: ...and refer to it directly
+   |
+LL -     pub struct A<H: A::Trait>(pub H);
+LL +     pub struct A<H: Trait>(pub H);
+   | 
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.