diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e9331fcd8bad1..b50e37519d463 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -137,6 +137,9 @@ impl Ord for BindingError { } } +/// A span, message, replacement text, and applicability. +type Suggestion = (Span, String, String, Applicability); + enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. GenericParamsFromOuterFunction(Def), @@ -166,7 +169,7 @@ enum ResolutionError<'a> { /// Error E0431: `self` import can only appear in an import list with a non-empty prefix. SelfImportOnlyInImportListWithNonEmptyPrefix, /// Error E0433: failed to resolve. - FailedToResolve(&'a str), + FailedToResolve { label: String, suggestion: Option }, /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, /// Error E0435: attempt to use a non-constant value in a constant. @@ -380,10 +383,15 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, err.span_label(span, "can only appear in an import list with a non-empty prefix"); err } - ResolutionError::FailedToResolve(msg) => { + ResolutionError::FailedToResolve { label, suggestion } => { let mut err = struct_span_err!(resolver.session, span, E0433, - "failed to resolve: {}", msg); - err.span_label(span, msg); + "failed to resolve: {}", &label); + err.span_label(span, label); + + if let Some((span, msg, suggestion, applicability)) = suggestion { + err.span_suggestion(span, &msg, suggestion, applicability); + } + err } ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { @@ -1050,7 +1058,12 @@ enum PathResult<'a> { Module(ModuleOrUniformRoot<'a>), NonModule(PathResolution), Indeterminate, - Failed(Span, String, bool /* is the error from the last segment? */), + Failed { + span: Span, + label: String, + suggestion: Option, + is_error_from_last_segment: bool, + }, } enum ModuleKind { @@ -1775,13 +1788,18 @@ impl<'a> Resolver<'a> { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => path_res.base_def(), PathResult::NonModule(..) => { - let msg = "type-relative paths are not supported in this context"; - error_callback(self, span, ResolutionError::FailedToResolve(msg)); + error_callback(self, span, ResolutionError::FailedToResolve { + label: String::from("type-relative paths are not supported in this context"), + suggestion: None, + }); Def::Err } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), - PathResult::Failed(span, msg, _) => { - error_callback(self, span, ResolutionError::FailedToResolve(&msg)); + PathResult::Failed { span, label, suggestion, .. } => { + error_callback(self, span, ResolutionError::FailedToResolve { + label, + suggestion, + }); Def::Err } }; @@ -3429,7 +3447,7 @@ impl<'a> Resolver<'a> { // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. PathResult::Module(ModuleOrUniformRoot::Module(_)) | - PathResult::Failed(..) + PathResult::Failed { .. } if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types .contains_key(&path[0].ident.name) => { @@ -3438,11 +3456,11 @@ impl<'a> Resolver<'a> { } PathResult::Module(ModuleOrUniformRoot::Module(module)) => PathResolution::new(module.def().unwrap()), - PathResult::Failed(span, msg, false) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { + resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion }); err_path_resolution() } - PathResult::Module(..) | PathResult::Failed(..) => return None, + PathResult::Module(..) | PathResult::Failed { .. } => return None, PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), }; @@ -3550,7 +3568,12 @@ impl<'a> Resolver<'a> { } } let msg = "there are too many initial `super`s.".to_string(); - return PathResult::Failed(ident.span, msg, false); + return PathResult::Failed { + span: ident.span, + label: msg, + suggestion: None, + is_error_from_last_segment: false, + }; } if i == 0 { if name == keywords::SelfLower.name() { @@ -3587,12 +3610,17 @@ impl<'a> Resolver<'a> { } else { format!("`{}`", name) }; - let msg = if i == 1 && path[0].ident.name == keywords::PathRoot.name() { + let label = if i == 1 && path[0].ident.name == keywords::PathRoot.name() { format!("global paths cannot start with {}", name_str) } else { format!("{} in paths can only be used in start position", name_str) }; - return PathResult::Failed(ident.span, msg, false); + return PathResult::Failed { + span: ident.span, + label, + suggestion: None, + is_error_from_last_segment: false, + }; } let binding = if let Some(module) = module { @@ -3653,9 +3681,12 @@ impl<'a> Resolver<'a> { def, path.len() - i - 1 )); } else { - return PathResult::Failed(ident.span, - format!("not a module `{}`", ident), - is_last); + return PathResult::Failed { + span: ident.span, + label: format!("not a module `{}`", ident), + suggestion: None, + is_error_from_last_segment: is_last, + }; } } Err(Undetermined) => return PathResult::Indeterminate, @@ -3671,7 +3702,7 @@ impl<'a> Resolver<'a> { Some(ModuleOrUniformRoot::Module(module)) => module.def(), _ => None, }; - let msg = if module_def == self.graph_root.def() { + let (label, suggestion) = if module_def == self.graph_root.def() { let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; let mut candidates = self.lookup_import_candidates(ident, TypeNS, is_mod); @@ -3679,19 +3710,32 @@ impl<'a> Resolver<'a> { (c.path.segments.len(), c.path.to_string()) }); if let Some(candidate) = candidates.get(0) { - format!("did you mean `{}`?", candidate.path) + ( + String::from("unresolved import"), + Some(( + ident.span, + String::from("a similar path exists"), + candidate.path.to_string(), + Applicability::MaybeIncorrect, + )), + ) } else if !ident.is_reserved() { - format!("maybe a missing `extern crate {};`?", ident) + (format!("maybe a missing `extern crate {};`?", ident), None) } else { // the parser will already have complained about the keyword being used return PathResult::NonModule(err_path_resolution()); } } else if i == 0 { - format!("use of undeclared type or module `{}`", ident) + (format!("use of undeclared type or module `{}`", ident), None) } else { - format!("could not find `{}` in `{}`", ident, path[i - 1].ident) + (format!("could not find `{}` in `{}`", ident, path[i - 1].ident), None) + }; + return PathResult::Failed { + span: ident.span, + label, + suggestion, + is_error_from_last_segment: is_last, }; - return PathResult::Failed(ident.span, msg, is_last); } } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 63f752ac9c942..8e4b2a9a4cb1a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -426,9 +426,9 @@ impl<'a> Resolver<'a> { Ok(path_res.base_def()) } PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), - PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => { - Err(Determinacy::Determined) - } + PathResult::NonModule(..) + | PathResult::Indeterminate + | PathResult::Failed { .. } => Err(Determinacy::Determined), PathResult::Module(..) => unreachable!(), }; @@ -990,14 +990,17 @@ impl<'a> Resolver<'a> { let def = path_res.base_def(); check_consistency(self, &path, path_span, kind, initial_def, def); } - path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => { - let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res { - (span, msg) + path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { + (span, label) } else { (path_span, format!("partially resolved path in {} {}", kind.article(), kind.descr())) }; - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + resolve_error(self, span, ResolutionError::FailedToResolve { + label, + suggestion: None + }); } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index b930c30c51192..9daffd522bf2c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -6,9 +6,11 @@ use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use crate::{Resolver, Segment}; use crate::{names_to_string, module_to_string}; -use crate::{resolve_error, ResolutionError}; +use crate::{resolve_error, ResolutionError, Suggestion}; use crate::macros::ParentScope; +use errors::Applicability; + use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; use rustc::lint::builtin::BuiltinLintDiagnostics; @@ -27,7 +29,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax::{struct_span_err, unwrap_or}; use syntax_pos::{MultiSpan, Span}; -use log::debug; +use log::*; use std::cell::{Cell, RefCell}; use std::{mem, ptr}; @@ -623,6 +625,16 @@ impl<'a> Resolver<'a> { } } +/// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved +/// import errors within the same use tree into a single diagnostic. +#[derive(Debug, Clone)] +struct UnresolvedImportError { + span: Span, + label: Option, + note: Option, + suggestion: Option, +} + pub struct ImportResolver<'a, 'b: 'a> { pub resolver: &'a mut Resolver<'b>, } @@ -675,14 +687,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.finalize_resolutions_in(module); } - let mut errors = false; + let mut has_errors = false; let mut seen_spans = FxHashSet::default(); - let mut error_vec = Vec::new(); + let mut errors = vec![]; let mut prev_root_id: NodeId = NodeId::from_u32(0); for i in 0 .. self.determined_imports.len() { let import = self.determined_imports[i]; - if let Some((span, err, note)) = self.finalize_import(import) { - errors = true; + if let Some(err) = self.finalize_import(import) { + has_errors = true; if let SingleImport { source, ref source_bindings, .. } = import.subclass { if source.name == "self" { @@ -696,37 +708,36 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(import); - if prev_root_id.as_u32() != 0 && - prev_root_id.as_u32() != import.root_id.as_u32() && - !error_vec.is_empty(){ - // in case of new import line, throw diagnostic message - // for previous line. - let mut empty_vec = vec![]; - mem::swap(&mut empty_vec, &mut error_vec); - self.throw_unresolved_import_error(empty_vec, None); + if prev_root_id.as_u32() != 0 + && prev_root_id.as_u32() != import.root_id.as_u32() + && !errors.is_empty() { + // In the case of a new import line, throw a diagnostic message + // for the previous line. + self.throw_unresolved_import_error(errors, None); + errors = vec![]; } - if !seen_spans.contains(&span) { + if !seen_spans.contains(&err.span) { let path = import_path_to_string( &import.module_path.iter().map(|seg| seg.ident).collect::>(), &import.subclass, - span, + err.span, ); - error_vec.push((span, path, err, note)); - seen_spans.insert(span); + seen_spans.insert(err.span); + errors.push((path, err)); prev_root_id = import.root_id; } } } - if !error_vec.is_empty() { - self.throw_unresolved_import_error(error_vec.clone(), None); + if !errors.is_empty() { + self.throw_unresolved_import_error(errors.clone(), None); } // Report unresolved imports only if no hard error was already reported // to avoid generating multiple errors on the same import. - if !errors { + if !has_errors { for import in &self.indeterminate_imports { - self.throw_unresolved_import_error(error_vec, Some(MultiSpan::from(import.span))); + self.throw_unresolved_import_error(errors, Some(MultiSpan::from(import.span))); break; } } @@ -734,44 +745,58 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { fn throw_unresolved_import_error( &self, - error_vec: Vec<(Span, String, String, Option)>, + errors: Vec<(String, UnresolvedImportError)>, span: Option, ) { - let max_span_label_msg_count = 10; // upper limit on number of span_label message. - let (span, msg, note) = if error_vec.is_empty() { + /// Upper limit on the number of `span_label` messages. + const MAX_LABEL_COUNT: usize = 10; + + let (span, msg, note) = if errors.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, Option)| elem.0) - .collect() + errors + .iter() + .map(|(_, err)| err.span) + .collect(), ); - let note: Option = error_vec.clone().into_iter() - .filter_map(|elem: (Span, String, String, Option)| elem.3) + let note = errors + .iter() + .filter_map(|(_, err)| err.note.as_ref()) .last(); - let path_vec: Vec = error_vec.clone().into_iter() - .map(|elem: (Span, String, String, Option)| format!("`{}`", elem.1)) - .collect(); - let path = path_vec.join(", "); + let paths = errors + .iter() + .map(|(path, _)| format!("`{}`", path)) + .collect::>(); + let msg = format!( "unresolved import{} {}", - if path_vec.len() > 1 { "s" } else { "" }, - path + if paths.len() > 1 { "s" } else { "" }, + paths.join(", "), ); (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); + let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); + + if let Some(note) = ¬e { + diag.note(note); } - if let Some(note) = note { - err.note(¬e); + + for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { + if let Some(label) = err.label { + diag.span_label(err.span, label); + } + + if let Some((span, msg, suggestion, applicability)) = err.suggestion { + diag.span_suggestion(span, &msg, suggestion, applicability); + } } - err.emit(); + + diag.emit(); } /// Attempts to resolve the given import, returning true if its resolution is determined. @@ -802,7 +827,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { match path_res { PathResult::Module(module) => module, PathResult::Indeterminate => return false, - PathResult::NonModule(..) | PathResult::Failed(..) => return true, + PathResult::NonModule(..) | PathResult::Failed { .. } => return true, } }; @@ -866,11 +891,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { !indeterminate } - // If appropriate, returns an error to report. + /// Performs final import resolution, consistency checks and error reporting. + /// + /// Optionally returns an unresolved import error. This error is buffered and used to + /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import( &mut self, directive: &'b ImportDirective<'b> - ) -> Option<(Span, String, Option)> { + ) -> Option { self.current_module = directive.parent_scope.module; let orig_vis = directive.vis.replace(ty::Visibility::Invisible); @@ -896,25 +924,48 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { module } - PathResult::Failed(span, msg, false) => { + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + resolve_error(self, span, ResolutionError::FailedToResolve { + label, + suggestion, + }); } return None; } - PathResult::Failed(span, msg, true) => { + PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { assert!(directive.imported_module.get().is_none()); - return Some(match self.make_path_suggestion(span, directive.module_path.clone(), - &directive.parent_scope) { - Some((suggestion, note)) => ( - span, - format!("did you mean `{}`?", Segment::names_to_string(&suggestion)), - note, - ), - None => (span, msg, None), - }); + let err = match self.make_path_suggestion( + span, + directive.module_path.clone(), + &directive.parent_scope, + ) { + Some((suggestion, note)) => { + UnresolvedImportError { + span, + label: None, + note, + suggestion: Some(( + span, + String::from("a similar path exists"), + Segment::names_to_string(&suggestion), + Applicability::MaybeIncorrect, + )), + } + } + None => { + UnresolvedImportError { + span, + label: Some(label), + note: None, + suggestion, + } + } + }; + + return Some(err); } return None; } @@ -950,11 +1001,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let ModuleOrUniformRoot::Module(module) = module { if module.def_id() == directive.parent_scope.module.def_id() { // Importing a module into itself is not allowed. - return Some(( - directive.span, - "Cannot glob-import a module into itself.".to_string(), - None, - )); + return Some(UnresolvedImportError { + span: directive.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + }); } } if !is_prelude && @@ -1059,31 +1111,42 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => Some(&i.name), } }); + let lev_suggestion = - match find_best_match_for_name(names, &ident.as_str(), None) { - Some(name) => format!(". Did you mean to use `{}`?", name), - None => String::new(), - }; - let msg = match module { + find_best_match_for_name(names, &ident.as_str(), None).map(|suggestion| { + ( + ident.span, + String::from("a similar name exists in the module"), + suggestion.to_string(), + Applicability::MaybeIncorrect, + ) + }); + + let label = match module { ModuleOrUniformRoot::Module(module) => { let module_str = module_to_string(module); if let Some(module_str) = module_str { - format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) + format!("no `{}` in `{}`", ident, module_str) } else { - format!("no `{}` in the root{}", ident, lev_suggestion) + format!("no `{}` in the root", ident) } } _ => { if !ident.is_path_segment_keyword() { - format!("no `{}` external crate{}", ident, lev_suggestion) + format!("no `{}` external crate", ident) } else { // HACK(eddyb) this shows up for `self` & `super`, which // should work instead - for now keep the same error message. - format!("no `{}` in the root{}", ident, lev_suggestion) + format!("no `{}` in the root", ident) } } }; - Some((directive.span, msg, None)) + Some(UnresolvedImportError { + span: directive.span, + label: Some(label), + note: None, + suggestion: lev_suggestion, + }) } else { // `resolve_ident_in_module` reported a privacy error. self.import_dummy_binding(directive); diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index 4d2e35dff4629..603b29aa989fd 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -8,7 +8,10 @@ error[E0432]: unresolved import `prelude` --> $DIR/issue-55897.rs:1:5 | LL | use prelude::*; //~ ERROR unresolved import `prelude` - | ^^^^^^^ did you mean `std::prelude`? + | ^^^^^^^ + | | + | unresolved import + | help: a similar path exists: `std::prelude` error: cannot determine resolution for the macro `env` --> $DIR/issue-55897.rs:6:22 diff --git a/src/test/ui/import.rs b/src/test/ui/import.rs index 540258daaec82..3170dd2fae108 100644 --- a/src/test/ui/import.rs +++ b/src/test/ui/import.rs @@ -1,6 +1,8 @@ use zed::bar; use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - //~^ no `baz` in `zed`. Did you mean to use `bar`? + //~| no `baz` in `zed` + //~| HELP a similar name exists in the module + //~| SUGGESTION bar mod zed { diff --git a/src/test/ui/import.stderr b/src/test/ui/import.stderr index 737d10cdecb23..bfbb6560d49d9 100644 --- a/src/test/ui/import.stderr +++ b/src/test/ui/import.stderr @@ -2,16 +2,19 @@ error[E0432]: unresolved import `zed::baz` --> $DIR/import.rs:2:5 | LL | use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - | ^^^^^^^^ no `baz` in `zed`. Did you mean to use `bar`? + | ^^^^^--- + | | | + | | help: a similar name exists in the module: `bar` + | no `baz` in `zed` error[E0432]: unresolved import `foo` - --> $DIR/import.rs:8:9 + --> $DIR/import.rs:10:9 | LL | use foo; //~ ERROR unresolved import `foo` [E0432] | ^^^ no `foo` in the root error[E0603]: unresolved item `foo` is private - --> $DIR/import.rs:13:10 + --> $DIR/import.rs:15:10 | LL | zed::foo(); //~ ERROR `foo` is private | ^^^ diff --git a/src/test/ui/imports/issue-55457.stderr b/src/test/ui/imports/issue-55457.stderr index 4ee0332d04bcd..a3474b2f7dbf1 100644 --- a/src/test/ui/imports/issue-55457.stderr +++ b/src/test/ui/imports/issue-55457.stderr @@ -2,7 +2,10 @@ error[E0432]: unresolved import `NonExistent` --> $DIR/issue-55457.rs:1:5 | LL | use NonExistent; //~ ERROR unresolved import `NonExistent` - | ^^^^^^^^^^^ no `NonExistent` in the root. Did you mean to use `non_existent`? + | ^^^^^^^^^^^ + | | + | no `NonExistent` in the root + | help: a similar name exists in the module: `non_existent` error[E0432]: unresolved import `non_existent` --> $DIR/issue-55457.rs:2:5 diff --git a/src/test/ui/inaccessible-test-modules.stderr b/src/test/ui/inaccessible-test-modules.stderr index 636ef8187059b..40f2b7fd2eebd 100644 --- a/src/test/ui/inaccessible-test-modules.stderr +++ b/src/test/ui/inaccessible-test-modules.stderr @@ -2,13 +2,19 @@ error[E0432]: unresolved import `__test` --> $DIR/inaccessible-test-modules.rs:5:5 | LL | use __test as x; //~ ERROR unresolved import `__test` - | ^^^^^^^^^^^ no `__test` in the root. Did you mean to use `test`? + | ------^^^^^ + | | + | no `__test` in the root + | help: a similar name exists in the module: `test` error[E0432]: unresolved import `__test_reexports` --> $DIR/inaccessible-test-modules.rs:6:5 | LL | use __test_reexports as y; //~ ERROR unresolved import `__test_reexports` - | ^^^^^^^^^^^^^^^^^^^^^ no `__test_reexports` in the root. Did you mean to use `__test_reexports`? + | ----------------^^^^^ + | | + | no `__test_reexports` in the root + | help: a similar name exists in the module: `__test_reexports` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-31212.stderr b/src/test/ui/issues/issue-31212.stderr index d964b702f221f..09300ffc78793 100644 --- a/src/test/ui/issues/issue-31212.stderr +++ b/src/test/ui/issues/issue-31212.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `self::*` --> $DIR/issue-31212.rs:5:13 | LL | pub use self::*; //~ ERROR unresolved - | ^^^^^^^ Cannot glob-import a module into itself. + | ^^^^^^^ cannot glob-import a module into itself error[E0425]: cannot find function `f` in module `foo` --> $DIR/issue-31212.rs:9:10 diff --git a/src/test/ui/issues/issue-8208.rs b/src/test/ui/issues/issue-8208.rs index ad94f99098db8..1c566938f9d0e 100644 --- a/src/test/ui/issues/issue-8208.rs +++ b/src/test/ui/issues/issue-8208.rs @@ -1,14 +1,14 @@ use self::*; //~ ERROR: unresolved import `self::*` [E0432] - //~^ Cannot glob-import a module into itself. + //~^ cannot glob-import a module into itself mod foo { use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] - //~^ Cannot glob-import a module into itself. + //~^ cannot glob-import a module into itself mod bar { use super::bar::*; //~^ ERROR: unresolved import `super::bar::*` [E0432] - //~| Cannot glob-import a module into itself. + //~| cannot glob-import a module into itself } } diff --git a/src/test/ui/issues/issue-8208.stderr b/src/test/ui/issues/issue-8208.stderr index 6de95fb953a9f..a042dce1ac1d0 100644 --- a/src/test/ui/issues/issue-8208.stderr +++ b/src/test/ui/issues/issue-8208.stderr @@ -2,19 +2,19 @@ error[E0432]: unresolved import `self::*` --> $DIR/issue-8208.rs:1:5 | LL | use self::*; //~ ERROR: unresolved import `self::*` [E0432] - | ^^^^^^^ Cannot glob-import a module into itself. + | ^^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `foo::*` --> $DIR/issue-8208.rs:5:9 | LL | use foo::*; //~ ERROR: unresolved import `foo::*` [E0432] - | ^^^^^^ Cannot glob-import a module into itself. + | ^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `super::bar::*` --> $DIR/issue-8208.rs:9:13 | LL | use super::bar::*; - | ^^^^^^^^^^^^^ Cannot glob-import a module into itself. + | ^^^^^^^^^^^^^ cannot glob-import a module into itself error: aborting due to 3 previous errors diff --git a/src/test/ui/resolve_self_super_hint.rs b/src/test/ui/resolve_self_super_hint.rs index 193a6ecf9d570..91a01cc0fa231 100644 --- a/src/test/ui/resolve_self_super_hint.rs +++ b/src/test/ui/resolve_self_super_hint.rs @@ -5,19 +5,23 @@ mod a { extern crate alloc; use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `self::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION self::alloc mod b { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `super::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION super::alloc mod c { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `a::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION a::alloc mod d { use alloc::HashMap; //~^ ERROR unresolved import `alloc` [E0432] - //~| did you mean `a::alloc`? + //~| HELP a similar path exists + //~| SUGGESTION a::alloc } } } diff --git a/src/test/ui/resolve_self_super_hint.stderr b/src/test/ui/resolve_self_super_hint.stderr index ddae0e5f6aaba..03214cad8e41a 100644 --- a/src/test/ui/resolve_self_super_hint.stderr +++ b/src/test/ui/resolve_self_super_hint.stderr @@ -2,25 +2,31 @@ error[E0432]: unresolved import `alloc` --> $DIR/resolve_self_super_hint.rs:6:9 | LL | use alloc::HashMap; - | ^^^^^ did you mean `self::alloc`? + | ^^^^^ help: a similar path exists: `self::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:10:13 + --> $DIR/resolve_self_super_hint.rs:11:13 | LL | use alloc::HashMap; - | ^^^^^ did you mean `super::alloc`? + | ^^^^^ help: a similar path exists: `super::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:14:17 + --> $DIR/resolve_self_super_hint.rs:16:17 | LL | use alloc::HashMap; - | ^^^^^ did you mean `a::alloc`? + | ^^^^^ + | | + | unresolved import + | help: a similar path exists: `a::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:18:21 + --> $DIR/resolve_self_super_hint.rs:21:21 | LL | use alloc::HashMap; - | ^^^^^ did you mean `a::alloc`? + | ^^^^^ + | | + | unresolved import + | help: a similar path exists: `a::alloc` error: aborting due to 4 previous errors diff --git a/src/test/ui/rust-2018/issue-54006.stderr b/src/test/ui/rust-2018/issue-54006.stderr index 6c6d7720be2c2..1978138a68878 100644 --- a/src/test/ui/rust-2018/issue-54006.stderr +++ b/src/test/ui/rust-2018/issue-54006.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `alloc` --> $DIR/issue-54006.rs:6:5 | LL | use alloc::vec; - | ^^^^^ did you mean `core::alloc`? + | ^^^^^ help: a similar path exists: `core::alloc` error: cannot determine resolution for the macro `vec` --> $DIR/issue-54006.rs:10:18 diff --git a/src/test/ui/rust-2018/local-path-suggestions-2015.stderr b/src/test/ui/rust-2018/local-path-suggestions-2015.stderr index be642c3bcdcbb..fafb35ec50d6d 100644 --- a/src/test/ui/rust-2018/local-path-suggestions-2015.stderr +++ b/src/test/ui/rust-2018/local-path-suggestions-2015.stderr @@ -2,7 +2,10 @@ error[E0432]: unresolved import `foobar` --> $DIR/local-path-suggestions-2015.rs:24:5 | LL | use foobar::Baz; //~ ERROR unresolved import `foobar` - | ^^^^^^ did you mean `aux_baz::foobar`? + | ^^^^^^ + | | + | unresolved import + | help: a similar path exists: `aux_baz::foobar` error: aborting due to previous error diff --git a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr index 71c8289264ffe..759977b3f0629 100644 --- a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr +++ b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `foo` --> $DIR/local-path-suggestions-2018.rs:10:9 | LL | use foo::Bar; //~ ERROR unresolved import `foo` - | ^^^ did you mean `crate::foo`? + | ^^^ help: a similar path exists: `crate::foo` | = note: `use` statements changed in Rust 2018; read more at @@ -10,7 +10,7 @@ error[E0432]: unresolved import `foobar` --> $DIR/local-path-suggestions-2018.rs:19:5 | LL | use foobar::Baz; //~ ERROR unresolved import `foobar` - | ^^^^^^ did you mean `baz::foobar`? + | ^^^^^^ help: a similar path exists: `baz::foobar` error: aborting due to 2 previous errors diff --git a/src/test/ui/unresolved/unresolved-import.rs b/src/test/ui/unresolved/unresolved-import.rs index be2a2c75485f6..4c7d4bb935331 100644 --- a/src/test/ui/unresolved/unresolved-import.rs +++ b/src/test/ui/unresolved/unresolved-import.rs @@ -1,16 +1,20 @@ -// ignore-tidy-linelength - use foo::bar; //~ ERROR unresolved import `foo` [E0432] //~^ maybe a missing `extern crate foo;`? use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] - //~^ no `Baz` in `bar`. Did you mean to use `Bar`? + //~| no `Baz` in `bar` + //~| HELP a similar name exists in the module + //~| SUGGESTION Bar use food::baz; //~ ERROR unresolved import `food::baz` - //~^ no `baz` in `food`. Did you mean to use `bag`? + //~| no `baz` in `food` + //~| HELP a similar name exists in the module + //~| SUGGESTION bag use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432] - //~^ no `beens` in `food`. Did you mean to use `beans`? + //~| no `beens` in `food` + //~| HELP a similar name exists in the module + //~| SUGGESTION beans mod bar { pub struct Bar; @@ -32,7 +36,8 @@ mod m { } use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432] - //~^ did you mean `self::MyEnum`? + //~| HELP a similar path exists + //~| SUGGESTION self::MyEnum } mod items { @@ -41,7 +46,8 @@ mod items { } use Enum::*; //~ ERROR unresolved import `Enum` [E0432] - //~^ did you mean `self::Enum`? + //~| HELP a similar path exists + //~| SUGGESTION self::Enum fn item() {} } diff --git a/src/test/ui/unresolved/unresolved-import.stderr b/src/test/ui/unresolved/unresolved-import.stderr index 0dc4b72208ac1..4f2fef938c975 100644 --- a/src/test/ui/unresolved/unresolved-import.stderr +++ b/src/test/ui/unresolved/unresolved-import.stderr @@ -1,38 +1,47 @@ error[E0432]: unresolved import `foo` - --> $DIR/unresolved-import.rs:3:5 + --> $DIR/unresolved-import.rs:1:5 | LL | use foo::bar; //~ ERROR unresolved import `foo` [E0432] | ^^^ maybe a missing `extern crate foo;`? error[E0432]: unresolved import `bar::Baz` - --> $DIR/unresolved-import.rs:6:5 + --> $DIR/unresolved-import.rs:4:5 | LL | use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] - | ^^^^^^^^^^^^^ no `Baz` in `bar`. Did you mean to use `Bar`? + | ^^^^^---^^^^^ + | | | + | | help: a similar name exists in the module: `Bar` + | no `Baz` in `bar` error[E0432]: unresolved import `food::baz` --> $DIR/unresolved-import.rs:9:5 | LL | use food::baz; //~ ERROR unresolved import `food::baz` - | ^^^^^^^^^ no `baz` in `food`. Did you mean to use `bag`? + | ^^^^^^--- + | | | + | | help: a similar name exists in the module: `bag` + | no `baz` in `food` error[E0432]: unresolved import `food::beens` - --> $DIR/unresolved-import.rs:12:12 + --> $DIR/unresolved-import.rs:14:12 | LL | use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432] - | ^^^^^^^^^^^^ no `beens` in `food`. Did you mean to use `beans`? + | -----^^^^^^^ + | | + | no `beens` in `food` + | help: a similar name exists in the module: `beans` error[E0432]: unresolved import `MyEnum` - --> $DIR/unresolved-import.rs:34:9 + --> $DIR/unresolved-import.rs:38:9 | LL | use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432] - | ^^^^^^ did you mean `self::MyEnum`? + | ^^^^^^ help: a similar path exists: `self::MyEnum` error[E0432]: unresolved import `Enum` - --> $DIR/unresolved-import.rs:43:9 + --> $DIR/unresolved-import.rs:48:9 | LL | use Enum::*; //~ ERROR unresolved import `Enum` [E0432] - | ^^^^ did you mean `self::Enum`? + | ^^^^ help: a similar path exists: `self::Enum` error: aborting due to 6 previous errors diff --git a/src/test/ui/use/use-nested-groups-error.stderr b/src/test/ui/use/use-nested-groups-error.stderr index 9d6fd9df6cbe6..7234c8ec621cd 100644 --- a/src/test/ui/use/use-nested-groups-error.stderr +++ b/src/test/ui/use/use-nested-groups-error.stderr @@ -2,7 +2,10 @@ error[E0432]: unresolved import `a::b1::C1` --> $DIR/use-nested-groups-error.rs:9:14 | LL | use a::{b1::{C1, C2}, B2}; - | ^^ no `C1` in `a::b1`. Did you mean to use `C2`? + | ^^ + | | + | no `C1` in `a::b1` + | help: a similar name exists in the module: `C2` error: aborting due to previous error