expand.rs 71.4 KB
Newer Older
S
Steven Fackler 已提交
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
12
use ast::{Local, Ident, Mac_, Name};
13 14
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi};
15
use ast::TokenTree;
16
use ast;
17
use ext::mtwt;
18
use ext::build::AstBuilder;
19
use attr;
20
use attr::{AttrMetaMethods, WithAttrs};
21
use codemap;
22
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
P
Patrick Walton 已提交
23
use ext::base::*;
24
use feature_gate::{self, Features};
J
John Clements 已提交
25
use fold;
26
use fold::*;
M
Marvin Löbel 已提交
27
use util::move_map::MoveMap;
28
use parse;
29
use parse::token::{fresh_mark, fresh_name, intern};
30 31
use ptr::P;
use util::small_vector::SmallVector;
J
John Clements 已提交
32
use visit;
H
Huon Wilson 已提交
33
use visit::Visitor;
34
use std_inject;
35

36 37
use std::collections::HashSet;

38

39
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
40
    let expr_span = e.span;
41
    return e.and_then(|ast::Expr {id, node, span, attrs}| match node {
42

43 44
        // expr_mac should really be expr_ext or something; it's the
        // entry-point for all syntax extensions.
45
        ast::ExprMac(mac) => {
46

47
            // Assert that we drop any macro attributes on the floor here
48
            drop(attrs);
49

50 51 52
            let expanded_expr = match expand_mac_invoc(mac, span,
                                                       |r| r.make_expr(),
                                                       mark_expr, fld) {
J
John Clements 已提交
53 54
                Some(expr) => expr,
                None => {
55
                    return DummyResult::raw_expr(span);
J
John Clements 已提交
56 57
                }
            };
58

J
John Clements 已提交
59
            // Keep going, outside-in.
60
            let fully_expanded = fld.fold_expr(expanded_expr);
N
Nick Cameron 已提交
61
            let span = fld.new_span(span);
J
John Clements 已提交
62
            fld.cx.bt_pop();
63

64
            fully_expanded.map(|e| ast::Expr {
J
John Clements 已提交
65
                id: ast::DUMMY_NODE_ID,
66
                node: e.node,
67
                span: span,
68
                attrs: e.attrs,
69
            })
70
        }
71

72
        ast::ExprInPlace(placer, value_expr) => {
73 74 75 76 77 78
            // Ensure feature-gate is enabled
            feature_gate::check_for_placement_in(
                fld.cx.ecfg.features,
                &fld.cx.parse_sess.span_diagnostic,
                expr_span);

79
            let placer = fld.fold_expr(placer);
80
            let value_expr = fld.fold_expr(value_expr);
N
Nick Cameron 已提交
81
            fld.cx.expr(span, ast::ExprInPlace(placer, value_expr))
82
                .with_attrs(fold_thin_attrs(attrs, fld))
83 84
        }

P
Pythoner6 已提交
85 86 87
        ast::ExprWhile(cond, body, opt_ident) => {
            let cond = fld.fold_expr(cond);
            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
88
            fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
89
                .with_attrs(fold_thin_attrs(attrs, fld))
P
Pythoner6 已提交
90 91
        }

J
John Gallagher 已提交
92
        ast::ExprWhileLet(pat, expr, body, opt_ident) => {
N
Nick Cameron 已提交
93 94
            let pat = fld.fold_pat(pat);
            let expr = fld.fold_expr(expr);
95 96 97 98 99 100 101 102 103 104 105 106

            // Hygienic renaming of the body.
            let ((body, opt_ident), mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                (body, opt_ident),
                                |rename_fld, fld, (body, opt_ident)| {
                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
            });
            assert!(rewritten_pats.len() == 1);

            fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident))
107
                .with_attrs(fold_thin_attrs(attrs, fld))
108 109
        }

E
Edward Wang 已提交
110
        ast::ExprLoop(loop_block, opt_ident) => {
111
            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
112
            fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
113
                .with_attrs(fold_thin_attrs(attrs, fld))
E
Edward Wang 已提交
114 115
        }

116
        ast::ExprForLoop(pat, head, body, opt_ident) => {
117
            let pat = fld.fold_pat(pat);
118 119 120 121 122 123 124 125 126 127 128

            // Hygienic renaming of the for loop body (for loop binds its pattern).
            let ((body, opt_ident), mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                (body, opt_ident),
                                |rename_fld, fld, (body, opt_ident)| {
                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
            });
            assert!(rewritten_pats.len() == 1);

129
            let head = fld.fold_expr(head);
130
            fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident))
131
                .with_attrs(fold_thin_attrs(attrs, fld))
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
        }

        ast::ExprIfLet(pat, sub_expr, body, else_opt) => {
            let pat = fld.fold_pat(pat);

            // Hygienic renaming of the body.
            let (body, mut rewritten_pats) =
                rename_in_scope(vec![pat],
                                fld,
                                body,
                                |rename_fld, fld, body| {
                fld.fold_block(rename_fld.fold_block(body))
            });
            assert!(rewritten_pats.len() == 1);

            let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
            let sub_expr = fld.fold_expr(sub_expr);
            fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt))
150
                .with_attrs(fold_thin_attrs(attrs, fld))
151 152
        }

153
        ast::ExprClosure(capture_clause, fn_decl, block) => {
154
            let (rewritten_fn_decl, rewritten_block)
155
                = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
156
            let new_node = ast::ExprClosure(capture_clause,
157 158
                                            rewritten_fn_decl,
                                            rewritten_block);
159
            P(ast::Expr{id:id, node: new_node, span: fld.new_span(span),
160
                        attrs: fold_thin_attrs(attrs, fld)})
161 162
        }

163 164 165 166
        _ => {
            P(noop_fold_expr(ast::Expr {
                id: id,
                node: node,
167
                span: span,
168
                attrs: attrs
169 170
            }, fld))
        }
171
    });
172 173
}

J
John Clements 已提交
174 175 176 177
/// Expand a (not-ident-style) macro invocation. Returns the result
/// of expansion and the mark which must be applied to the result.
/// Our current interface doesn't allow us to apply the mark to the
/// result until after calling make_expr, make_items, etc.
178 179
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                             span: codemap::Span,
J
Jorge Aparicio 已提交
180 181 182 183
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
184
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
185
    G: FnOnce(T, Mrk) -> T,
186
{
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    // it would almost certainly be cleaner to pass the whole
    // macro invocation in, rather than pulling it apart and
    // marking the tts and the ctxt separately. This also goes
    // for the other three macro invocation chunks of code
    // in this file.

    let Mac_ { path: pth, tts, .. } = mac.node;
    if pth.segments.len() > 1 {
        fld.cx.span_err(pth.span,
                        "expected macro name without module \
                        separators");
        // let compilation continue
        return None;
    }
    let extname = pth.segments[0].identifier.name;
202
    match fld.cx.syntax_env.find(extname) {
203 204 205 206 207
        None => {
            fld.cx.span_err(
                pth.span,
                &format!("macro undefined: '{}!'",
                        &extname));
208
            fld.cx.suggest_macro_name(&extname.as_str(), pth.span);
J
John Clements 已提交
209

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
            // let compilation continue
            None
        }
        Some(rc) => match *rc {
            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
                            format: MacroBang(extname),
                            span: exp_span,
                            allow_internal_unstable: allow_internal_unstable,
                        },
                    });
                let fm = fresh_mark();
                let marked_before = mark_tts(&tts[..], fm);

                // The span that we pass to the expanders we want to
                // be the root of the call stack. That's the most
                // relevant span and it's the actual invocation of
                // the macro.
                let mac_span = fld.cx.original_span();

                let opt_parsed = {
                    let expanded = expandfun.expand(fld.cx,
                                                    mac_span,
                                                    &marked_before[..]);
                    parse_thunk(expanded)
                };
                let parsed = match opt_parsed {
                    Some(e) => e,
                    None => {
241 242
                        fld.cx.span_err(
                            pth.span,
243 244 245 246
                            &format!("non-expression macro in expression position: {}",
                                    extname
                                    ));
                        return None;
247
                    }
248 249 250 251 252 253 254 255 256
                };
                Some(mark_thunk(parsed,fm))
            }
            _ => {
                fld.cx.span_err(
                    pth.span,
                    &format!("'{}' is not a tt-style macro",
                            extname));
                None
J
John Clements 已提交
257 258 259 260 261
            }
        }
    }
}

262 263 264 265 266
/// Rename loop label and expand its loop body
///
/// The renaming procedure for loop is different in the sense that the loop
/// body is in a block enclosed by loop head so the renaming of loop label
/// must be propagated to the enclosed context.
267 268 269
fn expand_loop_block(loop_block: P<Block>,
                     opt_ident: Option<Ident>,
                     fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
E
Edward Wang 已提交
270 271
    match opt_ident {
        Some(label) => {
272
            let new_label = fresh_name(label);
E
Edward Wang 已提交
273
            let rename = (label, new_label);
274 275 276 277 278 279

            // The rename *must not* be added to the pending list of current
            // syntax context otherwise an unrelated `break` or `continue` in
            // the same context will pick that up in the deferred renaming pass
            // and be renamed incorrectly.
            let mut rename_list = vec!(rename);
280
            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
281 282 283 284 285
            let renamed_ident = rename_fld.fold_ident(label);

            // The rename *must* be added to the enclosed syntax context for
            // `break` or `continue` to pick up because by definition they are
            // in a block enclosed by loop head.
286 287
            fld.cx.syntax_env.push_frame();
            fld.cx.syntax_env.info().pending_renames.push(rename);
288
            let expanded_block = expand_block_elts(loop_block, fld);
289
            fld.cx.syntax_env.pop_frame();
290 291

            (expanded_block, Some(renamed_ident))
E
Edward Wang 已提交
292
        }
293
        None => (fld.fold_block(loop_block), opt_ident)
E
Edward Wang 已提交
294 295 296
    }
}

297 298
// eval $e with a new exts frame.
// must be a macro so that $e isn't evaluated too early.
299
macro_rules! with_exts_frame {
300
    ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
S
Steven Fackler 已提交
301 302
    ({$extsboxexpr.push_frame();
      $extsboxexpr.info().macros_escape = $macros_escape;
J
John Clements 已提交
303
      let result = $e;
S
Steven Fackler 已提交
304
      $extsboxexpr.pop_frame();
J
John Clements 已提交
305 306
      result
     })
307
}
J
John Clements 已提交
308

309
// When we enter a module, record it, for the sake of `module!`
310 311
pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
                   -> SmallVector<P<ast::Item>> {
312
    let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
313

314
    expand_annotatable(it, fld)
315
        .into_iter().map(|i| i.expect_item()).collect()
316 317
}

J
John Clements 已提交
318
/// Expand item_underscore
319 320
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
    match item {
321
        ast::ItemFn(decl, unsafety, constness, abi, generics, body) => {
J
John Clements 已提交
322
            let (rewritten_fn_decl, rewritten_body)
323
                = expand_and_rename_fn_decl_and_block(decl, body, fld);
M
Marvin Löbel 已提交
324
            let expanded_generics = fold::noop_fold_generics(generics,fld);
325 326
            ast::ItemFn(rewritten_fn_decl, unsafety, constness, abi,
                        expanded_generics, rewritten_body)
J
John Clements 已提交
327
        }
328
        _ => noop_fold_item_underscore(item, fld)
J
John Clements 已提交
329 330 331
    }
}

332 333
// does this attribute list contain "macro_use" ?
fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
334
    for attr in attrs {
335 336 337 338
        let mut is_use = attr.check_name("macro_use");
        if attr.check_name("macro_escape") {
            fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
            is_use = true;
339
            if let ast::AttrStyle::Inner = attr.node.style {
340
                fld.cx.fileline_help(attr.span, "consider an outer attribute, \
341 342 343 344 345 346 347 348 349 350 351 352 353
                                             #[macro_use] mod ...");
            }
        };

        if is_use {
            match attr.node.value.node {
                ast::MetaWord(..) => (),
                _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
            }
            return true;
        }
    }
    false
J
John Clements 已提交
354 355
}

356 357
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
358 359
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
360 361 362
    let (extname, path_span, tts, span, attrs, ident) = it.and_then(|it| match it.node {
        ItemMac(codemap::Spanned { node: Mac_ { path, tts, .. }, .. }) =>
            (path.segments[0].identifier.name, path.span, tts, it.span, it.attrs, it.ident),
363
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
364
    });
365

366
    let fm = fresh_mark();
367
    let items = {
368
        let expanded = match fld.cx.syntax_env.find(extname) {
369
            None => {
370
                fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
371
                                &format!("macro undefined: '{}!'",
372
                                        extname));
373 374 375
                // let compilation continue
                return SmallVector::zero();
            }
376

377
            Some(rc) => match *rc {
378 379
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
                    if ident.name != parse::token::special_idents::invalid.name {
380
                        fld.cx
381
                            .span_err(path_span,
382
                                      &format!("macro {}! expects no ident argument, given '{}'",
383
                                               extname,
384
                                               ident));
385 386 387
                        return SmallVector::zero();
                    }
                    fld.cx.bt_push(ExpnInfo {
388
                        call_site: span,
389
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
390
                            format: MacroBang(extname),
391
                            span: tt_span,
392
                            allow_internal_unstable: allow_internal_unstable,
393 394 395
                        }
                    });
                    // mark before expansion:
396
                    let marked_before = mark_tts(&tts[..], fm);
397
                    expander.expand(fld.cx, span, &marked_before[..])
398
                }
399 400
                IdentTT(ref expander, tt_span, allow_internal_unstable) => {
                    if ident.name == parse::token::special_idents::invalid.name {
401
                        fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
402
                                        &format!("macro {}! expects an ident argument",
403
                                                extname));
404
                        return SmallVector::zero();
405
                    }
406
                    fld.cx.bt_push(ExpnInfo {
407
                        call_site: span,
408
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
409
                            format: MacroBang(extname),
410
                            span: tt_span,
411
                            allow_internal_unstable: allow_internal_unstable,
412 413 414
                        }
                    });
                    // mark before expansion:
415
                    let marked_tts = mark_tts(&tts[..], fm);
416
                    expander.expand(fld.cx, span, ident, marked_tts)
417
                }
418
                MacroRulesTT => {
419
                    if ident.name == parse::token::special_idents::invalid.name {
S
Steve Klabnik 已提交
420
                        fld.cx.span_err(path_span, "macro_rules! expects an ident argument");
421
                        return SmallVector::zero();
422
                    }
423

424
                    fld.cx.bt_push(ExpnInfo {
425
                        call_site: span,
426
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
427
                            format: MacroBang(extname),
428
                            span: None,
429 430 431 432
                            // `macro_rules!` doesn't directly allow
                            // unstable (this is orthogonal to whether
                            // the macro it creates allows it)
                            allow_internal_unstable: false,
433 434
                        }
                    });
435
                    // DON'T mark before expansion.
436

437
                    let allow_internal_unstable = attr::contains_name(&attrs,
438 439 440 441 442 443 444 445 446
                                                                      "allow_internal_unstable");

                    // ensure any #[allow_internal_unstable]s are
                    // detected (including nested macro definitions
                    // etc.)
                    if allow_internal_unstable && !fld.cx.ecfg.enable_allow_internal_unstable() {
                        feature_gate::emit_feature_err(
                            &fld.cx.parse_sess.span_diagnostic,
                            "allow_internal_unstable",
447
                            span,
448
                            feature_gate::GateIssue::Language,
449 450 451
                            feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
                    }

452
                    let export = attr::contains_name(&attrs, "macro_export");
453
                    let def = ast::MacroDef {
454 455
                        ident: ident,
                        attrs: attrs,
456
                        id: ast::DUMMY_NODE_ID,
457
                        span: span,
458
                        imported_from: None,
459
                        export: export,
K
Keegan McAllister 已提交
460
                        use_locally: true,
461
                        allow_internal_unstable: allow_internal_unstable,
462 463
                        body: tts,
                    };
464
                    fld.cx.insert_macro(def);
465 466 467 468

                    // macro_rules! has a side effect but expands to nothing.
                    fld.cx.bt_pop();
                    return SmallVector::zero();
469 470
                }
                _ => {
471
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
472
                                    &format!("{}! is not legal in item position",
473
                                            extname));
474
                    return SmallVector::zero();
475
                }
J
John Clements 已提交
476
            }
477 478
        };

479
        expanded.make_items()
480
    };
481

482 483
    let items = match items {
        Some(items) => {
A
Aaron Turon 已提交
484
            items.into_iter()
485
                .map(|i| mark_item(i, fm))
A
Aaron Turon 已提交
486
                .flat_map(|i| fld.fold_item(i).into_iter())
487 488
                .collect()
        }
489
        None => {
490
            fld.cx.span_err(path_span,
J
Jorge Aparicio 已提交
491
                            &format!("non-item macro in item position: {}",
492
                                    extname));
493
            return SmallVector::zero();
494
        }
495
    };
496

497
    fld.cx.bt_pop();
498
    items
499 500
}

J
John Clements 已提交
501
/// Expand a stmt
502 503
fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
    let stmt = stmt.and_then(|stmt| stmt);
504 505
    let (mac, style, attrs) = match stmt.node {
        StmtMac(mac, style, attrs) => (mac, style, attrs),
506
        _ => return expand_non_macro_stmt(stmt, fld)
507
    };
508

509
    // Assert that we drop any macro attributes on the floor here
510
    drop(attrs);
511

512 513 514 515 516 517
    let maybe_new_items =
        expand_mac_invoc(mac.and_then(|m| m), stmt.span,
                         |r| r.make_stmts(),
                         |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
                         fld);

518
    let mut fully_expanded = match maybe_new_items {
519 520
        Some(stmts) => {
            // Keep going, outside-in.
521
            let new_items = stmts.into_iter().flat_map(|s| {
522
                fld.fold_stmt(s).into_iter()
523 524 525
            }).collect();
            fld.cx.bt_pop();
            new_items
526
        }
527
        None => SmallVector::zero()
528 529
    };

530 531
    // If this is a macro invocation with a semicolon, then apply that
    // semicolon to the final statement produced by expansion.
532
    if style == MacStmtWithSemicolon {
533 534 535 536 537 538 539 540 541 542 543
        if let Some(stmt) = fully_expanded.pop() {
            let new_stmt = stmt.map(|Spanned {node, span}| {
                Spanned {
                    node: match node {
                        StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id),
                        _ => node /* might already have a semi */
                    },
                    span: span
                }
            });
            fully_expanded.push(new_stmt);
544
        }
545
    }
546 547

    fully_expanded
548 549
}

550 551
// expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above.
552 553
fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroExpander)
                         -> SmallVector<P<Stmt>> {
554
    // is it a let?
555 556 557 558
    match node {
        StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl {
            DeclLocal(local) => {
                // take it apart:
559
                let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| {
560 561
                    // expand the ty since TyFixedLengthVec contains an Expr
                    // and thus may have a macro use
S
Seo Sanghyeon 已提交
562
                    let expanded_ty = ty.map(|t| fld.fold_ty(t));
563
                    // expand the pat (it might contain macro uses):
564
                    let expanded_pat = fld.fold_pat(pat);
565
                    // find the PatIdents in the pattern:
566 567 568 569
                    // oh dear heaven... this is going to include the enum
                    // names, as well... but that should be okay, as long as
                    // the new names are gensyms for the old ones.
                    // generate fresh names, push them to a new pending list
S
Seo Sanghyeon 已提交
570
                    let idents = pattern_bindings(&expanded_pat);
571
                    let mut new_pending_renames =
572
                        idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect();
573 574
                    // rewrite the pattern using the new names (the old
                    // ones have already been applied):
575
                    let rewritten_pat = {
576 577
                        // nested binding to allow borrow to expire:
                        let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
578 579 580
                        rename_fld.fold_pat(expanded_pat)
                    };
                    // add them to the existing pending renames:
581
                    fld.cx.syntax_env.info().pending_renames
582
                          .extend(new_pending_renames);
583 584 585 586 587 588
                    Local {
                        id: id,
                        ty: expanded_ty,
                        pat: rewritten_pat,
                        // also, don't forget to expand the init:
                        init: init.map(|e| fld.fold_expr(e)),
589
                        span: span,
590
                        attrs: fold::fold_thin_attrs(attrs, fld),
591 592 593 594 595 596 597 598 599 600
                    }
                });
                SmallVector::one(P(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: DeclLocal(rewritten_local),
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }))
S
Steven Fackler 已提交
601
            }
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
            _ => {
                noop_fold_stmt(Spanned {
                    node: StmtDecl(P(Spanned {
                            node: decl,
                            span: span
                        }),
                        node_id),
                    span: stmt_span
                }, fld)
            }
        }),
        _ => {
            noop_fold_stmt(Spanned {
                node: node,
                span: stmt_span
            }, fld)
        }
619 620 621
    }
}

J
John Clements 已提交
622
// expand the arm of a 'match', renaming for macro hygiene
623
fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
624
    // expand pats... they might contain macro uses:
625
    let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat));
626
    if expanded_pats.is_empty() {
S
Steve Klabnik 已提交
627
        panic!("encountered match arm with 0 patterns");
J
John Clements 已提交
628
    }
629

630
    // apply renaming and then expansion to the guard and the body:
631 632 633 634 635 636 637 638 639 640
    let ((rewritten_guard, rewritten_body), rewritten_pats) =
        rename_in_scope(expanded_pats,
                        fld,
                        (arm.guard, arm.body),
                        |rename_fld, fld, (ag, ab)|{
        let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
        let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab));
        (rewritten_guard, rewritten_body)
    });

J
John Clements 已提交
641
    ast::Arm {
642
        attrs: fold::fold_attrs(arm.attrs, fld),
643 644 645
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
646
    }
J
John Clements 已提交
647 648
}

649 650 651 652 653 654 655 656 657
fn rename_in_scope<X, F>(pats: Vec<P<ast::Pat>>,
                         fld: &mut MacroExpander,
                         x: X,
                         f: F)
                         -> (X, Vec<P<ast::Pat>>)
    where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X
{
    // all of the pats must have the same set of bindings, so use the
    // first one to extract them and generate new names:
S
Seo Sanghyeon 已提交
658
    let idents = pattern_bindings(&pats[0]);
659 660 661 662 663 664 665 666 667
    let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
    // apply the renaming, but only to the PatIdents:
    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
    let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat));

    let mut rename_fld = IdentRenamer{ renames:&new_renames };
    (f(&mut rename_fld, fld, x), rewritten_pats)
}

668 669 670
/// A visitor that extracts the PatIdent (binding) paths
/// from a given thingy and puts them in a mutable
/// array
671
#[derive(Clone)]
672
struct PatIdentFinder {
673
    ident_accumulator: Vec<ast::Ident>
674 675
}

676
impl<'v> Visitor<'v> for PatIdentFinder {
677
    fn visit_pat(&mut self, pattern: &ast::Pat) {
678
        match *pattern {
679
            ast::Pat { id: _, node: ast::PatIdent(_, ref path1, ref inner), span: _ } => {
680
                self.ident_accumulator.push(path1.node);
681
                // visit optional subpattern of PatIdent:
682
                if let Some(ref subpat) = *inner {
S
Seo Sanghyeon 已提交
683
                    self.visit_pat(subpat)
J
John Clements 已提交
684 685
                }
            }
686
            // use the default traversal for non-PatIdents
687
            _ => visit::walk_pat(self, pattern)
688 689 690 691
        }
    }
}

692
/// find the PatIdent paths in a pattern
693
fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
694
    let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
695
    name_finder.visit_pat(pat);
696
    name_finder.ident_accumulator
697 698
}

J
John Clements 已提交
699 700 701
/// find the PatIdent paths in a
fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
    let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()};
702
    for arg in &fn_decl.inputs {
S
Seo Sanghyeon 已提交
703
        pat_idents.visit_pat(&arg.pat);
J
John Clements 已提交
704 705 706 707
    }
    pat_idents.ident_accumulator
}

J
John Clements 已提交
708
// expand a block. pushes a new exts_frame, then calls expand_block_elts
709
pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
710
    // see note below about treatment of exts table
711
    with_exts_frame!(fld.cx.syntax_env,false,
712
                     expand_block_elts(blk, fld))
713 714
}

J
John Clements 已提交
715
// expand the elements of a block.
716
pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
717
    b.map(|Block {id, stmts, expr, rules, span}| {
A
Aaron Turon 已提交
718
        let new_stmts = stmts.into_iter().flat_map(|x| {
719
            // perform all pending renames
720
            let renamed_stmt = {
721
                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
722
                let mut rename_fld = IdentRenamer{renames:pending_renames};
723
                rename_fld.fold_stmt(x).expect_one("rename_fold didn't return one value")
724
            };
725
            // expand macros in the statement
A
Aaron Turon 已提交
726
            fld.fold_stmt(renamed_stmt).into_iter()
727
        }).collect();
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
        let new_expr = expr.map(|x| {
            let expr = {
                let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
                let mut rename_fld = IdentRenamer{renames:pending_renames};
                rename_fld.fold_expr(x)
            };
            fld.fold_expr(expr)
        });
        Block {
            id: fld.new_id(id),
            stmts: new_stmts,
            expr: new_expr,
            rules: rules,
            span: span
        }
743
    })
J
John Clements 已提交
744 745
}

746 747 748 749
fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
    match p.node {
        PatMac(_) => {}
        _ => return noop_fold_pat(p, fld)
K
Keegan McAllister 已提交
750
    }
751 752
    p.map(|ast::Pat {node, span, ..}| {
        let (pth, tts) = match node {
753
            PatMac(mac) => (mac.node.path, mac.node.tts),
754 755
            _ => unreachable!()
        };
756
        if pth.segments.len() > 1 {
757 758
            fld.cx.span_err(pth.span, "expected macro name without module separators");
            return DummyResult::raw_pat(span);
K
Keegan McAllister 已提交
759
        }
760
        let extname = pth.segments[0].identifier.name;
761
        let marked_after = match fld.cx.syntax_env.find(extname) {
762 763
            None => {
                fld.cx.span_err(pth.span,
J
Jorge Aparicio 已提交
764
                                &format!("macro undefined: '{}!'",
765
                                        extname));
766 767 768
                // let compilation continue
                return DummyResult::raw_pat(span);
            }
K
Keegan McAllister 已提交
769

770
            Some(rc) => match *rc {
771
                NormalTT(ref expander, tt_span, allow_internal_unstable) => {
772 773 774
                    fld.cx.bt_push(ExpnInfo {
                        call_site: span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
775
                            format: MacroBang(extname),
776 777
                            span: tt_span,
                            allow_internal_unstable: allow_internal_unstable,
778 779
                        }
                    });
K
Keegan McAllister 已提交
780

781
                    let fm = fresh_mark();
782
                    let marked_before = mark_tts(&tts[..], fm);
783
                    let mac_span = fld.cx.original_span();
784 785 786 787
                    let pat = expander.expand(fld.cx,
                                              mac_span,
                                              &marked_before[..]).make_pat();
                    let expanded = match pat {
788 789 790 791
                        Some(e) => e,
                        None => {
                            fld.cx.span_err(
                                pth.span,
J
Jorge Aparicio 已提交
792
                                &format!(
793
                                    "non-pattern macro in pattern position: {}",
794
                                    extname
795
                                    )
796 797 798 799
                            );
                            return DummyResult::raw_pat(span);
                        }
                    };
800

801 802 803 804 805
                    // mark after:
                    mark_pat(expanded,fm)
                }
                _ => {
                    fld.cx.span_err(span,
J
Jorge Aparicio 已提交
806
                                    &format!("{}! is not legal in pattern position",
807
                                            extname));
808 809
                    return DummyResult::raw_pat(span);
                }
810
            }
811
        };
K
Keegan McAllister 已提交
812

813 814 815
        let fully_expanded =
            fld.fold_pat(marked_after).node.clone();
        fld.cx.bt_pop();
K
Keegan McAllister 已提交
816

817 818 819 820 821 822
        ast::Pat {
            id: ast::DUMMY_NODE_ID,
            node: fully_expanded,
            span: span
        }
    })
K
Keegan McAllister 已提交
823 824
}

J
John Clements 已提交
825 826 827
/// A tree-folder that applies every rename in its (mutable) list
/// to every identifier, including both bindings and varrefs
/// (and lots of things that will turn out to be neither)
828
pub struct IdentRenamer<'a> {
829
    renames: &'a mtwt::RenameList,
830 831
}

832
impl<'a> Folder for IdentRenamer<'a> {
833
    fn fold_ident(&mut self, id: Ident) -> Ident {
834
        Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt))
835
    }
K
Keegan McAllister 已提交
836 837
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
838
    }
839 840
}

J
John Clements 已提交
841 842 843 844 845 846 847 848 849
/// A tree-folder that applies every rename in its list to
/// the idents that are in PatIdent patterns. This is more narrowly
/// focused than IdentRenamer, and is needed for FnDecl,
/// where we want to rename the args but not the fn name or the generics etc.
pub struct PatIdentRenamer<'a> {
    renames: &'a mtwt::RenameList,
}

impl<'a> Folder for PatIdentRenamer<'a> {
850
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
851
        match pat.node {
852 853 854 855 856 857
            ast::PatIdent(..) => {},
            _ => return noop_fold_pat(pat, self)
        }

        pat.map(|ast::Pat {id, node, span}| match node {
            ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => {
858 859
                let new_ident = Ident::new(ident.name,
                                           mtwt::apply_renames(self.renames, ident.ctxt));
J
John Clements 已提交
860 861
                let new_node =
                    ast::PatIdent(binding_mode,
862
                                  Spanned{span: self.new_span(sp), node: new_ident},
J
John Clements 已提交
863
                                  sub.map(|p| self.fold_pat(p)));
864 865
                ast::Pat {
                    id: id,
J
John Clements 已提交
866
                    node: new_node,
867
                    span: self.new_span(span)
J
John Clements 已提交
868 869
                }
            },
870 871
            _ => unreachable!()
        })
872
    }
K
Keegan McAllister 已提交
873 874
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
875
    }
K
Kevin Atkinson 已提交
876 877
}

878 879 880 881 882 883 884
fn expand_annotatable(a: Annotatable,
                      fld: &mut MacroExpander)
                      -> SmallVector<Annotatable> {
    let a = expand_item_multi_modifier(a, fld);

    let mut decorator_items = SmallVector::zero();
    let mut new_attrs = Vec::new();
885
    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
886 887 888 889 890 891 892 893 894 895 896 897 898

    let mut new_items: SmallVector<Annotatable> = match a {
        Annotatable::Item(it) => match it.node {
            ast::ItemMac(..) => {
                expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
            }
            ast::ItemMod(_) | ast::ItemForeignMod(_) => {
                let valid_ident =
                    it.ident.name != parse::token::special_idents::invalid.name;

                if valid_ident {
                    fld.cx.mod_push(it.ident);
                }
899
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
                let result = with_exts_frame!(fld.cx.syntax_env,
                                              macro_use,
                                              noop_fold_item(it, fld));
                if valid_ident {
                    fld.cx.mod_pop();
                }
                result.into_iter().map(|i| Annotatable::Item(i)).collect()
            },
            _ => {
                let it = P(ast::Item {
                    attrs: new_attrs,
                    ..(*it).clone()
                });
                noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
            }
        },
916

917
        Annotatable::TraitItem(it) => match it.node {
918 919 920 921 922 923 924 925 926
            ast::MethodTraitItem(_, Some(_)) => SmallVector::one(it.map(|ti| ast::TraitItem {
                id: ti.id,
                ident: ti.ident,
                attrs: ti.attrs,
                node: match ti.node  {
                    ast::MethodTraitItem(sig, Some(body)) => {
                        let (sig, body) = expand_and_rename_method(sig, body, fld);
                        ast::MethodTraitItem(sig, Some(body))
                    }
927
                    _ => unreachable!()
928 929 930 931 932 933
                },
                span: fld.new_span(ti.span)
            })),
            _ => fold::noop_fold_trait_item(it, fld)
        }.into_iter().map(Annotatable::TraitItem).collect(),

934
        Annotatable::ImplItem(ii) => {
935
            expand_impl_item(ii, fld).into_iter().map(Annotatable::ImplItem).collect()
936 937 938
        }
    };

939
    new_items.push_all(decorator_items);
940 941 942
    new_items
}

943 944 945 946 947 948 949 950
// Partition a set of attributes into one kind of attribute, and other kinds.
macro_rules! partition {
    ($fn_name: ident, $variant: ident) => {
        #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
        fn $fn_name(attrs: &[ast::Attribute],
                    fld: &MacroExpander)
                     -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
            attrs.iter().cloned().partition(|attr| {
951
                match fld.cx.syntax_env.find(intern(&attr.name())) {
952 953 954 955 956 957 958
                    Some(rc) => match *rc {
                        $variant(..) => true,
                        _ => false
                    },
                    _ => false
                }
            })
959
        }
960
    }
961 962
}

963 964 965 966 967 968 969 970 971
partition!(multi_modifiers, MultiModifier);


fn expand_decorators(a: Annotatable,
                     fld: &mut MacroExpander,
                     decorator_items: &mut SmallVector<Annotatable>,
                     new_attrs: &mut Vec<ast::Attribute>)
{
    for attr in a.attrs() {
M
Manish Goregaokar 已提交
972
        let mname = intern(&attr.name());
973
        match fld.cx.syntax_env.find(mname) {
974
            Some(rc) => match *rc {
975 976 977 978 979 980
                MultiDecorator(ref dec) => {
                    attr::mark_used(&attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
981
                            format: MacroAttribute(mname),
982 983 984 985 986 987 988 989 990 991 992 993 994
                            span: Some(attr.span),
                            // attributes can do whatever they like,
                            // for now.
                            allow_internal_unstable: true,
                        }
                    });

                    // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
                    // but that double-mut-borrows fld
                    let mut items: SmallVector<Annotatable> = SmallVector::zero();
                    dec.expand(fld.cx,
                               attr.span,
                               &attr.node.value,
995
                               &a,
996 997 998 999 1000 1001 1002
                               &mut |ann| items.push(ann));
                    decorator_items.extend(items.into_iter()
                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));

                    fld.cx.bt_pop();
                }
                _ => new_attrs.push((*attr).clone()),
1003
            },
1004
            _ => new_attrs.push((*attr).clone()),
1005
        }
1006
    }
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
}

fn expand_item_multi_modifier(mut it: Annotatable,
                              fld: &mut MacroExpander)
                              -> Annotatable {
    let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);

    // Update the attrs, leave everything else alone. Is this mutation really a good idea?
    it = it.fold_attrs(other_attrs);

    if modifiers.is_empty() {
        return it
    }

1021
    for attr in &modifiers {
M
Manish Goregaokar 已提交
1022
        let mname = intern(&attr.name());
1023

1024
        match fld.cx.syntax_env.find(mname) {
1025 1026 1027 1028 1029 1030
            Some(rc) => match *rc {
                MultiModifier(ref mac) => {
                    attr::mark_used(attr);
                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
1031
                            format: MacroAttribute(mname),
1032
                            span: Some(attr.span),
1033 1034 1035
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
                        }
                    });
                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
                    fld.cx.bt_pop();
                }
                _ => unreachable!()
            },
            _ => unreachable!()
        }
    }

    // Expansion may have added new ItemModifiers.
    expand_item_multi_modifier(it, fld)
}

1051
fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
1052 1053
                 -> SmallVector<P<ast::ImplItem>> {
    match ii.node {
1054
        ast::ImplItemKind::Method(..) => SmallVector::one(ii.map(|ii| ast::ImplItem {
1055 1056 1057 1058 1059
            id: ii.id,
            ident: ii.ident,
            attrs: ii.attrs,
            vis: ii.vis,
            node: match ii.node  {
1060
                ast::ImplItemKind::Method(sig, body) => {
1061
                    let (sig, body) = expand_and_rename_method(sig, body, fld);
1062
                    ast::ImplItemKind::Method(sig, body)
1063 1064 1065 1066 1067
                }
                _ => unreachable!()
            },
            span: fld.new_span(ii.span)
        })),
1068
        ast::ImplItemKind::Macro(_) => {
1069
            let (span, mac) = ii.and_then(|ii| match ii.node {
1070
                ast::ImplItemKind::Macro(mac) => (ii.span, mac),
1071 1072
                _ => unreachable!()
            });
1073
            let maybe_new_items =
1074
                expand_mac_invoc(mac, span,
1075 1076
                                 |r| r.make_impl_items(),
                                 |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
J
John Clements 已提交
1077 1078
                                 fld);

1079 1080
            match maybe_new_items {
                Some(impl_items) => {
A
Adolfo Ochagavía 已提交
1081
                    // expand again if necessary
1082 1083 1084
                    let new_items = impl_items.into_iter().flat_map(|ii| {
                        expand_impl_item(ii, fld).into_iter()
                    }).collect();
A
Adolfo Ochagavía 已提交
1085
                    fld.cx.bt_pop();
1086
                    new_items
A
Adolfo Ochagavía 已提交
1087
                }
J
John Clements 已提交
1088
                None => SmallVector::zero()
A
Adolfo Ochagavía 已提交
1089
            }
1090
        }
1091
        _ => fold::noop_fold_impl_item(ii, fld)
1092
    }
1093 1094
}

J
John Clements 已提交
1095 1096 1097
/// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
/// PatIdents in its arguments to perform renaming in the FnDecl and
/// the block, returning both the new FnDecl and the new Block.
1098
fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
J
John Clements 已提交
1099
                                       fld: &mut MacroExpander)
1100
                                       -> (P<ast::FnDecl>, P<ast::Block>) {
J
John Clements 已提交
1101
    let expanded_decl = fld.fold_fn_decl(fn_decl);
S
Seo Sanghyeon 已提交
1102
    let idents = fn_decl_arg_bindings(&expanded_decl);
J
John Clements 已提交
1103
    let renames =
1104
        idents.iter().map(|id| (*id,fresh_name(*id))).collect();
J
John Clements 已提交
1105 1106
    // first, a renamer for the PatIdents, for the fn_decl:
    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1107
    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
J
John Clements 已提交
1108 1109 1110 1111 1112 1113
    // now, a renamer for *all* idents, for the body:
    let mut rename_fld = IdentRenamer{renames: &renames};
    let rewritten_body = fld.fold_block(rename_fld.fold_block(block));
    (rewritten_fn_decl,rewritten_body)
}

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
fn expand_and_rename_method(sig: ast::MethodSig, body: P<ast::Block>,
                            fld: &mut MacroExpander)
                            -> (ast::MethodSig, P<ast::Block>) {
    let (rewritten_fn_decl, rewritten_body)
        = expand_and_rename_fn_decl_and_block(sig.decl, body, fld);
    (ast::MethodSig {
        generics: fld.fold_generics(sig.generics),
        abi: sig.abi,
        explicit_self: fld.fold_explicit_self(sig.explicit_self),
        unsafety: sig.unsafety,
N
Niko Matsakis 已提交
1124
        constness: sig.constness,
1125 1126 1127 1128
        decl: rewritten_fn_decl
    }, rewritten_body)
}

1129 1130 1131
pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
    let t = match t.node.clone() {
        ast::Ty_::TyMac(mac) => {
J
Jared Roesch 已提交
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
            if fld.cx.ecfg.features.unwrap().type_macros {
                let expanded_ty = match expand_mac_invoc(mac, t.span,
                                                         |r| r.make_ty(),
                                                         mark_ty,
                                                         fld) {
                    Some(ty) => ty,
                    None => {
                        return DummyResult::raw_ty(t.span);
                    }
                };
1142

J
Jared Roesch 已提交
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
                // Keep going, outside-in.
                let fully_expanded = fld.fold_ty(expanded_ty);
                fld.cx.bt_pop();

                fully_expanded.map(|t| ast::Ty {
                    id: ast::DUMMY_NODE_ID,
                    node: t.node,
                    span: t.span,
                    })
            } else {
                feature_gate::emit_feature_err(
                    &fld.cx.parse_sess.span_diagnostic,
                    "type_macros",
                    t.span,
1157 1158
                    feature_gate::GateIssue::Language,
                    "type macros are experimental");
J
Jared Roesch 已提交
1159 1160

                DummyResult::raw_ty(t.span)
J
Jared Roesch 已提交
1161
            }
1162 1163 1164
        }
        _ => t
    };
J
Jared Roesch 已提交
1165

1166 1167 1168
    fold::noop_fold_ty(t, fld)
}

J
John Clements 已提交
1169
/// A tree-folder that performs macro expansion
1170
pub struct MacroExpander<'a, 'b:'a> {
1171
    pub cx: &'a mut ExtCtxt<'b>,
N
Nick Cameron 已提交
1172 1173 1174 1175
}

impl<'a, 'b> MacroExpander<'a, 'b> {
    pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1176
        MacroExpander { cx: cx }
N
Nick Cameron 已提交
1177
    }
1178 1179
}

E
Eduard Burtescu 已提交
1180
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1181
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1182
        expand_expr(expr, self)
1183 1184
    }

1185
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1186 1187 1188
        expand_pat(pat, self)
    }

1189
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1190
        expand_item(item, self)
1191 1192
    }

1193
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
J
John Clements 已提交
1194 1195 1196
        expand_item_underscore(item, self)
    }

1197
    fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1198
        expand_stmt(stmt, self)
1199 1200
    }

S
Steven Fackler 已提交
1201
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1202
        expand_block(block, self)
1203 1204
    }

1205
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1206 1207 1208
        expand_arm(arm, self)
    }

1209 1210 1211
    fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
        expand_annotatable(Annotatable::TraitItem(i), self)
            .into_iter().map(|i| i.expect_trait_item()).collect()
1212 1213
    }

1214 1215 1216
    fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
        expand_annotatable(Annotatable::ImplItem(i), self)
            .into_iter().map(|i| i.expect_impl_item()).collect()
1217 1218
    }

1219 1220 1221 1222
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
        expand_type(ty, self)
    }

S
Steven Fackler 已提交
1223
    fn new_span(&mut self, span: Span) -> Span {
1224 1225
        new_span(self.cx, span)
    }
1226 1227
}

J
John Clements 已提交
1228 1229 1230 1231 1232
fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
    /* this discards information in the case of macro-defining macros */
    Span {
        lo: sp.lo,
        hi: sp.hi,
1233
        expn_id: cx.backtrace(),
J
John Clements 已提交
1234 1235 1236
    }
}

1237
pub struct ExpansionConfig<'feat> {
1238
    pub crate_name: String,
1239
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1240
    pub recursion_limit: usize,
1241
    pub trace_mac: bool,
1242 1243
}

1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1257 1258
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1259 1260
        ExpansionConfig {
            crate_name: crate_name,
1261
            features: None,
1262
            recursion_limit: 64,
1263
            trace_mac: false,
1264 1265
        }
    }
1266

1267 1268 1269 1270 1271 1272 1273
    feature_tests! {
        fn enable_quotes = allow_quote,
        fn enable_asm = allow_asm,
        fn enable_log_syntax = allow_log_syntax,
        fn enable_concat_idents = allow_concat_idents,
        fn enable_trace_macros = allow_trace_macros,
        fn enable_allow_internal_unstable = allow_internal_unstable,
1274
        fn enable_custom_derive = allow_custom_derive,
1275
        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
1276
    }
1277 1278
}

1279 1280 1281 1282 1283
pub fn expand_crate(mut cx: ExtCtxt,
                    // these are the macros being imported to this crate:
                    imported_macros: Vec<ast::MacroDef>,
                    user_exts: Vec<NamedSyntaxExtension>,
                    c: Crate) -> (Crate, HashSet<Name>) {
A
Alex Crichton 已提交
1284 1285 1286 1287 1288 1289 1290
    if std_inject::no_core(&c) {
        cx.crate_root = None;
    } else if std_inject::no_std(&c) {
        cx.crate_root = Some("core");
    } else {
        cx.crate_root = Some("std");
    }
1291 1292
    let ret = {
        let mut expander = MacroExpander::new(&mut cx);
1293

1294 1295 1296
        for def in imported_macros {
            expander.cx.insert_macro(def);
        }
1297

1298 1299 1300
        for (name, extension) in user_exts {
            expander.cx.syntax_env.insert(name, extension);
        }
1301

1302 1303
        let mut ret = expander.fold_crate(c);
        ret.exported_macros = expander.cx.exported_macros.clone();
1304
        cx.parse_sess.span_diagnostic.handler().abort_if_errors();
1305 1306 1307
        ret
    };
    return (ret, cx.syntax_env.names);
1308
}
J
John Clements 已提交
1309

1310 1311 1312 1313 1314 1315 1316 1317
// HYGIENIC CONTEXT EXTENSION:
// all of these functions are for walking over
// ASTs and making some change to the context of every
// element that has one. a CtxtFn is a trait-ified
// version of a closure in (SyntaxContext -> SyntaxContext).
// the ones defined here include:
// Marker - add a mark to a context

E
Eduard Burtescu 已提交
1318 1319
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1320

E
Eduard Burtescu 已提交
1321
impl Folder for Marker {
1322
    fn fold_ident(&mut self, id: Ident) -> Ident {
1323
        ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
1324
    }
1325
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1326
        Spanned {
1327 1328 1329 1330
            node: Mac_ {
                path: self.fold_path(node.path),
                tts: self.fold_tts(&node.tts),
                ctxt: mtwt::apply_mark(self.mark, node.ctxt),
1331 1332
            },
            span: span,
1333
        }
1334 1335 1336
    }
}

1337
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1338
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1339
    noop_fold_tts(tts, &mut Marker{mark:m})
1340 1341 1342
}

// apply a given mark to the given expr. Used following the expansion of a macro.
1343
fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
J
John Clements 已提交
1344
    Marker{mark:m}.fold_expr(expr)
1345 1346
}

K
Keegan McAllister 已提交
1347
// apply a given mark to the given pattern. Used following the expansion of a macro.
1348
fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
J
John Clements 已提交
1349
    Marker{mark:m}.fold_pat(pat)
K
Keegan McAllister 已提交
1350 1351
}

1352
// apply a given mark to the given stmt. Used following the expansion of a macro.
1353 1354
fn mark_stmt(stmt: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1355
        .expect_one("marking a stmt didn't return exactly one stmt")
1356 1357 1358
}

// apply a given mark to the given item. Used following the expansion of a macro.
1359
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1360
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1361 1362 1363 1364
        .expect_one("marking an item didn't return exactly one item")
}

// apply a given mark to the given item. Used following the expansion of a macro.
1365
fn mark_impl_item(ii: P<ast::ImplItem>, m: Mrk) -> P<ast::ImplItem> {
1366
    Marker{mark:m}.fold_impl_item(ii)
1367
        .expect_one("marking an impl item didn't return exactly one impl item")
1368 1369
}

1370 1371 1372 1373
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
    Marker { mark: m }.fold_ty(ty)
}

J
John Clements 已提交
1374 1375
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1376
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1377 1378 1379 1380 1381 1382 1383
}

/// A visitor that ensures that no macro invocations remain in an AST.
struct MacroExterminator<'a>{
    sess: &'a parse::ParseSess
}

1384
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1385 1386
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1387 1388 1389 1390 1391 1392
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1393
#[cfg(test)]
1394
mod tests {
A
Alex Crichton 已提交
1395
    use super::{pattern_bindings, expand_crate};
1396
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1397
    use ast;
J
Jorge Aparicio 已提交
1398
    use ast::Name;
1399
    use codemap;
1400
    use ext::mtwt;
1401
    use fold::Folder;
1402
    use parse;
1403
    use parse::token;
E
Eduard Burtescu 已提交
1404
    use util::parser_testing::{string_to_parser};
1405
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1406
    use visit;
1407 1408 1409 1410 1411
    use visit::Visitor;

    // a visitor that extracts the paths
    // from a given thingy and puts them in a mutable
    // array (passed in to the traversal)
1412
    #[derive(Clone)]
1413
    struct PathExprFinderContext {
1414
        path_accumulator: Vec<ast::Path> ,
1415 1416
    }

1417
    impl<'v> Visitor<'v> for PathExprFinderContext {
1418
        fn visit_expr(&mut self, expr: &ast::Expr) {
1419 1420
            if let ast::ExprPath(None, ref p) = expr.node {
                self.path_accumulator.push(p.clone());
1421
            }
1422
            visit::walk_expr(self, expr);
1423 1424 1425
        }
    }

1426 1427 1428
    // find the variable references in a crate
    fn crate_varrefs(the_crate : &ast::Crate) -> Vec<ast::Path> {
        let mut path_finder = PathExprFinderContext{path_accumulator:Vec::new()};
1429
        visit::walk_crate(&mut path_finder, the_crate);
1430
        path_finder.path_accumulator
1431
    }
J
John Clements 已提交
1432

1433 1434
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1435
    struct IdentFinder {
1436 1437
        ident_accumulator: Vec<ast::Ident>
    }
1438

1439
    impl<'v> Visitor<'v> for IdentFinder {
1440
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1441 1442 1443 1444 1445 1446 1447
            self.ident_accumulator.push(id);
        }
    }

    /// Find the idents in a crate
    fn crate_idents(the_crate: &ast::Crate) -> Vec<ast::Ident> {
        let mut ident_finder = IdentFinder{ident_accumulator: Vec::new()};
1448
        visit::walk_crate(&mut ident_finder, the_crate);
1449 1450
        ident_finder.ident_accumulator
    }
1451

J
John Clements 已提交
1452 1453 1454
    // these following tests are quite fragile, in that they don't test what
    // *kind* of failure occurs.

1455
    fn test_ecfg() -> ExpansionConfig<'static> {
1456 1457 1458
        ExpansionConfig::default("test".to_string())
    }

J
John Clements 已提交
1459
    // make sure that macros can't escape fns
1460
    #[should_panic]
J
John Clements 已提交
1461
    #[test] fn macros_cant_escape_fns_test () {
1462
        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1463
                   fn inty() -> i32 { z!() }".to_string();
1464
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1465
        let crate_ast = parse::parse_crate_from_source_str(
1466
            "<test>".to_string(),
1467
            src,
E
Eduard Burtescu 已提交
1468
            Vec::new(), &sess);
J
John Clements 已提交
1469
        // should fail:
1470
        expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1471 1472
    }

J
John Clements 已提交
1473
    // make sure that macros can't escape modules
1474
    #[should_panic]
J
John Clements 已提交
1475
    #[test] fn macros_cant_escape_mods_test () {
1476
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1477
                   fn inty() -> i32 { z!() }".to_string();
1478
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1479
        let crate_ast = parse::parse_crate_from_source_str(
1480
            "<test>".to_string(),
1481
            src,
E
Eduard Burtescu 已提交
1482
            Vec::new(), &sess);
1483
        expand_crate(&sess,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1484 1485
    }

1486
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1487
    #[test] fn macros_can_escape_flattened_mods_test () {
1488
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1489
                   fn inty() -> i32 { z!() }".to_string();
1490
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1491
        let crate_ast = parse::parse_crate_from_source_str(
1492
            "<test>".to_string(),
1493
            src,
E
Eduard Burtescu 已提交
1494
            Vec::new(), &sess);
1495
        expand_crate(&sess, test_ecfg(), vec!(), vec!(), &mut vec![], crate_ast);
J
John Clements 已提交
1496 1497
    }

1498
    fn expand_crate_str(crate_str: String) -> ast::Crate {
1499
        let ps = parse::ParseSess::new();
1500
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1501
        // the cfg argument actually does matter, here...
1502
        expand_crate(&ps,test_ecfg(),vec!(),vec!(), &mut vec![], crate_ast).0
1503 1504
    }

1505 1506
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1507
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1508
        visit::walk_crate(&mut name_finder, the_crate);
1509 1510 1511
        name_finder.ident_accumulator
    }

1512
    #[test] fn macro_tokens_should_match(){
1513
        expand_crate_str(
1514
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1515 1516
    }

1517 1518 1519
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1520 1521
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1522 1523 1524
            );
    }

1525 1526 1527 1528 1529 1530 1531
    // renaming tests expand a crate and then check that the bindings match
    // the right varrefs. The specification of the test case includes the
    // text of the crate, and also an array of arrays.  Each element in the
    // outer array corresponds to a binding in the traversal of the AST
    // induced by visit.  Each of these arrays contains a list of indexes,
    // interpreted as the varrefs in the varref traversal that this binding
    // should match.  So, for instance, in a program with two bindings and
1532
    // three varrefs, the array [[1, 2], [0]] would indicate that the first
1533 1534 1535
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1536 1537 1538 1539 1540 1541
    // Put differently; this is a sparse representation of a boolean matrix
    // indicating which bindings capture which identifiers.
    //
    // Note also that this matrix is dependent on the implicit ordering of
    // the bindings and the varrefs discovered by the name-finder and the path-finder.
    //
1542 1543
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1544
    //
1545
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1546 1547 1548 1549 1550
    // not just "do these have the same name", but "do they have the same
    // name *and* the same marks"? Understanding this is really pretty painful.
    // in principle, you might want to control this boolean on a per-varref basis,
    // but that would make things even harder to understand, and might not be
    // necessary for thorough testing.
P
Paul Collier 已提交
1551
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1552

1553 1554
    #[test]
    fn automatic_renaming () {
1555 1556
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1557
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1558
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1559
                // both x's should be renamed (how is this causing a bug?)
1560
                ("fn main () {let x: i32 = 13;x;}",
1561
                 vec!(vec!(0)), false),
1562
                // the use of b after the + should be renamed, the other one not:
1563
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1564
                 vec!(vec!(1)), false),
J
John Clements 已提交
1565
                // the b before the plus should not be renamed (requires marks)
1566
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1567
                 vec!(vec!(1)), false),
1568 1569 1570
                // the marks going in and out of letty should cancel, allowing that $x to
                // capture the one following the semicolon.
                // this was an awesome test case, and caught a *lot* of bugs.
1571 1572
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1573
                  fn main() -> i32 {user!(z)}",
1574 1575
                 vec!(vec!(0)), false)
                );
1576 1577
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
1578 1579 1580
        }
    }

1581 1582 1583 1584 1585
    // no longer a fixme #8062: this test exposes a *potential* bug; our system does
    // not behave exactly like MTWT, but a conversation with Matthew Flatt
    // suggests that this can only occur in the presence of local-expand, which
    // we have no plans to support. ... unless it's needed for item hygiene....
    #[ignore]
R
Richo Healey 已提交
1586 1587
    #[test]
    fn issue_8062(){
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
        run_renaming_test(
            &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
              vec!(vec!(0)), true), 0)
    }

    // FIXME #6994:
    // the z flows into and out of two macros (g & f) along one path, and one
    // (just g) along the other, so the result of the whole thing should
    // be "let z_123 = 3; z_123"
    #[ignore]
R
Richo Healey 已提交
1598 1599
    #[test]
    fn issue_6994(){
1600 1601
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
1602
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1603 1604 1605
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
1606 1607
    }

1608
    // match variable hygiene. Should expand into
1609
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
1610 1611
    #[test]
    fn issue_9384(){
1612
        run_renaming_test(
1613
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1614
              fn z() {match 8 {x => bad_macro!(x)}}",
1615
              // NB: the third "binding" is the repeat of the second one.
1616
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1617 1618
              true),
            0)
1619 1620
    }

1621
    // interpolated nodes weren't getting labeled.
1622 1623
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
1624 1625
    #[test]
    fn pat_expand_issue_15221(){
1626
        run_renaming_test(
1627 1628
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
1629 1630 1631 1632 1633 1634
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

1635
    // create a really evil test case where a $x appears inside a binding of $x
J
Joseph Crail 已提交
1636
    // but *shouldn't* bind because it was inserted by a different macro....
1637 1638
    // can't write this test case until we have macro-generating macros.

1639
    // method arg hygiene
1640
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
1641 1642
    #[test]
    fn method_arg_hygiene(){
1643
        run_renaming_test(
1644 1645
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
1646
              struct A;
1647
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1648 1649 1650 1651 1652
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
1653 1654
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
1655 1656
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
1657 1658 1659
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
1660 1661
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
1662 1663 1664 1665 1666
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
1667
    // item fn hygiene
1668
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
1669 1670
    #[test]
    fn issue_9383(){
1671
        run_renaming_test(
1672 1673
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
1674
              vec!(vec!(1),vec!(0)),true),
1675
            0)
1676
    }
1677

1678
    // closure arg hygiene (ExprClosure)
1679
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
1680 1681
    #[test]
    fn closure_arg_hygiene(){
1682
        run_renaming_test(
1683
            &("macro_rules! inject_x (()=>(x));
1684
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1685 1686 1687 1688 1689
              vec!(vec!(1)),
              true),
            0)
    }

1690
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
1691 1692
    #[test]
    fn macro_in_method_posn(){
1693
        expand_crate_str(
1694
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1695
            struct A;
1696
            impl A{ my_method!(); }
1697 1698 1699
            fn f(){A.thirteen;}".to_string());
    }

1700 1701
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
1702 1703
    #[test]
    fn item_macro_workaround(){
1704 1705 1706 1707
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
1708
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1709 1710 1711 1712 1713
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
1714
    // run one of the renaming tests
P
Paul Collier 已提交
1715
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
1716
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
1717
        let (teststr, bound_connections, bound_ident_check) = match *t {
1718
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1719
        };
1720
        let cr = expand_crate_str(teststr.to_string());
1721 1722
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
1723

1724 1725 1726
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1727 1728
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1729
            // shouldmatch can't name varrefs that don't exist:
1730
            assert!((shouldmatch.is_empty()) ||
1731 1732
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
1733
                let print_hygiene_debug_info = || {
J
John Clements 已提交
1734 1735 1736
                    // good lord, you can't make a path with 0 segments, can you?
                    let final_varref_ident = match varref.segments.last() {
                        Some(pathsegment) => pathsegment.identifier,
S
Steve Klabnik 已提交
1737
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
1738 1739 1740 1741 1742
                    };
                    let varref_name = mtwt::resolve(final_varref_ident);
                    let varref_idents : Vec<ast::Ident>
                        = varref.segments.iter().map(|s| s.identifier)
                        .collect();
A
Alex Crichton 已提交
1743
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
1744
                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
J
John Clements 已提交
1745
                    println!("binding #{}: {}, resolves to {}",
1746
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
1747 1748
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
1749 1750
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
1751
                    // be free-identifier=? or bound-identifier=? to the given binding
1752
                    assert_eq!(varref.segments.len(),1);
1753 1754
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
1755 1756 1757
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
1758
                    if !(varref_name==binding_name) {
1759
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
1760
                        print_hygiene_debug_info();
1761 1762
                    }
                    assert_eq!(varref_name,binding_name);
1763
                    if bound_ident_check {
J
John Clements 已提交
1764 1765
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
1766 1767
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
1768
                } else {
1769
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
1770
                    let fail = (varref.segments.len() == 1)
1771
                        && (varref_name == binding_name);
1772
                    // temp debugging:
1773
                    if fail {
1774 1775 1776 1777
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
1778
                        print_hygiene_debug_info();
1779 1780 1781 1782
                    }
                    assert!(!fail);
                }
            }
1783 1784
        }
    }
1785

R
Richo Healey 已提交
1786 1787
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
1788 1789 1790
        let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
foo_module!();
1791
".to_string();
J
John Clements 已提交
1792 1793
        let cr = expand_crate_str(crate_str);
        // find the xx binding
1794
        let bindings = crate_bindings(&cr);
1795
        let cxbinds: Vec<&ast::Ident> =
1796
            bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
1797
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
1798 1799
        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
            (1, Some(b)) => *b,
S
Steve Klabnik 已提交
1800
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
1801
        };
1802
        let resolved_binding = mtwt::resolve(*cxbind);
1803
        let varrefs = crate_varrefs(&cr);
1804

J
John Clements 已提交
1805
        // the xx binding should bind all of the xx varrefs:
1806
        for (idx,v) in varrefs.iter().filter(|p| {
1807
            p.segments.len() == 1
1808
            && p.segments[0].identifier.name.as_str() == "xx"
1809
        }).enumerate() {
1810
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1811
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
1812 1813 1814
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
1815
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
1816
                println!("resolves to: {}",
1817
                         mtwt::resolve(v.segments[0].identifier));
1818
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
1819
            }
1820
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
1821
                       resolved_binding);
J
John Clements 已提交
1822 1823 1824
        };
    }

J
John Clements 已提交
1825 1826
    #[test]
    fn pat_idents(){
1827
        let pat = string_to_pat(
1828
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
S
Seo Sanghyeon 已提交
1829
        let idents = pattern_bindings(&pat);
1830
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
1831
    }
J
John Clements 已提交
1832

1833 1834 1835
    // test the list of identifier patterns gathered by the visitor. Note that
    // 'None' is listed as an identifier pattern because we don't yet know that
    // it's the name of a 0-ary variant, and that 'i' appears twice in succession.
1836
    #[test]
1837
    fn crate_bindings_test(){
1838
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
1839
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
1840 1841
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
1842 1843
    }

1844 1845 1846
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
1847
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1848 1849
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1850
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1851
        let renames = vec!((x_ident,Name(16)));
1852 1853 1854 1855
        let mut renamer = IdentRenamer{renames: &renames};
        let renamed_crate = renamer.fold_crate(the_crate);
        let idents = crate_idents(&renamed_crate);
        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
1856
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
1857 1858 1859 1860 1861
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
1862
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1863 1864
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1865
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1866
        let renames = vec!((x_ident,Name(16)));
1867 1868 1869 1870 1871
        let mut renamer = PatIdentRenamer{renames: &renames};
        let renamed_crate = renamer.fold_crate(the_crate);
        let idents = crate_idents(&renamed_crate);
        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
        let x_name = x_ident.name;
1872
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
1873
    }
J
John Clements 已提交
1874
}