]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/fold.rs
Implement tuple and tuple struct indexing
[rust.git] / src / libsyntax / fold.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A Folder represents an AST->AST fold; it accepts an AST piece,
12 //! and returns a piece of the same type. So, for instance, macro
13 //! expansion is a Folder that walks over an AST and produces another
14 //! AST.
15 //!
16 //! Note: using a Folder (other than the MacroExpander Folder) on
17 //! an AST before macro expansion is probably a bad idea. For instance,
18 //! a folder renaming item names in a module will miss all of those
19 //! that are created by the expansion of a macro.
20
21 use ast::*;
22 use ast;
23 use ast_util;
24 use codemap::{respan, Span, Spanned};
25 use parse::token;
26 use owned_slice::OwnedSlice;
27 use util::small_vector::SmallVector;
28
29 use std::rc::Rc;
30 use std::gc::{Gc, GC};
31
32 pub trait Folder {
33     // Any additions to this trait should happen in form
34     // of a call to a public `noop_*` function that only calls
35     // out to the folder again, not other `noop_*` functions.
36     //
37     // This is a necessary API workaround to the problem of not
38     // being able to call out to the super default method
39     // in an overridden default method.
40
41     fn fold_crate(&mut self, c: Crate) -> Crate {
42         noop_fold_crate(c, self)
43     }
44
45     fn fold_meta_items(&mut self, meta_items: &[Gc<MetaItem>]) -> Vec<Gc<MetaItem>> {
46         noop_fold_meta_items(meta_items, self)
47     }
48
49     fn fold_meta_item(&mut self, meta_item: &MetaItem) -> MetaItem {
50         noop_fold_meta_item(meta_item, self)
51     }
52
53     fn fold_view_path(&mut self, view_path: Gc<ViewPath>) -> Gc<ViewPath> {
54         noop_fold_view_path(view_path, self)
55     }
56
57     fn fold_view_item(&mut self, vi: &ViewItem) -> ViewItem {
58         noop_fold_view_item(vi, self)
59     }
60
61     fn fold_foreign_item(&mut self, ni: Gc<ForeignItem>) -> Gc<ForeignItem> {
62         noop_fold_foreign_item(&*ni, self)
63     }
64
65     fn fold_item(&mut self, i: Gc<Item>) -> SmallVector<Gc<Item>> {
66         noop_fold_item(&*i, self)
67     }
68
69     fn fold_item_simple(&mut self, i: &Item) -> Item {
70         noop_fold_item_simple(i, self)
71     }
72
73     fn fold_struct_field(&mut self, sf: &StructField) -> StructField {
74         noop_fold_struct_field(sf, self)
75     }
76
77     fn fold_item_underscore(&mut self, i: &Item_) -> Item_ {
78         noop_fold_item_underscore(i, self)
79     }
80
81     fn fold_fn_decl(&mut self, d: &FnDecl) -> P<FnDecl> {
82         noop_fold_fn_decl(d, self)
83     }
84
85     fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod {
86         noop_fold_type_method(m, self)
87     }
88
89     fn fold_method(&mut self, m: Gc<Method>) -> SmallVector<Gc<Method>>  {
90         noop_fold_method(&*m, self)
91     }
92
93     fn fold_block(&mut self, b: P<Block>) -> P<Block> {
94         noop_fold_block(b, self)
95     }
96
97     fn fold_stmt(&mut self, s: &Stmt) -> SmallVector<Gc<Stmt>> {
98         noop_fold_stmt(s, self)
99     }
100
101     fn fold_arm(&mut self, a: &Arm) -> Arm {
102         noop_fold_arm(a, self)
103     }
104
105     fn fold_pat(&mut self, p: Gc<Pat>) -> Gc<Pat> {
106         noop_fold_pat(p, self)
107     }
108
109     fn fold_decl(&mut self, d: Gc<Decl>) -> SmallVector<Gc<Decl>> {
110         noop_fold_decl(d, self)
111     }
112
113     fn fold_expr(&mut self, e: Gc<Expr>) -> Gc<Expr> {
114         noop_fold_expr(e, self)
115     }
116
117     fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
118         noop_fold_ty(t, self)
119     }
120
121     fn fold_mod(&mut self, m: &Mod) -> Mod {
122         noop_fold_mod(m, self)
123     }
124
125     fn fold_foreign_mod(&mut self, nm: &ForeignMod) -> ForeignMod {
126         noop_fold_foreign_mod(nm, self)
127     }
128
129     fn fold_variant(&mut self, v: &Variant) -> P<Variant> {
130         noop_fold_variant(v, self)
131     }
132
133     fn fold_ident(&mut self, i: Ident) -> Ident {
134         noop_fold_ident(i, self)
135     }
136
137     fn fold_uint(&mut self, i: uint) -> uint {
138         noop_fold_uint(i, self)
139     }
140
141     fn fold_path(&mut self, p: &Path) -> Path {
142         noop_fold_path(p, self)
143     }
144
145     fn fold_local(&mut self, l: Gc<Local>) -> Gc<Local> {
146         noop_fold_local(l, self)
147     }
148
149     fn fold_mac(&mut self, _macro: &Mac) -> Mac {
150         fail!("fold_mac disabled by default");
151         // NB: see note about macros above.
152         // if you really want a folder that
153         // works on macros, use this
154         // definition in your trait impl:
155         // fold::noop_fold_mac(_macro, self)
156     }
157
158     fn fold_explicit_self(&mut self, es: &ExplicitSelf) -> ExplicitSelf {
159         noop_fold_explicit_self(es, self)
160     }
161
162     fn fold_explicit_self_underscore(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ {
163         noop_fold_explicit_self_underscore(es, self)
164     }
165
166     fn fold_lifetime(&mut self, l: &Lifetime) -> Lifetime {
167         noop_fold_lifetime(l, self)
168     }
169
170     fn fold_lifetime_def(&mut self, l: &LifetimeDef) -> LifetimeDef {
171         noop_fold_lifetime_def(l, self)
172     }
173
174     fn fold_attribute(&mut self, at: Attribute) -> Attribute {
175         noop_fold_attribute(at, self)
176     }
177
178     fn fold_arg(&mut self, a: &Arg) -> Arg {
179         noop_fold_arg(a, self)
180     }
181
182     fn fold_generics(&mut self, generics: &Generics) -> Generics {
183         noop_fold_generics(generics, self)
184     }
185
186     fn fold_trait_ref(&mut self, p: &TraitRef) -> TraitRef {
187         noop_fold_trait_ref(p, self)
188     }
189
190     fn fold_struct_def(&mut self, struct_def: Gc<StructDef>) -> Gc<StructDef> {
191         noop_fold_struct_def(struct_def, self)
192     }
193
194     fn fold_lifetimes(&mut self, lts: &[Lifetime]) -> Vec<Lifetime> {
195         noop_fold_lifetimes(lts, self)
196     }
197
198     fn fold_lifetime_defs(&mut self, lts: &[LifetimeDef]) -> Vec<LifetimeDef> {
199         noop_fold_lifetime_defs(lts, self)
200     }
201
202     fn fold_ty_param(&mut self, tp: &TyParam) -> TyParam {
203         noop_fold_ty_param(tp, self)
204     }
205
206     fn fold_ty_params(&mut self, tps: &[TyParam]) -> OwnedSlice<TyParam> {
207         noop_fold_ty_params(tps, self)
208     }
209
210     fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree {
211         noop_fold_tt(tt, self)
212     }
213
214     fn fold_tts(&mut self, tts: &[TokenTree]) -> Vec<TokenTree> {
215         noop_fold_tts(tts, self)
216     }
217
218     fn fold_token(&mut self, t: &token::Token) -> token::Token {
219         noop_fold_token(t, self)
220     }
221
222     fn fold_interpolated(&mut self, nt : &token::Nonterminal) -> token::Nonterminal {
223         noop_fold_interpolated(nt, self)
224     }
225
226     fn fold_opt_lifetime(&mut self, o_lt: &Option<Lifetime>) -> Option<Lifetime> {
227         noop_fold_opt_lifetime(o_lt, self)
228     }
229
230     fn fold_variant_arg(&mut self, va: &VariantArg) -> VariantArg {
231         noop_fold_variant_arg(va, self)
232     }
233
234     fn fold_opt_bounds(&mut self, b: &Option<OwnedSlice<TyParamBound>>)
235                        -> Option<OwnedSlice<TyParamBound>> {
236         noop_fold_opt_bounds(b, self)
237     }
238
239     fn fold_bounds(&mut self, b: &OwnedSlice<TyParamBound>)
240                        -> OwnedSlice<TyParamBound> {
241         noop_fold_bounds(b, self)
242     }
243
244     fn fold_ty_param_bound(&mut self, tpb: &TyParamBound) -> TyParamBound {
245         noop_fold_ty_param_bound(tpb, self)
246     }
247
248     fn fold_mt(&mut self, mt: &MutTy) -> MutTy {
249         noop_fold_mt(mt, self)
250     }
251
252     fn fold_field(&mut self, field: Field) -> Field {
253         noop_fold_field(field, self)
254     }
255
256     fn fold_where_clause(&mut self, where_clause: &WhereClause)
257                          -> WhereClause {
258         noop_fold_where_clause(where_clause, self)
259     }
260
261     fn fold_where_predicate(&mut self, where_predicate: &WherePredicate)
262                             -> WherePredicate {
263         noop_fold_where_predicate(where_predicate, self)
264     }
265
266 // Helper methods:
267
268     fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
269                  es: &[Gc<Expr>]) -> Vec<Gc<Expr>> {
270         es.iter().map(|x| f(*x)).collect()
271     }
272
273     fn new_id(&mut self, i: NodeId) -> NodeId {
274         i
275     }
276
277     fn new_span(&mut self, sp: Span) -> Span {
278         sp
279     }
280 }
281
282 pub fn noop_fold_meta_items<T: Folder>(meta_items: &[Gc<MetaItem>], fld: &mut T)
283                                        -> Vec<Gc<MetaItem>> {
284     meta_items.iter().map(|x| box (GC) fld.fold_meta_item(&**x)).collect()
285 }
286
287 pub fn noop_fold_view_path<T: Folder>(view_path: Gc<ViewPath>, fld: &mut T) -> Gc<ViewPath> {
288     let inner_view_path = match view_path.node {
289         ViewPathSimple(ref ident, ref path, node_id) => {
290             let id = fld.new_id(node_id);
291             ViewPathSimple(ident.clone(),
292                         fld.fold_path(path),
293                         id)
294         }
295         ViewPathGlob(ref path, node_id) => {
296             let id = fld.new_id(node_id);
297             ViewPathGlob(fld.fold_path(path), id)
298         }
299         ViewPathList(ref path, ref path_list_idents, node_id) => {
300             let id = fld.new_id(node_id);
301             ViewPathList(fld.fold_path(path),
302                         path_list_idents.iter().map(|path_list_ident| {
303                             Spanned {
304                                 node: match path_list_ident.node {
305                                     PathListIdent { id, name } =>
306                                         PathListIdent {
307                                             id: fld.new_id(id),
308                                             name: name.clone()
309                                         },
310                                     PathListMod { id } =>
311                                         PathListMod { id: fld.new_id(id) }
312                                 },
313                                 span: fld.new_span(path_list_ident.span)
314                             }
315                         }).collect(),
316                         id)
317         }
318     };
319     box(GC) Spanned {
320         node: inner_view_path,
321         span: fld.new_span(view_path.span),
322     }
323 }
324
325 pub fn noop_fold_arm<T: Folder>(a: &Arm, fld: &mut T) -> Arm {
326     Arm {
327         attrs: a.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(),
328         pats: a.pats.iter().map(|x| fld.fold_pat(*x)).collect(),
329         guard: a.guard.map(|x| fld.fold_expr(x)),
330         body: fld.fold_expr(a.body),
331     }
332 }
333
334 pub fn noop_fold_decl<T: Folder>(d: Gc<Decl>, fld: &mut T) -> SmallVector<Gc<Decl>> {
335     let node = match d.node {
336         DeclLocal(ref l) => SmallVector::one(DeclLocal(fld.fold_local(*l))),
337         DeclItem(it) => {
338             fld.fold_item(it).move_iter().map(|i| DeclItem(i)).collect()
339         }
340     };
341
342     node.move_iter().map(|node| {
343         box(GC) Spanned {
344             node: node,
345             span: fld.new_span(d.span),
346         }
347     }).collect()
348 }
349
350 pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
351     let id = fld.new_id(t.id);
352     let node = match t.node {
353         TyNil | TyBot | TyInfer => t.node.clone(),
354         TyBox(ty) => TyBox(fld.fold_ty(ty)),
355         TyUniq(ty) => TyUniq(fld.fold_ty(ty)),
356         TyVec(ty) => TyVec(fld.fold_ty(ty)),
357         TyPtr(ref mt) => TyPtr(fld.fold_mt(mt)),
358         TyRptr(ref region, ref mt) => {
359             TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
360         }
361         TyClosure(ref f) => {
362             TyClosure(box(GC) ClosureTy {
363                 fn_style: f.fn_style,
364                 onceness: f.onceness,
365                 bounds: fld.fold_bounds(&f.bounds),
366                 decl: fld.fold_fn_decl(&*f.decl),
367                 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
368             })
369         }
370         TyProc(ref f) => {
371             TyProc(box(GC) ClosureTy {
372                 fn_style: f.fn_style,
373                 onceness: f.onceness,
374                 bounds: fld.fold_bounds(&f.bounds),
375                 decl: fld.fold_fn_decl(&*f.decl),
376                 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
377             })
378         }
379         TyBareFn(ref f) => {
380             TyBareFn(box(GC) BareFnTy {
381                 lifetimes: fld.fold_lifetime_defs(f.lifetimes.as_slice()),
382                 fn_style: f.fn_style,
383                 abi: f.abi,
384                 decl: fld.fold_fn_decl(&*f.decl)
385             })
386         }
387         TyUnboxedFn(ref f) => {
388             TyUnboxedFn(box(GC) UnboxedFnTy {
389                 decl: fld.fold_fn_decl(&*f.decl),
390                 kind: f.kind,
391             })
392         }
393         TyTup(ref tys) => TyTup(tys.iter().map(|&ty| fld.fold_ty(ty)).collect()),
394         TyParen(ref ty) => TyParen(fld.fold_ty(*ty)),
395         TyPath(ref path, ref bounds, id) => {
396             let id = fld.new_id(id);
397             TyPath(fld.fold_path(path),
398                     fld.fold_opt_bounds(bounds),
399                     id)
400         }
401         TyFixedLengthVec(ty, e) => {
402             TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
403         }
404         TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)),
405     };
406     P(Ty {
407         id: id,
408         span: fld.new_span(t.span),
409         node: node,
410     })
411 }
412
413 pub fn noop_fold_foreign_mod<T: Folder>(nm: &ForeignMod, fld: &mut T) -> ForeignMod {
414     ast::ForeignMod {
415         abi: nm.abi,
416         view_items: nm.view_items
417                         .iter()
418                         .map(|x| fld.fold_view_item(x))
419                         .collect(),
420         items: nm.items
421                     .iter()
422                     .map(|x| fld.fold_foreign_item(*x))
423                     .collect(),
424     }
425 }
426
427 pub fn noop_fold_variant<T: Folder>(v: &Variant, fld: &mut T) -> P<Variant> {
428     let id = fld.new_id(v.node.id);
429     let kind;
430     match v.node.kind {
431         TupleVariantKind(ref variant_args) => {
432             kind = TupleVariantKind(variant_args.iter().map(|x|
433                 fld.fold_variant_arg(x)).collect())
434         }
435         StructVariantKind(ref struct_def) => {
436             kind = StructVariantKind(box(GC) ast::StructDef {
437                 fields: struct_def.fields.iter()
438                     .map(|f| fld.fold_struct_field(f)).collect(),
439                 ctor_id: struct_def.ctor_id.map(|c| fld.new_id(c)),
440                 super_struct: match struct_def.super_struct {
441                     Some(t) => Some(fld.fold_ty(t)),
442                     None => None
443                 },
444                 is_virtual: struct_def.is_virtual,
445             })
446         }
447     }
448
449     let attrs = v.node.attrs.iter().map(|x| fld.fold_attribute(*x)).collect();
450
451     let de = match v.node.disr_expr {
452         Some(e) => Some(fld.fold_expr(e)),
453         None => None
454     };
455     let node = ast::Variant_ {
456         name: v.node.name,
457         attrs: attrs,
458         kind: kind,
459         id: id,
460         disr_expr: de,
461         vis: v.node.vis,
462     };
463     P(Spanned {
464         node: node,
465         span: fld.new_span(v.span),
466     })
467 }
468
469 pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
470     i
471 }
472
473 pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
474     i
475 }
476
477 pub fn noop_fold_path<T: Folder>(p: &Path, fld: &mut T) -> Path {
478     ast::Path {
479         span: fld.new_span(p.span),
480         global: p.global,
481         segments: p.segments.iter().map(|segment| ast::PathSegment {
482             identifier: fld.fold_ident(segment.identifier),
483             lifetimes: segment.lifetimes.iter().map(|l| fld.fold_lifetime(l)).collect(),
484             types: segment.types.iter().map(|&typ| fld.fold_ty(typ)).collect(),
485         }).collect()
486     }
487 }
488
489 pub fn noop_fold_local<T: Folder>(l: Gc<Local>, fld: &mut T) -> Gc<Local> {
490     let id = fld.new_id(l.id); // Needs to be first, for ast_map.
491     box(GC) Local {
492         id: id,
493         ty: fld.fold_ty(l.ty),
494         pat: fld.fold_pat(l.pat),
495         init: l.init.map(|e| fld.fold_expr(e)),
496         span: fld.new_span(l.span),
497         source: l.source,
498     }
499 }
500
501 pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Attribute {
502     Spanned {
503         span: fld.new_span(at.span),
504         node: ast::Attribute_ {
505             id: at.node.id,
506             style: at.node.style,
507             value: box (GC) fld.fold_meta_item(&*at.node.value),
508             is_sugared_doc: at.node.is_sugared_doc
509         }
510     }
511 }
512
513 pub fn noop_fold_explicit_self_underscore<T: Folder>(es: &ExplicitSelf_, fld: &mut T)
514                                                      -> ExplicitSelf_ {
515     match *es {
516         SelfStatic | SelfValue(_) => *es,
517         SelfRegion(ref lifetime, m, id) => {
518             SelfRegion(fld.fold_opt_lifetime(lifetime), m, id)
519         }
520         SelfExplicit(ref typ, id) => SelfExplicit(fld.fold_ty(*typ), id),
521     }
522 }
523
524 pub fn noop_fold_explicit_self<T: Folder>(es: &ExplicitSelf, fld: &mut T) -> ExplicitSelf {
525     Spanned {
526         span: fld.new_span(es.span),
527         node: fld.fold_explicit_self_underscore(&es.node)
528     }
529 }
530
531
532 pub fn noop_fold_mac<T: Folder>(macro: &Mac, fld: &mut T) -> Mac {
533     Spanned {
534         node: match macro.node {
535             MacInvocTT(ref p, ref tts, ctxt) => {
536                 MacInvocTT(fld.fold_path(p),
537                            fld.fold_tts(tts.as_slice()),
538                            ctxt)
539             }
540         },
541         span: fld.new_span(macro.span)
542     }
543 }
544
545 pub fn noop_fold_meta_item<T: Folder>(mi: &MetaItem, fld: &mut T) -> MetaItem {
546     Spanned {
547         node:
548             match mi.node {
549                 MetaWord(ref id) => MetaWord((*id).clone()),
550                 MetaList(ref id, ref mis) => {
551                     MetaList((*id).clone(),
552                              mis.iter()
553                                 .map(|e| box (GC) fld.fold_meta_item(&**e)).collect())
554                 }
555                 MetaNameValue(ref id, ref s) => {
556                     MetaNameValue((*id).clone(), (*s).clone())
557                 }
558             },
559         span: fld.new_span(mi.span) }
560 }
561
562 pub fn noop_fold_arg<T: Folder>(a: &Arg, fld: &mut T) -> Arg {
563     let id = fld.new_id(a.id); // Needs to be first, for ast_map.
564     Arg {
565         id: id,
566         ty: fld.fold_ty(a.ty),
567         pat: fld.fold_pat(a.pat),
568     }
569 }
570
571 pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
572     match *tt {
573         TTTok(span, ref tok) =>
574             TTTok(span, fld.fold_token(tok)),
575         TTDelim(ref tts) => TTDelim(Rc::new(fld.fold_tts(tts.as_slice()))),
576         TTSeq(span, ref pattern, ref sep, is_optional) =>
577             TTSeq(span,
578                   Rc::new(fld.fold_tts(pattern.as_slice())),
579                   sep.as_ref().map(|tok| fld.fold_token(tok)),
580                   is_optional),
581         TTNonterminal(sp,ref ident) =>
582             TTNonterminal(sp,fld.fold_ident(*ident))
583     }
584 }
585
586 pub fn noop_fold_tts<T: Folder>(tts: &[TokenTree], fld: &mut T) -> Vec<TokenTree> {
587     tts.iter().map(|tt| fld.fold_tt(tt)).collect()
588 }
589
590 // apply ident folder if it's an ident, apply other folds to interpolated nodes
591 pub fn noop_fold_token<T: Folder>(t: &token::Token, fld: &mut T) -> token::Token {
592     match *t {
593         token::IDENT(id, followed_by_colons) => {
594             token::IDENT(fld.fold_ident(id), followed_by_colons)
595         }
596         token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)),
597         token::INTERPOLATED(ref nt) => token::INTERPOLATED(fld.fold_interpolated(nt)),
598         _ => (*t).clone()
599     }
600 }
601
602 /// apply folder to elements of interpolated nodes
603 //
604 // NB: this can occur only when applying a fold to partially expanded code, where
605 // parsed pieces have gotten implanted ito *other* macro invocations. This is relevant
606 // for macro hygiene, but possibly not elsewhere.
607 //
608 // One problem here occurs because the types for fold_item, fold_stmt, etc. allow the
609 // folder to return *multiple* items; this is a problem for the nodes here, because
610 // they insist on having exactly one piece. One solution would be to mangle the fold
611 // trait to include one-to-many and one-to-one versions of these entry points, but that
612 // would probably confuse a lot of people and help very few. Instead, I'm just going
613 // to put in dynamic checks. I think the performance impact of this will be pretty much
614 // nonexistent. The danger is that someone will apply a fold to a partially expanded
615 // node, and will be confused by the fact that their "fold_item" or "fold_stmt" isn't
616 // getting called on NtItem or NtStmt nodes. Hopefully they'll wind up reading this
617 // comment, and doing something appropriate.
618 //
619 // BTW, design choice: I considered just changing the type of, e.g., NtItem to contain
620 // multiple items, but decided against it when I looked at parse_item_or_view_item and
621 // tried to figure out what I would do with multiple items there....
622 pub fn noop_fold_interpolated<T: Folder>(nt : &token::Nonterminal, fld: &mut T)
623                                          -> token::Nonterminal {
624     match *nt {
625         token::NtItem(item) =>
626             token::NtItem(fld.fold_item(item)
627                           // this is probably okay, because the only folds likely
628                           // to peek inside interpolated nodes will be renamings/markings,
629                           // which map single items to single items
630                           .expect_one("expected fold to produce exactly one item")),
631         token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
632         token::NtStmt(stmt) =>
633             token::NtStmt(fld.fold_stmt(&*stmt)
634                           // this is probably okay, because the only folds likely
635                           // to peek inside interpolated nodes will be renamings/markings,
636                           // which map single items to single items
637                           .expect_one("expected fold to produce exactly one statement")),
638         token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
639         token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
640         token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
641         token::NtIdent(ref id, is_mod_name) =>
642             token::NtIdent(box fld.fold_ident(**id),is_mod_name),
643         token::NtMeta(meta_item) => token::NtMeta(box (GC) fld.fold_meta_item(&*meta_item)),
644         token::NtPath(ref path) => token::NtPath(box fld.fold_path(&**path)),
645         token::NtTT(tt) => token::NtTT(box (GC) fld.fold_tt(&*tt)),
646         // it looks to me like we can leave out the matchers: token::NtMatchers(matchers)
647         _ => (*nt).clone()
648     }
649 }
650
651 pub fn noop_fold_fn_decl<T: Folder>(decl: &FnDecl, fld: &mut T) -> P<FnDecl> {
652     P(FnDecl {
653         inputs: decl.inputs.iter().map(|x| fld.fold_arg(x)).collect(), // bad copy
654         output: fld.fold_ty(decl.output),
655         cf: decl.cf,
656         variadic: decl.variadic
657     })
658 }
659
660 pub fn noop_fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
661                                            -> TyParamBound {
662     match *tpb {
663         TraitTyParamBound(ref ty) => TraitTyParamBound(fld.fold_trait_ref(ty)),
664         RegionTyParamBound(ref lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
665         UnboxedFnTyParamBound(ref unboxed_function_type) => {
666             UnboxedFnTyParamBound(UnboxedFnTy {
667                 decl: fld.fold_fn_decl(&*unboxed_function_type.decl),
668                 kind: unboxed_function_type.kind,
669             })
670         }
671     }
672 }
673
674 pub fn noop_fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
675     let id = fld.new_id(tp.id);
676     TyParam {
677         ident: tp.ident,
678         id: id,
679         bounds: fld.fold_bounds(&tp.bounds),
680         unbound: tp.unbound.as_ref().map(|x| fld.fold_ty_param_bound(x)),
681         default: tp.default.map(|x| fld.fold_ty(x)),
682         span: tp.span
683     }
684 }
685
686 pub fn noop_fold_ty_params<T: Folder>(tps: &[TyParam], fld: &mut T)
687                                       -> OwnedSlice<TyParam> {
688     tps.iter().map(|tp| fld.fold_ty_param(tp)).collect()
689 }
690
691 pub fn noop_fold_lifetime<T: Folder>(l: &Lifetime, fld: &mut T) -> Lifetime {
692     let id = fld.new_id(l.id);
693     Lifetime {
694         id: id,
695         span: fld.new_span(l.span),
696         name: l.name
697     }
698 }
699
700 pub fn noop_fold_lifetime_def<T: Folder>(l: &LifetimeDef, fld: &mut T)
701                                          -> LifetimeDef
702 {
703     LifetimeDef {
704         lifetime: fld.fold_lifetime(&l.lifetime),
705         bounds: fld.fold_lifetimes(l.bounds.as_slice()),
706     }
707 }
708
709 pub fn noop_fold_lifetimes<T: Folder>(lts: &[Lifetime], fld: &mut T) -> Vec<Lifetime> {
710     lts.iter().map(|l| fld.fold_lifetime(l)).collect()
711 }
712
713 pub fn noop_fold_lifetime_defs<T: Folder>(lts: &[LifetimeDef], fld: &mut T) -> Vec<LifetimeDef> {
714     lts.iter().map(|l| fld.fold_lifetime_def(l)).collect()
715 }
716
717 pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
718                                       -> Option<Lifetime> {
719     o_lt.as_ref().map(|lt| fld.fold_lifetime(lt))
720 }
721
722 pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
723     Generics {
724         ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
725         lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()),
726         where_clause: fld.fold_where_clause(&generics.where_clause),
727     }
728 }
729
730 pub fn noop_fold_where_clause<T: Folder>(
731                               where_clause: &WhereClause,
732                               fld: &mut T)
733                               -> WhereClause {
734     WhereClause {
735         id: fld.new_id(where_clause.id),
736         predicates: where_clause.predicates.iter().map(|predicate| {
737             fld.fold_where_predicate(predicate)
738         }).collect(),
739     }
740 }
741
742 pub fn noop_fold_where_predicate<T: Folder>(
743                                  predicate: &WherePredicate,
744                                  fld: &mut T)
745                                  -> WherePredicate {
746     WherePredicate {
747         id: fld.new_id(predicate.id),
748         span: fld.new_span(predicate.span),
749         ident: fld.fold_ident(predicate.ident),
750         bounds: predicate.bounds.map(|x| {
751             fld.fold_ty_param_bound(x)
752         }),
753     }
754 }
755
756 pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,
757                               fld: &mut T) -> Gc<StructDef> {
758     box(GC) ast::StructDef {
759         fields: struct_def.fields.iter().map(|f| fld.fold_struct_field(f)).collect(),
760         ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(cid)),
761         super_struct: match struct_def.super_struct {
762             Some(t) => Some(fld.fold_ty(t)),
763             None => None
764         },
765         is_virtual: struct_def.is_virtual,
766     }
767 }
768
769 pub fn noop_fold_trait_ref<T: Folder>(p: &TraitRef, fld: &mut T) -> TraitRef {
770     let id = fld.new_id(p.ref_id);
771     ast::TraitRef {
772         path: fld.fold_path(&p.path),
773         ref_id: id,
774     }
775 }
776
777 pub fn noop_fold_struct_field<T: Folder>(f: &StructField, fld: &mut T) -> StructField {
778     let id = fld.new_id(f.node.id);
779     Spanned {
780         node: ast::StructField_ {
781             kind: f.node.kind,
782             id: id,
783             ty: fld.fold_ty(f.node.ty),
784             attrs: f.node.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
785         },
786         span: fld.new_span(f.span),
787     }
788 }
789
790 pub fn noop_fold_field<T: Folder>(field: Field, folder: &mut T) -> Field {
791     ast::Field {
792         ident: respan(field.ident.span, folder.fold_ident(field.ident.node)),
793         expr: folder.fold_expr(field.expr),
794         span: folder.new_span(field.span),
795     }
796 }
797
798 pub fn noop_fold_mt<T: Folder>(mt: &MutTy, folder: &mut T) -> MutTy {
799     MutTy {
800         ty: folder.fold_ty(mt.ty),
801         mutbl: mt.mutbl,
802     }
803 }
804
805 pub fn noop_fold_opt_bounds<T: Folder>(b: &Option<OwnedSlice<TyParamBound>>, folder: &mut T)
806                               -> Option<OwnedSlice<TyParamBound>> {
807     b.as_ref().map(|bounds| folder.fold_bounds(bounds))
808 }
809
810 fn noop_fold_bounds<T: Folder>(bounds: &TyParamBounds, folder: &mut T)
811                           -> TyParamBounds {
812     bounds.map(|bound| folder.fold_ty_param_bound(bound))
813 }
814
815 pub fn noop_fold_variant_arg<T: Folder>(va: &VariantArg, folder: &mut T) -> VariantArg {
816     let id = folder.new_id(va.id);
817     ast::VariantArg {
818         ty: folder.fold_ty(va.ty),
819         id: id,
820     }
821 }
822
823 pub fn noop_fold_view_item<T: Folder>(vi: &ViewItem, folder: &mut T)
824                                        -> ViewItem{
825     let inner_view_item = match vi.node {
826         ViewItemExternCrate(ref ident, ref string, node_id) => {
827             ViewItemExternCrate(ident.clone(),
828                               (*string).clone(),
829                               folder.new_id(node_id))
830         }
831         ViewItemUse(ref view_path) => {
832             ViewItemUse(folder.fold_view_path(*view_path))
833         }
834     };
835     ViewItem {
836         node: inner_view_item,
837         attrs: vi.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
838         vis: vi.vis,
839         span: folder.new_span(vi.span),
840     }
841 }
842
843 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
844     let id = folder.new_id(b.id); // Needs to be first, for ast_map.
845     let view_items = b.view_items.iter().map(|x| folder.fold_view_item(x)).collect();
846     let stmts = b.stmts.iter().flat_map(|s| folder.fold_stmt(&**s).move_iter()).collect();
847     P(Block {
848         id: id,
849         view_items: view_items,
850         stmts: stmts,
851         expr: b.expr.map(|x| folder.fold_expr(x)),
852         rules: b.rules,
853         span: folder.new_span(b.span),
854     })
855 }
856
857 pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_ {
858     match *i {
859         ItemStatic(t, m, e) => {
860             ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
861         }
862         ItemFn(decl, fn_style, abi, ref generics, body) => {
863             ItemFn(
864                 folder.fold_fn_decl(&*decl),
865                 fn_style,
866                 abi,
867                 folder.fold_generics(generics),
868                 folder.fold_block(body)
869             )
870         }
871         ItemMod(ref m) => ItemMod(folder.fold_mod(m)),
872         ItemForeignMod(ref nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
873         ItemTy(t, ref generics) => {
874             ItemTy(folder.fold_ty(t), folder.fold_generics(generics))
875         }
876         ItemEnum(ref enum_definition, ref generics) => {
877             ItemEnum(
878                 ast::EnumDef {
879                     variants: enum_definition.variants.iter().map(|&x| {
880                         folder.fold_variant(&*x)
881                     }).collect(),
882                 },
883                 folder.fold_generics(generics))
884         }
885         ItemStruct(ref struct_def, ref generics) => {
886             let struct_def = folder.fold_struct_def(*struct_def);
887             ItemStruct(struct_def, folder.fold_generics(generics))
888         }
889         ItemImpl(ref generics, ref ifce, ty, ref impl_items) => {
890             ItemImpl(folder.fold_generics(generics),
891                      ifce.as_ref().map(|p| folder.fold_trait_ref(p)),
892                      folder.fold_ty(ty),
893                      impl_items.iter()
894                                .flat_map(|impl_item| {
895                                     match *impl_item {
896                                         MethodImplItem(x) => {
897                                             folder.fold_method(x)
898                                                   .move_iter()
899                                                   .map(|x| MethodImplItem(x))
900                                         }
901                                     }
902                                }).collect()
903             )
904         }
905         ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
906             let bounds = folder.fold_bounds(bounds);
907             let methods = methods.iter().flat_map(|method| {
908                 let r = match *method {
909                     RequiredMethod(ref m) => {
910                             SmallVector::one(RequiredMethod(
911                                     folder.fold_type_method(m))).move_iter()
912                     }
913                     ProvidedMethod(method) => {
914                             // the awkward collect/iter idiom here is because
915                             // even though an iter and a map satisfy the same trait bound,
916                             // they're not actually the same type, so the method arms
917                             // don't unify.
918                             let methods : SmallVector<ast::TraitItem> =
919                                 folder.fold_method(method).move_iter()
920                                 .map(|m| ProvidedMethod(m)).collect();
921                             methods.move_iter()
922                         }
923                 };
924                 r
925             }).collect();
926             ItemTrait(folder.fold_generics(generics),
927                       unbound.clone(),
928                       bounds,
929                       methods)
930         }
931         ItemMac(ref m) => ItemMac(folder.fold_mac(m)),
932     }
933 }
934
935 pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMethod {
936     let id = fld.new_id(m.id); // Needs to be first, for ast_map.
937     TypeMethod {
938         id: id,
939         ident: fld.fold_ident(m.ident),
940         attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
941         fn_style: m.fn_style,
942         abi: m.abi,
943         decl: fld.fold_fn_decl(&*m.decl),
944         generics: fld.fold_generics(&m.generics),
945         explicit_self: fld.fold_explicit_self(&m.explicit_self),
946         span: fld.new_span(m.span),
947         vis: m.vis,
948     }
949 }
950
951 pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
952     ast::Mod {
953         inner: folder.new_span(m.inner),
954         view_items: m.view_items
955                      .iter()
956                      .map(|x| folder.fold_view_item(x)).collect(),
957         items: m.items.iter().flat_map(|x| folder.fold_item(*x).move_iter()).collect(),
958     }
959 }
960
961 pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
962     Crate {
963         module: folder.fold_mod(&c.module),
964         attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
965         config: c.config.iter().map(|x| box (GC) folder.fold_meta_item(&**x)).collect(),
966         span: folder.new_span(c.span),
967         exported_macros: c.exported_macros
968     }
969 }
970
971 // fold one item into possibly many items
972 pub fn noop_fold_item<T: Folder>(i: &Item,
973                                  folder: &mut T) -> SmallVector<Gc<Item>> {
974     SmallVector::one(box(GC) folder.fold_item_simple(i))
975 }
976
977
978 // fold one item into exactly one item
979 pub fn noop_fold_item_simple<T: Folder>(i: &Item, folder: &mut T) -> Item {
980     let id = folder.new_id(i.id); // Needs to be first, for ast_map.
981     let node = folder.fold_item_underscore(&i.node);
982     let ident = match node {
983         // The node may have changed, recompute the "pretty" impl name.
984         ItemImpl(_, ref maybe_trait, ty, _) => {
985             ast_util::impl_pretty_name(maybe_trait, &*ty)
986         }
987         _ => i.ident
988     };
989
990     Item {
991         id: id,
992         ident: folder.fold_ident(ident),
993         attrs: i.attrs.iter().map(|e| folder.fold_attribute(*e)).collect(),
994         node: node,
995         vis: i.vis,
996         span: folder.new_span(i.span)
997     }
998 }
999
1000 pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
1001                                          folder: &mut T) -> Gc<ForeignItem> {
1002     let id = folder.new_id(ni.id); // Needs to be first, for ast_map.
1003     box(GC) ForeignItem {
1004         id: id,
1005         ident: folder.fold_ident(ni.ident),
1006         attrs: ni.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
1007         node: match ni.node {
1008             ForeignItemFn(ref fdec, ref generics) => {
1009                 ForeignItemFn(P(FnDecl {
1010                     inputs: fdec.inputs.iter().map(|a| folder.fold_arg(a)).collect(),
1011                     output: folder.fold_ty(fdec.output),
1012                     cf: fdec.cf,
1013                     variadic: fdec.variadic
1014                 }), folder.fold_generics(generics))
1015             }
1016             ForeignItemStatic(t, m) => {
1017                 ForeignItemStatic(folder.fold_ty(t), m)
1018             }
1019         },
1020         span: folder.new_span(ni.span),
1021         vis: ni.vis,
1022     }
1023 }
1024
1025 // Default fold over a method.
1026 // Invariant: produces exactly one method.
1027 pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc<Method>> {
1028     let id = folder.new_id(m.id); // Needs to be first, for ast_map.
1029     SmallVector::one(box(GC) Method {
1030         attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
1031         id: id,
1032         span: folder.new_span(m.span),
1033         node: match m.node {
1034             MethDecl(ident,
1035                      ref generics,
1036                      abi,
1037                      ref explicit_self,
1038                      fn_style,
1039                      decl,
1040                      body,
1041                      vis) => {
1042                 MethDecl(folder.fold_ident(ident),
1043                          folder.fold_generics(generics),
1044                          abi,
1045                          folder.fold_explicit_self(explicit_self),
1046                          fn_style,
1047                          folder.fold_fn_decl(&*decl),
1048                          folder.fold_block(body),
1049                          vis)
1050             },
1051             MethMac(ref mac) => MethMac(folder.fold_mac(mac)),
1052         }
1053     })
1054 }
1055
1056 pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
1057     let id = folder.new_id(p.id);
1058     let node = match p.node {
1059         PatWild(k) => PatWild(k),
1060         PatIdent(binding_mode, ref pth1, ref sub) => {
1061             PatIdent(binding_mode,
1062                      Spanned{span: folder.new_span(pth1.span),
1063                              node: folder.fold_ident(pth1.node)},
1064                      sub.map(|x| folder.fold_pat(x)))
1065         }
1066         PatLit(e) => PatLit(folder.fold_expr(e)),
1067         PatEnum(ref pth, ref pats) => {
1068             PatEnum(folder.fold_path(pth),
1069                     pats.as_ref().map(|pats| pats.iter().map(|x| folder.fold_pat(*x)).collect()))
1070         }
1071         PatStruct(ref pth, ref fields, etc) => {
1072             let pth_ = folder.fold_path(pth);
1073             let fs = fields.iter().map(|f| {
1074                 ast::FieldPat {
1075                     ident: f.ident,
1076                     pat: folder.fold_pat(f.pat)
1077                 }
1078             }).collect();
1079             PatStruct(pth_, fs, etc)
1080         }
1081         PatTup(ref elts) => PatTup(elts.iter().map(|x| folder.fold_pat(*x)).collect()),
1082         PatBox(inner) => PatBox(folder.fold_pat(inner)),
1083         PatRegion(inner) => PatRegion(folder.fold_pat(inner)),
1084         PatRange(e1, e2) => {
1085             PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
1086         },
1087         PatVec(ref before, ref slice, ref after) => {
1088             PatVec(before.iter().map(|x| folder.fold_pat(*x)).collect(),
1089                     slice.map(|x| folder.fold_pat(x)),
1090                     after.iter().map(|x| folder.fold_pat(*x)).collect())
1091         }
1092         PatMac(ref mac) => PatMac(folder.fold_mac(mac)),
1093     };
1094
1095     box(GC) Pat {
1096         id: id,
1097         span: folder.new_span(p.span),
1098         node: node,
1099     }
1100 }
1101
1102 pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
1103     let id = folder.new_id(e.id);
1104     let node = match e.node {
1105         ExprBox(p, e) => {
1106             ExprBox(folder.fold_expr(p), folder.fold_expr(e))
1107         }
1108         ExprVec(ref exprs) => {
1109             ExprVec(exprs.iter().map(|&x| folder.fold_expr(x)).collect())
1110         }
1111         ExprRepeat(expr, count) => {
1112             ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count))
1113         }
1114         ExprTup(ref elts) => ExprTup(elts.iter().map(|x| folder.fold_expr(*x)).collect()),
1115         ExprCall(f, ref args) => {
1116             ExprCall(folder.fold_expr(f),
1117                      args.iter().map(|&x| folder.fold_expr(x)).collect())
1118         }
1119         ExprMethodCall(i, ref tps, ref args) => {
1120             ExprMethodCall(
1121                 respan(i.span, folder.fold_ident(i.node)),
1122                 tps.iter().map(|&x| folder.fold_ty(x)).collect(),
1123                 args.iter().map(|&x| folder.fold_expr(x)).collect())
1124         }
1125         ExprBinary(binop, lhs, rhs) => {
1126             ExprBinary(binop,
1127                        folder.fold_expr(lhs),
1128                        folder.fold_expr(rhs))
1129         }
1130         ExprUnary(binop, ohs) => {
1131             ExprUnary(binop, folder.fold_expr(ohs))
1132         }
1133         ExprLit(_) => e.node.clone(),
1134         ExprCast(expr, ty) => {
1135             ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
1136         }
1137         ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
1138         ExprIf(cond, tr, fl) => {
1139             ExprIf(folder.fold_expr(cond),
1140                    folder.fold_block(tr),
1141                    fl.map(|x| folder.fold_expr(x)))
1142         }
1143         ExprWhile(cond, body, opt_ident) => {
1144             ExprWhile(folder.fold_expr(cond),
1145                       folder.fold_block(body),
1146                       opt_ident.map(|i| folder.fold_ident(i)))
1147         }
1148         ExprForLoop(pat, iter, body, ref opt_ident) => {
1149             ExprForLoop(folder.fold_pat(pat),
1150                         folder.fold_expr(iter),
1151                         folder.fold_block(body),
1152                         opt_ident.map(|i| folder.fold_ident(i)))
1153         }
1154         ExprLoop(body, opt_ident) => {
1155             ExprLoop(folder.fold_block(body),
1156                      opt_ident.map(|i| folder.fold_ident(i)))
1157         }
1158         ExprMatch(expr, ref arms) => {
1159             ExprMatch(folder.fold_expr(expr),
1160                       arms.iter().map(|x| folder.fold_arm(x)).collect())
1161         }
1162         ExprFnBlock(capture_clause, ref decl, ref body) => {
1163             ExprFnBlock(capture_clause,
1164                         folder.fold_fn_decl(&**decl),
1165                         folder.fold_block(body.clone()))
1166         }
1167         ExprProc(ref decl, ref body) => {
1168             ExprProc(folder.fold_fn_decl(&**decl),
1169                      folder.fold_block(body.clone()))
1170         }
1171         ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => {
1172             ExprUnboxedFn(capture_clause,
1173                           kind,
1174                           folder.fold_fn_decl(&**decl),
1175                           folder.fold_block(*body))
1176         }
1177         ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
1178         ExprAssign(el, er) => {
1179             ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
1180         }
1181         ExprAssignOp(op, el, er) => {
1182             ExprAssignOp(op,
1183                          folder.fold_expr(el),
1184                          folder.fold_expr(er))
1185         }
1186         ExprField(el, id, ref tys) => {
1187             ExprField(folder.fold_expr(el),
1188                       respan(id.span, folder.fold_ident(id.node)),
1189                       tys.iter().map(|&x| folder.fold_ty(x)).collect())
1190         }
1191         ExprTupField(el, id, ref tys) => {
1192             ExprTupField(folder.fold_expr(el),
1193                       respan(id.span, folder.fold_uint(id.node)),
1194                       tys.iter().map(|&x| folder.fold_ty(x)).collect())
1195         }
1196         ExprIndex(el, er) => {
1197             ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
1198         }
1199         ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
1200         ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
1201         ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
1202         ExprRet(ref e) => {
1203             ExprRet(e.map(|x| folder.fold_expr(x)))
1204         }
1205         ExprInlineAsm(ref a) => {
1206             ExprInlineAsm(InlineAsm {
1207                 inputs: a.inputs.iter().map(|&(ref c, input)| {
1208                     ((*c).clone(), folder.fold_expr(input))
1209                 }).collect(),
1210                 outputs: a.outputs.iter().map(|&(ref c, out, is_rw)| {
1211                     ((*c).clone(), folder.fold_expr(out), is_rw)
1212                 }).collect(),
1213                 .. (*a).clone()
1214             })
1215         }
1216         ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
1217         ExprStruct(ref path, ref fields, maybe_expr) => {
1218             ExprStruct(folder.fold_path(path),
1219                        fields.iter().map(|x| folder.fold_field(*x)).collect(),
1220                        maybe_expr.map(|x| folder.fold_expr(x)))
1221         },
1222         ExprParen(ex) => ExprParen(folder.fold_expr(ex))
1223     };
1224
1225     box(GC) Expr {
1226         id: id,
1227         node: node,
1228         span: folder.new_span(e.span),
1229     }
1230 }
1231
1232 pub fn noop_fold_stmt<T: Folder>(s: &Stmt,
1233                                  folder: &mut T) -> SmallVector<Gc<Stmt>> {
1234     let nodes = match s.node {
1235         StmtDecl(d, id) => {
1236             let id = folder.new_id(id);
1237             folder.fold_decl(d).move_iter()
1238                     .map(|d| StmtDecl(d, id))
1239                     .collect()
1240         }
1241         StmtExpr(e, id) => {
1242             let id = folder.new_id(id);
1243             SmallVector::one(StmtExpr(folder.fold_expr(e), id))
1244         }
1245         StmtSemi(e, id) => {
1246             let id = folder.new_id(id);
1247             SmallVector::one(StmtSemi(folder.fold_expr(e), id))
1248         }
1249         StmtMac(ref mac, semi) => SmallVector::one(StmtMac(folder.fold_mac(mac), semi))
1250     };
1251
1252     nodes.move_iter().map(|node| box(GC) Spanned {
1253         node: node,
1254         span: folder.new_span(s.span),
1255     }).collect()
1256 }
1257
1258 #[cfg(test)]
1259 mod test {
1260     use std::io;
1261     use ast;
1262     use util::parser_testing::{string_to_crate, matches_codepattern};
1263     use parse::token;
1264     use print::pprust;
1265     use fold;
1266     use super::*;
1267
1268     // this version doesn't care about getting comments or docstrings in.
1269     fn fake_print_crate(s: &mut pprust::State,
1270                         krate: &ast::Crate) -> io::IoResult<()> {
1271         s.print_mod(&krate.module, krate.attrs.as_slice())
1272     }
1273
1274     // change every identifier to "zz"
1275     struct ToZzIdentFolder;
1276
1277     impl Folder for ToZzIdentFolder {
1278         fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
1279             token::str_to_ident("zz")
1280         }
1281         fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
1282             fold::noop_fold_mac(macro, self)
1283         }
1284     }
1285
1286     // maybe add to expand.rs...
1287     macro_rules! assert_pred (
1288         ($pred:expr, $predname:expr, $a:expr , $b:expr) => (
1289             {
1290                 let pred_val = $pred;
1291                 let a_val = $a;
1292                 let b_val = $b;
1293                 if !(pred_val(a_val.as_slice(),b_val.as_slice())) {
1294                     fail!("expected args satisfying {}, got {:?} and {:?}",
1295                           $predname, a_val, b_val);
1296                 }
1297             }
1298         )
1299     )
1300
1301     // make sure idents get transformed everywhere
1302     #[test] fn ident_transformation () {
1303         let mut zz_fold = ToZzIdentFolder;
1304         let ast = string_to_crate(
1305             "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string());
1306         let folded_crate = zz_fold.fold_crate(ast);
1307         assert_pred!(
1308             matches_codepattern,
1309             "matches_codepattern",
1310             pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
1311             "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string());
1312     }
1313
1314     // even inside macro defs....
1315     #[test] fn ident_transformation_in_defs () {
1316         let mut zz_fold = ToZzIdentFolder;
1317         let ast = string_to_crate(
1318             "macro_rules! a {(b $c:expr $(d $e:token)f+ => \
1319              (g $(d $d $e)+))} ".to_string());
1320         let folded_crate = zz_fold.fold_crate(ast);
1321         assert_pred!(
1322             matches_codepattern,
1323             "matches_codepattern",
1324             pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
1325             "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))".to_string());
1326     }
1327 }