Skip to content

Commit 0d06b8c

Browse files
committed
Add note linking to Rust 2018 path semantics docs.
This commit extends existing path suggestions to link to documentation on the changed semantics of `use` in Rust 2018.
1 parent 1982f18 commit 0d06b8c

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)