Skip to content

Commit a083070

Browse files
authored
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. r? @nikomatsakis
2 parents 830c6b0 + d2baf92 commit a083070

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
@@ -24,7 +24,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
2424
&mut self,
2525
span: Span,
2626
path: Vec<Ident>
27-
) -> Option<Vec<Ident>> {
27+
) -> Option<(Vec<Ident>, Option<String>)> {
2828
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
2929
// If we don't have a path to suggest changes to, then return.
3030
if path.is_empty() {
@@ -60,13 +60,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
6060
&mut self,
6161
span: Span,
6262
mut path: Vec<Ident>
63-
) -> Option<Vec<Ident>> {
63+
) -> Option<(Vec<Ident>, Option<String>)> {
6464
// Replace first ident with `self` and check if that is valid.
6565
path[0].name = keywords::SelfValue.name();
6666
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
6767
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
6868
if let PathResult::Module(..) = result {
69-
Some(path)
69+
Some((path, None))
7070
} else {
7171
None
7272
}
@@ -83,13 +83,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
8383
&mut self,
8484
span: Span,
8585
mut path: Vec<Ident>
86-
) -> Option<Vec<Ident>> {
86+
) -> Option<(Vec<Ident>, Option<String>)> {
8787
// Replace first ident with `crate` and check if that is valid.
8888
path[0].name = keywords::Crate.name();
8989
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
9090
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
9191
if let PathResult::Module(..) = result {
92-
Some(path)
92+
Some((
93+
path,
94+
Some(
95+
"`use` statements changed in Rust 2018; read more at \
96+
<https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
97+
clarity.html>".to_string()
98+
),
99+
))
93100
} else {
94101
None
95102
}
@@ -106,13 +113,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
106113
&mut self,
107114
span: Span,
108115
mut path: Vec<Ident>
109-
) -> Option<Vec<Ident>> {
116+
) -> Option<(Vec<Ident>, Option<String>)> {
110117
// Replace first ident with `crate` and check if that is valid.
111118
path[0].name = keywords::Super.name();
112119
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
113120
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
114121
if let PathResult::Module(..) = result {
115-
Some(path)
122+
Some((path, None))
116123
} else {
117124
None
118125
}
@@ -132,7 +139,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
132139
&mut self,
133140
span: Span,
134141
mut path: Vec<Ident>
135-
) -> Option<Vec<Ident>> {
142+
) -> Option<(Vec<Ident>, Option<String>)> {
136143
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
137144
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
138145
// each time.
@@ -157,7 +164,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
157164
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
158165
name, path, result);
159166
if let PathResult::Module(..) = result {
160-
return Some(path)
167+
return Some((path, None))
161168
}
162169
}
163170
}

src/librustc_resolve/resolve_imports.rs

+45-20
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
700700
}
701701
}
702702
});
703-
} else if let Some((span, err)) = error {
703+
} else if let Some((span, err, note)) = error {
704704
errors = true;
705705

706706
if let SingleImport { source, ref result, .. } = import.subclass {
@@ -728,7 +728,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
728728
let path = import_path_to_string(&import.module_path[..],
729729
&import.subclass,
730730
span);
731-
error_vec.push((span, path, err));
731+
error_vec.push((span, path, err, note));
732732
seen_spans.insert(span);
733733
prev_root_id = import.root_id;
734734
}
@@ -821,27 +821,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
821821
}
822822
}
823823

824-
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
825-
span: Option<MultiSpan>) {
824+
fn throw_unresolved_import_error(
825+
&self,
826+
error_vec: Vec<(Span, String, String, Option<String>)>,
827+
span: Option<MultiSpan>,
828+
) {
826829
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
827-
let (span, msg) = if error_vec.is_empty() {
828-
(span.unwrap(), "unresolved import".to_string())
830+
let (span, msg, note) = if error_vec.is_empty() {
831+
(span.unwrap(), "unresolved import".to_string(), None)
829832
} else {
830-
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
831-
.map(|elem: (Span, String, String)| { elem.0 })
832-
.collect());
833+
let span = MultiSpan::from_spans(
834+
error_vec.clone().into_iter()
835+
.map(|elem: (Span, String, String, Option<String>)| elem.0)
836+
.collect()
837+
);
838+
839+
let note: Option<String> = error_vec.clone().into_iter()
840+
.filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
841+
.last();
842+
833843
let path_vec: Vec<String> = error_vec.clone().into_iter()
834-
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) })
844+
.map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
835845
.collect();
836846
let path = path_vec.join(", ");
837-
let msg = format!("unresolved import{} {}",
838-
if path_vec.len() > 1 { "s" } else { "" }, path);
839-
(span, msg)
847+
let msg = format!(
848+
"unresolved import{} {}",
849+
if path_vec.len() > 1 { "s" } else { "" },
850+
path
851+
);
852+
853+
(span, msg, note)
840854
};
855+
841856
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
842857
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
843858
err.span_label(span_error.0, span_error.2);
844859
}
860+
if let Some(note) = note {
861+
err.note(&note);
862+
}
845863
err.emit();
846864
}
847865

@@ -936,7 +954,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
936954
}
937955

938956
// If appropriate, returns an error to report.
939-
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
957+
fn finalize_import(
958+
&mut self,
959+
directive: &'b ImportDirective<'b>
960+
) -> Option<(Span, String, Option<String>)> {
940961
self.current_module = directive.parent;
941962
let ImportDirective { ref module_path, span, .. } = *directive;
942963

@@ -959,15 +980,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
959980
return None;
960981
}
961982
PathResult::Failed(span, msg, true) => {
962-
return if let Some(suggested_path) = self.make_path_suggestion(
983+
return if let Some((suggested_path, note)) = self.make_path_suggestion(
963984
span, module_path.clone()
964985
) {
965986
Some((
966987
span,
967-
format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
988+
format!("Did you mean `{}`?", names_to_string(&suggested_path[..])),
989+
note,
968990
))
969991
} else {
970-
Some((span, msg))
992+
Some((span, msg, None))
971993
};
972994
},
973995
_ => return None,
@@ -992,8 +1014,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
9921014
if let ModuleOrUniformRoot::Module(module) = module {
9931015
if module.def_id() == directive.parent.def_id() {
9941016
// Importing a module into itself is not allowed.
995-
return Some((directive.span,
996-
"Cannot glob-import a module into itself.".to_string()));
1017+
return Some((
1018+
directive.span,
1019+
"Cannot glob-import a module into itself.".to_string(),
1020+
None,
1021+
));
9971022
}
9981023
}
9991024
if !is_prelude &&
@@ -1084,7 +1109,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10841109
}
10851110
}
10861111
};
1087-
Some((span, msg))
1112+
Some((span, msg, None))
10881113
} else {
10891114
// `resolve_ident_in_module` reported a privacy error.
10901115
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)