diff options
Diffstat (limited to 'compiler/rustc_resolve/src/macros.rs')
| -rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 159 |
1 files changed, 137 insertions, 22 deletions
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 268e7f06d04..8763e7aec43 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution; use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope}; use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; -use crate::{BuiltinMacroState, Determinacy, MacroData, Used}; +use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, Used}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::expand::StrippedCfgItem; @@ -140,9 +140,10 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { } } } - // We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools, - // but it's not an error to register them explicitly. - let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic, sym::miri]; + // We implicitly add `rustfmt`, `clippy`, `diagnostic`, `miri` and `rust_analyzer` to known + // tools, but it's not an error to register them explicitly. + let predefined_tools = + [sym::clippy, sym::rustfmt, sym::diagnostic, sym::miri, sym::rust_analyzer]; registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span)); registered_tools } @@ -198,6 +199,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); + if let Some(unexpanded_invocations) = + self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) + { + unexpanded_invocations.remove(&expansion); + } } fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) { @@ -262,15 +268,21 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { } }; - let (path, kind, inner_attr, derives) = match invoc.kind { - InvocationKind::Attr { ref attr, ref derives, .. } => ( - &attr.get_normal_item().path, - MacroKind::Attr, - attr.style == ast::AttrStyle::Inner, - self.arenas.alloc_ast_paths(derives), - ), - InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]), - InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]), + let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None); + let (path, kind) = match invoc.kind { + InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => { + derives = self.arenas.alloc_ast_paths(attr_derives); + inner_attr = attr.style == ast::AttrStyle::Inner; + (&attr.get_normal_item().path, MacroKind::Attr) + } + InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang), + InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive), + InvocationKind::GlobDelegation { ref item } => { + let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; + deleg_impl = Some(self.invocation_parent(invoc_id)); + // It is sufficient to consider glob delegation a bang macro for now. + (&deleg.prefix, MacroKind::Bang) + } }; // Derives are not included when `invocations` are collected, so we have to add them here. @@ -286,10 +298,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { node_id, force, soft_custom_inner_attributes_gate(path, invoc), + deleg_impl, )?; let span = invoc.span(); - let def_id = res.opt_def_id(); + let def_id = if deleg_impl.is_some() { None } else { res.opt_def_id() }; invoc_id.set_expn_data( ext.expn_data( parent_scope.expansion, @@ -452,6 +465,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { fn registered_tools(&self) -> &RegisteredTools { self.registered_tools } + + fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) { + self.glob_delegation_invoc_ids.insert(invoc_id); + } + + fn glob_delegation_suffixes( + &mut self, + trait_def_id: DefId, + impl_def_id: LocalDefId, + ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> { + let target_trait = self.expect_module(trait_def_id); + if !target_trait.unexpanded_invocations.borrow().is_empty() { + return Err(Indeterminate); + } + // FIXME: Instead of waiting try generating all trait methods, and pruning + // the shadowed ones a bit later, e.g. when all macro expansion completes. + // Pros: expansion will be stuck less (but only in exotic cases), the implementation may be + // less hacky. + // Cons: More code is generated just to be deleted later, deleting already created `DefId`s + // may be nontrivial. + if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get(&impl_def_id) + && !unexpanded_invocations.is_empty() + { + return Err(Indeterminate); + } + + let mut idents = Vec::new(); + 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.normalize_to_macros_2_0(), ns)) + { + // The name is overridden, do not produce it from the glob delegation. + } else { + idents.push((ident, None)); + } + }); + Ok(idents) + } } impl<'a, 'tcx> Resolver<'a, 'tcx> { @@ -468,15 +520,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id: NodeId, force: bool, soft_custom_inner_attributes_gate: bool, + deleg_impl: Option<LocalDefId>, ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> { - let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) - { + let (ext, res) = match self.resolve_macro_or_delegation_path( + path, + Some(kind), + parent_scope, + true, + force, + deleg_impl, + ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), Err(Determinacy::Undetermined) => return Err(Indeterminate), }; + // Everything below is irrelevant to glob delegation, take a shortcut. + if deleg_impl.is_some() { + if !matches!(res, Res::Err | Res::Def(DefKind::Trait, _)) { + self.dcx().emit_err(MacroExpectedFound { + span: path.span, + expected: "trait", + article: "a", + found: res.descr(), + macro_path: &pprust::path_to_string(path), + remove_surrounding_derive: None, + add_as_non_derive: None, + }); + return Ok((self.dummy_ext(kind), Res::Err)); + } + + return Ok((ext, res)); + } + // Report errors for the resolved macro. for segment in &path.segments { if let Some(args) = &segment.args { @@ -606,11 +683,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trace: bool, force: bool, ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { + self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None) + } + + fn resolve_macro_or_delegation_path( + &mut self, + path: &ast::Path, + kind: Option<MacroKind>, + parent_scope: &ParentScope<'a>, + trace: bool, + force: bool, + deleg_impl: Option<LocalDefId>, + ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { let path_span = path.span; let mut path = Segment::from_path(path); // Possibly apply the macro helper hack - if kind == Some(MacroKind::Bang) + if deleg_impl.is_none() + && kind == Some(MacroKind::Bang) && path.len() == 1 && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros { @@ -618,13 +708,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path.insert(0, Segment::from_ident(root)); } - let res = if path.len() > 1 { - let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) { + 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) { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed { .. } => Err(Determinacy::Determined), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + Ok(module.res().unwrap()) + } PathResult::Module(..) => unreachable!(), }; @@ -636,6 +730,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { kind, *parent_scope, res.ok(), + ns, )); } @@ -670,7 +765,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { res }; - res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res)) + let res = res?; + let ext = match deleg_impl { + Some(impl_def_id) => match res { + def::Res::Def(DefKind::Trait, def_id) => { + let edition = self.tcx.sess.edition(); + Some(Lrc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) + } + _ => None, + }, + None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()), + }; + Ok((ext, res)) } pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { @@ -706,14 +812,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); - for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { + 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( &path, - Some(MacroNS), + Some(ns), &parent_scope, Some(Finalize::new(ast::CRATE_NODE_ID, path_span)), None, @@ -721,6 +827,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { check_consistency(self, &path, path_span, kind, initial_res, res) } + // This may be a trait for glob delegation expansions. + PathResult::Module(ModuleOrUniformRoot::Module(module)) => check_consistency( + self, + &path, + path_span, + kind, + initial_res, + module.res().unwrap(), + ), path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; let (span, label, module) = |
