Skip to content

Commit

Permalink
Rollup merge of rust-lang#55185 - davidtwco:issue-55130, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Mark-Simulacrum authored Oct 27, 2018
2 parents ef8f09a + 8d5fb4c commit be00065
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 29 deletions.
25 changes: 16 additions & 9 deletions src/librustc_resolve/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&mut self,
span: Span,
path: Vec<Segment>
) -> Option<Vec<Segment>> {
) -> Option<(Vec<Segment>, Option<String>)> {
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
// If we don't have a path to suggest changes to, then return.
if path.is_empty() {
Expand Down Expand Up @@ -60,13 +60,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&mut self,
span: Span,
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `self` and check if that is valid.
path[0].ident.name = keywords::SelfValue.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
Some(path)
Some((path, None))
} else {
None
}
Expand All @@ -83,13 +83,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&mut self,
span: Span,
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = keywords::Crate.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
Some(path)
Some((
path,
Some(
"`use` statements changed in Rust 2018; read more at \
<https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
clarity.html>".to_string()
),
))
} else {
None
}
Expand All @@ -106,13 +113,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&mut self,
span: Span,
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
) -> Option<(Vec<Segment>, Option<String>)> {
// Replace first ident with `crate` and check if that is valid.
path[0].ident.name = keywords::Super.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
Some(path)
Some((path, None))
} else {
None
}
Expand All @@ -132,7 +139,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&mut self,
span: Span,
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
) -> Option<(Vec<Segment>, Option<String>)> {
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
// each time.
Expand All @@ -153,7 +160,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result);
if let PathResult::Module(..) = result {
return Some(path)
return Some((path, None));
}
}

Expand Down
65 changes: 45 additions & 20 deletions src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
}
}
});
} else if let Some((span, err)) = error {
} else if let Some((span, err, note)) = error {
errors = true;

if let SingleImport { source, ref result, .. } = import.subclass {
Expand Down Expand Up @@ -733,7 +733,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
&import.subclass,
span,
);
error_vec.push((span, path, err));
error_vec.push((span, path, err, note));
seen_spans.insert(span);
prev_root_id = import.root_id;
}
Expand Down Expand Up @@ -825,27 +825,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
}
}

fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
span: Option<MultiSpan>) {
fn throw_unresolved_import_error(
&self,
error_vec: Vec<(Span, String, String, Option<String>)>,
span: Option<MultiSpan>,
) {
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
let (span, msg) = if error_vec.is_empty() {
(span.unwrap(), "unresolved import".to_string())
let (span, msg, note) = if error_vec.is_empty() {
(span.unwrap(), "unresolved import".to_string(), None)
} else {
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
.map(|elem: (Span, String, String)| { elem.0 })
.collect());
let span = MultiSpan::from_spans(
error_vec.clone().into_iter()
.map(|elem: (Span, String, String, Option<String>)| elem.0)
.collect()
);

let note: Option<String> = error_vec.clone().into_iter()
.filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
.last();

let path_vec: Vec<String> = error_vec.clone().into_iter()
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) })
.map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
.collect();
let path = path_vec.join(", ");
let msg = format!("unresolved import{} {}",
if path_vec.len() > 1 { "s" } else { "" }, path);
(span, msg)
let msg = format!(
"unresolved import{} {}",
if path_vec.len() > 1 { "s" } else { "" },
path
);

(span, msg, note)
};

let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
err.span_label(span_error.0, span_error.2);
}
if let Some(note) = note {
err.note(&note);
}
err.emit();
}

Expand Down Expand Up @@ -941,7 +959,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
}

// If appropriate, returns an error to report.
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
fn finalize_import(
&mut self,
directive: &'b ImportDirective<'b>
) -> Option<(Span, String, Option<String>)> {
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;

Expand All @@ -964,15 +985,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
return None;
}
PathResult::Failed(span, msg, true) => {
return if let Some(suggested_path) = self.make_path_suggestion(
return if let Some((suggested_path, note)) = self.make_path_suggestion(
span, module_path.clone()
) {
Some((
span,
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)),
note,
))
} else {
Some((span, msg))
Some((span, msg, None))
};
},
_ => return None,
Expand All @@ -997,8 +1019,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
if let ModuleOrUniformRoot::Module(module) = module {
if module.def_id() == directive.parent.def_id() {
// Importing a module into itself is not allowed.
return Some((directive.span,
"Cannot glob-import a module into itself.".to_string()));
return Some((
directive.span,
"Cannot glob-import a module into itself.".to_string(),
None,
));
}
}
if !is_prelude &&
Expand Down Expand Up @@ -1096,7 +1121,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
}
}
};
Some((span, msg))
Some((span, msg, None))
} else {
// `resolve_ident_in_module` reported a privacy error.
self.import_dummy_binding(directive);
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/rust-2018/local-path-suggestions-2018.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ error[E0432]: unresolved import `foo`
|
LL | use foo::Bar;
| ^^^ Did you mean `crate::foo`?
|
= note: `use` statements changed in Rust 2018; read more at <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html>

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

0 comments on commit be00065

Please sign in to comment.