Rollup merge of #145399 - estebank:resolve-error-wording-2, r=petrochenkov
Unify wording of resolve error
Remove "failed to resolve" from the main error message and use the same format we use in other resolution errors "cannot find `name`":
```
error[E0433]: cannot find `nonexistent` in `existent`
--> $DIR/custom_attr_multisegment_error.rs:5:13
|
LL | #[existent::nonexistent]
| ^^^^^^^^^^^ could not find `nonexistent` in `existent`
```
The intent behind this is to end up with all resolve errors eventually be on the form of
```
error[ECODE]: cannot find `{NAME}` in {SCOPE}
--> $DIR/file.rs:5:13
|
LL | #[existent::nonexistent]
| ^^^^^^^^^^^ {SPECIFIC LABEL}
```
A category of errors that is interest are those that involve keywords. For example:
```
error[E0433]: cannot find `Self` in this scope
--> $DIR/issue-97194.rs:2:35
|
LL | fn bget(&self, index: [usize; Self::DIM]) -> bool {
| ^^^^ `Self` is only available in impls, traits, and type definitions
```
and
```
error[E0433]: cannot find `super` in this scope
--> $DIR/keyword-super.rs:2:9
|
LL | let super: isize;
| ^^^^^ there are too many leading `super` keywords
```
For these the label provides the actual help, while the message is less informative beyond telling you "couldn't find `name`".
This is an off-shoot of https://github.com/rust-lang/rust/pull/126810 and https://github.com/rust-lang/rust/pull/128086, a subset of the intended changes there with review comments applied.
r? @petrochenkov
This commit is contained in:
commit
efbc8957a6
249 changed files with 820 additions and 698 deletions
|
|
@ -469,9 +469,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
PathResult::NonModule(partial_res) => {
|
||||
expected_found_error(partial_res.expect_full_res())
|
||||
}
|
||||
PathResult::Failed { span, label, suggestion, .. } => {
|
||||
Err(VisResolutionError::FailedToResolve(span, label, suggestion))
|
||||
}
|
||||
PathResult::Failed {
|
||||
span, label, suggestion, message, segment_name, ..
|
||||
} => Err(VisResolutionError::FailedToResolve(
|
||||
span,
|
||||
segment_name,
|
||||
label,
|
||||
suggestion,
|
||||
message,
|
||||
)),
|
||||
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
|||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
|
||||
use rustc_span::{BytePos, Ident, RemapPathScopeComponents, Span, Symbol, SyntaxContext, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -899,9 +899,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
|
||||
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
|
||||
}
|
||||
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
|
||||
let mut err =
|
||||
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
|
||||
ResolutionError::FailedToResolve { segment, label, suggestion, module, message } => {
|
||||
let mut err = struct_span_code_err!(self.dcx(), span, E0433, "{message}");
|
||||
err.span_label(span, label);
|
||||
|
||||
if let Some((suggestions, msg, applicability)) = suggestion {
|
||||
|
|
@ -909,16 +908,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
err.help(msg);
|
||||
return err;
|
||||
}
|
||||
err.multipart_suggestion(msg, suggestions, applicability);
|
||||
err.multipart_suggestion_verbose(msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
if let Some(segment) = segment {
|
||||
let module = match module {
|
||||
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
|
||||
_ => CRATE_DEF_ID.to_def_id(),
|
||||
};
|
||||
self.find_cfg_stripped(&mut err, &segment, module);
|
||||
}
|
||||
let module = match module {
|
||||
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
|
||||
_ => CRATE_DEF_ID.to_def_id(),
|
||||
};
|
||||
self.find_cfg_stripped(&mut err, &segment, module);
|
||||
|
||||
err
|
||||
}
|
||||
|
|
@ -1108,10 +1105,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
VisResolutionError::AncestorOnly(span) => {
|
||||
self.dcx().create_err(errs::AncestorOnly(span))
|
||||
}
|
||||
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
|
||||
),
|
||||
VisResolutionError::FailedToResolve(span, segment, label, suggestion, message) => self
|
||||
.into_struct_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
segment,
|
||||
label,
|
||||
suggestion,
|
||||
module: None,
|
||||
message,
|
||||
},
|
||||
),
|
||||
VisResolutionError::ExpectedFound(span, path_str, res) => {
|
||||
self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
|
||||
}
|
||||
|
|
@ -2438,13 +2442,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
failed_segment_idx: usize,
|
||||
ident: Ident,
|
||||
diag_metadata: Option<&DiagMetadata<'_>>,
|
||||
) -> (String, Option<Suggestion>) {
|
||||
) -> (String, String, Option<Suggestion>) {
|
||||
let is_last = failed_segment_idx == path.len() - 1;
|
||||
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
||||
let module_res = match module {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
|
||||
_ => None,
|
||||
};
|
||||
let scope = match &path[..failed_segment_idx] {
|
||||
[.., prev] => {
|
||||
if prev.ident.name == kw::PathRoot {
|
||||
format!("the crate root")
|
||||
} else {
|
||||
format!("`{}`", prev.ident)
|
||||
}
|
||||
}
|
||||
_ => format!("this scope"),
|
||||
};
|
||||
let message = format!("cannot find `{ident}` in {scope}");
|
||||
|
||||
if module_res == self.graph_root.res() {
|
||||
let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
|
||||
let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
|
||||
|
|
@ -2462,6 +2478,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
Path { segments, span: Span::default(), tokens: None }
|
||||
};
|
||||
(
|
||||
message,
|
||||
String::from("unresolved import"),
|
||||
Some((
|
||||
vec![(ident.span, pprust::path_to_string(&path))],
|
||||
|
|
@ -2471,6 +2488,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
)
|
||||
} else if ident.name == sym::core {
|
||||
(
|
||||
message,
|
||||
format!("you might be missing crate `{ident}`"),
|
||||
Some((
|
||||
vec![(ident.span, "std".to_string())],
|
||||
|
|
@ -2479,9 +2497,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
)),
|
||||
)
|
||||
} else if ident.name == kw::Underscore {
|
||||
(format!("`_` is not a valid crate or module name"), None)
|
||||
(
|
||||
"invalid crate or module name `_`".to_string(),
|
||||
"`_` is not a valid crate or module name".to_string(),
|
||||
None,
|
||||
)
|
||||
} else if self.tcx.sess.is_rust_2015() {
|
||||
(
|
||||
format!("cannot find module or crate `{ident}` in {scope}"),
|
||||
format!("use of unresolved module or unlinked crate `{ident}`"),
|
||||
Some((
|
||||
vec![(
|
||||
|
|
@ -2490,8 +2513,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
)],
|
||||
if was_invoked_from_cargo() {
|
||||
format!(
|
||||
"if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
|
||||
to add it to your `Cargo.toml` and import it in your code",
|
||||
"if you wanted to use a crate named `{ident}`, use `cargo add \
|
||||
{ident}` to add it to your `Cargo.toml` and import it in your \
|
||||
code",
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
|
|
@ -2503,7 +2527,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
)),
|
||||
)
|
||||
} else {
|
||||
(format!("could not find `{ident}` in the crate root"), None)
|
||||
(message, format!("could not find `{ident}` in the crate root"), None)
|
||||
}
|
||||
} else if failed_segment_idx > 0 {
|
||||
let parent = path[failed_segment_idx - 1].ident.name;
|
||||
|
|
@ -2569,15 +2593,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
);
|
||||
};
|
||||
}
|
||||
(msg, None)
|
||||
(message, msg, None)
|
||||
} else if ident.name == kw::SelfUpper {
|
||||
// As mentioned above, `opt_ns` being `None` indicates a module path in import.
|
||||
// We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
|
||||
// impl
|
||||
if opt_ns.is_none() {
|
||||
("`Self` cannot be used in imports".to_string(), None)
|
||||
(message, "`Self` cannot be used in imports".to_string(), None)
|
||||
} else {
|
||||
(
|
||||
message,
|
||||
"`Self` is only available in impls, traits, and type definitions".to_string(),
|
||||
None,
|
||||
)
|
||||
|
|
@ -2608,12 +2633,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// }
|
||||
// ```
|
||||
Some(LateDecl::RibDef(Res::Local(id))) => {
|
||||
Some(*self.pat_span_map.get(&id).unwrap())
|
||||
Some((*self.pat_span_map.get(&id).unwrap(), "a", "local binding"))
|
||||
}
|
||||
// Name matches item from a local name binding
|
||||
// created by `use` declaration. For example:
|
||||
// ```
|
||||
// pub Foo: &str = "";
|
||||
// pub const Foo: &str = "";
|
||||
//
|
||||
// mod submod {
|
||||
// use super::Foo;
|
||||
|
|
@ -2621,18 +2646,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// // binding `Foo`.
|
||||
// }
|
||||
// ```
|
||||
Some(LateDecl::Decl(name_binding)) => Some(name_binding.span),
|
||||
Some(LateDecl::Decl(name_binding)) => Some((
|
||||
name_binding.span,
|
||||
name_binding.res().article(),
|
||||
name_binding.res().descr(),
|
||||
)),
|
||||
_ => None,
|
||||
};
|
||||
let suggestion = match_span.map(|span| {
|
||||
(
|
||||
vec![(span, String::from(""))],
|
||||
format!("`{ident}` is defined here, but is not a type"),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
});
|
||||
|
||||
(format!("use of undeclared type `{ident}`"), suggestion)
|
||||
let message = format!("cannot find type `{ident}` in {scope}");
|
||||
let label = if let Some((span, article, descr)) = match_span {
|
||||
format!(
|
||||
"`{ident}` is declared as {article} {descr} at `{}`, not a type",
|
||||
self.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_short_string(span, RemapPathScopeComponents::DIAGNOSTICS)
|
||||
)
|
||||
} else {
|
||||
format!("use of undeclared type `{ident}`")
|
||||
};
|
||||
(message, label, None)
|
||||
} else {
|
||||
let mut suggestion = None;
|
||||
if ident.name == sym::alloc {
|
||||
|
|
@ -2663,7 +2697,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ignore_import,
|
||||
) {
|
||||
let descr = binding.res().descr();
|
||||
(format!("{descr} `{ident}` is not a crate or module"), suggestion)
|
||||
let message = format!("cannot find module or crate `{ident}` in {scope}");
|
||||
(message, format!("{descr} `{ident}` is not a crate or module"), suggestion)
|
||||
} else {
|
||||
let suggestion = if suggestion.is_some() {
|
||||
suggestion
|
||||
|
|
@ -2685,7 +2720,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
))
|
||||
};
|
||||
(format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
|
||||
let message = format!("cannot find module or crate `{ident}` in {scope}");
|
||||
(
|
||||
message,
|
||||
format!("use of unresolved module or unlinked crate `{ident}`"),
|
||||
suggestion,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1775,7 +1775,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| ("there are too many leading `super` keywords".to_string(), None),
|
||||
|| {
|
||||
(
|
||||
"too many leading `super` keywords".to_string(),
|
||||
"there are too many leading `super` keywords".to_string(),
|
||||
None,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
if segment_idx == 0 {
|
||||
|
|
@ -1823,16 +1829,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
module,
|
||||
|| {
|
||||
let name_str = if name == kw::PathRoot {
|
||||
"crate root".to_string()
|
||||
"the crate root".to_string()
|
||||
} else {
|
||||
format!("`{name}`")
|
||||
};
|
||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
||||
format!("global paths cannot start with {name_str}")
|
||||
let (message, label) = if segment_idx == 1
|
||||
&& path[0].ident.name == kw::PathRoot
|
||||
{
|
||||
(
|
||||
format!("global paths cannot start with {name_str}"),
|
||||
"cannot start with this".to_string(),
|
||||
)
|
||||
} else {
|
||||
format!("{name_str} in paths can only be used in start position")
|
||||
(
|
||||
format!("{name_str} in paths can only be used in start position"),
|
||||
"can only be used in path start position".to_string(),
|
||||
)
|
||||
};
|
||||
(label, None)
|
||||
(message, label, None)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1948,7 +1962,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
res.article(),
|
||||
res.descr()
|
||||
);
|
||||
(label, None)
|
||||
let scope = match &path[..segment_idx] {
|
||||
[.., prev] => {
|
||||
if prev.ident.name == kw::PathRoot {
|
||||
format!("the crate root")
|
||||
} else {
|
||||
format!("`{}`", prev.ident)
|
||||
}
|
||||
}
|
||||
_ => format!("this scope"),
|
||||
};
|
||||
// FIXME: reword, as the reason we expected a module is because of
|
||||
// the following path segment.
|
||||
let message = format!("cannot find module `{ident}` in {scope}");
|
||||
(message, label, None)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1042,16 +1042,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
suggestion,
|
||||
module,
|
||||
error_implied_by_parse_error: _,
|
||||
message,
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
segment: Some(segment_name),
|
||||
segment: segment_name,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
message,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4890,14 +4890,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
module,
|
||||
segment_name,
|
||||
error_implied_by_parse_error: _,
|
||||
message,
|
||||
} => {
|
||||
return Err(respan(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
segment: Some(segment_name),
|
||||
segment: segment_name,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
message,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,10 +280,11 @@ enum ResolutionError<'ra> {
|
|||
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
||||
/// Error E0433: failed to resolve.
|
||||
FailedToResolve {
|
||||
segment: Option<Symbol>,
|
||||
segment: Symbol,
|
||||
label: String,
|
||||
suggestion: Option<Suggestion>,
|
||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
message: String,
|
||||
},
|
||||
/// Error E0434: can't capture dynamic environment in a fn item.
|
||||
CannotCaptureDynamicEnvironmentInFnItem,
|
||||
|
|
@ -342,7 +343,7 @@ enum ResolutionError<'ra> {
|
|||
enum VisResolutionError<'a> {
|
||||
Relative2018(Span, &'a ast::Path),
|
||||
AncestorOnly(Span),
|
||||
FailedToResolve(Span, String, Option<Suggestion>),
|
||||
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
|
||||
ExpectedFound(Span, String, Res),
|
||||
Indeterminate(Span),
|
||||
ModuleOnly(Span),
|
||||
|
|
@ -486,6 +487,7 @@ enum PathResult<'ra> {
|
|||
/// The segment name of target
|
||||
segment_name: Symbol,
|
||||
error_implied_by_parse_error: bool,
|
||||
message: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -496,10 +498,14 @@ impl<'ra> PathResult<'ra> {
|
|||
finalize: bool,
|
||||
error_implied_by_parse_error: bool,
|
||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||||
label_and_suggestion: impl FnOnce() -> (String, String, Option<Suggestion>),
|
||||
) -> PathResult<'ra> {
|
||||
let (label, suggestion) =
|
||||
if finalize { label_and_suggestion() } else { (String::new(), None) };
|
||||
let (message, label, suggestion) = if finalize {
|
||||
label_and_suggestion()
|
||||
} else {
|
||||
// FIXME: this output isn't actually present in the test suite.
|
||||
(format!("cannot find `{ident}` in this scope"), String::new(), None)
|
||||
};
|
||||
PathResult::Failed {
|
||||
span: ident.span,
|
||||
segment_name: ident.name,
|
||||
|
|
@ -508,6 +514,7 @@ impl<'ra> PathResult<'ra> {
|
|||
is_error_from_last_segment,
|
||||
module,
|
||||
error_implied_by_parse_error,
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -908,10 +908,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
),
|
||||
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
|
||||
let mut suggestion = None;
|
||||
let (span, label, module, segment) =
|
||||
if let PathResult::Failed { span, label, module, segment_name, .. } =
|
||||
path_res
|
||||
{
|
||||
let (span, message, label, module, segment) = match path_res {
|
||||
PathResult::Failed {
|
||||
span, label, module, segment_name, message, ..
|
||||
} => {
|
||||
// try to suggest if it's not a macro, maybe a function
|
||||
if let PathResult::NonModule(partial_res) = self
|
||||
.cm()
|
||||
|
|
@ -930,26 +930,52 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
));
|
||||
}
|
||||
(span, label, module, segment_name)
|
||||
} else {
|
||||
(span, message, label, module, segment_name)
|
||||
}
|
||||
PathResult::NonModule(partial_res) => {
|
||||
let found_an = partial_res.base_res().article();
|
||||
let found_descr = partial_res.base_res().descr();
|
||||
let scope = match &path[..partial_res.unresolved_segments()] {
|
||||
[.., prev] => {
|
||||
format!("{found_descr} `{}`", prev.ident)
|
||||
}
|
||||
_ => found_descr.to_string(),
|
||||
};
|
||||
let expected_an = kind.article();
|
||||
let expected_descr = kind.descr();
|
||||
let expected_name = path[partial_res.unresolved_segments()].ident;
|
||||
|
||||
(
|
||||
path_span,
|
||||
format!(
|
||||
"partially resolved path in {} {}",
|
||||
kind.article(),
|
||||
kind.descr()
|
||||
"cannot find {expected_descr} `{expected_name}` in {scope}"
|
||||
),
|
||||
match partial_res.base_res() {
|
||||
Res::Def(
|
||||
DefKind::Mod | DefKind::Macro(..) | DefKind::ExternCrate,
|
||||
_,
|
||||
) => format!(
|
||||
"partially resolved path in {expected_an} {expected_descr}",
|
||||
),
|
||||
_ => format!(
|
||||
"{expected_an} {expected_descr} can't exist within \
|
||||
{found_an} {found_descr}"
|
||||
),
|
||||
},
|
||||
None,
|
||||
path.last().map(|segment| segment.ident.name).unwrap(),
|
||||
)
|
||||
};
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
segment: Some(segment),
|
||||
segment,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
message,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue