From 0d29142aad9554a23f0881be95110ad96365bfcf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 14 Aug 2019 01:59:14 +0300 Subject: [PATCH 1/2] expand: `expand_fragment` -> `fully_expand_fragment` --- src/libsyntax/ext/expand.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9a3195b1165b1..21cf232ecc34a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -118,13 +118,13 @@ macro_rules! ast_fragments { impl<'a, 'b> MutVisitor for MacroExpander<'a, 'b> { fn filter_map_expr(&mut self, expr: P) -> Option> { - self.expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr() + self.fully_expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr() } $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) { - visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast()); + visit_clobber(ast, |ast| self.fully_expand_fragment(AstFragment::$Kind(ast)).$make_ast()); })?)* $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { - self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast() + self.fully_expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast() })?)* } @@ -265,7 +265,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { tokens: None, })]); - match self.expand_fragment(krate_item).make_items().pop().map(P::into_inner) { + match self.fully_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; @@ -285,8 +285,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate } - // Fully expand all macro invocations in this AST fragment. - fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { + // Recursively expand all macro invocations in this AST fragment. + fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; From d416ebeb6ee265c980778df9bc4d84dc4a7b8580 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 14 Aug 2019 02:30:09 +0300 Subject: [PATCH 2/2] expand: Unimplement `MutVisitor` on `MacroExpander` Each call to `fully_expand_fragment` is something unique, interesting, and requiring attention. It represents a "root" of expansion and its use means that something unusual is happening, like eager expansion or expansion performed outside of the primary expansion pass. So, it shouldn't be hide under a generic visitor call. Also, from all the implemented visitor methods only two were actually used. --- src/libsyntax/ext/base.rs | 14 +++++++++---- src/libsyntax/ext/expand.rs | 14 +------------ src/libsyntax_ext/proc_macro_harness.rs | 9 +++++---- src/libsyntax_ext/test_harness.rs | 27 ++++++++++++++----------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7f4feff6be670..532de05eea214 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -947,8 +947,10 @@ pub fn expr_to_spanned_string<'a>( // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. expr.span = expr.span.apply_mark(cx.current_expansion.id); - // we want to be able to handle e.g., `concat!("foo", "bar")` - cx.expander().visit_expr(&mut expr); + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + Err(match expr.node { ast::ExprKind::Lit(ref l) => match l.node { ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), @@ -1013,8 +1015,12 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { - let mut expr = panictry!(p.parse_expr()); - cx.expander().visit_expr(&mut expr); + let expr = panictry!(p.parse_expr()); + + // Perform eager expansion on the expression. + // We want to be able to handle e.g., `concat!("foo", "bar")`. + let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); + es.push(expr); if p.eat(&token::Comma) { continue; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 21cf232ecc34a..402b42dfbc80d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -116,18 +116,6 @@ macro_rules! ast_fragments { } } - impl<'a, 'b> MutVisitor for MacroExpander<'a, 'b> { - fn filter_map_expr(&mut self, expr: P) -> Option> { - self.fully_expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr() - } - $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) { - visit_clobber(ast, |ast| self.fully_expand_fragment(AstFragment::$Kind(ast)).$make_ast()); - })?)* - $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { - self.fully_expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast() - })?)* - } - impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> { $(fn $make_ast(self: Box>) -> Option<$AstTy> { @@ -286,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } // Recursively expand all macro invocations in this AST fragment. - fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { + pub fn fully_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_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 7913a7442edc7..70325539f301f 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -1,18 +1,17 @@ use std::mem; +use smallvec::smallvec; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::source_map::{ExpnInfo, ExpnKind, respan}; use syntax::ext::base::{ExtCtxt, MacroKind}; -use syntax::ext::expand::ExpansionConfig; +use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::hygiene::ExpnId; use syntax::ext::proc_macro::is_proc_macro_attr; -use syntax::mut_visit::MutVisitor; use syntax::parse::ParseSess; use syntax::ptr::P; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; - use syntax_pos::{Span, DUMMY_SP}; struct ProcMacroDerive { @@ -409,5 +408,7 @@ fn mk_decls( i }); - cx.monotonic_expander().flat_map_item(module).pop().unwrap() + // Integrate the new module into existing module structures. + let module = AstFragment::Items(smallvec![module]); + cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap() } diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index eec8a3f802343..0267637e54062 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -6,7 +6,7 @@ use syntax::ast::{self, Ident}; use syntax::attr; use syntax::entry::{self, EntryPointType}; use syntax::ext::base::{ExtCtxt, Resolver}; -use syntax::ext::expand::ExpansionConfig; +use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::hygiene::{ExpnId, MacroKind}; use syntax::feature_gate::Features; use syntax::mut_visit::{*, ExpectOne}; @@ -74,12 +74,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { noop_visit_crate(c, self); // Create a main function to run our tests - let test_main = { - let unresolved = mk_main(&mut self.cx); - self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap() - }; - - c.module.items.push(test_main); + c.module.items.push(mk_main(&mut self.cx)); } fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { @@ -216,7 +211,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>, let name = Ident::from_str("__test_reexports").gensym(); let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent }; cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent); - let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item { + let module = P(ast::Item { ident: name, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, @@ -224,9 +219,14 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>, vis: dummy_spanned(ast::VisibilityKind::Public), span: DUMMY_SP, tokens: None, - })).pop().unwrap(); + }); - (it, name) + // Integrate the new module into existing module structures. + let module = AstFragment::Items(smallvec![module]); + let module = + cx.ext_cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap(); + + (module, name) } /// Crawl over the crate, inserting test reexports and the test main function @@ -321,7 +321,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { None => Ident::from_str_and_span("main", sp).gensym(), }; - P(ast::Item { + let main = P(ast::Item { ident: main_id, attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, @@ -329,8 +329,11 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { vis: dummy_spanned(ast::VisibilityKind::Public), span: sp, tokens: None, - }) + }); + // Integrate the new item into existing module structures. + let main = AstFragment::Items(smallvec![main]); + cx.ext_cx.monotonic_expander().fully_expand_fragment(main).make_items().pop().unwrap() } fn path_name_i(idents: &[Ident]) -> String {