expand.rs 72.1 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, DeclKind, 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
        None => {
N
Nick Cameron 已提交
204
            let mut err = fld.cx.struct_span_err(
205 206 207
                pth.span,
                &format!("macro undefined: '{}!'",
                        &extname));
N
Nick Cameron 已提交
208 209
            fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err);
            err.emit();
J
John Clements 已提交
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 241
            // 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 => {
242 243
                        fld.cx.span_err(
                            pth.span,
244 245 246 247
                            &format!("non-expression macro in expression position: {}",
                                    extname
                                    ));
                        return None;
248
                    }
249 250 251 252 253 254 255 256 257
                };
                Some(mark_thunk(parsed,fm))
            }
            _ => {
                fld.cx.span_err(
                    pth.span,
                    &format!("'{}' is not a tt-style macro",
                            extname));
                None
J
John Clements 已提交
258 259 260 261 262
            }
        }
    }
}

263 264 265 266 267
/// 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.
268 269 270
fn expand_loop_block(loop_block: P<Block>,
                     opt_ident: Option<Ident>,
                     fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
E
Edward Wang 已提交
271 272
    match opt_ident {
        Some(label) => {
273
            let new_label = fresh_name(label);
E
Edward Wang 已提交
274
            let rename = (label, new_label);
275 276 277 278 279 280

            // 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);
281
            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
282 283 284 285 286
            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.
287 288
            fld.cx.syntax_env.push_frame();
            fld.cx.syntax_env.info().pending_renames.push(rename);
289
            let expanded_block = expand_block_elts(loop_block, fld);
290
            fld.cx.syntax_env.pop_frame();
291 292

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

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

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

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

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

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

        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 已提交
359 360
}

361 362
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
363 364
pub fn expand_item_mac(it: P<ast::Item>,
                       fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
365 366 367
    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),
368
        _ => fld.cx.span_bug(it.span, "invalid item macro invocation")
369
    });
370

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

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

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

442
                    let allow_internal_unstable = attr::contains_name(&attrs,
443 444 445 446 447 448 449 450 451
                                                                      "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",
452
                            span,
453
                            feature_gate::GateIssue::Language,
454 455 456
                            feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
                    }

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

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

484
        expanded.make_items()
485
    };
486

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

502
    fld.cx.bt_pop();
503
    items
504 505
}

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

514
    // Assert that we drop any macro attributes on the floor here
515
    drop(attrs);
516

517 518 519 520 521 522
    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);

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

535 536
    // If this is a macro invocation with a semicolon, then apply that
    // semicolon to the final statement produced by expansion.
537
    if style == MacStmtWithSemicolon {
538 539 540 541 542 543 544 545 546 547 548
        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);
549
        }
550
    }
551 552

    fully_expanded
553 554
}

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

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

635
    // apply renaming and then expansion to the guard and the body:
636 637 638 639 640 641 642 643 644 645
    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 已提交
646
    ast::Arm {
647
        attrs: fold::fold_attrs(arm.attrs, fld),
648 649 650
        pats: rewritten_pats,
        guard: rewritten_guard,
        body: rewritten_body,
J
John Clements 已提交
651
    }
J
John Clements 已提交
652 653
}

654 655 656 657 658 659 660 661 662
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 已提交
663
    let idents = pattern_bindings(&pats[0]);
664 665 666 667 668 669 670 671 672
    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)
}

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

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

697
/// find the PatIdent paths in a pattern
698
fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
699
    let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
700
    name_finder.visit_pat(pat);
701
    name_finder.ident_accumulator
702 703
}

J
John Clements 已提交
704 705 706
/// 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()};
707
    for arg in &fn_decl.inputs {
S
Seo Sanghyeon 已提交
708
        pat_idents.visit_pat(&arg.pat);
J
John Clements 已提交
709 710 711 712
    }
    pat_idents.ident_accumulator
}

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

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

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

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

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

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

818 819 820
        let fully_expanded =
            fld.fold_pat(marked_after).node.clone();
        fld.cx.bt_pop();
K
Keegan McAllister 已提交
821

822 823 824 825 826 827
        ast::Pat {
            id: ast::DUMMY_NODE_ID,
            node: fully_expanded,
            span: span
        }
    })
K
Keegan McAllister 已提交
828 829
}

J
John Clements 已提交
830 831 832
/// 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)
833
pub struct IdentRenamer<'a> {
834
    renames: &'a mtwt::RenameList,
835 836
}

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

J
John Clements 已提交
846 847 848 849 850 851 852 853 854
/// 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> {
855
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
856
        match pat.node {
857 858 859 860 861 862
            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) => {
863 864
                let new_ident = Ident::new(ident.name,
                                           mtwt::apply_renames(self.renames, ident.ctxt));
J
John Clements 已提交
865 866
                let new_node =
                    ast::PatIdent(binding_mode,
867
                                  Spanned{span: self.new_span(sp), node: new_ident},
J
John Clements 已提交
868
                                  sub.map(|p| self.fold_pat(p)));
869 870
                ast::Pat {
                    id: id,
J
John Clements 已提交
871
                    node: new_node,
872
                    span: self.new_span(span)
J
John Clements 已提交
873 874
                }
            },
875 876
            _ => unreachable!()
        })
877
    }
K
Keegan McAllister 已提交
878 879
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
J
John Clements 已提交
880
    }
K
Kevin Atkinson 已提交
881 882
}

883 884 885 886 887 888 889
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();
890
    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
891 892 893 894 895 896 897 898 899 900 901 902 903

    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);
                }
904
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
                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()
            }
        },
921

922
        Annotatable::TraitItem(it) => match it.node {
923 924 925 926 927 928 929 930 931
            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))
                    }
932
                    _ => unreachable!()
933 934 935 936 937 938
                },
                span: fld.new_span(ti.span)
            })),
            _ => fold::noop_fold_trait_item(it, fld)
        }.into_iter().map(Annotatable::TraitItem).collect(),

939
        Annotatable::ImplItem(ii) => {
940
            expand_impl_item(ii, fld).into_iter().map(Annotatable::ImplItem).collect()
941 942 943
        }
    };

944
    new_items.push_all(decorator_items);
945 946 947
    new_items
}

948 949 950 951 952 953 954 955
// 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| {
956
                match fld.cx.syntax_env.find(intern(&attr.name())) {
957 958 959 960 961 962 963
                    Some(rc) => match *rc {
                        $variant(..) => true,
                        _ => false
                    },
                    _ => false
                }
            })
964
        }
965
    }
966 967
}

968 969 970 971 972 973 974 975 976
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 已提交
977
        let mname = intern(&attr.name());
978
        match fld.cx.syntax_env.find(mname) {
979
            Some(rc) => match *rc {
980 981 982 983 984 985
                MultiDecorator(ref dec) => {
                    attr::mark_used(&attr);

                    fld.cx.bt_push(ExpnInfo {
                        call_site: attr.span,
                        callee: NameAndSpan {
M
Manish Goregaokar 已提交
986
                            format: MacroAttribute(mname),
987 988 989 990 991 992 993 994 995 996 997 998 999
                            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,
1000
                               &a,
1001 1002 1003 1004 1005 1006 1007
                               &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()),
1008
            },
1009
            _ => new_attrs.push((*attr).clone()),
1010
        }
1011
    }
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
}

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
    }

1026
    for attr in &modifiers {
M
Manish Goregaokar 已提交
1027
        let mname = intern(&attr.name());
1028

1029
        match fld.cx.syntax_env.find(mname) {
1030 1031 1032 1033 1034 1035
            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 已提交
1036
                            format: MacroAttribute(mname),
1037
                            span: Some(attr.span),
1038 1039 1040
                            // attributes can do whatever they like,
                            // for now
                            allow_internal_unstable: true,
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
                        }
                    });
                    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)
}

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

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

J
John Clements 已提交
1100 1101 1102
/// 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.
1103
fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
J
John Clements 已提交
1104
                                       fld: &mut MacroExpander)
1105
                                       -> (P<ast::FnDecl>, P<ast::Block>) {
J
John Clements 已提交
1106
    let expanded_decl = fld.fold_fn_decl(fn_decl);
S
Seo Sanghyeon 已提交
1107
    let idents = fn_decl_arg_bindings(&expanded_decl);
J
John Clements 已提交
1108
    let renames =
1109
        idents.iter().map(|id| (*id,fresh_name(*id))).collect();
J
John Clements 已提交
1110 1111
    // first, a renamer for the PatIdents, for the fn_decl:
    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
1112
    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
J
John Clements 已提交
1113 1114 1115 1116 1117 1118
    // 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)
}

1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
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 已提交
1129
        constness: sig.constness,
1130 1131 1132 1133
        decl: rewritten_fn_decl
    }, rewritten_body)
}

1134 1135 1136
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 已提交
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
            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);
                    }
                };
1147

J
Jared Roesch 已提交
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
                // 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,
1162 1163
                    feature_gate::GateIssue::Language,
                    "type macros are experimental");
J
Jared Roesch 已提交
1164 1165

                DummyResult::raw_ty(t.span)
J
Jared Roesch 已提交
1166
            }
1167 1168 1169
        }
        _ => t
    };
J
Jared Roesch 已提交
1170

1171 1172 1173
    fold::noop_fold_ty(t, fld)
}

J
John Clements 已提交
1174
/// A tree-folder that performs macro expansion
1175
pub struct MacroExpander<'a, 'b:'a> {
1176
    pub cx: &'a mut ExtCtxt<'b>,
N
Nick Cameron 已提交
1177 1178 1179 1180
}

impl<'a, 'b> MacroExpander<'a, 'b> {
    pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1181
        MacroExpander { cx: cx }
N
Nick Cameron 已提交
1182
    }
1183 1184
}

E
Eduard Burtescu 已提交
1185
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1186
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1187
        expand_expr(expr, self)
1188 1189
    }

1190
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1191 1192 1193
        expand_pat(pat, self)
    }

1194
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1195
        expand_item(item, self)
1196 1197
    }

1198
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
J
John Clements 已提交
1199 1200 1201
        expand_item_underscore(item, self)
    }

1202
    fn fold_stmt(&mut self, stmt: P<ast::Stmt>) -> SmallVector<P<ast::Stmt>> {
1203
        expand_stmt(stmt, self)
1204 1205
    }

S
Steven Fackler 已提交
1206
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1207
        expand_block(block, self)
1208 1209
    }

1210
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1211 1212 1213
        expand_arm(arm, self)
    }

1214 1215 1216
    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()
1217 1218
    }

1219 1220 1221
    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()
1222 1223
    }

1224 1225 1226 1227
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
        expand_type(ty, self)
    }

S
Steven Fackler 已提交
1228
    fn new_span(&mut self, span: Span) -> Span {
1229 1230
        new_span(self.cx, span)
    }
1231 1232
}

J
John Clements 已提交
1233 1234 1235 1236 1237
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,
1238
        expn_id: cx.backtrace(),
J
John Clements 已提交
1239 1240 1241
    }
}

1242
pub struct ExpansionConfig<'feat> {
1243
    pub crate_name: String,
1244
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1245
    pub recursion_limit: usize,
1246
    pub trace_mac: bool,
1247 1248
}

1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1262 1263
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1264 1265
        ExpansionConfig {
            crate_name: crate_name,
1266
            features: None,
1267
            recursion_limit: 64,
1268
            trace_mac: false,
1269 1270
        }
    }
1271

1272 1273 1274 1275 1276 1277 1278
    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,
1279
        fn enable_custom_derive = allow_custom_derive,
1280
        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
1281
    }
1282 1283
}

1284 1285 1286 1287 1288
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 已提交
1289 1290 1291 1292 1293 1294 1295
    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");
    }
1296 1297
    let ret = {
        let mut expander = MacroExpander::new(&mut cx);
1298

1299 1300 1301
        for def in imported_macros {
            expander.cx.insert_macro(def);
        }
1302

1303 1304 1305
        for (name, extension) in user_exts {
            expander.cx.syntax_env.insert(name, extension);
        }
1306

N
Nick Cameron 已提交
1307
        let err_count = cx.parse_sess.span_diagnostic.err_count();
1308 1309
        let mut ret = expander.fold_crate(c);
        ret.exported_macros = expander.cx.exported_macros.clone();
N
Nick Cameron 已提交
1310 1311 1312 1313 1314

        if cx.parse_sess.span_diagnostic.err_count() > err_count {
            cx.parse_sess.span_diagnostic.abort_if_errors();
        }

1315 1316 1317
        ret
    };
    return (ret, cx.syntax_env.names);
1318
}
J
John Clements 已提交
1319

1320 1321 1322 1323 1324 1325 1326 1327
// 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 已提交
1328 1329
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1330

E
Eduard Burtescu 已提交
1331
impl Folder for Marker {
1332
    fn fold_ident(&mut self, id: Ident) -> Ident {
1333
        ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
1334
    }
1335
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1336
        Spanned {
1337 1338 1339 1340
            node: Mac_ {
                path: self.fold_path(node.path),
                tts: self.fold_tts(&node.tts),
                ctxt: mtwt::apply_mark(self.mark, node.ctxt),
1341 1342
            },
            span: span,
1343
        }
1344 1345 1346
    }
}

1347
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1348
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1349
    noop_fold_tts(tts, &mut Marker{mark:m})
1350 1351 1352
}

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

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

1362
// apply a given mark to the given stmt. Used following the expansion of a macro.
1363 1364
fn mark_stmt(stmt: P<ast::Stmt>, m: Mrk) -> P<ast::Stmt> {
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1365
        .expect_one("marking a stmt didn't return exactly one stmt")
1366 1367 1368
}

// apply a given mark to the given item. Used following the expansion of a macro.
1369
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1370
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1371 1372 1373 1374
        .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.
1375
fn mark_impl_item(ii: P<ast::ImplItem>, m: Mrk) -> P<ast::ImplItem> {
1376
    Marker{mark:m}.fold_impl_item(ii)
1377
        .expect_one("marking an impl item didn't return exactly one impl item")
1378 1379
}

1380 1381 1382 1383
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
    Marker { mark: m }.fold_ty(ty)
}

J
John Clements 已提交
1384 1385
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1386
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1387 1388 1389 1390 1391 1392 1393
}

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

1394
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1395 1396
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1397 1398 1399 1400 1401 1402
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1403
#[cfg(test)]
1404
mod tests {
A
Alex Crichton 已提交
1405
    use super::{pattern_bindings, expand_crate};
1406
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1407
    use ast;
J
Jorge Aparicio 已提交
1408
    use ast::Name;
1409
    use codemap;
S
Seo Sanghyeon 已提交
1410
    use ext::base::ExtCtxt;
1411
    use ext::mtwt;
1412
    use fold::Folder;
1413
    use parse;
1414
    use parse::token;
E
Eduard Burtescu 已提交
1415
    use util::parser_testing::{string_to_parser};
1416
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1417
    use visit;
1418 1419 1420 1421 1422
    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)
1423
    #[derive(Clone)]
1424
    struct PathExprFinderContext {
1425
        path_accumulator: Vec<ast::Path> ,
1426 1427
    }

1428
    impl<'v> Visitor<'v> for PathExprFinderContext {
1429
        fn visit_expr(&mut self, expr: &ast::Expr) {
1430 1431
            if let ast::ExprPath(None, ref p) = expr.node {
                self.path_accumulator.push(p.clone());
1432
            }
1433
            visit::walk_expr(self, expr);
1434 1435 1436
        }
    }

1437 1438 1439
    // 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()};
1440
        visit::walk_crate(&mut path_finder, the_crate);
1441
        path_finder.path_accumulator
1442
    }
J
John Clements 已提交
1443

1444 1445
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1446
    struct IdentFinder {
1447 1448
        ident_accumulator: Vec<ast::Ident>
    }
1449

1450
    impl<'v> Visitor<'v> for IdentFinder {
1451
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1452 1453 1454 1455 1456 1457 1458
            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()};
1459
        visit::walk_crate(&mut ident_finder, the_crate);
1460 1461
        ident_finder.ident_accumulator
    }
1462

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

1466
    fn test_ecfg() -> ExpansionConfig<'static> {
1467 1468 1469
        ExpansionConfig::default("test".to_string())
    }

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

J
John Clements 已提交
1486
    // make sure that macros can't escape modules
1487
    #[should_panic]
J
John Clements 已提交
1488
    #[test] fn macros_cant_escape_mods_test () {
1489
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1490
                   fn inty() -> i32 { z!() }".to_string();
1491
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1492
        let crate_ast = parse::parse_crate_from_source_str(
1493
            "<test>".to_string(),
1494
            src,
E
Eduard Burtescu 已提交
1495
            Vec::new(), &sess);
S
Seo Sanghyeon 已提交
1496 1497 1498
        let mut gated_cfgs = vec![];
        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
        expand_crate(ecx, vec![], vec![], crate_ast);
J
John Clements 已提交
1499 1500
    }

1501
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1502
    #[test] fn macros_can_escape_flattened_mods_test () {
1503
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1504
                   fn inty() -> i32 { z!() }".to_string();
1505
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1506
        let crate_ast = parse::parse_crate_from_source_str(
1507
            "<test>".to_string(),
1508
            src,
E
Eduard Burtescu 已提交
1509
            Vec::new(), &sess);
S
Seo Sanghyeon 已提交
1510 1511 1512
        let mut gated_cfgs = vec![];
        let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs);
        expand_crate(ecx, vec![], vec![], crate_ast);
J
John Clements 已提交
1513 1514
    }

1515
    fn expand_crate_str(crate_str: String) -> ast::Crate {
1516
        let ps = parse::ParseSess::new();
1517
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1518
        // the cfg argument actually does matter, here...
S
Seo Sanghyeon 已提交
1519 1520 1521
        let mut gated_cfgs = vec![];
        let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs);
        expand_crate(ecx, vec![], vec![], crate_ast).0
1522 1523
    }

1524 1525
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1526
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1527
        visit::walk_crate(&mut name_finder, the_crate);
1528 1529 1530
        name_finder.ident_accumulator
    }

1531
    #[test] fn macro_tokens_should_match(){
1532
        expand_crate_str(
1533
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1534 1535
    }

1536 1537 1538
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1539 1540
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1541 1542 1543
            );
    }

1544 1545 1546 1547 1548 1549 1550
    // 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
1551
    // three varrefs, the array [[1, 2], [0]] would indicate that the first
1552 1553 1554
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1555 1556 1557 1558 1559 1560
    // 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.
    //
1561 1562
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1563
    //
1564
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1565 1566 1567 1568 1569
    // 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 已提交
1570
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1571

1572 1573
    #[test]
    fn automatic_renaming () {
1574 1575
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1576
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1577
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1578
                // both x's should be renamed (how is this causing a bug?)
1579
                ("fn main () {let x: i32 = 13;x;}",
1580
                 vec!(vec!(0)), false),
1581
                // the use of b after the + should be renamed, the other one not:
1582
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1583
                 vec!(vec!(1)), false),
J
John Clements 已提交
1584
                // the b before the plus should not be renamed (requires marks)
1585
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1586
                 vec!(vec!(1)), false),
1587 1588 1589
                // 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.
1590 1591
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1592
                  fn main() -> i32 {user!(z)}",
1593 1594
                 vec!(vec!(0)), false)
                );
1595 1596
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
1597 1598 1599
        }
    }

1600 1601 1602 1603 1604
    // 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 已提交
1605 1606
    #[test]
    fn issue_8062(){
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
        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 已提交
1617 1618
    #[test]
    fn issue_6994(){
1619 1620
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
1621
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1622 1623 1624
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
1625 1626
    }

1627
    // match variable hygiene. Should expand into
1628
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
1629 1630
    #[test]
    fn issue_9384(){
1631
        run_renaming_test(
1632
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1633
              fn z() {match 8 {x => bad_macro!(x)}}",
1634
              // NB: the third "binding" is the repeat of the second one.
1635
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1636 1637
              true),
            0)
1638 1639
    }

1640
    // interpolated nodes weren't getting labeled.
1641 1642
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
1643 1644
    #[test]
    fn pat_expand_issue_15221(){
1645
        run_renaming_test(
1646 1647
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
1648 1649 1650 1651 1652 1653
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

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

1658
    // method arg hygiene
1659
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
1660 1661
    #[test]
    fn method_arg_hygiene(){
1662
        run_renaming_test(
1663 1664
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
1665
              struct A;
1666
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1667 1668 1669 1670 1671
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
1672 1673
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
1674 1675
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
1676 1677 1678
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
1679 1680
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
1681 1682 1683 1684 1685
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
1686
    // item fn hygiene
1687
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
1688 1689
    #[test]
    fn issue_9383(){
1690
        run_renaming_test(
1691 1692
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
1693
              vec!(vec!(1),vec!(0)),true),
1694
            0)
1695
    }
1696

1697
    // closure arg hygiene (ExprClosure)
1698
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
1699 1700
    #[test]
    fn closure_arg_hygiene(){
1701
        run_renaming_test(
1702
            &("macro_rules! inject_x (()=>(x));
1703
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1704 1705 1706 1707 1708
              vec!(vec!(1)),
              true),
            0)
    }

1709
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
1710 1711
    #[test]
    fn macro_in_method_posn(){
1712
        expand_crate_str(
1713
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1714
            struct A;
1715
            impl A{ my_method!(); }
1716 1717 1718
            fn f(){A.thirteen;}".to_string());
    }

1719 1720
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
1721 1722
    #[test]
    fn item_macro_workaround(){
1723 1724 1725 1726
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
1727
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1728 1729 1730 1731 1732
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
1733
    // run one of the renaming tests
P
Paul Collier 已提交
1734
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
1735
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
1736
        let (teststr, bound_connections, bound_ident_check) = match *t {
1737
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1738
        };
1739
        let cr = expand_crate_str(teststr.to_string());
1740 1741
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
1742

1743 1744 1745
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1746 1747
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1748
            // shouldmatch can't name varrefs that don't exist:
1749
            assert!((shouldmatch.is_empty()) ||
1750 1751
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
1752
                let print_hygiene_debug_info = || {
J
John Clements 已提交
1753 1754 1755
                    // 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 已提交
1756
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
1757 1758 1759 1760 1761
                    };
                    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 已提交
1762
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
1763
                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
J
John Clements 已提交
1764
                    println!("binding #{}: {}, resolves to {}",
1765
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
1766 1767
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
1768 1769
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
1770
                    // be free-identifier=? or bound-identifier=? to the given binding
1771
                    assert_eq!(varref.segments.len(),1);
1772 1773
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
1774 1775 1776
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
1777
                    if !(varref_name==binding_name) {
1778
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
1779
                        print_hygiene_debug_info();
1780 1781
                    }
                    assert_eq!(varref_name,binding_name);
1782
                    if bound_ident_check {
J
John Clements 已提交
1783 1784
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
1785 1786
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
1787
                } else {
1788
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
1789
                    let fail = (varref.segments.len() == 1)
1790
                        && (varref_name == binding_name);
1791
                    // temp debugging:
1792
                    if fail {
1793 1794 1795 1796
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
1797
                        print_hygiene_debug_info();
1798 1799 1800 1801
                    }
                    assert!(!fail);
                }
            }
1802 1803
        }
    }
1804

R
Richo Healey 已提交
1805 1806
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
1807 1808 1809
        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!();
1810
".to_string();
J
John Clements 已提交
1811 1812
        let cr = expand_crate_str(crate_str);
        // find the xx binding
1813
        let bindings = crate_bindings(&cr);
1814
        let cxbinds: Vec<&ast::Ident> =
1815
            bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
1816
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
1817 1818
        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
            (1, Some(b)) => *b,
S
Steve Klabnik 已提交
1819
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
1820
        };
1821
        let resolved_binding = mtwt::resolve(*cxbind);
1822
        let varrefs = crate_varrefs(&cr);
1823

J
John Clements 已提交
1824
        // the xx binding should bind all of the xx varrefs:
1825
        for (idx,v) in varrefs.iter().filter(|p| {
1826
            p.segments.len() == 1
1827
            && p.segments[0].identifier.name.as_str() == "xx"
1828
        }).enumerate() {
1829
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1830
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
1831 1832 1833
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
1834
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
1835
                println!("resolves to: {}",
1836
                         mtwt::resolve(v.segments[0].identifier));
1837
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
1838
            }
1839
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
1840
                       resolved_binding);
J
John Clements 已提交
1841 1842 1843
        };
    }

J
John Clements 已提交
1844 1845
    #[test]
    fn pat_idents(){
1846
        let pat = string_to_pat(
1847
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
S
Seo Sanghyeon 已提交
1848
        let idents = pattern_bindings(&pat);
1849
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
1850
    }
J
John Clements 已提交
1851

1852 1853 1854
    // 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.
1855
    #[test]
1856
    fn crate_bindings_test(){
1857
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
1858
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
1859 1860
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
1861 1862
    }

1863 1864 1865
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
1866
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1867 1868
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1869
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1870
        let renames = vec!((x_ident,Name(16)));
1871 1872 1873 1874
        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();
1875
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
1876 1877 1878 1879 1880
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
1881
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1882 1883
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1884
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1885
        let renames = vec!((x_ident,Name(16)));
1886 1887 1888 1889 1890
        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;
1891
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
1892
    }
J
John Clements 已提交
1893
}