Auto merge of #96353 - estebank:issue-95413, r=compiler-errors

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
This commit is contained in:
bors 2022-05-04 01:58:23 +00:00
commit 9add63257b
14 changed files with 132 additions and 1 deletions

View File

@ -117,7 +117,7 @@ impl<'a> Resolver<'a> {
} }
fn report_with_use_injections(&mut self, krate: &Crate) { 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(..) self.use_injections.drain(..)
{ {
let (span, found_use) = if let Some(def_id) = def_id.as_local() { 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 }, if instead { Instead::Yes } else { Instead::No },
found_use, found_use,
IsPattern::No, IsPattern::No,
path,
); );
} else if let Some((span, msg, sugg, appl)) = suggestion { } else if let Some((span, msg, sugg, appl)) = suggestion {
err.span_suggestion(span, msg, sugg, appl); err.span_suggestion(span, msg, sugg, appl);
@ -702,6 +703,7 @@ impl<'a> Resolver<'a> {
Instead::No, Instead::No,
FoundUse::Yes, FoundUse::Yes,
IsPattern::Yes, IsPattern::Yes,
vec![],
); );
} }
err err
@ -1482,6 +1484,7 @@ impl<'a> Resolver<'a> {
Instead::No, Instead::No,
FoundUse::Yes, FoundUse::Yes,
IsPattern::No, IsPattern::No,
vec![],
); );
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@ -2448,6 +2451,7 @@ fn show_candidates(
instead: Instead, instead: Instead,
found_use: FoundUse, found_use: FoundUse,
is_pattern: IsPattern, is_pattern: IsPattern,
path: Vec<Segment>,
) { ) {
if candidates.is_empty() { if candidates.is_empty() {
return; return;
@ -2515,6 +2519,14 @@ fn show_candidates(
accessible_path_strings.into_iter().map(|a| a.0), accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect, 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 { } else {
msg.push(':'); msg.push(':');

View File

@ -2693,6 +2693,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
def_id, def_id,
instead, instead,
suggestion, suggestion,
path: path.into(),
}); });
} }
@ -2756,6 +2757,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
def_id, def_id,
instead: false, instead: false,
suggestion: None, suggestion: None,
path: path.into(),
}); });
} else { } else {
err.cancel(); err.cancel();

View File

@ -696,6 +696,9 @@ struct UseError<'a> {
instead: bool, instead: bool,
/// Extra free-form suggestion. /// Extra free-form suggestion.
suggestion: Option<(Span, &'static str, String, Applicability)>, 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)] #[derive(Clone, Copy, PartialEq, Debug)]

View File

@ -8,6 +8,11 @@ help: consider importing this function
| |
LL | use b::bar; LL | use b::bar;
| |
help: if you import `bar`, refer to it directly
|
LL - a::bar();
LL + bar();
|
error: aborting due to previous error error: aborting due to previous error

View File

@ -18,6 +18,11 @@ LL | use m2::S;
| |
LL | use xm2::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` error[E0423]: expected value, found type alias `xm1::S`
--> $DIR/namespace-mix.rs:40:11 --> $DIR/namespace-mix.rs:40:11
@ -41,6 +46,11 @@ LL | use m2::S;
| |
LL | use xm2::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` error[E0423]: expected value, found struct variant `m7::V`
--> $DIR/namespace-mix.rs:100:11 --> $DIR/namespace-mix.rs:100:11
@ -67,6 +77,11 @@ LL | use m8::V;
| |
LL | use xm8::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` error[E0423]: expected value, found struct variant `xm7::V`
--> $DIR/namespace-mix.rs:106:11 --> $DIR/namespace-mix.rs:106:11
@ -95,6 +110,11 @@ LL | use m8::V;
| |
LL | use xm8::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 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
--> $DIR/namespace-mix.rs:33:11 --> $DIR/namespace-mix.rs:33:11

View File

@ -14,6 +14,11 @@ help: consider importing this function
| |
LL | use hi_str; 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 error: aborting due to 2 previous errors

View File

@ -8,6 +8,11 @@ help: consider importing this unit variant
| |
LL | use namespaced_enums::Foo::A; 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` error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `namespaced_enums`
--> $DIR/enums-are-namespaced-xc.rs:7:31 --> $DIR/enums-are-namespaced-xc.rs:7:31
@ -19,6 +24,11 @@ help: consider importing this tuple variant
| |
LL | use namespaced_enums::Foo::B; 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` error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced_enums`
--> $DIR/enums-are-namespaced-xc.rs:9:31 --> $DIR/enums-are-namespaced-xc.rs:9:31
@ -30,6 +40,11 @@ help: consider importing this variant
| |
LL | use namespaced_enums::Foo::C; 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 error: aborting due to 3 previous errors

View File

@ -10,6 +10,11 @@ LL | use std::f32::consts::LOG10_2;
| |
LL | use std::f64::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 error: aborting due to previous error

View File

@ -8,6 +8,11 @@ help: consider importing this struct
| |
LL | use std::collections::HashMap; 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 error: aborting due to previous error

View File

@ -105,6 +105,11 @@ LL | use std::f32::consts::E;
| |
LL | use std::f64::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` error[E0423]: expected value, found struct variant `m::E::Struct`
--> $DIR/privacy-enum-ctor.rs:45:16 --> $DIR/privacy-enum-ctor.rs:45:16

View File

@ -14,6 +14,11 @@ help: consider importing this builtin type
| |
LL | use std::primitive::u8; 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 error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/resolve-primitive-fallback.rs:3:5 --> $DIR/resolve-primitive-fallback.rs:3:5

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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: if you import `Trait`, 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`.