Skip to content

Commit 7dc3ace

Browse files
authored
Rollup merge of #103706 - zbyrn:issue-101637-fix, r=estebank
Fix E0433 No Typo Suggestions Fixes #48676 Fixes #87791 Fixes #96625 Fixes #95462 Fixes #101637 Follows up PR #72923 Several open issues refer to the problem that E0433 does not suggest typos like other errors normally do. This fix augments the implementation of PR #72923. **Background** When the path of a function call, e.g. `Struct::foo()`, involves names that cannot be resolved, there are two errors that could be emitted by the compiler: - If `Struct` is not found, it is ``E0433: failed to resolve: use of undeclared type `Struct` ``. - If `foo` is not found in `Struct`, it is ``E0599: no function or associated item named `foo` found for struct `Struct` in the current scope`` When a name is used as a type, `e.g. fn foo() -> Struct`, and the name cannot be resolved, it is ``E0412: cannot find type `Struct` in this scope``. Before #72923, `E0433` does not implement any suggestions, and the PR introduces suggestions for missing `use`s. When a resolution error occurs in the path of a function call, it tries to smart resolve just the type part of the path, e.g. `module::Struct` of a call to `module::Struct::foo()`. However, along with the suggestions, the smart-resolve function will report `E0412` since it only knows that it is a type that we cannot resolve instead of being a part of the path. So, the original implementation swap out `E0412` errors returned by the smart-resolve function with the real `E0433` error, but keeps the "missing `use`" suggestions to be reported to the programmer. **Issue** The current implementation only reports if there are "missing `use`" suggestions returned by the smart-resolve function; otherwise, it would fall back the normal reporting, which does not emit suggestions. But the smart-resolve function could also produce typo suggestions, which are omitted currently. Also, it seems like that not all info has been swapped out when there are missing suggestions. The error message underlining the name in the snippet still says ``not found in this scope``, which is a `E0412` messages, if there are `use` suggestions, but says the normal `use of undeclared type` otherwise. **Fixes** This fix swaps out all fields in `Diagnostic` returned by the smart-resolve function except for `suggestions` with the current error, and merges the `suggestions` of the returned error and that of the current error together. If there are `use` suggestions, the error is saved to `use_injection` to be reported at the end; otherwise, the error is emitted immediately as `Resolver::report_error` does. Some tests are updated to use the correct underlining error messages, and one additional test for typo suggestion is added to the test suite. r? rust-lang/diagnostics
2 parents 94241e7 + a10737c commit 7dc3ace

12 files changed

+148
-36
lines changed

compiler/rustc_resolve/src/late.rs

+37-17
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use smallvec::{smallvec, SmallVec};
3232
use rustc_span::source_map::{respan, Spanned};
3333
use std::assert_matches::debug_assert_matches;
3434
use std::collections::{hash_map::Entry, BTreeSet};
35-
use std::mem::{replace, take};
35+
use std::mem::{replace, swap, take};
3636

3737
mod diagnostics;
3838

@@ -3369,11 +3369,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
33693369
let (mut err, candidates) =
33703370
this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
33713371

3372-
if candidates.is_empty() {
3373-
err.cancel();
3374-
return Some(parent_err);
3375-
}
3376-
33773372
// There are two different error messages user might receive at
33783373
// this point:
33793374
// - E0412 cannot find type `{}` in this scope
@@ -3383,37 +3378,62 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
33833378
// latter one - for paths in expression-position.
33843379
//
33853380
// Thus (since we're in expression-position at this point), not to
3386-
// confuse the user, we want to keep the *message* from E0432 (so
3381+
// confuse the user, we want to keep the *message* from E0433 (so
33873382
// `parent_err`), but we want *hints* from E0412 (so `err`).
33883383
//
33893384
// And that's what happens below - we're just mixing both messages
33903385
// into a single one.
33913386
let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
33923387

3388+
// overwrite all properties with the parent's error message
33933389
err.message = take(&mut parent_err.message);
33943390
err.code = take(&mut parent_err.code);
3391+
swap(&mut err.span, &mut parent_err.span);
33953392
err.children = take(&mut parent_err.children);
3393+
err.sort_span = parent_err.sort_span;
3394+
err.is_lint = parent_err.is_lint;
3395+
3396+
// merge the parent's suggestions with the typo suggestions
3397+
fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
3398+
match res1 {
3399+
Ok(vec1) => match res2 {
3400+
Ok(mut vec2) => vec1.append(&mut vec2),
3401+
Err(e) => *res1 = Err(e),
3402+
},
3403+
Err(_) => (),
3404+
};
3405+
}
3406+
append_result(&mut err.suggestions, parent_err.suggestions.clone());
33963407

33973408
parent_err.cancel();
33983409

33993410
let def_id = this.parent_scope.module.nearest_parent_mod();
34003411

34013412
if this.should_report_errs() {
3402-
this.r.use_injections.push(UseError {
3403-
err,
3404-
candidates,
3405-
def_id,
3406-
instead: false,
3407-
suggestion: None,
3408-
path: path.into(),
3409-
is_call: source.is_call(),
3410-
});
3413+
if candidates.is_empty() {
3414+
// When there is no suggested imports, we can just emit the error
3415+
// and suggestions immediately. Note that we bypass the usually error
3416+
// reporting routine (ie via `self.r.report_error`) because we need
3417+
// to post-process the `ResolutionError` above.
3418+
err.emit();
3419+
} else {
3420+
// If there are suggested imports, the error reporting is delayed
3421+
this.r.use_injections.push(UseError {
3422+
err,
3423+
candidates,
3424+
def_id,
3425+
instead: false,
3426+
suggestion: None,
3427+
path: path.into(),
3428+
is_call: source.is_call(),
3429+
});
3430+
}
34113431
} else {
34123432
err.cancel();
34133433
}
34143434

34153435
// We don't return `Some(parent_err)` here, because the error will
3416-
// be already printed as part of the `use` injections
3436+
// be already printed either immediately or as part of the `use` injections
34173437
None
34183438
};
34193439

src/test/ui/const-generics/issues/issue-82956.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0433]: failed to resolve: use of undeclared type `IntoIter`
22
--> $DIR/issue-82956.rs:25:24
33
|
44
LL | let mut iter = IntoIter::new(self);
5-
| ^^^^^^^^ not found in this scope
5+
| ^^^^^^^^ use of undeclared type `IntoIter`
66
|
77
help: consider importing one of these items
88
|

src/test/ui/derived-errors/issue-31997-1.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0433]: failed to resolve: use of undeclared type `HashMap`
22
--> $DIR/issue-31997-1.rs:20:19
33
|
44
LL | let mut map = HashMap::new();
5-
| ^^^^^^^ not found in this scope
5+
| ^^^^^^^ use of undeclared type `HashMap`
66
|
77
help: consider importing this struct
88
|

src/test/ui/hygiene/no_implicit_prelude.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn f() { ::bar::m!(); }
55
| ----------- in this macro invocation
66
...
77
LL | Vec::new();
8-
| ^^^ not found in this scope
8+
| ^^^ use of undeclared type `Vec`
99
|
1010
= note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
1111
help: consider importing this struct

src/test/ui/proc-macro/amputate-span.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0433]: failed to resolve: use of undeclared type `Command`
22
--> $DIR/amputate-span.rs:49:5
33
|
44
LL | Command::new("git");
5-
| ^^^^^^^ not found in this scope
5+
| ^^^^^^^ use of undeclared type `Command`
66
|
77
help: consider importing this struct
88
|
@@ -13,7 +13,7 @@ error[E0433]: failed to resolve: use of undeclared type `Command`
1313
--> $DIR/amputate-span.rs:63:9
1414
|
1515
LL | Command::new("git");
16-
| ^^^^^^^ not found in this scope
16+
| ^^^^^^^ use of undeclared type `Command`
1717
|
1818
help: consider importing this struct
1919
|

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0433]: failed to resolve: could not find `hahmap` in `std`
2-
--> $DIR/missing-in-namespace.rs:2:29
2+
--> $DIR/missing-in-namespace.rs:2:21
33
|
44
LL | let _map = std::hahmap::HashMap::new();
5-
| ^^^^^^^ not found in `std::hahmap`
5+
| ^^^^^^ could not find `hahmap` in `std`
66
|
77
help: consider importing this struct
88
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
struct Struct;
2+
//~^ NOTE function or associated item `fob` not found for this struct
3+
4+
impl Struct {
5+
fn foo() { }
6+
}
7+
8+
mod module {
9+
fn foo() { }
10+
11+
struct Struct;
12+
13+
impl Struct {
14+
fn foo() { }
15+
}
16+
}
17+
18+
trait Trait {
19+
fn foo();
20+
}
21+
22+
fn main() {
23+
Struct::fob();
24+
//~^ ERROR no function or associated item named `fob` found for struct `Struct` in the current scope
25+
//~| NOTE function or associated item not found in `Struct`
26+
27+
Struc::foo();
28+
//~^ ERROR failed to resolve: use of undeclared type `Struc`
29+
//~| NOTE use of undeclared type `Struc`
30+
31+
modul::foo();
32+
//~^ ERROR failed to resolve: use of undeclared crate or module `modul`
33+
//~| NOTE use of undeclared crate or module `modul`
34+
35+
module::Struc::foo();
36+
//~^ ERROR failed to resolve: could not find `Struc` in `module`
37+
//~| NOTE could not find `Struc` in `module`
38+
39+
Trai::foo();
40+
//~^ ERROR failed to resolve: use of undeclared type `Trai`
41+
//~| NOTE use of undeclared type `Trai`
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error[E0433]: failed to resolve: use of undeclared type `Struc`
2+
--> $DIR/typo-suggestion-mistyped-in-path.rs:27:5
3+
|
4+
LL | Struc::foo();
5+
| ^^^^^
6+
| |
7+
| use of undeclared type `Struc`
8+
| help: a struct with a similar name exists: `Struct`
9+
10+
error[E0433]: failed to resolve: use of undeclared crate or module `modul`
11+
--> $DIR/typo-suggestion-mistyped-in-path.rs:31:5
12+
|
13+
LL | modul::foo();
14+
| ^^^^^ use of undeclared crate or module `modul`
15+
|
16+
help: there is a crate or module with a similar name
17+
|
18+
LL | module::foo();
19+
| ~~~~~~
20+
21+
error[E0433]: failed to resolve: could not find `Struc` in `module`
22+
--> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
23+
|
24+
LL | module::Struc::foo();
25+
| ^^^^^
26+
| |
27+
| could not find `Struc` in `module`
28+
| help: a struct with a similar name exists: `Struct`
29+
30+
error[E0433]: failed to resolve: use of undeclared type `Trai`
31+
--> $DIR/typo-suggestion-mistyped-in-path.rs:39:5
32+
|
33+
LL | Trai::foo();
34+
| ^^^^
35+
| |
36+
| use of undeclared type `Trai`
37+
| help: a trait with a similar name exists: `Trait`
38+
39+
error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
40+
--> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
41+
|
42+
LL | struct Struct;
43+
| ------------- function or associated item `fob` not found for this struct
44+
...
45+
LL | Struct::fob();
46+
| ^^^
47+
| |
48+
| function or associated item not found in `Struct`
49+
| help: there is an associated function with a similar name: `foo`
50+
51+
error: aborting due to 5 previous errors
52+
53+
Some errors have detailed explanations: E0433, E0599.
54+
For more information about an error, try `rustc --explain E0433`.

src/test/ui/resolve/use_suggestion.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ error[E0433]: failed to resolve: use of undeclared type `HashMap`
88
--> $DIR/use_suggestion.rs:2:14
99
|
1010
LL | let x1 = HashMap::new();
11-
| ^^^^^^^ not found in this scope
11+
| ^^^^^^^ use of undeclared type `HashMap`
1212
|
1313
help: consider importing this struct
1414
|

src/test/ui/suggestions/core-std-import-order-issue-83564.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0433]: failed to resolve: use of undeclared type `NonZeroU32`
22
--> $DIR/core-std-import-order-issue-83564.rs:8:14
33
|
44
LL | let _x = NonZeroU32::new(5).unwrap();
5-
| ^^^^^^^^^^ not found in this scope
5+
| ^^^^^^^^^^ use of undeclared type `NonZeroU32`
66
|
77
help: consider importing one of these items
88
|

src/test/ui/suggestions/suggest-tryinto-edition-change.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ fn test() {
1010

1111
let _i: i16 = TryFrom::try_from(0_i32).unwrap();
1212
//~^ ERROR failed to resolve: use of undeclared type
13-
//~| NOTE not found in this scope
13+
//~| NOTE use of undeclared type
1414
//~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
1515
//~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
1616

1717
let _i: i16 = TryInto::try_into(0_i32).unwrap();
1818
//~^ ERROR failed to resolve: use of undeclared type
19-
//~| NOTE not found in this scope
19+
//~| NOTE use of undeclared type
2020
//~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
2121
//~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
2222

2323
let _v: Vec<_> = FromIterator::from_iter(&[1]);
2424
//~^ ERROR failed to resolve: use of undeclared type
25+
//~| NOTE use of undeclared type
2526
//~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
2627
//~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
2728
}

src/test/ui/suggestions/suggest-tryinto-edition-change.stderr

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom`
22
--> $DIR/suggest-tryinto-edition-change.rs:11:19
33
|
44
LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
5-
| ^^^^^^^ not found in this scope
5+
| ^^^^^^^ use of undeclared type `TryFrom`
66
|
77
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
88
= note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
@@ -17,7 +17,7 @@ error[E0433]: failed to resolve: use of undeclared type `TryInto`
1717
--> $DIR/suggest-tryinto-edition-change.rs:17:19
1818
|
1919
LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
20-
| ^^^^^^^ not found in this scope
20+
| ^^^^^^^ use of undeclared type `TryInto`
2121
|
2222
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
2323
= note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
@@ -32,12 +32,7 @@ error[E0433]: failed to resolve: use of undeclared type `FromIterator`
3232
--> $DIR/suggest-tryinto-edition-change.rs:23:22
3333
|
3434
LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
35-
| ^^^^^^^^^^^^
36-
|
37-
::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
38-
|
39-
LL | pub trait IntoIterator {
40-
| ---------------------- similarly named trait `IntoIterator` defined here
35+
| ^^^^^^^^^^^^ use of undeclared type `FromIterator`
4136
|
4237
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
4338
= note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021

0 commit comments

Comments
 (0)