Skip to content

Commit dc5ce0a

Browse files
committed
auto merge of #14298 : kmcallister/rust/pattern-macros, r=huonw
First commit is an unrelated fix for a test suite warning I introduced last week.
2 parents e865415 + fd40d0c commit dc5ce0a

File tree

20 files changed

+283
-14
lines changed

20 files changed

+283
-14
lines changed

src/libcore/cell.rs

+1
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ mod test {
482482
}
483483

484484
#[test]
485+
#[allow(experimental)]
485486
fn clone_ref_updates_flag() {
486487
let x = RefCell::new(0);
487488
{

src/librustc/middle/cfg/construct.rs

+4
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ impl<'a> CFGBuilder<'a> {
142142
self.pats_all(post.iter().map(|p| *p), vec_exit);
143143
self.add_node(pat.id, [post_exit])
144144
}
145+
146+
ast::PatMac(_) => {
147+
self.tcx.sess.span_bug(pat.span, "unexpanded macro");
148+
}
145149
}
146150
}
147151

src/librustc/middle/check_match.rs

+6
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ fn pat_ctor_id(cx: &MatchCheckCtxt, p: @Pat) -> Option<ctor> {
392392
None => Some(vec(before.len() + after.len()))
393393
}
394394
}
395+
PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
395396
}
396397
}
397398

@@ -849,6 +850,10 @@ fn specialize(cx: &MatchCheckCtxt,
849850
_ => None
850851
}
851852
}
853+
PatMac(_) => {
854+
cx.tcx.sess.span_err(pat_span, "unexpanded macro");
855+
None
856+
}
852857
}
853858
}
854859
}
@@ -947,6 +952,7 @@ fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec<Span>) {
947952
}
948953
PatEnum(_,_) => {}
949954
PatVec(..) => { this_pattern!() }
955+
PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
950956
}
951957
}
952958

src/librustc/middle/mem_categorization.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
10881088
ast::PatLit(_) | ast::PatRange(_, _) => {
10891089
/*always ok*/
10901090
}
1091+
1092+
ast::PatMac(_) => {
1093+
self.tcx().sess.span_bug(pat.span, "unexpanded macro");
1094+
}
10911095
}
10921096

10931097
Ok(())

src/librustc/middle/trans/_match.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,9 @@ fn bind_irrefutable_pat<'a>(
22822282
bcx.sess().span_bug(pat.span,
22832283
"vector patterns are never irrefutable!");
22842284
}
2285+
ast::PatMac(..) => {
2286+
bcx.sess().span_bug(pat.span, "unexpanded macro");
2287+
}
22852288
ast::PatWild | ast::PatWildMulti | ast::PatLit(_) | ast::PatRange(_, _) => ()
22862289
}
22872290
return bcx;

src/librustc/middle/trans/debuginfo.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,11 @@ fn populate_scope_map(cx: &CrateContext,
26642664
walk_pattern(cx, sub_pat, scope_stack, scope_map);
26652665
}
26662666
}
2667+
2668+
ast::PatMac(_) => {
2669+
cx.sess().span_bug(pat.span, "debuginfo::populate_scope_map() - \
2670+
Found unexpanded macro.");
2671+
}
26672672
}
26682673
}
26692674

src/librustc/middle/typeck/check/_match.rs

+2
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
722722
}
723723
fcx.write_ty(pat.id, expected);
724724
}
725+
726+
ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
725727
}
726728
}
727729

src/librustdoc/clean/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,12 @@ fn name_from_pat(p: &ast::Pat) -> String {
17311731
PatRange(..) => fail!("tried to get argument name from PatRange, \
17321732
which is not allowed in function arguments"),
17331733
PatVec(..) => fail!("tried to get argument name from pat_vec, \
1734-
which is not allowed in function arguments")
1734+
which is not allowed in function arguments"),
1735+
PatMac(..) => {
1736+
warn!("can't document the name of a function argument \
1737+
produced by a pattern macro");
1738+
"(argument produced by macro)".to_string()
1739+
}
17351740
}
17361741
}
17371742

src/libsyntax/ast.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ pub enum Pat_ {
353353
PatRange(@Expr, @Expr),
354354
// [a, b, ..i, y, z] is represented as
355355
// PatVec(~[a, b], Some(i), ~[y, z])
356-
PatVec(Vec<@Pat> , Option<@Pat>, Vec<@Pat> )
356+
PatVec(Vec<@Pat> , Option<@Pat>, Vec<@Pat> ),
357+
PatMac(Mac),
357358
}
358359

359360
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash, Show)]

src/libsyntax/ast_util.rs

+1
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ pub fn walk_pat(pat: &Pat, it: |&Pat| -> bool) -> bool {
665665
slice.iter().advance(|&p| walk_pat(p, |p| it(p))) &&
666666
after.iter().advance(|&p| walk_pat(p, |p| it(p)))
667667
}
668+
PatMac(_) => fail!("attempted to analyze unexpanded pattern"),
668669
PatWild | PatWildMulti | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
669670
PatEnum(_, _) => {
670671
true

src/libsyntax/ext/base.rs

+30
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ pub trait MacResult {
114114
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
115115
None
116116
}
117+
/// Create a pattern.
118+
fn make_pat(&self) -> Option<@ast::Pat> {
119+
None
120+
}
117121

118122
/// Create a statement.
119123
///
@@ -139,6 +143,20 @@ impl MacResult for MacExpr {
139143
Some(self.e)
140144
}
141145
}
146+
/// A convenience type for macros that return a single pattern.
147+
pub struct MacPat {
148+
p: @ast::Pat
149+
}
150+
impl MacPat {
151+
pub fn new(p: @ast::Pat) -> Box<MacResult> {
152+
box MacPat { p: p } as Box<MacResult>
153+
}
154+
}
155+
impl MacResult for MacPat {
156+
fn make_pat(&self) -> Option<@ast::Pat> {
157+
Some(self.p)
158+
}
159+
}
142160
/// A convenience type for macros that return a single item.
143161
pub struct MacItem {
144162
i: @ast::Item
@@ -194,12 +212,24 @@ impl DummyResult {
194212
span: sp,
195213
}
196214
}
215+
216+
/// A plain dummy pattern.
217+
pub fn raw_pat(sp: Span) -> @ast::Pat {
218+
@ast::Pat {
219+
id: ast::DUMMY_NODE_ID,
220+
node: ast::PatWild,
221+
span: sp,
222+
}
223+
}
197224
}
198225

199226
impl MacResult for DummyResult {
200227
fn make_expr(&self) -> Option<@ast::Expr> {
201228
Some(DummyResult::raw_expr(self.span))
202229
}
230+
fn make_pat(&self) -> Option<@ast::Pat> {
231+
Some(DummyResult::raw_pat(self.span))
232+
}
203233
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
204234
if self.expr_only {
205235
None

src/libsyntax/ext/expand.rs

+90-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use ast::{P, Block, Crate, DeclLocal, ExprMac};
11+
use ast::{P, Block, Crate, DeclLocal, ExprMac, PatMac};
1212
use ast::{Local, Ident, MacInvocTT};
1313
use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
1414
use ast::TokenTree;
@@ -92,8 +92,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
9292
None => {
9393
fld.cx.span_err(
9494
pth.span,
95-
format!("non-expr macro in expr pos: \
96-
{}",
95+
format!("non-expression macro in expression position: {}",
9796
extnamestr.get().as_slice()
9897
).as_slice());
9998
return DummyResult::raw_expr(e.span);
@@ -487,7 +486,7 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander)
487486
}
488487
None => {
489488
fld.cx.span_err(pth.span,
490-
format!("expr macro in item position: {}",
489+
format!("non-item macro in item position: {}",
491490
extnamestr.get()).as_slice());
492491
return SmallVector::zero();
493492
}
@@ -639,7 +638,7 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> {
639638
Some(stmt) => stmt,
640639
None => {
641640
fld.cx.span_err(pth.span,
642-
format!("non-stmt macro in stmt pos: {}",
641+
format!("non-statement macro in statement position: {}",
643642
extnamestr).as_slice());
644643
return SmallVector::zero();
645644
}
@@ -842,6 +841,83 @@ pub fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
842841
})
843842
}
844843

844+
pub fn expand_pat(p: @ast::Pat, fld: &mut MacroExpander) -> @ast::Pat {
845+
let (pth, tts) = match p.node {
846+
PatMac(ref mac) => {
847+
match mac.node {
848+
MacInvocTT(ref pth, ref tts, _) => {
849+
(pth, (*tts).clone())
850+
}
851+
}
852+
}
853+
_ => return noop_fold_pat(p, fld),
854+
};
855+
if pth.segments.len() > 1u {
856+
fld.cx.span_err(pth.span, "expected macro name without module separators");
857+
return DummyResult::raw_pat(p.span);
858+
}
859+
let extname = pth.segments.get(0).identifier;
860+
let extnamestr = token::get_ident(extname);
861+
let marked_after = match fld.extsbox.find(&extname.name) {
862+
None => {
863+
fld.cx.span_err(pth.span,
864+
format!("macro undefined: '{}!'",
865+
extnamestr).as_slice());
866+
// let compilation continue
867+
return DummyResult::raw_pat(p.span);
868+
}
869+
870+
Some(&NormalTT(ref expander, span)) => {
871+
fld.cx.bt_push(ExpnInfo {
872+
call_site: p.span,
873+
callee: NameAndSpan {
874+
name: extnamestr.get().to_string(),
875+
format: MacroBang,
876+
span: span
877+
}
878+
});
879+
880+
let fm = fresh_mark();
881+
let marked_before = mark_tts(tts.as_slice(), fm);
882+
let mac_span = original_span(fld.cx);
883+
let expanded = match expander.expand(fld.cx,
884+
mac_span.call_site,
885+
marked_before.as_slice()).make_pat() {
886+
Some(e) => e,
887+
None => {
888+
fld.cx.span_err(
889+
pth.span,
890+
format!(
891+
"non-pattern macro in pattern position: {}",
892+
extnamestr.get()
893+
).as_slice()
894+
);
895+
return DummyResult::raw_pat(p.span);
896+
}
897+
};
898+
899+
// mark after:
900+
mark_pat(expanded,fm)
901+
}
902+
_ => {
903+
fld.cx.span_err(p.span,
904+
format!("{}! is not legal in pattern position",
905+
extnamestr.get()).as_slice());
906+
return DummyResult::raw_pat(p.span);
907+
}
908+
};
909+
910+
let fully_expanded =
911+
fld.fold_pat(marked_after).node.clone();
912+
fld.cx.bt_pop();
913+
914+
@ast::Pat {
915+
id: ast::DUMMY_NODE_ID,
916+
node: fully_expanded,
917+
span: p.span,
918+
}
919+
}
920+
845921
pub struct IdentRenamer<'a> {
846922
renames: &'a mut RenameList,
847923
}
@@ -885,6 +961,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
885961
expand_expr(expr, self)
886962
}
887963

964+
fn fold_pat(&mut self, pat: @ast::Pat) -> @ast::Pat {
965+
expand_pat(pat, self)
966+
}
967+
888968
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
889969
expand_item(item, self)
890970
}
@@ -974,6 +1054,11 @@ fn mark_expr(expr: @ast::Expr, m: Mrk) -> @ast::Expr {
9741054
new_mark_folder(m).fold_expr(expr)
9751055
}
9761056

1057+
// apply a given mark to the given pattern. Used following the expansion of a macro.
1058+
fn mark_pat(pat: @ast::Pat, m: Mrk) -> @ast::Pat {
1059+
new_mark_folder(m).fold_pat(pat)
1060+
}
1061+
9771062
// apply a given mark to the given stmt. Used following the expansion of a macro.
9781063
fn mark_stmt(expr: &ast::Stmt, m: Mrk) -> @ast::Stmt {
9791064
new_mark_folder(m).fold_stmt(expr)

src/libsyntax/ext/tt/macro_rules.rs

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
6363
self.ensure_complete_parse(true);
6464
Some(ret)
6565
}
66+
fn make_pat(&self) -> Option<@ast::Pat> {
67+
let ret = self.parser.borrow_mut().parse_pat();
68+
self.ensure_complete_parse(false);
69+
Some(ret)
70+
}
6671
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
6772
let mut ret = SmallVector::zero();
6873
loop {

src/libsyntax/fold.rs

+1
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ pub fn noop_fold_pat<T: Folder>(p: @Pat, folder: &mut T) -> @Pat {
770770
slice.map(|x| folder.fold_pat(x)),
771771
after.iter().map(|x| folder.fold_pat(*x)).collect())
772772
}
773+
PatMac(ref mac) => PatMac(folder.fold_mac(mac)),
773774
};
774775

775776
@Pat {

src/libsyntax/parse/parser.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -2911,15 +2911,28 @@ impl<'a> Parser<'a> {
29112911
pat = PatRange(start, end);
29122912
} else if is_plain_ident(&self.token) && !can_be_enum_or_struct {
29132913
let name = self.parse_path(NoTypesAllowed).path;
2914-
let sub;
2915-
if self.eat(&token::AT) {
2916-
// parse foo @ pat
2917-
sub = Some(self.parse_pat());
2914+
if self.eat(&token::NOT) {
2915+
// macro invocation
2916+
let ket = token::close_delimiter_for(&self.token)
2917+
.unwrap_or_else(|| self.fatal("expected open delimiter"));
2918+
self.bump();
2919+
2920+
let tts = self.parse_seq_to_end(&ket,
2921+
seq_sep_none(),
2922+
|p| p.parse_token_tree());
2923+
2924+
let mac = MacInvocTT(name, tts, EMPTY_CTXT);
2925+
pat = ast::PatMac(codemap::Spanned {node: mac, span: self.span});
29182926
} else {
2919-
// or just foo
2920-
sub = None;
2927+
let sub = if self.eat(&token::AT) {
2928+
// parse foo @ pat
2929+
Some(self.parse_pat())
2930+
} else {
2931+
// or just foo
2932+
None
2933+
};
2934+
pat = PatIdent(BindByValue(MutImmutable), name, sub);
29212935
}
2922-
pat = PatIdent(BindByValue(MutImmutable), name, sub);
29232936
} else {
29242937
// parse an enum pat
29252938
let enum_path = self.parse_path(LifetimeAndTypesWithColons)

src/libsyntax/print/pprust.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,7 @@ impl<'a> State<'a> {
17571757
|s, &p| s.print_pat(p)));
17581758
try!(word(&mut self.s, "]"));
17591759
}
1760+
ast::PatMac(ref m) => try!(self.print_mac(m)),
17601761
}
17611762
self.ann.post(self, NodePat(pat))
17621763
}

src/libsyntax/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ pub fn walk_pat<E: Clone, V: Visitor<E>>(visitor: &mut V, pattern: &Pat, env: E)
457457
visitor.visit_pat(*postpattern, env.clone())
458458
}
459459
}
460+
PatMac(ref macro) => visitor.visit_mac(macro, env),
460461
}
461462
}
462463

0 commit comments

Comments
 (0)