Skip to content

Commit 8d5fb4c

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 82239b0 commit 8d5fb4c

File tree

3 files changed

+63
-29
lines changed

3 files changed

+63
-29
lines changed

Diff for: 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<Segment>
27-
) -> Option<Vec<Segment>> {
27+
) -> Option<(Vec<Segment>, 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<Segment>
63-
) -> Option<Vec<Segment>> {
63+
) -> Option<(Vec<Segment>, Option<String>)> {
6464
// Replace first ident with `self` and check if that is valid.
6565
path[0].ident.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<Segment>
86-
) -> Option<Vec<Segment>> {
86+
) -> Option<(Vec<Segment>, Option<String>)> {
8787
// Replace first ident with `crate` and check if that is valid.
8888
path[0].ident.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<Segment>
109-
) -> Option<Vec<Segment>> {
116+
) -> Option<(Vec<Segment>, Option<String>)> {
110117
// Replace first ident with `crate` and check if that is valid.
111118
path[0].ident.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<Segment>
135-
) -> Option<Vec<Segment>> {
142+
) -> Option<(Vec<Segment>, 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.
@@ -153,7 +160,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
153160
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
154161
name, path, result);
155162
if let PathResult::Module(..) = result {
156-
return Some(path)
163+
return Some((path, None));
157164
}
158165
}
159166

Diff for: src/librustc_resolve/resolve_imports.rs

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

709709
if let SingleImport { source, ref result, .. } = import.subclass {
@@ -733,7 +733,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
733733
&import.subclass,
734734
span,
735735
);
736-
error_vec.push((span, path, err));
736+
error_vec.push((span, path, err, note));
737737
seen_spans.insert(span);
738738
prev_root_id = import.root_id;
739739
}
@@ -825,27 +825,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
825825
}
826826
}
827827

828-
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
829-
span: Option<MultiSpan>) {
828+
fn throw_unresolved_import_error(
829+
&self,
830+
error_vec: Vec<(Span, String, String, Option<String>)>,
831+
span: Option<MultiSpan>,
832+
) {
830833
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
831-
let (span, msg) = if error_vec.is_empty() {
832-
(span.unwrap(), "unresolved import".to_string())
834+
let (span, msg, note) = if error_vec.is_empty() {
835+
(span.unwrap(), "unresolved import".to_string(), None)
833836
} else {
834-
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
835-
.map(|elem: (Span, String, String)| { elem.0 })
836-
.collect());
837+
let span = MultiSpan::from_spans(
838+
error_vec.clone().into_iter()
839+
.map(|elem: (Span, String, String, Option<String>)| elem.0)
840+
.collect()
841+
);
842+
843+
let note: Option<String> = error_vec.clone().into_iter()
844+
.filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
845+
.last();
846+
837847
let path_vec: Vec<String> = error_vec.clone().into_iter()
838-
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) })
848+
.map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
839849
.collect();
840850
let path = path_vec.join(", ");
841-
let msg = format!("unresolved import{} {}",
842-
if path_vec.len() > 1 { "s" } else { "" }, path);
843-
(span, msg)
851+
let msg = format!(
852+
"unresolved import{} {}",
853+
if path_vec.len() > 1 { "s" } else { "" },
854+
path
855+
);
856+
857+
(span, msg, note)
844858
};
859+
845860
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
846861
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
847862
err.span_label(span_error.0, span_error.2);
848863
}
864+
if let Some(note) = note {
865+
err.note(&note);
866+
}
849867
err.emit();
850868
}
851869

@@ -941,7 +959,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
941959
}
942960

943961
// If appropriate, returns an error to report.
944-
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
962+
fn finalize_import(
963+
&mut self,
964+
directive: &'b ImportDirective<'b>
965+
) -> Option<(Span, String, Option<String>)> {
945966
self.current_module = directive.parent;
946967
let ImportDirective { ref module_path, span, .. } = *directive;
947968

@@ -964,15 +985,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
964985
return None;
965986
}
966987
PathResult::Failed(span, msg, true) => {
967-
return if let Some(suggested_path) = self.make_path_suggestion(
988+
return if let Some((suggested_path, note)) = self.make_path_suggestion(
968989
span, module_path.clone()
969990
) {
970991
Some((
971992
span,
972-
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
993+
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)),
994+
note,
973995
))
974996
} else {
975-
Some((span, msg))
997+
Some((span, msg, None))
976998
};
977999
},
9781000
_ => return None,
@@ -997,8 +1019,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
9971019
if let ModuleOrUniformRoot::Module(module) = module {
9981020
if module.def_id() == directive.parent.def_id() {
9991021
// Importing a module into itself is not allowed.
1000-
return Some((directive.span,
1001-
"Cannot glob-import a module into itself.".to_string()));
1022+
return Some((
1023+
directive.span,
1024+
"Cannot glob-import a module into itself.".to_string(),
1025+
None,
1026+
));
10021027
}
10031028
}
10041029
if !is_prelude &&
@@ -1096,7 +1121,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10961121
}
10971122
}
10981123
};
1099-
Some((span, msg))
1124+
Some((span, msg, None))
11001125
} else {
11011126
// `resolve_ident_in_module` reported a privacy error.
11021127
self.import_dummy_binding(directive);

Diff for: 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)