From 9b2a89b7f172eb677adbb0fb80d7f2d8a2158fa9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Wed, 20 Jun 2018 00:08:14 +0300 Subject: [PATCH 01/11] hygiene: Give `Debug` impls to hygiene structures --- src/libsyntax_pos/hygiene.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 0ca42169b8e..6cf6f6f17c1 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -29,7 +29,7 @@ use std::fmt; #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] pub struct SyntaxContext(pub(super) u32); -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct SyntaxContextData { pub outer_mark: Mark, pub prev_ctxt: SyntaxContext, @@ -40,13 +40,14 @@ pub struct SyntaxContextData { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Mark(u32); +#[derive(Debug)] struct MarkData { parent: Mark, kind: MarkKind, expn_info: Option<ExpnInfo>, } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum MarkKind { Modern, Builtin, @@ -147,6 +148,7 @@ impl Mark { } } +#[derive(Debug)] pub struct HygieneData { marks: Vec<MarkData>, syntax_contexts: Vec<SyntaxContextData>, From 17f20bec227244a0b47c8c0c24e09452a061e09a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Wed, 20 Jun 2018 00:09:56 +0300 Subject: [PATCH 02/11] expansion: Remove unnecessary override from `impl Folder for Marker` --- src/libsyntax/ext/expand.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 29030783ca6..af30c494888 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1569,11 +1569,6 @@ impl<'feat> ExpansionConfig<'feat> { pub struct Marker(pub Mark); impl Folder for Marker { - fn fold_ident(&mut self, mut ident: Ident) -> Ident { - ident.span = ident.span.apply_mark(self.0); - ident - } - fn new_span(&mut self, span: Span) -> Span { span.apply_mark(self.0) } From b15785b67133b5017f141d1fda1dd3dcf331b4b4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Wed, 20 Jun 2018 00:13:11 +0300 Subject: [PATCH 03/11] hygiene: Make sure expansion info is set at most once for a given `Mark` --- src/libsyntax_pos/hygiene.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 6cf6f6f17c1..64cd31a485c 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -85,7 +85,14 @@ impl Mark { #[inline] pub fn set_expn_info(self, info: ExpnInfo) { - HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info)) + HygieneData::with(|data| { + let old_info = &mut data.marks[self.0 as usize].expn_info; + if let Some(old_info) = old_info { + panic!("expansion info is reset for the mark {}\nold: {:#?}\nnew: {:#?}", + self.0, old_info, info); + } + *old_info = Some(info); + }) } pub fn modern(mut self) -> Mark { From 869fa27d131d3376c3a7b6e1d3a1fb0d1ce20c9c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Wed, 20 Jun 2018 00:54:17 +0300 Subject: [PATCH 04/11] hygiene: Rename `MarkKind` to `Transparency` Move `is_builtin` for `Mark` to a separate flag --- src/librustc_resolve/lib.rs | 4 +- src/librustc_resolve/macros.rs | 6 +-- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax_pos/hygiene.rs | 70 +++++++++++++++++++++++++--------- 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 792edf4d12b..2052918747b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,7 +45,7 @@ use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use syntax::codemap::CodeMap; -use syntax::ext::hygiene::{Mark, MarkKind, SyntaxContext}; +use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; @@ -1988,7 +1988,7 @@ impl<'a> Resolver<'a> { // When resolving `$crate` from a `macro_rules!` invoked in a `macro`, // we don't want to pretend that the `macro_rules!` definition is in the `macro` // as described in `SyntaxContext::apply_mark`, so we ignore prepended modern marks. - ctxt.marks().into_iter().find(|&mark| mark.kind() != MarkKind::Modern) + ctxt.marks().into_iter().find(|&mark| mark.transparency() != Transparency::Opaque) } else { ctxt = ctxt.modern(); ctxt.adjust(Mark::root()) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 649e8858b09..65dec8ad16c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; -use syntax::ext::hygiene::{self, Mark, MarkKind}; +use syntax::ext::hygiene::{self, Mark, Transparency}; use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; @@ -331,9 +331,9 @@ impl<'a> base::Resolver for Resolver<'a> { self.unused_macros.remove(&def_id); let ext = self.get_macro(def); if ext.is_modern() { - invoc.expansion_data.mark.set_kind(MarkKind::Modern); + invoc.expansion_data.mark.set_transparency(Transparency::Opaque); } else if def_id.krate == BUILTIN_MACROS_CRATE { - invoc.expansion_data.mark.set_kind(MarkKind::Builtin); + invoc.expansion_data.mark.set_is_builtin(true); } Ok(Some(ext)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ac8088507dd..70c4324a056 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -18,7 +18,7 @@ use util::parser::{self, AssocOp, Fixity}; use attr; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; -use syntax_pos::hygiene::{Mark, MarkKind, SyntaxContext}; +use syntax_pos::hygiene::{Mark, SyntaxContext}; use parse::token::{self, BinOpToken, Token}; use parse::lexer::comments; use parse::{self, ParseSess}; @@ -842,7 +842,7 @@ pub trait PrintState<'a> { fn print_dollar_crate(&mut self, mut ctxt: SyntaxContext) -> io::Result<()> { if let Some(mark) = ctxt.adjust(Mark::root()) { // Make a best effort to print something that complies - if mark.kind() == MarkKind::Builtin { + if mark.is_builtin() { if let Some(name) = std_inject::injected_crate_name() { self.writer().word("::")?; self.writer().word(name)?; diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 64cd31a485c..cd2b8b2bff8 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -43,21 +43,41 @@ pub struct Mark(u32); #[derive(Debug)] struct MarkData { parent: Mark, - kind: MarkKind, + transparency: Transparency, + is_builtin: bool, expn_info: Option<ExpnInfo>, } +/// A property of a macro expansion that determines how identifiers +/// produced by that expansion are resolved. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum MarkKind { - Modern, - Builtin, - Legacy, +pub enum Transparency { + /// Identifier produced by a transparent expansion is always resolved at call-site. + /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. + /// (Not used yet.) + Transparent, + /// Identifier produced by a semi-transparent expansion may be resolved + /// either at call-site or at definition-site. + /// If it's a local variable, label or `$crate` then it's resolved at def-site. + /// Otherwise it's resolved at call-site. + /// `macro_rules` macros behave like this, built-in macros currently behave like this too, + /// but that's an implementation detail. + SemiTransparent, + /// Identifier produced by an opaque expansion is always resolved at definition-site. + /// Def-site spans in procedural macros, identifiers from `macro` by default use this. + Opaque, } impl Mark { pub fn fresh(parent: Mark) -> Self { HygieneData::with(|data| { - data.marks.push(MarkData { parent: parent, kind: MarkKind::Legacy, expn_info: None }); + data.marks.push(MarkData { + parent, + // By default expansions behave like `macro_rules`. + transparency: Transparency::SemiTransparent, + is_builtin: false, + expn_info: None, + }); Mark(data.marks.len() as u32 - 1) }) } @@ -97,23 +117,31 @@ impl Mark { pub fn modern(mut self) -> Mark { HygieneData::with(|data| { - loop { - if self == Mark::root() || data.marks[self.0 as usize].kind == MarkKind::Modern { - return self; - } + while data.marks[self.0 as usize].transparency != Transparency::Opaque { self = data.marks[self.0 as usize].parent; } + self }) } #[inline] - pub fn kind(self) -> MarkKind { - HygieneData::with(|data| data.marks[self.0 as usize].kind) + pub fn transparency(self) -> Transparency { + HygieneData::with(|data| data.marks[self.0 as usize].transparency) } #[inline] - pub fn set_kind(self, kind: MarkKind) { - HygieneData::with(|data| data.marks[self.0 as usize].kind = kind) + pub fn set_transparency(self, transparency: Transparency) { + HygieneData::with(|data| data.marks[self.0 as usize].transparency = transparency) + } + + #[inline] + pub fn is_builtin(self) -> bool { + HygieneData::with(|data| data.marks[self.0 as usize].is_builtin) + } + + #[inline] + pub fn set_is_builtin(self, is_builtin: bool) { + HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin) } pub fn is_descendant_of(mut self, ancestor: Mark) -> bool { @@ -169,7 +197,10 @@ impl HygieneData { HygieneData { marks: vec![MarkData { parent: Mark::root(), - kind: MarkKind::Builtin, + // If the root is opaque, then loops searching for an opaque mark + // will automatically stop after reaching it. + transparency: Transparency::Opaque, + is_builtin: true, expn_info: None, }], syntax_contexts: vec![SyntaxContextData { @@ -215,8 +246,9 @@ impl SyntaxContext { HygieneData::with(|data| { data.marks.push(MarkData { parent: Mark::root(), - kind: MarkKind::Legacy, - expn_info: Some(expansion_info) + transparency: Transparency::SemiTransparent, + is_builtin: false, + expn_info: Some(expansion_info), }); let mark = Mark(data.marks.len() as u32 - 1); @@ -232,7 +264,7 @@ impl SyntaxContext { /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { - if mark.kind() == MarkKind::Modern { + if mark.transparency() == Transparency::Opaque { return self.apply_mark_internal(mark); } @@ -262,7 +294,7 @@ impl SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; let mut modern = syntax_contexts[self.0 as usize].modern; - if data.marks[mark.0 as usize].kind == MarkKind::Modern { + if data.marks[mark.0 as usize].transparency == Transparency::Opaque { modern = *data.markings.entry((modern, mark)).or_insert_with(|| { let len = syntax_contexts.len() as u32; syntax_contexts.push(SyntaxContextData { From a12726460ee2b36fe97ed5751c0d93758ed7cee5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Wed, 20 Jun 2018 02:08:08 +0300 Subject: [PATCH 05/11] expansion: Rename `Expansion` to `AstFragment` --- src/librustc_resolve/macros.rs | 17 +- src/libsyntax/ext/base.rs | 8 +- src/libsyntax/ext/expand.rs | 311 ++++++++++++++-------------- src/libsyntax/ext/placeholders.rs | 57 ++--- src/libsyntax/ext/tt/macro_rules.rs | 10 +- 5 files changed, 208 insertions(+), 195 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 65dec8ad16c..1c49e8f4753 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -23,7 +23,7 @@ use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; -use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; +use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, Mark, Transparency}; use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; @@ -187,9 +187,10 @@ impl<'a> base::Resolver for Resolver<'a> { self.whitelisted_legacy_custom_derives.contains(&name) } - fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]) { + fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, + derives: &[Mark]) { let invocation = self.invocations[&mark]; - self.collect_def_ids(mark, invocation, expansion); + self.collect_def_ids(mark, invocation, fragment); self.current_module = invocation.module.get(); self.current_module.unresolved_invocations.borrow_mut().remove(&mark); @@ -202,7 +203,7 @@ impl<'a> base::Resolver for Resolver<'a> { legacy_scope: LegacyScope::Invocation(invocation), expansion: mark, }; - expansion.visit_with(&mut visitor); + fragment.visit_with(&mut visitor); invocation.expansion.set(visitor.legacy_scope); } @@ -396,14 +397,14 @@ impl<'a> Resolver<'a> { Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext { if inert_attrs.contains(&attr_name) { // FIXME(jseyfried) Avoid `mem::replace` here. - let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + let dummy_item = placeholder(AstFragmentKind::Items, ast::DUMMY_NODE_ID) .make_items().pop().unwrap(); let dummy_item = Annotatable::Item(dummy_item); *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| { let inert_attr = attr.take().unwrap(); attr::mark_known(&inert_attr); if self.proc_macro_enabled { - *attr = find_attr_invoc(&mut attrs); + *attr = expand::find_attr_invoc(&mut attrs); } attrs.push(inert_attr); attrs @@ -769,7 +770,7 @@ impl<'a> Resolver<'a> { fn collect_def_ids(&mut self, mark: Mark, invocation: &'a InvocationData<'a>, - expansion: &Expansion) { + fragment: &AstFragment) { let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; let InvocationData { def_index, .. } = *invocation; @@ -787,7 +788,7 @@ impl<'a> Resolver<'a> { let mut def_collector = DefCollector::new(&mut self.definitions, mark); def_collector.visit_macro_invoc = Some(visit_macro_invoc); def_collector.with_parent(def_index, |def_collector| { - expansion.visit_with(def_collector) + fragment.visit_with(def_collector) }); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7c2eb540a30..b7f4bc61435 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -16,7 +16,7 @@ use codemap::{self, CodeMap, Spanned, respan}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; use edition::Edition; use errors::{DiagnosticBuilder, DiagnosticId}; -use ext::expand::{self, Expansion, Invocation}; +use ext::expand::{self, AstFragment, Invocation}; use ext::hygiene::{self, Mark, SyntaxContext}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; @@ -697,7 +697,8 @@ pub trait Resolver { fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>; fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; - fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); + fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, + derives: &[Mark]); fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>); fn resolve_imports(&mut self); @@ -726,7 +727,8 @@ impl Resolver for DummyResolver { fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item } fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } - fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} + fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment, + _derives: &[Mark]) {} fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {} fn resolve_imports(&mut self) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index af30c494888..f67ced13a9f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -40,46 +40,51 @@ use std::mem; use std::rc::Rc; use std::path::PathBuf; -macro_rules! expansions { +macro_rules! ast_fragments { ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*, $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { - #[derive(Copy, Clone, PartialEq, Eq)] - pub enum ExpansionKind { OptExpr, $( $kind, )* } - pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* } + /// A fragment of AST that can be produced by a single macro expansion. + /// Can also serve as an input and intermediate result for macro expansion operations. + pub enum AstFragment { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* } - impl ExpansionKind { + /// "Discriminant" of an AST fragment. + #[derive(Copy, Clone, PartialEq, Eq)] + pub enum AstFragmentKind { OptExpr, $( $kind, )* } + + impl AstFragmentKind { pub fn name(self) -> &'static str { match self { - ExpansionKind::OptExpr => "expression", - $( ExpansionKind::$kind => $kind_name, )* + AstFragmentKind::OptExpr => "expression", + $( AstFragmentKind::$kind => $kind_name, )* } } - fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<Expansion> { + fn make_from<'a>(self, result: Box<MacResult + 'a>) -> Option<AstFragment> { match self { - ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr), - $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )* + AstFragmentKind::OptExpr => + result.make_expr().map(Some).map(AstFragment::OptExpr), + $( AstFragmentKind::$kind => result.$make().map(AstFragment::$kind), )* } } } - impl Expansion { + impl AstFragment { pub fn make_opt_expr(self) -> Option<P<ast::Expr>> { match self { - Expansion::OptExpr(expr) => expr, - _ => panic!("Expansion::make_* called on the wrong kind of expansion"), + AstFragment::OptExpr(expr) => expr, + _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), } } $( pub fn $make(self) -> $ty { match self { - Expansion::$kind(ast) => ast, - _ => panic!("Expansion::make_* called on the wrong kind of expansion"), + AstFragment::$kind(ast) => ast, + _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), } } )* pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self { - use self::Expansion::*; + use self::AstFragment::*; match self { OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))), $($( $kind(ast) => $kind(folder.$fold(ast)), )*)* @@ -91,10 +96,10 @@ macro_rules! expansions { pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { match *self { - Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), - Expansion::OptExpr(None) => {} - $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* - $($( Expansion::$kind(ref ast) => for ast in &ast[..] { + AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), + AstFragment::OptExpr(None) => {} + $($( AstFragment::$kind(ref ast) => visitor.$visit(ast), )*)* + $($( AstFragment::$kind(ref ast) => for ast in &ast[..] { visitor.$visit_elt(ast); }, )*)* } @@ -103,25 +108,25 @@ macro_rules! expansions { impl<'a, 'b> Folder for MacroExpander<'a, 'b> { fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { - self.expand(Expansion::OptExpr(Some(expr))).make_opt_expr() + self.expand(AstFragment::OptExpr(Some(expr))).make_opt_expr() } $($(fn $fold(&mut self, node: $ty) -> $ty { - self.expand(Expansion::$kind(node)).$make() + self.expand(AstFragment::$kind(node)).$make() })*)* $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty { - self.expand(Expansion::$kind(SmallVector::one(node))).$make() + self.expand(AstFragment::$kind(SmallVector::one(node))).$make() })*)* } impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> { $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> { - Some(self.make(ExpansionKind::$kind).$make()) + Some(self.make(AstFragmentKind::$kind).$make()) })* } } } -expansions! { +ast_fragments! { Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr; Pat: P<ast::Pat> [], "pattern", .make_pat, .fold_pat, .visit_pat; Ty: P<ast::Ty> [], "type", .make_ty, .fold_ty, .visit_ty; @@ -137,29 +142,31 @@ expansions! { "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item; } -impl ExpansionKind { - fn dummy(self, span: Span) -> Option<Expansion> { +impl AstFragmentKind { + fn dummy(self, span: Span) -> Option<AstFragment> { self.make_from(DummyResult::any(span)) } - fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) -> Expansion { + fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) + -> AstFragment { let mut items = items.into_iter(); match self { - ExpansionKind::Items => - Expansion::Items(items.map(Annotatable::expect_item).collect()), - ExpansionKind::ImplItems => - Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()), - ExpansionKind::TraitItems => - Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()), - ExpansionKind::ForeignItems => - Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()), - ExpansionKind::Stmts => Expansion::Stmts(items.map(Annotatable::expect_stmt).collect()), - ExpansionKind::Expr => Expansion::Expr( + AstFragmentKind::Items => + AstFragment::Items(items.map(Annotatable::expect_item).collect()), + AstFragmentKind::ImplItems => + AstFragment::ImplItems(items.map(Annotatable::expect_impl_item).collect()), + AstFragmentKind::TraitItems => + AstFragment::TraitItems(items.map(Annotatable::expect_trait_item).collect()), + AstFragmentKind::ForeignItems => + AstFragment::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()), + AstFragmentKind::Stmts => + AstFragment::Stmts(items.map(Annotatable::expect_stmt).collect()), + AstFragmentKind::Expr => AstFragment::Expr( items.next().expect("expected exactly one expression").expect_expr() ), - ExpansionKind::OptExpr => - Expansion::OptExpr(items.next().map(Annotatable::expect_expr)), - ExpansionKind::Pat | ExpansionKind::Ty => + AstFragmentKind::OptExpr => + AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)), + AstFragmentKind::Pat | AstFragmentKind::Ty => panic!("patterns and types aren't annotatable"), } } @@ -187,7 +194,7 @@ fn macro_bang_format(path: &ast::Path) -> ExpnFormat { pub struct Invocation { pub kind: InvocationKind, - expansion_kind: ExpansionKind, + fragment_kind: AstFragmentKind, pub expansion_data: ExpansionData, } @@ -244,7 +251,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_mod_span = krate.module.inner; - let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { + let krate_item = AstFragment::Items(SmallVector::one(P(ast::Item { attrs: krate.attrs, span: krate.span, node: ast::ItemKind::Mod(krate.module), @@ -273,16 +280,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate } - // Fully expand all the invocations in `expansion`. - fn expand(&mut self, expansion: Expansion) -> Expansion { + // Fully expand all macro invocations in this AST fragment. + fn expand(&mut self, input_fragment: AstFragment) -> AstFragment { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; - let (expansion, mut invocations) = self.collect_invocations(expansion, &[]); + let (fragment_with_placeholders, mut invocations) + = self.collect_invocations(input_fragment, &[]); self.resolve_imports(); invocations.reverse(); - let mut expansions = Vec::new(); + let mut expanded_fragments = Vec::new(); let mut derives = HashMap::new(); let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); @@ -314,11 +322,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion.mark = scope; // FIXME(jseyfried): Refactor out the following logic - let (expansion, new_invocations) = if let Some(ext) = ext { + let (expanded_fragment, new_invocations) = if let Some(ext) = ext { if let Some(ext) = ext { - let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap(); - let expansion = self.expand_invoc(invoc, &*ext).unwrap_or(dummy); - self.collect_invocations(expansion, &[]) + let dummy = invoc.fragment_kind.dummy(invoc.span()).unwrap(); + let fragment = self.expand_invoc(invoc, &*ext).unwrap_or(dummy); + self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), "derive") @@ -359,27 +367,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; invocations.push(Invocation { kind: InvocationKind::Derive { path: path.clone(), item: item }, - expansion_kind: invoc.expansion_kind, + fragment_kind: invoc.fragment_kind, expansion_data: ExpansionData { mark, ..invoc.expansion_data.clone() }, }); } - let expansion = invoc.expansion_kind + let fragment = invoc.fragment_kind .expect_from_annotatables(::std::iter::once(item_with_markers)); - self.collect_invocations(expansion, derives) + self.collect_invocations(fragment, derives) } else { unreachable!() } } else { - self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[]) + self.collect_invocations(invoc.fragment_kind.dummy(invoc.span()).unwrap(), &[]) }; - if expansions.len() < depth { - expansions.push(Vec::new()); + if expanded_fragments.len() < depth { + expanded_fragments.push(Vec::new()); } - expansions[depth - 1].push((mark, expansion)); + expanded_fragments[depth - 1].push((mark, expanded_fragment)); if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } @@ -388,14 +396,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); - while let Some(expansions) = expansions.pop() { - for (mark, expansion) in expansions.into_iter().rev() { + while let Some(expanded_fragments) = expanded_fragments.pop() { + for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() { let derives = derives.remove(&mark).unwrap_or_else(Vec::new); - placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives); + placeholder_expander.add(NodeId::placeholder_from_mark(mark), + expanded_fragment, derives); } } - expansion.fold_with(&mut placeholder_expander) + fragment_with_placeholders.fold_with(&mut placeholder_expander) } fn resolve_imports(&mut self) { @@ -406,9 +415,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark]) - -> (Expansion, Vec<Invocation>) { - let result = { + fn collect_invocations(&mut self, fragment: AstFragment, derives: &[Mark]) + -> (AstFragment, Vec<Invocation>) { + let (fragment_with_placeholders, invocations) = { let mut collector = InvocationCollector { cfg: StripUnconfigured { should_test: self.cx.ecfg.should_test, @@ -419,17 +428,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invocations: Vec::new(), monotonic: self.monotonic, }; - (expansion.fold_with(&mut collector), collector.invocations) + (fragment.fold_with(&mut collector), collector.invocations) }; if self.monotonic { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); let mark = self.cx.current_expansion.mark; - self.cx.resolver.visit_expansion(mark, &result.0, derives); + self.cx.resolver.visit_ast_fragment_with_placeholders(mark, &fragment_with_placeholders, + derives); self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; } - result + (fragment_with_placeholders, invocations) } fn fully_configure(&mut self, item: Annotatable) -> Annotatable { @@ -464,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<Expansion> { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> { let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?, InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?, @@ -491,8 +501,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_attr_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option<Expansion> { - let Invocation { expansion_kind: kind, .. } = invoc; + -> Option<AstFragment> { let (attr, item) = match invoc.kind { InvocationKind::Attr { attr, item, .. } => (attr?, item), _ => unreachable!(), @@ -515,7 +524,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let meta = attr.parse_meta(self.cx.parse_sess) .map_err(|mut e| { e.emit(); }).ok()?; let item = mac.expand(self.cx, attr.span, &meta, item); - Some(kind.expect_from_annotatables(item)) + Some(invoc.fragment_kind.expect_from_annotatables(item)) } MultiDecorator(ref mac) => { let mut items = Vec::new(); @@ -523,7 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .expect("derive meta should already have been parsed"); mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); items.push(item); - Some(kind.expect_from_annotatables(items)) + Some(invoc.fragment_kind.expect_from_annotatables(items)) } AttrProcMacro(ref mac, ..) => { self.gate_proc_macro_attr_item(attr.span, &item); @@ -537,20 +546,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { })).into(); let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); let tok_result = mac.expand(self.cx, attr.span, input, item_tok); - let res = self.parse_expansion(tok_result, kind, &attr.path, attr.span); + let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind, + &attr.path, attr.span); self.gate_proc_macro_expansion(attr.span, &res); res } ProcMacroDerive(..) | BuiltinDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); self.cx.trace_macros_diag(); - kind.dummy(attr.span) + invoc.fragment_kind.dummy(attr.span) } _ => { let msg = &format!("macro `{}` may not be used in attributes", attr.path); self.cx.span_err(attr.span, msg); self.cx.trace_macros_diag(); - kind.dummy(attr.span) + invoc.fragment_kind.dummy(attr.span) } } } @@ -598,16 +608,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - fn gate_proc_macro_expansion(&self, span: Span, expansion: &Option<Expansion>) { + fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option<AstFragment>) { if self.cx.ecfg.proc_macro_gen() { return } - let expansion = match expansion { - Some(expansion) => expansion, + let fragment = match fragment { + Some(fragment) => fragment, None => return, }; - expansion.visit_with(&mut DisallowModules { + fragment.visit_with(&mut DisallowModules { span, parse_sess: self.cx.parse_sess, }); @@ -642,12 +652,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - /// Expand a macro invocation. Returns the result of expansion. + /// Expand a macro invocation. Returns the resulting expanded AST fragment. fn expand_bang_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option<Expansion> { - let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind); + -> Option<AstFragment> { + let (mark, kind) = (invoc.expansion_data.mark, invoc.fragment_kind); let (mac, ident, span) = match invoc.kind { InvocationKind::Bang { mac, ident, span } => (mac, ident, span), _ => unreachable!(), @@ -790,7 +800,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); let tok_result = expandfun.expand(self.cx, span, mac.node.stream()); - let result = self.parse_expansion(tok_result, kind, path, span); + let result = self.parse_ast_fragment(tok_result, kind, path, span); self.gate_proc_macro_expansion(span, &result); result } @@ -808,17 +818,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) { + fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { - ExpansionKind::Expr => "expressions", - ExpansionKind::OptExpr => "expressions", - ExpansionKind::Pat => "patterns", - ExpansionKind::Ty => "types", - ExpansionKind::Stmts => "statements", - ExpansionKind::Items => return, - ExpansionKind::TraitItems => return, - ExpansionKind::ImplItems => return, - ExpansionKind::ForeignItems => return, + AstFragmentKind::Expr => "expressions", + AstFragmentKind::OptExpr => "expressions", + AstFragmentKind::Pat => "patterns", + AstFragmentKind::Ty => "types", + AstFragmentKind::Stmts => "statements", + AstFragmentKind::Items => return, + AstFragmentKind::TraitItems => return, + AstFragmentKind::ImplItems => return, + AstFragmentKind::ForeignItems => return, }; if self.cx.ecfg.proc_macro_non_items() { return @@ -832,12 +842,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - /// Expand a derive invocation. Returns the result of expansion. + /// Expand a derive invocation. Returns the resulting expanded AST fragment. fn expand_derive_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option<Expansion> { - let Invocation { expansion_kind: kind, .. } = invoc; + -> Option<AstFragment> { let (path, item) = match invoc.kind { InvocationKind::Derive { path, item } => (path, item), _ => unreachable!(), @@ -876,7 +885,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { node: ast::MetaItemKind::Word, }; let items = ext.expand(self.cx, span, &dummy, item); - Some(kind.expect_from_annotatables(items)) + Some(invoc.fragment_kind.expect_from_annotatables(items)) } BuiltinDerive(func) => { expn_info.callee.allow_internal_unstable = true; @@ -884,28 +893,28 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let span = span.with_ctxt(self.cx.backtrace()); let mut items = Vec::new(); func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a)); - Some(kind.expect_from_annotatables(items)) + Some(invoc.fragment_kind.expect_from_annotatables(items)) } _ => { let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); self.cx.span_err(span, msg); self.cx.trace_macros_diag(); - kind.dummy(span) + invoc.fragment_kind.dummy(span) } } } - fn parse_expansion(&mut self, - toks: TokenStream, - kind: ExpansionKind, - path: &Path, - span: Span) - -> Option<Expansion> { + fn parse_ast_fragment(&mut self, + toks: TokenStream, + kind: AstFragmentKind, + path: &Path, + span: Span) + -> Option<AstFragment> { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>()); - match parser.parse_expansion(kind, false) { - Ok(expansion) => { + match parser.parse_ast_fragment(kind, false) { + Ok(fragment) => { parser.ensure_complete_parse(path, kind.name(), span); - Some(expansion) + Some(fragment) } Err(mut err) => { err.set_span(span); @@ -918,40 +927,40 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } impl<'a> Parser<'a> { - pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool) - -> PResult<'a, Expansion> { + pub fn parse_ast_fragment(&mut self, kind: AstFragmentKind, macro_legacy_warnings: bool) + -> PResult<'a, AstFragment> { Ok(match kind { - ExpansionKind::Items => { + AstFragmentKind::Items => { let mut items = SmallVector::new(); while let Some(item) = self.parse_item()? { items.push(item); } - Expansion::Items(items) + AstFragment::Items(items) } - ExpansionKind::TraitItems => { + AstFragmentKind::TraitItems => { let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_trait_item(&mut false)?); } - Expansion::TraitItems(items) + AstFragment::TraitItems(items) } - ExpansionKind::ImplItems => { + AstFragmentKind::ImplItems => { let mut items = SmallVector::new(); while self.token != token::Eof { items.push(self.parse_impl_item(&mut false)?); } - Expansion::ImplItems(items) + AstFragment::ImplItems(items) } - ExpansionKind::ForeignItems => { + AstFragmentKind::ForeignItems => { let mut items = SmallVector::new(); while self.token != token::Eof { if let Some(item) = self.parse_foreign_item()? { items.push(item); } } - Expansion::ForeignItems(items) + AstFragment::ForeignItems(items) } - ExpansionKind::Stmts => { + AstFragmentKind::Stmts => { let mut stmts = SmallVector::new(); while self.token != token::Eof && // won't make progress on a `}` @@ -960,18 +969,18 @@ impl<'a> Parser<'a> { stmts.push(stmt); } } - Expansion::Stmts(stmts) + AstFragment::Stmts(stmts) } - ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), - ExpansionKind::OptExpr => { + AstFragmentKind::Expr => AstFragment::Expr(self.parse_expr()?), + AstFragmentKind::OptExpr => { if self.token != token::Eof { - Expansion::OptExpr(Some(self.parse_expr()?)) + AstFragment::OptExpr(Some(self.parse_expr()?)) } else { - Expansion::OptExpr(None) + AstFragment::OptExpr(None) } }, - ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), - ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), + AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?), + AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?), }) } @@ -998,21 +1007,21 @@ struct InvocationCollector<'a, 'b: 'a> { } impl<'a, 'b> InvocationCollector<'a, 'b> { - fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { + fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { let mark = Mark::fresh(self.cx.current_expansion.mark); self.invocations.push(Invocation { kind, - expansion_kind, + fragment_kind, expansion_data: ExpansionData { mark, depth: self.cx.current_expansion.depth + 1, ..self.cx.current_expansion.clone() }, }); - placeholder(expansion_kind, NodeId::placeholder_from_mark(mark)) + placeholder(fragment_kind, NodeId::placeholder_from_mark(mark)) } - fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { + fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment { self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span }) } @@ -1020,8 +1029,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: Option<ast::Attribute>, traits: Vec<Path>, item: Annotatable, - kind: ExpansionKind) - -> Expansion { + kind: AstFragmentKind) + -> AstFragment { self.collect(kind, InvocationKind::Attr { attr, traits, item }) } @@ -1119,14 +1128,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // expansion will eat the attribute so it won't error later attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); - // ExpansionKind::Expr requires the macro to emit an expression - return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), ExpansionKind::Expr) - .make_expr(); + // AstFragmentKind::Expr requires the macro to emit an expression + return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), + AstFragmentKind::Expr).make_expr(); } if let ast::ExprKind::Mac(mac) = expr.node { self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr() + self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr() } else { P(noop_fold_expr(expr, self)) } @@ -1143,13 +1152,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a)); return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)), - ExpansionKind::OptExpr) + AstFragmentKind::OptExpr) .make_opt_expr(); } if let ast::ExprKind::Mac(mac) = expr.node { self.check_attributes(&expr.attrs); - self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr() + self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr() } else { Some(P(noop_fold_expr(expr, self))) } @@ -1163,7 +1172,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } pat.and_then(|pat| match pat.node { - PatKind::Mac(mac) => self.collect_bang(mac, pat.span, ExpansionKind::Pat).make_pat(), + PatKind::Mac(mac) => self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat(), _ => unreachable!(), }) } @@ -1187,7 +1196,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { if attr.is_some() || !derives.is_empty() { return self.collect_attr(attr, derives, - Annotatable::Stmt(P(stmt_)), ExpansionKind::Stmts) + Annotatable::Stmt(P(stmt_)), AstFragmentKind::Stmts) .make_stmts(); } @@ -1197,7 +1206,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { if let StmtKind::Mac(mac) = stmt.node { let (mac, style, attrs) = mac.into_inner(); self.check_attributes(&attrs); - let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts) + let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts) .make_stmts(); // If this is a macro invocation with a semicolon, then apply that @@ -1233,7 +1242,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, mut item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { let item = Annotatable::Item(item); - return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items(); + return self.collect_attr(attr, traits, item, AstFragmentKind::Items).make_items(); } match item.node { @@ -1241,7 +1250,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { self.check_attributes(&item.attrs); item.and_then(|item| match item.node { ItemKind::Mac(mac) => { - self.collect(ExpansionKind::Items, InvocationKind::Bang { + self.collect(AstFragmentKind::Items, InvocationKind::Bang { mac, ident: Some(item.ident), span: item.span, @@ -1317,7 +1326,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { let item = Annotatable::TraitItem(P(item)); - return self.collect_attr(attr, traits, item, ExpansionKind::TraitItems) + return self.collect_attr(attr, traits, item, AstFragmentKind::TraitItems) .make_trait_items() } @@ -1325,7 +1334,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ast::TraitItemKind::Macro(mac) => { let ast::TraitItem { attrs, span, .. } = item; self.check_attributes(&attrs); - self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items() + self.collect_bang(mac, span, AstFragmentKind::TraitItems).make_trait_items() } _ => fold::noop_fold_trait_item(item, self), } @@ -1337,7 +1346,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { let item = Annotatable::ImplItem(P(item)); - return self.collect_attr(attr, traits, item, ExpansionKind::ImplItems) + return self.collect_attr(attr, traits, item, AstFragmentKind::ImplItems) .make_impl_items(); } @@ -1345,7 +1354,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ast::ImplItemKind::Macro(mac) => { let ast::ImplItem { attrs, span, .. } = item; self.check_attributes(&attrs); - self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items() + self.collect_bang(mac, span, AstFragmentKind::ImplItems).make_impl_items() } _ => fold::noop_fold_impl_item(item, self), } @@ -1358,7 +1367,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }; match ty.node { - ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, ExpansionKind::Ty).make_ty(), + ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty(), _ => unreachable!(), } } @@ -1386,7 +1395,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } let item = Annotatable::ForeignItem(P(foreign_item)); - return self.collect_attr(attr, traits, item, ExpansionKind::ForeignItems) + return self.collect_attr(attr, traits, item, AstFragmentKind::ForeignItems) .make_foreign_items(); } @@ -1398,7 +1407,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { GateIssue::Language, explain); } - return self.collect_bang(mac, foreign_item.span, ExpansionKind::ForeignItems) + return self.collect_bang(mac, foreign_item.span, AstFragmentKind::ForeignItems) .make_foreign_items(); } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 5c1c661fffd..968cf508eda 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -11,7 +11,7 @@ use ast::{self, NodeId}; use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; -use ext::expand::{Expansion, ExpansionKind}; +use ext::expand::{AstFragment, AstFragmentKind}; use ext::hygiene::Mark; use tokenstream::TokenStream; use fold::*; @@ -22,7 +22,7 @@ use util::small_vector::SmallVector; use std::collections::HashMap; -pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { +pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { fn mac_placeholder() -> ast::Mac { dummy_spanned(ast::Mac_ { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, @@ -43,35 +43,36 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { }); match kind { - ExpansionKind::Expr => Expansion::Expr(expr_placeholder()), - ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())), - ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item { + AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), + AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), + AstFragmentKind::Items => AstFragment::Items(SmallVector::one(P(ast::Item { id, span, ident, vis, attrs, node: ast::ItemKind::Mac(mac_placeholder()), tokens: None, }))), - ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem { + AstFragmentKind::TraitItems => AstFragment::TraitItems(SmallVector::one(ast::TraitItem { id, span, ident, attrs, generics, node: ast::TraitItemKind::Macro(mac_placeholder()), tokens: None, })), - ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem { + AstFragmentKind::ImplItems => AstFragment::ImplItems(SmallVector::one(ast::ImplItem { id, span, ident, vis, attrs, generics, node: ast::ImplItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, })), - ExpansionKind::ForeignItems => Expansion::ForeignItems(SmallVector::one(ast::ForeignItem { - id, span, ident, vis, attrs, - node: ast::ForeignItemKind::Macro(mac_placeholder()), - })), - ExpansionKind::Pat => Expansion::Pat(P(ast::Pat { + AstFragmentKind::ForeignItems => + AstFragment::ForeignItems(SmallVector::one(ast::ForeignItem { + id, span, ident, vis, attrs, + node: ast::ForeignItemKind::Macro(mac_placeholder()), + })), + AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat { id, span, node: ast::PatKind::Mac(mac_placeholder()), })), - ExpansionKind::Ty => Expansion::Ty(P(ast::Ty { + AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { id, span, node: ast::TyKind::Mac(mac_placeholder()), })), - ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({ + AstFragmentKind::Stmts => AstFragment::Stmts(SmallVector::one({ let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new())); ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) } })), @@ -79,7 +80,7 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { } pub struct PlaceholderExpander<'a, 'b: 'a> { - expansions: HashMap<ast::NodeId, Expansion>, + expanded_fragments: HashMap<ast::NodeId, AstFragment>, cx: &'a mut ExtCtxt<'b>, monotonic: bool, } @@ -88,27 +89,27 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { PlaceholderExpander { cx, - expansions: HashMap::new(), + expanded_fragments: HashMap::new(), monotonic, } } - pub fn add(&mut self, id: ast::NodeId, expansion: Expansion, derives: Vec<Mark>) { - let mut expansion = expansion.fold_with(self); - if let Expansion::Items(mut items) = expansion { + pub fn add(&mut self, id: ast::NodeId, fragment: AstFragment, derives: Vec<Mark>) { + let mut fragment = fragment.fold_with(self); + if let AstFragment::Items(mut items) = fragment { for derive in derives { match self.remove(NodeId::placeholder_from_mark(derive)) { - Expansion::Items(derived_items) => items.extend(derived_items), + AstFragment::Items(derived_items) => items.extend(derived_items), _ => unreachable!(), } } - expansion = Expansion::Items(items); + fragment = AstFragment::Items(items); } - self.expansions.insert(id, expansion); + self.expanded_fragments.insert(id, fragment); } - fn remove(&mut self, id: ast::NodeId) -> Expansion { - self.expansions.remove(&id).unwrap() + fn remove(&mut self, id: ast::NodeId) -> AstFragment { + self.expanded_fragments.remove(&id).unwrap() } } @@ -159,18 +160,18 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> { - let (style, mut expansion) = match stmt.node { + let (style, mut stmts) = match stmt.node { ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), _ => return noop_fold_stmt(stmt, self), }; if style == ast::MacStmtStyle::Semicolon { - if let Some(stmt) = expansion.pop() { - expansion.push(stmt.add_trailing_semicolon()); + if let Some(stmt) = stmts.pop() { + stmts.push(stmt.add_trailing_semicolon()); } } - expansion + stmts } fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 2e6d590c333..4ee5357f476 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -13,7 +13,7 @@ use syntax_pos::{Span, DUMMY_SP}; use edition::Edition; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::expand::{Expansion, ExpansionKind}; +use ext::expand::{AstFragment, AstFragmentKind}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -43,21 +43,21 @@ pub struct ParserAnyMacro<'a> { } impl<'a> ParserAnyMacro<'a> { - pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion { + pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self; - let expansion = panictry!(parser.parse_expansion(kind, true)); + let fragment = panictry!(parser.parse_ast_fragment(kind, true)); // We allow semicolons at the end of expressions -- e.g. the semicolon in // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`, // but `m!()` is allowed in expression positions (c.f. issue #34706). - if kind == ExpansionKind::Expr && parser.token == token::Semi { + if kind == AstFragmentKind::Expr && parser.token == token::Semi { parser.bump(); } // Make sure we don't have any tokens left to parse so we don't silently drop anything. let path = ast::Path::from_ident(macro_ident.with_span_pos(site_span)); parser.ensure_complete_parse(&path, kind.name(), site_span); - expansion + fragment } } From 399da7bc351714a0bc829bbbf2ab1f0b3e4f60f8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 01:05:07 +0300 Subject: [PATCH 06/11] expansion: Improve searchability for `AstFragments` methods --- src/libsyntax/ext/expand.rs | 104 +++++++++++++++++++++--------------- src/libsyntax/lib.rs | 9 ++-- 2 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f67ced13a9f..f7fc5bd5798 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -41,22 +41,33 @@ use std::rc::Rc; use std::path::PathBuf; macro_rules! ast_fragments { - ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident, - $(.$fold:ident)* $(lift .$fold_elt:ident)*, - $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { + ( + $($Kind:ident($AstTy:ty) { + $kind_name:expr; + $(one fn $fold_ast:ident; fn $visit_ast:ident;)? + $(many fn $fold_ast_elt:ident; fn $visit_ast_elt:ident;)? + fn $make_ast:ident; + })* + ) => { /// A fragment of AST that can be produced by a single macro expansion. /// Can also serve as an input and intermediate result for macro expansion operations. - pub enum AstFragment { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* } + pub enum AstFragment { + OptExpr(Option<P<ast::Expr>>), + $($Kind($AstTy),)* + } /// "Discriminant" of an AST fragment. #[derive(Copy, Clone, PartialEq, Eq)] - pub enum AstFragmentKind { OptExpr, $( $kind, )* } + pub enum AstFragmentKind { + OptExpr, + $($Kind,)* + } impl AstFragmentKind { pub fn name(self) -> &'static str { match self { AstFragmentKind::OptExpr => "expression", - $( AstFragmentKind::$kind => $kind_name, )* + $(AstFragmentKind::$Kind => $kind_name,)* } } @@ -64,7 +75,7 @@ macro_rules! ast_fragments { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), - $( AstFragmentKind::$kind => result.$make().map(AstFragment::$kind), )* + $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* } } } @@ -76,21 +87,24 @@ macro_rules! ast_fragments { _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), } } - $( pub fn $make(self) -> $ty { + + $(pub fn $make_ast(self) -> $AstTy { match self { - AstFragment::$kind(ast) => ast, + AstFragment::$Kind(ast) => ast, _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), } - } )* + })* pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self { - use self::AstFragment::*; match self { - OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))), - $($( $kind(ast) => $kind(folder.$fold(ast)), )*)* - $($( $kind(ast) => { - $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect()) - }, )*)* + AstFragment::OptExpr(expr) => + AstFragment::OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))), + $($(AstFragment::$Kind(ast) => + AstFragment::$Kind(folder.$fold_ast(ast)),)?)* + $($(AstFragment::$Kind(ast) => + AstFragment::$Kind(ast.into_iter() + .flat_map(|ast| folder.$fold_ast_elt(ast)) + .collect()),)?)* } } @@ -98,48 +112,50 @@ macro_rules! ast_fragments { match *self { AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), AstFragment::OptExpr(None) => {} - $($( AstFragment::$kind(ref ast) => visitor.$visit(ast), )*)* - $($( AstFragment::$kind(ref ast) => for ast in &ast[..] { - visitor.$visit_elt(ast); - }, )*)* + $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* + $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { + visitor.$visit_ast_elt(ast_elt); + })?)* } } } impl<'a, 'b> Folder for MacroExpander<'a, 'b> { fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { - self.expand(AstFragment::OptExpr(Some(expr))).make_opt_expr() + self.expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr() } - $($(fn $fold(&mut self, node: $ty) -> $ty { - self.expand(AstFragment::$kind(node)).$make() - })*)* - $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty { - self.expand(AstFragment::$kind(SmallVector::one(node))).$make() - })*)* + $($(fn $fold_ast(&mut self, ast: $AstTy) -> $AstTy { + self.expand_fragment(AstFragment::$Kind(ast)).$make_ast() + })?)* + $($(fn $fold_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { + self.expand_fragment(AstFragment::$Kind(SmallVector::one(ast_elt))).$make_ast() + })?)* } impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> { - $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> { - Some(self.make(AstFragmentKind::$kind).$make()) + $(fn $make_ast(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) + -> Option<$AstTy> { + Some(self.make(AstFragmentKind::$Kind).$make_ast()) })* } } } ast_fragments! { - Expr: P<ast::Expr> [], "expression", .make_expr, .fold_expr, .visit_expr; - Pat: P<ast::Pat> [], "pattern", .make_pat, .fold_pat, .visit_pat; - Ty: P<ast::Ty> [], "type", .make_ty, .fold_ty, .visit_ty; - Stmts: SmallVector<ast::Stmt> [SmallVector, ast::Stmt], - "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt; - Items: SmallVector<P<ast::Item>> [SmallVector, P<ast::Item>], - "item", .make_items, lift .fold_item, lift .visit_item; - TraitItems: SmallVector<ast::TraitItem> [SmallVector, ast::TraitItem], - "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; - ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem], - "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; - ForeignItems: SmallVector<ast::ForeignItem> [SmallVector, ast::ForeignItem], - "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item; + Expr(P<ast::Expr>) { "expression"; one fn fold_expr; fn visit_expr; fn make_expr; } + Pat(P<ast::Pat>) { "pattern"; one fn fold_pat; fn visit_pat; fn make_pat; } + Ty(P<ast::Ty>) { "type"; one fn fold_ty; fn visit_ty; fn make_ty; } + Stmts(SmallVector<ast::Stmt>) { "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts; } + Items(SmallVector<P<ast::Item>>) { "item"; many fn fold_item; fn visit_item; fn make_items; } + TraitItems(SmallVector<ast::TraitItem>) { + "trait item"; many fn fold_trait_item; fn visit_trait_item; fn make_trait_items; + } + ImplItems(SmallVector<ast::ImplItem>) { + "impl item"; many fn fold_impl_item; fn visit_impl_item; fn make_impl_items; + } + ForeignItems(SmallVector<ast::ForeignItem>) { + "foreign item"; many fn fold_foreign_item; fn visit_foreign_item; fn make_foreign_items; + } } impl AstFragmentKind { @@ -261,7 +277,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { tokens: None, }))); - match self.expand(krate_item).make_items().pop().map(P::into_inner) { + match self.expand_fragment(krate_item).make_items().pop().map(P::into_inner) { Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => { krate.attrs = attrs; krate.module = module; @@ -281,7 +297,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } // Fully expand all macro invocations in this AST fragment. - fn expand(&mut self, input_fragment: AstFragment) -> AstFragment { + fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 2ee14bd61c2..1ace9193dc6 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -19,13 +19,14 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(unicode_internals)] +#![feature(const_atomic_usize_new)] +#![feature(crate_visibility_modifier)] +#![feature(macro_at_most_once_rep)] +#![feature(rustc_attrs)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] -#![feature(const_atomic_usize_new)] -#![feature(rustc_attrs)] #![feature(str_escape)] -#![feature(crate_visibility_modifier)] +#![feature(unicode_internals)] #![recursion_limit="256"] From 296955a6e1ac7b5cb52f3c84d93cd57b19a7a715 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 19:27:01 +0300 Subject: [PATCH 07/11] expansion: Add some comments --- src/libsyntax/ext/expand.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f7fc5bd5798..eb26bdc74b5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -301,11 +301,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; + // Collect all macro invocations and replace them with placeholders. let (fragment_with_placeholders, mut invocations) = self.collect_invocations(input_fragment, &[]); - self.resolve_imports(); - invocations.reverse(); + // Optimization: if we resolve all imports now, + // we'll be able to immediately resolve most of imported macros. + self.resolve_imports(); + + // Resolve paths in all invocations and produce ouput expanded fragments for them, but + // do not insert them into our input AST fragment yet, only store in `expanded_fragments`. + // The output fragments also go through expansion recursively until no invocations are left. + // Unresolved macros produce dummy outputs as a recovery measure. + invocations.reverse(); let mut expanded_fragments = Vec::new(); let mut derives = HashMap::new(); let mut undetermined_invocations = Vec::new(); @@ -411,6 +419,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; + // Finally incorporate all the expanded macros into the input AST fragment. let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expanded_fragments) = expanded_fragments.pop() { for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() { @@ -419,7 +428,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expanded_fragment, derives); } } - fragment_with_placeholders.fold_with(&mut placeholder_expander) } @@ -431,6 +439,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } + /// Collect all macro invocations reachable at this time in this AST fragment, and replace + /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s. + /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and + /// prepares data for resolving paths of macro invocations. fn collect_invocations(&mut self, fragment: AstFragment, derives: &[Mark]) -> (AstFragment, Vec<Invocation>) { let (fragment_with_placeholders, invocations) = { From fffe9fbb5134da7ce77660dfc4562b5e395853e8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 19:27:28 +0300 Subject: [PATCH 08/11] hygiene: More descriptive names for things involved in late hygienic name resolution --- src/librustc/hir/map/definitions.rs | 31 +++++++++++++++++------------ src/librustc/ty/mod.rs | 11 +++++----- src/librustc_resolve/macros.rs | 3 ++- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index b1cb9d7fbd4..b2365e22cc6 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -157,8 +157,13 @@ pub struct Definitions { node_to_def_index: NodeMap<DefIndex>, def_index_to_node: [Vec<ast::NodeId>; 2], pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>, - macro_def_scopes: FxHashMap<Mark, DefId>, - expansions: FxHashMap<DefIndex, Mark>, + /// If `Mark` is an ID of some macro expansion, + /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. + parent_modules_of_macro_defs: FxHashMap<Mark, DefId>, + /// Item with a given `DefIndex` was defined during opaque macro expansion with ID `Mark`. + /// It can actually be defined during transparent macro expansions inside that opaque expansion, + /// but transparent expansions are ignored here. + opaque_expansions_that_defined: FxHashMap<DefIndex, Mark>, next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, def_index_to_span: FxHashMap<DefIndex, Span>, } @@ -175,8 +180,8 @@ impl Clone for Definitions { self.def_index_to_node[1].clone(), ], node_to_hir_id: self.node_to_hir_id.clone(), - macro_def_scopes: self.macro_def_scopes.clone(), - expansions: self.expansions.clone(), + parent_modules_of_macro_defs: self.parent_modules_of_macro_defs.clone(), + opaque_expansions_that_defined: self.opaque_expansions_that_defined.clone(), next_disambiguator: self.next_disambiguator.clone(), def_index_to_span: self.def_index_to_span.clone(), } @@ -397,8 +402,8 @@ impl Definitions { node_to_def_index: NodeMap(), def_index_to_node: [vec![], vec![]], node_to_hir_id: IndexVec::new(), - macro_def_scopes: FxHashMap(), - expansions: FxHashMap(), + parent_modules_of_macro_defs: FxHashMap(), + opaque_expansions_that_defined: FxHashMap(), next_disambiguator: FxHashMap(), def_index_to_span: FxHashMap(), } @@ -580,7 +585,7 @@ impl Definitions { let expansion = expansion.modern(); if expansion != Mark::root() { - self.expansions.insert(index, expansion); + self.opaque_expansions_that_defined.insert(index, expansion); } // The span is added if it isn't DUMMY_SP @@ -600,16 +605,16 @@ impl Definitions { self.node_to_hir_id = mapping; } - pub fn expansion(&self, index: DefIndex) -> Mark { - self.expansions.get(&index).cloned().unwrap_or(Mark::root()) + pub fn opaque_expansion_that_defined(&self, index: DefIndex) -> Mark { + self.opaque_expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root()) } - pub fn macro_def_scope(&self, mark: Mark) -> DefId { - self.macro_def_scopes[&mark] + pub fn parent_module_of_macro_def(&self, mark: Mark) -> DefId { + self.parent_modules_of_macro_defs[&mark] } - pub fn add_macro_def_scope(&mut self, mark: Mark, scope: DefId) { - self.macro_def_scopes.insert(mark, scope); + pub fn add_parent_module_of_macro_def(&mut self, mark: Mark, module: DefId) { + self.parent_modules_of_macro_defs.insert(mark, module); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4f5f0c9d740..ce709831455 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2732,13 +2732,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) { - let expansion = match scope.krate { - LOCAL_CRATE => self.hir.definitions().expansion(scope.index), + ident = ident.modern(); + let target_expansion = match scope.krate { + LOCAL_CRATE => self.hir.definitions().opaque_expansion_that_defined(scope.index), _ => Mark::root(), }; - ident = ident.modern(); - let scope = match ident.span.adjust(expansion) { - Some(macro_def) => self.hir.definitions().macro_def_scope(macro_def), + let scope = match ident.span.adjust(target_expansion) { + Some(actual_expansion) => + self.hir.definitions().parent_module_of_macro_def(actual_expansion), None if block == DUMMY_NODE_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId None => self.hir.get_module_parent(block), }; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 1c49e8f4753..ebdaa456170 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -327,7 +327,8 @@ impl<'a> base::Resolver for Resolver<'a> { self.macro_defs.insert(invoc.expansion_data.mark, def_id); let normal_module_def_id = self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id; - self.definitions.add_macro_def_scope(invoc.expansion_data.mark, normal_module_def_id); + self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark, + normal_module_def_id); self.unused_macros.remove(&def_id); let ext = self.get_macro(def); From c00f5af4d6e709cb23f9d47ceb466c13a073f7b5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 20:09:11 +0300 Subject: [PATCH 09/11] hygiene: Do not reset expansion info for `quote!` --- src/libproc_macro/quote.rs | 3 --- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/libsyntax/ext/base.rs | 6 +++++- src/libsyntax/ext/expand.rs | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index c9d0bc1405f..4cd822aa9d0 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -85,9 +85,6 @@ impl ProcMacro for Quoter { _: ::syntax_pos::Span, stream: tokenstream::TokenStream) -> tokenstream::TokenStream { - let mut info = cx.current_expansion.mark.expn_info().unwrap(); - info.callee.allow_internal_unstable = true; - cx.current_expansion.mark.set_expn_info(info); ::__internal::set_sess(cx, || TokenStream(stream).quote().0) } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 6c199145743..1a13335a0e4 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -570,7 +570,7 @@ impl<'a> CrateLoader<'a> { name: &str, expand: fn(TokenStream) -> TokenStream) { let expand = SyntaxExtension::ProcMacro( - Box::new(BangProcMacro { inner: expand }), self.edition + Box::new(BangProcMacro { inner: expand }), false, self.edition ); self.extensions.push((Symbol::intern(name), Lrc::new(expand))); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index b33d97cb1ee..d0e4e54e63d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -519,7 +519,7 @@ impl CrateStore for cstore::CStore { } else if data.name == "proc_macro" && self.get_crate_data(id.krate).item_name(id.index) == "quote" { let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter), - data.root.edition); + true, data.root.edition); return LoadedMacro::ProcMacro(Lrc::new(ext)); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b7f4bc61435..e8fad1a2177 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -597,7 +597,11 @@ pub enum SyntaxExtension { MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>), /// A function-like procedural macro. TokenStream -> TokenStream. - ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>, Edition), + ProcMacro( + /* expander: */ Box<ProcMacro + sync::Sync + sync::Send>, + /* allow_internal_unstable: */ bool, + /* edition: */ Edition, + ), /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream. /// The first TokenSteam is the attribute, the second is the annotated item. diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eb26bdc74b5..8ad6e32f42d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -804,7 +804,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.dummy(span) } - ProcMacro(ref expandfun, edition) => { + ProcMacro(ref expandfun, allow_internal_unstable, edition) => { if ident.name != keywords::Invalid.name() { let msg = format!("macro {}! expects no ident argument, given '{}'", path, ident); @@ -821,7 +821,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // yet, when they do, we should use it here. span: None, // FIXME probably want to follow macro_rules macros here. - allow_internal_unstable: false, + allow_internal_unstable, allow_internal_unsafe: false, edition, }, From 117cb040f14719489a38ace1c256ec282f42c367 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 20:42:25 +0300 Subject: [PATCH 10/11] hygiene: Make sure transparency of `Mark::root()` is an implementation detail and cannot be inspected outside of `hygiene.rs` --- src/libsyntax_pos/hygiene.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index cd2b8b2bff8..5c35984dfd0 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -126,11 +126,13 @@ impl Mark { #[inline] pub fn transparency(self) -> Transparency { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].transparency) } #[inline] pub fn set_transparency(self, transparency: Transparency) { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].transparency = transparency) } From 20ce91076af125eda82bb36e446e67b1c7af4218 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com> Date: Sat, 23 Jun 2018 21:41:39 +0300 Subject: [PATCH 11/11] hygiene: Merge `NameAndSpan` into `ExpnInfo` --- src/librustc/hir/lowering.rs | 12 ++-- src/librustc/ich/impls_syntax.rs | 8 +-- src/librustc/traits/error_reporting.rs | 3 +- src/librustc_allocator/expand.rs | 14 ++--- src/librustc_save_analysis/lib.rs | 4 +- src/libsyntax/codemap.rs | 2 +- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/derive.rs | 14 ++--- src/libsyntax/ext/expand.rs | 72 ++++++++++------------- src/libsyntax/std_inject.rs | 14 ++--- src/libsyntax/test.rs | 14 ++--- src/libsyntax_ext/deriving/mod.rs | 4 +- src/libsyntax_ext/proc_macro_registrar.rs | 14 ++--- src/libsyntax_pos/hygiene.rs | 54 ++++++++--------- src/libsyntax_pos/lib.rs | 39 ++++++------ 15 files changed, 116 insertions(+), 154 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 02e9415fd8e..4f470e1c26b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -612,13 +612,11 @@ impl<'a> LoweringContext<'a> { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(codemap::ExpnInfo { call_site: span, - callee: codemap::NameAndSpan { - format: codemap::CompilerDesugaring(reason), - span: Some(span), - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: codemap::hygiene::default_edition(), - }, + def_site: Some(span), + format: codemap::CompilerDesugaring(reason), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: codemap::hygiene::default_edition(), }); span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 0f4603be39d..935bc4c8c6d 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -391,15 +391,11 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, - callee -}); - -impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan { + def_site, format, allow_internal_unstable, allow_internal_unsafe, - edition, - span + edition }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f76b312ee53..0d7d39ccf40 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -366,9 +366,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { - let desugaring = k.as_symbol().as_str(); flags.push(("from_desugaring".to_string(), None)); - flags.push(("from_desugaring".to_string(), Some(desugaring.to_string()))); + flags.push(("from_desugaring".to_string(), Some(k.name().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 78406e88c75..a9530964bff 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -15,7 +15,7 @@ use syntax::ast::{Arg, FnHeader, Generics, Mac, Mutability, Ty, Unsafety}; use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}; use syntax::attr; use syntax::codemap::respan; -use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan}; +use syntax::codemap::{ExpnInfo, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::base::Resolver; use syntax::ext::build::AstBuilder; @@ -80,13 +80,11 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(name)), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - }, + def_site: None, + format: MacroAttribute(Symbol::intern(name)), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); let ecfg = ExpansionConfig::default(name.to_string()); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 453500d5ab7..deb91774175 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -844,7 +844,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let callsite = span.source_callsite(); let callsite_span = self.span_from_span(callsite); let callee = span.source_callee()?; - let callee_span = callee.span?; + let callee_span = callee.def_site?; // Ignore attribute macros, their spans are usually mangled if let MacroAttribute(_) = callee.format { @@ -872,7 +872,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let callee_span = self.span_from_span(callee_span); Some(MacroRef { span: callsite_span, - qualname: callee.name().to_string(), // FIXME: generate the real qualname + qualname: callee.format.name().to_string(), // FIXME: generate the real qualname callee_span, }) } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index fe8ce75a4b8..8e4b7660a1c 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -19,7 +19,7 @@ pub use syntax_pos::*; -pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; +pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo}; pub use self::ExpnFormat::*; use rustc_data_structures::fx::FxHashMap; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e8fad1a2177..16d786dd6ca 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -834,7 +834,7 @@ impl<'a> ExtCtxt<'a> { let mut last_macro = None; loop { if ctxt.outer().expn_info().map_or(None, |info| { - if info.callee.name() == "include" { + if info.format.name() == "include" { // Stop going up the backtrace once include! is encountered return None; } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 0b6a7e1c4f4..940fb6405f1 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -10,7 +10,7 @@ use attr::HasAttrs; use ast; -use codemap::{hygiene, ExpnInfo, NameAndSpan, ExpnFormat}; +use codemap::{hygiene, ExpnInfo, ExpnFormat}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use parse::parser::PathStyle; @@ -60,13 +60,11 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path] cx.current_expansion.mark.set_expn_info(ExpnInfo { call_site: span, - callee: NameAndSpan { - format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - }, + def_site: None, + format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); let span = span.with_ctxt(cx.backtrace()); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8ad6e32f42d..69c99c63aaf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -11,7 +11,7 @@ use ast::{self, Block, Ident, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; -use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan}; +use codemap::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan}; use config::{is_test_or_bench, StripUnconfigured}; use errors::{Applicability, FatalError}; use ext::base::*; @@ -514,7 +514,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let suggested_limit = self.cx.ecfg.recursion_limit * 2; let mut err = self.cx.struct_span_err(info.call_site, &format!("recursion limit reached while expanding the macro `{}`", - info.callee.name())); + info.format.name())); err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)); @@ -538,13 +538,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { attr::mark_used(&attr); invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: None, - allow_internal_unstable: false, - allow_internal_unsafe: false, - edition: ext.edition(), - } + def_site: None, + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), + allow_internal_unstable: false, + allow_internal_unsafe: false, + edition: ext.edition(), }); match *ext { @@ -727,13 +725,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } mark.set_expn_info(ExpnInfo { call_site: span, - callee: NameAndSpan { - format: macro_bang_format(path), - span: def_site_span, - allow_internal_unstable, - allow_internal_unsafe, - edition, - }, + def_site: def_site_span, + format: macro_bang_format(path), + allow_internal_unstable, + allow_internal_unsafe, + edition, }); Ok(()) }; @@ -777,13 +773,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } else { invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, - callee: NameAndSpan { - format: macro_bang_format(path), - span: tt_span, - allow_internal_unstable, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - } + def_site: tt_span, + format: macro_bang_format(path), + allow_internal_unstable, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); let input: Vec<_> = mac.node.stream().into_trees().collect(); @@ -815,16 +809,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.gate_proc_macro_expansion_kind(span, kind); invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, - callee: NameAndSpan { - format: macro_bang_format(path), - // FIXME procedural macros do not have proper span info - // yet, when they do, we should use it here. - span: None, - // FIXME probably want to follow macro_rules macros here. - allow_internal_unstable, - allow_internal_unsafe: false, - edition, - }, + // FIXME procedural macros do not have proper span info + // yet, when they do, we should use it here. + def_site: None, + format: macro_bang_format(path), + // FIXME probably want to follow macro_rules macros here. + allow_internal_unstable, + allow_internal_unsafe: false, + edition, }); let tok_result = expandfun.expand(self.cx, span, mac.node.stream()); @@ -894,13 +886,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut expn_info = ExpnInfo { call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: false, - allow_internal_unsafe: false, - edition: ext.edition(), - } + def_site: None, + format: MacroAttribute(pretty_name), + allow_internal_unstable: false, + allow_internal_unsafe: false, + edition: ext.edition(), }; match *ext { @@ -916,7 +906,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Some(invoc.fragment_kind.expect_from_annotatables(items)) } BuiltinDerive(func) => { - expn_info.callee.allow_internal_unstable = true; + expn_info.allow_internal_unstable = true; invoc.expansion_data.mark.set_expn_info(expn_info); let span = span.with_ctxt(self.cx.backtrace()); let mut items = Vec::new(); diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index e9cd7adb9c1..66e8e0d7a9c 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -14,7 +14,7 @@ use std::cell::Cell; use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; -use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, hygiene, respan}; +use codemap::{ExpnInfo, MacroAttribute, dummy_spanned, hygiene, respan}; use ptr::P; use tokenstream::TokenStream; @@ -25,13 +25,11 @@ fn ignored_span(sp: Span) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("std_inject")), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - } + def_site: None, + format: MacroAttribute(Symbol::intern("std_inject")), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 77225585141..141fd122ff5 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -22,7 +22,7 @@ use std::vec; use attr::{self, HasAttrs}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; -use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned}; +use codemap::{self, CodeMap, ExpnInfo, MacroAttribute, dummy_spanned}; use errors; use config; use entry::{self, EntryPointType}; @@ -307,13 +307,11 @@ fn generate_test_harness(sess: &ParseSess, mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("test")), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - } + def_site: None, + format: MacroAttribute(Symbol::intern("test")), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); TestHarnessGenerator { diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 6ff385b18e8..e6a1434ca9d 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -157,11 +157,11 @@ fn call_intrinsic(cx: &ExtCtxt, intrinsic: &str, args: Vec<P<ast::Expr>>) -> P<ast::Expr> { - if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable { + if cx.current_expansion.mark.expn_info().unwrap().allow_internal_unstable { span = span.with_ctxt(cx.backtrace()); } else { // Avoid instability errors with user defined curstom derives, cc #36316 let mut info = cx.current_expansion.mark.expn_info().unwrap(); - info.callee.allow_internal_unstable = true; + info.allow_internal_unstable = true; let mark = Mark::fresh(Mark::root()); mark.set_expn_info(info); span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 3593165023a..ee343e47bd8 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -14,7 +14,7 @@ use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::attr; -use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, hygiene, respan}; +use syntax::codemap::{ExpnInfo, MacroAttribute, hygiene, respan}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; @@ -364,13 +364,11 @@ fn mk_registrar(cx: &mut ExtCtxt, let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("proc_macro")), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - edition: hygiene::default_edition(), - } + def_site: None, + format: MacroAttribute(Symbol::intern("proc_macro")), + allow_internal_unstable: true, + allow_internal_unsafe: false, + edition: hygiene::default_edition(), }); let span = DUMMY_SP.apply_mark(mark); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 5c35984dfd0..08b7f7c76cb 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -482,12 +482,11 @@ pub struct ExpnInfo { /// call_site span would have its own ExpnInfo, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// Information about the expansion. - pub callee: NameAndSpan -} - -#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct NameAndSpan { + /// The span of the macro definition itself. The macro may not + /// have a sensible definition span (e.g. something defined + /// completely inside libsyntax) in which case this is None. + /// This span serves only informational purpose and is not used for resolution. + pub def_site: Option<Span>, /// The format with which the macro was invoked. pub format: ExpnFormat, /// Whether the macro is allowed to use #[unstable]/feature-gated @@ -499,20 +498,6 @@ pub struct NameAndSpan { pub allow_internal_unsafe: bool, /// Edition of the crate in which the macro is defined. pub edition: Edition, - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g. something defined - /// completely inside libsyntax) in which case this is None. - pub span: Option<Span> -} - -impl NameAndSpan { - pub fn name(&self) -> Symbol { - match self.format { - ExpnFormat::MacroAttribute(s) | - ExpnFormat::MacroBang(s) => s, - ExpnFormat::CompilerDesugaring(ref kind) => kind.as_symbol(), - } - } } /// The source of expansion. @@ -526,8 +511,17 @@ pub enum ExpnFormat { CompilerDesugaring(CompilerDesugaringKind) } +impl ExpnFormat { + pub fn name(&self) -> Symbol { + match *self { + ExpnFormat::MacroBang(name) | ExpnFormat::MacroAttribute(name) => name, + ExpnFormat::CompilerDesugaring(kind) => kind.name(), + } + } +} + /// The kind of compiler desugaring. -#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { DotFill, QuestionMark, @@ -540,16 +534,14 @@ pub enum CompilerDesugaringKind { } impl CompilerDesugaringKind { - pub fn as_symbol(&self) -> Symbol { - use CompilerDesugaringKind::*; - let s = match *self { - Async => "async", - DotFill => "...", - QuestionMark => "?", - Catch => "do catch", - ExistentialReturnType => "existental type", - }; - Symbol::intern(s) + pub fn name(self) -> Symbol { + Symbol::intern(match self { + CompilerDesugaringKind::Async => "async", + CompilerDesugaringKind::DotFill => "...", + CompilerDesugaringKind::QuestionMark => "?", + CompilerDesugaringKind::Catch => "do catch", + CompilerDesugaringKind::ExistentialReturnType => "existental type", + }) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 17163576901..a4fb9571ecb 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -51,7 +51,7 @@ extern crate unicode_width; pub mod edition; pub mod hygiene; -pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind}; +pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, CompilerDesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -303,19 +303,19 @@ impl Span { /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().outer().expn_info().map_or_else(|| hygiene::default_edition(), - |einfo| einfo.callee.edition) + |einfo| einfo.edition) } /// Return the source callee. /// - /// Returns None if the supplied span has no expansion trace, - /// else returns the NameAndSpan for the macro definition + /// Returns `None` if the supplied span has no expansion trace, + /// else returns the `ExpnInfo` for the macro definition /// corresponding to the source callsite. - pub fn source_callee(self) -> Option<NameAndSpan> { - fn source_callee(info: ExpnInfo) -> NameAndSpan { + pub fn source_callee(self) -> Option<ExpnInfo> { + fn source_callee(info: ExpnInfo) -> ExpnInfo { match info.call_site.ctxt().outer().expn_info() { Some(info) => source_callee(info), - None => info.callee, + None => info, } } self.ctxt().outer().expn_info().map(source_callee) @@ -326,7 +326,7 @@ impl Span { /// `#[allow_internal_unstable]`). pub fn allows_unstable(&self) -> bool { match self.ctxt().outer().expn_info() { - Some(info) => info.callee.allow_internal_unstable, + Some(info) => info.allow_internal_unstable, None => false, } } @@ -334,7 +334,7 @@ impl Span { /// Check if this span arises from a compiler desugaring of kind `kind`. pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { match self.ctxt().outer().expn_info() { - Some(info) => match info.callee.format { + Some(info) => match info.format { ExpnFormat::CompilerDesugaring(k) => k == kind, _ => false, }, @@ -346,7 +346,7 @@ impl Span { /// if this span is not from a desugaring. pub fn compiler_desugaring_kind(&self) -> Option<CompilerDesugaringKind> { match self.ctxt().outer().expn_info() { - Some(info) => match info.callee.format { + Some(info) => match info.format { ExpnFormat::CompilerDesugaring(k) => Some(k), _ => None }, @@ -359,7 +359,7 @@ impl Span { // (that is, a macro marked with `#[allow_internal_unsafe]`). pub fn allows_unsafe(&self) -> bool { match self.ctxt().outer().expn_info() { - Some(info) => info.callee.allow_internal_unsafe, + Some(info) => info.allow_internal_unsafe, None => false, } } @@ -368,20 +368,17 @@ impl Span { let mut prev_span = DUMMY_SP; let mut result = vec![]; while let Some(info) = self.ctxt().outer().expn_info() { - let (pre, post) = match info.callee.format { - ExpnFormat::MacroAttribute(..) => ("#[", "]"), - ExpnFormat::MacroBang(..) => ("", "!"), - ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), - }; - let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post); - let def_site_span = info.callee.span; - // Don't print recursive invocations if !info.call_site.source_equal(&prev_span) { + let (pre, post) = match info.format { + ExpnFormat::MacroAttribute(..) => ("#[", "]"), + ExpnFormat::MacroBang(..) => ("", "!"), + ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + }; result.push(MacroBacktrace { call_site: info.call_site, - macro_decl_name, - def_site_span, + macro_decl_name: format!("{}{}{}", pre, info.format.name(), post), + def_site_span: info.def_site, }); }