summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_resolve
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs18
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs147
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs9
-rw-r--r--compiler/rustc_resolve/src/ident.rs12
-rw-r--r--compiler/rustc_resolve/src/imports.rs197
-rw-r--r--compiler/rustc_resolve/src/late.rs296
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs257
-rw-r--r--compiler/rustc_resolve/src/lib.rs38
-rw-r--r--compiler/rustc_resolve/src/macros.rs34
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs75
11 files changed, 694 insertions, 393 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index e6ceedddf..127bec22c 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -41,6 +41,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a>
arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Module(self.0),
ambiguity: None,
+ warn_ambiguity: false,
vis: self.1.to_def_id(),
span: self.2,
expansion: self.3,
@@ -53,6 +54,7 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span,
arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Res(self.0),
ambiguity: None,
+ warn_ambiguity: false,
vis: self.1.to_def_id(),
span: self.2,
expansion: self.3,
@@ -69,7 +71,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
{
let binding = def.to_name_binding(self.arenas);
let key = self.new_disambiguated_key(ident, ns);
- if let Err(old_binding) = self.try_define(parent, key, binding) {
+ if let Err(old_binding) = self.try_define(parent, key, binding, false) {
self.report_conflict(parent, ident, ns, old_binding, binding);
}
}
@@ -169,7 +171,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return macro_data.clone();
}
- let load_macro_untracked = self.cstore().load_macro_untracked(def_id, &self.tcx.sess);
+ let load_macro_untracked = self.cstore().load_macro_untracked(def_id, self.tcx);
let (ext, macro_rules) = match load_macro_untracked {
LoadedMacro::MacroDef(item, edition) => (
Lrc::new(self.compile_macro(&item, edition).0),
@@ -276,7 +278,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
};
match self.r.resolve_path(
&segments,
- Some(TypeNS),
+ None,
parent_scope,
finalize.then(|| Finalize::new(id, path.span)),
None,
@@ -698,7 +700,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// These items live in the type namespace.
ItemKind::TyAlias(..) => {
- let res = Res::Def(DefKind::TyAlias, def_id);
+ let res = Res::Def(
+ DefKind::TyAlias { lazy: self.r.tcx.features().lazy_type_alias },
+ def_id,
+ );
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
@@ -946,10 +951,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
DefKind::Struct
| DefKind::Union
| DefKind::Variant
- | DefKind::TyAlias
+ | DefKind::TyAlias { .. }
| DefKind::ForeignTy
| DefKind::OpaqueTy
- | DefKind::ImplTraitPlaceholder
| DefKind::TraitAlias
| DefKind::AssocTy,
_,
@@ -1000,7 +1004,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
allow_shadowing: bool,
) {
if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
- let msg = format!("`{}` is already in scope", name);
+ let msg = format!("`{name}` is already in scope");
let note =
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
self.r.tcx.sess.struct_span_err(span, msg).note(note).emit();
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index dc35c8b17..7dbbd4c34 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -362,7 +362,7 @@ impl Resolver<'_, '_> {
let mut span_snippets = spans
.iter()
.filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
- Ok(s) => Some(format!("`{}`", s)),
+ Ok(s) => Some(format!("`{s}`")),
_ => None,
})
.collect::<Vec<String>>();
@@ -440,7 +440,7 @@ impl Resolver<'_, '_> {
// If we are not in Rust 2018 edition, then we don't make any further
// suggestions.
- if !tcx.sess.rust_2018() {
+ if !tcx.sess.at_least_rust_2018() {
continue;
}
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()) {
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index eb210532f..46f5df5ca 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -128,11 +128,14 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
// If the binding is ambiguous, put the root ambiguity binding and all reexports
// leading to it into the table. They are used by the `ambiguous_glob_reexports`
// lint. For all bindings added to the table this way `is_ambiguity` returns true.
+ let is_ambiguity =
+ |binding: NameBinding<'a>, warn: bool| binding.ambiguity.is_some() && !warn;
let mut parent_id = ParentId::Def(module_id);
+ let mut warn_ambiguity = binding.warn_ambiguity;
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
self.update_import(binding, parent_id);
- if binding.ambiguity.is_some() {
+ if is_ambiguity(binding, warn_ambiguity) {
// Stop at the root ambiguity, further bindings in the chain should not
// be reexported because the root ambiguity blocks any access to them.
// (Those further bindings are most likely not ambiguities themselves.)
@@ -141,9 +144,9 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
parent_id = ParentId::Import(binding);
binding = nested_binding;
+ warn_ambiguity |= nested_binding.warn_ambiguity;
}
-
- if binding.ambiguity.is_none()
+ if !is_ambiguity(binding, warn_ambiguity)
&& let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
self.update_def(def_id, binding.vis.expect_local(), parent_id);
}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 520fab1f0..3bd9cea27 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -677,6 +677,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ident: orig_ident,
b1: innermost_binding,
b2: binding,
+ warning: false,
misc1: misc(innermost_flags),
misc2: misc(flags),
});
@@ -905,6 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ident,
b1: binding,
b2: shadowed_glob,
+ warning: false,
misc1: AmbiguityErrorMisc::None,
misc2: AmbiguityErrorMisc::None,
});
@@ -1417,13 +1419,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
));
continue;
}
- if name == kw::PathRoot && ident.span.rust_2018() {
+ if name == kw::PathRoot && ident.span.at_least_rust_2018() {
module = Some(ModuleOrUniformRoot::ExternPrelude);
continue;
}
if name == kw::PathRoot
&& ident.span.is_rust_2015()
- && self.tcx.sess.rust_2018()
+ && self.tcx.sess.at_least_rust_2018()
{
// `::a::b` from 2015 macro on 2018 global edition
module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
@@ -1443,12 +1445,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let name_str = if name == kw::PathRoot {
"crate root".to_string()
} else {
- format!("`{}`", name)
+ format!("`{name}`")
};
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
- format!("global paths cannot start with {}", name_str)
+ format!("global paths cannot start with {name_str}")
} else {
- format!("{} in paths can only be used in start position", name_str)
+ format!("{name_str} in paths can only be used in start position")
};
(label, None)
});
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d37fe783b..a175d9f6c 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -284,6 +284,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
ambiguity: None,
+ warn_ambiguity: false,
span: import.span,
vis,
expansion: import.parent_scope.expansion,
@@ -291,16 +292,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
/// Define the name or return the existing binding if there is a collision.
+ /// `update` indicates if the definition is a redefinition of an existing binding.
pub(crate) fn try_define(
&mut self,
module: Module<'a>,
key: BindingKey,
binding: NameBinding<'a>,
+ warn_ambiguity: bool,
) -> Result<(), NameBinding<'a>> {
let res = binding.res();
self.check_reserved_macro_name(key.ident, res);
self.set_binding_parent_module(binding, module);
- self.update_resolution(module, key, |this, resolution| {
+ self.update_resolution(module, key, warn_ambiguity, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if res == Res::Err && old_binding.res() != Res::Err {
// Do not override real bindings with `Res::Err`s from error recovery.
@@ -308,15 +311,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
match (old_binding.is_glob_import(), binding.is_glob_import()) {
(true, true) => {
- if res != old_binding.res() {
- resolution.binding = Some(this.ambiguity(
- AmbiguityKind::GlobVsGlob,
- old_binding,
- binding,
- ));
+ // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity.
+ if !binding.is_ambiguity()
+ && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind
+ && let NameBindingKind::Import { import, .. } = binding.kind
+ && old_import == import {
+ // We should replace the `old_binding` with `binding` regardless
+ // of whether they has same resolution or not when they are
+ // imported from the same glob-import statement.
+ // However we currently using `Some(old_binding)` for back compact
+ // purposes.
+ // This case can be removed after once `Undetermined` is prepared
+ // for glob-imports.
+ } else if res != old_binding.res() {
+ let binding = if warn_ambiguity {
+ this.warn_ambiguity(
+ AmbiguityKind::GlobVsGlob,
+ old_binding,
+ binding,
+ )
+ } else {
+ this.ambiguity(
+ AmbiguityKind::GlobVsGlob,
+ old_binding,
+ binding,
+ )
+ };
+ resolution.binding = Some(binding);
} else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
// We are glob-importing the same item but with greater visibility.
resolution.binding = Some(binding);
+ } else if binding.is_ambiguity() {
+ resolution.binding =
+ Some(self.arenas.alloc_name_binding(NameBindingData {
+ warn_ambiguity: true,
+ ..(*binding).clone()
+ }));
}
}
(old_glob @ true, false) | (old_glob @ false, true) => {
@@ -374,29 +404,52 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
})
}
+ fn warn_ambiguity(
+ &self,
+ kind: AmbiguityKind,
+ primary_binding: NameBinding<'a>,
+ secondary_binding: NameBinding<'a>,
+ ) -> NameBinding<'a> {
+ self.arenas.alloc_name_binding(NameBindingData {
+ ambiguity: Some((secondary_binding, kind)),
+ warn_ambiguity: true,
+ ..(*primary_binding).clone()
+ })
+ }
+
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
- fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T
+ fn update_resolution<T, F>(
+ &mut self,
+ module: Module<'a>,
+ key: BindingKey,
+ warn_ambiguity: bool,
+ f: F,
+ ) -> T
where
F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T,
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
- let (binding, t) = {
+ let (binding, t, warn_ambiguity) = {
let resolution = &mut *self.resolution(module, key).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
- if old_binding.is_none() && let Some(binding) = resolution.binding() {
- (binding, t)
+ if let Some(binding) = resolution.binding() && old_binding != Some(binding) {
+ (binding, t, warn_ambiguity || old_binding.is_some())
} else {
return t;
}
};
- // Define `binding` in `module`s glob importers.
- for import in module.glob_importers.borrow_mut().iter() {
+ let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else {
+ return t;
+ };
+
+ // Define or update `binding` in `module`s glob importers.
+ for import in glob_importers.iter() {
let mut ident = key.ident;
let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) {
Some(Some(def)) => self.expn_def_scope(def),
@@ -406,7 +459,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, *import);
let key = BindingKey { ident, ..key };
- let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+ let _ = self.try_define(
+ import.parent_scope.module,
+ key,
+ imported_binding,
+ warn_ambiguity,
+ );
}
}
@@ -425,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let dummy_binding = self.import(dummy_binding, import);
self.per_ns(|this, ns| {
let key = BindingKey::new(target, ns);
- let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
+ let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
});
self.record_use(target, dummy_binding, false);
} else if import.imported_module.get().is_none() {
@@ -475,15 +533,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
for (is_indeterminate, import) in determined_imports
- .into_iter()
+ .iter()
.map(|i| (false, i))
- .chain(indeterminate_imports.into_iter().map(|i| (true, i)))
+ .chain(indeterminate_imports.iter().map(|i| (true, i)))
{
- let unresolved_import_error = self.finalize_import(import);
+ let unresolved_import_error = self.finalize_import(*import);
// If this import is unresolved then create a dummy import
// resolution for it so that later resolve stages won't complain.
- self.import_dummy_binding(import, is_indeterminate);
+ self.import_dummy_binding(*import, is_indeterminate);
if let Some(err) = unresolved_import_error {
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
@@ -505,27 +563,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
errors = vec![];
}
if seen_spans.insert(err.span) {
- errors.push((import, err));
+ errors.push((*import, err));
prev_root_id = import.root_id;
}
- } else if is_indeterminate {
- let path = import_path_to_string(
- &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
- &import.kind,
- import.span,
- );
- let err = UnresolvedImportError {
- span: import.span,
- label: None,
- note: None,
- suggestion: None,
- candidates: None,
- };
- // FIXME: there should be a better way of doing this than
- // formatting this as a string then checking for `::`
- if path.contains("::") {
- errors.push((import, err))
- }
+ }
+ }
+
+ if !errors.is_empty() {
+ self.throw_unresolved_import_error(errors);
+ return;
+ }
+
+ for import in &indeterminate_imports {
+ let path = import_path_to_string(
+ &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+ &import.kind,
+ import.span,
+ );
+ let err = UnresolvedImportError {
+ span: import.span,
+ label: None,
+ note: None,
+ suggestion: None,
+ candidates: None,
+ };
+ // FIXME: there should be a better way of doing this than
+ // formatting this as a string then checking for `::`
+ if path.contains("::") {
+ errors.push((*import, err))
}
}
@@ -700,7 +765,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Segment::names_to_string(&import.module_path),
module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()),
);
-
let module = if let Some(module) = import.imported_module.get() {
module
} else {
@@ -773,7 +837,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.emit();
}
let key = BindingKey::new(target, ns);
- this.update_resolution(parent, key, |_, resolution| {
+ this.update_resolution(parent, key, false, |_, resolution| {
resolution.single_imports.remove(&import);
});
}
@@ -989,14 +1053,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
initial_binding.res()
});
let res = binding.res();
+ let has_ambiguity_error = this
+ .ambiguity_errors
+ .iter()
+ .filter(|error| !error.warning)
+ .next()
+ .is_some();
+ if res == Res::Err || has_ambiguity_error {
+ this.tcx
+ .sess
+ .delay_span_bug(import.span, "some error happened for an import");
+ return;
+ }
if let Ok(initial_res) = initial_res {
- if res != initial_res && this.ambiguity_errors.is_empty() {
+ if res != initial_res {
span_bug!(import.span, "inconsistent resolution for an import");
}
- } else if res != Res::Err
- && this.ambiguity_errors.is_empty()
- && this.privacy_errors.is_empty()
- {
+ } else if this.privacy_errors.is_empty() {
this.tcx
.sess
.create_err(CannotDetermineImportResolution { span: import.span })
@@ -1087,18 +1160,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ModuleOrUniformRoot::Module(module) => {
let module_str = module_to_string(module);
if let Some(module_str) = module_str {
- format!("no `{}` in `{}`", ident, module_str)
+ format!("no `{ident}` in `{module_str}`")
} else {
- format!("no `{}` in the root", ident)
+ format!("no `{ident}` in the root")
}
}
_ => {
if !ident.is_path_segment_keyword() {
- format!("no external crate `{}`", ident)
+ 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)
+ format!("no `{ident}` in the root")
}
}
};
@@ -1146,10 +1219,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let (ns, binding) = reexport_error.unwrap();
if pub_use_of_private_extern_crate_hack(import, binding) {
let msg = format!(
- "extern crate `{}` is private, and cannot be \
+ "extern crate `{ident}` is private, and cannot be \
re-exported (error E0365), consider declaring with \
- `pub`",
- ident
+ `pub`"
);
self.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
@@ -1289,7 +1361,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
UNUSED_IMPORTS,
id,
import.span,
- format!("the item `{}` is imported redundantly", ident),
+ format!("the item `{ident}` is imported redundantly"),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
);
}
@@ -1300,9 +1372,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
- self.tcx.sess.create_err(CannotGlobImportAllCrates {
- span: import.span,
- }).emit();
+ self.tcx.sess.create_err(CannotGlobImportAllCrates { span: import.span }).emit();
return;
};
@@ -1337,7 +1407,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, import);
- let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+ let warn_ambiguity = self
+ .resolution(import.parent_scope.module, key)
+ .borrow()
+ .binding()
+ .is_some_and(|binding| binding.is_warn_ambiguity());
+ let _ = self.try_define(
+ import.parent_scope.module,
+ key,
+ imported_binding,
+ warn_ambiguity,
+ );
}
}
@@ -1356,7 +1436,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
module.for_each_child(self, |this, ident, _, binding| {
let res = binding.res().expect_non_local();
- if res != def::Res::Err && !binding.is_ambiguity() {
+ let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity;
+ if res != def::Res::Err && !error_ambiguity {
let mut reexport_chain = SmallVec::new();
let mut next_binding = binding;
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 90cb312ed..c87db96a5 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -337,6 +337,7 @@ enum LifetimeBinderKind {
PolyTrait,
WhereBound,
Item,
+ ConstItem,
Function,
Closure,
ImplBlock,
@@ -349,7 +350,7 @@ impl LifetimeBinderKind {
BareFnType => "type",
PolyTrait => "bound",
WhereBound => "bound",
- Item => "item",
+ Item | ConstItem => "item",
ImplBlock => "impl block",
Function => "function",
Closure => "closure",
@@ -469,7 +470,7 @@ impl<'a> PathSource<'a> {
| DefKind::Enum
| DefKind::Trait
| DefKind::TraitAlias
- | DefKind::TyAlias
+ | DefKind::TyAlias { .. }
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::OpaqueTy
@@ -508,7 +509,7 @@ impl<'a> PathSource<'a> {
DefKind::Struct
| DefKind::Union
| DefKind::Variant
- | DefKind::TyAlias
+ | DefKind::TyAlias { .. }
| DefKind::AssocTy,
_,
) | Res::SelfTyParam { .. }
@@ -549,6 +550,7 @@ enum MaybeExported<'a> {
Ok(NodeId),
Impl(Option<DefId>),
ImplItem(Result<DefId, &'a Visibility>),
+ NestedUse(&'a Visibility),
}
impl MaybeExported<'_> {
@@ -559,7 +561,9 @@ impl MaybeExported<'_> {
trait_def_id.as_local()
}
MaybeExported::Impl(None) => return true,
- MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(),
+ MaybeExported::ImplItem(Err(vis)) | MaybeExported::NestedUse(vis) => {
+ return vis.kind.is_pub();
+ }
};
def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
}
@@ -900,9 +904,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
&sig.decl.output,
);
+
+ if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() {
+ this.record_lifetime_params_for_impl_trait(async_node_id, span);
+ }
},
);
- self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id());
return;
}
FnKind::Fn(..) => {
@@ -938,12 +945,14 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
.iter()
.map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
&declaration.output,
- )
+ );
+
+ if let Some((async_node_id, span)) = async_node_id {
+ this.record_lifetime_params_for_impl_trait(async_node_id, span);
+ }
},
);
- this.record_lifetime_params_for_async(fn_id, async_node_id);
-
if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
@@ -1361,7 +1370,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) {
// For type parameter defaults, we have to ban access
- // to following type parameters, as the InternalSubsts can only
+ // to following type parameters, as the GenericArgs can only
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
@@ -1690,6 +1699,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Leave the responsibility to create the `LocalDefId` to lowering.
let param = self.r.next_node_id();
let res = LifetimeRes::Fresh { param, binder };
+ self.record_lifetime_param(param, res);
// Record the created lifetime parameter so lowering can pick it up and add it to HIR.
self.r
@@ -1730,7 +1740,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
Res::Def(DefKind::Struct, def_id)
| Res::Def(DefKind::Union, def_id)
| Res::Def(DefKind::Enum, def_id)
- | Res::Def(DefKind::TyAlias, def_id)
+ | Res::Def(DefKind::TyAlias { .. }, def_id)
| Res::Def(DefKind::Trait, def_id)
if i + 1 == proj_start =>
{
@@ -1913,10 +1923,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
candidate: LifetimeElisionCandidate,
) {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
- panic!(
- "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
- id, prev_res, res
- )
+ panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
}
match res {
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
@@ -1932,8 +1939,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
panic!(
- "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
- id, prev_res, res
+ "lifetime parameter {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)"
)
}
}
@@ -2284,7 +2290,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
fn resolve_item(&mut self, item: &'ast Item) {
let mod_inner_docs =
matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs);
- if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) {
+ if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..) | ItemKind::Use(..)) {
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
}
@@ -2401,33 +2407,53 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
});
}
- ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. })
- | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => {
+ ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
self.with_static_rib(|this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
});
- this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+ if let Some(expr) = expr {
+ // We already forbid generic params because of the above item rib,
+ // so it doesn't matter whether this is a trivial constant.
+ this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static)));
+ }
+ });
+ }
+
+ ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
+ self.with_generic_param_rib(
+ &generics.params,
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
+ LifetimeRibKind::Generics {
+ binder: item.id,
+ kind: LifetimeBinderKind::ConstItem,
+ span: generics.span,
+ },
+ |this| {
+ this.visit_generics(generics);
+
+ this.with_lifetime_rib(
+ LifetimeRibKind::Elided(LifetimeRes::Static),
+ |this| this.visit_ty(ty),
+ );
+
if let Some(expr) = expr {
- let constant_item_kind = match item.kind {
- ItemKind::Const(..) => ConstantItemKind::Const,
- ItemKind::Static(..) => ConstantItemKind::Static,
- _ => unreachable!(),
- };
- // We already forbid generic params because of the above item rib,
- // so it doesn't matter whether this is a trivial constant.
- this.with_constant_rib(
- IsRepeatExpr::No,
- ConstantHasGenerics::Yes,
- Some((item.ident, constant_item_kind)),
- |this| this.visit_expr(expr),
+ this.resolve_const_body(
+ expr,
+ Some((item.ident, ConstantItemKind::Const)),
);
}
- });
- });
+ },
+ );
}
ItemKind::Use(ref use_tree) => {
+ let maybe_exported = match use_tree.kind {
+ UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id),
+ UseTreeKind::Nested(_) => MaybeExported::NestedUse(&item.vis),
+ };
+ self.resolve_doc_links(&item.attrs, maybe_exported);
+
self.future_proof_import(use_tree);
}
@@ -2460,8 +2486,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
F: FnOnce(&mut Self),
{
debug!("with_generic_param_rib");
- let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. }
- = lifetime_kind else { panic!() };
+ let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. } =
+ lifetime_kind
+ else {
+ panic!()
+ };
let mut function_type_rib = Rib::new(kind);
let mut function_value_rib = Rib::new(kind);
@@ -2566,7 +2595,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let res = match kind {
RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
RibKind::Normal => {
- if self.r.tcx.sess.features_untracked().non_lifetime_binders {
+ if self.r.tcx.features().non_lifetime_binders {
Res::Def(def_kind, def_id.to_def_id())
} else {
Res::Err
@@ -2688,28 +2717,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
for item in trait_items {
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
match &item.kind {
- AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
- self.visit_ty(ty);
- // Only impose the restrictions of `ConstRibKind` for an
- // actual constant expression in a provided default.
- if let Some(expr) = expr {
- // We allow arbitrary const expressions inside of associated consts,
- // even if they are potentially not const evaluatable.
- //
- // Type parameters can already be used and as associated consts are
- // not used as part of the type system, this is far less surprising.
- self.with_lifetime_rib(
- LifetimeRibKind::Elided(LifetimeRes::Infer),
- |this| {
- this.with_constant_rib(
- IsRepeatExpr::No,
- ConstantHasGenerics::Yes,
- None,
- |this| this.visit_expr(expr),
- )
- },
- );
- }
+ AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
+ self.with_generic_param_rib(
+ &generics.params,
+ RibKind::AssocItem,
+ LifetimeRibKind::Generics {
+ binder: item.id,
+ span: generics.span,
+ kind: LifetimeBinderKind::ConstItem,
+ },
+ |this| {
+ this.visit_generics(generics);
+ this.visit_ty(ty);
+
+ // Only impose the restrictions of `ConstRibKind` for an
+ // actual constant expression in a provided default.
+ if let Some(expr) = expr {
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.resolve_const_body(expr, None);
+ }
+ },
+ );
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
@@ -2864,36 +2896,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
use crate::ResolutionError::*;
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
match &item.kind {
- AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
+ AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
debug!("resolve_implementation AssocItemKind::Const");
- // If this is a trait impl, ensure the const
- // exists in trait
- self.check_trait_item(
- item.id,
- item.ident,
- &item.kind,
- ValueNS,
- item.span,
- seen_trait_items,
- |i, s, c| ConstNotMemberOfTrait(i, s, c),
- );
- self.visit_ty(ty);
- if let Some(expr) = expr {
- // We allow arbitrary const expressions inside of associated consts,
- // even if they are potentially not const evaluatable.
- //
- // Type parameters can already be used and as associated consts are
- // not used as part of the type system, this is far less surprising.
- self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
- this.with_constant_rib(
- IsRepeatExpr::No,
- ConstantHasGenerics::Yes,
- None,
- |this| this.visit_expr(expr),
- )
- });
- }
+ self.with_generic_param_rib(
+ &generics.params,
+ RibKind::AssocItem,
+ LifetimeRibKind::Generics {
+ binder: item.id,
+ span: generics.span,
+ kind: LifetimeBinderKind::ConstItem,
+ },
+ |this| {
+ // If this is a trait impl, ensure the const
+ // exists in trait
+ this.check_trait_item(
+ item.id,
+ item.ident,
+ &item.kind,
+ ValueNS,
+ item.span,
+ seen_trait_items,
+ |i, s, c| ConstNotMemberOfTrait(i, s, c),
+ );
+
+ this.visit_generics(generics);
+ this.visit_ty(ty);
+ if let Some(expr) = expr {
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.resolve_const_body(expr, None);
+ }
+ },
+ );
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
@@ -2972,7 +3010,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
{
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
- let Some((module, _)) = self.current_trait_ref else { return; };
+ let Some((module, _)) = self.current_trait_ref else {
+ return;
+ };
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
let key = BindingKey::new(ident, ns);
let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
@@ -3049,6 +3089,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
);
}
+ fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
+ self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+ this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
+ this.visit_expr(expr)
+ });
+ })
+ }
+
fn resolve_params(&mut self, params: &'ast [Param]) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
@@ -3503,7 +3551,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let report_errors = |this: &mut Self, res: Option<Res>| {
if this.should_report_errs() {
let (err, candidates) =
- this.smart_resolve_report_errors(path, path, path_span, source, res);
+ this.smart_resolve_report_errors(path, None, path_span, source, res);
let def_id = this.parent_scope.module.nearest_parent_mod();
let instead = res.is_some();
@@ -3555,14 +3603,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically:
// we're transforming `HashMap::new` into just `HashMap`.
- let prefix_path = match path.split_last() {
- Some((_, path)) if !path.is_empty() => path,
+ let (following_seg, prefix_path) = match path.split_last() {
+ Some((last, path)) if !path.is_empty() => (Some(last), path),
_ => return Some(parent_err),
};
let (mut err, candidates) = this.smart_resolve_report_errors(
prefix_path,
- path,
+ following_seg,
path_span,
PathSource::Type,
None,
@@ -3902,12 +3950,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if path.len() > 1
&& let Some(res) = result.full_res()
+ && let Some((&last_segment, prev_segs)) = path.split_last()
+ && prev_segs.iter().all(|seg| !seg.has_generic_args)
&& res != Res::Err
&& path[0].ident.name != kw::PathRoot
&& path[0].ident.name != kw::DollarCrate
{
let unqualified_result = {
- match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
+ match self.resolve_path(&[last_segment], Some(ns), None) {
PathResult::NonModule(path_res) => path_res.expect_full_res(),
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
module.res().unwrap()
@@ -3917,11 +3967,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
};
if res == unqualified_result {
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
- self.r.lint_buffer.buffer_lint(
+ self.r.lint_buffer.buffer_lint_with_diagnostic(
lint,
finalize.node_id,
finalize.path_span,
"unnecessary qualification",
+ lint::BuiltinLintDiagnostics::UnusedQualifications {
+ removal_span: finalize.path_span.until(last_segment.ident.span),
+ }
)
}
}
@@ -4223,7 +4276,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ExprKind::ConstBlock(ref ct) => {
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
}
- ExprKind::Index(ref elem, ref idx) => {
+ ExprKind::Index(ref elem, ref idx, _) => {
self.resolve_expr(elem, Some(expr));
self.visit_expr(idx);
}
@@ -4279,39 +4332,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
)
}
- /// Construct the list of in-scope lifetime parameters for async lowering.
+ /// Construct the list of in-scope lifetime parameters for impl trait lowering.
/// We include all lifetime parameters, either named or "Fresh".
/// The order of those parameters does not matter, as long as it is
/// deterministic.
- fn record_lifetime_params_for_async(
- &mut self,
- fn_id: NodeId,
- async_node_id: Option<(NodeId, Span)>,
- ) {
- if let Some((async_node_id, span)) = async_node_id {
- let mut extra_lifetime_params =
- self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
- for rib in self.lifetime_ribs.iter().rev() {
- extra_lifetime_params.extend(
- rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)),
- );
- match rib.kind {
- LifetimeRibKind::Item => break,
- LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
- if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
- extra_lifetime_params.extend(earlier_fresh);
- }
- }
- LifetimeRibKind::Generics { .. } => {}
- _ => {
- // We are in a function definition. We should only find `Generics`
- // and `AnonymousCreateParameter` inside the innermost `Item`.
- span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+ fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) {
+ let mut extra_lifetime_params = vec![];
+
+ for rib in self.lifetime_ribs.iter().rev() {
+ extra_lifetime_params
+ .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)));
+ match rib.kind {
+ LifetimeRibKind::Item => break,
+ LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+ if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
+ extra_lifetime_params.extend(earlier_fresh);
}
}
+ LifetimeRibKind::Generics { .. } => {}
+ _ => {
+ // We are in a function definition. We should only find `Generics`
+ // and `AnonymousCreateParameter` inside the innermost `Item`.
+ span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+ }
}
- self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
}
+ self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
}
fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> {
@@ -4328,7 +4374,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(res) = res
&& let Some(def_id) = res.opt_def_id()
&& !def_id.is_local()
- && self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
+ && self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
&& matches!(self.r.tcx.sess.opts.resolve_doc_links, ResolveDocLinks::ExportedMetadata) {
// Encoding foreign def ids in proc macro crate metadata will ICE.
return None;
@@ -4343,7 +4389,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match self.r.tcx.sess.opts.resolve_doc_links {
ResolveDocLinks::None => return,
ResolveDocLinks::ExportedMetadata
- if !self.r.tcx.sess.crate_types().iter().copied().any(CrateType::has_metadata)
+ if !self.r.tcx.crate_types().iter().copied().any(CrateType::has_metadata)
|| !maybe_exported.eval(self.r) =>
{
return;
@@ -4402,7 +4448,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
.into_iter()
.filter_map(|tr| {
if !tr.def_id.is_local()
- && self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
+ && self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
&& matches!(
self.r.tcx.sess.opts.resolve_doc_links,
ResolveDocLinks::ExportedMetadata
@@ -4430,6 +4476,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
fn visit_item(&mut self, item: &'ast Item) {
match &item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
+ | ItemKind::Const(box ConstItem { ref generics, .. })
| ItemKind::Fn(box Fn { ref generics, .. })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
@@ -4449,7 +4496,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::Static(..)
- | ItemKind::Const(..)
| ItemKind::Use(..)
| ItemKind::ExternCrate(..)
| ItemKind::MacroDef(..)
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c0e3f1aaf..c34b7df9b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -332,15 +332,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
pub(crate) fn smart_resolve_partial_mod_path_errors(
&mut self,
prefix_path: &[Segment],
- path: &[Segment],
+ following_seg: Option<&Segment>,
) -> Vec<ImportSuggestion> {
- let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
- path.get(prefix_path.len())
- } else {
- None
- };
if let Some(segment) = prefix_path.last() &&
- let Some(next_seg) = next_seg {
+ let Some(following_seg) = following_seg
+ {
let candidates = self.r.lookup_import_candidates(
segment.ident,
Namespace::TypeNS,
@@ -353,9 +349,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.filter(|candidate| {
if let Some(def_id) = candidate.did &&
let Some(module) = self.r.get_module(def_id) {
- self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
- key.ident.name == next_seg.ident.name
- })
+ Some(def_id) != self.parent_scope.module.opt_def_id() &&
+ self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
+ key.ident.name == following_seg.ident.name
+ })
} else {
false
}
@@ -371,7 +368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
pub(crate) fn smart_resolve_report_errors(
&mut self,
path: &[Segment],
- full_path: &[Segment],
+ following_seg: Option<&Segment>,
span: Span,
source: PathSource<'_>,
res: Option<Res>,
@@ -412,8 +409,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
return (err, Vec::new());
}
- let (found, candidates) =
- self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
+ let (found, candidates) = self.try_lookup_name_relaxed(
+ &mut err,
+ source,
+ path,
+ following_seg,
+ span,
+ res,
+ &base_error,
+ );
if found {
return (err, candidates);
}
@@ -422,7 +426,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// if we have suggested using pattern matching, then don't add needless suggestions
// for typos.
- fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
+ fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error);
if fallback {
// Fallback label.
@@ -442,20 +446,29 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic,
base_error: &BaseError,
) {
- let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
- let TyKind::Path(_, path) = &ty.kind else { return; };
+ let Some(ty) = self.diagnostic_metadata.current_type_path else {
+ return;
+ };
+ let TyKind::Path(_, path) = &ty.kind else {
+ return;
+ };
for segment in &path.segments {
- let Some(params) = &segment.args else { continue; };
- let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
+ let Some(params) = &segment.args else {
+ continue;
+ };
+ let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else {
+ continue;
+ };
for param in &params.args {
- let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
+ let ast::AngleBracketedArg::Constraint(constraint) = param else {
+ continue;
+ };
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
continue;
};
for bound in bounds {
- let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
- = bound else
- {
+ let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None) = bound
+ else {
continue;
};
if base_error.span == trait_ref.span {
@@ -519,7 +532,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic,
source: PathSource<'_>,
path: &[Segment],
- full_path: &[Segment],
+ following_seg: Option<&Segment>,
span: Span,
res: Option<Res>,
base_error: &BaseError,
@@ -542,7 +555,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
})
.collect::<Vec<_>>();
- let crate_def_id = CRATE_DEF_ID.to_def_id();
// Try to filter out intrinsics candidates, as long as we have
// some other candidates to suggest.
let intrinsic_candidates: Vec<_> = candidates
@@ -553,8 +565,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.collect();
if candidates.is_empty() {
// Put them back if we have no more candidates to suggest...
- candidates.extend(intrinsic_candidates);
+ candidates = intrinsic_candidates;
}
+ let crate_def_id = CRATE_DEF_ID.to_def_id();
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
let mut enum_candidates: Vec<_> = self
.r
@@ -572,13 +585,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let others = match enum_candidates.len() {
1 => String::new(),
2 => " and 1 other".to_owned(),
- n => format!(" and {} others", n),
+ n => format!(" and {n} others"),
};
format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
} else {
String::new()
};
- let msg = format!("{}try using the variant's enum", preamble);
+ let msg = format!("{preamble}try using the variant's enum");
err.span_suggestions(
span,
@@ -590,8 +603,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
// Try finding a suitable replacement.
- let typo_sugg =
- self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
+ let typo_sugg = self
+ .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
+ .to_opt_suggestion();
if path.len() == 1 && self.self_type_is_available() {
if let Some(candidate) =
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
@@ -682,7 +696,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
ident.name == path[0].ident.name {
err.span_help(
ident.span,
- format!("the binding `{}` is available in a different scope in the same function", path_str),
+ format!("the binding `{path_str}` is available in a different scope in the same function"),
);
return (true, candidates);
}
@@ -690,7 +704,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
if candidates.is_empty() {
- candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
+ candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
}
return (false, candidates);
@@ -776,12 +790,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic,
source: PathSource<'_>,
path: &[Segment],
+ following_seg: Option<&Segment>,
span: Span,
base_error: &BaseError,
) -> bool {
let is_expected = &|res| source.is_expected(res);
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
- let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+ let typo_sugg =
+ self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
let is_in_same_file = &|sp1, sp2| {
let source_map = self.r.tcx.sess.source_map();
let file1 = source_map.span_to_filename(sp1);
@@ -842,7 +858,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
for label_rib in &self.label_ribs {
for (label_ident, node_id) in &label_rib.bindings {
let ident = path.last().unwrap().ident;
- if format!("'{}", ident) == label_ident.to_string() {
+ if format!("'{ident}") == label_ident.to_string() {
err.span_label(label_ident.span, "a label with a similar name exists");
if let PathSource::Expr(Some(Expr {
kind: ExprKind::Break(None, Some(_)),
@@ -967,7 +983,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if let Some(ident) = fn_kind.ident() {
err.span_label(
ident.span,
- format!("this function {} have a `self` parameter", doesnt),
+ format!("this function {doesnt} have a `self` parameter"),
);
}
}
@@ -1141,10 +1157,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
&poly_trait_ref.trait_ref.path.segments[..]
{
if ident.span == span {
- let Some(new_where_bound_predicate) = mk_where_bound_predicate(path, poly_trait_ref, ty) else { return false; };
+ let Some(new_where_bound_predicate) =
+ mk_where_bound_predicate(path, poly_trait_ref, ty)
+ else {
+ return false;
+ };
err.span_suggestion_verbose(
*where_span,
- format!("constrain the associated type to `{}`", ident),
+ format!("constrain the associated type to `{ident}`"),
where_bound_predicate_to_string(&new_where_bound_predicate),
Applicability::MaybeIncorrect,
);
@@ -1160,37 +1180,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
/// return the span of whole call and the span for all arguments expect the first one (`self`).
fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
let mut has_self_arg = None;
- if let PathSource::Expr(Some(parent)) = source {
- match &parent.kind {
- ExprKind::Call(_, args) if !args.is_empty() => {
- let mut expr_kind = &args[0].kind;
- loop {
- match expr_kind {
- ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
- if arg_name.segments[0].ident.name == kw::SelfLower {
- let call_span = parent.span;
- let tail_args_span = if args.len() > 1 {
- Some(Span::new(
- args[1].span.lo(),
- args.last().unwrap().span.hi(),
- call_span.ctxt(),
- None,
- ))
- } else {
- None
- };
- has_self_arg = Some((call_span, tail_args_span));
- }
- break;
+ if let PathSource::Expr(Some(parent)) = source
+ && let ExprKind::Call(_, args) = &parent.kind
+ && !args.is_empty() {
+ let mut expr_kind = &args[0].kind;
+ loop {
+ match expr_kind {
+ ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
+ if arg_name.segments[0].ident.name == kw::SelfLower {
+ let call_span = parent.span;
+ let tail_args_span = if args.len() > 1 {
+ Some(Span::new(
+ args[1].span.lo(),
+ args.last().unwrap().span.hi(),
+ call_span.ctxt(),
+ None,
+ ))
+ } else {
+ None
+ };
+ has_self_arg = Some((call_span, tail_args_span));
}
- ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
- _ => break,
+ break;
}
+ ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
+ _ => break,
}
}
- _ => (),
- }
- };
+ }
has_self_arg
}
@@ -1200,15 +1217,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
let sm = self.r.tcx.sess.source_map();
- let sp = sm.span_look_ahead(span, None, Some(50));
- let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
- // In case this could be a struct literal that needs to be surrounded
- // by parentheses, find the appropriate span.
- let closing_span = sm.span_look_ahead(span, Some("}"), Some(50));
- let closing_brace: Option<Span> = sm
- .span_to_snippet(closing_span)
- .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None });
- (followed_by_brace, closing_brace)
+ if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
+ // In case this could be a struct literal that needs to be surrounded
+ // by parentheses, find the appropriate span.
+ let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
+ let closing_brace = close_brace_span.map(|sp| span.to(sp));
+ (true, closing_brace)
+ } else {
+ (false, None)
+ }
}
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
@@ -1318,8 +1335,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
span, // Note the parentheses surrounding the suggestion below
format!(
"you might want to surround a struct literal with parentheses: \
- `({} {{ /* fields */ }})`?",
- path_str
+ `({path_str} {{ /* fields */ }})`?"
),
);
}
@@ -1353,7 +1369,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.map(|(idx, new)| (new, old_fields.get(idx)))
.map(|(new, old)| {
let new = new.to_ident_string();
- if let Some(Some(old)) = old && new != *old { format!("{}: {}", new, old) } else { new }
+ if let Some(Some(old)) = old && new != *old { format!("{new}: {old}") } else { new }
})
.collect::<Vec<String>>()
} else {
@@ -1370,7 +1386,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
};
err.span_suggestion(
span,
- format!("use struct {} syntax instead", descr),
+ format!("use struct {descr} syntax instead"),
format!("{path_str} {{{pad}{fields}{pad}}}"),
applicability,
);
@@ -1403,7 +1419,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
err.span_label(span, fallback_label.to_string());
}
- (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
+ (Res::Def(DefKind::TyAlias { .. }, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
if self.r.tcx.sess.is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
@@ -1564,7 +1580,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestion(
span,
"use the tuple variant pattern syntax instead",
- format!("{}({})", path_str, fields),
+ format!("{path_str}({fields})"),
Applicability::HasPlaceholders,
);
}
@@ -1572,7 +1588,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_label(span, fallback_label.to_string());
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
- (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
+ (Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, _), _) if ns == ValueNS => {
err.note("can't use a type alias as a constructor");
}
_ => return false,
@@ -1715,6 +1731,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn lookup_typo_candidate(
&mut self,
path: &[Segment],
+ following_seg: Option<&Segment>,
ns: Namespace,
filter_fn: &impl Fn(Res) -> bool,
) -> TypoCandidate {
@@ -1793,6 +1810,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
}
+ // if next_seg is present, let's filter everything that does not continue the path
+ if let Some(following_seg) = following_seg {
+ names.retain(|suggestion| match suggestion.res {
+ Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
+ // FIXME: this is not totally accurate, but mostly works
+ suggestion.candidate != following_seg.ident.name
+ }
+ Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
+ || false,
+ |module| {
+ self.r
+ .resolutions(module)
+ .borrow()
+ .iter()
+ .any(|(key, _)| key.ident.name == following_seg.ident.name)
+ },
+ ),
+ _ => true,
+ });
+ }
let name = path[path.len() - 1].ident.name;
// Make sure error reporting is deterministic.
names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
@@ -1803,7 +1840,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
None,
) {
Some(found) => {
- let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
+ let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found)
+ else {
return TypoCandidate::None;
};
if found == name {
@@ -1952,9 +1990,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if !suggestable_variants.is_empty() {
let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
- format!("try {} the enum's variant", source_msg)
+ format!("try {source_msg} the enum's variant")
} else {
- format!("try {} one of the enum's variants", source_msg)
+ format!("try {source_msg} one of the enum's variants")
};
err.span_suggestions(
@@ -1967,19 +2005,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// If the enum has no tuple variants..
if non_suggestable_variant_count == variants.len() {
- err.help(format!("the enum has no tuple variants {}", source_msg));
+ err.help(format!("the enum has no tuple variants {source_msg}"));
}
// If there are also non-tuple variants..
if non_suggestable_variant_count == 1 {
- err.help(format!(
- "you might have meant {} the enum's non-tuple variant",
- source_msg
- ));
+ err.help(format!("you might have meant {source_msg} the enum's non-tuple variant"));
} else if non_suggestable_variant_count >= 1 {
err.help(format!(
- "you might have meant {} one of the enum's non-tuple variants",
- source_msg
+ "you might have meant {source_msg} one of the enum's non-tuple variants"
));
}
} else {
@@ -1999,7 +2033,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
.map(|(variant, kind)| match kind {
CtorKind::Const => variant,
- CtorKind::Fn => format!("({}())", variant),
+ CtorKind::Fn => format!("({variant}())"),
})
.collect::<Vec<_>>();
let no_suggestable_variant = suggestable_variants.is_empty();
@@ -2024,7 +2058,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
.filter_map(|(variant, kind)| match kind {
- CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
+ CtorKind::Fn => Some(format!("({variant}(/* fields */))")),
_ => None,
})
.collect::<Vec<_>>();
@@ -2306,13 +2340,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let mut should_continue = true;
match rib.kind {
LifetimeRibKind::Generics { binder: _, span, kind } => {
+ // Avoid suggesting placing lifetime parameters on constant items unless the relevant
+ // feature is enabled. Suggest the parent item as a possible location if applicable.
+ if let LifetimeBinderKind::ConstItem = kind
+ && !self.r.tcx().features().generic_const_items
+ {
+ continue;
+ }
+
if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(
span,
format!(
- "lifetime `{}` is missing in item created through this procedural macro",
- name,
+ "lifetime `{name}` is missing in item created through this procedural macro",
),
);
continue;
@@ -2356,14 +2397,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
);
} else if let Some(name) = name {
let message =
- Cow::from(format!("consider introducing lifetime `{}` here", name));
+ Cow::from(format!("consider introducing lifetime `{name}` here"));
should_continue = suggest(err, false, span, message, sugg);
} else {
let message = Cow::from("consider introducing a named lifetime parameter");
should_continue = suggest(err, false, span, message, sugg);
}
}
- LifetimeRibKind::Item => break,
+ LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
_ => {}
}
if !should_continue {
@@ -2469,7 +2510,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.lifetime_ribs
.iter()
.rev()
- .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item))
+ .take_while(|rib| {
+ !matches!(rib.kind, LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy)
+ })
.flat_map(|rib| rib.bindings.iter())
.map(|(&ident, &res)| (ident, res))
.filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
@@ -2500,7 +2543,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
let help_name = if let Some(ident) = ident {
- format!("`{}`", ident)
+ format!("`{ident}`")
} else {
format!("argument {}", index + 1)
};
@@ -2508,7 +2551,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if lifetime_count == 1 {
m.push_str(&help_name[..])
} else {
- m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+ m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..])
}
}
@@ -2538,14 +2581,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
} else if num_params == 1 {
err.help(format!(
"this function's return type contains a borrowed value, \
- but the signature does not say which {} it is borrowed from",
- m
+ but the signature does not say which {m} it is borrowed from"
));
} else {
err.help(format!(
"this function's return type contains a borrowed value, \
- but the signature does not say whether it is borrowed from {}",
- m
+ but the signature does not say whether it is borrowed from {m}"
));
}
}
@@ -2564,7 +2605,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
MissingLifetimeKind::Ampersand => {
debug_assert_eq!(lt.count, 1);
- (lt.span.shrink_to_hi(), format!("{} ", existing_name))
+ (lt.span.shrink_to_hi(), format!("{existing_name} "))
}
MissingLifetimeKind::Comma => {
let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
@@ -2611,7 +2652,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
1 => {
err.multipart_suggestion_verbose(
- format!("consider using the `{}` lifetime", existing_name),
+ format!("consider using the `{existing_name}` lifetime"),
spans_suggs,
Applicability::MaybeIncorrect,
);
@@ -2649,7 +2690,9 @@ fn mk_where_bound_predicate(
use rustc_span::DUMMY_SP;
let modified_segments = {
let mut segments = path.segments.clone();
- let [preceding @ .., second_last, last] = segments.as_mut_slice() else { return None; };
+ let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
+ return None;
+ };
let mut segments = ThinVec::from(preceding);
let added_constraint = ast::AngleBracketedArg::Constraint(ast::AssocConstraint {
@@ -2726,9 +2769,9 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident
let shadower = shadower.span;
let mut err = sess.struct_span_warn(
shadower,
- format!("label name `{}` shadows a label name that is already in scope", name),
+ format!("label name `{name}` shadows a label name that is already in scope"),
);
err.span_label(orig, "first declared here");
- err.span_label(shadower, format!("label `{}` already in scope", name));
+ err.span_label(shadower, format!("label `{name}` already in scope"));
err.emit();
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index da3d86a47..76e54e60d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -18,6 +18,7 @@
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
#![allow(rustc::potential_query_instability)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#[macro_use]
extern crate tracing;
@@ -658,6 +659,7 @@ impl<'a> fmt::Debug for Module<'a> {
struct NameBindingData<'a> {
kind: NameBindingKind<'a>,
ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>,
+ warn_ambiguity: bool,
expansion: LocalExpnId,
span: Span,
vis: ty::Visibility<DefId>,
@@ -767,6 +769,7 @@ struct AmbiguityError<'a> {
b2: NameBinding<'a>,
misc1: AmbiguityErrorMisc,
misc2: AmbiguityErrorMisc,
+ warning: bool,
}
impl<'a> NameBindingData<'a> {
@@ -794,6 +797,14 @@ impl<'a> NameBindingData<'a> {
}
}
+ fn is_warn_ambiguity(&self) -> bool {
+ self.warn_ambiguity
+ || match self.kind {
+ NameBindingKind::Import { binding, .. } => binding.is_warn_ambiguity(),
+ _ => false,
+ }
+ }
+
fn is_possibly_imported_variant(&self) -> bool {
match self.kind {
NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
@@ -1158,7 +1169,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
}
fn local_def_id(&self, node: NodeId) -> LocalDefId {
- self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+ self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
}
/// Adds a definition with a parent definition.
@@ -1271,7 +1282,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let registered_tools = tcx.registered_tools(());
- let features = tcx.sess.features_untracked();
+ let features = tcx.features();
let mut resolver = Resolver {
tcx,
@@ -1322,6 +1333,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
dummy_binding: arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Res(Res::Err),
ambiguity: None,
+ warn_ambiguity: false,
expansion: LocalExpnId::ROOT,
span: DUMMY_SP,
vis: ty::Visibility::Public,
@@ -1685,6 +1697,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) {
+ self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity);
+ }
+
+ fn record_use_inner(
+ &mut self,
+ ident: Ident,
+ used_binding: NameBinding<'a>,
+ is_lexical_scope: bool,
+ warn_ambiguity: bool,
+ ) {
if let Some((b2, kind)) = used_binding.ambiguity {
let ambiguity_error = AmbiguityError {
kind,
@@ -1693,9 +1715,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
b2,
misc1: AmbiguityErrorMisc::None,
misc2: AmbiguityErrorMisc::None,
+ warning: warn_ambiguity,
};
if !self.matches_previous_ambiguity_error(&ambiguity_error) {
- // avoid duplicated span information to be emitt out
+ // avoid duplicated span information to be emit out
self.ambiguity_errors.push(ambiguity_error);
}
}
@@ -1715,7 +1738,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.used_imports.insert(id);
}
self.add_to_glob_map(import, ident);
- self.record_use(ident, binding, false);
+ self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity);
}
}
@@ -1812,7 +1835,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
debug!("(recording res) recording {:?} for {}", resolution, node_id);
if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
- panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution);
+ panic!("path resolved multiple times ({prev_res:?} before, {resolution:?} now)");
}
}
@@ -1871,7 +1894,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} else {
let crate_id = if finalize {
let Some(crate_id) =
- self.crate_loader(|c| c.process_path_extern(ident.name, ident.span)) else { return Some(self.dummy_binding); };
+ self.crate_loader(|c| c.process_path_extern(ident.name, ident.span))
+ else {
+ return Some(self.dummy_binding);
+ };
crate_id
} else {
self.crate_loader(|c| c.maybe_process_path_extern(ident.name))?
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d16b7902f..6a5b675b4 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -24,7 +24,9 @@ use rustc_hir::def_id::{CrateNum, LocalDefId};
use rustc_middle::middle::stability;
use rustc_middle::ty::RegisteredTools;
use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
+use rustc_session::lint::builtin::{
+ LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+};
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::feature_err;
@@ -140,9 +142,9 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
}
}
}
- // We implicitly add `rustfmt` and `clippy` to known tools,
+ // We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
// but it's not an error to register them explicitly.
- let predefined_tools = [sym::clippy, sym::rustfmt];
+ let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic];
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
registered_tools
}
@@ -205,7 +207,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
self.tcx
.sess
.diagnostic()
- .bug(format!("built-in macro `{}` was already registered", name));
+ .bug(format!("built-in macro `{name}` was already registered"));
}
}
@@ -568,7 +570,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
let mut err = self.tcx.sess.create_err(err);
- err.span_label(path.span, format!("not {} {}", article, expected));
+ err.span_label(path.span, format!("not {article} {expected}"));
err.emit();
@@ -576,10 +578,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
// We are trying to avoid reporting this error if other related errors were reported.
- if res != Res::Err
- && inner_attr
- && !self.tcx.sess.features_untracked().custom_inner_attributes
- {
+ if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
let msg = match res {
Res::Def(..) => "inner macro attributes are unstable",
Res::NonMacroAttr(..) => "custom inner attributes are unstable",
@@ -598,6 +597,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
+ if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
+ && path.segments.len() >= 2
+ && path.segments[0].ident.name == sym::diagnostic
+ {
+ self.tcx.sess.parse_sess.buffer_lint(
+ UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+ path.segments[1].span(),
+ node_id,
+ "unknown diagnostic attribute",
+ );
+ }
+
Ok((ext, res))
}
@@ -895,7 +906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
self.tcx.sess.span_err(
ident.span,
- format!("name `{}` is reserved in attribute namespace", ident),
+ format!("name `{ident}` is reserved in attribute namespace"),
);
}
}
@@ -909,7 +920,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
item: &ast::Item,
edition: Edition,
) -> (SyntaxExtension, Vec<(usize, Span)>) {
- let (mut result, mut rule_spans) = compile_declarative_macro(self.tcx.sess, item, edition);
+ let (mut result, mut rule_spans) =
+ compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
if let Some(builtin_name) = result.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index d433391f2..ba7417b6d 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -1,4 +1,4 @@
-use pulldown_cmark::{BrokenLink, Event, LinkType, Options, Parser, Tag};
+use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
use rustc_ast as ast;
use rustc_ast::util::comments::beautify_doc_string;
use rustc_data_structures::fx::FxHashMap;
@@ -392,16 +392,73 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
- Parser::new_with_broken_link_callback(
+ parse_links(&doc)
+}
+
+/// Similiar version of `markdown_links` from rustdoc.
+/// This will collect destination links and display text if exists.
+fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
+ let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
+ let mut event_iter = Parser::new_with_broken_link_callback(
&doc,
main_body_opts(),
- Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
+ Some(&mut broken_link_callback),
)
- .filter_map(|event| match event {
- Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
- Some(preprocess_link(&dest))
+ .into_iter();
+ let mut links = Vec::new();
+
+ while let Some(event) = event_iter.next() {
+ match event {
+ Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+ if matches!(
+ link_type,
+ LinkType::Inline
+ | LinkType::ReferenceUnknown
+ | LinkType::Reference
+ | LinkType::Shortcut
+ | LinkType::ShortcutUnknown
+ ) {
+ if let Some(display_text) = collect_link_data(&mut event_iter) {
+ links.push(display_text);
+ }
+ }
+
+ links.push(preprocess_link(&dest));
+ }
+ _ => {}
+ }
+ }
+
+ links
+}
+
+/// Collects additional data of link.
+fn collect_link_data<'input, 'callback>(
+ event_iter: &mut Parser<'input, 'callback>,
+) -> Option<Box<str>> {
+ let mut display_text: Option<String> = None;
+ let mut append_text = |text: CowStr<'_>| {
+ if let Some(display_text) = &mut display_text {
+ display_text.push_str(&text);
+ } else {
+ display_text = Some(text.to_string());
+ }
+ };
+
+ while let Some(event) = event_iter.next() {
+ match event {
+ Event::Text(text) => {
+ append_text(text);
+ }
+ Event::Code(code) => {
+ append_text(code);
+ }
+ Event::End(_) => {
+ break;
+ }
+ _ => {}
}
- _ => None,
- })
- .collect()
+ }
+
+ display_text.map(String::into_boxed_str)
}