Skip to content

Commit dab9160

Browse files
committed
Add filter with next segment while lookup typo for path
1 parent 4dbc7e3 commit dab9160

File tree

4 files changed

+91
-21
lines changed

4 files changed

+91
-21
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
35033503
let report_errors = |this: &mut Self, res: Option<Res>| {
35043504
if this.should_report_errs() {
35053505
let (err, candidates) =
3506-
this.smart_resolve_report_errors(path, path, path_span, source, res);
3506+
this.smart_resolve_report_errors(path, None, path_span, source, res);
35073507

35083508
let def_id = this.parent_scope.module.nearest_parent_mod();
35093509
let instead = res.is_some();
@@ -3555,14 +3555,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
35553555
// Before we start looking for candidates, we have to get our hands
35563556
// on the type user is trying to perform invocation on; basically:
35573557
// we're transforming `HashMap::new` into just `HashMap`.
3558-
let prefix_path = match path.split_last() {
3559-
Some((_, path)) if !path.is_empty() => path,
3558+
let (following_seg, prefix_path) = match path.split_last() {
3559+
Some((last, path)) if !path.is_empty() => (Some(last), path),
35603560
_ => return Some(parent_err),
35613561
};
35623562

35633563
let (mut err, candidates) = this.smart_resolve_report_errors(
35643564
prefix_path,
3565-
path,
3565+
following_seg,
35663566
path_span,
35673567
PathSource::Type,
35683568
None,

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -332,15 +332,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
332332
pub(crate) fn smart_resolve_partial_mod_path_errors(
333333
&mut self,
334334
prefix_path: &[Segment],
335-
path: &[Segment],
335+
following_seg: Option<&Segment>,
336336
) -> Vec<ImportSuggestion> {
337-
let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
338-
path.get(prefix_path.len())
339-
} else {
340-
None
341-
};
342337
if let Some(segment) = prefix_path.last() &&
343-
let Some(next_seg) = next_seg {
338+
let Some(following_seg) = following_seg {
344339
let candidates = self.r.lookup_import_candidates(
345340
segment.ident,
346341
Namespace::TypeNS,
@@ -354,7 +349,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
354349
if let Some(def_id) = candidate.did &&
355350
let Some(module) = self.r.get_module(def_id) {
356351
self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
357-
key.ident.name == next_seg.ident.name
352+
key.ident.name == following_seg.ident.name
358353
})
359354
} else {
360355
false
@@ -371,7 +366,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
371366
pub(crate) fn smart_resolve_report_errors(
372367
&mut self,
373368
path: &[Segment],
374-
full_path: &[Segment],
369+
following_seg: Option<&Segment>,
375370
span: Span,
376371
source: PathSource<'_>,
377372
res: Option<Res>,
@@ -412,8 +407,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
412407
return (err, Vec::new());
413408
}
414409

415-
let (found, candidates) =
416-
self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
410+
let (found, candidates) = self.try_lookup_name_relaxed(
411+
&mut err,
412+
source,
413+
path,
414+
following_seg,
415+
span,
416+
res,
417+
&base_error,
418+
);
417419
if found {
418420
return (err, candidates);
419421
}
@@ -422,7 +424,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
422424

423425
// if we have suggested using pattern matching, then don't add needless suggestions
424426
// for typos.
425-
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
427+
fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error);
426428

427429
if fallback {
428430
// Fallback label.
@@ -519,7 +521,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
519521
err: &mut Diagnostic,
520522
source: PathSource<'_>,
521523
path: &[Segment],
522-
full_path: &[Segment],
524+
following_seg: Option<&Segment>,
523525
span: Span,
524526
res: Option<Res>,
525527
base_error: &BaseError,
@@ -590,8 +592,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
590592
}
591593

592594
// Try finding a suitable replacement.
593-
let typo_sugg =
594-
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
595+
let typo_sugg = self
596+
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
597+
.to_opt_suggestion();
595598
if path.len() == 1 && self.self_type_is_available() {
596599
if let Some(candidate) =
597600
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
@@ -690,7 +693,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
690693
}
691694

692695
if candidates.is_empty() {
693-
candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
696+
candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
694697
}
695698

696699
return (false, candidates);
@@ -776,12 +779,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
776779
err: &mut Diagnostic,
777780
source: PathSource<'_>,
778781
path: &[Segment],
782+
following_seg: Option<&Segment>,
779783
span: Span,
780784
base_error: &BaseError,
781785
) -> bool {
782786
let is_expected = &|res| source.is_expected(res);
783787
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
784-
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
788+
let typo_sugg =
789+
self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
785790
let is_in_same_file = &|sp1, sp2| {
786791
let source_map = self.r.tcx.sess.source_map();
787792
let file1 = source_map.span_to_filename(sp1);
@@ -1715,6 +1720,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
17151720
fn lookup_typo_candidate(
17161721
&mut self,
17171722
path: &[Segment],
1723+
following_seg: Option<&Segment>,
17181724
ns: Namespace,
17191725
filter_fn: &impl Fn(Res) -> bool,
17201726
) -> TypoCandidate {
@@ -1793,6 +1799,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
17931799
}
17941800
}
17951801

1802+
// if next_seg is present, let's filter everything that does not continue the path
1803+
if let Some(following_seg) = following_seg {
1804+
names.retain(|suggestion| match suggestion.res {
1805+
Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
1806+
// this is not totally accurate, but mostly works
1807+
suggestion.candidate != following_seg.ident.name
1808+
}
1809+
Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
1810+
|| false,
1811+
|module| {
1812+
self.r
1813+
.resolutions(module)
1814+
.borrow()
1815+
.iter()
1816+
.any(|(key, _)| key.ident.name == following_seg.ident.name)
1817+
},
1818+
),
1819+
_ => true,
1820+
});
1821+
}
17961822
let name = path[path.len() - 1].ident.name;
17971823
// Make sure error reporting is deterministic.
17981824
names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));

tests/ui/resolve/112590-2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
let _t = vec::new(); //~ ERROR failed to resolve
3+
type B = vec::Vec::<u8>; //~ ERROR failed to resolve
4+
let _t = std::sync_error::atomic::AtomicBool; //~ ERROR failed to resolve
5+
}

tests/ui/resolve/112590-2.stderr

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
2+
--> $DIR/112590-2.rs:3:14
3+
|
4+
LL | type B = vec::Vec::<u8>;
5+
| ^^^ use of undeclared crate or module `vec`
6+
|
7+
help: consider importing this module
8+
|
9+
LL + use std::vec;
10+
|
11+
12+
error[E0433]: failed to resolve: could not find `sync_error` in `std`
13+
--> $DIR/112590-2.rs:4:19
14+
|
15+
LL | let _t = std::sync_error::atomic::AtomicBool;
16+
| ^^^^^^^^^^ could not find `sync_error` in `std`
17+
|
18+
help: consider importing this module
19+
|
20+
LL + use std::sync::atomic;
21+
|
22+
help: if you import `atomic`, refer to it directly
23+
|
24+
LL - let _t = std::sync_error::atomic::AtomicBool;
25+
LL + let _t = atomic::AtomicBool;
26+
|
27+
28+
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
29+
--> $DIR/112590-2.rs:2:14
30+
|
31+
LL | let _t = vec::new();
32+
| ^^^
33+
| |
34+
| use of undeclared crate or module `vec`
35+
| help: a struct with a similar name exists (notice the capitalization): `Vec`
36+
37+
error: aborting due to 3 previous errors
38+
39+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)