mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-11 16:15:03 +00:00
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.
This commit is contained in:
parent
1982f1887a
commit
0d06b8c8e5
@ -26,7 +26,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
path: Vec<Segment>,
|
path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> Option<Vec<Segment>> {
|
) -> Option<(Vec<Segment>, Option<String>)> {
|
||||||
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
|
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
|
||||||
// If we don't have a path to suggest changes to, then return.
|
// If we don't have a path to suggest changes to, then return.
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
@ -65,13 +65,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
mut path: Vec<Segment>,
|
mut path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> Option<Vec<Segment>> {
|
) -> Option<(Vec<Segment>, Option<String>)> {
|
||||||
// Replace first ident with `self` and check if that is valid.
|
// Replace first ident with `self` and check if that is valid.
|
||||||
path[0].ident.name = keywords::SelfValue.name();
|
path[0].ident.name = keywords::SelfValue.name();
|
||||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||||
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
|
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
|
||||||
if let PathResult::Module(..) = result {
|
if let PathResult::Module(..) = result {
|
||||||
Some(path)
|
Some((path, None))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -89,13 +89,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
mut path: Vec<Segment>,
|
mut path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> Option<Vec<Segment>> {
|
) -> Option<(Vec<Segment>, Option<String>)> {
|
||||||
// Replace first ident with `crate` and check if that is valid.
|
// Replace first ident with `crate` and check if that is valid.
|
||||||
path[0].ident.name = keywords::Crate.name();
|
path[0].ident.name = keywords::Crate.name();
|
||||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||||
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
|
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
|
||||||
if let PathResult::Module(..) = 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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -113,13 +120,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
mut path: Vec<Segment>,
|
mut path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> Option<Vec<Segment>> {
|
) -> Option<(Vec<Segment>, Option<String>)> {
|
||||||
// Replace first ident with `crate` and check if that is valid.
|
// Replace first ident with `crate` and check if that is valid.
|
||||||
path[0].ident.name = keywords::Super.name();
|
path[0].ident.name = keywords::Super.name();
|
||||||
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
let result = self.resolve_path(None, &path, None, parent_scope, false, span, CrateLint::No);
|
||||||
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
|
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
|
||||||
if let PathResult::Module(..) = result {
|
if let PathResult::Module(..) = result {
|
||||||
Some(path)
|
Some((path, None))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -140,7 +147,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
mut path: Vec<Segment>,
|
mut path: Vec<Segment>,
|
||||||
parent_scope: &ParentScope<'b>,
|
parent_scope: &ParentScope<'b>,
|
||||||
) -> 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
|
// 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)
|
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
|
||||||
// each time.
|
// each time.
|
||||||
@ -162,7 +169,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
|
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
|
||||||
name, path, result);
|
name, path, result);
|
||||||
if let PathResult::Module(..) = result {
|
if let PathResult::Module(..) = result {
|
||||||
return Some(path)
|
return Some((path, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,7 +707,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;
|
errors = true;
|
||||||
|
|
||||||
if let SingleImport { source, ref result, .. } = import.subclass {
|
if let SingleImport { source, ref result, .. } = import.subclass {
|
||||||
@ -737,7 +737,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
&import.subclass,
|
&import.subclass,
|
||||||
span,
|
span,
|
||||||
);
|
);
|
||||||
error_vec.push((span, path, err));
|
error_vec.push((span, path, err, note));
|
||||||
seen_spans.insert(span);
|
seen_spans.insert(span);
|
||||||
prev_root_id = import.root_id;
|
prev_root_id = import.root_id;
|
||||||
}
|
}
|
||||||
@ -829,27 +829,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
|
fn throw_unresolved_import_error(
|
||||||
span: Option<MultiSpan>) {
|
&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 max_span_label_msg_count = 10; // upper limit on number of span_label message.
|
||||||
let (span, msg) = if error_vec.is_empty() {
|
let (span, msg, note) = if error_vec.is_empty() {
|
||||||
(span.unwrap(), "unresolved import".to_string())
|
(span.unwrap(), "unresolved import".to_string(), None)
|
||||||
} else {
|
} else {
|
||||||
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
|
let span = MultiSpan::from_spans(
|
||||||
.map(|elem: (Span, String, String)| { elem.0 })
|
error_vec.clone().into_iter()
|
||||||
.collect());
|
.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()
|
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();
|
.collect();
|
||||||
let path = path_vec.join(", ");
|
let path = path_vec.join(", ");
|
||||||
let msg = format!("unresolved import{} {}",
|
let msg = format!(
|
||||||
if path_vec.len() > 1 { "s" } else { "" }, path);
|
"unresolved import{} {}",
|
||||||
(span, msg)
|
if path_vec.len() > 1 { "s" } else { "" },
|
||||||
|
path
|
||||||
|
);
|
||||||
|
|
||||||
|
(span, msg, note)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
|
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) {
|
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
|
||||||
err.span_label(span_error.0, span_error.2);
|
err.span_label(span_error.0, span_error.2);
|
||||||
}
|
}
|
||||||
|
if let Some(note) = note {
|
||||||
|
err.note(¬e);
|
||||||
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,7 +963,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If appropriate, returns an error to report.
|
// 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_scope.module;
|
self.current_module = directive.parent_scope.module;
|
||||||
let ImportDirective { ref module_path, span, .. } = *directive;
|
let ImportDirective { ref module_path, span, .. } = *directive;
|
||||||
|
|
||||||
@ -969,15 +990,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
PathResult::Failed(span, msg, true) => {
|
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(), &directive.parent_scope
|
span, module_path.clone(), &directive.parent_scope
|
||||||
) {
|
) {
|
||||||
Some((
|
Some((
|
||||||
span,
|
span,
|
||||||
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
|
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)),
|
||||||
|
note,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Some((span, msg))
|
Some((span, msg, None))
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
@ -1002,8 +1024,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
if let ModuleOrUniformRoot::Module(module) = module {
|
if let ModuleOrUniformRoot::Module(module) = module {
|
||||||
if module.def_id() == directive.parent_scope.module.def_id() {
|
if module.def_id() == directive.parent_scope.module.def_id() {
|
||||||
// Importing a module into itself is not allowed.
|
// Importing a module into itself is not allowed.
|
||||||
return Some((directive.span,
|
return Some((
|
||||||
"Cannot glob-import a module into itself.".to_string()));
|
directive.span,
|
||||||
|
"Cannot glob-import a module into itself.".to_string(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !is_prelude &&
|
if !is_prelude &&
|
||||||
@ -1101,7 +1126,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some((span, msg))
|
Some((span, msg, None))
|
||||||
} else {
|
} else {
|
||||||
// `resolve_ident_in_module` reported a privacy error.
|
// `resolve_ident_in_module` reported a privacy error.
|
||||||
self.import_dummy_binding(directive);
|
self.import_dummy_binding(directive);
|
||||||
|
@ -3,6 +3,8 @@ error[E0432]: unresolved import `foo`
|
|||||||
|
|
|
|
||||||
LL | use foo::Bar;
|
LL | use foo::Bar;
|
||||||
| ^^^ Did you mean `crate::foo`?
|
| ^^^ 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`
|
error[E0432]: unresolved import `foo`
|
||||||
--> $DIR/local-path-suggestions-2018.rs:27:5
|
--> $DIR/local-path-suggestions-2018.rs:27:5
|
||||||
|
Loading…
Reference in New Issue
Block a user