summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:25:56 +0000
commit018c4950b9406055dec02ef0fb52f132e2bb1e2c (patch)
treea835ebdf2088ef88fa681f8fad45f09922c1ae9a /compiler/rustc_resolve
parentAdding debian version 1.75.0+dfsg1-5. (diff)
downloadrustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.tar.xz
rustc-018c4950b9406055dec02ef0fb52f132e2bb1e2c.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r--compiler/rustc_resolve/messages.ftl6
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs155
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs210
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs128
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs6
-rw-r--r--compiler/rustc_resolve/src/errors.rs7
-rw-r--r--compiler/rustc_resolve/src/ident.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs35
-rw-r--r--compiler/rustc_resolve/src/late.rs65
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs650
-rw-r--r--compiler/rustc_resolve/src/lib.rs64
-rw-r--r--compiler/rustc_resolve/src/macros.rs38
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs5
13 files changed, 1005 insertions, 368 deletions
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 272483d4a..3f8df16e0 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -127,8 +127,6 @@ resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
-resolve_glob_import_doesnt_reexport =
- glob import doesn't reexport anything because no candidate is public enough
resolve_ident_bound_more_than_once_in_parameter_list =
identifier `{$identifier}` is bound more than once in this parameter list
@@ -183,6 +181,8 @@ resolve_method_not_member_of_trait =
method `{$method}` is not a member of trait `{$trait_}`
.label = not a member of trait `{$trait_}`
+resolve_missing_macro_rules_name = maybe you have forgotten to define a name for this `macro_rules!`
+
resolve_module_only =
visibility must resolve to a module
@@ -200,7 +200,7 @@ resolve_param_in_non_trivial_anon_const =
.label = cannot perform const operation using `{$name}`
resolve_param_in_non_trivial_anon_const_help =
- use `#![feature(generic_const_exprs)]` to allow generic const expressions
+ add `#![feature(generic_const_exprs)]` to allow generic const expressions
resolve_param_in_ty_of_const_param =
the type of const parameters must not depend on other generic parameters
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 0407db528..98a9d0ba4 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -123,7 +123,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.map(|parent_id| self.get_nearest_non_block_module(parent_id));
// Query `expn_that_defined` is not used because
// hashing spans in its result is expensive.
- let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess);
+ let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
return Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)),
@@ -156,33 +156,26 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
- pub(crate) fn get_macro(&mut self, res: Res) -> Option<MacroData> {
+ pub(crate) fn get_macro(&mut self, res: Res) -> Option<&MacroData> {
match res {
Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
- Res::NonMacroAttr(_) => {
- Some(MacroData { ext: self.non_macro_attr.clone(), macro_rules: false })
- }
+ Res::NonMacroAttr(_) => Some(&self.non_macro_attr),
_ => None,
}
}
- pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> MacroData {
- if let Some(macro_data) = self.macro_map.get(&def_id) {
- return macro_data.clone();
+ pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> &MacroData {
+ if self.macro_map.contains_key(&def_id) {
+ return &self.macro_map[&def_id];
}
- 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),
- matches!(item.kind, ItemKind::MacroDef(def) if def.macro_rules),
- ),
- LoadedMacro::ProcMacro(extz) => (Lrc::new(extz), false),
+ let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx);
+ let macro_data = match loaded_macro {
+ LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition),
+ LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)),
};
- let macro_data = MacroData { ext, macro_rules };
- self.macro_map.insert(def_id, macro_data.clone());
- macro_data
+ self.macro_map.entry(def_id).or_insert(macro_data)
}
pub(crate) fn build_reduced_graph(
@@ -217,6 +210,11 @@ impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for BuildReducedGraphVisitor<'a, '_, 't
}
impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
+ fn res(&self, def_id: impl Into<DefId>) -> Res {
+ let def_id = def_id.into();
+ Res::Def(self.r.tcx.def_kind(def_id), def_id)
+ }
+
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
self.try_resolve_visibility(vis, true).unwrap_or_else(|err| {
self.r.report_vis_error(err);
@@ -238,7 +236,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// (i.e. variants, fields, and trait items) inherits from the visibility
// of the enum or trait.
ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => {
- self.r.visibilities[&def_id.expect_local()]
+ self.r.tcx.visibility(def_id).expect_local()
}
// Otherwise, the visibility is restricted to the nearest parent `mod` item.
_ => ty::Visibility::Restricted(
@@ -396,6 +394,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
id: NodeId,
parent_prefix: &[Segment],
nested: bool,
+ list_stem: bool,
// The whole `use` item
item: &Item,
vis: ty::Visibility,
@@ -406,6 +405,12 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
parent_prefix, use_tree, nested
);
+ // Top level use tree reuses the item's id and list stems reuse their parent
+ // use tree's ids, so in both cases their visibilities are already filled.
+ if nested && !list_stem {
+ self.r.feed_visibility(self.r.local_def_id(id), vis);
+ }
+
let mut prefix_iter = parent_prefix
.iter()
.cloned()
@@ -444,8 +449,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let mut source = module_path.pop().unwrap();
let mut type_ns_only = false;
- self.r.visibilities.insert(self.r.local_def_id(id), vis);
-
if nested {
// Correctly handle `self`
if source.ident.name == kw::SelfLower {
@@ -559,7 +562,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
max_vis: Cell::new(None),
id,
};
- self.r.visibilities.insert(self.r.local_def_id(id), vis);
+
self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
}
ast::UseTreeKind::Nested(ref items) => {
@@ -592,7 +595,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
for &(ref tree, id) in items {
self.build_reduced_graph_for_use_tree(
// This particular use tree
- tree, id, &prefix, true, // The whole `use` item
+ tree, id, &prefix, true, false, // The whole `use` item
item, vis, root_span,
);
}
@@ -613,6 +616,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
id,
&prefix,
true,
+ true,
// The whole `use` item
item,
ty::Visibility::Restricted(
@@ -635,8 +639,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let vis = self.resolve_visibility(&item.vis);
let local_def_id = self.r.local_def_id(item.id);
let def_id = local_def_id.to_def_id();
+ let def_kind = self.r.tcx.def_kind(def_id);
+ let res = Res::Def(def_kind, def_id);
- self.r.visibilities.insert(local_def_id, vis);
+ self.r.feed_visibility(local_def_id, vis);
match item.kind {
ItemKind::Use(ref use_tree) => {
@@ -646,6 +652,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
item.id,
&[],
false,
+ false,
// The whole `use` item
item,
vis,
@@ -666,7 +673,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ItemKind::Mod(..) => {
let module = self.r.new_module(
Some(parent),
- ModuleKind::Def(DefKind::Mod, def_id, ident.name),
+ ModuleKind::Def(def_kind, def_id, ident.name),
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude
@@ -679,16 +686,13 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
// These items live in the value namespace.
- ItemKind::Static(box ast::StaticItem { mutability, .. }) => {
- let res = Res::Def(DefKind::Static(mutability), def_id);
+ ItemKind::Static(..) => {
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Const(..) => {
- let res = Res::Def(DefKind::Const, def_id);
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
}
ItemKind::Fn(..) => {
- let res = Res::Def(DefKind::Fn, def_id);
self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
// Functions introducing procedural macros reserve a slot
@@ -698,14 +702,13 @@ 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);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
ItemKind::Enum(_, _) => {
let module = self.r.new_module(
Some(parent),
- ModuleKind::Def(DefKind::Enum, def_id, ident.name),
+ ModuleKind::Def(def_kind, def_id, ident.name),
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude,
@@ -715,14 +718,12 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
ItemKind::TraitAlias(..) => {
- let res = Res::Def(DefKind::TraitAlias, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
}
// These items live in both the type and value namespaces.
ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
- let res = Res::Def(DefKind::Struct, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
// Record field names for error reporting.
@@ -731,7 +732,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// If this is a tuple or unit struct, define a name
// in the value namespace as well.
- if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(vdata) {
+ if let Some(ctor_node_id) = vdata.ctor_node_id() {
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
let mut ctor_vis = if vis.is_public()
@@ -757,10 +758,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ret_fields.push(field_vis.to_def_id());
}
let ctor_def_id = self.r.local_def_id(ctor_node_id);
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id.to_def_id());
+ let ctor_res = self.res(ctor_def_id);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
- self.r.visibilities.insert(ctor_def_id, ctor_vis);
+ self.r.feed_visibility(ctor_def_id, ctor_vis);
// We need the field visibility spans also for the constructor for E0603.
self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata);
@@ -771,7 +771,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
ItemKind::Union(ref vdata, _) => {
- let res = Res::Def(DefKind::Union, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
// Record field names for error reporting.
@@ -783,7 +782,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// Add all the items within to a new module.
let module = self.r.new_module(
Some(parent),
- ModuleKind::Def(DefKind::Trait, def_id, ident.name),
+ ModuleKind::Def(def_kind, def_id, ident.name),
expansion.to_expn_id(),
item.span,
parent.no_implicit_prelude,
@@ -895,18 +894,17 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
let local_def_id = self.r.local_def_id(item.id);
let def_id = local_def_id.to_def_id();
- let (def_kind, ns) = match item.kind {
- ForeignItemKind::Fn(..) => (DefKind::Fn, ValueNS),
- ForeignItemKind::Static(_, mt, _) => (DefKind::Static(mt), ValueNS),
- ForeignItemKind::TyAlias(..) => (DefKind::ForeignTy, TypeNS),
- ForeignItemKind::MacCall(_) => unreachable!(),
+ let ns = match item.kind {
+ ForeignItemKind::Fn(..) => ValueNS,
+ ForeignItemKind::Static(..) => ValueNS,
+ ForeignItemKind::TyAlias(..) => TypeNS,
+ ForeignItemKind::MacCall(..) => unreachable!(),
};
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
let vis = self.resolve_visibility(&item.vis);
- let res = Res::Def(def_kind, def_id);
- self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
- self.r.visibilities.insert(local_def_id, vis);
+ self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion));
+ self.r.feed_visibility(local_def_id, vis);
}
fn build_reduced_graph_for_block(&mut self, block: &Block) {
@@ -980,8 +978,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
| DefKind::LifetimeParam
| DefKind::GlobalAsm
| DefKind::Closure
- | DefKind::Impl { .. }
- | DefKind::Coroutine,
+ | DefKind::Impl { .. },
_,
)
| Res::Local(..)
@@ -1175,16 +1172,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// Mark the given macro as unused unless its name starts with `_`.
// Macro uses will remove items from this set, and the remaining
// items will be reported as `unused_macros`.
- fn insert_unused_macro(
- &mut self,
- ident: Ident,
- def_id: LocalDefId,
- node_id: NodeId,
- rule_spans: &[(usize, Span)],
- ) {
+ fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) {
if !ident.as_str().starts_with('_') {
self.r.unused_macros.insert(def_id, (node_id, ident));
- for (rule_i, rule_span) in rule_spans.iter() {
+ for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans {
self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span));
}
}
@@ -1194,24 +1185,21 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let parent_scope = self.parent_scope;
let expansion = parent_scope.expansion;
let def_id = self.r.local_def_id(item.id);
- let (ext, ident, span, macro_rules, rule_spans) = match &item.kind {
- ItemKind::MacroDef(def) => {
- let (ext, rule_spans) = self.r.compile_macro(item, self.r.tcx.sess.edition());
- let ext = Lrc::new(ext);
- (ext, item.ident, item.span, def.macro_rules, rule_spans)
- }
+ let (res, ident, span, macro_rules) = match &item.kind {
+ ItemKind::MacroDef(def) => (self.res(def_id), item.ident, item.span, def.macro_rules),
ItemKind::Fn(..) => match self.proc_macro_stub(item) {
Some((macro_kind, ident, span)) => {
+ let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id());
+ let macro_data = MacroData::new(self.r.dummy_ext(macro_kind));
+ self.r.macro_map.insert(def_id.to_def_id(), macro_data);
self.r.proc_macro_stubs.insert(def_id);
- (self.r.dummy_ext(macro_kind), ident, span, false, Vec::new())
+ (res, ident, span, false)
}
None => return parent_scope.macro_rules,
},
_ => unreachable!(),
};
- let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id());
- self.r.macro_map.insert(def_id.to_def_id(), MacroData { ext, macro_rules });
self.r.local_macro_def_scopes.insert(def_id, parent_scope.module);
if macro_rules {
@@ -1245,9 +1233,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
} else {
self.r.check_reserved_macro_name(ident, res);
- self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
+ self.insert_unused_macro(ident, def_id, item.id);
}
- self.r.visibilities.insert(def_id, vis);
+ self.r.feed_visibility(def_id, vis);
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
parent_macro_rules_scope: parent_scope.macro_rules,
@@ -1268,10 +1256,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
_ => self.resolve_visibility(&item.vis),
};
if !vis.is_public() {
- self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
+ self.insert_unused_macro(ident, def_id, item.id);
}
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
- self.r.visibilities.insert(def_id, vis);
+ self.r.feed_visibility(def_id, vis);
self.parent_scope.macro_rules
}
}
@@ -1373,26 +1361,25 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// Trait impl item visibility is inherited from its trait when not specified
// explicitly. In that case we cannot determine it here in early resolve,
// so we leave a hole in the visibility table to be filled later.
- self.r.visibilities.insert(local_def_id, vis);
+ self.r.feed_visibility(local_def_id, vis);
}
if ctxt == AssocCtxt::Trait {
- let (def_kind, ns) = match item.kind {
- AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
+ let ns = match item.kind {
+ AssocItemKind::Const(..) => ValueNS,
AssocItemKind::Fn(box Fn { ref sig, .. }) => {
if sig.decl.has_self() {
self.r.has_self.insert(local_def_id);
}
- (DefKind::AssocFn, ValueNS)
+ ValueNS
}
- AssocItemKind::Type(..) => (DefKind::AssocTy, TypeNS),
+ AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) => bug!(), // handled above
};
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
- let res = Res::Def(def_kind, def_id);
- self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
+ self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion));
}
visit::walk_assoc_item(self, item, ctxt);
@@ -1452,7 +1439,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.visit_invoc(sf.id);
} else {
let vis = self.resolve_visibility(&sf.vis);
- self.r.visibilities.insert(self.r.local_def_id(sf.id), vis);
+ self.r.feed_visibility(self.r.local_def_id(sf.id), vis);
visit::walk_field_def(self, sf);
}
}
@@ -1471,10 +1458,9 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// Define a name in the type namespace.
let def_id = self.r.local_def_id(variant.id);
- let res = Res::Def(DefKind::Variant, def_id.to_def_id());
let vis = self.resolve_visibility(&variant.vis);
- self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
- self.r.visibilities.insert(def_id, vis);
+ self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id));
+ self.r.feed_visibility(def_id, vis);
// If the variant is marked as non_exhaustive then lower the visibility to within the crate.
let ctor_vis =
@@ -1485,12 +1471,11 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
};
// Define a constructor name in the value namespace.
- if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) {
+ if let Some(ctor_node_id) = variant.data.ctor_node_id() {
let ctor_def_id = self.r.local_def_id(ctor_node_id);
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id.to_def_id());
+ let ctor_res = self.res(ctor_def_id);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
- self.r.visibilities.insert(ctor_def_id, ctor_vis);
+ self.r.feed_visibility(ctor_def_id, ctor_vis);
}
// Record field names for error reporting.
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 13df7efe6..02553d500 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -2,10 +2,10 @@ use crate::{ImplTraitContext, Resolver};
use rustc_ast::visit::{self, FnKind};
use rustc_ast::*;
use rustc_expand::expand::AstFragment;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::definitions::*;
use rustc_span::hygiene::LocalExpnId;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
pub(crate) fn collect_definitions(
@@ -26,13 +26,23 @@ struct DefCollector<'a, 'b, 'tcx> {
}
impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
- fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
+ fn create_def(
+ &mut self,
+ node_id: NodeId,
+ name: Symbol,
+ def_kind: DefKind,
+ span: Span,
+ ) -> LocalDefId {
let parent_def = self.parent_def;
- debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
+ debug!(
+ "create_def(node_id={:?}, def_kind={:?}, parent_def={:?})",
+ node_id, def_kind, parent_def
+ );
self.resolver.create_def(
parent_def,
node_id,
- data,
+ name,
+ def_kind,
self.expansion.to_expn_id(),
span.with_parent(None),
)
@@ -68,7 +78,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
self.visit_macro_invoc(field.id);
} else {
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
- let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
+ let def = self.create_def(field.id, name, DefKind::Field, field.span);
self.with_parent(def, |this| visit::walk_field_def(this, field));
}
}
@@ -87,39 +97,54 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
// Pick the def data. This need not be unique, but the more
// information we encapsulate into, the better
- let def_data = match &i.kind {
- ItemKind::Impl { .. } => DefPathData::Impl,
- ItemKind::ForeignMod(..) => DefPathData::ForeignMod,
- ItemKind::Mod(..)
- | ItemKind::Trait(..)
- | ItemKind::TraitAlias(..)
- | ItemKind::Enum(..)
- | ItemKind::Struct(..)
- | ItemKind::Union(..)
- | ItemKind::ExternCrate(..)
- | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
- ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => {
- DefPathData::ValueNs(i.ident.name)
+ let mut opt_macro_data = None;
+ let def_kind = match &i.kind {
+ ItemKind::Impl(i) => DefKind::Impl { of_trait: i.of_trait.is_some() },
+ ItemKind::ForeignMod(..) => DefKind::ForeignMod,
+ ItemKind::Mod(..) => DefKind::Mod,
+ ItemKind::Trait(..) => DefKind::Trait,
+ ItemKind::TraitAlias(..) => DefKind::TraitAlias,
+ ItemKind::Enum(..) => DefKind::Enum,
+ ItemKind::Struct(..) => DefKind::Struct,
+ ItemKind::Union(..) => DefKind::Union,
+ ItemKind::ExternCrate(..) => DefKind::ExternCrate,
+ ItemKind::TyAlias(..) => DefKind::TyAlias,
+ ItemKind::Static(s) => DefKind::Static(s.mutability),
+ ItemKind::Const(..) => DefKind::Const,
+ ItemKind::Fn(..) => DefKind::Fn,
+ ItemKind::MacroDef(..) => {
+ let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
+ let macro_kind = macro_data.ext.macro_kind();
+ opt_macro_data = Some(macro_data);
+ DefKind::Macro(macro_kind)
}
- ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name),
ItemKind::MacCall(..) => {
visit::walk_item(self, i);
return self.visit_macro_invoc(i.id);
}
- ItemKind::GlobalAsm(..) => DefPathData::GlobalAsm,
+ ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(..) => {
return visit::walk_item(self, i);
}
};
- let def = self.create_def(i.id, def_data, i.span);
+ let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
- self.with_parent(def, |this| {
+ if let Some(macro_data) = opt_macro_data {
+ self.resolver.macro_map.insert(def_id.to_def_id(), macro_data);
+ }
+
+ self.with_parent(def_id, |this| {
this.with_impl_trait(ImplTraitContext::Existential, |this| {
match i.kind {
ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
// If this is a unit or tuple-like struct, register the constructor.
- if let Some(ctor_node_id) = struct_def.ctor_node_id() {
- this.create_def(ctor_node_id, DefPathData::Ctor, i.span);
+ if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) {
+ this.create_def(
+ ctor_node_id,
+ kw::Empty,
+ DefKind::Ctor(CtorOf::Struct, ctor_kind),
+ i.span,
+ );
}
}
_ => {}
@@ -131,25 +156,33 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
- if let Async::Yes { closure_id, .. } = sig.header.asyncness {
- self.visit_generics(generics);
-
- // For async functions, we need to create their inner defs inside of a
- // closure to match their desugared representation. Besides that,
- // we must mirror everything that `visit::walk_fn` below does.
- self.visit_fn_header(&sig.header);
- for param in &sig.decl.inputs {
- self.visit_param(param);
- }
- self.visit_fn_ret_ty(&sig.decl.output);
- // If this async fn has no body (i.e. it's an async fn signature in a trait)
- // then the closure_def will never be used, and we should avoid generating a
- // def-id for it.
- if let Some(body) = body {
- let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
- self.with_parent(closure_def, |this| this.visit_block(body));
+ match sig.header.coroutine_kind {
+ Some(coroutine_kind) => {
+ self.visit_generics(generics);
+
+ // For async functions, we need to create their inner defs inside of a
+ // closure to match their desugared representation. Besides that,
+ // we must mirror everything that `visit::walk_fn` below does.
+ self.visit_fn_header(&sig.header);
+ for param in &sig.decl.inputs {
+ self.visit_param(param);
+ }
+ self.visit_fn_ret_ty(&sig.decl.output);
+ // If this async fn has no body (i.e. it's an async fn signature in a trait)
+ // then the closure_def will never be used, and we should avoid generating a
+ // def-id for it.
+ if let Some(body) = body {
+ let closure_def = self.create_def(
+ coroutine_kind.closure_id(),
+ kw::Empty,
+ DefKind::Closure,
+ span,
+ );
+ self.with_parent(closure_def, |this| this.visit_block(body));
+ }
+ return;
}
- return;
+ None => {}
}
}
@@ -157,34 +190,36 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
- self.create_def(id, DefPathData::Use, use_tree.span);
+ self.create_def(id, kw::Empty, DefKind::Use, use_tree.span);
visit::walk_use_tree(self, use_tree, id);
}
- fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
- if let ForeignItemKind::MacCall(_) = foreign_item.kind {
- return self.visit_macro_invoc(foreign_item.id);
- }
+ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
+ let def_kind = match fi.kind {
+ ForeignItemKind::Static(_, mt, _) => DefKind::Static(mt),
+ ForeignItemKind::Fn(_) => DefKind::Fn,
+ ForeignItemKind::TyAlias(_) => DefKind::ForeignTy,
+ ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id),
+ };
- let def = self.create_def(
- foreign_item.id,
- DefPathData::ValueNs(foreign_item.ident.name),
- foreign_item.span,
- );
+ let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span);
- self.with_parent(def, |this| {
- visit::walk_foreign_item(this, foreign_item);
- });
+ self.with_parent(def, |this| visit::walk_foreign_item(this, fi));
}
fn visit_variant(&mut self, v: &'a Variant) {
if v.is_placeholder {
return self.visit_macro_invoc(v.id);
}
- let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span);
+ let def = self.create_def(v.id, v.ident.name, DefKind::Variant, v.span);
self.with_parent(def, |this| {
- if let Some(ctor_node_id) = v.data.ctor_node_id() {
- this.create_def(ctor_node_id, DefPathData::Ctor, v.span);
+ if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) {
+ this.create_def(
+ ctor_node_id,
+ kw::Empty,
+ DefKind::Ctor(CtorOf::Variant, ctor_kind),
+ v.span,
+ );
}
visit::walk_variant(this, v)
});
@@ -204,13 +239,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
self.visit_macro_invoc(param.id);
return;
}
- let name = param.ident.name;
- let def_path_data = match param.kind {
- GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name),
- GenericParamKind::Type { .. } => DefPathData::TypeNs(name),
- GenericParamKind::Const { .. } => DefPathData::ValueNs(name),
+ let def_kind = match param.kind {
+ GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
+ GenericParamKind::Type { .. } => DefKind::TyParam,
+ GenericParamKind::Const { .. } => DefKind::ConstParam,
};
- self.create_def(param.id, def_path_data, param.ident.span);
+ self.create_def(param.id, param.ident.name, def_kind, param.ident.span);
// impl-Trait can happen inside generic parameters, like
// ```
@@ -218,19 +252,20 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
// ```
//
// In that case, the impl-trait is lowered as an additional generic parameter.
- self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
+ self.with_impl_trait(ImplTraitContext::Universal, |this| {
visit::walk_generic_param(this, param)
});
}
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
- let def_data = match &i.kind {
- AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
- AssocItemKind::Type(..) => DefPathData::TypeNs(i.ident.name),
+ let def_kind = match &i.kind {
+ AssocItemKind::Fn(..) => DefKind::AssocFn,
+ AssocItemKind::Const(..) => DefKind::AssocConst,
+ AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
};
- let def = self.create_def(i.id, def_data, i.span);
+ let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
}
@@ -242,7 +277,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}
fn visit_anon_const(&mut self, constant: &'a AnonConst) {
- let def = self.create_def(constant.id, DefPathData::AnonConst, constant.value.span);
+ let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
}
@@ -252,15 +287,30 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ExprKind::Closure(ref closure) => {
// Async closures desugar to closures inside of closures, so
// we must create two defs.
- let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
- match closure.asyncness {
- Async::Yes { closure_id, .. } => {
- self.create_def(closure_id, DefPathData::ClosureExpr, expr.span)
- }
- Async::No => closure_def,
+ let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
+ match closure.coroutine_kind {
+ Some(coroutine_kind) => self.create_def(
+ coroutine_kind.closure_id(),
+ kw::Empty,
+ DefKind::Closure,
+ expr.span,
+ ),
+ None => closure_def,
}
}
- ExprKind::Gen(_, _, _) => self.create_def(expr.id, DefPathData::ClosureExpr, expr.span),
+ ExprKind::Gen(_, _, _) => {
+ self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
+ }
+ ExprKind::ConstBlock(ref constant) => {
+ let def = self.create_def(
+ constant.id,
+ kw::Empty,
+ DefKind::InlineConst,
+ constant.value.span,
+ );
+ self.with_parent(def, |this| visit::walk_anon_const(this, constant));
+ return;
+ }
_ => self.parent_def,
};
@@ -305,9 +355,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
if p.is_placeholder {
self.visit_macro_invoc(p.id)
} else {
- self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
- visit::walk_param(this, p)
- })
+ self.with_impl_trait(ImplTraitContext::Universal, |this| visit::walk_param(this, p))
}
}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 93db6cfc4..542aff69e 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -27,10 +27,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span, SyntaxContext};
use thin_vec::{thin_vec, ThinVec};
-use crate::errors::{
- AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
- ExplicitUnsafeTraits,
-};
+use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
+use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
use crate::imports::{Import, ImportKind};
use crate::late::{PatternSource, Rib};
use crate::path_names_to_string;
@@ -979,7 +977,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path_span: path.span,
// intentionally converting to String, as the text would also be used as
// in suggestion context
- path_str: pprust::path_to_string(&path),
+ path_str: pprust::path_to_string(path),
})
}
VisResolutionError::AncestorOnly(span) => {
@@ -1421,14 +1419,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
"",
);
+ if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
+ err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span });
+ return;
+ }
+
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
return;
}
+
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
err.subdiagnostic(AddedMacroUse);
return;
}
+
if ident.name == kw::Default
&& let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
{
@@ -1444,7 +1449,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::All(ns),
- &parent_scope,
+ parent_scope,
None,
false,
None,
@@ -1697,6 +1702,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
err.span_label(ident.span, format!("private {descr}"));
+ let mut not_publicly_reexported = false;
if let Some((this_res, outer_ident)) = outermost_res {
let import_suggestions = self.lookup_import_candidates(
outer_ident,
@@ -1717,6 +1723,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
);
// If we suggest importing a public re-export, don't point at the definition.
if point_to_def && ident.span != outer_ident.span {
+ not_publicly_reexported = true;
err.span_label(
outer_ident.span,
format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()),
@@ -1749,10 +1756,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
+ let mut sugg_paths = vec![];
+ if let Some(mut def_id) = res.opt_def_id() {
+ // We can't use `def_path_str` in resolve.
+ let mut path = vec![def_id];
+ while let Some(parent) = self.tcx.opt_parent(def_id) {
+ def_id = parent;
+ if !def_id.is_top_level_module() {
+ path.push(def_id);
+ } else {
+ break;
+ }
+ }
+ // We will only suggest importing directly if it is accessible through that path.
+ let path_names: Option<Vec<String>> = path
+ .iter()
+ .rev()
+ .map(|def_id| {
+ self.tcx.opt_item_name(*def_id).map(|n| {
+ if def_id.is_top_level_module() {
+ "crate".to_string()
+ } else {
+ n.to_string()
+ }
+ })
+ })
+ .collect();
+ if let Some(def_id) = path.get(0)
+ && let Some(path) = path_names
+ {
+ if let Some(def_id) = def_id.as_local() {
+ if self.effective_visibilities.is_directly_public(def_id) {
+ sugg_paths.push((path, false));
+ }
+ } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
+ {
+ sugg_paths.push((path, false));
+ }
+ }
+ }
+
// Print the whole import chain to make it easier to see what happens.
let first_binding = binding;
let mut next_binding = Some(binding);
let mut next_ident = ident;
+ let mut path = vec![];
while let Some(binding) = next_binding {
let name = next_ident;
next_binding = match binding.kind {
@@ -1771,6 +1819,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
_ => None,
};
+ match binding.kind {
+ NameBindingKind::Import { import, .. } => {
+ for segment in import.module_path.iter().skip(1) {
+ path.push(segment.ident.to_string());
+ }
+ sugg_paths.push((
+ path.iter()
+ .cloned()
+ .chain(vec![ident.to_string()].into_iter())
+ .collect::<Vec<_>>(),
+ true, // re-export
+ ));
+ }
+ NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
+ }
let first = binding == first_binding;
let msg = format!(
"{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
@@ -1782,7 +1845,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
let mut note_span = MultiSpan::from_span(def_span);
if !first && binding.vis.is_public() {
- note_span.push_span_label(def_span, "consider importing it directly");
+ let desc = match binding.kind {
+ NameBindingKind::Import { .. } => "re-export",
+ _ => "directly",
+ };
+ note_span.push_span_label(def_span, format!("you could import this {desc}"));
}
// Final step in the import chain, point out if the ADT is `non_exhaustive`
// which is probably why this privacy violation occurred.
@@ -1796,6 +1863,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
err.span_note(note_span, msg);
}
+ // We prioritize shorter paths, non-core imports and direct imports over the alternatives.
+ sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
+ for (sugg, reexport) in sugg_paths {
+ if not_publicly_reexported {
+ break;
+ }
+ if sugg.len() <= 1 {
+ // A single path segment suggestion is wrong. This happens on circular imports.
+ // `tests/ui/imports/issue-55884-2.rs`
+ continue;
+ }
+ let path = sugg.join("::");
+ err.span_suggestion_verbose(
+ dedup_span,
+ format!(
+ "import `{ident}` {}",
+ if reexport { "through the re-export" } else { "directly" }
+ ),
+ path,
+ Applicability::MachineApplicable,
+ );
+ break;
+ }
err.emit();
}
@@ -1858,6 +1948,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Applicability::MaybeIncorrect,
)),
)
+ } else if ident.name == sym::core {
+ (
+ format!("maybe a missing crate `{ident}`?"),
+ Some((
+ vec![(ident.span, "std".to_string())],
+ "try using `std` instead of `core`".to_string(),
+ Applicability::MaybeIncorrect,
+ )),
+ )
} else if self.tcx.sess.is_rust_2015() {
(
format!("maybe a missing crate `{ident}`?"),
@@ -2028,7 +2127,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
},
)
});
- (format!("use of undeclared crate or module `{ident}`"), suggestion)
+ if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
+ ident,
+ ScopeSet::All(ValueNS),
+ parent_scope,
+ None,
+ false,
+ ignore_binding,
+ ) {
+ let descr = binding.res().descr();
+ (format!("{descr} `{ident}` is not a crate or module"), suggestion)
+ } else {
+ (format!("use of undeclared crate or module `{ident}`"), suggestion)
+ }
}
}
@@ -2596,6 +2707,7 @@ fn show_candidates(
path_strings.extend(core_path_strings);
path_strings.dedup_by(|a, b| a.0 == b.0);
}
+ accessible_path_strings.sort();
if !accessible_path_strings.is_empty() {
let (determiner, kind, name, through) =
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 4477b9672..503521692 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -115,7 +115,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
/// Update effective visibilities of bindings in the given module,
/// including their whole reexport chains.
fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
- assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+ assert!(self.r.module_map.contains_key(&module_id.to_def_id()));
let module = self.r.get_module(module_id.to_def_id()).unwrap();
let resolutions = self.r.resolutions(module);
@@ -186,7 +186,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
) -> Option<Option<Visibility>> {
match parent_id {
ParentId::Def(def_id) => (nominal_vis != self.current_private_vis
- && self.r.visibilities[&def_id] != self.current_private_vis)
+ && self.r.tcx.local_visibility(def_id) != self.current_private_vis)
.then_some(Some(self.current_private_vis)),
ParentId::Import(_) => Some(None),
}
@@ -222,7 +222,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
}
fn update_field(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
- self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id));
+ self.update_def(def_id, self.r.tcx.local_visibility(def_id), ParentId::Def(parent_id));
}
}
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 72ff959bb..1fdb193e5 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -666,6 +666,13 @@ pub(crate) struct ExplicitUnsafeTraits {
}
#[derive(Subdiagnostic)]
+#[note(resolve_missing_macro_rules_name)]
+pub(crate) struct MaybeMissingMacroRulesName {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
#[help(resolve_added_macro_use)]
pub(crate) struct AddedMacroUse;
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 1a50bd5ec..a9f7002e5 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -240,7 +240,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
{
// The macro is a proc macro derive
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
- let ext = self.get_macro_by_def_id(def_id).ext;
+ let ext = &self.get_macro_by_def_id(def_id).ext;
if ext.builtin_name.is_none()
&& ext.macro_kind() == MacroKind::Derive
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
@@ -1201,7 +1201,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
};
self.report_error(span, error);
- self.tcx.sess.delay_span_bug(span, CG_BUG_STR);
+ self.tcx.sess.span_delayed_bug(span, CG_BUG_STR);
}
return Res::Err;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index b34790a92..39e82da6d 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -8,7 +8,7 @@ use crate::errors::{
ItemsInTraitsAreNotImportable,
};
use crate::Determinacy::{self, *};
-use crate::{fluent_generated as fluent, Namespace::*};
+use crate::Namespace::*;
use crate::{module_to_string, names_to_string, ImportSuggestion};
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
@@ -477,6 +477,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.per_ns(|this, ns| {
let key = BindingKey::new(target, ns);
let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
+ this.update_resolution(import.parent_scope.module, key, false, |_, resolution| {
+ resolution.single_imports.remove(&import);
+ })
});
self.record_use(target, dummy_binding, false);
} else if import.imported_module.get().is_none() {
@@ -708,7 +711,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.tcx,
&mut diag,
Some(err.span),
- &candidates,
+ candidates,
DiagnosticMode::Import,
(source != target)
.then(|| format!(" as {target}"))
@@ -720,7 +723,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.tcx,
&mut diag,
None,
- &candidates,
+ candidates,
DiagnosticMode::Normal,
(source != target)
.then(|| format!(" as {target}"))
@@ -987,13 +990,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
if !is_prelude
&& let Some(max_vis) = max_vis.get()
- && !max_vis.is_at_least(import.expect_vis(), self.tcx)
+ && let import_vis = import.expect_vis()
+ && !max_vis.is_at_least(import_vis, self.tcx)
{
- self.lint_buffer.buffer_lint(
+ let def_id = self.local_def_id(id);
+ let msg = format!(
+ "glob import doesn't reexport anything with visibility `{}` because no imported item is public enough",
+ import_vis.to_string(def_id, self.tcx)
+ );
+ self.lint_buffer.buffer_lint_with_diagnostic(
UNUSED_IMPORTS,
id,
import.span,
- fluent::resolve_glob_import_doesnt_reexport,
+ msg,
+ BuiltinLintDiagnostics::RedundantImportVisibility {
+ max_vis: max_vis.to_string(def_id, self.tcx),
+ span: import.span,
+ },
);
}
return None;
@@ -1050,16 +1063,12 @@ 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();
+ let has_ambiguity_error =
+ this.ambiguity_errors.iter().any(|error| !error.warning);
if res == Res::Err || has_ambiguity_error {
this.tcx
.sess
- .delay_span_bug(import.span, "some error happened for an import");
+ .span_delayed_bug(import.span, "some error happened for an import");
return;
}
if let Ok(initial_res) = initial_res {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3be962dab..cf50f630b 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -603,6 +603,8 @@ struct DiagnosticMetadata<'ast> {
/// Only used for better errors on `let <pat>: <expr, not type>;`.
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
+ current_pat: Option<&'ast Pat>,
+
/// Used to detect possible `if let` written without `let` and to provide structured suggestion.
in_if_condition: Option<&'ast Expr>,
@@ -703,6 +705,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
fn visit_expr(&mut self, expr: &'ast Expr) {
self.resolve_expr(expr, None);
}
+ fn visit_pat(&mut self, p: &'ast Pat) {
+ let prev = self.diagnostic_metadata.current_pat;
+ self.diagnostic_metadata.current_pat = Some(p);
+ visit::walk_pat(self, p);
+ self.diagnostic_metadata.current_pat = prev;
+ }
fn visit_local(&mut self, local: &'ast Local) {
let local_spans = match local.pat.kind {
// We check for this to avoid tuple struct fields.
@@ -731,7 +739,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
}
TyKind::Path(qself, path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
- self.smart_resolve_path(ty.id, &qself, path, PathSource::Type);
+ self.smart_resolve_path(ty.id, qself, path, PathSource::Type);
// Check whether we should interpret this as a bare trait object.
if qself.is_none()
@@ -751,7 +759,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
kind: LifetimeBinderKind::PolyTrait,
span,
},
- |this| this.visit_path(&path, ty.id),
+ |this| this.visit_path(path, ty.id),
);
} else {
visit::walk_ty(self, ty)
@@ -908,8 +916,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&sig.decl.output,
);
- if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
- this.record_lifetime_params_for_impl_trait(async_node_id);
+ if let Some((coro_node_id, _)) = sig
+ .header
+ .coroutine_kind
+ .map(|coroutine_kind| coroutine_kind.return_id())
+ {
+ this.record_lifetime_params_for_impl_trait(coro_node_id);
}
},
);
@@ -932,12 +944,15 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
this.visit_generics(generics);
let declaration = &sig.decl;
- let async_node_id = sig.header.asyncness.opt_return_id();
+ let coro_node_id = sig
+ .header
+ .coroutine_kind
+ .map(|coroutine_kind| coroutine_kind.return_id());
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
binder: fn_id,
- report_in_path: async_node_id.is_some(),
+ report_in_path: coro_node_id.is_some(),
},
|this| {
this.resolve_fn_signature(
@@ -950,7 +965,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&declaration.output,
);
- if let Some((async_node_id, _)) = async_node_id {
+ if let Some((async_node_id, _)) = coro_node_id {
this.record_lifetime_params_for_impl_trait(async_node_id);
}
},
@@ -1035,7 +1050,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
ClosureBinder::NotPresent => {}
ClosureBinder::For { generic_params, .. } => {
self.visit_generic_params(
- &generic_params,
+ generic_params,
self.diagnostic_metadata.current_self_item.is_some(),
);
}
@@ -1179,7 +1194,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
{
let span = predicate_span.shrink_to_lo().to(bounded_ty.span.shrink_to_lo());
this.with_generic_param_rib(
- &bound_generic_params,
+ bound_generic_params,
RibKind::Normal,
LifetimeRibKind::Generics {
binder: bounded_ty.id,
@@ -1187,7 +1202,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
span,
},
|this| {
- this.visit_generic_params(&bound_generic_params, false);
+ this.visit_generic_params(bound_generic_params, false);
this.visit_ty(bounded_ty);
for bound in bounds {
this.visit_param_bound(bound, BoundKind::Bound)
@@ -1989,7 +2004,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
} else {
LifetimeRibKind::ElisionFailure
};
- self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty));
+ self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, output_ty));
let elision_failures =
replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures);
if !elision_failures.is_empty() {
@@ -2371,7 +2386,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
&item.attrs,
generics,
of_trait,
- &self_ty,
+ self_ty,
item.id,
impl_items,
);
@@ -2735,7 +2750,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
/// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
let trait_assoc_items =
- replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
+ replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(trait_items));
let walk_assoc_item =
|this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| {
@@ -3063,17 +3078,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
debug!(?binding);
}
+
+ let feed_visibility = |this: &mut Self, def_id| {
+ let vis = this.r.tcx.visibility(def_id).expect_local();
+ this.r.feed_visibility(this.r.local_def_id(id), vis);
+ };
+
let Some(binding) = binding else {
// We could not find the method: report an error.
let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
let path_names = path_names_to_string(path);
self.report_error(span, err(ident, path_names, candidate));
+ feed_visibility(self, module.def_id());
return;
};
let res = binding.res();
let Res::Def(def_kind, id_in_trait) = res else { bug!() };
+ feed_visibility(self, id_in_trait);
match seen_trait_items.entry(id_in_trait) {
Entry::Occupied(entry) => {
@@ -3286,7 +3309,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
walk_list!(this, visit_expr, &arm.guard);
- this.visit_expr(&arm.body);
+ walk_list!(this, visit_expr, &arm.body);
});
}
@@ -3536,7 +3559,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
Res::SelfCtor(_) => {
// We resolve `Self` in pattern position as an ident sometimes during recovery,
// so delay a bug instead of ICEing.
- self.r.tcx.sess.delay_span_bug(
+ self.r.tcx.sess.span_delayed_bug(
ident.span,
"unexpected `SelfCtor` in pattern, expected identifier"
);
@@ -3937,7 +3960,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
)));
}
- let result = match self.resolve_path(&path, Some(ns), Some(finalize)) {
+ let result = match self.resolve_path(path, Some(ns), Some(finalize)) {
PathResult::NonModule(path_res) => path_res,
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
PartialRes::new(module.res().unwrap())
@@ -4200,7 +4223,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ExprKind::Break(None, Some(ref e)) => {
// We use this instead of `visit::walk_expr` to keep the parent expr around for
// better diagnostics.
- self.resolve_expr(e, Some(&expr));
+ self.resolve_expr(e, Some(expr));
}
ExprKind::Let(ref pat, ref scrutinee, _, _) => {
@@ -4221,7 +4244,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
ExprKind::Loop(ref block, label, _) => {
- self.resolve_labeled_block(label, expr.id, &block)
+ self.resolve_labeled_block(label, expr.id, block)
}
ExprKind::While(ref cond, ref block, label) => {
@@ -4280,8 +4303,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// `async |x| ...` gets desugared to `|x| async {...}`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
// closure are detected as upvars rather than normal closure arg usages.
+ //
+ // Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too.
ExprKind::Closure(box ast::Closure {
- asyncness: Async::Yes { .. },
+ coroutine_kind: Some(_),
ref fn_decl,
ref body,
..
@@ -4310,7 +4335,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
..
}) => {
self.with_generic_param_rib(
- &generic_params,
+ generic_params,
RibKind::Normal,
LifetimeRibKind::Generics {
binder: expr.id,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index fd5d6fabf..d767ed741 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,12 +1,14 @@
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
+use crate::ty::fast_reject::SimplifiedType;
use crate::{errors, path_names_to_string};
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
use rustc_hir::def::Namespace::{self, *};
-use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
+use rustc_ast::ptr::P;
+use rustc_ast::visit::{walk_ty, FnCtxt, FnKind, LifetimeCtxt, Visitor};
use rustc_ast::{
self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
@@ -15,7 +17,7 @@ use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
- MultiSpan,
+ MultiSpan, SuggestionStyle,
};
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
@@ -29,6 +31,8 @@ use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
+use rustc_middle::ty;
+
use std::borrow::Cow;
use std::iter;
use std::ops::Deref;
@@ -431,6 +435,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
code,
);
+ self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
if let Some((span, label)) = base_error.span_label {
@@ -739,6 +744,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err,
span,
source,
+ path,
res,
&path_str,
&base_error.fallback_label,
@@ -901,7 +907,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
// If the trait has a single item (which wasn't matched by the algorithm), suggest it
- let suggestion = self.get_single_associated_item(&path, &source, is_expected);
+ let suggestion = self.get_single_associated_item(path, &source, is_expected);
if !self.r.add_typo_suggestion(err, suggestion, ident_span) {
fallback = !self.let_binding_suggestion(err, ident_span);
}
@@ -1063,6 +1069,32 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
true
}
+ fn suggest_at_operator_in_slice_pat_with_range(
+ &mut self,
+ err: &mut Diagnostic,
+ path: &[Segment],
+ ) {
+ if let Some(pat) = self.diagnostic_metadata.current_pat
+ && let ast::PatKind::Range(Some(start), None, range) = &pat.kind
+ && let ExprKind::Path(None, range_path) = &start.kind
+ && let [segment] = &range_path.segments[..]
+ && let [s] = path
+ && segment.ident == s.ident
+ {
+ // We've encountered `[first, rest..]` where the user might have meant
+ // `[first, rest @ ..]` (#88404).
+ err.span_suggestion_verbose(
+ segment.ident.span.between(range.span),
+ format!(
+ "if you meant to collect the rest of the slice in `{}`, use the at operator",
+ segment.ident,
+ ),
+ " @ ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
fn suggest_swapping_misplaced_self_ty_and_trait(
&mut self,
err: &mut Diagnostic,
@@ -1297,6 +1329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic,
span: Span,
source: PathSource<'_>,
+ path: &[Segment],
res: Res,
path_str: &str,
fallback_label: &str,
@@ -1304,7 +1337,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let ns = source.namespace();
let is_expected = &|res| source.is_expected(res);
- let path_sep = |err: &mut Diagnostic, expr: &Expr, kind: DefKind| {
+ let path_sep = |this: &mut Self, err: &mut Diagnostic, expr: &Expr, kind: DefKind| {
const MESSAGE: &str = "use the path separator to refer to an item";
let (lhs_span, rhs_span) = match &expr.kind {
@@ -1325,7 +1358,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
true
} else if kind == DefKind::Struct
&& let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
- && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
+ && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
{
// The LHS is a type that originates from a macro call.
// We have to add angle brackets around it.
@@ -1360,13 +1393,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
};
- let mut bad_struct_syntax_suggestion = |def_id: DefId| {
- let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
+ let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| {
+ let (followed_by_brace, closing_brace) = this.followed_by_brace(span);
match source {
PathSource::Expr(Some(
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
- )) if path_sep(err, &parent, DefKind::Struct) => {}
+ )) if path_sep(this, err, parent, DefKind::Struct) => {}
PathSource::Expr(
None
| Some(Expr {
@@ -1403,7 +1436,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
let span = find_span(&source, err);
- err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
+ err.span_label(this.r.def_span(def_id), format!("`{path_str}` defined here"));
let (tail, descr, applicability, old_fields) = match source {
PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
@@ -1413,50 +1446,69 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
Applicability::MachineApplicable,
Some(
args.iter()
- .map(|a| self.r.tcx.sess.source_map().span_to_snippet(*a).ok())
+ .map(|a| this.r.tcx.sess.source_map().span_to_snippet(*a).ok())
.collect::<Vec<Option<String>>>(),
),
),
_ => (": val", "literal", Applicability::HasPlaceholders, None),
};
- let field_ids = self.r.field_def_ids(def_id);
- let (fields, applicability) = match field_ids {
- Some(field_ids) => {
- let fields = field_ids.iter().map(|&id| self.r.tcx.item_name(id));
-
- let fields = if let Some(old_fields) = old_fields {
- fields
- .enumerate()
- .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
- }
- })
- .collect::<Vec<String>>()
- } else {
- fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>()
- };
- (fields.join(", "), applicability)
- }
- None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
- };
- let pad = match field_ids {
- Some(field_ids) if field_ids.is_empty() => "",
- _ => " ",
- };
- err.span_suggestion(
- span,
- format!("use struct {descr} syntax instead"),
- format!("{path_str} {{{pad}{fields}{pad}}}"),
- applicability,
- );
+ if !this.has_private_fields(def_id) {
+ // If the fields of the type are private, we shouldn't be suggesting using
+ // the struct literal syntax at all, as that will cause a subsequent error.
+ let field_ids = this.r.field_def_ids(def_id);
+ let (fields, applicability) = match field_ids {
+ Some(field_ids) => {
+ let fields = field_ids.iter().map(|&id| this.r.tcx.item_name(id));
+
+ let fields = if let Some(old_fields) = old_fields {
+ fields
+ .enumerate()
+ .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
+ }
+ })
+ .collect::<Vec<String>>()
+ } else {
+ fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>()
+ };
+
+ (fields.join(", "), applicability)
+ }
+ None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
+ };
+ let pad = match field_ids {
+ Some(field_ids) if field_ids.is_empty() => "",
+ _ => " ",
+ };
+ err.span_suggestion(
+ span,
+ format!("use struct {descr} syntax instead"),
+ format!("{path_str} {{{pad}{fields}{pad}}}"),
+ applicability,
+ );
+ }
+ if let PathSource::Expr(Some(Expr {
+ kind: ExprKind::Call(path, ref args),
+ span: call_span,
+ ..
+ })) = source
+ {
+ this.suggest_alternative_construction_methods(
+ def_id,
+ err,
+ path.span,
+ *call_span,
+ &args[..],
+ );
+ }
}
_ => {
err.span_label(span, fallback_label.to_string());
@@ -1473,12 +1525,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
| PathSource::Struct,
) => {
err.span_label(span, fallback_label.to_string());
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "use `!` to invoke the macro",
- "!",
- Applicability::MaybeIncorrect,
- );
+
+ // Don't suggest `!` for a macro invocation if there are generic args
+ if path
+ .last()
+ .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
+ {
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "use `!` to invoke the macro",
+ "!",
+ Applicability::MaybeIncorrect,
+ );
+ }
+
if path_str == "try" && span.is_rust_2015() {
err.note("if you want the `try` keyword, you need Rust 2018 or later");
}
@@ -1506,7 +1566,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
PathSource::Expr(Some(parent)),
) => {
- if !path_sep(err, &parent, kind) {
+ if !path_sep(self, err, parent, kind) {
return false;
}
}
@@ -1540,13 +1600,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor {
if let PathSource::Expr(Some(parent)) = source {
if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
- bad_struct_syntax_suggestion(def_id);
+ bad_struct_syntax_suggestion(self, def_id);
return true;
}
}
struct_ctor
} else {
- bad_struct_syntax_suggestion(def_id);
+ bad_struct_syntax_suggestion(self, def_id);
return true;
};
@@ -1566,30 +1626,21 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
Some(Vec::from(pattern_spans))
}
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
- _ if source.is_call() => {
+ PathSource::Expr(Some(Expr {
+ kind: ExprKind::Call(path, ref args),
+ span: call_span,
+ ..
+ })) => {
err.set_primary_message(
"cannot initialize a tuple struct which contains private fields",
);
- if !def_id.is_local()
- && self
- .r
- .tcx
- .inherent_impls(def_id)
- .iter()
- .flat_map(|impl_def_id| {
- self.r.tcx.provided_trait_methods(*impl_def_id)
- })
- .any(|assoc| !assoc.fn_has_self_parameter && assoc.name == sym::new)
- {
- // FIXME: look for associated functions with Self return type,
- // instead of relying only on the name and lack of self receiver.
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "you might have meant to use the `new` associated function",
- "::new".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
+ self.suggest_alternative_construction_methods(
+ def_id,
+ err,
+ path.span,
+ *call_span,
+ &args[..],
+ );
// Use spans of the tuple struct definition.
self.r.field_def_ids(def_id).map(|field_ids| {
field_ids
@@ -1636,7 +1687,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_label(span, "constructor is not visible here due to private fields");
}
(Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => {
- bad_struct_syntax_suggestion(def_id);
+ bad_struct_syntax_suggestion(self, def_id);
}
(Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
match source {
@@ -1682,6 +1733,156 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
true
}
+ fn suggest_alternative_construction_methods(
+ &mut self,
+ def_id: DefId,
+ err: &mut Diagnostic,
+ path_span: Span,
+ call_span: Span,
+ args: &[P<Expr>],
+ ) {
+ if def_id.is_local() {
+ // Doing analysis on local `DefId`s would cause infinite recursion.
+ return;
+ }
+ // Look at all the associated functions without receivers in the type's
+ // inherent impls to look for builders that return `Self`
+ let mut items = self
+ .r
+ .tcx
+ .inherent_impls(def_id)
+ .iter()
+ .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
+ // Only assoc fn with no receivers.
+ .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
+ .filter_map(|item| {
+ // Only assoc fns that return `Self`
+ let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
+ let ret_ty = fn_sig.output();
+ let ret_ty = self
+ .r
+ .tcx
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), ret_ty);
+ let ty::Adt(def, _args) = ret_ty.kind() else {
+ return None;
+ };
+ let input_len = fn_sig.inputs().skip_binder().len();
+ if def.did() != def_id {
+ return None;
+ }
+ let order = !item.name.as_str().starts_with("new");
+ Some((order, item.name, input_len))
+ })
+ .collect::<Vec<_>>();
+ items.sort_by_key(|(order, _, _)| *order);
+ let suggestion = |name, args| {
+ format!(
+ "::{name}({})",
+ std::iter::repeat("_").take(args).collect::<Vec<_>>().join(", ")
+ )
+ };
+ match &items[..] {
+ [] => {}
+ [(_, name, len)] if *len == args.len() => {
+ err.span_suggestion_verbose(
+ path_span.shrink_to_hi(),
+ format!("you might have meant to use the `{name}` associated function",),
+ format!("::{name}"),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ [(_, name, len)] => {
+ err.span_suggestion_verbose(
+ path_span.shrink_to_hi().with_hi(call_span.hi()),
+ format!("you might have meant to use the `{name}` associated function",),
+ suggestion(name, *len),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_suggestions_with_style(
+ path_span.shrink_to_hi().with_hi(call_span.hi()),
+ "you might have meant to use an associated function to build this type",
+ items
+ .iter()
+ .map(|(_, name, len)| suggestion(name, *len))
+ .collect::<Vec<String>>(),
+ Applicability::MaybeIncorrect,
+ SuggestionStyle::ShowAlways,
+ );
+ }
+ }
+ // We'd ideally use `type_implements_trait` but don't have access to
+ // the trait solver here. We can't use `get_diagnostic_item` or
+ // `all_traits` in resolve either. So instead we abuse the import
+ // suggestion machinery to get `std::default::Default` and perform some
+ // checks to confirm that we got *only* that trait. We then see if the
+ // Adt we have has a direct implementation of `Default`. If so, we
+ // provide a structured suggestion.
+ let default_trait = self
+ .r
+ .lookup_import_candidates(
+ Ident::with_dummy_span(sym::Default),
+ Namespace::TypeNS,
+ &self.parent_scope,
+ &|res: Res| matches!(res, Res::Def(DefKind::Trait, _)),
+ )
+ .iter()
+ .filter_map(|candidate| candidate.did)
+ .find(|did| {
+ self.r
+ .tcx
+ .get_attrs(*did, sym::rustc_diagnostic_item)
+ .any(|attr| attr.value_str() == Some(sym::Default))
+ });
+ let Some(default_trait) = default_trait else {
+ return;
+ };
+ if self
+ .r
+ .extern_crate_map
+ .iter()
+ // FIXME: This doesn't include impls like `impl Default for String`.
+ .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait)))
+ .filter_map(|(_, simplified_self_ty)| *simplified_self_ty)
+ .filter_map(|simplified_self_ty| match simplified_self_ty {
+ SimplifiedType::Adt(did) => Some(did),
+ _ => None,
+ })
+ .any(|did| did == def_id)
+ {
+ err.multipart_suggestion(
+ "consider using the `Default` trait",
+ vec![
+ (path_span.shrink_to_lo(), "<".to_string()),
+ (
+ path_span.shrink_to_hi().with_hi(call_span.hi()),
+ " as std::default::Default>::default()".to_string(),
+ ),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
+ fn has_private_fields(&self, def_id: DefId) -> bool {
+ let fields = match def_id.as_local() {
+ Some(def_id) => self.r.struct_constructors.get(&def_id).cloned().map(|(_, _, f)| f),
+ None => Some(
+ self.r
+ .tcx
+ .associated_item_def_ids(def_id)
+ .iter()
+ .map(|field_id| self.r.tcx.visibility(field_id))
+ .collect(),
+ ),
+ };
+
+ fields.is_some_and(|fields| {
+ fields.iter().any(|vis| !self.r.is_accessible_from(*vis, self.parent_scope.module))
+ })
+ }
+
/// Given the target `ident` and `kind`, search for the similarly named associated item
/// in `self.current_trait_ref`.
pub(crate) fn find_similarly_named_assoc_item(
@@ -1966,13 +2167,22 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) =
self.diagnostic_metadata.in_assignment
- && let ast::ExprKind::Path(None, _) = lhs.kind
+ && let ast::ExprKind::Path(None, ref path) = lhs.kind
{
if !ident_span.from_expansion() {
+ let (span, text) = match path.segments.first() {
+ Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => {
+ // a special case for #117894
+ let name = name.strip_prefix('_').unwrap_or(name);
+ (ident_span, format!("let {name}"))
+ }
+ _ => (ident_span.shrink_to_lo(), "let ".to_string()),
+ };
+
err.span_suggestion_verbose(
- ident_span.shrink_to_lo(),
+ span,
"you might have meant to introduce a new binding",
- "let ".to_string(),
+ text,
Applicability::MaybeIncorrect,
);
return true;
@@ -2062,11 +2272,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
// suggest path with added parentheses.
- let suggestable_variants = variants
+ let mut suggestable_variants = variants
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
.map(|(variant, ..)| path_names_to_string(variant))
.collect::<Vec<_>>();
+ suggestable_variants.sort();
let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
@@ -2117,7 +2328,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
};
- let suggestable_variants = variants
+ let mut suggestable_variants = variants
.iter()
.filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
@@ -2126,6 +2337,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
CtorKind::Fn => format!("({variant}())"),
})
.collect::<Vec<_>>();
+ suggestable_variants.sort();
let no_suggestable_variant = suggestable_variants.is_empty();
if !no_suggestable_variant {
@@ -2143,7 +2355,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
);
}
- let suggestable_variants_with_placeholders = variants
+ let mut suggestable_variants_with_placeholders = variants
.iter()
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
@@ -2152,6 +2364,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
_ => None,
})
.collect::<Vec<_>>();
+ suggestable_variants_with_placeholders.sort();
if !suggestable_variants_with_placeholders.is_empty() {
let msg =
@@ -2612,6 +2825,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.collect();
debug!(?in_scope_lifetimes);
+ let mut maybe_static = false;
debug!(?function_param_lifetimes);
if let Some((param_lifetimes, params)) = &function_param_lifetimes {
let elided_len = param_lifetimes.len();
@@ -2650,10 +2864,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if num_params == 0 {
err.help(
- "this function's return type contains a borrowed value, \
- but there is no value for it to be borrowed from",
+ "this function's return type contains a borrowed value, but there is no value \
+ for it to be borrowed from",
);
if in_scope_lifetimes.is_empty() {
+ maybe_static = true;
in_scope_lifetimes = vec![(
Ident::with_dummy_span(kw::StaticLifetime),
(DUMMY_NODE_ID, LifetimeRes::Static),
@@ -2661,11 +2876,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
} else if elided_len == 0 {
err.help(
- "this function's return type contains a borrowed value with \
- an elided lifetime, but the lifetime cannot be derived from \
- the arguments",
+ "this function's return type contains a borrowed value with an elided \
+ lifetime, but the lifetime cannot be derived from the arguments",
);
if in_scope_lifetimes.is_empty() {
+ maybe_static = true;
in_scope_lifetimes = vec![(
Ident::with_dummy_span(kw::StaticLifetime),
(DUMMY_NODE_ID, LifetimeRes::Static),
@@ -2673,13 +2888,13 @@ 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 {m} it is borrowed from"
+ "this function's return type contains a borrowed value, 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}"
+ "this function's return type contains a borrowed value, but the signature does \
+ not say whether it is borrowed from {m}",
));
}
}
@@ -2744,11 +2959,238 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
);
}
1 => {
+ let post = if maybe_static {
+ let owned = if let [lt] = &lifetime_refs[..]
+ && lt.kind != MissingLifetimeKind::Ampersand
+ {
+ ", or if you will only have owned values"
+ } else {
+ ""
+ };
+ format!(
+ ", but this is uncommon unless you're returning a borrowed value from a \
+ `const` or a `static`{owned}",
+ )
+ } else {
+ String::new()
+ };
err.multipart_suggestion_verbose(
- format!("consider using the `{existing_name}` lifetime"),
+ format!("consider using the `{existing_name}` lifetime{post}"),
spans_suggs,
Applicability::MaybeIncorrect,
);
+ if maybe_static {
+ // FIXME: what follows are general suggestions, but we'd want to perform some
+ // minimal flow analysis to provide more accurate suggestions. For example, if
+ // we identified that the return expression references only one argument, we
+ // would suggest borrowing only that argument, and we'd skip the prior
+ // "use `'static`" suggestion entirely.
+ if let [lt] = &lifetime_refs[..]
+ && (lt.kind == MissingLifetimeKind::Ampersand
+ || lt.kind == MissingLifetimeKind::Underscore)
+ {
+ let pre = if lt.kind == MissingLifetimeKind::Ampersand
+ && let Some((kind, _span)) = self.diagnostic_metadata.current_function
+ && let FnKind::Fn(_, _, sig, _, _, _) = kind
+ && !sig.decl.inputs.is_empty()
+ && let sugg = sig
+ .decl
+ .inputs
+ .iter()
+ .filter_map(|param| {
+ if param.ty.span.contains(lt.span) {
+ // We don't want to suggest `fn elision(_: &fn() -> &i32)`
+ // when we have `fn elision(_: fn() -> &i32)`
+ None
+ } else if let TyKind::CVarArgs = param.ty.kind {
+ // Don't suggest `&...` for ffi fn with varargs
+ None
+ } else if let TyKind::ImplTrait(..) = &param.ty.kind {
+ // We handle these in the next `else if` branch.
+ None
+ } else {
+ Some((param.ty.span.shrink_to_lo(), "&".to_string()))
+ }
+ })
+ .collect::<Vec<_>>()
+ && !sugg.is_empty()
+ {
+ let (the, s) = if sig.decl.inputs.len() == 1 {
+ ("the", "")
+ } else {
+ ("one of the", "s")
+ };
+ err.multipart_suggestion_verbose(
+ format!(
+ "instead, you are more likely to want to change {the} \
+ argument{s} to be borrowed...",
+ ),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ "...or alternatively, you might want"
+ } else if (lt.kind == MissingLifetimeKind::Ampersand
+ || lt.kind == MissingLifetimeKind::Underscore)
+ && let Some((kind, _span)) = self.diagnostic_metadata.current_function
+ && let FnKind::Fn(_, _, sig, _, _, _) = kind
+ && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
+ && !sig.decl.inputs.is_empty()
+ && let arg_refs = sig
+ .decl
+ .inputs
+ .iter()
+ .filter_map(|param| match &param.ty.kind {
+ TyKind::ImplTrait(_, bounds) => Some(bounds),
+ _ => None,
+ })
+ .flat_map(|bounds| bounds.into_iter())
+ .collect::<Vec<_>>()
+ && !arg_refs.is_empty()
+ {
+ // We have a situation like
+ // fn g(mut x: impl Iterator<Item = &()>) -> Option<&()>
+ // So we look at every ref in the trait bound. If there's any, we
+ // suggest
+ // fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()>
+ let mut lt_finder =
+ LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
+ for bound in arg_refs {
+ if let ast::GenericBound::Trait(trait_ref, _) = bound {
+ lt_finder.visit_trait_ref(&trait_ref.trait_ref);
+ }
+ }
+ lt_finder.visit_ty(ret_ty);
+ let spans_suggs: Vec<_> = lt_finder
+ .seen
+ .iter()
+ .filter_map(|ty| match &ty.kind {
+ TyKind::Ref(_, mut_ty) => {
+ let span = ty.span.with_hi(mut_ty.ty.span.lo());
+ Some((span, "&'a ".to_string()))
+ }
+ _ => None,
+ })
+ .collect();
+ self.suggest_introducing_lifetime(
+ err,
+ None,
+ |err, higher_ranked, span, message, intro_sugg| {
+ err.multipart_suggestion_verbose(
+ message,
+ std::iter::once((span, intro_sugg))
+ .chain(spans_suggs.iter().cloned())
+ .collect(),
+ Applicability::MaybeIncorrect,
+ );
+ higher_ranked
+ },
+ );
+ "alternatively, you might want"
+ } else {
+ "instead, you are more likely to want"
+ };
+ let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
+ let mut sugg = vec![(lt.span, String::new())];
+ if let Some((kind, _span)) = self.diagnostic_metadata.current_function
+ && let FnKind::Fn(_, _, sig, _, _, _) = kind
+ && let ast::FnRetTy::Ty(ty) = &sig.decl.output
+ {
+ let mut lt_finder =
+ LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
+ lt_finder.visit_ty(&ty);
+
+ if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
+ &lt_finder.seen[..]
+ {
+ // We might have a situation like
+ // fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
+ // but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
+ // we need to find a more accurate span to end up with
+ // fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
+ sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
+ owned_sugg = true;
+ }
+ if let Some(ty) = lt_finder.found {
+ if let TyKind::Path(None, path) = &ty.kind {
+ // Check if the path being borrowed is likely to be owned.
+ let path: Vec<_> = Segment::from_path(path);
+ match self.resolve_path(&path, Some(TypeNS), None) {
+ PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
+ match module.res() {
+ Some(Res::PrimTy(PrimTy::Str)) => {
+ // Don't suggest `-> str`, suggest `-> String`.
+ sugg = vec![(
+ lt.span.with_hi(ty.span.hi()),
+ "String".to_string(),
+ )];
+ }
+ Some(Res::PrimTy(..)) => {}
+ Some(Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::ForeignTy
+ | DefKind::AssocTy
+ | DefKind::OpaqueTy
+ | DefKind::TyParam,
+ _,
+ )) => {}
+ _ => {
+ // Do not suggest in all other cases.
+ owned_sugg = false;
+ }
+ }
+ }
+ PathResult::NonModule(res) => {
+ match res.base_res() {
+ Res::PrimTy(PrimTy::Str) => {
+ // Don't suggest `-> str`, suggest `-> String`.
+ sugg = vec![(
+ lt.span.with_hi(ty.span.hi()),
+ "String".to_string(),
+ )];
+ }
+ Res::PrimTy(..) => {}
+ Res::Def(
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::ForeignTy
+ | DefKind::AssocTy
+ | DefKind::OpaqueTy
+ | DefKind::TyParam,
+ _,
+ ) => {}
+ _ => {
+ // Do not suggest in all other cases.
+ owned_sugg = false;
+ }
+ }
+ }
+ _ => {
+ // Do not suggest in all other cases.
+ owned_sugg = false;
+ }
+ }
+ }
+ if let TyKind::Slice(inner_ty) = &ty.kind {
+ // Don't suggest `-> [T]`, suggest `-> Vec<T>`.
+ sugg = vec![
+ (lt.span.with_hi(inner_ty.span.lo()), "Vec<".to_string()),
+ (ty.span.with_lo(inner_ty.span.hi()), ">".to_string()),
+ ];
+ }
+ }
+ }
+ if owned_sugg {
+ err.multipart_suggestion_verbose(
+ format!("{pre} to return an owned value"),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
// Record as using the suggested resolution.
let (_, (_, res)) = in_scope_lifetimes[0];
@@ -2778,7 +3220,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn mk_where_bound_predicate(
path: &Path,
poly_trait_ref: &ast::PolyTraitRef,
- ty: &ast::Ty,
+ ty: &Ty,
) -> Option<ast::WhereBoundPredicate> {
use rustc_span::DUMMY_SP;
let modified_segments = {
@@ -2855,6 +3297,24 @@ pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: I
err.emit();
}
+struct LifetimeFinder<'ast> {
+ lifetime: Span,
+ found: Option<&'ast Ty>,
+ seen: Vec<&'ast Ty>,
+}
+
+impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
+ fn visit_ty(&mut self, t: &'ast Ty) {
+ if let TyKind::Ref(_, mut_ty) = &t.kind {
+ self.seen.push(t);
+ if t.span.lo() == self.lifetime.lo() {
+ self.found = Some(&mut_ty.ty);
+ }
+ }
+ walk_ty(self, t)
+ }
+}
+
/// Shadowing involving a label is only a warning for historical reasons.
//FIXME: make this a proper lint.
pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 501747df5..75ec594eb 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -7,8 +7,8 @@
//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(extract_if)]
@@ -37,18 +37,14 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
-use rustc_errors::{
- Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
-};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
use rustc_feature::BUILTIN_ATTRIBUTES;
-use rustc_fluent_macro::fluent_messages;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::NonMacroAttrKind;
use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::definitions::DefPathData;
use rustc_hir::{PrimTy, TraitCandidate};
use rustc_index::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
@@ -90,7 +86,7 @@ mod late;
mod macros;
pub mod rustdoc;
-fluent_messages! { "../messages.ftl" }
+rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
#[derive(Debug)]
enum Weak {
@@ -175,7 +171,7 @@ impl<'a> ParentScope<'a> {
#[derive(Copy, Debug, Clone)]
enum ImplTraitContext {
Existential,
- Universal(LocalDefId),
+ Universal,
}
#[derive(Debug)]
@@ -927,9 +923,16 @@ struct DeriveData {
#[derive(Clone)]
struct MacroData {
ext: Lrc<SyntaxExtension>,
+ rule_spans: Vec<(usize, Span)>,
macro_rules: bool,
}
+impl MacroData {
+ fn new(ext: Lrc<SyntaxExtension>) -> MacroData {
+ MacroData { ext, rule_spans: Vec::new(), macro_rules: false }
+ }
+}
+
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
@@ -1004,8 +1007,7 @@ pub struct Resolver<'a, 'tcx> {
/// Maps glob imports to the names of items actually imported.
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
- /// Visibilities in "lowered" form, for all entities that have them.
- visibilities: FxHashMap<LocalDefId, ty::Visibility>,
+ visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@@ -1030,15 +1032,12 @@ pub struct Resolver<'a, 'tcx> {
used_extern_options: FxHashSet<Symbol>,
macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
- /// A small map keeping true kinds of built-in macros that appear to be fn-like on
- /// the surface (`macro` items in libcore), but are actually attributes or derives.
- builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
registered_tools: &'tcx RegisteredTools,
macro_use_prelude: FxHashMap<Symbol, NameBinding<'a>>,
macro_map: FxHashMap<DefId, MacroData>,
dummy_ext_bang: Lrc<SyntaxExtension>,
dummy_ext_derive: Lrc<SyntaxExtension>,
- non_macro_attr: Lrc<SyntaxExtension>,
+ non_macro_attr: MacroData,
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
@@ -1085,7 +1084,7 @@ pub struct Resolver<'a, 'tcx> {
next_node_id: NodeId,
- node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+ node_id_to_def_id: NodeMap<LocalDefId>,
def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
/// Indices of unnamed struct or variant fields with unresolved attributes.
@@ -1211,10 +1210,12 @@ impl<'tcx> Resolver<'_, 'tcx> {
&mut self,
parent: LocalDefId,
node_id: ast::NodeId,
- data: DefPathData,
+ name: Symbol,
+ def_kind: DefKind,
expn_id: ExpnId,
span: Span,
) -> LocalDefId {
+ let data = def_kind.def_path_data(name);
assert!(
!self.node_id_to_def_id.contains_key(&node_id),
"adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
@@ -1224,7 +1225,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
);
// FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()`
- let def_id = self.tcx.untracked().definitions.write().create_def(parent, data);
+ let def_id = self.tcx.create_def(parent, name, def_kind);
// Create the definition.
if expn_id != ExpnId::root() {
@@ -1290,12 +1291,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&mut FxHashMap::default(),
);
- let mut visibilities = FxHashMap::default();
- visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
-
let mut def_id_to_node_id = IndexVec::default();
assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID);
- let mut node_id_to_def_id = FxHashMap::default();
+ let mut node_id_to_def_id = NodeMap::default();
node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID);
let mut invocation_parents = FxHashMap::default();
@@ -1321,6 +1319,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let features = tcx.features();
let pub_vis = ty::Visibility::<DefId>::Public;
+ let edition = tcx.sess.edition();
let mut resolver = Resolver {
tcx,
@@ -1357,7 +1356,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ast_transform_scopes: FxHashMap::default(),
glob_map: Default::default(),
- visibilities,
+ visibilities_for_hashing: Default::default(),
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
@@ -1398,13 +1397,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
used_extern_options: Default::default(),
macro_names: FxHashSet::default(),
builtin_macros: Default::default(),
- builtin_macro_kinds: Default::default(),
registered_tools,
macro_use_prelude: FxHashMap::default(),
macro_map: FxHashMap::default(),
- dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(tcx.sess.edition())),
- dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(tcx.sess.edition())),
- non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(tcx.sess.edition())),
+ dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(edition)),
+ dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(edition)),
+ non_macro_attr: MacroData::new(Lrc::new(SyntaxExtension::non_macro_attr(edition))),
invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(),
macro_rules_scopes: Default::default(),
@@ -1445,6 +1443,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let root_parent_scope = ParentScope::module(graph_root, &resolver);
resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope);
+ resolver.feed_visibility(CRATE_DEF_ID, ty::Visibility::Public);
resolver
}
@@ -1492,10 +1491,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Default::default()
}
+ fn feed_visibility(&mut self, def_id: LocalDefId, vis: ty::Visibility) {
+ self.tcx.feed_local_def_id(def_id).visibility(vis.to_def_id());
+ self.visibilities_for_hashing.push((def_id, vis));
+ }
+
pub fn into_outputs(self) -> ResolverOutputs {
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let expn_that_defined = self.expn_that_defined;
- let visibilities = self.visibilities;
let extern_crate_map = self.extern_crate_map;
let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
let glob_map = self.glob_map;
@@ -1512,7 +1515,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let global_ctxt = ResolverGlobalCtxt {
expn_that_defined,
- visibilities,
+ visibilities_for_hashing: self.visibilities_for_hashing,
effective_visibilities,
extern_crate_map,
module_children: self.module_children,
@@ -1537,7 +1540,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
node_id_to_def_id: self.node_id_to_def_id,
def_id_to_node_id: self.def_id_to_node_id,
trait_map: self.trait_map,
- builtin_macro_kinds: self.builtin_macro_kinds,
lifetime_elision_allowed: self.lifetime_elision_allowed,
lint_buffer: Steal::new(self.lint_buffer),
};
@@ -1564,7 +1566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match macro_kind {
MacroKind::Bang => self.dummy_ext_bang.clone(),
MacroKind::Derive => self.dummy_ext_derive.clone(),
- MacroKind::Attr => self.non_macro_attr.clone(),
+ MacroKind::Attr => self.non_macro_attr.ext.clone(),
}
}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2ff6fb424..1001286b6 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -6,7 +6,7 @@ use crate::errors::{
MacroExpectedFound, RemoveSurroundingDerive,
};
use crate::Namespace::*;
-use crate::{BuiltinMacroState, Determinacy};
+use crate::{BuiltinMacroState, Determinacy, MacroData};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
@@ -205,10 +205,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
if self.builtin_macros.insert(name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
- self.tcx
- .sess
- .diagnostic()
- .bug(format!("built-in macro `{name}` was already registered"));
+ self.tcx.sess.dcx().bug(format!("built-in macro `{name}` was already registered"));
}
}
@@ -371,7 +368,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
if opt_ext.is_none() {
*opt_ext = Some(
match self.resolve_macro_path(
- &path,
+ path,
Some(MacroKind::Derive),
&parent_scope,
true,
@@ -485,7 +482,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
}
fn registered_tools(&self) -> &RegisteredTools {
- &self.registered_tools
+ self.registered_tools
}
}
@@ -695,7 +692,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
res
};
- res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext), res))
+ res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res))
}
pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
@@ -710,7 +707,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Make sure compilation does not succeed if preferred macro resolution
// has changed after the macro had been expanded. In theory all such
// situations should be reported as errors, so this is a bug.
- this.tcx.sess.delay_span_bug(span, "inconsistent resolution for a macro");
+ this.tcx.sess.span_delayed_bug(span, "inconsistent resolution for a macro");
}
} else {
// It's possible that the macro was unresolved (indeterminate) and silently
@@ -887,7 +884,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
if let Some(depr) = &ext.deprecation {
- let path = pprust::path_to_string(&path);
+ let path = pprust::path_to_string(path);
let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path);
stability::early_report_deprecation(
&mut self.lint_buffer,
@@ -936,28 +933,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Compile the macro into a `SyntaxExtension` and its rule spans.
///
/// Possibly replace its expander to a pre-defined one for built-in macros.
- pub(crate) fn compile_macro(
- &mut self,
- item: &ast::Item,
- edition: Edition,
- ) -> (SyntaxExtension, Vec<(usize, Span)>) {
- let (mut result, mut rule_spans) =
+ pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData {
+ let (mut ext, mut rule_spans) =
compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
- if let Some(builtin_name) = result.builtin_name {
+ if let Some(builtin_name) = ext.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
if let Some(builtin_macro) = self.builtin_macros.get_mut(&builtin_name) {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
// If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
- BuiltinMacroState::NotYetSeen(ext) => {
- result.kind = ext;
+ BuiltinMacroState::NotYetSeen(builtin_ext) => {
+ ext.kind = builtin_ext;
rule_spans = Vec::new();
- if item.id != ast::DUMMY_NODE_ID {
- self.builtin_macro_kinds
- .insert(self.local_def_id(item.id), result.macro_kind());
- }
}
BuiltinMacroState::AlreadySeen(span) => {
struct_span_err!(
@@ -976,6 +965,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
- (result, rule_spans)
+ let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
+ MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules }
}
}
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index fe4b8c7f6..4ff4ccf5e 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -404,11 +404,10 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s
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,
+ doc,
main_body_opts(),
Some(&mut broken_link_callback),
- )
- .into_iter();
+ );
let mut links = Vec::new();
while let Some(event) = event_iter.next() {