expand.rs 75.5 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, PatKind};
12
use ast::{Local, Ident, Mac_, Name};
13
use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind};
14
use ast::TokenTree;
15
use ast;
16
use ext::mtwt;
17
use ext::build::AstBuilder;
18
use attr;
19
use attr::{AttrMetaMethods, WithAttrs};
20
use codemap;
21
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
P
Patrick Walton 已提交
22
use ext::base::*;
23
use feature_gate::{self, Features};
J
John Clements 已提交
24
use fold;
25
use fold::*;
M
Marvin Löbel 已提交
26
use util::move_map::MoveMap;
27
use parse;
28
use parse::token::{fresh_mark, fresh_name, intern};
29 30
use ptr::P;
use util::small_vector::SmallVector;
J
John Clements 已提交
31
use visit;
H
Huon Wilson 已提交
32
use visit::Visitor;
33
use std_inject;
34

35
use std::collections::HashSet;
36
use std::env;
37

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

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

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

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

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

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

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

78
            let placer = fld.fold_expr(placer);
79
            let value_expr = fld.fold_expr(value_expr);
80
            fld.cx.expr(span, ast::ExprKind::InPlace(placer, value_expr))
81
                .with_attrs(fold_thin_attrs(attrs, fld))
82 83
        }

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

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

            // 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);

105 106
            let wl = ast::ExprKind::WhileLet(rewritten_pats.remove(0), expr, body, opt_ident);
            fld.cx.expr(span, wl).with_attrs(fold_thin_attrs(attrs, fld))
107 108
        }

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

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

            // 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);

128
            let head = fld.fold_expr(head);
129 130
            let fl = ast::ExprKind::ForLoop(rewritten_pats.remove(0), head, body, opt_ident);
            fld.cx.expr(span, fl).with_attrs(fold_thin_attrs(attrs, fld))
131 132
        }

133
        ast::ExprKind::IfLet(pat, sub_expr, body, else_opt) => {
134 135 136 137 138 139 140 141 142 143 144 145 146 147
            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);
148 149
            let il = ast::ExprKind::IfLet(rewritten_pats.remove(0), sub_expr, body, else_opt);
            fld.cx.expr(span, il).with_attrs(fold_thin_attrs(attrs, fld))
150 151
        }

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

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

J
John Clements 已提交
173 174 175 176
/// 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.
177 178
fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                             span: codemap::Span,
J
Jorge Aparicio 已提交
179 180 181 182
                             parse_thunk: F,
                             mark_thunk: G,
                             fld: &mut MacroExpander)
                             -> Option<T> where
183
    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
J
Jorge Aparicio 已提交
184
    G: FnOnce(T, Mrk) -> T,
185
{
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    // 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;
201
    match fld.cx.syntax_env.find(extname) {
202
        None => {
N
Nick Cameron 已提交
203
            let mut err = fld.cx.struct_span_err(
204 205 206
                pth.span,
                &format!("macro undefined: '{}!'",
                        &extname));
N
Nick Cameron 已提交
207 208
            fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err);
            err.emit();
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
}

318 319
/// Expand item_kind
fn expand_item_kind(item: ast::ItemKind, fld: &mut MacroExpander) -> ast::ItemKind {
320
    match item {
321
        ast::ItemKind::Fn(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
            ast::ItemKind::Fn(rewritten_fn_decl, unsafety, constness, abi,
326
                        expanded_generics, rewritten_body)
J
John Clements 已提交
327
        }
328
        _ => noop_fold_item_kind(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
        let mut is_use = attr.check_name("macro_use");
        if attr.check_name("macro_escape") {
N
Nick Cameron 已提交
337 338 339
            let mut err =
                fld.cx.struct_span_warn(attr.span,
                                        "macro_escape is a deprecated synonym for macro_use");
340
            is_use = true;
341
            if let ast::AttrStyle::Inner = attr.node.style {
N
Nick Cameron 已提交
342 343 344 345
                err.fileline_help(attr.span, "consider an outer attribute, \
                                              #[macro_use] mod ...").emit();
            } else {
                err.emit();
346 347 348 349 350
            }
        };

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

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

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

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

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

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

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

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

483
        expanded.make_items()
484
    };
485

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

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

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

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

515
    let maybe_new_items =
516
        expand_mac_invoc(mac.unwrap(), stmt.span,
517 518 519 520
                         |r| r.make_stmts(),
                         |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
                         fld);

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

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

    fully_expanded
549 550
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

J
John Clements 已提交
842
/// A tree-folder that applies every rename in its list to
843
/// the idents that are in PatKind::Ident patterns. This is more narrowly
J
John Clements 已提交
844 845 846 847 848 849 850
/// 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> {
851
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
J
John Clements 已提交
852
        match pat.node {
853
            PatKind::Ident(..) => {},
854 855 856 857
            _ => return noop_fold_pat(pat, self)
        }

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

879 880 881 882 883 884 885
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();
886
    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
887 888 889

    let mut new_items: SmallVector<Annotatable> = match a {
        Annotatable::Item(it) => match it.node {
890
            ast::ItemKind::Mac(..) => {
891 892
                expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
            }
893
            ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
894 895 896 897 898 899
                let valid_ident =
                    it.ident.name != parse::token::special_idents::invalid.name;

                if valid_ident {
                    fld.cx.mod_push(it.ident);
                }
900
                let macro_use = contains_macro_use(fld, &new_attrs[..]);
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
                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()
            }
        },
917

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

938
        Annotatable::ImplItem(ii) => {
939 940
            expand_impl_item(ii.unwrap(), fld).into_iter().
                map(|ii| Annotatable::ImplItem(P(ii))).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
                    it = mac.expand(fld.cx, attr.span, &attr.node.value, it);
1044 1045 1046 1047 1048 1049 1050 1051
                    fld.cx.bt_pop();
                }
                _ => unreachable!()
            },
            _ => unreachable!()
        }
    }

1052
    // Expansion may have added new ItemKind::Modifiers.
1053 1054 1055
    expand_item_multi_modifier(it, fld)
}

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

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

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

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

1135 1136
pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
    let t = match t.node.clone() {
1137
        ast::TyKind::Mac(mac) => {
J
Jared Roesch 已提交
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
            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);
                    }
                };
1148

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

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

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

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

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

E
Eduard Burtescu 已提交
1186
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
1187 1188 1189 1190 1191
    fn fold_crate(&mut self, c: Crate) -> Crate {
        self.cx.filename = Some(self.cx.parse_sess.codemap().span_to_filename(c.span));
        noop_fold_crate(c, self)
    }

1192
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
1193
        expand_expr(expr, self)
1194 1195
    }

1196
    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
K
Keegan McAllister 已提交
1197 1198 1199
        expand_pat(pat, self)
    }

1200
    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
        use std::mem::replace;
        let result;
        if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
            if item.span.contains(inner) {
                self.push_mod_path(item.ident, &item.attrs);
                result = expand_item(item, self);
                self.pop_mod_path();
            } else {
                let filename = if inner != codemap::DUMMY_SP {
                    Some(self.cx.parse_sess.codemap().span_to_filename(inner))
                } else { None };
                let orig_filename = replace(&mut self.cx.filename, filename);
                let orig_mod_path_stack = replace(&mut self.cx.mod_path_stack, Vec::new());
                result = expand_item(item, self);
                self.cx.filename = orig_filename;
                self.cx.mod_path_stack = orig_mod_path_stack;
            }
        } else {
            result = expand_item(item, self);
        }
        result
1222 1223
    }

1224 1225
    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
        expand_item_kind(item, self)
J
John Clements 已提交
1226 1227
    }

1228
    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
1229
        expand_stmt(stmt, self)
1230 1231
    }

S
Steven Fackler 已提交
1232
    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
1233 1234 1235 1236
        let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
        let result = expand_block(block, self);
        self.cx.in_block = was_in_block;
        result
1237 1238
    }

1239
    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
J
John Clements 已提交
1240 1241 1242
        expand_arm(arm, self)
    }

1243 1244
    fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
        expand_annotatable(Annotatable::TraitItem(P(i)), self)
1245
            .into_iter().map(|i| i.expect_trait_item()).collect()
1246 1247
    }

1248 1249
    fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
        expand_annotatable(Annotatable::ImplItem(P(i)), self)
1250
            .into_iter().map(|i| i.expect_impl_item()).collect()
1251 1252
    }

1253 1254 1255 1256
    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
        expand_type(ty, self)
    }

S
Steven Fackler 已提交
1257
    fn new_span(&mut self, span: Span) -> Span {
1258 1259
        new_span(self.cx, span)
    }
1260 1261
}

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
impl<'a, 'b> MacroExpander<'a, 'b> {
    fn push_mod_path(&mut self, id: Ident, attrs: &[ast::Attribute]) {
        let default_path = id.name.as_str();
        let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
            Some(d) => d,
            None => default_path,
        };
        self.cx.mod_path_stack.push(file_path)
    }

    fn pop_mod_path(&mut self) {
        self.cx.mod_path_stack.pop().unwrap();
    }
}

J
John Clements 已提交
1277
fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
    debug!("new_span(sp={:?})", sp);

    if cx.codemap().more_specific_trace(sp.expn_id, cx.backtrace()) {
        // If the span we are looking at has a backtrace that has more
        // detail than our current backtrace, then we keep that
        // backtrace.  Honestly, I have no idea if this makes sense,
        // because I have no idea why we are stripping the backtrace
        // below. But the reason I made this change is because, in
        // deriving, we were generating attributes with a specific
        // backtrace, which was essential for `#[structural_match]` to
        // be properly supported, but these backtraces were being
        // stripped and replaced with a null backtrace. Sort of
        // unclear why this is the case. --nmatsakis
        debug!("new_span: keeping trace from {:?} because it is more specific",
               sp.expn_id);
        sp
    } else {
        // This discards information in the case of macro-defining macros.
        //
        // The comment above was originally added in
        // b7ec2488ff2f29681fe28691d20fd2c260a9e454 in Feb 2012. I
        // *THINK* the reason we are doing this is because we want to
        // replace the backtrace of the macro contents with the
        // backtrace that contains the macro use. But it's pretty
        // unclear to me. --nmatsakis
        let sp1 = Span {
            lo: sp.lo,
            hi: sp.hi,
            expn_id: cx.backtrace(),
        };
        debug!("new_span({:?}) = {:?}", sp, sp1);
        if sp.expn_id.into_u32() == 0 && env::var_os("NDM").is_some() {
            panic!("NDM");
        }
        sp1
J
John Clements 已提交
1313 1314 1315
    }
}

1316
pub struct ExpansionConfig<'feat> {
1317
    pub crate_name: String,
1318
    pub features: Option<&'feat Features>,
P
Paul Collier 已提交
1319
    pub recursion_limit: usize,
1320
    pub trace_mac: bool,
1321 1322
}

1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
macro_rules! feature_tests {
    ($( fn $getter:ident = $field:ident, )*) => {
        $(
            pub fn $getter(&self) -> bool {
                match self.features {
                    Some(&Features { $field: true, .. }) => true,
                    _ => false,
                }
            }
        )*
    }
}

1336 1337
impl<'feat> ExpansionConfig<'feat> {
    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
1338 1339
        ExpansionConfig {
            crate_name: crate_name,
1340
            features: None,
1341
            recursion_limit: 64,
1342
            trace_mac: false,
1343 1344
        }
    }
1345

1346 1347 1348 1349 1350 1351 1352
    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,
1353
        fn enable_custom_derive = allow_custom_derive,
1354
        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
1355
    }
1356 1357
}

1358 1359 1360 1361 1362
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 已提交
1363 1364 1365 1366 1367 1368 1369
    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");
    }
1370 1371
    let ret = {
        let mut expander = MacroExpander::new(&mut cx);
1372

1373 1374 1375
        for def in imported_macros {
            expander.cx.insert_macro(def);
        }
1376

1377 1378 1379
        for (name, extension) in user_exts {
            expander.cx.syntax_env.insert(name, extension);
        }
1380

N
Nick Cameron 已提交
1381
        let err_count = cx.parse_sess.span_diagnostic.err_count();
1382 1383
        let mut ret = expander.fold_crate(c);
        ret.exported_macros = expander.cx.exported_macros.clone();
N
Nick Cameron 已提交
1384 1385 1386 1387 1388

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

1389 1390 1391
        ret
    };
    return (ret, cx.syntax_env.names);
1392
}
J
John Clements 已提交
1393

1394 1395 1396 1397 1398 1399 1400 1401
// 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 已提交
1402 1403
// A Marker adds the given mark to the syntax context
struct Marker { mark: Mrk }
1404

E
Eduard Burtescu 已提交
1405
impl Folder for Marker {
1406
    fn fold_ident(&mut self, id: Ident) -> Ident {
1407
        ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
1408
    }
1409
    fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
1410
        Spanned {
1411 1412 1413 1414
            node: Mac_ {
                path: self.fold_path(node.path),
                tts: self.fold_tts(&node.tts),
                ctxt: mtwt::apply_mark(self.mark, node.ctxt),
1415 1416
            },
            span: span,
1417
        }
1418 1419 1420
    }
}

1421
// apply a given mark to the given token trees. Used prior to expansion of a macro.
1422
fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
M
Marvin Löbel 已提交
1423
    noop_fold_tts(tts, &mut Marker{mark:m})
1424 1425 1426
}

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

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

1436
// apply a given mark to the given stmt. Used following the expansion of a macro.
1437
fn mark_stmt(stmt: ast::Stmt, m: Mrk) -> ast::Stmt {
1438
    Marker{mark:m}.fold_stmt(stmt)
J
John Clements 已提交
1439
        .expect_one("marking a stmt didn't return exactly one stmt")
1440 1441 1442
}

// apply a given mark to the given item. Used following the expansion of a macro.
1443
fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
J
John Clements 已提交
1444
    Marker{mark:m}.fold_item(expr)
J
John Clements 已提交
1445 1446 1447 1448
        .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.
1449
fn mark_impl_item(ii: ast::ImplItem, m: Mrk) -> ast::ImplItem {
1450
    Marker{mark:m}.fold_impl_item(ii)
1451
        .expect_one("marking an impl item didn't return exactly one impl item")
1452 1453
}

1454 1455 1456 1457
fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
    Marker { mark: m }.fold_ty(ty)
}

J
John Clements 已提交
1458 1459
/// Check that there are no macro invocations left in the AST:
pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
1460
    visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);
J
John Clements 已提交
1461 1462 1463 1464 1465 1466 1467
}

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

1468
impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
K
Keegan McAllister 已提交
1469 1470
    fn visit_mac(&mut self, mac: &ast::Mac) {
        self.sess.span_diagnostic.span_bug(mac.span,
J
John Clements 已提交
1471 1472 1473 1474 1475 1476
                                           "macro exterminator: expected AST \
                                           with no macro invocations");
    }
}


J
John Clements 已提交
1477
#[cfg(test)]
1478
mod tests {
A
Alex Crichton 已提交
1479
    use super::{pattern_bindings, expand_crate};
1480
    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
1481
    use ast;
J
Jorge Aparicio 已提交
1482
    use ast::Name;
1483
    use codemap;
S
Seo Sanghyeon 已提交
1484
    use ext::base::ExtCtxt;
1485
    use ext::mtwt;
1486
    use fold::Folder;
1487
    use parse;
1488
    use parse::token;
E
Eduard Burtescu 已提交
1489
    use util::parser_testing::{string_to_parser};
1490
    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
1491
    use visit;
1492 1493 1494 1495 1496
    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)
1497
    #[derive(Clone)]
1498
    struct PathExprFinderContext {
1499
        path_accumulator: Vec<ast::Path> ,
1500 1501
    }

1502
    impl<'v> Visitor<'v> for PathExprFinderContext {
1503
        fn visit_expr(&mut self, expr: &ast::Expr) {
1504
            if let ast::ExprKind::Path(None, ref p) = expr.node {
1505
                self.path_accumulator.push(p.clone());
1506
            }
1507
            visit::walk_expr(self, expr);
1508 1509 1510
        }
    }

1511 1512 1513
    // 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()};
1514
        visit::walk_crate(&mut path_finder, the_crate);
1515
        path_finder.path_accumulator
1516
    }
J
John Clements 已提交
1517

1518 1519
    /// A Visitor that extracts the identifiers from a thingy.
    // as a side note, I'm starting to want to abstract over these....
1520
    struct IdentFinder {
1521 1522
        ident_accumulator: Vec<ast::Ident>
    }
1523

1524
    impl<'v> Visitor<'v> for IdentFinder {
1525
        fn visit_ident(&mut self, _: codemap::Span, id: ast::Ident){
1526 1527 1528 1529 1530 1531 1532
            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()};
1533
        visit::walk_crate(&mut ident_finder, the_crate);
1534 1535
        ident_finder.ident_accumulator
    }
1536

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

1540
    fn test_ecfg() -> ExpansionConfig<'static> {
1541 1542 1543
        ExpansionConfig::default("test".to_string())
    }

J
John Clements 已提交
1544
    // make sure that macros can't escape fns
1545
    #[should_panic]
J
John Clements 已提交
1546
    #[test] fn macros_cant_escape_fns_test () {
1547
        let src = "fn bogus() {macro_rules! z (() => (3+4));}\
1548
                   fn inty() -> i32 { z!() }".to_string();
1549
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1550
        let crate_ast = parse::parse_crate_from_source_str(
1551
            "<test>".to_string(),
1552
            src,
1553
            Vec::new(), &sess).unwrap();
J
John Clements 已提交
1554
        // should fail:
S
Seo Sanghyeon 已提交
1555 1556 1557
        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 已提交
1558 1559
    }

J
John Clements 已提交
1560
    // make sure that macros can't escape modules
1561
    #[should_panic]
J
John Clements 已提交
1562
    #[test] fn macros_cant_escape_mods_test () {
1563
        let src = "mod foo {macro_rules! z (() => (3+4));}\
1564
                   fn inty() -> i32 { z!() }".to_string();
1565
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1566
        let crate_ast = parse::parse_crate_from_source_str(
1567
            "<test>".to_string(),
1568
            src,
1569
            Vec::new(), &sess).unwrap();
S
Seo Sanghyeon 已提交
1570 1571 1572
        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 已提交
1573 1574
    }

1575
    // macro_use modules should allow macros to escape
J
John Clements 已提交
1576
    #[test] fn macros_can_escape_flattened_mods_test () {
1577
        let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
1578
                   fn inty() -> i32 { z!() }".to_string();
1579
        let sess = parse::ParseSess::new();
J
John Clements 已提交
1580
        let crate_ast = parse::parse_crate_from_source_str(
1581
            "<test>".to_string(),
1582
            src,
1583
            Vec::new(), &sess).unwrap();
S
Seo Sanghyeon 已提交
1584 1585 1586
        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 已提交
1587 1588
    }

1589
    fn expand_crate_str(crate_str: String) -> ast::Crate {
1590
        let ps = parse::ParseSess::new();
1591
        let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
1592
        // the cfg argument actually does matter, here...
S
Seo Sanghyeon 已提交
1593 1594 1595
        let mut gated_cfgs = vec![];
        let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs);
        expand_crate(ecx, vec![], vec![], crate_ast).0
1596 1597
    }

1598 1599
    // find the pat_ident paths in a crate
    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
1600
        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
1601
        visit::walk_crate(&mut name_finder, the_crate);
1602 1603 1604
        name_finder.ident_accumulator
    }

1605
    #[test] fn macro_tokens_should_match(){
1606
        expand_crate_str(
1607
            "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
1608 1609
    }

1610 1611 1612
    // should be able to use a bound identifier as a literal in a macro definition:
    #[test] fn self_macro_parsing(){
        expand_crate_str(
1613 1614
            "macro_rules! foo ((zz) => (287;));
            fn f(zz: i32) {foo!(zz);}".to_string()
1615 1616 1617
            );
    }

1618 1619 1620 1621 1622 1623 1624
    // 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
1625
    // three varrefs, the array [[1, 2], [0]] would indicate that the first
1626 1627 1628
    // binding should match the second two varrefs, and the second binding
    // should match the first varref.
    //
J
John Clements 已提交
1629 1630 1631 1632 1633 1634
    // 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.
    //
1635 1636
    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
    // names; differences in marks don't matter any more.
J
John Clements 已提交
1637
    //
1638
    // oog... I also want tests that check "bound-identifier-=?". That is,
J
John Clements 已提交
1639 1640 1641 1642 1643
    // 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 已提交
1644
    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
1645

1646 1647
    #[test]
    fn automatic_renaming () {
1648 1649
        let tests: Vec<RenamingTest> =
            vec!(// b & c should get new names throughout, in the expr too:
1650
                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
1651
                 vec!(vec!(0,1),vec!(2)), false),
J
John Clements 已提交
1652
                // both x's should be renamed (how is this causing a bug?)
1653
                ("fn main () {let x: i32 = 13;x;}",
1654
                 vec!(vec!(0)), false),
1655
                // the use of b after the + should be renamed, the other one not:
1656
                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
1657
                 vec!(vec!(1)), false),
J
John Clements 已提交
1658
                // the b before the plus should not be renamed (requires marks)
1659
                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
1660
                 vec!(vec!(1)), false),
1661 1662 1663
                // 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.
1664 1665
                ("macro_rules! letty(($x:ident) => (let $x = 15;));
                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
1666
                  fn main() -> i32 {user!(z)}",
1667 1668
                 vec!(vec!(0)), false)
                );
1669 1670
        for (idx,s) in tests.iter().enumerate() {
            run_renaming_test(s,idx);
1671 1672 1673
        }
    }

1674 1675 1676 1677 1678
    // 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 已提交
1679 1680
    #[test]
    fn issue_8062(){
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
        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 已提交
1691 1692
    #[test]
    fn issue_6994(){
1693 1694
        run_renaming_test(
            &("macro_rules! g (($x:ident) =>
1695
              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
1696 1697 1698
              fn a(){g!(z)}",
              vec!(vec!(0)),false),
            0)
1699 1700
    }

1701
    // match variable hygiene. Should expand into
1702
    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
R
Richo Healey 已提交
1703 1704
    #[test]
    fn issue_9384(){
1705
        run_renaming_test(
1706
            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
1707
              fn z() {match 8 {x => bad_macro!(x)}}",
1708
              // NB: the third "binding" is the repeat of the second one.
1709
              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
1710 1711
              true),
            0)
1712 1713
    }

1714
    // interpolated nodes weren't getting labeled.
1715 1716
    // should expand into
    // fn main(){let g1_1 = 13; g1_1}}
R
Richo Healey 已提交
1717 1718
    #[test]
    fn pat_expand_issue_15221(){
1719
        run_renaming_test(
1720 1721
            &("macro_rules! inner ( ($e:pat ) => ($e));
              macro_rules! outer ( ($e:pat ) => (inner!($e)));
1722 1723 1724 1725 1726 1727
              fn main() { let outer!(g) = 13; g;}",
              vec!(vec!(0)),
              true),
            0)
    }

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

1732
    // method arg hygiene
1733
    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
R
Richo Healey 已提交
1734 1735
    #[test]
    fn method_arg_hygiene(){
1736
        run_renaming_test(
1737 1738
            &("macro_rules! inject_x (()=>(x));
              macro_rules! inject_self (()=>(self));
1739
              struct A;
1740
              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
1741 1742 1743 1744 1745
              vec!(vec!(0),vec!(3)),
              true),
            0)
    }

J
John Clements 已提交
1746 1747
    // ooh, got another bite?
    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
R
Richo Healey 已提交
1748 1749
    #[test]
    fn method_arg_hygiene_2(){
J
John Clements 已提交
1750 1751 1752
        run_renaming_test(
            &("struct A;
              macro_rules! add_method (($T:ty) =>
1753 1754
              (impl $T {  fn thingy(&self) {self;} }));
              add_method!(A);",
J
John Clements 已提交
1755 1756 1757 1758 1759
              vec!(vec!(0)),
              true),
            0)
    }

J
John Clements 已提交
1760
    // item fn hygiene
1761
    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
R
Richo Healey 已提交
1762 1763
    #[test]
    fn issue_9383(){
1764
        run_renaming_test(
1765 1766
            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
              fn q(x: i32) { bad_macro!(x); }",
1767
              vec!(vec!(1),vec!(0)),true),
1768
            0)
1769
    }
1770

1771
    // closure arg hygiene (ExprKind::Closure)
1772
    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
R
Richo Healey 已提交
1773 1774
    #[test]
    fn closure_arg_hygiene(){
1775
        run_renaming_test(
1776
            &("macro_rules! inject_x (()=>(x));
1777
            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
1778 1779 1780 1781 1782
              vec!(vec!(1)),
              true),
            0)
    }

1783
    // macro_rules in method position. Sadly, unimplemented.
R
Richo Healey 已提交
1784 1785
    #[test]
    fn macro_in_method_posn(){
1786
        expand_crate_str(
1787
            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
1788
            struct A;
1789
            impl A{ my_method!(); }
1790 1791 1792
            fn f(){A.thirteen;}".to_string());
    }

1793 1794
    // another nested macro
    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
R
Richo Healey 已提交
1795 1796
    #[test]
    fn item_macro_workaround(){
1797 1798 1799 1800
        run_renaming_test(
            &("macro_rules! item { ($i:item) => {$i}}
              struct Entries;
              macro_rules! iterator_impl {
1801
              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
1802 1803 1804 1805 1806
              iterator_impl! { }",
              vec!(vec!(0)), true),
            0)
    }

J
John Clements 已提交
1807
    // run one of the renaming tests
P
Paul Collier 已提交
1808
    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
J
John Clements 已提交
1809
        let invalid_name = token::special_idents::invalid.name;
J
John Clements 已提交
1810
        let (teststr, bound_connections, bound_ident_check) = match *t {
1811
            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
1812
        };
1813
        let cr = expand_crate_str(teststr.to_string());
1814 1815
        let bindings = crate_bindings(&cr);
        let varrefs = crate_varrefs(&cr);
1816

1817 1818 1819
        // must be one check clause for each binding:
        assert_eq!(bindings.len(),bound_connections.len());
        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
1820 1821
            let binding_name = mtwt::resolve(bindings[binding_idx]);
            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
1822
            // shouldmatch can't name varrefs that don't exist:
1823
            assert!((shouldmatch.is_empty()) ||
1824 1825
                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
            for (idx,varref) in varrefs.iter().enumerate() {
1826
                let print_hygiene_debug_info = || {
J
John Clements 已提交
1827 1828 1829
                    // 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 已提交
1830
                        None => panic!("varref with 0 path segments?")
J
John Clements 已提交
1831 1832 1833 1834 1835
                    };
                    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 已提交
1836
                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
1837
                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
J
John Clements 已提交
1838
                    println!("binding #{}: {}, resolves to {}",
1839
                             binding_idx, bindings[binding_idx], binding_name);
J
John Clements 已提交
1840 1841
                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
                };
1842 1843
                if shouldmatch.contains(&idx) {
                    // it should be a path of length 1, and it should
J
John Clements 已提交
1844
                    // be free-identifier=? or bound-identifier=? to the given binding
1845
                    assert_eq!(varref.segments.len(),1);
1846 1847
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
                    let varref_marks = mtwt::marksof(varref.segments[0]
1848 1849 1850
                                                           .identifier
                                                           .ctxt,
                                                     invalid_name);
1851
                    if !(varref_name==binding_name) {
1852
                        println!("uh oh, should match but doesn't:");
J
John Clements 已提交
1853
                        print_hygiene_debug_info();
1854 1855
                    }
                    assert_eq!(varref_name,binding_name);
1856
                    if bound_ident_check {
J
John Clements 已提交
1857 1858
                        // we're checking bound-identifier=?, and the marks
                        // should be the same, too:
J
John Clements 已提交
1859 1860
                        assert_eq!(varref_marks,binding_marks.clone());
                    }
1861
                } else {
1862
                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
1863
                    let fail = (varref.segments.len() == 1)
1864
                        && (varref_name == binding_name);
1865
                    // temp debugging:
1866
                    if fail {
1867 1868 1869 1870
                        println!("failure on test {}",test_idx);
                        println!("text of test case: \"{}\"", teststr);
                        println!("");
                        println!("uh oh, matches but shouldn't:");
J
John Clements 已提交
1871
                        print_hygiene_debug_info();
1872 1873 1874 1875
                    }
                    assert!(!fail);
                }
            }
1876 1877
        }
    }
1878

R
Richo Healey 已提交
1879 1880
    #[test]
    fn fmt_in_macro_used_inside_module_macro() {
1881 1882 1883
        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!();
1884
".to_string();
J
John Clements 已提交
1885 1886
        let cr = expand_crate_str(crate_str);
        // find the xx binding
1887
        let bindings = crate_bindings(&cr);
1888
        let cxbinds: Vec<&ast::Ident> =
1889
            bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
1890
        let cxbinds: &[&ast::Ident] = &cxbinds[..];
1891 1892
        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
            (1, Some(b)) => *b,
S
Steve Klabnik 已提交
1893
            _ => panic!("expected just one binding for ext_cx")
J
John Clements 已提交
1894
        };
1895
        let resolved_binding = mtwt::resolve(*cxbind);
1896
        let varrefs = crate_varrefs(&cr);
1897

J
John Clements 已提交
1898
        // the xx binding should bind all of the xx varrefs:
1899
        for (idx,v) in varrefs.iter().filter(|p| {
1900
            p.segments.len() == 1
1901
            && p.segments[0].identifier.name.as_str() == "xx"
1902
        }).enumerate() {
1903
            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
1904
                println!("uh oh, xx binding didn't match xx varref:");
L
Luqman Aden 已提交
1905 1906 1907
                println!("this is xx varref \\# {}", idx);
                println!("binding: {}", cxbind);
                println!("resolves to: {}", resolved_binding);
1908
                println!("varref: {}", v.segments[0].identifier);
L
Luqman Aden 已提交
1909
                println!("resolves to: {}",
1910
                         mtwt::resolve(v.segments[0].identifier));
1911
                mtwt::with_sctable(|x| mtwt::display_sctable(x));
J
John Clements 已提交
1912
            }
1913
            assert_eq!(mtwt::resolve(v.segments[0].identifier),
1914
                       resolved_binding);
J
John Clements 已提交
1915 1916 1917
        };
    }

J
John Clements 已提交
1918 1919
    #[test]
    fn pat_idents(){
1920
        let pat = string_to_pat(
1921
            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
S
Seo Sanghyeon 已提交
1922
        let idents = pattern_bindings(&pat);
1923
        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
J
John Clements 已提交
1924
    }
J
John Clements 已提交
1925

1926 1927 1928
    // 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.
1929
    #[test]
1930
    fn crate_bindings_test(){
1931
        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
1932
        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
1933 1934
        let idents = crate_bindings(&the_crate);
        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
1935 1936
    }

1937 1938 1939
    // test the IdentRenamer directly
    #[test]
    fn ident_renamer_test () {
1940
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1941 1942
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1943
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1944
        let renames = vec!((x_ident,Name(16)));
1945 1946 1947 1948
        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();
1949
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
1950 1951 1952 1953 1954
    }

    // test the PatIdentRenamer; only PatIdents get renamed
    #[test]
    fn pat_ident_renamer_test () {
1955
        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
1956 1957
        let f_ident = token::str_to_ident("f");
        let x_ident = token::str_to_ident("x");
1958
        let int_ident = token::str_to_ident("i32");
C
Corey Richardson 已提交
1959
        let renames = vec!((x_ident,Name(16)));
1960 1961 1962 1963 1964
        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;
1965
        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
1966
    }
J
John Clements 已提交
1967
}