diff options
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r-- | compiler/rustc_resolve/messages.ftl | 6 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 155 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 210 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 128 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/effective_visibilities.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 35 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late.rs | 65 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 650 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 64 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 38 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/rustdoc.rs | 5 |
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(..) = ¶m.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 ¶m.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), .. }] = + <_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() { |