Skip to content

Commit 5796726

Browse files
committed
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
1 parent 3d0ac7e commit 5796726

14 files changed

+149
-17
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl<'a> Resolver<'a> {
117117
}
118118

119119
fn report_with_use_injections(&mut self, krate: &Crate) {
120-
for UseError { mut err, candidates, def_id, instead, suggestion } in
120+
for UseError { mut err, candidates, def_id, instead, suggestion, path } in
121121
self.use_injections.drain(..)
122122
{
123123
let (span, found_use) = if let Some(def_id) = def_id.as_local() {
@@ -135,6 +135,7 @@ impl<'a> Resolver<'a> {
135135
if instead { Instead::Yes } else { Instead::No },
136136
found_use,
137137
IsPattern::No,
138+
path,
138139
);
139140
} else if let Some((span, msg, sugg, appl)) = suggestion {
140141
err.span_suggestion(span, msg, sugg, appl);
@@ -702,6 +703,7 @@ impl<'a> Resolver<'a> {
702703
Instead::No,
703704
FoundUse::Yes,
704705
IsPattern::Yes,
706+
vec![],
705707
);
706708
}
707709
err
@@ -1482,6 +1484,7 @@ impl<'a> Resolver<'a> {
14821484
Instead::No,
14831485
FoundUse::Yes,
14841486
IsPattern::No,
1487+
vec![],
14851488
);
14861489

14871490
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -2448,6 +2451,7 @@ fn show_candidates(
24482451
instead: Instead,
24492452
found_use: FoundUse,
24502453
is_pattern: IsPattern,
2454+
path: Vec<Segment>,
24512455
) {
24522456
if candidates.is_empty() {
24532457
return;
@@ -2480,14 +2484,15 @@ fn show_candidates(
24802484
("one of these", "items", String::new())
24812485
};
24822486

2487+
let tail = if path.len() > 1 { "..." } else { "" };
24832488
let instead = if let Instead::Yes = instead { " instead" } else { "" };
24842489
let mut msg = if let IsPattern::Yes = is_pattern {
24852490
format!(
2486-
"if you meant to match on {}{}{}, use the full path in the pattern",
2487-
kind, instead, name
2491+
"if you meant to match on {}{}{}, use the full path in the pattern{}",
2492+
kind, instead, name, tail
24882493
)
24892494
} else {
2490-
format!("consider importing {} {}{}", determiner, kind, instead)
2495+
format!("consider importing {} {}{}{}", determiner, kind, instead, tail)
24912496
};
24922497

24932498
for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
@@ -2515,6 +2520,14 @@ fn show_candidates(
25152520
accessible_path_strings.into_iter().map(|a| a.0),
25162521
Applicability::MaybeIncorrect,
25172522
);
2523+
if let [first, .., last] = &path[..] {
2524+
err.span_suggestion_verbose(
2525+
first.ident.span.until(last.ident.span),
2526+
"...and refer to it directly",
2527+
String::new(),
2528+
Applicability::Unspecified,
2529+
);
2530+
}
25182531
} else {
25192532
msg.push(':');
25202533

compiler/rustc_resolve/src/late.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2682,6 +2682,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26822682
def_id,
26832683
instead,
26842684
suggestion,
2685+
path: path.into(),
26852686
});
26862687
}
26872688

@@ -2745,6 +2746,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27452746
def_id,
27462747
instead: false,
27472748
suggestion: None,
2749+
path: path.into(),
27482750
});
27492751
} else {
27502752
err.cancel();

compiler/rustc_resolve/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ struct UseError<'a> {
696696
instead: bool,
697697
/// Extra free-form suggestion.
698698
suggestion: Option<(Span, &'static str, String, Applicability)>,
699+
/// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
700+
/// the user to import the item directly.
701+
path: Vec<Segment>,
699702
}
700703

701704
#[derive(Clone, Copy, PartialEq, Debug)]

src/test/ui/macros/macro-outer-attributes.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ error[E0425]: cannot find function `bar` in module `a`
44
LL | a::bar();
55
| ^^^ not found in `a`
66
|
7-
help: consider importing this function
7+
help: consider importing this function...
88
|
99
LL | use b::bar;
1010
|
11+
help: ...and refer to it directly
12+
|
13+
LL - a::bar();
14+
LL + bar();
15+
|
1116

1217
error: aborting due to previous error
1318

src/test/ui/namespace/namespace-mix.stderr

+24-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@ help: a tuple struct with a similar name exists
1212
|
1313
LL | check(m1::TS);
1414
| ~~
15-
help: consider importing one of these items instead
15+
help: consider importing one of these items instead...
1616
|
1717
LL | use m2::S;
1818
|
1919
LL | use xm2::S;
2020
|
21+
help: ...and refer to it directly
22+
|
23+
LL - check(m1::S);
24+
LL + check(S);
25+
|
2126

2227
error[E0423]: expected value, found type alias `xm1::S`
2328
--> $DIR/namespace-mix.rs:40:11
@@ -35,12 +40,17 @@ help: a tuple struct with a similar name exists
3540
|
3641
LL | check(xm1::TS);
3742
| ~~
38-
help: consider importing one of these items instead
43+
help: consider importing one of these items instead...
3944
|
4045
LL | use m2::S;
4146
|
4247
LL | use xm2::S;
4348
|
49+
help: ...and refer to it directly
50+
|
51+
LL - check(xm1::S);
52+
LL + check(S);
53+
|
4454

4555
error[E0423]: expected value, found struct variant `m7::V`
4656
--> $DIR/namespace-mix.rs:100:11
@@ -61,12 +71,17 @@ help: a tuple variant with a similar name exists
6171
|
6272
LL | check(m7::TV);
6373
| ~~
64-
help: consider importing one of these items instead
74+
help: consider importing one of these items instead...
6575
|
6676
LL | use m8::V;
6777
|
6878
LL | use xm8::V;
6979
|
80+
help: ...and refer to it directly
81+
|
82+
LL - check(m7::V);
83+
LL + check(V);
84+
|
7085

7186
error[E0423]: expected value, found struct variant `xm7::V`
7287
--> $DIR/namespace-mix.rs:106:11
@@ -89,12 +104,17 @@ help: a tuple variant with a similar name exists
89104
|
90105
LL | check(xm7::TV);
91106
| ~~
92-
help: consider importing one of these items instead
107+
help: consider importing one of these items instead...
93108
|
94109
LL | use m8::V;
95110
|
96111
LL | use xm8::V;
97112
|
113+
help: ...and refer to it directly
114+
|
115+
LL - check(xm7::V);
116+
LL + check(V);
117+
|
98118

99119
error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
100120
--> $DIR/namespace-mix.rs:33:11

src/test/ui/parser/circular_modules_main.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
1010
LL | println!("{}", circular_modules_main::hi_str());
1111
| ^^^^^^ not found in `circular_modules_main`
1212
|
13-
help: consider importing this function
13+
help: consider importing this function...
1414
|
1515
LL | use hi_str;
1616
|
17+
help: ...and refer to it directly
18+
|
19+
LL - println!("{}", circular_modules_main::hi_str());
20+
LL + println!("{}", hi_str());
21+
|
1722

1823
error: aborting due to 2 previous errors
1924

src/test/ui/resolve/enums-are-namespaced-xc.stderr

+18-3
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,47 @@ error[E0425]: cannot find value `A` in crate `namespaced_enums`
44
LL | let _ = namespaced_enums::A;
55
| ^ not found in `namespaced_enums`
66
|
7-
help: consider importing this unit variant
7+
help: consider importing this unit variant...
88
|
99
LL | use namespaced_enums::Foo::A;
1010
|
11+
help: ...and refer to it directly
12+
|
13+
LL - let _ = namespaced_enums::A;
14+
LL + let _ = A;
15+
|
1116

1217
error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `namespaced_enums`
1318
--> $DIR/enums-are-namespaced-xc.rs:7:31
1419
|
1520
LL | let _ = namespaced_enums::B(10);
1621
| ^ not found in `namespaced_enums`
1722
|
18-
help: consider importing this tuple variant
23+
help: consider importing this tuple variant...
1924
|
2025
LL | use namespaced_enums::Foo::B;
2126
|
27+
help: ...and refer to it directly
28+
|
29+
LL - let _ = namespaced_enums::B(10);
30+
LL + let _ = B(10);
31+
|
2232

2333
error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced_enums`
2434
--> $DIR/enums-are-namespaced-xc.rs:9:31
2535
|
2636
LL | let _ = namespaced_enums::C { a: 10 };
2737
| ^ not found in `namespaced_enums`
2838
|
29-
help: consider importing this variant
39+
help: consider importing this variant...
3040
|
3141
LL | use namespaced_enums::Foo::C;
3242
|
43+
help: ...and refer to it directly
44+
|
45+
LL - let _ = namespaced_enums::C { a: 10 };
46+
LL + let _ = C { a: 10 };
47+
|
3348

3449
error: aborting due to 3 previous errors
3550

src/test/ui/resolve/issue-50599.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64`
44
LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
55
| ^^^^^^^ not found in `std::f64`
66
|
7-
help: consider importing one of these items
7+
help: consider importing one of these items...
88
|
99
LL | use std::f32::consts::LOG10_2;
1010
|
1111
LL | use std::f64::consts::LOG10_2;
1212
|
13+
help: ...and refer to it directly
14+
|
15+
LL - const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
16+
LL + const M: usize = (f64::from(N) * LOG10_2) as usize;
17+
|
1318

1419
error: aborting due to previous error
1520

src/test/ui/resolve/missing-in-namespace.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ error[E0433]: failed to resolve: could not find `hahmap` in `std`
44
LL | let _map = std::hahmap::HashMap::new();
55
| ^^^^^^^ not found in `std::hahmap`
66
|
7-
help: consider importing this struct
7+
help: consider importing this struct...
88
|
99
LL | use std::collections::HashMap;
1010
|
11+
help: ...and refer to it directly
12+
|
13+
LL - let _map = std::hahmap::HashMap::new();
14+
LL + let _map = HashMap::new();
15+
|
1116

1217
error: aborting due to previous error
1318

src/test/ui/resolve/privacy-enum-ctor.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,17 @@ help: a function with a similar name exists
9999
|
100100
LL | let _: E = m::f;
101101
| ~
102-
help: consider importing one of these items instead
102+
help: consider importing one of these items instead...
103103
|
104104
LL | use std::f32::consts::E;
105105
|
106106
LL | use std::f64::consts::E;
107107
|
108+
help: ...and refer to it directly
109+
|
110+
LL - let _: E = m::E;
111+
LL + let _: E = E;
112+
|
108113

109114
error[E0423]: expected value, found struct variant `m::E::Struct`
110115
--> $DIR/privacy-enum-ctor.rs:45:16

src/test/ui/resolve/resolve-primitive-fallback.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ error[E0412]: cannot find type `u8` in the crate root
1010
LL | let _: ::u8;
1111
| ^^ not found in the crate root
1212
|
13-
help: consider importing this builtin type
13+
help: consider importing this builtin type...
1414
|
1515
LL | use std::primitive::u8;
1616
|
17+
help: ...and refer to it directly
18+
|
19+
LL - let _: ::u8;
20+
LL + let _: u8;
21+
|
1722

1823
error[E0061]: this function takes 0 arguments but 1 argument was supplied
1924
--> $DIR/resolve-primitive-fallback.rs:3:5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
#![allow(non_snake_case)]
3+
mod A {
4+
pub trait Trait {}
5+
impl Trait for i32 {}
6+
}
7+
8+
mod B {
9+
use A::Trait;
10+
11+
pub struct A<H: Trait>(pub H); //~ ERROR cannot find trait
12+
}
13+
14+
fn main() {
15+
let _ = B::A(42);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
#![allow(non_snake_case)]
3+
mod A {
4+
pub trait Trait {}
5+
impl Trait for i32 {}
6+
}
7+
8+
mod B {
9+
pub struct A<H: A::Trait>(pub H); //~ ERROR cannot find trait
10+
}
11+
12+
fn main() {
13+
let _ = B::A(42);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0405]: cannot find trait `Trait` in `A`
2+
--> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24
3+
|
4+
LL | pub struct A<H: A::Trait>(pub H);
5+
| ^^^^^ not found in `A`
6+
|
7+
help: consider importing this trait...
8+
|
9+
LL | use A::Trait;
10+
|
11+
help: ...and refer to it directly
12+
|
13+
LL - pub struct A<H: A::Trait>(pub H);
14+
LL + pub struct A<H: Trait>(pub H);
15+
|
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)