summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/diagnostics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src/diagnostics.rs')
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs147
1 files changed, 87 insertions, 60 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d3dcdfa42..cd1a9b934 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -5,10 +5,8 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{
- pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
-};
-use rustc_errors::{struct_span_err, SuggestionStyle};
+use rustc_errors::{pluralize, report_ambiguity_error, struct_span_err, SuggestionStyle};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
@@ -17,8 +15,9 @@ use rustc_hir::PrimTy;
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
+use rustc_session::lint::builtin::AMBIGUOUS_GLOB_IMPORTS;
use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
-use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiagnostics};
use rustc_session::Session;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
@@ -135,7 +134,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
for ambiguity_error in &self.ambiguity_errors {
- self.report_ambiguity_error(ambiguity_error);
+ let diag = self.ambiguity_diagnostics(ambiguity_error);
+ if ambiguity_error.warning {
+ let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
+ unreachable!()
+ };
+ self.lint_buffer.buffer_lint_with_diagnostic(
+ AMBIGUOUS_GLOB_IMPORTS,
+ import.root_id,
+ ambiguity_error.ident.span,
+ diag.msg.to_string(),
+ BuiltinLintDiagnostics::AmbiguousGlobImports { diag },
+ );
+ } else {
+ let mut err = struct_span_err!(self.tcx.sess, diag.span, E0659, "{}", &diag.msg);
+ report_ambiguity_error(&mut err, diag);
+ err.emit();
+ }
}
let mut reported_spans = FxHashSet::default();
@@ -228,7 +243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
(TypeNS, _) => "type",
};
- let msg = format!("the name `{}` is defined multiple times", name);
+ let msg = format!("the name `{name}` is defined multiple times");
let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
(true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg),
@@ -250,11 +265,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
container
));
- err.span_label(span, format!("`{}` re{} here", name, new_participle));
+ err.span_label(span, format!("`{name}` re{new_participle} here"));
if !old_binding.span.is_dummy() && old_binding.span != span {
err.span_label(
self.tcx.sess.source_map().guess_head_span(old_binding.span),
- format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+ format!("previous {old_noun} of the {old_kind} `{name}` here"),
);
}
@@ -343,15 +358,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
binding_span: Span,
) {
let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
- format!("Other{}", name)
+ format!("Other{name}")
} else {
- format!("other_{}", name)
+ format!("other_{name}")
};
let mut suggestion = None;
match import.kind {
ImportKind::Single { type_ns_only: true, .. } => {
- suggestion = Some(format!("self as {}", suggested_name))
+ suggestion = Some(format!("self as {suggested_name}"))
}
ImportKind::Single { source, .. } => {
if let Some(pos) =
@@ -587,11 +602,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let sugg_msg = "try using a local generic parameter instead";
let name = self.tcx.item_name(def_id);
let (span, snippet) = if span.is_empty() {
- let snippet = format!("<{}>", name);
+ let snippet = format!("<{name}>");
(span, snippet)
} else {
let span = sm.span_through_char(span, '<').shrink_to_hi();
- let snippet = format!("{}, ", name);
+ let snippet = format!("{name}, ");
(span, snippet)
};
// Suggest the modification to the user
@@ -652,7 +667,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
name,
);
for sp in target_sp {
- err.span_label(sp, format!("pattern doesn't bind `{}`", name));
+ err.span_label(sp, format!("pattern doesn't bind `{name}`"));
}
for sp in origin_sp {
err.span_label(sp, "variable not in all patterns");
@@ -679,8 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if import_suggestions.is_empty() {
let help_msg = format!(
"if you meant to match on a variant or a `const` item, consider \
- making the path in the pattern qualified: `path::to::ModOrType::{}`",
- name,
+ making the path in the pattern qualified: `path::to::ModOrType::{name}`",
);
err.span_help(span, help_msg);
}
@@ -938,8 +952,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut err = self.tcx.sess.struct_span_err_with_code(
span,
format!(
- "item `{}` is an associated {}, which doesn't match its trait `{}`",
- name, kind, trait_path,
+ "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
),
code,
);
@@ -1203,7 +1216,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if filter_fn(res) {
// create the path
let mut segms = path_segments.clone();
- if lookup_ident.span.rust_2018() {
+ if lookup_ident.span.at_least_rust_2018() {
// crate-local absolute paths start with `crate::` in edition 2018
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
segms.insert(0, ast::PathSegment::from_ident(crate_name));
@@ -1268,7 +1281,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path_segments.push(ast::PathSegment::from_ident(ident));
let is_extern_crate_that_also_appears_in_prelude =
- name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
+ name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
if !is_extern_crate_that_also_appears_in_prelude {
// add the module to the lookup
@@ -1315,7 +1328,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&filter_fn,
);
- if lookup_ident.span.rust_2018() {
+ if lookup_ident.span.at_least_rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
for (ident, _) in extern_prelude_names.into_iter() {
if ident.span.from_expansion() {
@@ -1395,7 +1408,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let head_span = source_map.guess_head_span(span);
err.subdiagnostic(ConsiderAddingADerive {
span: head_span.shrink_to_lo(),
- suggestion: format!("#[derive(Default)]\n")
+ suggestion: "#[derive(Default)]\n".to_string(),
});
}
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
@@ -1412,10 +1425,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
"a function-like macro".to_string()
}
Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
- format!("an attribute: `#[{}]`", ident)
+ format!("an attribute: `#[{ident}]`")
}
Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
- format!("a derive macro: `#[derive({})]`", ident)
+ format!("a derive macro: `#[derive({ident})]`")
}
Res::ToolMod => {
// Don't confuse the user with tool modules.
@@ -1436,7 +1449,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if !import.span.is_dummy() {
err.span_note(
import.span,
- format!("`{}` is imported here, but it is {}", ident, desc),
+ format!("`{ident}` is imported here, but it is {desc}"),
);
// Silence the 'unused import' warning we might get,
// since this diagnostic already covers that import.
@@ -1444,7 +1457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return;
}
}
- err.note(format!("`{}` is in scope, but it is {}", ident, desc));
+ err.note(format!("`{ident}` is in scope, but it is {desc}"));
return;
}
}
@@ -1540,20 +1553,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
- fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
- let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
+ fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
+ let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
// We have to print the span-less alternative first, otherwise formatting looks bad.
(b2, b1, misc2, misc1, true)
} else {
(b1, b2, misc1, misc2, false)
};
-
- let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous");
- err.span_label(ident.span, "ambiguous name");
- err.note(format!("ambiguous because of {}", kind.descr()));
-
- let mut could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
+ let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
let note_msg = format!("`{ident}` could{also} refer to {what}");
@@ -1568,7 +1576,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
"consider adding an explicit import of `{ident}` to disambiguate"
))
}
- if b.is_extern_crate() && ident.span.rust_2018() {
+ if b.is_extern_crate() && ident.span.at_least_rust_2018() {
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
}
match misc {
@@ -1579,16 +1587,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
}
- err.span_note(b.span, note_msg);
- for (i, help_msg) in help_msgs.iter().enumerate() {
- let or = if i == 0 { "" } else { "or " };
- err.help(format!("{}{}", or, help_msg));
- }
+ (
+ b.span,
+ note_msg,
+ help_msgs
+ .iter()
+ .enumerate()
+ .map(|(i, help_msg)| {
+ let or = if i == 0 { "" } else { "or " };
+ format!("{or}{help_msg}")
+ })
+ .collect::<Vec<_>>(),
+ )
};
-
- could_refer_to(b1, misc1, "");
- could_refer_to(b2, misc2, " also");
- err.emit();
+ let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
+ let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
+
+ AmbiguityErrorDiag {
+ msg: format!("`{ident}` is ambiguous"),
+ span: ident.span,
+ label_span: ident.span,
+ label_msg: "ambiguous name".to_string(),
+ note_msg: format!("ambiguous because of {}", kind.descr()),
+ b1_span,
+ b1_note_msg,
+ b1_help_msgs,
+ b2_span,
+ b2_note_msg,
+ b2_help_msgs,
+ }
}
/// If the binding refers to a tuple struct constructor with fields,
@@ -1626,7 +1653,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let descr = get_descr(binding);
let mut err =
struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
- err.span_label(ident.span, format!("private {}", descr));
+ err.span_label(ident.span, format!("private {descr}"));
if let Some((this_res, outer_ident)) = outermost_res {
let import_suggestions = self.lookup_import_candidates(
@@ -1718,7 +1745,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if next_binding.is_none() && let Some(span) = non_exhaustive {
note_span.push_span_label(
span,
- format!("cannot be constructed because it is `#[non_exhaustive]`"),
+ "cannot be constructed because it is `#[non_exhaustive]`",
);
}
err.span_note(note_span, msg);
@@ -1811,7 +1838,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
_ => format!("`{parent}`"),
};
- let mut msg = format!("could not find `{}` in {}", ident, parent);
+ let mut msg = format!("could not find `{ident}` in {parent}");
if ns == TypeNS || ns == ValueNS {
let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
let binding = if let Some(module) = module {
@@ -1926,12 +1953,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let suggestion = match_span.map(|span| {
(
vec![(span, String::from(""))],
- format!("`{}` is defined here, but is not a type", ident),
+ format!("`{ident}` is defined here, but is not a type"),
Applicability::MaybeIncorrect,
)
});
- (format!("use of undeclared type `{}`", ident), suggestion)
+ (format!("use of undeclared type `{ident}`"), suggestion)
} else {
let mut suggestion = None;
if ident.name == sym::alloc {
@@ -1953,7 +1980,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
},
)
});
- (format!("use of undeclared crate or module `{}`", ident), suggestion)
+ (format!("use of undeclared crate or module `{ident}`"), suggestion)
}
}
@@ -1973,7 +2000,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if fst.ident.name == kw::PathRoot && !snd.ident.is_path_segment_keyword() => {}
// `ident::...` on 2018.
(Some(fst), _)
- if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
+ if fst.ident.span.at_least_rust_2018() && !fst.ident.is_path_segment_keyword() =>
{
// Insert a placeholder that's later replaced by `self`/`super`/etc.
path.insert(0, Segment::from_ident(Ident::empty()));
@@ -2137,16 +2164,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let module_name = crate_module.kind.name().unwrap();
let import_snippet = match import.kind {
ImportKind::Single { source, target, .. } if source != target => {
- format!("{} as {}", source, target)
+ format!("{source} as {target}")
}
- _ => format!("{}", ident),
+ _ => format!("{ident}"),
};
let mut corrections: Vec<(Span, String)> = Vec::new();
if !import.is_nested() {
// Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
// intermediate segments.
- corrections.push((import.span, format!("{}::{}", module_name, import_snippet)));
+ corrections.push((import.span, format!("{module_name}::{import_snippet}")));
} else {
// Find the binding span (and any trailing commas and spaces).
// ie. `use a::b::{c, d, e};`
@@ -2213,11 +2240,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
start_point,
if has_nested {
// In this case, `start_snippet` must equal '{'.
- format!("{}{}, ", start_snippet, import_snippet)
+ format!("{start_snippet}{import_snippet}, ")
} else {
// In this case, add a `{`, then the moved import, then whatever
// was there before.
- format!("{{{}, {}", import_snippet, start_snippet)
+ format!("{{{import_snippet}, {start_snippet}")
},
));
@@ -2634,9 +2661,9 @@ fn show_candidates(
"item"
};
let plural_descr =
- if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
+ if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
- let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
+ let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
let mut has_colon = false;
let mut spans = Vec::new();
@@ -2657,7 +2684,7 @@ fn show_candidates(
let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
for (name, span) in spans {
- multi_span.push_span_label(span, format!("`{}`: not accessible", name));
+ multi_span.push_span_label(span, format!("`{name}`: not accessible"));
}
for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {