Skip to content

Commit 1cc978d

Browse files
davidtwcopietroalbini
authored andcommitted
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 f186dce commit 1cc978d

File tree

3 files changed

+65
-31
lines changed

3 files changed

+65
-31
lines changed

src/librustc_resolve/error_reporting.rs

Lines changed: 19 additions & 12 deletions
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<Ident>
2828
parent_scope: &ParentScope<'b>,
29-
) -> Option<Vec<Ident>> {
29+
) -> Option<(Vec<Ident>, 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<Ident>
6767
parent_scope: &ParentScope<'b>,
68-
) -> Option<Vec<Ident>> {
68+
) -> Option<(Vec<Ident>, Option<String>)> {
6969
// Replace first ident with `self` and check if that is valid.
70-
path[0].name = keywords::SelfValue.name();
70+
path[0] = 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<Ident>
9191
parent_scope: &ParentScope<'b>,
92-
) -> Option<Vec<Ident>> {
92+
) -> Option<(Vec<Ident>, Option<String>)> {
9393
// Replace first ident with `crate` and check if that is valid.
94-
path[0].name = keywords::Crate.name();
94+
path[0] = 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,14 +120,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
113120
span: Span,
114121
mut path: Vec<Ident>
115122
parent_scope: &ParentScope<'b>,
116-
) -> Option<Vec<Ident>> {
123+
) -> Option<(Vec<Ident>, Option<String>)> {
117124
// Replace first ident with `crate` and check if that is valid.
118-
path[0].name = keywords::Super.name();
125+
path[0] = keywords::Super.name();
119126
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
120127
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
121128
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
122129
if let PathResult::Module(..) = result {
123-
Some(path)
130+
Some((path, None))
124131
} else {
125132
None
126133
}
@@ -141,7 +148,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
141148
span: Span,
142149
mut path: Vec<Ident>
143150
parent_scope: &ParentScope<'b>,
144-
) -> Option<Vec<Ident>> {
151+
) -> Option<(Vec<Ident>, Option<String>)> {
145152
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
146153
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
147154
// each time.
@@ -163,7 +170,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
163170
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
164171
name, path, result);
165172
if let PathResult::Module(..) = result {
166-
return Some(path)
173+
return Some((path, None));
167174
}
168175
}
169176

src/librustc_resolve/resolve_imports.rs

Lines changed: 44 additions & 19 deletions
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 {
@@ -735,7 +735,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
735735
let path = import_path_to_string(&import.module_path[..],
736736
&import.subclass,
737737
span);
738-
error_vec.push((span, path, err));
738+
error_vec.push((span, path, err, note));
739739
seen_spans.insert(span);
740740
prev_root_id = import.root_id;
741741
}
@@ -827,27 +827,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
827827
}
828828
}
829829

830-
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
831-
span: Option<MultiSpan>) {
830+
fn throw_unresolved_import_error(
831+
&self,
832+
error_vec: Vec<(Span, String, String, Option<String>)>,
833+
span: Option<MultiSpan>,
834+
) {
832835
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
833-
let (span, msg) = if error_vec.is_empty() {
834-
(span.unwrap(), "unresolved import".to_string())
836+
let (span, msg, note) = if error_vec.is_empty() {
837+
(span.unwrap(), "unresolved import".to_string(), None)
835838
} else {
836-
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
837-
.map(|elem: (Span, String, String)| { elem.0 })
838-
.collect());
839+
let span = MultiSpan::from_spans(
840+
error_vec.clone().into_iter()
841+
.map(|elem: (Span, String, String, Option<String>)| elem.0)
842+
.collect()
843+
);
844+
845+
let note: Option<String> = error_vec.clone().into_iter()
846+
.filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
847+
.last();
848+
839849
let path_vec: Vec<String> = error_vec.clone().into_iter()
840-
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) })
850+
.map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
841851
.collect();
842852
let path = path_vec.join(", ");
843-
let msg = format!("unresolved import{} {}",
844-
if path_vec.len() > 1 { "s" } else { "" }, path);
845-
(span, msg)
853+
let msg = format!(
854+
"unresolved import{} {}",
855+
if path_vec.len() > 1 { "s" } else { "" },
856+
path
857+
);
858+
859+
(span, msg, note)
846860
};
861+
847862
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
848863
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
849864
err.span_label(span_error.0, span_error.2);
850865
}
866+
if let Some(note) = note {
867+
err.note(&note);
868+
}
851869
err.emit();
852870
}
853871

@@ -943,7 +961,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
943961
}
944962

945963
// If appropriate, returns an error to report.
946-
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
964+
fn finalize_import(
965+
&mut self,
966+
directive: &'b ImportDirective<'b>
967+
) -> Option<(Span, String, Option<String>)> {
947968
self.current_module = directive.parent_scope.module;
948969
let ImportDirective { ref module_path, span, .. } = *directive;
949970

@@ -967,15 +988,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
967988
return None;
968989
}
969990
PathResult::Failed(span, msg, true) => {
970-
return if let Some(suggested_path) = self.make_path_suggestion(
991+
return if let Some((suggested_path, note)) = self.make_path_suggestion(
971992
span, module_path.clone(), &directive.parent_scope
972993
) {
973994
Some((
974995
span,
975996
format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
997+
note,
976998
))
977999
} else {
978-
Some((span, msg))
1000+
Some((span, msg, None))
9791001
};
9801002
},
9811003
_ => return None,
@@ -1000,8 +1022,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10001022
if let ModuleOrUniformRoot::Module(module) = module {
10011023
if module.def_id() == directive.parent_scope.module.def_id() {
10021024
// Importing a module into itself is not allowed.
1003-
return Some((directive.span,
1004-
"Cannot glob-import a module into itself.".to_string()));
1025+
return Some((
1026+
directive.span,
1027+
"Cannot glob-import a module into itself.".to_string(),
1028+
None,
1029+
));
10051030
}
10061031
}
10071032
if !is_prelude &&
@@ -1099,7 +1124,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10991124
}
11001125
}
11011126
};
1102-
Some((span, msg))
1127+
Some((span, msg, None))
11031128
} else {
11041129
// `resolve_ident_in_module` reported a privacy error.
11051130
self.import_dummy_binding(directive);

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

Lines changed: 2 additions & 0 deletions
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)