diff options
Diffstat (limited to 'compiler/rustc_resolve/src')
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 123 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/def_collector.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 339 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/errors.rs | 69 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 334 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 97 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 178 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 125 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 366 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 126 |
11 files changed, 1038 insertions, 729 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 82eae088803..e0d8fce0685 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, - ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; @@ -27,7 +27,7 @@ use rustc_middle::metadata::ModChild; use rustc_middle::ty::{Feed, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -210,6 +210,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Add every proc macro accessible from the current crate to the `macro_map` so diagnostics can + /// find them for suggestions. + pub(crate) fn register_macros_for_all_crates(&mut self) { + if !self.all_crate_macros_already_registered { + for def_id in self.cstore().all_proc_macro_def_ids() { + self.get_macro_by_def_id(def_id); + } + self.all_crate_macros_already_registered = true; + } + } + pub(crate) fn build_reduced_graph( &mut self, fragment: &AstFragment, @@ -223,7 +234,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) { for child in self.tcx.module_children(module.def_id()) { - let parent_scope = ParentScope::module(module, self); + let parent_scope = ParentScope::module(module, self.arenas); self.build_reduced_graph_for_external_crate_res(child, parent_scope) } } @@ -373,7 +384,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { res, )) }; - match self.r.resolve_path( + match self.r.cm().resolve_path( &segments, None, parent_scope, @@ -420,14 +431,18 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // The fields are not expanded yet. return; } - let fields = fields + let field_name = |i, field: &ast::FieldDef| { + field.ident.unwrap_or_else(|| Ident::from_str_and_span(&format!("{i}"), field.span)) + }; + let field_names: Vec<_> = + fields.iter().enumerate().map(|(i, field)| field_name(i, field)).collect(); + let defaults = fields .iter() .enumerate() - .map(|(i, field)| { - field.ident.unwrap_or_else(|| Ident::from_str_and_span(&format!("{i}"), field.span)) - }) + .filter_map(|(i, field)| field.default.as_ref().map(|_| field_name(i, field).name)) .collect(); - self.r.field_names.insert(def_id, fields); + self.r.field_names.insert(def_id, field_names); + self.r.field_defaults.insert(def_id, defaults); } fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) { @@ -470,6 +485,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span, root_id, vis, + vis_span: item.vis.span, }); self.r.indeterminate_imports.push(import); @@ -489,9 +505,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } } - // We don't add prelude imports to the globs since they only affect lexical scopes, - // which are not relevant to import resolution. - ImportKind::Glob { is_prelude: true, .. } => {} ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), _ => unreachable!(), } @@ -654,13 +667,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Glob => { - let kind = ImportKind::Glob { - is_prelude: ast::attr::contains_name(&item.attrs, sym::prelude_import), - max_vis: Cell::new(None), - id, - }; - - self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); + if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { + let kind = ImportKind::Glob { max_vis: Cell::new(None), id }; + self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); + } else { + // Resolve the prelude import early. + let path_res = + self.r.cm().maybe_resolve_path(&prefix, None, &self.parent_scope, None); + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = path_res { + self.r.prelude = Some(module); + } else { + self.r.dcx().span_err(use_tree.span, "cannot resolve a prelude import"); + } + } } ast::UseTreeKind::Nested { ref items, .. } => { // Ensure there is at most one `self` in the list @@ -902,10 +921,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items do not add names to modules. - ItemKind::Impl(box Impl { of_trait: Some(..), .. }) - | ItemKind::Impl { .. } - | ItemKind::ForeignMod(..) - | ItemKind::GlobalAsm(..) => {} + ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { unreachable!() @@ -962,45 +978,47 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, module_path: Vec::new(), vis, + vis_span: item.vis.span, }); if used { self.r.import_use_map.insert(import, Used::Other); } self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - if parent == self.r.graph_root { - let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) + if ident.name != kw::Underscore && parent == self.r.graph_root { + let norm_ident = Macros20NormalizedIdent::new(ident); + // FIXME: this error is technically unnecessary now when extern prelude is split into + // two scopes, remove it with lang team approval. + if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() - && !entry.is_import() + && entry.item_binding.is_none() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, ); - // `return` is intended to discard this binding because it's an - // unregistered ambiguity error which would result in a panic - // caused by inconsistency `path_res` - // more details: https://github.com/rust-lang/rust/pull/111761 - return; - } - let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry { - binding: Cell::new(None), - introduced_by_item: true, - }); - if orig_name.is_some() { - entry.introduced_by_item = true; - } - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - if !entry.is_import() { - entry.binding.set(Some(imported_binding)); - } else if ident.name != kw::Underscore { - self.r.dcx().span_delayed_bug( - item.span, - format!("it had been define the external module '{ident}' multiple times"), - ); } + + use indexmap::map::Entry; + match self.r.extern_prelude.entry(norm_ident) { + Entry::Occupied(mut occupied) => { + let entry = occupied.get_mut(); + if entry.item_binding.is_some() { + let msg = format!("extern crate `{ident}` already in extern prelude"); + self.r.tcx.dcx().span_delayed_bug(item.span, msg); + } else { + entry.item_binding = Some(imported_binding); + entry.introduced_by_item = orig_name.is_some(); + } + entry + } + Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { + item_binding: Some(imported_binding), + flag_binding: Cell::new(None), + only_item: true, + introduced_by_item: true, + }), + }; } self.r.define_binding_local(parent, ident, TypeNS, imported_binding); } @@ -1095,6 +1113,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span, module_path: Vec::new(), vis: Visibility::Restricted(CRATE_DEF_ID), + vis_span: item.vis.span, }) }; @@ -1122,7 +1141,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } else { for ident in single_imports.iter().cloned() { - let result = self.r.maybe_resolve_ident_in_module( + let result = self.r.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, @@ -1225,7 +1244,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Fn(box ast::Fn { ident: fn_ident, .. }) => { match self.proc_macro_stub(item, *fn_ident) { Some((macro_kind, ident, span)) => { - let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); + let macro_kinds = macro_kind.into(); + let res = Res::Def(DefKind::Macro(macro_kinds), def_id.to_def_id()); let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); self.r.new_local_macro(def_id, macro_data); self.r.proc_macro_stubs.insert(def_id); @@ -1264,6 +1284,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span, module_path: Vec::new(), vis, + vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b85a814776a..11d93a58ae2 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -33,7 +33,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS, }; -use rustc_span::{DUMMY_SP, Ident, Span, kw}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string}; @@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { if self .r .extern_prelude - .get(&extern_crate.ident) + .get(&Macros20NormalizedIdent::new(extern_crate.ident)) .is_none_or(|entry| entry.introduced_by_item) { continue; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 7d51fef28d3..14538df8187 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -5,6 +5,7 @@ use rustc_ast::*; use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; +use rustc_hir::Target; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; @@ -138,6 +139,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, i.id, + Target::MacroDef, OmitDoc::Skip, std::convert::identity, |_l| { @@ -149,9 +151,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let macro_data = self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition); - let macro_kind = macro_data.ext.macro_kind(); + let macro_kinds = macro_data.ext.macro_kinds(); opt_macro_data = Some(macro_data); - DefKind::Macro(macro_kind) + DefKind::Macro(macro_kinds) } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(use_tree) => { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b14a6edb791..ff39ba46d97 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,4 +1,3 @@ -use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents, @@ -14,7 +13,7 @@ use rustc_errors::{ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; +use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr}; use rustc_middle::bug; @@ -30,7 +29,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -320,8 +319,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if the target of the use for both bindings is the same. let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); - let from_item = - self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item); + let from_item = self + .extern_prelude + .get(&Macros20NormalizedIdent::new(ident)) + .is_none_or(|entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -467,13 +468,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn lint_if_path_starts_with_module( &mut self, - finalize: Option<Finalize>, + finalize: Finalize, path: &[Segment], second_binding: Option<NameBinding<'_>>, ) { - let Some(Finalize { node_id, root_span, .. }) = finalize else { - return; - }; + let Finalize { node_id, root_span, .. } = finalize; let first_name = match path.get(0) { // In the 2018 edition this lint is a hard error, so nothing to do @@ -530,7 +529,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.for_each_child(self, |_this, ident, _ns, binding| { let res = binding.res(); if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) { - names.push(TypoSuggestion::typo_from_ident(ident, res)); + names.push(TypoSuggestion::typo_from_ident(ident.0, res)); } }); } @@ -801,10 +800,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } err.multipart_suggestion(msg, suggestions, applicability); } - if let Some(ModuleOrUniformRoot::Module(module)) = module - && let Some(module) = module.opt_def_id() - && let Some(segment) = segment - { + + if let Some(segment) = segment { + let module = match module { + Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id, + _ => CRATE_DEF_ID.to_def_id(), + }; self.find_cfg_stripped(&mut err, &segment, module); } @@ -1015,17 +1016,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit() } - /// Lookup typo candidate in scope for a macro or import. - fn early_lookup_typo_candidate( + pub(crate) fn add_scope_set_candidates( &mut self, + suggestions: &mut Vec<TypoSuggestion>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - ident: Ident, + ctxt: SyntaxContext, filter_fn: &impl Fn(Res) -> bool, - ) -> Option<TypoSuggestion> { - let mut suggestions = Vec::new(); - let ctxt = ident.span.ctxt(); - self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { + ) { + self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); @@ -1040,28 +1039,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::DeriveHelpersCompat => { - let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); - if filter_fn(res) { - for derive in parent_scope.derives { - let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = this.resolve_macro_path( - derive, - Some(MacroKind::Derive), - parent_scope, - false, - false, - None, - None, - ) else { - continue; - }; - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::typo_from_name(*name, res)), - ); - } - } + // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { @@ -1075,7 +1053,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::Module(module, _) => { - this.add_module_candidates(module, &mut suggestions, filter_fn, None); + this.add_module_candidates(module, suggestions, filter_fn, None); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( @@ -1095,12 +1073,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } } - Scope::ExternPrelude => { - suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { + Scope::ExternPreludeItems => { + // Add idents from both item and flag scopes. + suggestions.extend(this.extern_prelude.keys().filter_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); } + Scope::ExternPreludeFlags => {} Scope::ToolPrelude => { let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); suggestions.extend( @@ -1131,6 +1111,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None::<()> }); + } + + /// Lookup typo candidate in scope for a macro or import. + fn early_lookup_typo_candidate( + &mut self, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, + ident: Ident, + filter_fn: &impl Fn(Res) -> bool, + ) -> Option<TypoSuggestion> { + let mut suggestions = Vec::new(); + let ctxt = ident.span.ctxt(); + self.add_scope_set_candidates(&mut suggestions, scope_set, parent_scope, ctxt, filter_fn); // Make sure error reporting is deterministic. suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); @@ -1244,7 +1237,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; segms.append(&mut path_segments.clone()); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; if child_accessible @@ -1317,7 +1310,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let alias_import = if let NameBindingKind::Import { import, .. } = name_binding.kind @@ -1407,7 +1400,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); if lookup_ident.span.at_least_rust_2018() { - for ident in self.extern_prelude.clone().into_keys() { + for &ident in self.extern_prelude.keys() { if ident.span.from_expansion() { // Idents are adjusted to the root context before being // resolved in the extern prelude, so reporting this to the @@ -1451,7 +1444,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if needs_disambiguation { crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } - crate_path.push(ast::PathSegment::from_ident(ident)); + crate_path.push(ast::PathSegment::from_ident(ident.0)); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, @@ -1476,34 +1469,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { krate: &Crate, sugg_span: Option<Span>, ) { - // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used - // for suggestions. - self.visit_scopes( - ScopeSet::Macro(MacroKind::Derive), - &parent_scope, - ident.span.ctxt(), - |this, scope, _use_prelude, _ctxt| { - let Scope::Module(m, _) = scope else { - return None; - }; - for (_, resolution) in this.resolutions(m).borrow().iter() { - let Some(binding) = resolution.borrow().best_binding() else { - continue; - }; - let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = - binding.res() - else { - continue; - }; - // By doing this all *imported* macros get added to the `macro_map` even if they - // are *unused*, which makes the later suggestions find them and work. - let _ = this.get_macro_by_def_id(def_id); - } - None::<()> - }, - ); + // Bring all unused `derive` macros into `macro_map` so we ensure they can be used for + // suggestions. + self.register_macros_for_all_crates(); - let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); + let is_expected = + &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into())); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), parent_scope, @@ -1552,11 +1523,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some((def_id, unused_ident)) = unused_macro { let scope = self.local_macro_def_scopes[&def_id]; let parent_nearest = parent_scope.module.nearest_parent_mod(); - if Some(parent_nearest) == scope.opt_def_id() { + let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds(); + if !unused_macro_kinds.contains(macro_kind.into()) { match macro_kind { MacroKind::Bang => { - err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); - err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); + err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident }); } MacroKind::Attr => { err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident }); @@ -1565,14 +1536,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident }); } } - return; } - } - - if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.subdiagnostic(AddedMacroUse); - return; + if Some(parent_nearest) == scope.opt_def_id() { + err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); + err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); + return; + } } if ident.name == kw::Default @@ -1587,7 +1557,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1600,13 +1570,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let desc = match binding.res() { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(), - Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { + Res::Def(DefKind::Macro(MacroKinds::BANG), _) => { + "a function-like macro".to_string() + } + Res::Def(DefKind::Macro(MacroKinds::ATTR), _) | Res::NonMacroAttr(..) => { format!("an attribute: `#[{ident}]`") } - Res::Def(DefKind::Macro(MacroKind::Derive), _) => { + Res::Def(DefKind::Macro(MacroKinds::DERIVE), _) => { format!("a derive macro: `#[derive({ident})]`") } + Res::Def(DefKind::Macro(kinds), _) => { + format!("{} {}", kinds.article(), kinds.descr()) + } Res::ToolMod => { // Don't confuse the user with tool modules. continue; @@ -1643,6 +1618,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); return; } + + if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { + err.subdiagnostic(AddedMacroUse); + return; + } } /// Given an attribute macro that failed to be resolved, look for `derive` macros that could @@ -1861,14 +1841,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag { + fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> AmbiguityErrorDiag { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; + let extern_prelude_ambiguity = || { + self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { + entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2) + }) + }; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. (b2, b1, misc2, misc1, true) } else { (b1, b2, misc1, misc2, false) }; + let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -1884,7 +1870,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { "consider adding an explicit import of `{ident}` to disambiguate" )) } - if b.is_extern_crate() && ident.span.at_least_rust_2018() { + if b.is_extern_crate() && ident.span.at_least_rust_2018() && !extern_prelude_ambiguity() + { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } match misc { @@ -1942,8 +1929,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { - let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } = - *privacy_error; + let PrivacyError { + ident, + binding, + outermost_res, + parent_scope, + single_nested, + dedup_span, + ref source, + } = *privacy_error; let res = binding.res(); let ctor_fields_span = self.ctor_fields_span(binding); @@ -1959,6 +1953,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut err = self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); + self.mention_default_field_values(source, ident, &mut err); + let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { let import_suggestions = self.lookup_import_candidates( @@ -2140,6 +2136,85 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.emit(); } + /// When a private field is being set that has a default field value, we suggest using `..` and + /// setting the value of that field implicitly with its default. + /// + /// If we encounter code like + /// ```text + /// struct Priv; + /// pub struct S { + /// pub field: Priv = Priv, + /// } + /// ``` + /// which is used from a place where `Priv` isn't accessible + /// ```text + /// let _ = S { field: m::Priv1 {} }; + /// // ^^^^^ private struct + /// ``` + /// we will suggest instead using the `default_field_values` syntax instead: + /// ```text + /// let _ = S { .. }; + /// ``` + fn mention_default_field_values( + &self, + source: &Option<ast::Expr>, + ident: Ident, + err: &mut Diag<'_>, + ) { + let Some(expr) = source else { return }; + let ast::ExprKind::Struct(struct_expr) = &expr.kind else { return }; + // We don't have to handle type-relative paths because they're forbidden in ADT + // expressions, but that would change with `#[feature(more_qualified_paths)]`. + let Some(segment) = struct_expr.path.segments.last() else { return }; + let Some(partial_res) = self.partial_res_map.get(&segment.id) else { return }; + let Some(Res::Def(_, def_id)) = partial_res.full_res() else { + return; + }; + let Some(default_fields) = self.field_defaults(def_id) else { return }; + if struct_expr.fields.is_empty() { + return; + } + let last_span = struct_expr.fields.iter().last().unwrap().span; + let mut iter = struct_expr.fields.iter().peekable(); + let mut prev: Option<Span> = None; + while let Some(field) = iter.next() { + if field.expr.span.overlaps(ident.span) { + err.span_label(field.ident.span, "while setting this field"); + if default_fields.contains(&field.ident.name) { + let sugg = if last_span == field.span { + vec![(field.span, "..".to_string())] + } else { + vec![ + ( + // Account for trailing commas and ensure we remove them. + match (prev, iter.peek()) { + (_, Some(next)) => field.span.with_hi(next.span.lo()), + (Some(prev), _) => field.span.with_lo(prev.hi()), + (None, None) => field.span, + }, + String::new(), + ), + (last_span.shrink_to_hi(), ", ..".to_string()), + ] + }; + err.multipart_suggestion_verbose( + format!( + "the type `{ident}` of field `{}` is private, but you can construct \ + the default value defined for it in `{}` using `..` in the struct \ + initializer expression", + field.ident, + self.tcx.item_name(def_id), + ), + sugg, + Applicability::MachineApplicable, + ); + break; + } + } + prev = Some(field.span); + } + } + pub(crate) fn find_similarly_named_module_or_crate( &self, ident: Symbol, @@ -2267,16 +2342,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS || ns == ValueNS { let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns_to_try, - parent_scope, - None, - ignore_binding, - ignore_import, - ) - .ok() + self.cm() + .resolve_ident_in_module( + module, + ident, + ns_to_try, + parent_scope, + None, + ignore_binding, + ignore_import, + ) + .ok() } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { @@ -2294,16 +2370,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, } } else { - self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ns_to_try), - parent_scope, - None, - false, - ignore_binding, - ignore_import, - ) - .ok() + self.cm() + .early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns_to_try), + parent_scope, + None, + false, + ignore_binding, + ignore_import, + ) + .ok() }; if let Some(binding) = binding { msg = format!( @@ -2397,7 +2474,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + if let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ValueNS), parent_scope, @@ -2527,7 +2604,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2547,7 +2624,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some(( @@ -2579,7 +2656,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2614,7 +2691,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?name, ?result); if let PathResult::Module(..) = result { return Some((path, None)); @@ -2657,9 +2734,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let binding_key = BindingKey::new(ident, MacroNS); let binding = self.resolution(crate_module, binding_key)?.binding()?; - let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { + let Res::Def(DefKind::Macro(kinds), _) = binding.res() else { return None; }; + if !kinds.contains(MacroKinds::BANG) { + return None; + } let module_name = crate_module.kind.name().unwrap_or(kw::Crate); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { @@ -2839,16 +2919,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } - let note = errors::FoundItemConfigureOut { span: ident.span }; - err.subdiagnostic(note); - - if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { - let note = errors::ItemWasBehindFeature { feature, span: cfg.1 }; - err.subdiagnostic(note); + let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + errors::ItemWas::BehindFeature { feature, span: cfg.1 } } else { - let note = errors::ItemWasCfgOut { span: cfg.1 }; - err.subdiagnostic(note); - } + errors::ItemWas::CfgOut { span: cfg.1 } + }; + let note = errors::FoundItemConfigureOut { span: ident.span, item_was }; + err.subdiagnostic(note); } } } @@ -3346,7 +3423,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { } } -fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { +fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> { for item in items { if let ItemKind::Use(..) = item.kind && is_span_suitable_for_use_injection(item.span) diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index d6b1e4de6ea..63d6fa23a14 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,10 +1,13 @@ use rustc_errors::codes::*; -use rustc_errors::{Applicability, ElidedLifetimeInPathSubdiag, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan, + Subdiagnostic, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; -use crate::Res; use crate::late::PatternSource; +use crate::{Res, fluent_generated as fluent}; #[derive(Diagnostic)] #[diag(resolve_generic_params_from_outer_item, code = E0401)] @@ -669,6 +672,12 @@ pub(crate) struct MacroSuggMovePosition { #[derive(Subdiagnostic)] pub(crate) enum MacroRulesNot { + #[label(resolve_macro_cannot_use_as_fn_like)] + Func { + #[primary_span] + span: Span, + ident: Ident, + }, #[label(resolve_macro_cannot_use_as_attr)] Attr { #[primary_span] @@ -767,6 +776,17 @@ pub(crate) struct ConsiderAddingMacroExport { } #[derive(Subdiagnostic)] +#[suggestion( + resolve_consider_marking_as_pub_crate, + code = "pub(crate)", + applicability = "maybe-incorrect" +)] +pub(crate) struct ConsiderMarkingAsPubCrate { + #[primary_span] + pub(crate) vis_span: Span, +} + +#[derive(Subdiagnostic)] #[note(resolve_consider_marking_as_pub)] pub(crate) struct ConsiderMarkingAsPub { #[primary_span] @@ -1201,26 +1221,35 @@ pub(crate) struct IdentInScopeButItIsDesc<'a> { pub(crate) imported_ident_desc: &'a str, } -#[derive(Subdiagnostic)] -#[note(resolve_found_an_item_configured_out)] pub(crate) struct FoundItemConfigureOut { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Subdiagnostic)] -#[note(resolve_item_was_behind_feature)] -pub(crate) struct ItemWasBehindFeature { - pub(crate) feature: Symbol, - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Subdiagnostic)] -#[note(resolve_item_was_cfg_out)] -pub(crate) struct ItemWasCfgOut { - #[primary_span] pub(crate) span: Span, + pub(crate) item_was: ItemWas, +} + +pub(crate) enum ItemWas { + BehindFeature { feature: Symbol, span: Span }, + CfgOut { span: Span }, +} + +impl Subdiagnostic for FoundItemConfigureOut { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + let mut multispan: MultiSpan = self.span.into(); + match self.item_was { + ItemWas::BehindFeature { feature, span } => { + let key = "feature".into(); + let value = feature.into_diag_arg(&mut None); + let msg = diag.dcx.eagerly_translate_to_string( + fluent::resolve_item_was_behind_feature, + [(&key, &value)].into_iter(), + ); + multispan.push_span_label(span, msg); + } + ItemWas::CfgOut { span } => { + multispan.push_span_label(span, fluent::resolve_item_was_cfg_out); + } + } + diag.span_note(multispan, fluent::resolve_found_an_item_configured_out); + } } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f5bc46bf053..c1b3aff4e69 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -2,7 +2,7 @@ use Determinacy::*; use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; @@ -16,10 +16,10 @@ use crate::imports::{Import, NameResolution}; use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, - ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, - NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, Used, Weak, errors, + AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, + Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, + Resolver, Scope, ScopeSet, Segment, Used, Weak, errors, }; #[derive(Copy, Clone)] @@ -44,12 +44,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. /// If the callback returns `Some` result, we stop visiting scopes and return it. - pub(crate) fn visit_scopes<T>( - &mut self, + pub(crate) fn visit_scopes<'r, T>( + mut self: CmResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, - mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option<T>, + mut visitor: impl FnMut( + &mut CmResolver<'r, 'ra, 'tcx>, + Scope<'ra>, + UsePrelude, + SyntaxContext, + ) -> Option<T>, ) -> Option<T> { // General principles: // 1. Not controlled (user-defined) names should have higher priority than controlled names @@ -97,6 +102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; let module = match scope_set { @@ -106,8 +112,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => parent_scope.module.nearest_item_scope(), }; let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); + let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { _ if module_and_extern_prelude => Scope::Module(module, None), + _ if extern_prelude => Scope::ExternPreludeItems, TypeNS | ValueNS => Scope::Module(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; @@ -138,7 +146,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::Module(..) => true, Scope::MacroUsePrelude => use_prelude || rust_2015, Scope::BuiltinAttrs => true, - Scope::ExternPrelude => use_prelude || module_and_extern_prelude, + Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { + use_prelude || module_and_extern_prelude || extern_prelude + } Scope::ToolPrelude => use_prelude, Scope::StdLibPrelude => use_prelude || ns == MacroNS, Scope::BuiltinTypes => true, @@ -146,7 +156,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if visit { let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; - if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { + if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) { return break_result; } } @@ -177,7 +187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::Module(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); - Scope::ExternPrelude + Scope::ExternPreludeItems } ValueNS | MacroNS => break, }, @@ -194,7 +204,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => { ctxt.adjust(ExpnId::root()); match ns { - TypeNS => Scope::ExternPrelude, + TypeNS => Scope::ExternPreludeItems, ValueNS => Scope::StdLibPrelude, MacroNS => Scope::MacroUsePrelude, } @@ -203,8 +213,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::MacroUsePrelude => Scope::StdLibPrelude, Scope::BuiltinAttrs => break, // nowhere else to search - Scope::ExternPrelude if module_and_extern_prelude => break, - Scope::ExternPrelude => Scope::ToolPrelude, + Scope::ExternPreludeItems => Scope::ExternPreludeFlags, + Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break, + Scope::ExternPreludeFlags => Scope::ToolPrelude, Scope::ToolPrelude => Scope::StdLibPrelude, Scope::StdLibPrelude => match ns { TypeNS => Scope::BuiltinTypes, @@ -254,7 +265,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { let ext = &self.get_macro_by_def_id(def_id).ext; if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive + && ext.macro_kinds() == MacroKinds::DERIVE && parent.expansion.outer_expn_is_descendant_of(*ctxt) { return Some((parent, derive_fallback_lint_id)); @@ -307,7 +318,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let normalized_ident = Ident { span: normalized_span, ..ident }; // Walk backwards up the ribs in scope. - let mut module = self.graph_root; for (i, rib) in ribs.iter().enumerate().rev() { debug!("walk rib\n{:?}", rib.bindings); // Use the rib kind to determine whether we are resolving parameters @@ -323,50 +333,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { *original_rib_ident_def, ribs, ))); + } else if let RibKind::Block(Some(module)) = rib.kind + && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + Shadowing::Unrestricted, + finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), + ignore_binding, + None, + ) + { + // The ident resolves to an item in a block. + return Some(LexicalScopeBinding::Item(binding)); + } else if let RibKind::Module(module) = rib.kind { + // Encountered a module item, abandon ribs and look into that module and preludes. + return self + .cm() + .early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + None, + ) + .ok() + .map(LexicalScopeBinding::Item); } - module = match rib.kind { - RibKind::Module(module) => module, - RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { - // If an invocation of this macro created `ident`, give up on `ident` - // and switch to `ident`'s source from the macro definition. - ident.span.remove_mark(); - continue; - } - _ => continue, - }; - - match module.kind { - ModuleKind::Block => {} // We can see through blocks - _ => break, - } - - let item = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - Shadowing::Unrestricted, - finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), - ignore_binding, - None, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); + if let RibKind::MacroDefinition(def) = rib.kind + && def == self.macro_def(ident.span.ctxt()) + { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ident.span.remove_mark(); } } - self.early_resolve_ident_in_lexical_scope( - orig_ident, - ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - None, - ) - .ok() - .map(LexicalScopeBinding::Item) + + unreachable!() } /// Resolve an identifier in lexical scope. @@ -375,8 +382,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// 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. #[instrument(level = "debug", skip(self))] - pub(crate) fn early_resolve_ident_in_lexical_scope( - &mut self, + pub(crate) fn early_resolve_ident_in_lexical_scope<'r>( + self: CmResolver<'r, 'ra, 'tcx>, orig_ident: Ident, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, @@ -407,6 +414,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; @@ -423,6 +431,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // to detect potential ambiguities. let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None; let mut determinacy = Determinacy::Determined; + // Shadowed bindings don't need to be marked as used or non-speculatively loaded. + macro finalize_scope() { + if innermost_result.is_none() { finalize } else { None } + } // Go through all the scopes and try to resolve the name. let break_result = self.visit_scopes( @@ -442,17 +454,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::DeriveHelpersCompat => { - // FIXME: Try running this logic earlier, to allocate name bindings for - // legacy derive helpers when creating an attribute invocation with - // following derives. Legacy derive helpers are not common, so it shouldn't - // affect performance. It should also allow to remove the `derives` - // component from `ParentScope`. let mut result = Err(Determinacy::Determined); for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - match this.resolve_macro_path( + match this.reborrow().resolve_macro_path( derive, - Some(MacroKind::Derive), + MacroKind::Derive, parent_scope, true, force, @@ -488,7 +495,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::Module(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, finalize) = + // FIXME: use `finalize_scope` here. + let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { (parent_scope, finalize) } else { @@ -497,7 +505,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = this.resolve_ident_in_module_unadjusted( + let binding = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -507,14 +515,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { Shadowing::Restricted }, - finalize, + adjusted_finalize, ignore_binding, ignore_import, ); match binding { Ok(binding) => { if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint( + this.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, orig_ident.span, @@ -555,14 +563,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(binding) => Ok((*binding, Flags::empty())), None => Err(Determinacy::Determined), }, - Scope::ExternPrelude => { - match this.extern_prelude_get(ident, finalize.is_some()) { + Scope::ExternPreludeItems => { + // FIXME: use `finalize_scope` here. + match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { Some(binding) => Ok((binding, Flags::empty())), None => Err(Determinacy::determined( this.graph_root.unexpanded_invocations.borrow().is_empty(), )), } } + Scope::ExternPreludeFlags => { + match this.extern_prelude_get_flag(ident, finalize_scope!().is_some()) { + Some(binding) => Ok((binding, Flags::empty())), + None => Err(Determinacy::Determined), + } + } Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) { Some(binding) => Ok((*binding, Flags::empty())), None => Err(Determinacy::Determined), @@ -570,7 +585,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = this.prelude - && let Ok(binding) = this.resolve_ident_in_module_unadjusted( + && let Ok(binding) = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -593,8 +608,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if matches!(ident.name, sym::f16) && !this.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) - && finalize.is_some() - && innermost_result.is_none() + && finalize_scope!().is_some() { feature_err( this.tcx.sess, @@ -607,8 +621,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if matches!(ident.name, sym::f128) && !this.tcx.features().f128() && !ident.span.allows_unstable(sym::f128) - && finalize.is_some() - && innermost_result.is_none() + && finalize_scope!().is_some() { feature_err( this.tcx.sess, @@ -625,9 +638,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match result { - Ok((binding, flags)) - if sub_namespace_match(binding.macro_kind(), macro_kind) => - { + Ok((binding, flags)) => { + if !sub_namespace_match(binding.macro_kinds(), macro_kind) { + return None; + } + if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { return Some(Ok(binding)); } @@ -687,7 +702,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { AmbiguityErrorMisc::None } }; - this.ambiguity_errors.push(AmbiguityError { + this.get_mut().ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, @@ -704,7 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { innermost_result = Some((binding, flags)); } } - Ok(..) | Err(Determinacy::Determined) => {} + Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, } @@ -725,8 +740,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &mut self, + pub(crate) fn maybe_resolve_ident_in_module<'r>( + self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -738,8 +753,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_ident_in_module( - &mut self, + pub(crate) fn resolve_ident_in_module<'r>( + self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, @@ -776,12 +791,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import, ) } - /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted( - &mut self, + fn resolve_ident_in_module_unadjusted<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -812,13 +826,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert_eq!(shadowing, Shadowing::Unrestricted); return if ns != TypeNS { Err((Determined, Weak::No)) - } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) { - Ok(binding) - } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() { - // Macro-expanded `extern crate` items can add names to extern prelude. - Err((Undetermined, Weak::No)) } else { - Err((Determined, Weak::No)) + let binding = self.early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::ExternPrelude, + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ignore_import, + ); + return binding.map_err(|determinacy| (determinacy, Weak::No)); }; } ModuleOrUniformRoot::CurrentScope => { @@ -865,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .find_map(|binding| if binding == ignore_binding { None } else { binding }); if let Some(finalize) = finalize { - return self.finalize_module_binding( + return self.get_mut().finalize_module_binding( ident, binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, @@ -875,7 +893,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - let check_usable = |this: &Self, binding: NameBinding<'ra>| { + let check_usable = |this: CmResolver<'r, 'ra, 'tcx>, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -891,7 +909,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. - if self.single_import_can_define_name( + if self.reborrow().single_import_can_define_name( &resolution, binding, ns, @@ -962,7 +980,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => {} None => continue, }; - let result = self.resolve_ident_in_module_unadjusted( + let result = self.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -1010,6 +1028,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, dedup_span: path_span, outermost_res: None, + source: None, parent_scope: *parent_scope, single_nested: path_span != root_span, }); @@ -1049,8 +1068,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Checks if a single import can define the `Ident` corresponding to `binding`. // This is used to check whether we can definitively accept a glob as a resolution. - fn single_import_can_define_name( - &mut self, + fn single_import_can_define_name<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, binding: Option<NameBinding<'ra>>, ns: Namespace, @@ -1086,7 +1105,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - match self.resolve_ident_in_module( + match self.reborrow().resolve_ident_in_module( module, *source, ns, @@ -1147,6 +1166,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1239,6 +1259,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1332,6 +1353,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1409,19 +1431,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &mut self, + pub(crate) fn maybe_resolve_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ignore_import: Option<Import<'ra>>, ) -> PathResult<'ra> { - self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import) + self.resolve_path_with_ribs( + path, + opt_ns, + parent_scope, + None, + None, + None, + None, + ignore_import, + ) } - #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_path( - &mut self, + pub(crate) fn resolve_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1433,6 +1463,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path, opt_ns, parent_scope, + None, finalize, None, ignore_binding, @@ -1440,11 +1471,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - pub(crate) fn resolve_path_with_ribs( - &mut self, + pub(crate) fn resolve_path_with_ribs<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, + source: Option<PathSource<'_, '_, '_>>, finalize: Option<Finalize>, ribs: Option<&PerNS<Vec<Rib<'ra>>>>, ignore_binding: Option<NameBinding<'ra>>, @@ -1457,18 +1489,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); + fn record_segment_res<'r, 'ra, 'tcx>( + mut this: CmResolver<'r, 'ra, 'tcx>, + finalize: Option<Finalize>, + res: Res, + id: Option<NodeId>, + ) { + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.get_mut().record_partial_res(id, PartialRes::new(res)); + } + } for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); - let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() - && let Some(id) = id - && !this.partial_res_map.contains_key(&id) - { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - }; let is_last = segment_idx + 1 == path.len(); let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; @@ -1507,7 +1544,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); let self_mod = self.resolve_self(&mut ctxt, parent_scope.module); if let Some(res) = self_mod.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(self_mod)); continue; @@ -1529,7 +1566,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `::a::b`, `crate::a::b` or `$crate::a::b` let crate_root = self.resolve_crate_root(ident); if let Some(res) = crate_root.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(crate_root)); continue; @@ -1562,21 +1599,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) + self.reborrow() + .resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + ignore_binding, + ignore_import, + ) + .map_err(|(determinacy, _)| determinacy) } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { assert!(ignore_import.is_none()); - match self.resolve_ident_in_lexical_scope( + match self.get_mut().resolve_ident_in_lexical_scope( ident, ns, parent_scope, @@ -1588,7 +1626,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), // we found a local variable or type param Some(LexicalScopeBinding::Res(res)) => { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - 1, @@ -1597,7 +1635,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::determined(finalize.is_some())), } } else { - self.early_resolve_ident_in_lexical_scope( + self.reborrow().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1618,8 +1656,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Mark every privacy error in this path with the res to the last element. This allows us // to detect the item the user cares about and either find an alternative import, or tell // the user it is not accessible. - for error in &mut self.privacy_errors[privacy_errors_len..] { - error.outermost_res = Some((res, ident)); + if finalize.is_some() { + for error in &mut self.get_mut().privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + error.source = match source { + Some(PathSource::Struct(Some(expr))) + | Some(PathSource::Expr(Some(expr))) => Some(expr.clone()), + _ => None, + }; + } } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); @@ -1628,7 +1673,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors = true; } module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { self.dcx().emit_err(errors::ToolModuleImported { @@ -1641,8 +1686,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else if res == Res::Err { return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { - self.lint_if_path_starts_with_module(finalize, path, second_binding); - record_segment_res(self, res); + if let Some(finalize) = finalize { + self.get_mut().lint_if_path_starts_with_module( + finalize, + path, + second_binding, + ); + } + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - segment_idx - 1, @@ -1677,6 +1728,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )); } + let mut this = self.reborrow(); return PathResult::failed( ident, is_last, @@ -1684,7 +1736,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors, module, || { - self.report_path_resolution_error( + this.get_mut().report_path_resolution_error( path, opt_ns, parent_scope, @@ -1701,7 +1753,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.lint_if_path_starts_with_module(finalize, path, second_binding); + if let Some(finalize) = finalize { + self.get_mut().lint_if_path_starts_with_module(finalize, path, second_binding); + } PathResult::Module(match module { Some(module) => module, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 156df45147f..d3790394d2a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -30,12 +30,13 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, - ConsiderAddingMacroExport, ConsiderMarkingAsPub, + ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, + Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, + PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, + names_to_string, }; type Res = def::Res<NodeId>; @@ -86,7 +87,6 @@ pub(crate) enum ImportKind<'ra> { id: NodeId, }, Glob { - is_prelude: bool, // 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<Option<Visibility>>, @@ -124,12 +124,9 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { .field("nested", nested) .field("id", id) .finish(), - Glob { is_prelude, max_vis, id } => f - .debug_struct("Glob") - .field("is_prelude", is_prelude) - .field("max_vis", max_vis) - .field("id", id) - .finish(), + Glob { max_vis, id } => { + f.debug_struct("Glob").field("max_vis", max_vis).field("id", id).finish() + } ExternCrate { source, target, id } => f .debug_struct("ExternCrate") .field("source", source) @@ -187,6 +184,9 @@ pub(crate) struct ImportData<'ra> { /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, pub vis: Visibility, + + /// Span of the visibility. + pub vis_span: Span, } /// All imports are unique and allocated on a same arena, @@ -489,7 +489,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define or update `binding` in `module`s glob importers. for import in glob_importers.iter() { let mut ident = key.ident; - let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -498,7 +498,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let imported_binding = self.import(binding, *import); let _ = self.try_define_local( import.parent_scope.module, - ident, + ident.0, key.ns, imported_binding, warn_ambiguity, @@ -551,13 +551,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { + self.assert_speculative = true; let mut prev_indeterminate_count = usize::MAX; let mut indeterminate_count = self.indeterminate_imports.len() * 3; while indeterminate_count < prev_indeterminate_count { prev_indeterminate_count = indeterminate_count; indeterminate_count = 0; for import in mem::take(&mut self.indeterminate_imports) { - let import_indeterminate_count = self.resolve_import(import); + let import_indeterminate_count = self.cm().resolve_import(import); indeterminate_count += import_indeterminate_count; match import_indeterminate_count { 0 => self.determined_imports.push(import), @@ -565,6 +566,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + self.assert_speculative = false; } pub(crate) fn finalize_imports(&mut self) { @@ -837,7 +839,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// /// Meanwhile, if resolve successful, the resolved bindings are written /// into the module. - fn resolve_import(&mut self, import: Import<'ra>) -> usize { + fn resolve_import<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -846,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.maybe_resolve_path( + let path_res = self.reborrow().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -866,19 +868,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (source, target, bindings, type_ns_only) } ImportKind::Glob { .. } => { - self.resolve_glob_import(import); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // speculative resolution. + self.get_mut_unchecked().resolve_glob_import(import); return 0; } _ => unreachable!(), }; let mut indeterminate_count = 0; - self.per_ns(|this, ns| { + self.per_ns_cm(|this, ns| { if !type_ns_only || ns == TypeNS { if bindings[ns].get() != PendingBinding::Pending { return; }; - let binding_result = this.maybe_resolve_ident_in_module( + let binding_result = this.reborrow().maybe_resolve_ident_in_module( module, source, ns, @@ -901,16 +905,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define_binding_local(parent, target, ns, imported_binding); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // speculative resolution. + this.get_mut_unchecked().define_binding_local( + parent, + target, + ns, + imported_binding, + ); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); - this.update_local_resolution(parent, key, false, |_, resolution| { - resolution.single_imports.swap_remove(&import); - }); + // FIXME: Use mutable resolver directly as a hack, this should be an output of + // speculative resolution. + this.get_mut_unchecked().update_local_resolution( + parent, + key, + false, + |_, resolution| { + resolution.single_imports.swap_remove(&import); + }, + ); } PendingBinding::Ready(None) } @@ -943,7 +961,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.resolve_path( + let path_res = self.cm().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1054,13 +1072,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { (source, target, bindings, type_ns_only, id) } - ImportKind::Glob { is_prelude, ref max_vis, id } => { + ImportKind::Glob { ref max_vis, id } => { if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(Ident::dummy())); - self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + self.lint_if_path_starts_with_module(finalize, &full_path, None); } if let ModuleOrUniformRoot::Module(module) = module @@ -1077,8 +1095,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: None, }); } - if !is_prelude - && let Some(max_vis) = max_vis.get() + if let Some(max_vis) = max_vis.get() && !max_vis.is_at_least(import.vis, self.tcx) { let def_id = self.local_def_id(id); @@ -1103,7 +1120,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path( + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path( &path, None, &import.parent_scope, @@ -1121,7 +1138,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = this.cm().resolve_ident_in_module( module, ident, ns, @@ -1184,7 +1201,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_failed = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = this.cm().resolve_ident_in_module( module, ident, ns, @@ -1354,6 +1371,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic( ConsiderAddingMacroExport { span: binding.span, }); + err.subdiagnostic( ConsiderMarkingAsPubCrate { + vis_span: import.vis_span, + }); } _ => { err.subdiagnostic( ConsiderMarkingAsPub { @@ -1373,7 +1393,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { - this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding)); + this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } }); } @@ -1426,7 +1446,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match this.early_resolve_ident_in_lexical_scope( + match this.cm().early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns), &import.parent_scope, @@ -1466,7 +1486,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_glob_import(&mut self, import: Import<'ra>) { // This function is only called for glob imports. - let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; + let ImportKind::Glob { id, .. } = import.kind else { unreachable!() }; let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span }); @@ -1485,9 +1505,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if module == import.parent_scope.module { return; - } else if is_prelude { - self.prelude = Some(module); - return; } // Add to module's glob_importers @@ -1504,7 +1521,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) .collect::<Vec<_>>(); for (mut key, binding) in bindings { - let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { + let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) { Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, @@ -1517,7 +1534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define_local( import.parent_scope.module, - key.ident, + key.ident.0, key.ns, imported_binding, warn_ambiguity, @@ -1550,7 +1567,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { next_binding = binding; } - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + children.push(ModChild { ident: ident.0, res, vis: binding.vis, reexport_chain }); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 261d099abdc..679e663f886 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -12,7 +12,6 @@ use std::collections::BTreeSet; use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; -use rustc_ast::ptr::P; use rustc_ast::visit::{ AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list, }; @@ -193,6 +192,13 @@ pub(crate) enum RibKind<'ra> { /// No restriction needs to be applied. Normal, + /// We passed through an `ast::Block`. + /// Behaves like `Normal`, but also partially like `Module` if the block contains items. + /// `Block(None)` must be always processed in the same way as `Block(Some(module))` + /// with empty `module`. The module can be `None` only because creation of some definitely + /// empty modules is skipped as an optimization. + Block(Option<Module<'ra>>), + /// We passed through an impl or trait and are now in one of its /// methods or associated types. Allow references to ty params that impl or trait /// binds. Disallow any other upvars (including other ty params that are @@ -211,7 +217,7 @@ pub(crate) enum RibKind<'ra> { /// All other constants aren't allowed to use generic params at all. ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), - /// We passed through a module. + /// We passed through a module item. Module(Module<'ra>), /// We passed through a `macro_rules!` statement @@ -243,6 +249,7 @@ impl RibKind<'_> { pub(crate) fn contains_params(&self) -> bool { match self { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::ConstantItem(..) | RibKind::Module(_) @@ -259,15 +266,8 @@ impl RibKind<'_> { fn is_label_barrier(self) -> bool { match self { RibKind::Normal | RibKind::MacroDefinition(..) => false, - - RibKind::AssocItem - | RibKind::FnOrCoroutine - | RibKind::Item(..) - | RibKind::ConstantItem(..) - | RibKind::Module(..) - | RibKind::ForwardGenericParamBan(_) - | RibKind::ConstParamTy - | RibKind::InlineAsmSym => true, + RibKind::FnOrCoroutine | RibKind::ConstantItem(..) => true, + kind => bug!("unexpected rib kind: {kind:?}"), } } } @@ -425,7 +425,7 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> { /// Paths in path patterns `Path`. Pat, /// Paths in struct expressions and patterns `Path { .. }`. - Struct, + Struct(Option<&'a Expr>), /// Paths in tuple struct patterns `Path(..)`. TupleStruct(Span, &'ra [Span]), /// `m::A::B` in `<T as m::A>::B::C`. @@ -448,7 +448,7 @@ impl PathSource<'_, '_, '_> { match self { PathSource::Type | PathSource::Trait(_) - | PathSource::Struct + | PathSource::Struct(_) | PathSource::DefineOpaques => TypeNS, PathSource::Expr(..) | PathSource::Pat @@ -465,7 +465,7 @@ impl PathSource<'_, '_, '_> { PathSource::Type | PathSource::Expr(..) | PathSource::Pat - | PathSource::Struct + | PathSource::Struct(_) | PathSource::TupleStruct(..) | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) @@ -482,7 +482,7 @@ impl PathSource<'_, '_, '_> { PathSource::Type => "type", PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", - PathSource::Struct => "struct, variant or union type", + PathSource::Struct(_) => "struct, variant or union type", PathSource::TraitItem(ValueNS, PathSource::TupleStruct(..)) | PathSource::TupleStruct(..) => "tuple struct or tuple variant", PathSource::TraitItem(ns, _) => match ns { @@ -577,7 +577,7 @@ impl PathSource<'_, '_, '_> { || matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _)) } PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(), - PathSource::Struct => matches!( + PathSource::Struct(_) => matches!( res, Res::Def( DefKind::Struct @@ -617,8 +617,8 @@ impl PathSource<'_, '_, '_> { (PathSource::Trait(_), false) => E0405, (PathSource::Type | PathSource::DefineOpaques, true) => E0573, (PathSource::Type | PathSource::DefineOpaques, false) => E0412, - (PathSource::Struct, true) => E0574, - (PathSource::Struct, false) => E0422, + (PathSource::Struct(_), true) => E0574, + (PathSource::Struct(_), false) => E0422, (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423, (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425, (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532, @@ -670,7 +670,7 @@ pub(crate) struct UnnecessaryQualification<'ra> { #[derive(Default, Debug)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. - current_trait_assoc_items: Option<&'ast [P<AssocItem>]>, + current_trait_assoc_items: Option<&'ast [Box<AssocItem>]>, /// The current self type if inside an impl (used for better errors). current_self_type: Option<Ty>, @@ -720,7 +720,7 @@ struct DiagMetadata<'ast> { current_type_path: Option<&'ast Ty>, /// The current impl items (used to suggest). - current_impl_items: Option<&'ast [P<AssocItem>]>, + current_impl_items: Option<&'ast [Box<AssocItem>]>, /// When processing impl trait currently_processing_impl_trait: Option<(TraitRef, Ty)>, @@ -1424,7 +1424,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; - let parent_scope = ParentScope::module(graph_root, resolver); + let parent_scope = ParentScope::module(graph_root, resolver.arenas); let start_rib_kind = RibKind::Module(graph_root); LateResolutionVisitor { r: resolver, @@ -1483,11 +1483,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import finalize: Option<Finalize>, + source: PathSource<'_, 'ast, 'ra>, ) -> PathResult<'ra> { - self.r.resolve_path_with_ribs( + self.r.cm().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, + Some(source), finalize, Some(&self.ribs), None, @@ -1526,19 +1528,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ret } - fn with_mod_rib<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let module = self.r.expect_module(self.r.local_def_id(id).to_def_id()); - // Move down in the graph. - let orig_module = replace(&mut self.parent_scope.module, module); - self.with_rib(ValueNS, RibKind::Module(module), |this| { - this.with_rib(TypeNS, RibKind::Module(module), |this| { - let ret = f(this); - this.parent_scope.module = orig_module; - ret - }) - }) - } - fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) { // For type parameter defaults, we have to ban access // to following type parameters, as the GenericArgs can only @@ -1967,7 +1956,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, partial_res: PartialRes, path: &[Segment], - source: PathSource<'_, '_, '_>, + source: PathSource<'_, 'ast, 'ra>, path_span: Span, ) { let proj_start = path.len() - partial_res.unresolved_segments(); @@ -2020,7 +2009,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::ReturnTypeNotation => false, PathSource::Expr(..) | PathSource::Pat - | PathSource::Struct + | PathSource::Struct(_) | PathSource::TupleStruct(..) | PathSource::DefineOpaques | PathSource::Delegation => true, @@ -2619,7 +2608,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_adt(item, generics); } - ItemKind::Impl(box Impl { + ItemKind::Impl(Impl { ref generics, ref of_trait, ref self_ty, @@ -2630,7 +2619,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_implementation( &item.attrs, generics, - of_trait, + of_trait.as_deref(), self_ty, item.id, impl_items, @@ -2676,20 +2665,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - self.with_mod_rib(item.id, |this| { - if mod_inner_docs { - this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); - } - let old_macro_rules = this.parent_scope.macro_rules; - visit::walk_item(this, item); - // Maintain macro_rules scopes in the same way as during early resolution - // for diagnostics and doc links. - if item.attrs.iter().all(|attr| { - !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) - }) { - this.parent_scope.macro_rules = old_macro_rules; - } + let module = self.r.expect_module(self.r.local_def_id(item.id).to_def_id()); + let orig_module = replace(&mut self.parent_scope.module, module); + self.with_rib(ValueNS, RibKind::Module(module), |this| { + this.with_rib(TypeNS, RibKind::Module(module), |this| { + if mod_inner_docs { + this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); + } + let old_macro_rules = this.parent_scope.macro_rules; + visit::walk_item(this, item); + // Maintain macro_rules scopes in the same way as during early resolution + // for diagnostics and doc links. + if item.attrs.iter().all(|attr| { + !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) + }) { + this.parent_scope.macro_rules = old_macro_rules; + } + }) }); + self.parent_scope.module = orig_module; } ItemKind::Static(box ast::StaticItem { @@ -2820,9 +2814,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // We also can't shadow bindings from associated parent items. for ns in [ValueNS, TypeNS] { for parent_rib in self.ribs[ns].iter().rev() { - // Break at mod level, to account for nested items which are + // Break at module or block level, to account for nested items which are // allowed to shadow generic param names. - if matches!(parent_rib.kind, RibKind::Module(..)) { + if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block(..)) { break; } @@ -3038,7 +3032,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } /// When evaluating a `trait` use its associated types' idents for suggestions in E0412. - fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) { + fn resolve_trait_items(&mut self, trait_items: &'ast [Box<AssocItem>]) { let trait_assoc_items = replace(&mut self.diag_metadata.current_trait_assoc_items, Some(trait_items)); @@ -3176,10 +3170,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, attrs: &[ast::Attribute], generics: &'ast Generics, - opt_trait_reference: &'ast Option<TraitRef>, + of_trait: Option<&'ast ast::TraitImplHeader>, self_type: &'ast Ty, item_id: NodeId, - impl_items: &'ast [P<AssocItem>], + impl_items: &'ast [Box<AssocItem>], ) { debug!("resolve_implementation"); // If applicable, create a rib for the type parameters. @@ -3200,7 +3194,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| { // Resolve the trait reference, if necessary. this.with_optional_trait_ref( - opt_trait_reference.as_ref(), + of_trait.map(|t| &t.trait_ref), self_type, |this, trait_id| { this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id)); @@ -3223,9 +3217,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { is_trait_impl: trait_id.is_some() }; this.with_self_rib(res, |this| { - if let Some(trait_ref) = opt_trait_reference.as_ref() { + if let Some(of_trait) = of_trait { // Resolve type arguments in the trait path. - visit::walk_trait_ref(this, trait_ref); + visit::walk_trait_ref(this, &of_trait.trait_ref); } // Resolve the self type. this.visit_ty(self_type); @@ -3671,7 +3665,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// pattern as a whole counts as a never pattern (since it's definitionallly unreachable). fn compute_and_check_or_pat_binding_map( &mut self, - pats: &[P<Pat>], + pats: &[Box<Pat>], ) -> Result<FxIndexMap<Ident, BindingInfo>, IsNeverPattern> { let mut missing_vars = FxIndexMap::default(); let mut inconsistent_vars = FxIndexMap::default(); @@ -3867,7 +3861,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.smart_resolve_path(pat.id, qself, path, PathSource::Pat); } PatKind::Struct(ref qself, ref path, ref _fields, ref rest) => { - self.smart_resolve_path(pat.id, qself, path, PathSource::Struct); + self.smart_resolve_path(pat.id, qself, path, PathSource::Struct(None)); self.record_patterns_with_skipped_bindings(pat, rest); } PatKind::Or(ref ps) => { @@ -4109,9 +4103,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn smart_resolve_path( &mut self, id: NodeId, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &Path, - source: PathSource<'_, 'ast, '_>, + source: PathSource<'_, 'ast, 'ra>, ) { self.smart_resolve_path_fragment( qself, @@ -4126,9 +4120,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { #[instrument(level = "debug", skip(self))] fn smart_resolve_path_fragment( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], - source: PathSource<'_, 'ast, '_>, + source: PathSource<'_, 'ast, 'ra>, finalize: Finalize, record_partial_res: RecordPartialRes, parent_qself: Option<&QSelf>, @@ -4231,13 +4225,21 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // // And that's what happens below - we're just mixing both messages // into a single one. + let failed_to_resolve = match parent_err.node { + ResolutionError::FailedToResolve { .. } => true, + _ => false, + }; let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); // overwrite all properties with the parent's error message err.messages = take(&mut parent_err.messages); err.code = take(&mut parent_err.code); swap(&mut err.span, &mut parent_err.span); - err.children = take(&mut parent_err.children); + if failed_to_resolve { + err.children = take(&mut parent_err.children); + } else { + err.children.append(&mut parent_err.children); + } err.sort_span = parent_err.sort_span; err.is_lint = parent_err.is_lint.clone(); @@ -4268,7 +4270,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if path.len() == 2 && let [segment] = prefix_path { - // Delay to check whether methond name is an associated function or not + // Delay to check whether method name is an associated function or not // ``` // let foo = Foo {}; // foo::bar(); // possibly suggest to foo.bar(); @@ -4306,7 +4308,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself, path, ns, - path_span, source.defer_to_typeck(), finalize, source, @@ -4358,7 +4359,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std))); std_path.extend(path); if let PathResult::Module(_) | PathResult::NonModule(_) = - self.resolve_path(&std_path, Some(ns), None) + self.resolve_path(&std_path, Some(ns), None, source) { // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8` let item_span = @@ -4426,13 +4427,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], primary_ns: Namespace, - span: Span, defer_to_typeck: bool, finalize: Finalize, - source: PathSource<'_, 'ast, '_>, + source: PathSource<'_, 'ast, 'ra>, ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { let mut fin_res = None; @@ -4454,15 +4454,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } assert!(primary_ns != MacroNS); - - if qself.is_none() { - let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; - if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) - { - return Ok(Some(PartialRes::new(res))); - } + if qself.is_none() + && let PathResult::NonModule(res) = + self.r.cm().maybe_resolve_path(path, Some(MacroNS), &self.parent_scope, None) + { + return Ok(Some(res)); } Ok(fin_res) @@ -4471,11 +4467,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Handles paths that may refer to associated items. fn resolve_qpath( &mut self, - qself: &Option<P<QSelf>>, + qself: &Option<Box<QSelf>>, path: &[Segment], ns: Namespace, finalize: Finalize, - source: PathSource<'_, 'ast, '_>, + source: PathSource<'_, 'ast, 'ra>, ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { debug!( "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})", @@ -4538,7 +4534,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ))); } - let result = match self.resolve_path(path, Some(ns), Some(finalize)) { + let result = match self.resolve_path(path, Some(ns), Some(finalize), source) { PathResult::NonModule(path_res) => path_res, PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { PartialRes::new(module.res().unwrap()) @@ -4649,16 +4645,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving block) entering block"); // Move down in the graph, if there's an anonymous module rooted here. let orig_module = self.parent_scope.module; - let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference + let anonymous_module = self.r.block_map.get(&block.id).copied(); let mut num_macro_definition_ribs = 0; if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); - self.ribs[ValueNS].push(Rib::new(RibKind::Module(anonymous_module))); - self.ribs[TypeNS].push(Rib::new(RibKind::Module(anonymous_module))); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); + self.ribs[TypeNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); self.parent_scope.module = anonymous_module; } else { - self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(None))); } // Descend into the block. @@ -4761,7 +4757,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ExprKind::Struct(ref se) => { - self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct); + self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct(parent)); // This is the same as `visit::walk_expr(self, expr);`, but we want to pass the // parent in for accurate suggestions when encountering `Foo { bar }` that should // have been `Foo { bar: self.bar }`. @@ -5168,7 +5164,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) - | ItemKind::Impl(box Impl { generics, .. }) + | ItemKind::Impl(Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) | ItemKind::TraitAlias(_, generics, _) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 98e48664e68..9b201e40d13 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -4,7 +4,6 @@ use std::borrow::Cow; use std::iter; use std::ops::Deref; -use rustc_ast::ptr::P; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty}; use rustc_ast::{ self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind, @@ -20,14 +19,13 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; +use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_middle::ty; use rustc_session::{Session, lint}; use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; use rustc_span::edition::Edition; -use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -40,8 +38,8 @@ use crate::late::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors, - path_names_to_string, + Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, ScopeSet, Segment, + errors, path_names_to_string, }; type Res = def::Res<ast::NodeId>; @@ -175,7 +173,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, path: &[Segment], span: Span, - source: PathSource<'_, '_, '_>, + source: PathSource<'_, 'ast, 'ra>, res: Option<Res>, ) -> BaseError { // Make the base error. @@ -319,7 +317,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None) } else { let mod_path = &path[..path.len() - 1]; - let mod_res = self.resolve_path(mod_path, Some(TypeNS), None); + let mod_res = self.resolve_path(mod_path, Some(TypeNS), None, source); let mod_prefix = match mod_res { PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(), _ => None, @@ -420,7 +418,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { path: &[Segment], following_seg: Option<&Segment>, span: Span, - source: PathSource<'_, '_, '_>, + source: PathSource<'_, 'ast, 'ra>, res: Option<Res>, qself: Option<&QSelf>, ) -> (Diag<'tcx>, Vec<ImportSuggestion>) { @@ -525,9 +523,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } self.err_code_special_cases(&mut err, source, path, span); - if let Some(module) = base_error.module { - self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module); - } + let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id()); + self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module); (err, candidates) } @@ -852,9 +849,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // Try to find in last block rib - if let Some(rib) = &self.last_block_rib - && let RibKind::Normal = rib.kind - { + if let Some(rib) = &self.last_block_rib { for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -903,7 +898,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if path.len() == 1 { for rib in self.ribs[ns].iter().rev() { let item = path[0].ident; - if let RibKind::Module(module) = rib.kind + if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind && let Some(did) = find_doc_alias_name(self.r, module, item.name) { return Some((did, item)); @@ -1016,7 +1011,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_typo( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_, '_>, + source: PathSource<'_, 'ast, 'ra>, path: &[Segment], following_seg: Option<&Segment>, span: Span, @@ -1335,7 +1330,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, err: &mut Diag<'_>, - source: PathSource<'_, '_, '_>, + source: PathSource<'_, 'ast, 'ra>, res: Option<Res>, span: Span, ) { @@ -1343,7 +1338,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.diag_metadata.currently_processing_impl_trait.clone() && let TyKind::Path(_, self_ty_path) = &self_ty.kind && let PathResult::Module(ModuleOrUniformRoot::Module(module)) = - self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None) + self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source) && let ModuleKind::Def(DefKind::Trait, ..) = module.kind && trait_ref.path.span == span && let PathSource::Trait(_) = source @@ -1451,13 +1446,13 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn get_single_associated_item( &mut self, path: &[Segment], - source: &PathSource<'_, '_, '_>, + source: &PathSource<'_, 'ast, 'ra>, filter_fn: &impl Fn(Res) -> bool, ) -> Option<TypoSuggestion> { if let crate::PathSource::TraitItem(_, _) = source { let mod_path = &path[..path.len() - 1]; if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = - self.resolve_path(mod_path, None, None) + self.resolve_path(mod_path, None, None, *source) { let targets: Vec<_> = self .r @@ -1473,7 +1468,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }) .collect(); if let [target] = targets.as_slice() { - return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); + return Some(TypoSuggestion::single_item_from_ident( + target.0.ident.0, + target.1, + )); } } } @@ -1849,12 +1847,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { match (res, source) { ( - Res::Def(DefKind::Macro(MacroKind::Bang), def_id), + Res::Def(DefKind::Macro(kinds), def_id), PathSource::Expr(Some(Expr { kind: ExprKind::Index(..) | ExprKind::Call(..), .. })) - | PathSource::Struct, - ) => { + | PathSource::Struct(_), + ) if kinds.contains(MacroKinds::BANG) => { // Don't suggest macro if it's unstable. let suggestable = def_id.is_local() || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable()); @@ -1879,7 +1877,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.note("if you want the `try` keyword, you need Rust 2018 or later"); } } - (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { + (Res::Def(DefKind::Macro(kinds), _), _) if kinds.contains(MacroKinds::BANG) => { err.span_label(span, fallback_label.to_string()); } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { @@ -2148,7 +2146,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err: &mut Diag<'_>, path_span: Span, call_span: Span, - args: &[P<Expr>], + args: &[Box<Expr>], ) { if def_id.is_local() { // Doing analysis on local `DefId`s would cause infinite recursion. @@ -2387,7 +2385,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref - && let Ok(binding) = self.r.maybe_resolve_ident_in_module( + && let Ok(binding) = self.r.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ns, @@ -2458,59 +2456,33 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + if let RibKind::Block(Some(module)) = rib.kind { + self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); + } else if let RibKind::Module(module) = rib.kind { + // Encountered a module item, abandon ribs and look into that module and preludes. + self.r.add_scope_set_candidates( + &mut names, + ScopeSet::Late(ns, module, None), + &self.parent_scope, + ctxt, + filter_fn, + ); + break; + } + if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. ctxt.remove_mark(); - continue; } - - // Items in scope - if let RibKind::Module(module) = rib.kind { - // Items from this module - self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); - - if let ModuleKind::Block = module.kind { - // We can see through blocks - } else { - // Items from the prelude - if !module.no_implicit_prelude { - let extern_prelude = self.r.extern_prelude.clone(); - names.extend(extern_prelude.iter().flat_map(|(ident, _)| { - self.r - .cstore_mut() - .maybe_process_path_extern(self.r.tcx, ident.name) - .and_then(|crate_id| { - let crate_mod = - Res::Def(DefKind::Mod, crate_id.as_def_id()); - - filter_fn(crate_mod).then(|| { - TypoSuggestion::typo_from_ident(*ident, crate_mod) - }) - }) - })); - - if let Some(prelude) = self.r.prelude { - self.r.add_module_candidates(prelude, &mut names, &filter_fn, None); - } - } - break; - } - } - } - // Add primitive types to the mix - if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend(PrimTy::ALL.iter().map(|prim_ty| { - TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty)) - })) } } else { // Search in module. let mod_path = &path[..path.len() - 1]; if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = - self.resolve_path(mod_path, Some(TypeNS), None) + self.resolve_path(mod_path, Some(TypeNS), None, PathSource::Type) { self.r.add_module_candidates(module, &mut names, &filter_fn, None); } @@ -2649,7 +2621,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); + path_segments.push(ast::PathSegment::from_ident(ident.0)); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { @@ -2688,7 +2660,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { enum_module.for_each_child(self.r, |_, ident, _, name_binding| { if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); + segms.push(ast::PathSegment::from_ident(ident.0)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; variants.push((path, def_id, kind)); } @@ -3681,7 +3653,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let TyKind::Path(None, path) = &ty.kind { // Check if the path being borrowed is likely to be owned. let path: Vec<_> = Segment::from_path(path); - match self.resolve_path(&path, Some(TypeNS), None) { + match self.resolve_path( + &path, + Some(TypeNS), + None, + PathSource::Type, + ) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => { match module.res() { Some(Res::PrimTy(PrimTy::Str)) => { @@ -3795,7 +3772,7 @@ fn mk_where_bound_predicate( ident: last.ident, gen_args: None, kind: ast::AssocItemConstraintKind::Equality { - term: ast::Term::Ty(ast::ptr::P(ast::Ty { + term: ast::Term::Ty(Box::new(ast::Ty { kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()), id: DUMMY_NODE_ID, span: DUMMY_SP, @@ -3812,7 +3789,7 @@ fn mk_where_bound_predicate( Some(_) => return None, None => { second_last.args = - Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + Some(Box::new(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args: ThinVec::from([added_constraint]), span: DUMMY_SP, }))); @@ -3825,7 +3802,7 @@ fn mk_where_bound_predicate( let new_where_bound_predicate = ast::WhereBoundPredicate { bound_generic_params: ThinVec::new(), - bounded_ty: ast::ptr::P(ty.clone()), + bounded_ty: Box::new(ty.clone()), bounds: vec![ast::GenericBound::Trait(ast::PolyTraitRef { bound_generic_params: ThinVec::new(), modifiers: ast::TraitBoundModifiers::NONE, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index dbde6f7cfd7..2063c46124c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -12,8 +12,11 @@ #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(decl_macro)] +#![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(rustc_attrs)] @@ -52,7 +55,8 @@ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{ - self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS, + self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes, + PerNS, }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; @@ -71,7 +75,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -112,34 +116,46 @@ impl Determinacy { } /// A specific scope in which a name can be looked up. -/// This enum is currently used only for early resolution (imports and macros), -/// but not for late resolution yet. #[derive(Clone, Copy, Debug)] enum Scope<'ra> { + /// Inert attributes registered by derive macros. DeriveHelpers(LocalExpnId), + /// Inert attributes registered by derive macros, but used before they are actually declared. + /// This scope will exist until the compatibility lint `LEGACY_DERIVE_HELPERS` + /// is turned into a hard error. DeriveHelpersCompat, + /// Textual `let`-like scopes introduced by `macro_rules!` items. MacroRules(MacroRulesScopeRef<'ra>), - // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` - // lint if it should be reported. + /// Names declared in the given module. + /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + /// lint if it should be reported. Module(Module<'ra>, Option<NodeId>), + /// Names introduced by `#[macro_use]` attributes on `extern crate` items. MacroUsePrelude, + /// Built-in attributes. BuiltinAttrs, - ExternPrelude, + /// Extern prelude names introduced by `extern crate` items. + ExternPreludeItems, + /// Extern prelude names introduced by `--extern` flags. + ExternPreludeFlags, + /// Tool modules introduced with `#![register_tool]`. ToolPrelude, + /// Standard library prelude introduced with an internal `#[prelude_import]` import. StdLibPrelude, + /// Built-in types. BuiltinTypes, } /// Names from different contexts may want to visit different subsets of all specific scopes /// with different restrictions when looking up the resolution. -/// This enum is currently used only for early resolution (imports and macros), -/// but not for late resolution yet. #[derive(Clone, Copy, Debug)] enum ScopeSet<'ra> { /// All scopes with the given namespace. All(Namespace), /// A module, then extern prelude (used for mixed 2015-2018 mode in macros). ModuleAndExternPrelude(Namespace, Module<'ra>), + /// Just two extern prelude scopes. + ExternPrelude, /// All scopes with macro namespace and the given macro kind restriction. Macro(MacroKind), /// All scopes with the given namespace, used for partially performing late resolution. @@ -162,11 +178,11 @@ struct ParentScope<'ra> { impl<'ra> ParentScope<'ra> { /// Creates a parent scope with the passed argument used as the module scope component, /// and other scope components set to default empty values. - fn module(module: Module<'ra>, resolver: &Resolver<'ra, '_>) -> ParentScope<'ra> { + fn module(module: Module<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { ParentScope { module, expansion: LocalExpnId::ROOT, - macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), + macro_rules: arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], } } @@ -531,7 +547,7 @@ impl ModuleKind { struct BindingKey { /// The identifier for the binding, always the `normalize_to_macros_2_0` version of the /// identifier. - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, /// When we add an underscore binding (with ident `_`) to some module, this field has /// a non-zero value that uniquely identifies this binding in that module. @@ -543,7 +559,7 @@ struct BindingKey { impl BindingKey { fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator: 0 } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 } } fn new_disambiguated( @@ -552,7 +568,7 @@ impl BindingKey { disambiguator: impl FnOnce() -> u32, ) -> BindingKey { let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: ident.normalize_to_macros_2_0(), ns, disambiguator } + BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator } } } @@ -593,7 +609,8 @@ struct ModuleData<'ra> { globs: RefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>, Option<Module<'ra>>)]>>>, + traits: + RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -659,7 +676,7 @@ impl<'ra> Module<'ra> { fn for_each_child<'tcx, R: AsRef<Resolver<'ra, 'tcx>>>( self, resolver: &R, - mut f: impl FnMut(&R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -671,7 +688,7 @@ impl<'ra> Module<'ra> { fn for_each_child_mut<'tcx, R: AsMut<Resolver<'ra, 'tcx>>>( self, resolver: &mut R, - mut f: impl FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -764,7 +781,10 @@ impl<'ra> std::ops::Deref for Module<'ra> { impl<'ra> fmt::Debug for Module<'ra> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.res()) + match self.kind { + ModuleKind::Block => write!(f, "block"), + ModuleKind::Def(..) => write!(f, "{:?}", self.res()), + } } } @@ -820,6 +840,7 @@ struct PrivacyError<'ra> { parent_scope: ParentScope<'ra>, /// Is the format `use a::{b,c}`? single_nested: bool, + source: Option<ast::Expr>, } #[derive(Debug)] @@ -966,8 +987,8 @@ impl<'ra> NameBindingData<'ra> { matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _)) } - fn macro_kind(&self) -> Option<MacroKind> { - self.res().macro_kind() + fn macro_kinds(&self) -> Option<MacroKinds> { + self.res().macro_kinds() } // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding` @@ -1009,16 +1030,18 @@ impl<'ra> NameBindingData<'ra> { #[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { - binding: Cell<Option<NameBinding<'ra>>>, + /// Binding from an `extern crate` item. + item_binding: Option<NameBinding<'ra>>, + /// Binding from an `--extern` flag, lazily populated on first use. + flag_binding: Cell<Option<NameBinding<'ra>>>, + /// There was no `--extern` flag introducing this name, + /// `flag_binding` doesn't need to be populated. + only_item: bool, + /// `item_binding` is non-redundant, happens either when `only_item` is true, + /// or when `extern crate` introducing `item_binding` used renaming. introduced_by_item: bool, } -impl ExternPreludeEntry<'_> { - fn is_import(&self) -> bool { - self.binding.get().is_some_and(|binding| binding.is_import()) - } -} - struct DeriveData { resolutions: Vec<DeriveResolution>, helper_attrs: Vec<(usize, Ident)>, @@ -1053,21 +1076,25 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, - prelude: Option<Module<'ra>>, - extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'ra>>, + /// Assert that we are in speculative resolution mode. + assert_speculative: bool, + + prelude: Option<Module<'ra>> = None, + extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap<Vec<Ident>>, + field_defaults: LocalDefIdMap<Vec<Symbol>>, /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. /// Used for hints during error reporting. field_visibility_spans: FxHashMap<DefId, Vec<Span>>, /// All imports known to succeed or fail. - determined_imports: Vec<Import<'ra>>, + determined_imports: Vec<Import<'ra>> = Vec::new(), /// All non-determined imports. - indeterminate_imports: Vec<Import<'ra>>, + indeterminate_imports: Vec<Import<'ra>> = Vec::new(), // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. @@ -1118,19 +1145,19 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>, - glob_error: Option<ErrorGuaranteed>, - visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, + glob_error: Option<ErrorGuaranteed> = None, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), used_imports: FxHashSet<NodeId>, maybe_unused_trait_imports: FxIndexSet<LocalDefId>, /// Privacy errors are delayed until the end in order to deduplicate them. - privacy_errors: Vec<PrivacyError<'ra>>, + privacy_errors: Vec<PrivacyError<'ra>> = Vec::new(), /// Ambiguity errors are delayed for deduplication. - ambiguity_errors: Vec<AmbiguityError<'ra>>, + ambiguity_errors: Vec<AmbiguityError<'ra>> = Vec::new(), /// `use` injections are delayed for better placement and deduplication. - use_injections: Vec<UseError<'tcx>>, + use_injections: Vec<UseError<'tcx>> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. - macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>, + macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), arenas: &'ra ResolverArenas<'ra>, dummy_binding: NameBinding<'ra>, @@ -1155,10 +1182,11 @@ pub struct Resolver<'ra, 'tcx> { unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. + // FIXME: Remove interior mutability when speculative resolution produces these as outputs. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>, + RefCell<Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>>, multi_segment_macro_resolutions: - Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, + RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global @@ -1181,9 +1209,9 @@ pub struct Resolver<'ra, 'tcx> { /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap<Symbol, Span>, - potentially_unused_imports: Vec<Import<'ra>>, + potentially_unused_imports: Vec<Import<'ra>> = Vec::new(), - potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>>, + potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>> = Vec::new(), /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. @@ -1192,7 +1220,7 @@ pub struct Resolver<'ra, 'tcx> { lint_buffer: LintBuffer, - next_node_id: NodeId, + next_node_id: NodeId = CRATE_NODE_ID, node_id_to_def_id: NodeMap<Feed<'tcx, LocalDefId>>, @@ -1210,17 +1238,17 @@ pub struct Resolver<'ra, 'tcx> { item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>, delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>, - main_def: Option<MainDefinition>, + main_def: Option<MainDefinition> = None, trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>, /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. - proc_macros: Vec<LocalDefId>, + proc_macros: Vec<LocalDefId> = Vec::new(), confused_type_with_std_module: FxIndexMap<Span, Span>, /// Whether lifetime elision was successful. lifetime_elision_allowed: FxHashSet<NodeId>, /// Names of items that were stripped out via cfg with their corresponding cfg meta item. - stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>, + stripped_cfg_items: Vec<StrippedCfgItem<NodeId>> = Vec::new(), effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>, @@ -1242,6 +1270,10 @@ pub struct Resolver<'ra, 'tcx> { mods_with_parse_errors: FxHashSet<DefId>, + /// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we + /// don't need to run it more than once. + all_crate_macros_already_registered: bool = false, + // Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types // that were encountered during resolution. These names are used to generate item names // for APITs, so we don't want to leak details of resolution into these names. @@ -1487,19 +1519,31 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'_>> = tcx + let mut extern_prelude: FxIndexMap<_, _> = tcx .sess .opts .externs .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| (Ident::from_str(name), Default::default())) + .filter_map(|(name, entry)| { + // Make sure `self`, `super`, `_` etc do not get into extern prelude. + // FIXME: reject `--extern self` and similar in option parsing instead. + if entry.add_prelude + && let name = Symbol::intern(name) + && name.can_be_raw() + { + Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default())) + } else { + None + } + }) .collect(); if !attr::contains_name(attrs, sym::no_core) { - extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default()); if !attr::contains_name(attrs, sym::no_std) { - extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); + extern_prelude + .insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default()); } } @@ -1514,15 +1558,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The outermost module has def ID 0; this is not reflected in the // AST. graph_root, + assert_speculative: false, // Only set/cleared in Resolver::resolve_imports for now prelude: None, extern_prelude, field_names: Default::default(), + field_defaults: Default::default(), field_visibility_spans: FxHashMap::default(), - determined_imports: Vec::new(), - indeterminate_imports: Vec::new(), - pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), @@ -1541,16 +1584,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), - glob_error: None, - visibilities_for_hashing: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), - privacy_errors: Vec::new(), - ambiguity_errors: Vec::new(), - use_injections: Vec::new(), - macro_expanded_macro_export_errors: BTreeSet::new(), - arenas, dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL @@ -1594,8 +1630,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { derive_data: Default::default(), local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), - potentially_unused_imports: Vec::new(), - potentially_unnecessary_qualifications: Default::default(), struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), @@ -1605,16 +1639,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { builtin_attrs: Default::default(), containers_deriving_copy: Default::default(), lint_buffer: LintBuffer::default(), - next_node_id: CRATE_NODE_ID, node_id_to_def_id, disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), invocation_parents, legacy_const_generic_args: Default::default(), item_generics_num_lifetimes: Default::default(), - main_def: Default::default(), trait_impls: Default::default(), - proc_macros: Default::default(), confused_type_with_std_module: Default::default(), lifetime_elision_allowed: Default::default(), stripped_cfg_items: Default::default(), @@ -1629,9 +1660,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), impl_trait_names: Default::default(), + .. }; - let root_parent_scope = ParentScope::module(graph_root, &resolver); + let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver.feed_visibility(crate_feed, Visibility::Public); @@ -1779,6 +1811,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Returns a conditionally mutable resolver. + /// + /// Currently only dependent on `assert_speculative`, if `assert_speculative` is false, + /// the resolver will allow mutation; otherwise, it will be immutable. + fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> { + CmResolver::new(self, !self.assert_speculative) + } + /// Runs the function on each namespace. fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) { f(self, TypeNS); @@ -1786,6 +1826,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f(self, MacroNS); } + fn per_ns_cm<'r, F: FnMut(&mut CmResolver<'r, 'ra, 'tcx>, Namespace)>( + mut self: CmResolver<'r, 'ra, 'tcx>, + mut f: F, + ) { + f(&mut self, TypeNS); + f(&mut self, ValueNS); + f(&mut self, MacroNS); + } + fn is_builtin_macro(&self, res: Res) -> bool { self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some()) } @@ -1839,17 +1888,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { + self.cm().visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { match scope { Scope::Module(module, _) => { - this.traits_in_module(module, assoc_item, &mut found_traits); + this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { if let Some(module) = this.prelude { - this.traits_in_module(module, assoc_item, &mut found_traits); + this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } } - Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} + Scope::ExternPreludeItems + | Scope::ExternPreludeFlags + | Scope::ToolPrelude + | Scope::BuiltinTypes => {} _ => unreachable!(), } None::<()> @@ -1869,7 +1921,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name.0); found_traits.push(TraitCandidate { def_id, import_ids }); } } @@ -1989,14 +2041,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { - self.maybe_resolve_ident_in_module( - ModuleOrUniformRoot::Module(prelude), - ident, - MacroNS, - &ParentScope::module(self.empty_module, self), - None, - ) - .is_ok() + let empty_module = self.empty_module; + let arenas = self.arenas; + self.cm() + .maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(empty_module, arenas), + None, + ) + .is_ok() }); if !found_in_stdlib_prelude { self.lint_buffer().buffer_lint( @@ -2010,8 +2065,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope { - if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) { - if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) { + if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { + if !entry.introduced_by_item && entry.item_binding == Some(used_binding) { return; } } @@ -2167,44 +2222,48 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { - if ident.is_path_segment_keyword() { - // Make sure `self`, `super` etc produce an error when passed to here. - return None; - } + fn extern_prelude_get_item<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, + ident: Ident, + finalize: bool, + ) -> Option<NameBinding<'ra>> { + let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + entry.and_then(|entry| entry.item_binding).map(|binding| { + if finalize { + self.get_mut().record_use(ident, binding, Used::Scope); + } + binding + }) + } - let norm_ident = ident.normalize_to_macros_2_0(); - let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| { - Some(if let Some(binding) = entry.binding.get() { + fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { + let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + entry.and_then(|entry| match entry.flag_binding.get() { + Some(binding) => { if finalize { - if !entry.is_import() { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); - } else if entry.introduced_by_item { - self.record_use(ident, binding, Used::Other); - } + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - binding - } else { + Some(binding) + } + None if entry.only_item => None, + None => { let crate_id = if finalize { - let Some(crate_id) = - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - else { - return Some(self.dummy_binding); - }; - crate_id + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)? + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) }; - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) - }) - }); - - if let Some(entry) = self.extern_prelude.get(&norm_ident) { - entry.binding.set(binding); - } - - binding + match crate_id { + Some(crate_id) => { + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + let binding = + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); + entry.flag_binding.set(Some(binding)); + Some(binding) + } + None => finalize.then_some(self.dummy_binding), + } + } + }) } /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` @@ -2236,7 +2295,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); let Ok(segments) = segments else { return None }; - match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { + match self.cm().maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::NonModule(path_res) => { path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _))) @@ -2272,6 +2331,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn field_defaults(&self, def_id: DefId) -> Option<Vec<Symbol>> { + match def_id.as_local() { + Some(def_id) => self.field_defaults.get(&def_id).cloned(), + None => Some( + self.tcx + .associated_item_def_ids(def_id) + .iter() + .filter_map(|&def_id| { + self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id)) + }) + .collect(), + ), + } + } + /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. @@ -2315,9 +2389,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_main(&mut self) { let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); - let parent_scope = &ParentScope::module(module, self); + let parent_scope = &ParentScope::module(module, self.arenas); - let Ok(name_binding) = self.maybe_resolve_ident_in_module( + let Ok(name_binding) = self.cm().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ValueNS, @@ -2411,3 +2485,63 @@ impl Finalize { pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } + +mod ref_mut { + use std::ops::Deref; + + /// A wrapper around a mutable reference that conditionally allows mutable access. + pub(crate) struct RefOrMut<'a, T> { + p: &'a mut T, + mutable: bool, + } + + impl<'a, T> Deref for RefOrMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.p + } + } + + impl<'a, T> AsRef<T> for RefOrMut<'a, T> { + fn as_ref(&self) -> &T { + self.p + } + } + + impl<'a, T> RefOrMut<'a, T> { + pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self { + RefOrMut { p, mutable } + } + + /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. + pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> { + RefOrMut { p: self.p, mutable: self.mutable } + } + + /// Returns a mutable reference to the inner value if allowed. + /// + /// # Panics + /// Panics if the `mutable` flag is false. + #[track_caller] + pub(crate) fn get_mut(&mut self) -> &mut T { + match self.mutable { + false => panic!("Can't mutably borrow speculative resolver"), + true => self.p, + } + } + + /// Returns a mutable reference to the inner value without checking if + /// it's in a mutable state. + pub(crate) fn get_mut_unchecked(&mut self) -> &mut T { + self.p + } + } +} + +/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions. +/// +/// `Cm` stands for "conditionally mutable". +/// +/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4e3c0cd5bc0..72ed8990241 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,7 +1,6 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use std::any::Any; use std::cell::Cell; use std::mem; use std::sync::Arc; @@ -13,13 +12,13 @@ use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, }; +use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion, }; -use rustc_expand::{MacroRulesMacroExpander, compile_declarative_macro}; use rustc_hir::StabilityLevel; use rustc_hir::attrs::{CfgEntry, StrippedCfgItem}; -use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; +use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -41,9 +40,9 @@ use crate::errors::{ }; use crate::imports::Import; use crate::{ - BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, Used, + BindingKey, CmResolver, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, + ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, + ResolutionError, Resolver, ScopeSet, Segment, Used, }; type Res = def::Res<NodeId>; @@ -86,22 +85,19 @@ pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell<MacroRulesScope<'ra>>; /// one for attribute-like macros (attributes, derives). /// We ignore resolutions from one sub-namespace when searching names in scope for another. pub(crate) fn sub_namespace_match( - candidate: Option<MacroKind>, + candidate: Option<MacroKinds>, requirement: Option<MacroKind>, ) -> bool { - #[derive(PartialEq)] - enum SubNS { - Bang, - AttrLike, - } - let sub_ns = |kind| match kind { - MacroKind::Bang => SubNS::Bang, - MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, - }; - let candidate = candidate.map(sub_ns); - let requirement = requirement.map(sub_ns); // "No specific sub-namespace" means "matches anything" for both requirements and candidates. - candidate.is_none() || requirement.is_none() || candidate == requirement + let (Some(candidate), Some(requirement)) = (candidate, requirement) else { + return true; + }; + match requirement { + MacroKind::Bang => candidate.contains(MacroKinds::BANG), + MacroKind::Attr | MacroKind::Derive => { + candidate.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) + } + } } // We don't want to format a path using pretty-printing, @@ -323,6 +319,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { parent_scope.expansion, span, fast_print_path(path), + kind, def_id, def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()), ), @@ -356,11 +353,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } let def_id = self.local_def_id(node_id); let m = &self.local_macro_map[&def_id]; - let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else { - continue; - }; - let ext: &dyn Any = ext.as_ref(); - let Some(m) = ext.downcast_ref::<MacroRulesMacroExpander>() else { + let SyntaxExtensionKind::MacroRules(ref m) = m.ext.kind else { continue; }; for arm_i in unused_arms.iter() { @@ -403,9 +396,9 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { for (i, resolution) in entry.resolutions.iter_mut().enumerate() { if resolution.exts.is_none() { resolution.exts = Some( - match self.resolve_macro_path( + match self.cm().resolve_macro_path( &resolution.path, - Some(MacroKind::Derive), + MacroKind::Derive, &parent_scope, true, force, @@ -536,11 +529,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident, ns)) + && overriding_keys.contains(&BindingKey::new(ident.0, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { - idents.push((ident, None)); + idents.push((ident.0, None)); } }); Ok(idents) @@ -568,9 +561,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option<LocalDefId>, suggestion_span: Option<Span>, ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { - let (ext, res) = match self.resolve_macro_or_delegation_path( + let (ext, res) = match self.cm().resolve_macro_or_delegation_path( path, - Some(kind), + kind, parent_scope, true, force, @@ -633,7 +626,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.check_stability_and_deprecation(&ext, path, node_id); - let unexpected_res = if ext.macro_kind() != kind { + let unexpected_res = if !ext.macro_kinds().contains(kind.into()) { Some((kind.article(), kind.descr_expected())) } else if matches!(res, Res::Def(..)) { match supports_macro_expansion { @@ -665,7 +658,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Suggest moving the macro out of the derive() if the macro isn't Derive if !path.span.from_expansion() && kind == MacroKind::Derive - && ext.macro_kind() != MacroKind::Derive + && !ext.macro_kinds().contains(MacroKinds::DERIVE) + && ext.macro_kinds().contains(MacroKinds::ATTR) { err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); @@ -713,10 +707,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } - pub(crate) fn resolve_macro_path( - &mut self, + pub(crate) fn resolve_macro_path<'r>( + self: CmResolver<'r, 'ra, 'tcx>, path: &ast::Path, - kind: Option<MacroKind>, + kind: MacroKind, parent_scope: &ParentScope<'ra>, trace: bool, force: bool, @@ -736,10 +730,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - fn resolve_macro_or_delegation_path( - &mut self, + fn resolve_macro_or_delegation_path<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, ast_path: &ast::Path, - kind: Option<MacroKind>, + kind: MacroKind, parent_scope: &ParentScope<'ra>, trace: bool, force: bool, @@ -753,7 +747,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Possibly apply the macro helper hack if deleg_impl.is_none() - && kind == Some(MacroKind::Bang) + && kind == MacroKind::Bang && let [segment] = path.as_slice() && segment.ident.span.ctxt().outer_expn_data().local_inner_macros { @@ -763,7 +757,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = if deleg_impl.is_some() || path.len() > 1 { let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; - let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { + let res = match self.reborrow().maybe_resolve_path( + &path, + Some(ns), + parent_scope, + ignore_import, + ) { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) @@ -776,8 +775,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.multi_segment_macro_resolutions.push(( + // FIXME: Should be an output of Speculative Resolution. + self.multi_segment_macro_resolutions.borrow_mut().push(( path, path_span, kind, @@ -790,10 +789,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); res } else { - let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.reborrow().early_resolve_ident_in_lexical_scope( path[0].ident, - scope_set, + ScopeSet::Macro(kind), parent_scope, None, force, @@ -805,8 +803,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.single_segment_macro_resolutions.push(( + // FIXME: Should be an output of Speculative Resolution. + self.single_segment_macro_resolutions.borrow_mut().push(( path[0].ident, kind, *parent_scope, @@ -817,7 +815,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = binding.map(|binding| binding.res()); self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); - self.report_out_of_scope_macro_calls( + self.reborrow().report_out_of_scope_macro_calls( ast_path, parent_scope, invoc_in_mod_inert_attr, @@ -872,13 +870,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); + // FIXME: Should be an output of Speculative Resolution. + let macro_resolutions = self.multi_segment_macro_resolutions.take(); for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } - match self.resolve_path( + match self.cm().resolve_path( &path, Some(ns), &parent_scope, @@ -905,8 +904,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path_res { // try to suggest if it's not a macro, maybe a function - if let PathResult::NonModule(partial_res) = - self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) + if let PathResult::NonModule(partial_res) = self + .cm() + .maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) && partial_res.unresolved_segments() == 0 { let sm = self.tcx.sess.source_map(); @@ -948,9 +948,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); + // FIXME: Should be an output of Speculative Resolution. + let macro_resolutions = self.single_segment_macro_resolutions.take(); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.early_resolve_ident_in_lexical_scope( + match self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1005,7 +1006,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.early_resolve_ident_in_lexical_scope( + let _ = self.cm().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1090,8 +1091,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn report_out_of_scope_macro_calls( - &mut self, + fn report_out_of_scope_macro_calls<'r>( + mut self: CmResolver<'r, 'ra, 'tcx>, path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, @@ -1101,7 +1102,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let Some(binding) = binding // This is a `macro_rules` itself, not some import. && let NameBindingKind::Res(res) = binding.kind - && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res + && let Res::Def(DefKind::Macro(kinds), def_id) = res + && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, // so it cannot be in scope unless imported. && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) @@ -1110,7 +1112,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If such resolution is successful and gives the same result // (e.g. if the macro is re-imported), then silence the lint. let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); - let fallback_binding = self.early_resolve_ident_in_lexical_scope( + let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( path.segments[0].ident, ScopeSet::Macro(MacroKind::Bang), &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, @@ -1148,8 +1150,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr { - let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind()); - if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { + let macro_kinds = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kinds()); + if macro_kinds.is_some() && sub_namespace_match(macro_kinds, Some(MacroKind::Attr)) { self.dcx() .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident }); } @@ -1206,7 +1208,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate = false; for ns in namespaces { - match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) { + match self.cm().maybe_resolve_path(path, Some(*ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { return Ok(true); |
