Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}
Expand Down
112 changes: 76 additions & 36 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -899,26 +899,23 @@ 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 {
if suggestions.is_empty() {
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
}
Expand Down Expand Up @@ -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 })
}
Expand Down Expand Up @@ -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);
Expand All @@ -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))],
Expand All @@ -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())],
Expand All @@ -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![(
Expand All @@ -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!(
Expand All @@ -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;
Expand Down Expand Up @@ -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,
)
Expand Down Expand Up @@ -2608,31 +2633,40 @@ 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;
// println!("{}", Foo::Bar); // Name refers to local
// // 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 {
Expand Down Expand Up @@ -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
Expand All @@ -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,
)
}
}
}
Expand Down
41 changes: 34 additions & 7 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
},
);
}
Expand Down Expand Up @@ -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)
},
);
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
);
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
));
}
Expand Down
Loading
Loading