Skip to content

Commit aaa20c6

Browse files
committed
Rollup merge of rust-lang#55185 - davidtwco:issue-55130, r=nikomatsakis
path suggestions in Rust 2018 should point out the change in semantics Fixes rust-lang#55130. This commit extends existing path suggestions to link to documentation on the changed semantics of `use` in Rust 2018.
2 parents 360f32a + 0d06b8c commit aaa20c6

File tree

3 files changed

+63
-29
lines changed

3 files changed

+63
-29
lines changed

src/librustc_resolve/error_reporting.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
2626
span: Span,
2727
path: Vec<Segment>,
2828
parent_scope: &ParentScope<'b>,
29-
) -> Option<Vec<Segment>> {
29+
) -> Option<(Vec<Segment>, Option<String>)> {
3030
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
3131
// If we don't have a path to suggest changes to, then return.
3232
if path.is_empty() {
@@ -65,13 +65,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
6565
span: Span,
6666
mut path: Vec<Segment>,
6767
parent_scope: &ParentScope<'b>,
68-
) -> Option<Vec<Segment>> {
68+
) -> Option<(Vec<Segment>, Option<String>)> {
6969
// Replace first ident with `self` and check if that is valid.
7070
path[0].ident.name = keywords::SelfValue.name();
7171
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
7272
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
7373
if let PathResult::Module(..) = result {
74-
Some(path)
74+
Some((path, None))
7575
} else {
7676
None
7777
}
@@ -89,13 +89,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
8989
span: Span,
9090
mut path: Vec<Segment>,
9191
parent_scope: &ParentScope<'b>,
92-
) -> Option<Vec<Segment>> {
92+
) -> Option<(Vec<Segment>, Option<String>)> {
9393
// Replace first ident with `crate` and check if that is valid.
9494
path[0].ident.name = keywords::Crate.name();
9595
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
9696
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
9797
if let PathResult::Module(..) = result {
98-
Some(path)
98+
Some((
99+
path,
100+
Some(
101+
"`use` statements changed in Rust 2018; read more at \
102+
<https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
103+
clarity.html>".to_string()
104+
),
105+
))
99106
} else {
100107
None
101108
}
@@ -113,13 +120,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
113120
span: Span,
114121
mut path: Vec<Segment>,
115122
parent_scope: &ParentScope<'b>,
116-
) -> Option<Vec<Segment>> {
123+
) -> Option<(Vec<Segment>, Option<String>)> {
117124
// Replace first ident with `crate` and check if that is valid.
118125
path[0].ident.name = keywords::Super.name();
119126
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
120127
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
121128
if let PathResult::Module(..) = result {
122-
Some(path)
129+
Some((path, None))
123130
} else {
124131
None
125132
}
@@ -140,7 +147,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
140147
span: Span,
141148
mut path: Vec<Segment>,
142149
parent_scope: &ParentScope<'b>,
143-
) -> Option<Vec<Segment>> {
150+
) -> Option<(Vec<Segment>, Option<String>)> {
144151
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
145152
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
146153
// each time.
@@ -162,7 +169,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
162169
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
163170
name, path, result);
164171
if let PathResult::Module(..) = result {
165-
return Some(path)
172+
return Some((path, None));
166173
}
167174
}
168175

src/librustc_resolve/resolve_imports.rs

+45-20
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
707707
}
708708
}
709709
});
710-
} else if let Some((span, err)) = error {
710+
} else if let Some((span, err, note)) = error {
711711
errors = true;
712712

713713
if let SingleImport { source, ref result, .. } = import.subclass {
@@ -737,7 +737,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
737737
&import.subclass,
738738
span,
739739
);
740-
error_vec.push((span, path, err));
740+
error_vec.push((span, path, err, note));
741741
seen_spans.insert(span);
742742
prev_root_id = import.root_id;
743743
}
@@ -829,27 +829,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
829829
}
830830
}
831831

832-
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
833-
span: Option<MultiSpan>) {
832+
fn throw_unresolved_import_error(
833+
&self,
834+
error_vec: Vec<(Span, String, String, Option<String>)>,
835+
span: Option<MultiSpan>,
836+
) {
834837
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
835-
let (span, msg) = if error_vec.is_empty() {
836-
(span.unwrap(), "unresolved import".to_string())
838+
let (span, msg, note) = if error_vec.is_empty() {
839+
(span.unwrap(), "unresolved import".to_string(), None)
837840
} else {
838-
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
839-
.map(|elem: (Span, String, String)| { elem.0 })
840-
.collect());
841+
let span = MultiSpan::from_spans(
842+
error_vec.clone().into_iter()
843+
.map(|elem: (Span, String, String, Option<String>)| elem.0)
844+
.collect()
845+
);
846+
847+
let note: Option<String> = error_vec.clone().into_iter()
848+
.filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
849+
.last();
850+
841851
let path_vec: Vec<String> = error_vec.clone().into_iter()
842-
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) })
852+
.map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
843853
.collect();
844854
let path = path_vec.join(", ");
845-
let msg = format!("unresolved import{} {}",
846-
if path_vec.len() > 1 { "s" } else { "" }, path);
847-
(span, msg)
855+
let msg = format!(
856+
"unresolved import{} {}",
857+
if path_vec.len() > 1 { "s" } else { "" },
858+
path
859+
);
860+
861+
(span, msg, note)
848862
};
863+
849864
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
850865
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
851866
err.span_label(span_error.0, span_error.2);
852867
}
868+
if let Some(note) = note {
869+
err.note(&note);
870+
}
853871
err.emit();
854872
}
855873

@@ -945,7 +963,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
945963
}
946964

947965
// If appropriate, returns an error to report.
948-
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
966+
fn finalize_import(
967+
&mut self,
968+
directive: &'b ImportDirective<'b>
969+
) -> Option<(Span, String, Option<String>)> {
949970
self.current_module = directive.parent_scope.module;
950971
let ImportDirective { ref module_path, span, .. } = *directive;
951972

@@ -969,15 +990,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
969990
return None;
970991
}
971992
PathResult::Failed(span, msg, true) => {
972-
return if let Some(suggested_path) = self.make_path_suggestion(
993+
return if let Some((suggested_path, note)) = self.make_path_suggestion(
973994
span, module_path.clone(), &directive.parent_scope
974995
) {
975996
Some((
976997
span,
977-
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
998+
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)),
999+
note,
9781000
))
9791001
} else {
980-
Some((span, msg))
1002+
Some((span, msg, None))
9811003
};
9821004
},
9831005
_ => return None,
@@ -1002,8 +1024,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10021024
if let ModuleOrUniformRoot::Module(module) = module {
10031025
if module.def_id() == directive.parent_scope.module.def_id() {
10041026
// Importing a module into itself is not allowed.
1005-
return Some((directive.span,
1006-
"Cannot glob-import a module into itself.".to_string()));
1027+
return Some((
1028+
directive.span,
1029+
"Cannot glob-import a module into itself.".to_string(),
1030+
None,
1031+
));
10071032
}
10081033
}
10091034
if !is_prelude &&
@@ -1101,7 +1126,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
11011126
}
11021127
}
11031128
};
1104-
Some((span, msg))
1129+
Some((span, msg, None))
11051130
} else {
11061131
// `resolve_ident_in_module` reported a privacy error.
11071132
self.import_dummy_binding(directive);

src/test/ui/rust-2018/local-path-suggestions-2018.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0432]: unresolved import `foo`
33
|
44
LL | use foo::Bar;
55
| ^^^ Did you mean `crate::foo`?
6+
|
7+
= note: `use` statements changed in Rust 2018; read more at <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html>
68

79
error[E0432]: unresolved import `foo`
810
--> $DIR/local-path-suggestions-2018.rs:27:5

0 commit comments

Comments
 (0)