Move macro resolution into librustc_resolve.

This commit is contained in:
Jeffrey Seyfried
2016-09-07 23:21:59 +00:00
parent 20b43b2323
commit 72a636975f
11 changed files with 438 additions and 405 deletions

View File

@@ -10,27 +10,25 @@
pub use self::SyntaxExtension::*;
use ast;
use ast::{Name, PatKind};
use ast::{self, Attribute, Name, PatKind};
use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::DiagnosticBuilder;
use ext;
use ext::expand;
use ext::expand::{self, Invocation, Expansion};
use ext::hygiene::Mark;
use ext::tt::macro_rules;
use parse;
use parse::parser;
use parse::token;
use parse::token::{InternedString, intern, str_to_ident};
use parse::token::{InternedString, str_to_ident};
use ptr::P;
use std_inject;
use util::small_vector::SmallVector;
use util::lev_distance::find_best_match_for_name;
use fold::Folder;
use feature_gate;
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;
use tokenstream;
@@ -44,7 +42,7 @@ pub enum Annotatable {
}
impl HasAttrs for Annotatable {
fn attrs(&self) -> &[ast::Attribute] {
fn attrs(&self) -> &[Attribute] {
match *self {
Annotatable::Item(ref item) => &item.attrs,
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
@@ -52,7 +50,7 @@ impl HasAttrs for Annotatable {
}
}
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
match self {
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
@@ -464,91 +462,15 @@ pub enum SyntaxExtension {
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
/// The base map of methods for expanding syntax extension
/// AST nodes into full ASTs
fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
-> SyntaxEnv {
// utility function to simplify creating NormalTT syntax extensions
fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
NormalTT(Box::new(f), None, false)
}
let mut syntax_expanders = SyntaxEnv::new();
syntax_expanders.insert(intern("macro_rules"), MacroRulesTT);
if ecfg.enable_quotes() {
// Quasi-quoting expanders
syntax_expanders.insert(intern("quote_tokens"),
builtin_normal_expander(
ext::quote::expand_quote_tokens));
syntax_expanders.insert(intern("quote_expr"),
builtin_normal_expander(
ext::quote::expand_quote_expr));
syntax_expanders.insert(intern("quote_ty"),
builtin_normal_expander(
ext::quote::expand_quote_ty));
syntax_expanders.insert(intern("quote_item"),
builtin_normal_expander(
ext::quote::expand_quote_item));
syntax_expanders.insert(intern("quote_pat"),
builtin_normal_expander(
ext::quote::expand_quote_pat));
syntax_expanders.insert(intern("quote_arm"),
builtin_normal_expander(
ext::quote::expand_quote_arm));
syntax_expanders.insert(intern("quote_stmt"),
builtin_normal_expander(
ext::quote::expand_quote_stmt));
syntax_expanders.insert(intern("quote_matcher"),
builtin_normal_expander(
ext::quote::expand_quote_matcher));
syntax_expanders.insert(intern("quote_attr"),
builtin_normal_expander(
ext::quote::expand_quote_attr));
syntax_expanders.insert(intern("quote_arg"),
builtin_normal_expander(
ext::quote::expand_quote_arg));
syntax_expanders.insert(intern("quote_block"),
builtin_normal_expander(
ext::quote::expand_quote_block));
syntax_expanders.insert(intern("quote_meta_item"),
builtin_normal_expander(
ext::quote::expand_quote_meta_item));
syntax_expanders.insert(intern("quote_path"),
builtin_normal_expander(
ext::quote::expand_quote_path));
}
syntax_expanders.insert(intern("line"),
builtin_normal_expander(
ext::source_util::expand_line));
syntax_expanders.insert(intern("column"),
builtin_normal_expander(
ext::source_util::expand_column));
syntax_expanders.insert(intern("file"),
builtin_normal_expander(
ext::source_util::expand_file));
syntax_expanders.insert(intern("stringify"),
builtin_normal_expander(
ext::source_util::expand_stringify));
syntax_expanders.insert(intern("include"),
builtin_normal_expander(
ext::source_util::expand_include));
syntax_expanders.insert(intern("include_str"),
builtin_normal_expander(
ext::source_util::expand_include_str));
syntax_expanders.insert(intern("include_bytes"),
builtin_normal_expander(
ext::source_util::expand_include_bytes));
syntax_expanders.insert(intern("module_path"),
builtin_normal_expander(
ext::source_util::expand_mod));
syntax_expanders
}
pub trait Resolver {
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool)
-> Vec<LoadedMacro>;
fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_invoc(&mut self, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
}
pub enum LoadedMacro {
@@ -558,9 +480,31 @@ pub enum LoadedMacro {
pub struct DummyResolver;
impl Resolver for DummyResolver {
fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec<LoadedMacro> {
fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<LoadedMacro> {
Vec::new()
}
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
fn resolve_invoc(&mut self, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> { None }
}
#[derive(Clone)]
pub struct ModuleData {
pub mod_path: Vec<ast::Ident>,
pub directory: PathBuf,
}
#[derive(Clone)]
pub struct ExpansionData {
pub mark: Mark,
pub depth: usize,
pub backtrace: ExpnId,
pub module: Rc<ModuleData>,
pub in_block: bool,
}
/// One of these is made during expansion and incrementally updated as we go;
@@ -569,16 +513,12 @@ impl Resolver for DummyResolver {
pub struct ExtCtxt<'a> {
pub parse_sess: &'a parse::ParseSess,
pub cfg: ast::CrateConfig,
pub backtrace: ExpnId,
pub ecfg: expand::ExpansionConfig<'a>,
pub crate_root: Option<&'static str>,
pub resolver: &'a mut Resolver,
pub exported_macros: Vec<ast::MacroDef>,
pub syntax_env: SyntaxEnv,
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
pub recursion_count: usize,
pub current_expansion: ExpansionData,
}
impl<'a> ExtCtxt<'a> {
@@ -587,16 +527,20 @@ impl<'a> ExtCtxt<'a> {
resolver: &'a mut Resolver)
-> ExtCtxt<'a> {
ExtCtxt {
syntax_env: initial_syntax_expander_table(&ecfg),
parse_sess: parse_sess,
cfg: cfg,
backtrace: NO_EXPANSION,
ecfg: ecfg,
crate_root: None,
exported_macros: Vec::new(),
resolver: resolver,
derive_modes: HashMap::new(),
recursion_count: 0,
current_expansion: ExpansionData {
mark: Mark::root(),
depth: 0,
backtrace: NO_EXPANSION,
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
in_block: false,
},
}
}
@@ -609,23 +553,22 @@ impl<'a> ExtCtxt<'a> {
-> parser::Parser<'a> {
parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
}
pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
pub fn call_site(&self) -> Span {
self.codemap().with_expn_info(self.backtrace, |ei| match ei {
self.codemap().with_expn_info(self.backtrace(), |ei| match ei {
Some(expn_info) => expn_info.call_site,
None => self.bug("missing top span")
})
}
pub fn backtrace(&self) -> ExpnId { self.backtrace }
pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace }
/// Returns span for the macro which originally caused the current expansion to happen.
///
/// Stops backtracing at include! boundary.
pub fn expansion_cause(&self) -> Span {
let mut expn_id = self.backtrace;
let mut expn_id = self.backtrace();
let mut last_macro = None;
loop {
if self.codemap().with_expn_info(expn_id, |info| {
@@ -646,15 +589,15 @@ impl<'a> ExtCtxt<'a> {
}
pub fn bt_push(&mut self, ei: ExpnInfo) {
if self.recursion_count > self.ecfg.recursion_limit {
if self.current_expansion.depth > self.ecfg.recursion_limit {
self.span_fatal(ei.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
ei.callee.name()));
}
let mut call_site = ei.call_site;
call_site.expn_id = self.backtrace;
self.backtrace = self.codemap().record_expansion(ExpnInfo {
call_site.expn_id = self.backtrace();
self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
call_site: call_site,
callee: ei.callee
});
@@ -667,14 +610,11 @@ impl<'a> ExtCtxt<'a> {
}
if def.use_locally {
let ext = macro_rules::compile(self, &def);
self.syntax_env.insert(def.ident.name, ext);
self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext));
}
}
pub fn insert_custom_derive(&mut self,
name: &str,
ext: Box<MultiItemModifier>,
sp: Span) {
pub fn insert_custom_derive(&mut self, name: &str, ext: Box<MultiItemModifier>, sp: Span) {
if !self.ecfg.enable_rustc_macro() {
feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
"rustc_macro",
@@ -685,8 +625,7 @@ impl<'a> ExtCtxt<'a> {
}
let name = token::intern_and_get_ident(name);
if self.derive_modes.insert(name.clone(), ext).is_some() {
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`",
name));
self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
}
}
@@ -765,20 +704,6 @@ impl<'a> ExtCtxt<'a> {
token::intern(st)
}
pub fn suggest_macro_name(&mut self,
name: &str,
err: &mut DiagnosticBuilder<'a>) {
let names = &self.syntax_env.names;
if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) {
if suggestion != name {
err.help(&format!("did you mean `{}!`?", suggestion));
} else {
err.help(&format!("have you added the `#[macro_use]` on the \
module/import?"));
}
}
}
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
if std_inject::no_core(&krate) {
self.crate_root = None;
@@ -789,16 +714,16 @@ impl<'a> ExtCtxt<'a> {
}
for (name, extension) in user_exts {
self.syntax_env.insert(name, extension);
let ident = ast::Ident::with_empty_ctxt(name);
self.resolver.add_macro(Mark::root(), ident, Rc::new(extension));
}
self.syntax_env.current_module = Module(0);
let mut paths = ModulePaths {
let mut module = ModuleData {
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
};
paths.directory.pop();
self.syntax_env.module_data[0].paths = Rc::new(paths);
module.directory.pop();
self.current_expansion.module = Rc::new(module);
}
}
@@ -809,7 +734,7 @@ pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &st
-> Option<Spanned<(InternedString, ast::StrStyle)>> {
// Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
let expr = expr.map(|mut expr| {
expr.span.expn_id = cx.backtrace;
expr.span.expn_id = cx.backtrace();
expr
});
@@ -884,104 +809,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
}
Some(es)
}
/// In order to have some notion of scoping for macros,
/// we want to implement the notion of a transformation
/// environment.
///
/// This environment maps Names to SyntaxExtensions.
pub struct SyntaxEnv {
module_data: Vec<ModuleData>,
pub current_module: Module,
/// All bang-style macro/extension names
/// encountered so far; to be used for diagnostics in resolve
pub names: HashSet<Name>,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Module(u32);
struct ModuleData {
parent: Module,
paths: Rc<ModulePaths>,
macros: HashMap<Name, Rc<SyntaxExtension>>,
macros_escape: bool,
in_block: bool,
}
#[derive(Clone)]
pub struct ModulePaths {
pub mod_path: Vec<ast::Ident>,
pub directory: PathBuf,
}
impl SyntaxEnv {
fn new() -> SyntaxEnv {
let mut env = SyntaxEnv {
current_module: Module(0),
module_data: Vec::new(),
names: HashSet::new(),
};
let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
env.add_module(false, false, paths);
env
}
fn data(&self, module: Module) -> &ModuleData {
&self.module_data[module.0 as usize]
}
pub fn paths(&self) -> Rc<ModulePaths> {
self.data(self.current_module).paths.clone()
}
pub fn in_block(&self) -> bool {
self.data(self.current_module).in_block
}
pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc<ModulePaths>)
-> Module {
let data = ModuleData {
parent: self.current_module,
paths: paths,
macros: HashMap::new(),
macros_escape: macros_escape,
in_block: in_block,
};
self.module_data.push(data);
Module(self.module_data.len() as u32 - 1)
}
pub fn find(&self, name: Name) -> Option<Rc<SyntaxExtension>> {
let mut module = self.current_module;
let mut module_data;
loop {
module_data = self.data(module);
if let Some(ext) = module_data.macros.get(&name) {
return Some(ext.clone());
}
if module == module_data.parent {
return None;
}
module = module_data.parent;
}
}
pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
if let NormalTT(..) = ext {
self.names.insert(name);
}
let mut module = self.current_module;
while self.data(module).macros_escape {
module = self.data(module).parent;
}
self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
}
pub fn is_crate_root(&mut self) -> bool {
self.current_module == Module(0)
}
}