diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index aef9fb57a6a7c..5d80f49626a04 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, ) { if candidates.is_empty() { return; @@ -2515,6 +2519,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), + &format!("if you import `{}`, refer to it directly", last.ident), + String::new(), + Applicability::Unspecified, + ); + } } else { msg.push(':'); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3db4d4481b4ec..1bdf53cf84fed 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2693,6 +2693,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { def_id, instead, suggestion, + path: path.into(), }); } @@ -2756,6 +2757,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 f6109b1dc1a1a..ff11aba49d836 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, } #[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 8e064d980afab..91073d3698d91 100644 --- a/src/test/ui/macros/macro-outer-attributes.stderr +++ b/src/test/ui/macros/macro-outer-attributes.stderr @@ -8,6 +8,11 @@ help: consider importing this function | LL | use b::bar; | +help: if you import `bar`, 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 b610857229201..037a858d7e101 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -18,6 +18,11 @@ LL | use m2::S; | LL | use xm2::S; | +help: if you import `S`, 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 @@ -41,6 +46,11 @@ LL | use m2::S; | LL | use xm2::S; | +help: if you import `S`, 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 @@ -67,6 +77,11 @@ LL | use m8::V; | LL | use xm8::V; | +help: if you import `V`, 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 @@ -95,6 +110,11 @@ LL | use m8::V; | LL | use xm8::V; | +help: if you import `V`, 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 ee45f65a3bd5a..c5434c72b382b 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -14,6 +14,11 @@ help: consider importing this function | LL | use hi_str; | +help: if you import `hi_str`, 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 621686dd292d6..1d26a2c005872 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -8,6 +8,11 @@ help: consider importing this unit variant | LL | use namespaced_enums::Foo::A; | +help: if you import `A`, 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 @@ -19,6 +24,11 @@ help: consider importing this tuple variant | LL | use namespaced_enums::Foo::B; | +help: if you import `B`, 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 @@ -30,6 +40,11 @@ help: consider importing this variant | LL | use namespaced_enums::Foo::C; | +help: if you import `C`, 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 7ec567a06f09d..4cc035cb11e20 100644 --- a/src/test/ui/resolve/issue-50599.stderr +++ b/src/test/ui/resolve/issue-50599.stderr @@ -10,6 +10,11 @@ LL | use std::f32::consts::LOG10_2; | LL | use std::f64::consts::LOG10_2; | +help: if you import `LOG10_2`, 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 8b292aeda5074..338a5423aa472 100644 --- a/src/test/ui/resolve/missing-in-namespace.stderr +++ b/src/test/ui/resolve/missing-in-namespace.stderr @@ -8,6 +8,11 @@ help: consider importing this struct | LL | use std::collections::HashMap; | +help: if you import `HashMap`, 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 c93ba915efb2f..ed89170fd8a75 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -105,6 +105,11 @@ LL | use std::f32::consts::E; | LL | use std::f64::consts::E; | +help: if you import `E`, 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 44631f954df33..fcbc28475f998 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -14,6 +14,11 @@ help: consider importing this builtin type | LL | use std::primitive::u8; | +help: if you import `u8`, 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 0000000000000..39e90d7a3f786 --- /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(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 0000000000000..ee6ed0cae671c --- /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(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 0000000000000..a8b275f98034a --- /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(pub H); + | ^^^^^ not found in `A` + | +help: consider importing this trait + | +LL | use A::Trait; + | +help: if you import `Trait`, refer to it directly + | +LL - pub struct A(pub H); +LL + pub struct A(pub H); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0405`.