From 246f239d9f40f633160f0c18f87a20922d4e77bb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:06:37 +0200 Subject: Merging debian version 1.65.0+dfsg1-2. Signed-off-by: Daniel Baumann --- compiler/rustc_resolve/src/access_levels.rs | 160 +++---- compiler/rustc_resolve/src/build_reduced_graph.rs | 56 ++- compiler/rustc_resolve/src/check_unused.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 3 +- compiler/rustc_resolve/src/diagnostics.rs | 61 ++- compiler/rustc_resolve/src/ident.rs | 83 ++-- compiler/rustc_resolve/src/imports.rs | 109 +++-- compiler/rustc_resolve/src/late.rs | 234 +++++----- compiler/rustc_resolve/src/late/diagnostics.rs | 133 ++++-- compiler/rustc_resolve/src/late/lifetimes.rs | 511 +++++----------------- compiler/rustc_resolve/src/lib.rs | 87 ++-- compiler/rustc_resolve/src/macros.rs | 31 +- 12 files changed, 608 insertions(+), 862 deletions(-) (limited to 'compiler/rustc_resolve/src') diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs index 3fba923d9..0a3add2e0 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -1,25 +1,21 @@ +use crate::imports::ImportKind; +use crate::NameBinding; +use crate::NameBindingKind; +use crate::Resolver; use rustc_ast::ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; -use rustc_ast::ForeignMod; use rustc_ast::NodeId; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::middle::privacy::AccessLevel; -use rustc_middle::ty::Visibility; +use rustc_middle::ty::DefIdTree; use rustc_span::sym; -use crate::imports::ImportKind; -use crate::BindingKey; -use crate::NameBinding; -use crate::NameBindingKind; -use crate::Resolver; - pub struct AccessLevelsVisitor<'r, 'a> { r: &'r mut Resolver<'a>, - prev_level: Option, changed: bool, } @@ -28,31 +24,32 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// need access to a TyCtxt for that. pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { - let mut visitor = - AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) }; + let mut visitor = AccessLevelsVisitor { r, changed: false }; visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public)); - visitor.set_exports_access_level(CRATE_DEF_ID); + visitor.set_bindings_access_level(CRATE_DEF_ID); while visitor.changed { visitor.reset(); visit::walk_crate(&mut visitor, krate); } - tracing::info!("resolve::access_levels: {:#?}", r.access_levels); + info!("resolve::access_levels: {:#?}", r.access_levels); } fn reset(&mut self) { self.changed = false; - self.prev_level = Some(AccessLevel::Public); } - /// Update the access level of the exports of the given module accordingly. The module access + /// Update the access level of the bindings in the given module accordingly. The module access /// level has to be Exported or Public. /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level). - fn set_exports_access_level(&mut self, module_id: LocalDefId) { + fn set_bindings_access_level(&mut self, module_id: LocalDefId) { assert!(self.r.module_map.contains_key(&&module_id.to_def_id())); - + let module_level = self.r.access_levels.map.get(&module_id).copied(); + if !module_level.is_some() { + return; + } // Set the given binding access level to `AccessLevel::Public` and // sets the rest of the `use` chain to `AccessLevel::Exported` until // we hit the actual exported item. @@ -72,28 +69,20 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { } }; - let module_level = self.r.access_levels.map.get(&module_id).copied(); - assert!(module_level >= Some(AccessLevel::Exported)); - - if let Some(exports) = self.r.reexport_map.get(&module_id) { - let pub_exports = exports - .iter() - .filter(|ex| ex.vis == Visibility::Public) - .cloned() - .collect::>(); - - let module = self.r.get_module(module_id.to_def_id()).unwrap(); - for export in pub_exports.into_iter() { - if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) { - self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported)); - } - - if let Some(ns) = export.res.ns() { - let key = BindingKey { ident: export.ident, ns, disambiguator: 0 }; - let name_res = self.r.resolution(module, key); - if let Some(binding) = name_res.borrow().binding() { - set_import_binding_access_level(self, binding, module_level) - } + let module = self.r.get_module(module_id.to_def_id()).unwrap(); + let resolutions = self.r.resolutions(module); + + for (.., name_resolution) in resolutions.borrow().iter() { + if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() { + let access_level = match binding.is_import() { + true => { + set_import_binding_access_level(self, binding, module_level); + Some(AccessLevel::Exported) + }, + false => module_level, + }; + if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + self.set_access_level_def_id(def_id, access_level); } } } @@ -127,97 +116,59 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { fn visit_item(&mut self, item: &'ast ast::Item) { - let inherited_item_level = match item.kind { + let def_id = self.r.local_def_id(item.id); + // Set access level of nested items. + // If it's a mod, also make the visitor walk all of its items + match item.kind { // Resolved in rustc_privacy when types are available ast::ItemKind::Impl(..) => return, - // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { - let is_macro_export = - item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)); - if is_macro_export { Some(AccessLevel::Public) } else { None } - } - - // Foreign modules inherit level from parents. - ast::ItemKind::ForeignMod(..) => self.prev_level, - - // Other `pub` items inherit levels from parents. - ast::ItemKind::ExternCrate(..) - | ast::ItemKind::Use(..) - | ast::ItemKind::Static(..) - | ast::ItemKind::Const(..) - | ast::ItemKind::Fn(..) - | ast::ItemKind::Mod(..) - | ast::ItemKind::GlobalAsm(..) - | ast::ItemKind::TyAlias(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Struct(..) - | ast::ItemKind::Union(..) - | ast::ItemKind::Trait(..) - | ast::ItemKind::TraitAlias(..) - | ast::ItemKind::MacroDef(..) => { - if item.vis.kind.is_pub() { - self.prev_level - } else { - None - } - } - // Should be unreachable at this stage ast::ItemKind::MacCall(..) => panic!( "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage" ), - }; - let access_level = self.set_access_level(item.id, inherited_item_level); + // Foreign modules inherit level from parents. + ast::ItemKind::ForeignMod(..) => { + let parent_level = + self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied(); + self.set_access_level(item.id, parent_level); + } - // Set access level of nested items. - // If it's a mod, also make the visitor walk all of its items - match item.kind { - ast::ItemKind::Mod(..) => { - if access_level.is_some() { - self.set_exports_access_level(self.r.local_def_id(item.id)); + // Only exported `macro_rules!` items are public, but they always are + ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { + if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) { + self.set_access_level(item.id, Some(AccessLevel::Public)); } + } - let orig_level = std::mem::replace(&mut self.prev_level, access_level); + ast::ItemKind::Mod(..) => { + self.set_bindings_access_level(def_id); visit::walk_item(self, item); - self.prev_level = orig_level; } - ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => { - for nested in items { - if nested.vis.kind.is_pub() { - self.set_access_level(nested.id, access_level); - } - } - } ast::ItemKind::Enum(EnumDef { ref variants }, _) => { + self.set_bindings_access_level(def_id); for variant in variants { - let variant_level = self.set_access_level(variant.id, access_level); - if let Some(ctor_id) = variant.data.ctor_id() { - self.set_access_level(ctor_id, access_level); - } - + let variant_def_id = self.r.local_def_id(variant.id); + let variant_level = self.r.access_levels.map.get(&variant_def_id).copied(); for field in variant.data.fields() { self.set_access_level(field.id, variant_level); } } } - ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { - if let Some(ctor_id) = def.ctor_id() { - self.set_access_level(ctor_id, access_level); - } + ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { + let inherited_level = self.r.access_levels.map.get(&def_id).copied(); for field in def.fields() { if field.vis.kind.is_pub() { - self.set_access_level(field.id, access_level); + self.set_access_level(field.id, inherited_level); } } } - ast::ItemKind::Trait(ref trait_kind) => { - for nested in trait_kind.items.iter() { - self.set_access_level(nested.id, access_level); - } + + ast::ItemKind::Trait(..) => { + self.set_bindings_access_level(def_id); } ast::ItemKind::ExternCrate(..) @@ -229,9 +180,6 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { | ast::ItemKind::TraitAlias(..) | ast::ItemKind::MacroDef(..) | ast::ItemKind::Fn(..) => return, - - // Unreachable kinds - ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(), } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e955a1798..81b67b758 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -36,28 +36,29 @@ use rustc_span::Span; use std::cell::Cell; use std::ptr; -use tracing::debug; type Res = def::Res; -impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) { +impl<'a, Id: Into> ToNameBinding<'a> + for (Module<'a>, ty::Visibility, Span, LocalExpnId) +{ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Module(self.0), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) } } -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { +impl<'a, Id: Into> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, false), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) @@ -71,7 +72,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroE arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, true), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) @@ -261,7 +262,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities[&def_id.expect_local()] } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), + _ => ty::Visibility::Restricted( + self.parent_scope.module.nearest_parent_mod().expect_local(), + ), }) } ast::VisibilityKind::Restricted { ref path, id, .. } => { @@ -312,7 +315,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } else { let vis = ty::Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { - Ok(vis) + Ok(vis.expect_local()) } else { Err(VisResolutionError::AncestorOnly(path.span)) } @@ -380,7 +383,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { has_attributes: !item.attrs.is_empty(), root_span, root_id, - vis: Cell::new(vis), + vis: Cell::new(Some(vis)), used: Cell::new(false), }); @@ -588,7 +591,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import), - max_vis: Cell::new(ty::Visibility::Invisible), + max_vis: Cell::new(None), }; self.r.visibilities.insert(self.r.local_def_id(id), vis); self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis); @@ -650,7 +653,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { true, // The whole `use` item item, - ty::Visibility::Invisible, + ty::Visibility::Restricted( + self.parent_scope.module.nearest_parent_mod().expect_local(), + ), root_span, ); } @@ -766,10 +771,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if let Some(ctor_node_id) = vdata.ctor_id() { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. - let mut ctor_vis = if vis == ty::Visibility::Public + let mut ctor_vis = if vis.is_public() && self.r.session.contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -786,7 +791,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if ctor_vis.is_at_least(field_vis, &*self.r) { ctor_vis = field_vis; } - ret_fields.push(field_vis); + 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( @@ -796,7 +801,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); self.r.visibilities.insert(ctor_def_id, ctor_vis); - self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields)); + self.r + .struct_constructors + .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields)); } } @@ -868,8 +875,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let binding = - (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + let vis = ty::Visibility::::Public; + let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -885,7 +892,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { root_span: item.span, span: item.span, module_path: Vec::new(), - vis: Cell::new(vis), + vis: Cell::new(Some(vis)), used: Cell::new(used), }); self.r.potentially_unused_imports.push(import); @@ -965,6 +972,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | DefKind::TyAlias | DefKind::ForeignTy | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::TraitAlias | DefKind::AssocTy, _, @@ -1030,7 +1038,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.insert_field_names(def_id, field_names); } Res::Def(DefKind::AssocFn, def_id) => { - if cstore.fn_has_self_parameter_untracked(def_id) { + if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) { self.r.has_self.insert(def_id); } } @@ -1118,7 +1126,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { root_span: span, span, module_path: Vec::new(), - vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())), + vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))), used: Cell::new(false), }) }; @@ -1264,7 +1272,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let vis = if is_macro_export { ty::Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) }; let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); @@ -1295,7 +1303,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } _ => self.resolve_visibility(&item.vis), }; - if vis != ty::Visibility::Public { + if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id, &rule_spans); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); @@ -1508,10 +1516,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis == ty::Visibility::Public + let ctor_vis = if vis.is_public() && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) } else { vis }; diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index f2f6f1d89..8b58b32b6 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -227,7 +227,7 @@ impl Resolver<'_> { for import in self.potentially_unused_imports.iter() { match import.kind { _ if import.used.get() - || import.vis.get().is_public() + || import.expect_vis().is_public() || import.span.is_dummy() => { if let ImportKind::MacroUse = import.kind { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 66641fb2c..3f88f44ff 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,7 +8,6 @@ use rustc_hir::definitions::*; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; pub(crate) fn collect_definitions( resolver: &mut Resolver<'_>, @@ -155,7 +154,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } } - visit::walk_fn(self, fn_kind, span); + visit::walk_fn(self, fn_kind); } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8839fb1a1..ab71fa0bc 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -25,7 +25,6 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; -use tracing::debug; use crate::imports::{Import, ImportKind, ImportResolver}; use crate::late::{PatternSource, Rib}; @@ -511,7 +510,7 @@ impl<'a> Resolver<'a> { err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); - match outer_res { + let def_id = match outer_res { Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => { if let Some(impl_span) = maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) @@ -536,11 +535,13 @@ impl<'a> Resolver<'a> { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "type parameter from outer function"); } + def_id } Res::Def(DefKind::ConstParam, def_id) => { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "const parameter from outer function"); } + def_id } _ => { bug!( @@ -548,28 +549,23 @@ impl<'a> Resolver<'a> { DefKind::TyParam or DefKind::ConstParam" ); } - } + }; - if has_generic_params == HasGenericParams::Yes { + if let HasGenericParams::Yes(span) = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; - if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) { - // Suggest the modification to the user - err.span_suggestion( - sugg_span, - sugg_msg, - snippet, - Applicability::MachineApplicable, - ); - } else if let Some(sp) = sm.generate_fn_name_span(span) { - err.span_label( - sp, - "try adding a local generic parameter in this method instead", - ); + let name = self.opt_name(def_id).unwrap_or(sym::T); + let (span, snippet) = if span.is_empty() { + let snippet = format!("<{}>", name); + (span, snippet) } else { - err.help("try using a local generic parameter instead"); - } + let span = sm.span_through_char(span, '<').shrink_to_hi(); + let snippet = format!("{}, ", name); + (span, snippet) + }; + // Suggest the modification to the user + err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect); } err @@ -1175,16 +1171,6 @@ impl<'a> Resolver<'a> { Scope::Module(module, _) => { this.add_module_candidates(module, &mut suggestions, filter_fn); } - Scope::RegisteredAttrs => { - let res = Res::NonMacroAttr(NonMacroAttrKind::Registered); - if filter_fn(res) { - suggestions.extend( - this.registered_attrs - .iter() - .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)), - ); - } - } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { @@ -1407,7 +1393,7 @@ impl<'a> Resolver<'a> { // If only some candidates are accessible, take just them if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) { - candidates = candidates.into_iter().filter(|x| x.accessible).collect(); + candidates.retain(|x| x.accessible) } candidates @@ -2544,12 +2530,15 @@ fn show_candidates( Applicability::MaybeIncorrect, ); if let [first, .., last] = &path[..] { - err.span_suggestion_verbose( - first.ident.span.until(last.ident.span), - &format!("if you import `{}`, refer to it directly", last.ident), - "", - Applicability::Unspecified, - ); + let sp = first.ident.span.until(last.ident.span); + if sp.can_be_used_for_suggestions() { + err.span_suggestion_verbose( + sp, + &format!("if you import `{}`, refer to it directly", last.ident), + "", + Applicability::Unspecified, + ); + } } } else { msg.push(':'); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6e6782881..2287aa1eb 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -6,6 +6,7 @@ use rustc_middle::bug; use rustc_middle::ty; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::symbol::{kw, Ident}; @@ -13,7 +14,9 @@ use rustc_span::{Span, DUMMY_SP}; use std::ptr; -use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind}; +use crate::late::{ + ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, +}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; @@ -24,6 +27,8 @@ use Determinacy::*; use Namespace::*; use RibKind::*; +type Visibility = ty::Visibility; + impl<'a> Resolver<'a> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -125,7 +130,6 @@ impl<'a> Resolver<'a> { } Scope::CrateRoot => true, Scope::Module(..) => true, - Scope::RegisteredAttrs => use_prelude, Scope::MacroUsePrelude => use_prelude || rust_2015, Scope::BuiltinAttrs => true, Scope::ExternPrelude => use_prelude || is_absolute_path, @@ -185,12 +189,11 @@ impl<'a> Resolver<'a> { match ns { TypeNS => Scope::ExternPrelude, ValueNS => Scope::StdLibPrelude, - MacroNS => Scope::RegisteredAttrs, + MacroNS => Scope::MacroUsePrelude, } } } } - Scope::RegisteredAttrs => Scope::MacroUsePrelude, Scope::MacroUsePrelude => Scope::StdLibPrelude, Scope::BuiltinAttrs => break, // nowhere else to search Scope::ExternPrelude if is_absolute_path => break, @@ -273,7 +276,7 @@ impl<'a> Resolver<'a> { /// /// Invariant: This must only be called during main resolution, not during /// import resolution. - #[tracing::instrument(level = "debug", skip(self, ribs))] + #[instrument(level = "debug", skip(self, ribs))] pub(crate) fn resolve_ident_in_lexical_scope( &mut self, mut ident: Ident, @@ -367,7 +370,7 @@ impl<'a> Resolver<'a> { /// expansion and import resolution (perhaps they can be merged in the future). /// The function is used for resolving initial segments of macro paths (e.g., `foo` in /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. - #[tracing::instrument(level = "debug", skip(self, scope_set))] + #[instrument(level = "debug", skip(self, scope_set))] pub(crate) fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, @@ -424,8 +427,7 @@ impl<'a> Resolver<'a> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ok = |res, span, arenas| { Ok(( - (res, ty::Visibility::Public, span, LocalExpnId::ROOT) - .to_name_binding(arenas), + (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas), Flags::empty(), )) }; @@ -438,7 +440,7 @@ impl<'a> Resolver<'a> { { let binding = ( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), - ty::Visibility::Public, + Visibility::Public, attr.span, expn_id, ) @@ -554,14 +556,6 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() { - Some(ident) => ok( - Res::NonMacroAttr(NonMacroAttrKind::Registered), - ident.span, - this.arenas, - ), - None => Err(Determinacy::Determined), - }, Scope::MacroUsePrelude => { match this.macro_use_prelude.get(&ident.name).cloned() { Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)), @@ -716,7 +710,7 @@ impl<'a> Resolver<'a> { Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn maybe_resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'a>, @@ -728,7 +722,7 @@ impl<'a> Resolver<'a> { .map_err(|(determinacy, _)| determinacy) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'a>, @@ -742,7 +736,7 @@ impl<'a> Resolver<'a> { .map_err(|(determinacy, _)| determinacy) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_ext( &mut self, module: ModuleOrUniformRoot<'a>, @@ -780,7 +774,7 @@ impl<'a> Resolver<'a> { ) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted( &mut self, module: ModuleOrUniformRoot<'a>, @@ -804,7 +798,7 @@ impl<'a> Resolver<'a> { /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted_ext( &mut self, module: ModuleOrUniformRoot<'a>, @@ -849,9 +843,8 @@ impl<'a> Resolver<'a> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - let binding = - (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) - .to_name_binding(self.arenas); + let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT) + .to_name_binding(self.arenas); return Ok(binding); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. @@ -951,7 +944,10 @@ impl<'a> Resolver<'a> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. for single_import in &resolution.single_imports { - if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) { + let Some(import_vis) = single_import.vis.get() else { + continue; + }; + if !self.is_accessible_from(import_vis, parent_scope.module) { continue; } let Some(module) = single_import.imported_module.get() else { @@ -1016,7 +1012,10 @@ impl<'a> Resolver<'a> { // Check if one of glob imports can still define the name, // if it can then our "no resolution" result is not determined and can be invalidated. for glob_import in module.globs.borrow().iter() { - if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) { + let Some(import_vis) = glob_import.vis.get() else { + continue; + }; + if !self.is_accessible_from(import_vis, parent_scope.module) { continue; } let module = match glob_import.imported_module.get() { @@ -1061,7 +1060,7 @@ impl<'a> Resolver<'a> { } /// Validate a local resolution (from ribs). - #[tracing::instrument(level = "debug", skip(self, all_ribs))] + #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( &mut self, rib_index: usize, @@ -1103,7 +1102,7 @@ impl<'a> Resolver<'a> { | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. } - ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { + ItemRibKind(_) | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1168,10 +1167,10 @@ impl<'a> Resolver<'a> { let has_generic_params: HasGenericParams = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. continue; @@ -1180,7 +1179,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. @@ -1207,7 +1208,6 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( @@ -1232,28 +1232,22 @@ impl<'a> Resolver<'a> { } } Res::Def(DefKind::ConstParam, _) => { - let mut ribs = ribs.iter().peekable(); - if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { - // When declaring const parameters inside function signatures, the first rib - // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it - // (spuriously) conflicting with the const param. - ribs.next(); - } - for rib in ribs { let has_generic_params = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { if let Some(span) = finalize { self.report_error( span, @@ -1272,7 +1266,6 @@ impl<'a> Resolver<'a> { } ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( @@ -1302,7 +1295,7 @@ impl<'a> Resolver<'a> { res } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn maybe_resolve_path( &mut self, path: &[Segment], @@ -1312,7 +1305,7 @@ impl<'a> Resolver<'a> { self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_path( &mut self, path: &[Segment], diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b89273990..c133c272b 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -23,15 +23,13 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; -use tracing::*; - use std::cell::Cell; use std::{mem, ptr}; type Res = def::Res; /// Contains data for specific kinds of imports. -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum ImportKind<'a> { Single { /// `source` in `use prefix::source as target`. @@ -52,8 +50,8 @@ pub enum ImportKind<'a> { }, Glob { is_prelude: bool, - max_vis: Cell, // The visibility of the greatest re-export. - // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + max_vis: Cell>, // The visibility of the greatest re-export. + // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. }, ExternCrate { source: Option, @@ -62,6 +60,44 @@ pub enum ImportKind<'a> { MacroUse, } +/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` +/// contain `Cell`s which can introduce infinite loops while printing. +impl<'a> std::fmt::Debug for ImportKind<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ImportKind::*; + match self { + Single { + ref source, + ref target, + ref type_ns_only, + ref nested, + ref additional_ids, + // Ignore the following to avoid an infinite loop while printing. + source_bindings: _, + target_bindings: _, + } => f + .debug_struct("Single") + .field("source", source) + .field("target", target) + .field("type_ns_only", type_ns_only) + .field("nested", nested) + .field("additional_ids", additional_ids) + .finish_non_exhaustive(), + Glob { ref is_prelude, ref max_vis } => f + .debug_struct("Glob") + .field("is_prelude", is_prelude) + .field("max_vis", max_vis) + .finish(), + ExternCrate { ref source, ref target } => f + .debug_struct("ExternCrate") + .field("source", source) + .field("target", target) + .finish(), + MacroUse => f.debug_struct("MacroUse").finish(), + } + } +} + /// One import. #[derive(Debug, Clone)] pub(crate) struct Import<'a> { @@ -106,7 +142,7 @@ pub(crate) struct Import<'a> { pub module_path: Vec, /// The resolution of `module_path`. pub imported_module: Cell>>, - pub vis: Cell, + pub vis: Cell>, pub used: Cell, } @@ -121,6 +157,10 @@ impl<'a> Import<'a> { _ => false, } } + + pub(crate) fn expect_vis(&self) -> ty::Visibility { + self.vis.get().expect("encountered cleared import visibility") + } } /// Records information about the resolution of a name in a namespace of a module. @@ -161,7 +201,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi import: Import { kind: ImportKind::ExternCrate { .. }, .. }, .. }, - ) => import.vis.get().is_public(), + ) => import.expect_vis().is_public(), _ => false, } } @@ -174,17 +214,20 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, import: &'a Import<'a>, ) -> &'a NameBinding<'a> { - let vis = if binding.vis.is_at_least(import.vis.get(), self) + let import_vis = import.expect_vis().to_def_id(); + let vis = if binding.vis.is_at_least(import_vis, self) || pub_use_of_private_extern_crate_hack(import, binding) { - import.vis.get() + import_vis } else { binding.vis }; if let ImportKind::Glob { ref max_vis, .. } = import.kind { - if vis == import.vis.get() || vis.is_at_least(max_vis.get(), self) { - max_vis.set(vis) + if vis == import_vis + || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self)) + { + max_vis.set(Some(vis.expect_local())) } } @@ -498,7 +541,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } else { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let path_res = self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope); import.vis.set(orig_vis); @@ -533,7 +576,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Err(Undetermined) = source_bindings[ns].get() { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let binding = this.resolve_ident_in_module( module, source, @@ -582,7 +625,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let ignore_binding = match &import.kind { ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), _ => None, @@ -689,9 +732,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }); } } - if !is_prelude && - max_vis.get() != ty::Visibility::Invisible && // Allow empty globs. - !max_vis.get().is_at_least(import.vis.get(), &*self.r) + if !is_prelude + && let Some(max_vis) = max_vis.get() + && !max_vis.is_at_least(import.expect_vis(), &*self.r) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); @@ -704,7 +747,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut all_ns_err = true; self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let binding = this.resolve_ident_in_module( module, ident, @@ -868,8 +911,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut crate_private_reexport = false; self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - let vis = import.vis.get(); - if !binding.vis.is_at_least(vis, &*this) { + if !binding.vis.is_at_least(import.expect_vis(), &*this) { reexport_error = Some((ns, binding)); if let ty::Visibility::Restricted(binding_def_id) = binding.vis { if binding_def_id.is_top_level_module() { @@ -1091,24 +1133,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Some(def_id) = module.opt_def_id() { let mut reexports = Vec::new(); - module.for_each_child(self.r, |_, ident, _, binding| { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - reexports.push(ModChild { - ident, - res, - vis: binding.vis, - span: binding.span, - macro_rules: false, - }); - } + module.for_each_child(self.r, |this, ident, _, binding| { + if let Some(res) = this.is_reexport(binding) { + reexports.push(ModChild { + ident, + res, + vis: binding.vis, + span: binding.span, + macro_rules: false, + }); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dea3eaecd..d8d82e125 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -20,7 +20,7 @@ use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_lifetime::Set1; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; @@ -30,9 +30,9 @@ use rustc_span::{BytePos, Span}; use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; +use std::assert_matches::debug_assert_matches; use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; -use tracing::debug; mod diagnostics; pub(crate) mod lifetimes; @@ -51,7 +51,7 @@ use diagnostics::{ #[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, - binding_mode: BindingMode, + annotation: BindingAnnotation, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -91,13 +91,20 @@ enum PatBoundCtx { } /// Does this the item (from the item rib scope) allow generic parameters? -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { + Yes(Span), + No, +} + +/// May this constant have generics? +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum ConstantHasGenerics { Yes, No, } -impl HasGenericParams { +impl ConstantHasGenerics { fn force_yes_if(self, b: bool) -> Self { if b { Self::Yes } else { self } } @@ -125,10 +132,6 @@ pub(crate) enum RibKind<'a> { /// We passed through a closure. Disallow labels. ClosureOrAsyncRibKind, - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - /// We passed through an item scope. Disallow upvars. ItemRibKind(HasGenericParams), @@ -136,7 +139,7 @@ pub(crate) enum RibKind<'a> { /// /// The item may reference generic parameters in trivial constant expressions. /// All other constants aren't allowed to use generic params at all. - ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>), + ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -165,7 +168,6 @@ impl RibKind<'_> { match self { NormalRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) @@ -182,7 +184,6 @@ impl RibKind<'_> { AssocItemRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ItemRibKind(..) | ConstantItemRibKind(..) | ModuleRibKind(..) @@ -557,7 +558,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// They will be used to determine the correct lifetime for the fn return type. /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named /// lifetimes. - lifetime_elision_candidates: Option>, + lifetime_elision_candidates: Option>, /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -629,7 +630,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. // This span will be used in case of elision failure. - let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo()); + let span = self.r.session.source_map().start_point(ty.span); self.resolve_elided_lifetime(ty.id, span); visit::walk_ty(self, ty); } @@ -723,7 +724,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.current_trait_object = prev; self.diagnostic_metadata.current_type_path = prev_ty; } - fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) { let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo()); self.with_generic_param_rib( &tref.bound_generic_params, @@ -751,7 +752,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -765,7 +766,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -786,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { - let rib_kind = match fn_kind { + let previous_value = self.diagnostic_metadata.current_function; + match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) @@ -809,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); return; } - FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, - FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, - FnKind::Closure(..) => ClosureOrAsyncRibKind, + FnKind::Fn(..) => { + self.diagnostic_metadata.current_function = Some((fn_kind, sp)); + } + // Do not update `current_function` for closures: it suggests `self` parameters. + FnKind::Closure(..) => {} }; - let previous_value = self.diagnostic_metadata.current_function; - if matches!(fn_kind, FnKind::Fn(..)) { - self.diagnostic_metadata.current_function = Some((fn_kind, sp)); - } debug!("(resolving function) entering function"); // Create a value rib for the function. - self.with_rib(ValueNS, rib_kind, |this| { + self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| { // Create a label rib for the function. - this.with_label_rib(FnItemRibKind, |this| { + this.with_label_rib(ClosureOrAsyncRibKind, |this| { match fn_kind { FnKind::Fn(_, _, sig, _, generics, body) => { this.visit_generics(generics); @@ -852,7 +852,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // We include all lifetime parameters, either named or "Fresh". // The order of those parameters does not matter, as long as it is // deterministic. - if let Some(async_node_id) = async_node_id { + if let Some((async_node_id, _)) = async_node_id { let mut extra_lifetime_params = this .r .extra_lifetime_params_map @@ -995,7 +995,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // non-trivial constants this is doesn't matter. self.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| { this.smart_resolve_path( @@ -1031,7 +1031,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { if let Some(ref gen_args) = constraint.gen_args { // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided. self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { - this.visit_generic_args(gen_args.span(), gen_args) + this.visit_generic_args(gen_args) }); } match constraint.kind { @@ -1045,10 +1045,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { + fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { if let Some(ref args) = path_segment.args { match &**args { - GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), + GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), GenericArgs::Parenthesized(p_args) => { // Probe the lifetime ribs to know how to behave. for rib in self.lifetime_ribs.iter().rev() { @@ -1079,7 +1079,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // We have nowhere to introduce generics. Code is malformed, // so use regular lifetime resolution to avoid spurious errors. LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { - visit::walk_generic_args(self, path_span, args); + visit::walk_generic_args(self, args); break; } LifetimeRibKind::AnonymousCreateParameter { .. } @@ -1390,7 +1390,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }) } - #[tracing::instrument(level = "debug", skip(self, work))] + #[instrument(level = "debug", skip(self, work))] fn with_lifetime_rib( &mut self, kind: LifetimeRibKind, @@ -1404,7 +1404,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ret } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) { let ident = lifetime.ident; @@ -1508,7 +1508,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); @@ -1573,7 +1573,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; @@ -1586,7 +1586,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.resolve_anonymous_lifetime(<, true); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); @@ -1604,7 +1604,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { res } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetimes_in_path( &mut self, path_id: NodeId, @@ -1804,7 +1804,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn record_lifetime_res( &mut self, id: NodeId, @@ -1820,14 +1820,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match res { LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => { if let Some(ref mut candidates) = self.lifetime_elision_candidates { - candidates.insert(res, candidate); + candidates.push((res, candidate)); } } LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {} } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { panic!( @@ -1838,7 +1838,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } /// Perform resolution of a function signature, accounting for lifetime elision. - #[tracing::instrument(level = "debug", skip(self, inputs))] + #[instrument(level = "debug", skip(self, inputs))] fn resolve_fn_signature( &mut self, fn_id: NodeId, @@ -1873,12 +1873,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { has_self: bool, inputs: impl Iterator, &'ast Ty)>, ) -> Result, Vec)> { - let outer_candidates = - replace(&mut self.lifetime_elision_candidates, Some(Default::default())); + enum Elision { + /// We have not found any candidate. + None, + /// We have a candidate bound to `self`. + Self_(LifetimeRes), + /// We have a candidate bound to a parameter. + Param(LifetimeRes), + /// We failed elision. + Err, + } + + // Save elision state to reinstate it later. + let outer_candidates = self.lifetime_elision_candidates.take(); - let mut elision_lifetime = None; - let mut lifetime_count = 0; + // Result of elision. + let mut elision_lifetime = Elision::None; + // Information for diagnostics. let mut parameter_info = Vec::new(); + let mut all_candidates = Vec::new(); let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; for (index, (pat, ty)) in inputs.enumerate() { @@ -1886,12 +1899,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let Some(pat) = pat { self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); } + + // Record elision candidates only for this parameter. + debug_assert_matches!(self.lifetime_elision_candidates, None); + self.lifetime_elision_candidates = Some(Default::default()); self.visit_ty(ty); + let local_candidates = self.lifetime_elision_candidates.take(); - if let Some(ref candidates) = self.lifetime_elision_candidates { - let new_count = candidates.len(); - let local_count = new_count - lifetime_count; - if local_count != 0 { + if let Some(candidates) = local_candidates { + let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect(); + let lifetime_count = distinct.len(); + if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { index, ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind { @@ -1899,48 +1917,64 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } else { None }, - lifetime_count: local_count, + lifetime_count, span: ty.span, }); + all_candidates.extend(candidates.into_iter().filter_map(|(_, candidate)| { + match candidate { + LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => { + None + } + LifetimeElisionCandidate::Missing(missing) => Some(missing), + } + })); + } + let mut distinct_iter = distinct.into_iter(); + if let Some(res) = distinct_iter.next() { + match elision_lifetime { + // We are the first parameter to bind lifetimes. + Elision::None => { + if distinct_iter.next().is_none() { + // We have a single lifetime => success. + elision_lifetime = Elision::Param(res) + } else { + // We have have multiple lifetimes => error. + elision_lifetime = Elision::Err; + } + } + // We have 2 parameters that bind lifetimes => error. + Elision::Param(_) => elision_lifetime = Elision::Err, + // `self` elision takes precedence over everything else. + Elision::Self_(_) | Elision::Err => {} + } } - lifetime_count = new_count; } // Handle `self` specially. if index == 0 && has_self { let self_lifetime = self.find_lifetime_for_self(ty); if let Set1::One(lifetime) = self_lifetime { - elision_lifetime = Some(lifetime); - self.lifetime_elision_candidates = None; + // We found `self` elision. + elision_lifetime = Elision::Self_(lifetime); } else { - self.lifetime_elision_candidates = Some(Default::default()); - lifetime_count = 0; + // We do not have `self` elision: disregard the `Elision::Param` that we may + // have found. + elision_lifetime = Elision::None; } } debug!("(resolving function / closure) recorded parameter"); } - let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates); - debug!(?all_candidates); + // Reinstate elision state. + debug_assert_matches!(self.lifetime_elision_candidates, None); + self.lifetime_elision_candidates = outer_candidates; - if let Some(res) = elision_lifetime { + if let Elision::Param(res) | Elision::Self_(res) = elision_lifetime { return Ok(res); } - // We do not have a `self` candidate, look at the full list. - let all_candidates = all_candidates.unwrap(); - if all_candidates.len() == 1 { - Ok(*all_candidates.first().unwrap().0) - } else { - let all_candidates = all_candidates - .into_iter() - .filter_map(|(_, candidate)| match candidate { - LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None, - LifetimeElisionCandidate::Missing(missing) => Some(missing), - }) - .collect(); - Err((all_candidates, parameter_info)) - } + // We do not have a candidate. + Err((all_candidates, parameter_info)) } /// List all the lifetimes that appear in the provided type. @@ -2071,7 +2105,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2141,7 +2175,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2154,7 +2188,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2186,7 +2220,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2210,7 +2244,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2251,7 +2285,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // so it doesn't matter whether this is a trivial constant. this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, Some((item.ident, constant_item_kind)), |this| this.visit_expr(expr), ); @@ -2412,7 +2446,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Do not account for the parameters we just bound for function lifetime elision. if let Some(ref mut candidates) = self.lifetime_elision_candidates { for (_, res) in function_lifetime_rib.bindings.values() { - candidates.remove(res); + candidates.retain(|(r, _)| r != res); } } @@ -2450,7 +2484,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn with_constant_rib( &mut self, is_repeat: IsRepeatExpr, - may_use_generics: HasGenericParams, + may_use_generics: ConstantHasGenerics, item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { @@ -2517,7 +2551,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -2598,7 +2632,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, @@ -2689,7 +2723,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -2866,10 +2900,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { pat.walk(&mut |pat| { match pat.kind { - PatKind::Ident(binding_mode, ident, ref sub_pat) + PatKind::Ident(annotation, ident, ref sub_pat) if sub_pat.is_some() || self.is_base_res_local(pat.id) => { - binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode }); + binding_map.insert(ident, BindingInfo { span: ident.span, annotation }); } PatKind::Or(ref ps) => { // Check the consistency of this or-pattern and @@ -2926,7 +2960,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { binding_error.target.insert(pat_outer.span); } Some(binding_outer) => { - if binding_outer.binding_mode != binding_inner.binding_mode { + if binding_outer.annotation != binding_inner.annotation { // The binding modes in the outer and inner bindings differ. inconsistent_vars .entry(name) @@ -3147,14 +3181,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn try_resolve_as_non_binding( &mut self, pat_src: PatternSource, - bm: BindingMode, + ann: BindingAnnotation, ident: Ident, has_sub: bool, ) -> Option { // An immutable (no `mut`) by-value (no `ref`) binding pattern without // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could // also be interpreted as a path to e.g. a constant, variant, etc. - let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); + let is_syntactic_ambiguity = !has_sub && ann == BindingAnnotation::NONE; let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { @@ -3268,11 +3302,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, finalize: Finalize, ) -> PartialRes { - tracing::debug!( + debug!( "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})", - qself, - path, - finalize, + qself, path, finalize, ); let ns = source.namespace(); @@ -3696,9 +3728,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( is_repeat, if constant.value.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| visit::walk_anon_const(this, constant), @@ -3707,8 +3739,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { debug!("resolve_anon_const {constant:?}"); - self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { - visit::walk_anon_const(this, constant); + self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { + visit::walk_anon_const(this, constant) }); } @@ -3802,7 +3834,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for argument in arguments { self.resolve_expr(argument, None); } - self.visit_path_segment(expr.span, segment); + self.visit_path_segment(segment); } ExprKind::Call(ref callee, ref arguments) => { @@ -3815,9 +3847,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( IsRepeatExpr::No, if argument.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2b1f2b88e..3b095eeeb 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -33,8 +33,6 @@ use rustc_span::{BytePos, Span}; use std::iter; use std::ops::Deref; -use tracing::debug; - type Res = def::Res; /// A field or associated item from self type suggested in case of resolution failure. @@ -161,6 +159,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { msg: String, fallback_label: String, span: Span, + span_label: Option<(Span, &'a str)>, could_be_expr: bool, suggestion: Option<(Span, &'a str, String)>, } @@ -172,6 +171,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str), fallback_label: format!("not a {expected}"), span, + span_label: match res { + Res::Def(kind, def_id) if kind == DefKind::TyParam => { + self.def_span(def_id).map(|span| (span, "found this type parameter")) + } + _ => None, + }, could_be_expr: match res { Res::Def(DefKind::Fn, _) => { // Verify whether this is a fn call or an Fn used as a type. @@ -243,14 +248,32 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .map_or_else(String::new, |res| format!("{} ", res.descr())); (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None) }; + + let (fallback_label, suggestion) = if path_str == "async" + && expected.starts_with("struct") + { + ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion) + } else { + // check if we are in situation of typo like `True` instead of `true`. + let override_suggestion = + if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) { + let item_typo = item_str.to_string().to_lowercase(); + Some(( + item_span, + "you may want to use a bool value instead", + format!("{}", item_typo), + )) + } else { + suggestion + }; + (format!("not found in {mod_str}"), override_suggestion) + }; + BaseError { msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"), - fallback_label: if path_str == "async" && expected.starts_with("struct") { - "`async` blocks are only allowed in Rust 2018 or later".to_string() - } else { - format!("not found in {mod_str}") - }, + fallback_label, span: item_span, + span_label: None, could_be_expr: false, suggestion, } @@ -262,6 +285,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); + if let Some((span, label)) = base_error.span_label { + err.span_label(span, label); + } + if let Some(sugg) = base_error.suggestion { err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect); } @@ -590,9 +617,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .filter(|&sp| sp != base_error.span) .collect(); - let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap(); + let start_span = bounds[0].span(); // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><) - let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap(); + let end_span = bounds.last().unwrap().span(); // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar) let last_bound_span = spans.last().cloned().unwrap(); let mut multi_span: MultiSpan = spans.clone().into(); @@ -985,27 +1012,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); - let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind { - ExprKind::Field(_, ident) => { + let path_sep = |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 { + ExprKind::Field(base, ident) => (base.span, ident.span), + ExprKind::MethodCall(_, args, span) => (args[0].span, *span), + _ => return false, + }; + + if lhs_span.eq_ctxt(rhs_span) { err.span_suggestion( - expr.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), + lhs_span.between(rhs_span), + MESSAGE, + "::", Applicability::MaybeIncorrect, ); true - } - ExprKind::MethodCall(ref segment, ..) => { - let span = expr.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( - span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), + } else if kind == DefKind::Struct + && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) + && let Ok(snippet) = self.r.session.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. + + err.span_suggestion_verbose( + lhs_source_span.until(rhs_span), + MESSAGE, + format!("<{snippet}>::"), Applicability::MaybeIncorrect, ); true + } else { + // Either we were unable to obtain the source span / the snippet or + // the LHS originates from a macro call and it is not a type and thus + // there is no way to replace `.` with `::` and still somehow suggest + // valid Rust code. + + false } - _ => false, }; let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| { @@ -1027,7 +1072,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { match source { PathSource::Expr(Some( parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. }, - )) if path_sep(err, &parent) => {} + )) if path_sep(err, &parent, DefKind::Struct) => {} PathSource::Expr( None | Some(Expr { @@ -1143,8 +1188,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } } - (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { - if !path_sep(err, &parent) { + ( + Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _), + PathSource::Expr(Some(parent)), + ) => { + if !path_sep(err, &parent, kind) { return false; } } @@ -1742,7 +1790,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } }; - let mut suggestable_variants = variants + let suggestable_variants = variants .iter() .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) @@ -1752,8 +1800,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { CtorKind::Fictive => format!("({} {{}})", variant), }) .collect::>(); + let no_suggestable_variant = suggestable_variants.is_empty(); - if !suggestable_variants.is_empty() { + if !no_suggestable_variant { let msg = if suggestable_variants.len() == 1 { "you might have meant to use the following enum variant" } else { @@ -1763,7 +1812,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, msg, - suggestable_variants.drain(..), + suggestable_variants.into_iter(), Applicability::MaybeIncorrect, ); } @@ -1780,15 +1829,15 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect::>(); if !suggestable_variants_with_placeholders.is_empty() { - let msg = match ( - suggestable_variants.is_empty(), - suggestable_variants_with_placeholders.len(), - ) { - (true, 1) => "the following enum variant is available", - (true, _) => "the following enum variants are available", - (false, 1) => "alternatively, the following enum variant is available", - (false, _) => "alternatively, the following enum variants are also available", - }; + let msg = + match (no_suggestable_variant, suggestable_variants_with_placeholders.len()) { + (true, 1) => "the following enum variant is available", + (true, _) => "the following enum variants are available", + (false, 1) => "alternatively, the following enum variant is available", + (false, _) => { + "alternatively, the following enum variants are also available" + } + }; err.span_suggestions( span, @@ -2021,9 +2070,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn suggest_introducing_lifetime( &self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, name: Option<&str>, - suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool, + suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { @@ -2147,9 +2196,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.emit() } - pub(crate) fn add_missing_lifetime_specifiers_label( + fn add_missing_lifetime_specifiers_label( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, lifetime_refs: Vec, function_param_lifetimes: Option<(Vec, Vec)>, ) { @@ -2300,7 +2349,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.multipart_suggestion_verbose( message, std::iter::once((span, intro_sugg)) - .chain(spans_suggs.clone()) + .chain(spans_suggs.iter().cloned()) .collect(), Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 94460e33d..4d9704617 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -11,23 +11,21 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use std::borrow::Cow; use std::fmt; -use std::mem::take; trait RegionExt { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); @@ -36,19 +34,13 @@ trait RegionExt { fn shifted(self, amount: u32) -> Region; fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; - - fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option - where - L: Iterator; } impl RegionExt for Region { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) { - let i = *index; - *index += 1; + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { let def_id = hir_map.local_def_id(param.hir_id); - debug!("Region::early: index={} def_id={:?}", i, def_id); - (def_id, Region::EarlyBound(i, def_id.to_def_id())) + debug!("Region::early: def_id={:?}", def_id); + (def_id, Region::EarlyBound(def_id.to_def_id())) } fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { @@ -65,9 +57,7 @@ impl RegionExt for Region { match *self { Region::Static => None, - Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => { - Some(id) - } + Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id), } } @@ -88,17 +78,6 @@ impl RegionExt for Region { _ => self, } } - - fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where - L: Iterator, - { - if let Region::EarlyBound(index, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) - } else { - Some(self) - } - } } /// Maps the id of each lifetime reference to the lifetime decl @@ -131,9 +110,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// be false if the `Item` we are resolving lifetimes for is not a trait or /// we eventually need lifetimes resolve for trait items. trait_definition_only: bool, - - /// Cache for cross-crate per-definition object lifetime defaults. - xcrate_object_lifetime_defaults: DefIdMap>, } #[derive(Debug)] @@ -147,25 +123,6 @@ enum Scope<'a> { /// for diagnostics. lifetimes: FxIndexMap, - /// if we extend this scope with another scope, what is the next index - /// we should use for an early-bound region? - next_early_index: u32, - - /// Whether or not this binder would serve as the parent - /// binder for opaque types introduced within. For example: - /// - /// ```text - /// fn foo<'a>() -> impl for<'b> Trait> - /// ``` - /// - /// Here, the opaque types we create for the `impl Trait` - /// and `impl Trait2` references will both have the `foo` item - /// as their parent. When we get to `impl Trait2`, we find - /// that it is nested within the `for<>` binder -- this flag - /// allows us to skip that when looking for the parent binder - /// of the resulting opaque type. - opaque_type_parent: bool, - scope_type: BinderScopeType, /// The late bound vars for a given item are stored by `HirId` to be @@ -245,19 +202,9 @@ struct TruncatedScopeDebug<'a>(&'a Scope<'a>); impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { - Scope::Binder { - lifetimes, - next_early_index, - opaque_type_parent, - scope_type, - hir_id, - where_bound_origin, - s: _, - } => f + Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f .debug_struct("Binder") .field("lifetimes", lifetimes) - .field("next_early_index", next_early_index) - .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) .field("where_bound_origin", where_bound_origin) @@ -294,10 +241,7 @@ pub fn provide(providers: &mut ty::query::Providers) { named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), is_late_bound_map, - object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) { - Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item), - _ => None, - }, + object_lifetime_default, late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), ..*providers @@ -334,7 +278,7 @@ pub fn provide(providers: &mut ty::query::Providers) { /// lifetimes into a single binder.) This requires us to resolve the /// *trait definition* of `Sub`; basically just enough lifetime information /// to look at the supertraits. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] fn resolve_lifetimes_trait_definition( tcx: TyCtxt<'_>, local_def_id: LocalDefId, @@ -345,7 +289,7 @@ fn resolve_lifetimes_trait_definition( /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. /// You should not read the result of this query directly, but rather use /// `named_region_map`, `is_late_bound_map`, etc. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { convert_named_region_map(do_resolve(tcx, local_def_id, false)) } @@ -363,7 +307,6 @@ fn do_resolve( map: &mut named_region_map, scope: ROOT_SCOPE, trait_definition_only, - xcrate_object_lifetime_defaults: Default::default(), }; visitor.visit_item(item); @@ -432,13 +375,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { item } -/// In traits, there is an implicit `Self` type parameter which comes before the generics. -/// We have to account for this when computing the index of the other generic parameters. -/// This function returns whether there is such an implicit parameter defined on the given item. -fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) -} - fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { match region { Region::LateBound(_, _, def_id) => { @@ -558,7 +494,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - let next_early_index = self.next_early_index(); let (lifetimes, binders): (FxIndexMap, Vec<_>) = bound_generic_params .iter() @@ -576,8 +511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: e.hir_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -592,6 +525,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match &item.kind { hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { @@ -603,7 +537,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } match item.kind { hir::ItemKind::Fn(_, ref generics, _) => { - self.visit_early_late(None, item.hir_id(), generics, |this| { + self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); } @@ -670,31 +604,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.kind) { - 1 // Self comes before lifetimes - } else { - 0 - }; - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, where_bound_origin: None, @@ -712,7 +635,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(_, _, ref generics) => { - self.visit_early_late(None, item.hir_id(), generics, |this| { + self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) } @@ -725,11 +648,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(ref c) => { - let next_early_index = self.next_early_index(); let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() @@ -746,8 +668,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -762,7 +682,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { for bound in bounds { - this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + this.visit_poly_trait_ref(bound); } }); match lifetime.name { @@ -795,7 +715,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(&mt.ty)); } - hir::TyKind::OpaqueDef(item_id, lifetimes) => { + hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to // `type MyAnonTy<'b> = impl MyTrait<'b>;` @@ -886,32 +806,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // We want to start our early-bound indices at the end of the parent scope, // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_opaque_type(); - debug!(?index); - let mut lifetimes = FxIndexMap::default(); - let mut non_lifetime_count = 0; debug!(?generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { - let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); + let (def_id, reg) = Region::early(self.tcx.hir(), ¶m); lifetimes.insert(def_id, reg); } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {} } } - let next_early_index = index + non_lifetime_count; self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index, s: self.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -929,43 +840,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(_, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(trait_item.hir_id())), - trait_item.hir_id(), - &trait_item.generics, - |this| intravisit::walk_trait_item(this, trait_item), - ); + self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { + intravisit::walk_trait_item(this, trait_item) + }); } Type(bounds, ref ty) => { let generics = &trait_item.generics; - let mut index = self.next_early_index(); - debug!("visit_ty: index = {}", index); - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: trait_item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -990,43 +890,30 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; match impl_item.kind { - Fn(..) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(impl_item.hir_id())), - impl_item.hir_id(), - &impl_item.generics, - |this| intravisit::walk_impl_item(this, impl_item), - ); - } + Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { + intravisit::walk_impl_item(this, impl_item) + }), TyAlias(ref ty) => { let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut non_lifetime_count = 0; - debug!("visit_ty: index = {}", index); let lifetimes: FxIndexMap = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None, }) .collect(); self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -1046,7 +933,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { match lifetime_ref.name { hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static), @@ -1129,7 +1016,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .unzip(); this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); - let next_early_index = this.next_early_index(); // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1138,8 +1024,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: bounded_ty.hir_id, lifetimes, s: this.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: Some(origin), }; @@ -1210,8 +1094,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: *hir_id, lifetimes: FxIndexMap::default(), s: self.scope, - next_early_index: self.next_early_index(), - opaque_type_parent: false, scope_type, where_bound_origin: None, }; @@ -1223,14 +1105,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'tcx hir::PolyTraitRef<'tcx>, - _modifier: hir::TraitBoundModifier, - ) { + fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - let next_early_index = self.next_early_index(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let initial_bound_vars = binders.len() as u32; @@ -1260,8 +1137,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: trait_ref.trait_ref.hir_ref_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type, where_bound_origin: None, }; @@ -1272,139 +1147,49 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -fn compute_object_lifetime_defaults<'tcx>( - tcx: TyCtxt<'tcx>, - item: &hir::Item<'_>, -) -> Option<&'tcx [ObjectLifetimeDefault]> { - match item.kind { - hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - ref generics, - origin: hir::OpaqueTyOrigin::TyAlias, - .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); - - // Debugging aid. - let attrs = tcx.hir().attrs(item.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) { - let object_lifetime_default_reprs: String = result - .iter() - .map(|set| match *set { - Set1::Empty => "BaseDefault".into(), - Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _)) => generics - .params - .iter() - .find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if i == 0 { - return Some(param.name.ident().to_string().into()); - } - i -= 1; - None - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - Some(result) - } - _ => None, - } -} - -/// Scan the bounds and where-clauses on parameters to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` -/// for each type parameter. -fn object_lifetime_defaults_for_item<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &hir::Generics<'_>, -) -> &'tcx [ObjectLifetimeDefault] { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.normalize_to_macros_2_0()); - } - } - } - - let process_param = |param: &hir::GenericParam<'_>| match param.kind { - GenericParamKind::Lifetime { .. } => None, +fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault { + debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); + let param_def_id = param_def_id.expect_local(); + let parent_def_id = tcx.local_parent(param_def_id); + let generics = tcx.hir().get_generics(parent_def_id).unwrap(); + let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); + + // Scan the bounds and where-clauses on parameters to extract bounds + // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` + // for each type parameter. + match param.kind { GenericParamKind::Type { .. } => { let mut set = Set1::Empty; - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.predicates { - // Look for `type: ...` where clauses. - let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue }; - + // Look for `type: ...` where clauses. + for bound in generics.bounds_for_param(param_def_id) { // Ignore `for<'a> type: ...` as they can change what // lifetimes mean (although we could "just" handle it). - if !data.bound_generic_params.is_empty() { + if !bound.bound_generic_params.is_empty() { continue; } - let res = match data.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, - _ => continue, - }; - - if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { - add_bounds(&mut set, &data.bounds); + for bound in bound.bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.normalize_to_macros_2_0()); + } } } - Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - let param_def_id = tcx.hir().local_def_id(param.hir_id); - Some(( - param_def_id, - hir::LifetimeName::Param(param_def_id, param.name), - )) - } - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name))| lt_name == name) - .map_or(Set1::Many, |(i, (def_id, _))| { - Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) - }) - } + match set { + Set1::Empty => ObjectLifetimeDefault::Empty, + Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeName::Param(param_def_id, _)) => { + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) } - Set1::Many => Set1::Many, - }) + _ => ObjectLifetimeDefault::Ambiguous, + } } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - // - // We still store a dummy value here to allow generic parameters - // in an arbitrary order. - Some(Set1::Empty) + _ => { + bug!("object_lifetime_default_raw must only be called on a type parameter") } - }; - - tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param)) + } } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { @@ -1413,20 +1198,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), { let LifetimeContext { tcx, map, .. } = self; - let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, - xcrate_object_lifetime_defaults, }; - let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); + let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { let _enter = span.enter(); f(&mut this); } - self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -1449,30 +1231,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late( &mut self, - parent_id: Option, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F, ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - // Find the start of nested early scopes, e.g., in methods. - let mut next_early_index = 0; - if let Some(parent_id) = parent_id { - let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.kind) { - next_early_index += 1; // Self comes before lifetimes - } - match parent.kind { - hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { - next_early_index += generics.params.len() as u32; - } - _ => {} - } - } - - let mut non_lifetime_count = 0; let mut named_late_bound_vars = 0; let lifetimes: FxIndexMap = generics .params @@ -1484,16 +1248,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { named_late_bound_vars += 1; Some(Region::late(late_bound_idx, self.tcx.hir(), param)) } else { - Some(Region::early(self.tcx.hir(), &mut next_early_index, param)) + Some(Region::early(self.tcx.hir(), param)) } } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); - let next_early_index = next_early_index + non_lifetime_count; let binders: Vec<_> = generics .params @@ -1512,52 +1272,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id, lifetimes, - next_early_index, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; self.with(scope, walk); } - fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => return 0, - - Scope::Binder { next_early_index, opaque_type_parent, .. } - if (!only_opaque_type_parent || opaque_type_parent) => - { - return next_early_index; - } - - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => scope = s, - } - } - } - - /// Returns the next index one would use for an early-bound-region - /// if extending the current scope. - fn next_early_index(&self) -> u32 { - self.next_early_index_helper(true) - } - - /// Returns the next index one would use for an `impl Trait` that - /// is being converted into an opaque type alias `impl Trait`. This will be the - /// next early index from the enclosing item, for the most - /// part. See the `opaque_type_parent` field for more info. - fn next_early_index_for_opaque_type(&self) -> u32 { - self.next_early_index_helper(false) - } - - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_lifetime_ref( &mut self, region_def_id: LocalDefId, @@ -1638,7 +1360,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - // We may fail to resolve higher-ranked lifetimes that are mentionned by APIT. + // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT. // AST-based resolution does not care for impl-trait desugaring, which are the // responibility of lowering. This may create a mismatch between the resolution // AST found (`region_def_id`) which points to HRTB, and what HIR allows. @@ -1679,17 +1401,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); } + #[instrument(level = "debug", skip(self))] fn visit_segment_args( &mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs<'tcx>, ) { - debug!( - "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", - res, depth, generic_args, - ); - if generic_args.parenthesized { self.visit_fn_like_elision( generic_args.inputs(), @@ -1707,13 +1425,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Figure out if this is a type/trait segment, // which requires object lifetime defaults. - let parent_def_id = |this: &mut Self, def_id: DefId| { - let def_key = this.tcx.def_key(def_id); - DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } - }; let type_def_id = match res { - Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)), Res::Def( DefKind::Struct | DefKind::Union @@ -1725,7 +1439,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => None, }; - debug!("visit_segment_args: type_def_id={:?}", type_def_id); + debug!(?type_def_id); // Compute a vector of defaults, one for each type parameter, // per the rules given in RFCs 599 and 1156. Example: @@ -1763,55 +1477,52 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; let map = &self.map; - let set_to_region = |set: &ObjectLifetimeDefault| match *set { - Set1::Empty => { + let generics = self.tcx.generics_of(def_id); + + // `type_def_id` points to an item, so there is nothing to inherit generics from. + debug_assert_eq!(generics.parent_count, 0); + + let set_to_region = |set: ObjectLifetimeDefault| match set { + ObjectLifetimeDefault::Empty => { if in_body { None } else { Some(Region::Static) } } - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), + ObjectLifetimeDefault::Static => Some(Region::Static), + ObjectLifetimeDefault::Param(param_def_id) => { + // This index can be used with `generic_args` since `parent_count == 0`. + let index = generics.param_def_id_to_index[¶m_def_id] as usize; + generic_args.args.get(index).and_then(|arg| match arg { + GenericArg::Lifetime(lt) => map.defs.get(<.hir_id).copied(), _ => None, - }); - r.subst(lifetimes, map) + }) } - Set1::Many => None, + ObjectLifetimeDefault::Ambiguous => None, }; - if let Some(def_id) = def_id.as_local() { - let id = self.tcx.hir().local_def_id_to_hir_id(def_id); - self.tcx - .object_lifetime_defaults(id.owner) - .unwrap() - .iter() - .map(set_to_region) - .collect() - } else { - let tcx = self.tcx; - self.xcrate_object_lifetime_defaults - .entry(def_id) - .or_insert_with(|| { - tcx.generics_of(def_id) - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Const { .. } => Some(Set1::Empty), - GenericParamDefKind::Lifetime => None, - }) - .collect() - }) - .iter() - .map(set_to_region) - .collect() - } + generics + .params + .iter() + .filter_map(|param| { + match self.tcx.def_kind(param.def_id) { + // Generic consts don't impose any constraints. + // + // We still store a dummy value here to allow generic parameters + // in an arbitrary order. + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), + DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), + // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter + // works. Ignore it because it can't have a meaningful lifetime default. + DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, + dk => bug!("unexpected def_kind {:?}", dk), + } + }) + .map(set_to_region) + .collect() }); - debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); + debug!(?object_lifetime_defaults); let mut i = 0; for arg in generic_args.args { @@ -1953,7 +1664,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_fn_like_elision( &mut self, inputs: &'tcx [hir::Ty<'tcx>], @@ -2001,7 +1712,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { debug!( node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id), @@ -2112,7 +1823,7 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet< // is, those would be potentially inputs to // projections if let Some(last_segment) = path.segments.last() { - self.visit_path_segment(path.span, last_segment); + self.visit_path_segment(last_segment); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 62843c651..26b9284fe 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -7,12 +7,13 @@ //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_typeck`. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(drain_filter)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![feature(let_else)] +#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] @@ -57,8 +58,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::{cmp, fmt, ptr}; -use tracing::debug; +use std::{fmt, ptr}; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; @@ -108,7 +108,6 @@ enum Scope<'a> { // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` // lint if it should be reported. Module(Module<'a>, Option), - RegisteredAttrs, MacroUsePrelude, BuiltinAttrs, ExternPrelude, @@ -165,7 +164,6 @@ enum ImplTraitContext { Universal(LocalDefId), } -#[derive(Eq)] struct BindingError { name: Symbol, origin: BTreeSet, @@ -173,24 +171,6 @@ struct BindingError { could_be_path: bool, } -impl PartialOrd for BindingError { - fn partial_cmp(&self, other: &BindingError) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for BindingError { - fn eq(&self, other: &BindingError) -> bool { - self.name == other.name - } -} - -impl Ord for BindingError { - fn cmp(&self, other: &BindingError) -> cmp::Ordering { - self.name.cmp(&other.name) - } -} - enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. GenericParamsFromOuterFunction(Res, HasGenericParams), @@ -650,7 +630,7 @@ pub struct NameBinding<'a> { ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, expansion: LocalExpnId, span: Span, - vis: ty::Visibility, + vis: ty::Visibility, } pub trait ToNameBinding<'a> { @@ -847,7 +827,7 @@ impl<'a> NameBinding<'a> { } } -#[derive(Debug, Default, Clone)] +#[derive(Default, Clone)] pub struct ExternPreludeEntry<'a> { extern_crate_item: Option<&'a NameBinding<'a>>, pub introduced_by_item: bool, @@ -913,11 +893,6 @@ pub struct Resolver<'a> { label_res_map: NodeMap, /// Resolutions for lifetimes. lifetimes_res_map: NodeMap, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec>, /// Lifetime parameters that lowering will have to introduce. extra_lifetime_params_map: NodeMap>, @@ -976,7 +951,6 @@ pub struct Resolver<'a> { /// 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, - registered_attrs: FxHashSet, registered_tools: RegisteredTools, macro_use_prelude: FxHashMap>, macro_map: FxHashMap, @@ -1020,7 +994,7 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: DefIdMap<(Res, ty::Visibility, Vec)>, + struct_constructors: DefIdMap<(Res, ty::Visibility, Vec>)>, /// Features enabled for this crate. active_features: FxHashSet, @@ -1253,8 +1227,7 @@ impl<'a> Resolver<'a> { } } - let (registered_attrs, registered_tools) = - macros::registered_attrs_and_tools(session, &krate.attrs); + let registered_tools = macros::registered_tools(session, &krate.attrs); let features = session.features_untracked(); @@ -1282,7 +1255,6 @@ impl<'a> Resolver<'a> { import_res_map: Default::default(), label_res_map: Default::default(), lifetimes_res_map: Default::default(), - generics_def_id_map: Vec::new(), extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), reexport_map: FxHashMap::default(), @@ -1319,7 +1291,6 @@ impl<'a> Resolver<'a> { macro_names: FxHashSet::default(), builtin_macros: Default::default(), builtin_macro_kinds: Default::default(), - registered_attrs, registered_tools, macro_use_prelude: FxHashMap::default(), macro_map: FxHashMap::default(), @@ -1450,7 +1421,6 @@ impl<'a> Resolver<'a> { import_res_map: self.import_res_map, label_res_map: self.label_res_map, lifetimes_res_map: self.lifetimes_res_map, - generics_def_id_map: self.generics_def_id_map, extra_lifetime_params_map: self.extra_lifetime_params_map, next_node_id: self.next_node_id, node_id_to_def_id: self.node_id_to_def_id, @@ -1495,7 +1465,6 @@ impl<'a> Resolver<'a> { import_res_map: self.import_res_map.clone(), label_res_map: self.label_res_map.clone(), lifetimes_res_map: self.lifetimes_res_map.clone(), - generics_def_id_map: self.generics_def_id_map.clone(), extra_lifetime_params_map: self.extra_lifetime_params_map.clone(), next_node_id: self.next_node_id.clone(), node_id_to_def_id: self.node_id_to_def_id.clone(), @@ -1821,7 +1790,11 @@ impl<'a> Resolver<'a> { self.pat_span_map.insert(node, span); } - fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { + fn is_accessible_from( + &self, + vis: ty::Visibility>, + module: Module<'a>, + ) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self) } @@ -1875,10 +1848,8 @@ impl<'a> Resolver<'a> { self.crate_loader.maybe_process_path_extern(ident.name)? }; let crate_root = self.expect_module(crate_id.as_def_id()); - Some( - (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(self.arenas), - ) + let vis = ty::Visibility::::Public; + Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas)) } }) } @@ -1946,6 +1917,16 @@ impl<'a> Resolver<'a> { def_id.as_local().map(|def_id| self.source_span[def_id]) } + /// Retrieves the name of the given `DefId`. + #[inline] + pub fn opt_name(&self, def_id: DefId) -> Option { + let def_key = match def_id.as_local() { + Some(def_id) => self.definitions.def_key(def_id), + None => self.cstore().def_key(def_id), + }; + def_key.get_opt_name() + } + /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. @@ -1985,7 +1966,7 @@ impl<'a> Resolver<'a> { _ => panic!("invalid arg index"), } } - // Cache the lookup to avoid parsing attributes for an iterm multiple times. + // Cache the lookup to avoid parsing attributes for an item multiple times. self.legacy_const_generic_args.insert(def_id, Some(ret.clone())); return Some(ret); } @@ -2015,6 +1996,24 @@ impl<'a> Resolver<'a> { } self.main_def = Some(MainDefinition { res, is_import, span }); } + + // Items that go to reexport table encoded to metadata and visible through it to other crates. + fn is_reexport(&self, binding: &NameBinding<'a>) -> Option> { + // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` + // into the crate root to actual `NameBindingKind::Import`. + if binding.is_import() + || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) + { + let res = binding.res().expect_non_local(); + // Ambiguous imports are treated as errors at this point and are + // not exposed to other crates (see #36837 for more details). + if res != def::Res::Err && !binding.is_ambiguity() { + return Some(res); + } + } + + return None; + } } fn names_to_string(names: &[Symbol]) -> String { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 070fb9c72..dafa10e9e 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -112,47 +112,32 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } -/// The code common between processing `#![register_tool]` and `#![register_attr]`. -fn registered_idents( - sess: &Session, - attrs: &[ast::Attribute], - attr_name: Symbol, - descr: &str, -) -> FxHashSet { - let mut registered = FxHashSet::default(); - for attr in sess.filter_by_name(attrs, attr_name) { +pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHashSet { + let mut registered_tools = FxHashSet::default(); + for attr in sess.filter_by_name(attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { - if let Some(old_ident) = registered.replace(ident) { - let msg = format!("{} `{}` was already registered", descr, ident); + if let Some(old_ident) = registered_tools.replace(ident) { + let msg = format!("{} `{}` was already registered", "tool", ident); sess.struct_span_err(ident.span, &msg) .span_label(old_ident.span, "already registered here") .emit(); } } None => { - let msg = format!("`{}` only accepts identifiers", attr_name); + let msg = format!("`{}` only accepts identifiers", sym::register_tool); let span = nested_meta.span(); sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit(); } } } } - registered -} - -pub(crate) fn registered_attrs_and_tools( - sess: &Session, - attrs: &[ast::Attribute], -) -> (FxHashSet, FxHashSet) { - let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute"); - let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool"); // We implicitly add `rustfmt` and `clippy` to known tools, // but it's not an error to register them explicitly. let predefined_tools = [sym::clippy, sym::rustfmt]; registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); - (registered_attrs, registered_tools) + registered_tools } // Some feature gates for inner attributes are reported as lints for backward compatibility. @@ -456,7 +441,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } PathResult::Indeterminate => indeterminate = true, // We can only be sure that a path doesn't exist after having tested all the - // posibilities, only at that time we can return false. + // possibilities, only at that time we can return false. PathResult::Failed { .. } => {} PathResult::Module(_) => panic!("unexpected path resolution"), } -- cgit v1.2.3