Skip to content

Commit 0701571

Browse files
committed
Implement macro_rules! placeholders and the macro scope map
1 parent a15dfca commit 0701571

File tree

5 files changed

+127
-24
lines changed

5 files changed

+127
-24
lines changed

src/librustc_resolve/assign_ids.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,27 @@
1111
use Resolver;
1212
use rustc::session::Session;
1313
use syntax::ast;
14-
use syntax::fold::Folder;
14+
use syntax::ext::mtwt;
15+
use syntax::fold::{self, Folder};
1516
use syntax::ptr::P;
1617
use syntax::util::move_map::MoveMap;
18+
use syntax::util::small_vector::SmallVector;
19+
20+
use std::collections::HashMap;
21+
use std::mem;
1722

1823
impl<'a> Resolver<'a> {
1924
pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate {
2025
NodeIdAssigner {
2126
sess: self.session,
27+
macros_at_scope: &mut self.macros_at_scope,
2228
}.fold_crate(krate)
2329
}
2430
}
2531

2632
struct NodeIdAssigner<'a> {
2733
sess: &'a Session,
34+
macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<ast::Mrk>>,
2835
}
2936

3037
impl<'a> Folder for NodeIdAssigner<'a> {
@@ -38,22 +45,48 @@ impl<'a> Folder for NodeIdAssigner<'a> {
3845
block.id = self.new_id(block.id);
3946

4047
let stmt = block.stmts.pop();
41-
block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter());
42-
if let Some(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt {
48+
let mut macros = Vec::new();
49+
block.stmts = block.stmts.move_flat_map(|stmt| {
50+
if let ast::StmtKind::Item(ref item) = stmt.node {
51+
if let ast::ItemKind::Mac(..) = item.node {
52+
macros.push(mtwt::outer_mark(item.ident.ctxt));
53+
return None;
54+
}
55+
}
56+
57+
let stmt = self.fold_stmt(stmt).pop().unwrap();
58+
if !macros.is_empty() {
59+
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
60+
}
61+
Some(stmt)
62+
});
63+
64+
stmt.and_then(|mut stmt| {
4365
// Avoid wasting a node id on a trailing expression statement,
4466
// which shares a HIR node with the expression itself.
45-
let expr = self.fold_expr(expr);
46-
block.stmts.push(ast::Stmt {
47-
id: expr.id,
48-
node: ast::StmtKind::Expr(expr),
49-
span: span,
50-
});
51-
} else if let Some(stmt) = stmt {
52-
block.stmts.extend(self.fold_stmt(stmt));
53-
}
67+
if let ast::StmtKind::Expr(expr) = stmt.node {
68+
let expr = self.fold_expr(expr);
69+
stmt.id = expr.id;
70+
stmt.node = ast::StmtKind::Expr(expr);
71+
Some(stmt)
72+
} else {
73+
self.fold_stmt(stmt).pop()
74+
}
75+
}).map(|stmt| {
76+
if !macros.is_empty() {
77+
self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
78+
}
79+
block.stmts.push(stmt);
80+
});
5481

5582
block
5683
})
5784
}
58-
}
5985

86+
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
87+
match item.node {
88+
ast::ItemKind::Mac(..) => SmallVector::zero(),
89+
_ => fold::noop_fold_item(item, self),
90+
}
91+
}
92+
}

src/librustc_resolve/lib.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace};
5353
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
5454
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
5555

56+
use syntax::ext::mtwt;
5657
use syntax::ast::{self, FloatTy};
5758
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
5859
use syntax::parse::token::{self, keywords};
@@ -651,6 +652,9 @@ enum RibKind<'a> {
651652

652653
// We passed through a module.
653654
ModuleRibKind(Module<'a>),
655+
656+
// We passed through a `macro_rules!` statement with the given expansion
657+
MacroDefinition(ast::Mrk),
654658
}
655659

656660
#[derive(Copy, Clone)]
@@ -927,6 +931,10 @@ pub struct Resolver<'a> {
927931

928932
pub definitions: Definitions,
929933

934+
// Maps the node id of a statement to the expansions of the `macro_rules!`s
935+
// immediately above the statement (if appropriate).
936+
macros_at_scope: HashMap<NodeId, Vec<ast::Mrk>>,
937+
930938
graph_root: Module<'a>,
931939

932940
prelude: Option<Module<'a>>,
@@ -1113,6 +1121,7 @@ impl<'a> Resolver<'a> {
11131121
session: session,
11141122

11151123
definitions: Definitions::new(),
1124+
macros_at_scope: HashMap::new(),
11161125

11171126
// The outermost module has def ID 0; this is not reflected in the
11181127
// AST.
@@ -1421,6 +1430,16 @@ impl<'a> Resolver<'a> {
14211430
};
14221431
}
14231432
}
1433+
1434+
if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind {
1435+
// If an invocation of this macro created `ident`, give up on `ident`
1436+
// and switch to `ident`'s source from the macro definition.
1437+
if let Some((source_ident, source_macro)) = mtwt::source(ident) {
1438+
if mac == source_macro {
1439+
ident = source_ident;
1440+
}
1441+
}
1442+
}
14241443
}
14251444

14261445
None
@@ -2069,6 +2088,7 @@ impl<'a> Resolver<'a> {
20692088
let orig_module = self.current_module;
20702089
let anonymous_module = self.module_map.get(&block.id).cloned(); // clones a reference
20712090

2091+
let mut num_value_ribs = 1;
20722092
if let Some(anonymous_module) = anonymous_module {
20732093
debug!("(resolving block) found anonymous module, moving down");
20742094
self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
@@ -2079,11 +2099,22 @@ impl<'a> Resolver<'a> {
20792099
}
20802100

20812101
// Descend into the block.
2082-
visit::walk_block(self, block);
2102+
for stmt in &block.stmts {
2103+
if let Some(marks) = self.macros_at_scope.remove(&stmt.id) {
2104+
num_value_ribs += marks.len() as u32;
2105+
for mark in marks {
2106+
self.value_ribs.push(Rib::new(MacroDefinition(mark)));
2107+
}
2108+
}
2109+
2110+
self.visit_stmt(stmt);
2111+
}
20832112

20842113
// Move back up.
20852114
self.current_module = orig_module;
2086-
self.value_ribs.pop();
2115+
for _ in 0 .. num_value_ribs {
2116+
self.value_ribs.pop();
2117+
}
20872118
if let Some(_) = anonymous_module {
20882119
self.type_ribs.pop();
20892120
}
@@ -2497,7 +2528,7 @@ impl<'a> Resolver<'a> {
24972528
Def::Local(_, node_id) => {
24982529
for rib in ribs {
24992530
match rib.kind {
2500-
NormalRibKind | ModuleRibKind(..) => {
2531+
NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
25012532
// Nothing to do. Continue.
25022533
}
25032534
ClosureRibKind(function_id) => {
@@ -2546,7 +2577,7 @@ impl<'a> Resolver<'a> {
25462577
for rib in ribs {
25472578
match rib.kind {
25482579
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
2549-
ModuleRibKind(..) => {
2580+
ModuleRibKind(..) | MacroDefinition(..) => {
25502581
// Nothing to do. Continue.
25512582
}
25522583
ItemRibKind => {

src/libsyntax/ext/expand.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use attr::HasAttrs;
1515
use ext::mtwt;
1616
use attr;
1717
use attr::AttrMetaMethods;
18-
use codemap::{Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
18+
use codemap::{dummy_spanned, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
1919
use syntax_pos::{self, Span, ExpnId};
2020
use config::StripUnconfigured;
2121
use ext::base::*;
@@ -105,6 +105,23 @@ pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
105105
}
106106
}
107107

108+
struct MacroScopePlaceholder;
109+
impl MacResult for MacroScopePlaceholder {
110+
fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
111+
Some(SmallVector::one(P(ast::Item {
112+
ident: keywords::Invalid.ident(),
113+
attrs: Vec::new(),
114+
id: ast::DUMMY_NODE_ID,
115+
node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
116+
path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
117+
tts: Vec::new(),
118+
})),
119+
vis: ast::Visibility::Inherited,
120+
span: syntax_pos::DUMMY_SP,
121+
})))
122+
}
123+
}
124+
108125
/// Expand a macro invocation. Returns the result of expansion.
109126
fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attribute>, span: Span,
110127
fld: &mut MacroExpander) -> T
@@ -143,6 +160,7 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
143160
};
144161

145162
let ident = ident.unwrap_or(keywords::Invalid.ident());
163+
let marked_tts = mark_tts(&tts, mark);
146164
match *extension {
147165
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
148166
if ident.name != keywords::Invalid.name() {
@@ -161,7 +179,6 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
161179
},
162180
});
163181

164-
let marked_tts = mark_tts(&tts, mark);
165182
Some(expandfun.expand(fld.cx, call_site, &marked_tts))
166183
}
167184

@@ -181,7 +198,6 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
181198
}
182199
});
183200

184-
let marked_tts = mark_tts(&tts, mark);
185201
Some(expander.expand(fld.cx, call_site, ident, marked_tts))
186202
}
187203

@@ -210,15 +226,14 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
210226
span: call_site,
211227
imported_from: None,
212228
use_locally: true,
213-
body: tts,
229+
body: marked_tts,
214230
export: attr::contains_name(&attrs, "macro_export"),
215231
allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
216232
attrs: attrs,
217233
});
218234

219235
// macro_rules! has a side effect but expands to nothing.
220-
fld.cx.bt_pop();
221-
None
236+
Some(Box::new(MacroScopePlaceholder))
222237
}
223238

224239
MultiDecorator(..) | MultiModifier(..) => {
@@ -343,6 +358,12 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
343358
match a {
344359
Annotatable::Item(it) => match it.node {
345360
ast::ItemKind::Mac(..) => {
361+
if match it.node {
362+
ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
363+
_ => unreachable!(),
364+
} {
365+
return SmallVector::one(Annotatable::Item(it));
366+
}
346367
it.and_then(|it| match it.node {
347368
ItemKind::Mac(mac) =>
348369
expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),

src/libsyntax/ext/mtwt.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
1818
pub use self::SyntaxContext_::*;
1919

20-
use ast::{Mrk, SyntaxContext};
20+
use ast::{Ident, Mrk, SyntaxContext};
2121

2222
use std::cell::RefCell;
2323
use std::collections::HashMap;
@@ -112,6 +112,20 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
112112
})
113113
}
114114

115+
/// If `ident` is macro expanded, return the source ident from the macro definition
116+
/// and the mark of the expansion that created the macro definition.
117+
pub fn source(ident: Ident) -> Option<(Ident /* source ident */, Mrk /* source macro */)> {
118+
with_sctable(|sctable| {
119+
let ctxts = sctable.table.borrow();
120+
if let Mark(_expansion_mark, macro_ctxt) = ctxts[ident.ctxt.0 as usize] {
121+
if let Mark(definition_mark, orig_ctxt) = ctxts[macro_ctxt.0 as usize] {
122+
return Some((Ident::new(ident.name, orig_ctxt), definition_mark));
123+
}
124+
}
125+
None
126+
})
127+
}
128+
115129
#[cfg(test)]
116130
mod tests {
117131
use ast::{EMPTY_CTXT, Ident, Mrk, Name, SyntaxContext};

src/libsyntax/test.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
185185

186186
mod_folded
187187
}
188+
189+
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
188190
}
189191

190192
struct EntryPointCleaner {
@@ -234,6 +236,8 @@ impl fold::Folder for EntryPointCleaner {
234236

235237
SmallVector::one(folded)
236238
}
239+
240+
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
237241
}
238242

239243
fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,

0 commit comments

Comments
 (0)