resolve: Eliminate InvocationData

It was very similar to `ParentScope` and mostly could be replaced by it.
This commit is contained in:
Vadim Petrochenkov 2019-08-12 23:39:49 +03:00
parent 1a1557c285
commit 59dd07ae2b
3 changed files with 53 additions and 91 deletions

View file

@ -3,7 +3,7 @@
//! Here we build the "reduced graph": the graph of the module tree without
//! any imports resolved.
use crate::macros::{InvocationData, LegacyBinding, LegacyScope};
use crate::macros::{LegacyBinding, LegacyScope};
use crate::resolve_imports::ImportDirective;
use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
@ -1063,20 +1063,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
false
}
fn visit_invoc(&mut self, id: ast::NodeId) -> &'a InvocationData<'a> {
fn visit_invoc(&mut self, id: ast::NodeId) -> LegacyScope<'a> {
let invoc_id = id.placeholder_to_expn_id();
self.parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
let parent_scope = self.parent_scope.clone();
parent_scope.module.unresolved_invocations.borrow_mut().insert(invoc_id);
let invocation_data = self.r.arenas.alloc_invocation_data(InvocationData {
module: self.parent_scope.module,
parent_legacy_scope: self.parent_scope.legacy,
output_legacy_scope: Cell::new(None),
});
let old_invocation_data = self.r.invocations.insert(invoc_id, invocation_data);
assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation");
let old_parent_scope =
self.r.invocation_parent_scopes.insert(invoc_id, parent_scope.clone());
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
invocation_data
LegacyScope::Invocation(invoc_id)
}
fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
@ -1177,7 +1174,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
return
}
ItemKind::Mac(..) => {
self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(item.id));
self.parent_scope.legacy = self.visit_invoc(item.id);
return
}
ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
@ -1196,7 +1193,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
if let ast::StmtKind::Mac(..) = stmt.node {
self.parent_scope.legacy = LegacyScope::Invocation(self.visit_invoc(stmt.id));
self.parent_scope.legacy = self.visit_invoc(stmt.id);
} else {
visit::walk_stmt(self, stmt);
}

View file

@ -54,7 +54,7 @@ use diagnostics::{Suggestion, ImportSuggestion};
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
use late::{PathSource, Rib, RibKind::*};
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
use macros::{InvocationData, LegacyBinding, LegacyScope};
use macros::{LegacyBinding, LegacyScope};
type Res = def::Res<NodeId>;
@ -911,9 +911,12 @@ pub struct Resolver<'a> {
/// FIXME: Find a way for `PartialEq` and `Eq` to emulate `#[structural_match]`
/// by marking the produced impls rather than the original items.
special_derives: FxHashMap<ExpnId, SpecialDerives>,
/// Maps the `ExpnId` of an expansion to its containing module or block.
invocations: FxHashMap<ExpnId, &'a InvocationData<'a>>,
/// Parent scopes in which the macros were invoked.
/// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere.
invocation_parent_scopes: FxHashMap<ExpnId, ParentScope<'a>>,
/// Legacy scopes *produced* by expanding the macro invocations,
/// include all the `macro_rules` items and other invocations generated by them.
output_legacy_scopes: FxHashMap<ExpnId, LegacyScope<'a>>,
/// Avoid duplicated errors for "name already defined".
name_already_seen: FxHashMap<Name, Span>,
@ -936,7 +939,6 @@ pub struct ResolverArenas<'a> {
name_bindings: arena::TypedArena<NameBinding<'a>>,
import_directives: arena::TypedArena<ImportDirective<'a>>,
name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
invocation_data: arena::TypedArena<InvocationData<'a>>,
legacy_bindings: arena::TypedArena<LegacyBinding<'a>>,
}
@ -961,10 +963,6 @@ impl<'a> ResolverArenas<'a> {
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
self.name_resolutions.alloc(Default::default())
}
fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>)
-> &'a InvocationData<'a> {
self.invocation_data.alloc(expansion_data)
}
fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> {
self.legacy_bindings.alloc(binding)
}
@ -1078,9 +1076,8 @@ impl<'a> Resolver<'a> {
}
}
let mut invocations = FxHashMap::default();
invocations.insert(ExpnId::root(),
arenas.alloc_invocation_data(InvocationData::default(graph_root)));
let mut invocation_parent_scopes = FxHashMap::default();
invocation_parent_scopes.insert(ExpnId::root(), ParentScope::default(graph_root));
let mut macro_defs = FxHashMap::default();
macro_defs.insert(ExpnId::root(), root_def_id);
@ -1152,7 +1149,8 @@ impl<'a> Resolver<'a> {
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
invocations,
invocation_parent_scopes,
output_legacy_scopes: Default::default(),
macro_defs,
local_macro_def_scopes: FxHashMap::default(),
name_already_seen: FxHashMap::default(),
@ -1370,8 +1368,9 @@ impl<'a> Resolver<'a> {
LegacyScope::Binding(binding) => Scope::MacroRules(
binding.parent_legacy_scope
),
LegacyScope::Invocation(invoc) => Scope::MacroRules(
invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
LegacyScope::Invocation(invoc_id) => Scope::MacroRules(
self.output_legacy_scopes.get(&invoc_id).cloned()
.unwrap_or(self.invocation_parent_scopes[&invoc_id].legacy)
),
LegacyScope::Empty => Scope::Module(module),
}

View file

@ -1,6 +1,6 @@
use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
use crate::{ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
use crate::Namespace::*;
use crate::build_reduced_graph::BuildReducedGraphVisitor;
@ -22,36 +22,11 @@ use syntax::feature_gate::GateIssue;
use syntax::symbol::{Symbol, kw, sym};
use syntax_pos::{Span, DUMMY_SP};
use std::cell::Cell;
use std::{mem, ptr};
use rustc_data_structures::sync::Lrc;
type Res = def::Res<ast::NodeId>;
// FIXME: Merge this with `ParentScope`.
#[derive(Clone, Debug)]
pub struct InvocationData<'a> {
/// The module in which the macro was invoked.
crate module: Module<'a>,
/// The legacy scope in which the macro was invoked.
/// The invocation path is resolved in this scope.
crate parent_legacy_scope: LegacyScope<'a>,
/// The legacy scope *produced* by expanding this macro invocation,
/// includes all the macro_rules items, other invocations, etc generated by it.
/// `None` if the macro is not expanded yet.
crate output_legacy_scope: Cell<Option<LegacyScope<'a>>>,
}
impl<'a> InvocationData<'a> {
pub fn default(module: Module<'a>) -> Self {
InvocationData {
module,
parent_legacy_scope: LegacyScope::Empty,
output_legacy_scope: Cell::new(None),
}
}
}
/// Binding produced by a `macro_rules` item.
/// Not modularized, can shadow previous legacy bindings, etc.
#[derive(Debug)]
@ -75,7 +50,7 @@ pub enum LegacyScope<'a> {
Binding(&'a LegacyBinding<'a>),
/// The scope introduced by a macro invocation that can potentially
/// create a `macro_rules!` macro definition.
Invocation(&'a InvocationData<'a>),
Invocation(ExpnId),
}
// Macro namespace is separated into two sub-namespaces, one for bang macros and
@ -124,9 +99,8 @@ impl<'a> base::Resolver for Resolver<'a> {
ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
)));
let module = self.module_map[&self.definitions.local_def_id(id)];
let invocation_data = self.arenas.alloc_invocation_data(InvocationData::default(module));
self.invocation_parent_scopes.insert(expn_id, ParentScope::default(module));
self.definitions.set_invocation_parent(expn_id, module.def_id().unwrap().index);
self.invocations.insert(expn_id, invocation_data);
expn_id
}
@ -140,29 +114,29 @@ impl<'a> base::Resolver for Resolver<'a> {
});
}
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
derives: &[ExpnId]) {
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expn_id));
let invocation = self.invocations[&expn_id];
invocation.module.unresolved_invocations.borrow_mut().remove(&expn_id);
invocation.module.unresolved_invocations.borrow_mut().extend(derives);
let parent_def = self.definitions.invocation_parent(expn_id);
fn visit_ast_fragment_with_placeholders(
&mut self, expansion: ExpnId, fragment: &AstFragment, derives: &[ExpnId]
) {
// Fill in some data for derives if the fragment is from a derive container.
let parent_scope = self.invocation_parent_scopes[&expansion].clone();
let parent_def = self.definitions.invocation_parent(expansion);
self.invocation_parent_scopes.extend(
derives.iter().map(|&derive| (derive, parent_scope.clone()))
);
for &derive_invoc_id in derives {
self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
}
self.invocations.extend(derives.iter().map(|&derive| (derive, invocation)));
let mut visitor = BuildReducedGraphVisitor {
r: self,
parent_scope: ParentScope {
module: invocation.module,
expansion: expn_id,
legacy: invocation.parent_legacy_scope,
derives: Vec::new(),
},
};
parent_scope.module.unresolved_invocations.borrow_mut().remove(&expansion);
parent_scope.module.unresolved_invocations.borrow_mut().extend(derives);
// Integrate the new AST fragment into all the definition and module structures.
// We are inside the `expansion` new, but other parent scope components are still the same.
fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expansion));
let parent_scope = ParentScope { expansion, ..parent_scope };
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
fragment.visit_with(&mut visitor);
invocation.output_legacy_scope.set(Some(visitor.parent_scope.legacy));
let output_legacy_scope = visitor.parent_scope.legacy;
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
}
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
@ -178,7 +152,8 @@ impl<'a> base::Resolver for Resolver<'a> {
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Indeterminate> {
let (path, kind, derives_in_scope, after_derive) = match invoc.kind {
let parent_scope = &self.invocation_parent_scopes[&invoc_id].clone();
let (path, kind, derives, after_derive) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } =>
(&attr.path, MacroKind::Attr, derives.clone(), after_derive),
InvocationKind::Bang { ref mac, .. } =>
@ -192,7 +167,6 @@ impl<'a> base::Resolver for Resolver<'a> {
// will automatically knows about itself.
let mut result = Ok(None);
if derives.len() > 1 {
let parent_scope = &self.invoc_parent_scope(invoc_id, Vec::new());
for path in derives {
match self.resolve_macro_path(path, Some(MacroKind::Derive),
parent_scope, true, force) {
@ -209,7 +183,8 @@ impl<'a> base::Resolver for Resolver<'a> {
}
};
let parent_scope = &self.invoc_parent_scope(invoc_id, derives_in_scope);
// Derives are not included when `invocations` are collected, so we have to add them here.
let parent_scope = &ParentScope { derives, ..parent_scope.clone() };
let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;
let span = invoc.span();
@ -247,16 +222,6 @@ impl<'a> base::Resolver for Resolver<'a> {
}
impl<'a> Resolver<'a> {
fn invoc_parent_scope(&self, invoc_id: ExpnId, derives: Vec<ast::Path>) -> ParentScope<'a> {
let invoc = self.invocations[&invoc_id];
ParentScope {
module: invoc.module,
expansion: invoc_id.parent(),
legacy: invoc.parent_legacy_scope,
derives,
}
}
/// Resolve macro path with error reporting and recovery.
fn smart_resolve_macro_path(
&mut self,
@ -466,8 +431,9 @@ impl<'a> Resolver<'a> {
Scope::MacroRules(legacy_scope) => match legacy_scope {
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
Ok((legacy_binding.binding, Flags::MACRO_RULES)),
LegacyScope::Invocation(invoc) if invoc.output_legacy_scope.get().is_none() =>
Err(Determinacy::Undetermined),
LegacyScope::Invocation(invoc_id)
if !this.output_legacy_scopes.contains_key(&invoc_id) =>
Err(Determinacy::Undetermined),
_ => Err(Determinacy::Determined),
}
Scope::CrateRoot => {