]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/astencode.rs
2f753523a7bc089fdf2b371fef969aab65029d68
[rust.git] / src / librustc / middle / astencode.rs
1 // Copyright 2012 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 use c = metadata::common;
12 use cstore = metadata::cstore;
13 use driver::session::Session;
14 use e = metadata::encoder;
15 use metadata::decoder;
16 use metadata::encoder;
17 use metadata::tydecode;
18 use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
19 use metadata::tyencode;
20 use middle::freevars::freevar_entry;
21 use middle::typeck::{method_origin, method_map_entry};
22 use middle::{ty, typeck, moves};
23 use middle;
24 use util::ppaux::ty_to_str;
25
26 use std::ebml::reader;
27 use std::ebml;
28 use std::serialize;
29 use std::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers};
30 use std::serialize::{Decoder, Decodable};
31 use syntax::ast;
32 use syntax::ast_map;
33 use syntax::ast_util::inlined_item_utils;
34 use syntax::ast_util;
35 use syntax::codemap::span;
36 use syntax::codemap;
37 use syntax::fold::*;
38 use syntax::fold;
39 use syntax;
40 use writer = std::ebml::writer;
41
42 #[cfg(test)] use syntax::parse;
43 #[cfg(test)] use syntax::print::pprust;
44
45 // Auxiliary maps of things to be encoded
46 pub struct Maps {
47     mutbl_map: middle::borrowck::mutbl_map,
48     root_map: middle::borrowck::root_map,
49     last_use_map: middle::liveness::last_use_map,
50     method_map: middle::typeck::method_map,
51     vtable_map: middle::typeck::vtable_map,
52     write_guard_map: middle::borrowck::write_guard_map,
53     moves_map: middle::moves::MovesMap,
54     capture_map: middle::moves::CaptureMap,
55 }
56
57 struct DecodeContext {
58     cdata: @cstore::crate_metadata,
59     tcx: ty::ctxt,
60     maps: Maps
61 }
62
63 struct ExtendedDecodeContext {
64     dcx: @DecodeContext,
65     from_id_range: ast_util::id_range,
66     to_id_range: ast_util::id_range
67 }
68
69 trait tr {
70     fn tr(&self, xcx: @ExtendedDecodeContext) -> Self;
71 }
72
73 trait tr_intern {
74     fn tr_intern(&self, xcx: @ExtendedDecodeContext) -> ast::def_id;
75 }
76
77 // ______________________________________________________________________
78 // Top-level methods.
79
80 pub fn encode_inlined_item(ecx: @e::EncodeContext,
81                            ebml_w: &writer::Encoder,
82                            path: &[ast_map::path_elt],
83                            ii: ast::inlined_item,
84                            maps: Maps) {
85     debug!("> Encoding inlined item: %s::%s (%u)",
86            ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner),
87            *ecx.tcx.sess.str_of(ii.ident()),
88            ebml_w.writer.tell());
89
90     let id_range = ast_util::compute_id_range_for_inlined_item(&ii);
91     do ebml_w.wr_tag(c::tag_ast as uint) {
92         id_range.encode(ebml_w);
93         encode_ast(ebml_w, simplify_ast(&ii));
94         encode_side_tables_for_ii(ecx, maps, ebml_w, &ii);
95     }
96
97     debug!("< Encoded inlined fn: %s::%s (%u)",
98            ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner),
99            *ecx.tcx.sess.str_of(ii.ident()),
100            ebml_w.writer.tell());
101 }
102
103 pub fn decode_inlined_item(cdata: @cstore::crate_metadata,
104                            tcx: ty::ctxt,
105                            maps: Maps,
106                            path: ast_map::path,
107                            par_doc: ebml::Doc)
108                         -> Option<ast::inlined_item> {
109     let dcx = @DecodeContext {
110         cdata: cdata,
111         tcx: tcx,
112         maps: maps
113     };
114     match par_doc.opt_child(c::tag_ast) {
115       None => None,
116       Some(ast_doc) => {
117         debug!("> Decoding inlined fn: %s::?",
118                ast_map::path_to_str(path, tcx.sess.parse_sess.interner));
119         let ast_dsr = &reader::Decoder(ast_doc);
120         let from_id_range = Decodable::decode(ast_dsr);
121         let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range);
122         let xcx = @ExtendedDecodeContext {
123             dcx: dcx,
124             from_id_range: from_id_range,
125             to_id_range: to_id_range
126         };
127         let raw_ii = decode_ast(ast_doc);
128         let ii = renumber_ast(xcx, raw_ii);
129         debug!("Fn named: %s", *tcx.sess.str_of(ii.ident()));
130         debug!("< Decoded inlined fn: %s::%s",
131                ast_map::path_to_str(path, tcx.sess.parse_sess.interner),
132                *tcx.sess.str_of(ii.ident()));
133         ast_map::map_decoded_item(tcx.sess.diagnostic(),
134                                   dcx.tcx.items, path, &ii);
135         decode_side_tables(xcx, ast_doc);
136         match ii {
137           ast::ii_item(i) => {
138             debug!(">>> DECODED ITEM >>>\n%s\n<<< DECODED ITEM <<<",
139                    syntax::print::pprust::item_to_str(i, tcx.sess.intr()));
140           }
141           _ => { }
142         }
143         Some(ii)
144       }
145     }
146 }
147
148 // ______________________________________________________________________
149 // Enumerating the IDs which appear in an AST
150
151 fn reserve_id_range(sess: Session,
152                     from_id_range: ast_util::id_range) -> ast_util::id_range {
153     // Handle the case of an empty range:
154     if ast_util::empty(from_id_range) { return from_id_range; }
155     let cnt = from_id_range.max - from_id_range.min;
156     let to_id_min = sess.parse_sess.next_id;
157     let to_id_max = sess.parse_sess.next_id + cnt;
158     sess.parse_sess.next_id = to_id_max;
159     ast_util::id_range { min: to_id_min, max: to_id_min }
160 }
161
162 pub impl ExtendedDecodeContext {
163     fn tr_id(&self, id: ast::node_id) -> ast::node_id {
164         /*!
165          *
166          * Translates an internal id, meaning a node id that is known
167          * to refer to some part of the item currently being inlined,
168          * such as a local variable or argument.  All naked node-ids
169          * that appear in types have this property, since if something
170          * might refer to an external item we would use a def-id to
171          * allow for the possibility that the item resides in another
172          * crate.
173          */
174
175         // from_id_range should be non-empty
176         assert!(!ast_util::empty(self.from_id_range));
177         (id - self.from_id_range.min + self.to_id_range.min)
178     }
179     fn tr_def_id(&self, did: ast::def_id) -> ast::def_id {
180         /*!
181          *
182          * Translates an EXTERNAL def-id, converting the crate number
183          * from the one used in the encoded data to the current crate
184          * numbers..  By external, I mean that it be translated to a
185          * reference to the item in its original crate, as opposed to
186          * being translated to a reference to the inlined version of
187          * the item.  This is typically, but not always, what you
188          * want, because most def-ids refer to external things like
189          * types or other fns that may or may not be inlined.  Note
190          * that even when the inlined function is referencing itself
191          * recursively, we would want `tr_def_id` for that
192          * reference--- conceptually the function calls the original,
193          * non-inlined version, and trans deals with linking that
194          * recursive call to the inlined copy.
195          *
196          * However, there are a *few* cases where def-ids are used but
197          * we know that the thing being referenced is in fact *internal*
198          * to the item being inlined.  In those cases, you should use
199          * `tr_intern_def_id()` below.
200          */
201
202         decoder::translate_def_id(self.dcx.cdata, did)
203     }
204     fn tr_intern_def_id(&self, did: ast::def_id) -> ast::def_id {
205         /*!
206          *
207          * Translates an INTERNAL def-id, meaning a def-id that is
208          * known to refer to some part of the item currently being
209          * inlined.  In that case, we want to convert the def-id to
210          * refer to the current crate and to the new, inlined node-id.
211          */
212
213         assert!(did.crate == ast::local_crate);
214         ast::def_id { crate: ast::local_crate, node: self.tr_id(did.node) }
215     }
216     fn tr_span(&self, _span: span) -> span {
217         codemap::dummy_sp() // FIXME (#1972): handle span properly
218     }
219 }
220
221 impl tr_intern for ast::def_id {
222     fn tr_intern(&self, xcx: @ExtendedDecodeContext) -> ast::def_id {
223         xcx.tr_intern_def_id(*self)
224     }
225 }
226
227 impl tr for ast::def_id {
228     fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def_id {
229         xcx.tr_def_id(*self)
230     }
231 }
232
233 impl tr for span {
234     fn tr(&self, xcx: @ExtendedDecodeContext) -> span {
235         xcx.tr_span(*self)
236     }
237 }
238
239 trait def_id_encoder_helpers {
240     fn emit_def_id(&self, did: ast::def_id);
241 }
242
243 impl<S:serialize::Encoder> def_id_encoder_helpers for S {
244     fn emit_def_id(&self, did: ast::def_id) {
245         did.encode(self)
246     }
247 }
248
249 trait def_id_decoder_helpers {
250     fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id;
251 }
252
253 impl<D:serialize::Decoder> def_id_decoder_helpers for D {
254
255     fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id {
256         let did: ast::def_id = Decodable::decode(self);
257         did.tr(xcx)
258     }
259 }
260
261 // ______________________________________________________________________
262 // Encoding and decoding the AST itself
263 //
264 // The hard work is done by an autogenerated module astencode_gen.  To
265 // regenerate astencode_gen, run src/etc/gen-astencode.  It will
266 // replace astencode_gen with a dummy file and regenerate its
267 // contents.  If you get compile errors, the dummy file
268 // remains---resolve the errors and then rerun astencode_gen.
269 // Annoying, I know, but hopefully only temporary.
270 //
271 // When decoding, we have to renumber the AST so that the node ids that
272 // appear within are disjoint from the node ids in our existing ASTs.
273 // We also have to adjust the spans: for now we just insert a dummy span,
274 // but eventually we should add entries to the local codemap as required.
275
276 fn encode_ast(ebml_w: &writer::Encoder, item: ast::inlined_item) {
277     do ebml_w.wr_tag(c::tag_tree as uint) {
278         item.encode(ebml_w)
279     }
280 }
281
282 // Produces a simplified copy of the AST which does not include things
283 // that we do not need to or do not want to export.  For example, we
284 // do not include any nested items: if these nested items are to be
285 // inlined, their AST will be exported separately (this only makes
286 // sense because, in Rust, nested items are independent except for
287 // their visibility).
288 //
289 // As it happens, trans relies on the fact that we do not export
290 // nested items, as otherwise it would get confused when translating
291 // inlined items.
292 fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
293     fn drop_nested_items(blk: &ast::blk_, fld: @fold::ast_fold) -> ast::blk_ {
294         let stmts_sans_items = do blk.stmts.filtered |stmt| {
295             match stmt.node {
296               ast::stmt_expr(_, _) | ast::stmt_semi(_, _) |
297               ast::stmt_decl(@codemap::spanned { node: ast::decl_local(_),
298                                              span: _}, _) => true,
299               ast::stmt_decl(@codemap::spanned { node: ast::decl_item(_),
300                                              span: _}, _) => false,
301               ast::stmt_mac(*) => fail!(~"unexpanded macro in astencode")
302             }
303         };
304         let blk_sans_items = ast::blk_ {
305             view_items: ~[], // I don't know if we need the view_items here,
306                              // but it doesn't break tests!
307             stmts: stmts_sans_items,
308             expr: blk.expr,
309             id: blk.id,
310             rules: blk.rules
311         };
312         fold::noop_fold_block(&blk_sans_items, fld)
313     }
314
315     let fld = fold::make_fold(@fold::AstFoldFns {
316         fold_block: fold::wrap(drop_nested_items),
317         .. *fold::default_ast_fold()
318     });
319
320     match *ii {
321       ast::ii_item(i) => {
322         ast::ii_item(fld.fold_item(i).get()) //hack: we're not dropping items
323       }
324       ast::ii_method(d, m) => {
325         ast::ii_method(d, fld.fold_method(m))
326       }
327       ast::ii_foreign(i) => {
328         ast::ii_foreign(fld.fold_foreign_item(i))
329       }
330     }
331 }
332
333 fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
334     let chi_doc = par_doc.get(c::tag_tree as uint);
335     let d = &reader::Decoder(chi_doc);
336     Decodable::decode(d)
337 }
338
339 fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)
340     -> ast::inlined_item {
341     let fld = fold::make_fold(@fold::AstFoldFns{
342         new_id: |a| xcx.tr_id(a),
343         new_span: |a| xcx.tr_span(a),
344         .. *fold::default_ast_fold()
345     });
346
347     match ii {
348       ast::ii_item(i) => {
349         ast::ii_item(fld.fold_item(i).get())
350       }
351       ast::ii_method(d, m) => {
352         ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m))
353       }
354       ast::ii_foreign(i) => {
355         ast::ii_foreign(fld.fold_foreign_item(i))
356       }
357      }
358 }
359
360 // ______________________________________________________________________
361 // Encoding and decoding of ast::def
362
363 fn encode_def(ebml_w: &writer::Encoder, def: ast::def) {
364     def.encode(ebml_w)
365 }
366
367 fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def {
368     let dsr = &reader::Decoder(doc);
369     let def: ast::def = Decodable::decode(dsr);
370     def.tr(xcx)
371 }
372
373 impl tr for ast::def {
374     fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def {
375         match *self {
376           ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) }
377           ast::def_static_method(did, did2_opt, p) => {
378             ast::def_static_method(did.tr(xcx),
379                                    did2_opt.map(|did2| did2.tr(xcx)),
380                                    p)
381           }
382           ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
383           ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
384           ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
385           ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
386           ast::def_const(did) => { ast::def_const(did.tr(xcx)) }
387           ast::def_arg(nid, b) => { ast::def_arg(xcx.tr_id(nid), b) }
388           ast::def_local(nid, b) => { ast::def_local(xcx.tr_id(nid), b) }
389           ast::def_variant(e_did, v_did) => {
390             ast::def_variant(e_did.tr(xcx), v_did.tr(xcx))
391           }
392           ast::def_trait(did) => ast::def_trait(did.tr(xcx)),
393           ast::def_ty(did) => ast::def_ty(did.tr(xcx)),
394           ast::def_prim_ty(p) => ast::def_prim_ty(p),
395           ast::def_ty_param(did, v) => ast::def_ty_param(did.tr(xcx), v),
396           ast::def_binding(nid, bm) => ast::def_binding(xcx.tr_id(nid), bm),
397           ast::def_use(did) => ast::def_use(did.tr(xcx)),
398           ast::def_upvar(nid1, def, nid2, nid3) => {
399             ast::def_upvar(xcx.tr_id(nid1),
400                            @(*def).tr(xcx),
401                            xcx.tr_id(nid2),
402                            xcx.tr_id(nid3))
403           }
404           ast::def_struct(did) => {
405             ast::def_struct(did.tr(xcx))
406           }
407           ast::def_region(nid) => ast::def_region(xcx.tr_id(nid)),
408           ast::def_typaram_binder(nid) => {
409             ast::def_typaram_binder(xcx.tr_id(nid))
410           }
411           ast::def_label(nid) => ast::def_label(xcx.tr_id(nid))
412         }
413     }
414 }
415
416 // ______________________________________________________________________
417 // Encoding and decoding of adjustment information
418
419 impl tr for ty::AutoAdjustment {
420     fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment {
421         match self {
422             &ty::AutoAddEnv(r, s) => {
423                 ty::AutoAddEnv(r.tr(xcx), s)
424             }
425
426             &ty::AutoDerefRef(ref adr) => {
427                 ty::AutoDerefRef(ty::AutoDerefRef {
428                     autoderefs: adr.autoderefs,
429                     autoref: adr.autoref.map(|ar| ar.tr(xcx)),
430                 })
431             }
432         }
433     }
434 }
435
436 impl tr for ty::AutoRef {
437     fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoRef {
438         ty::AutoRef {
439             kind: self.kind,
440             region: self.region.tr(xcx),
441             mutbl: self.mutbl,
442         }
443     }
444 }
445
446 impl tr for ty::Region {
447     fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region {
448         match *self {
449             ty::re_bound(br) => ty::re_bound(br.tr(xcx)),
450             ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)),
451             ty::re_static | ty::re_infer(*) => *self,
452             ty::re_free(ref fr) => {
453                 ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id),
454                                             bound_region: fr.bound_region.tr(xcx)})
455             }
456         }
457     }
458 }
459
460 impl tr for ty::bound_region {
461     fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::bound_region {
462         match *self {
463             ty::br_anon(_) | ty::br_named(_) | ty::br_self |
464             ty::br_fresh(_) => *self,
465             ty::br_cap_avoid(id, br) => ty::br_cap_avoid(xcx.tr_id(id),
466                                                          @br.tr(xcx))
467         }
468     }
469 }
470
471 // ______________________________________________________________________
472 // Encoding and decoding of freevar information
473
474 fn encode_freevar_entry(ebml_w: &writer::Encoder, fv: @freevar_entry) {
475     (*fv).encode(ebml_w)
476 }
477
478 trait ebml_decoder_helper {
479     fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext)
480                          -> freevar_entry;
481 }
482
483 impl ebml_decoder_helper for reader::Decoder {
484     fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext)
485                          -> freevar_entry {
486         let fv: freevar_entry = Decodable::decode(self);
487         fv.tr(xcx)
488     }
489 }
490
491 impl tr for freevar_entry {
492     fn tr(&self, xcx: @ExtendedDecodeContext) -> freevar_entry {
493         freevar_entry {
494             def: self.def.tr(xcx),
495             span: self.span.tr(xcx),
496         }
497     }
498 }
499
500 // ______________________________________________________________________
501 // Encoding and decoding of CaptureVar information
502
503 trait capture_var_helper {
504     fn read_capture_var(&self, xcx: @ExtendedDecodeContext)
505                        -> moves::CaptureVar;
506 }
507
508 impl capture_var_helper for reader::Decoder {
509     fn read_capture_var(&self, xcx: @ExtendedDecodeContext)
510                        -> moves::CaptureVar {
511         let cvar: moves::CaptureVar = Decodable::decode(self);
512         cvar.tr(xcx)
513     }
514 }
515
516 impl tr for moves::CaptureVar {
517     fn tr(&self, xcx: @ExtendedDecodeContext) -> moves::CaptureVar {
518         moves::CaptureVar {
519             def: self.def.tr(xcx),
520             span: self.span.tr(xcx),
521             mode: self.mode
522         }
523     }
524 }
525
526 // ______________________________________________________________________
527 // Encoding and decoding of method_map_entry
528
529 trait read_method_map_entry_helper {
530     fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext)
531                             -> method_map_entry;
532 }
533
534 #[cfg(stage0)]
535 fn encode_method_map_entry(ecx: @e::EncodeContext,
536                               ebml_w: &writer::Encoder,
537                               mme: method_map_entry) {
538     do ebml_w.emit_struct("method_map_entry", 3) {
539         do ebml_w.emit_field(~"self_arg", 0u) {
540             ebml_w.emit_arg(ecx, mme.self_arg);
541         }
542         do ebml_w.emit_field(~"explicit_self", 2u) {
543             mme.explicit_self.encode(ebml_w);
544         }
545         do ebml_w.emit_field(~"origin", 1u) {
546             mme.origin.encode(ebml_w);
547         }
548         do ebml_w.emit_field(~"self_mode", 3) {
549             mme.self_mode.encode(ebml_w);
550         }
551     }
552 }
553
554 #[cfg(stage1)]
555 #[cfg(stage2)]
556 #[cfg(stage3)]
557 fn encode_method_map_entry(ecx: @e::EncodeContext,
558                               ebml_w: &writer::Encoder,
559                               mme: method_map_entry) {
560     do ebml_w.emit_struct("method_map_entry", 3) {
561         do ebml_w.emit_struct_field("self_arg", 0u) {
562             ebml_w.emit_arg(ecx, mme.self_arg);
563         }
564         do ebml_w.emit_struct_field("explicit_self", 2u) {
565             mme.explicit_self.encode(ebml_w);
566         }
567         do ebml_w.emit_struct_field("origin", 1u) {
568             mme.origin.encode(ebml_w);
569         }
570         do ebml_w.emit_struct_field("self_mode", 3) {
571             mme.self_mode.encode(ebml_w);
572         }
573     }
574 }
575
576 impl read_method_map_entry_helper for reader::Decoder {
577     #[cfg(stage0)]
578     fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext)
579         -> method_map_entry {
580         do self.read_struct("method_map_entry", 3) {
581             method_map_entry {
582                 self_arg: self.read_field(~"self_arg", 0u, || {
583                     self.read_arg(xcx)
584                 }),
585                 explicit_self: self.read_field(~"explicit_self", 2u, || {
586                     let self_type: ast::self_ty_ = Decodable::decode(self);
587                     self_type
588                 }),
589                 origin: self.read_field(~"origin", 1u, || {
590                     let method_origin: method_origin =
591                         Decodable::decode(self);
592                     method_origin.tr(xcx)
593                 }),
594                 self_mode: self.read_field(~"self_mode", 3, || {
595                     let self_mode: ty::SelfMode = Decodable::decode(self);
596                     self_mode
597                 }),
598             }
599         }
600     }
601
602     #[cfg(stage1)]
603     #[cfg(stage2)]
604     #[cfg(stage3)]
605     fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext)
606         -> method_map_entry {
607         do self.read_struct("method_map_entry", 3) {
608             method_map_entry {
609                 self_arg: self.read_struct_field("self_arg", 0u, || {
610                     self.read_arg(xcx)
611                 }),
612                 explicit_self: self.read_struct_field("explicit_self", 2, || {
613                     let self_type: ast::self_ty_ = Decodable::decode(self);
614                     self_type
615                 }),
616                 origin: self.read_struct_field("origin", 1u, || {
617                     let method_origin: method_origin =
618                         Decodable::decode(self);
619                     method_origin.tr(xcx)
620                 }),
621                 self_mode: self.read_struct_field("self_mode", 3, || {
622                     let self_mode: ty::SelfMode = Decodable::decode(self);
623                     self_mode
624                 }),
625             }
626         }
627     }
628 }
629
630 impl tr for method_origin {
631     fn tr(&self, xcx: @ExtendedDecodeContext) -> method_origin {
632         match *self {
633           typeck::method_static(did) => {
634               typeck::method_static(did.tr(xcx))
635           }
636           typeck::method_param(ref mp) => {
637             typeck::method_param(
638                 typeck::method_param {
639                     trait_id: mp.trait_id.tr(xcx),
640                     .. *mp
641                 }
642             )
643           }
644           typeck::method_trait(did, m, vstore) => {
645               typeck::method_trait(did.tr(xcx), m, vstore)
646           }
647           typeck::method_self(did, m) => {
648               typeck::method_self(did.tr(xcx), m)
649           }
650           typeck::method_super(trait_did, m) => {
651               typeck::method_super(trait_did.tr(xcx), m)
652           }
653         }
654     }
655 }
656
657 // ______________________________________________________________________
658 // Encoding and decoding vtable_res
659
660 fn encode_vtable_res(ecx: @e::EncodeContext,
661                      ebml_w: &writer::Encoder,
662                      dr: typeck::vtable_res) {
663     // can't autogenerate this code because automatic code of
664     // ty::t doesn't work, and there is no way (atm) to have
665     // hand-written encoding routines combine with auto-generated
666     // ones.  perhaps we should fix this.
667     do ebml_w.emit_from_vec(*dr) |vtable_origin| {
668         encode_vtable_origin(ecx, ebml_w, vtable_origin)
669     }
670 }
671
672 fn encode_vtable_origin(ecx: @e::EncodeContext,
673                         ebml_w: &writer::Encoder,
674                         vtable_origin: &typeck::vtable_origin) {
675     do ebml_w.emit_enum(~"vtable_origin") {
676         match *vtable_origin {
677           typeck::vtable_static(def_id, ref tys, vtable_res) => {
678             do ebml_w.emit_enum_variant(~"vtable_static", 0u, 3u) {
679                 do ebml_w.emit_enum_variant_arg(0u) {
680                     ebml_w.emit_def_id(def_id)
681                 }
682                 do ebml_w.emit_enum_variant_arg(1u) {
683                     ebml_w.emit_tys(ecx, /*bad*/copy *tys);
684                 }
685                 do ebml_w.emit_enum_variant_arg(2u) {
686                     encode_vtable_res(ecx, ebml_w, vtable_res);
687                 }
688             }
689           }
690           typeck::vtable_param(pn, bn) => {
691             do ebml_w.emit_enum_variant(~"vtable_param", 1u, 2u) {
692                 do ebml_w.emit_enum_variant_arg(0u) {
693                     ebml_w.emit_uint(pn);
694                 }
695                 do ebml_w.emit_enum_variant_arg(1u) {
696                     ebml_w.emit_uint(bn);
697                 }
698             }
699           }
700         }
701     }
702
703 }
704
705 trait vtable_decoder_helpers {
706     fn read_vtable_res(&self, xcx: @ExtendedDecodeContext)
707                       -> typeck::vtable_res;
708     fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
709         -> typeck::vtable_origin;
710 }
711
712 impl vtable_decoder_helpers for reader::Decoder {
713     fn read_vtable_res(&self, xcx: @ExtendedDecodeContext)
714                       -> typeck::vtable_res {
715         @self.read_to_vec(|| self.read_vtable_origin(xcx) )
716     }
717
718     fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext)
719         -> typeck::vtable_origin {
720         do self.read_enum("vtable_origin") {
721             do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| {
722                 match i {
723                   0 => {
724                     typeck::vtable_static(
725                         do self.read_enum_variant_arg(0u) {
726                             self.read_def_id(xcx)
727                         },
728                         do self.read_enum_variant_arg(1u) {
729                             self.read_tys(xcx)
730                         },
731                         do self.read_enum_variant_arg(2u) {
732                             self.read_vtable_res(xcx)
733                         }
734                     )
735                   }
736                   1 => {
737                     typeck::vtable_param(
738                         do self.read_enum_variant_arg(0u) {
739                             self.read_uint()
740                         },
741                         do self.read_enum_variant_arg(1u) {
742                             self.read_uint()
743                         }
744                     )
745                   }
746                   // hard to avoid - user input
747                   _ => fail!(~"bad enum variant")
748                 }
749             }
750         }
751     }
752 }
753
754 // ______________________________________________________________________
755 // Encoding and decoding the side tables
756
757 trait get_ty_str_ctxt {
758     fn ty_str_ctxt(@self) -> @tyencode::ctxt;
759 }
760
761 impl get_ty_str_ctxt for e::EncodeContext {
762     // IMPLICIT SELF WARNING: fix this!
763     fn ty_str_ctxt(@self) -> @tyencode::ctxt {
764         @tyencode::ctxt {diag: self.tcx.sess.diagnostic(),
765                         ds: e::def_to_str,
766                         tcx: self.tcx,
767                         reachable: |a| encoder::reachable(self, a),
768                         abbrevs: tyencode::ac_use_abbrevs(self.type_abbrevs)}
769     }
770 }
771
772 trait ebml_writer_helpers {
773     fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg);
774     fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t);
775     fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore);
776     fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]);
777     fn emit_type_param_def(&self,
778                            ecx: @e::EncodeContext,
779                            type_param_def: &ty::TypeParameterDef);
780     fn emit_tpbt(&self, ecx: @e::EncodeContext,
781                  tpbt: ty::ty_param_bounds_and_ty);
782 }
783
784 impl ebml_writer_helpers for writer::Encoder {
785     fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t) {
786         do self.emit_opaque {
787             e::write_type(ecx, self, ty)
788         }
789     }
790
791     fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore) {
792         do self.emit_opaque {
793             e::write_vstore(ecx, self, vstore)
794         }
795     }
796
797     fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg) {
798         do self.emit_opaque {
799             tyencode::enc_arg(self.writer, ecx.ty_str_ctxt(), arg);
800         }
801     }
802
803     fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]) {
804         do self.emit_from_vec(tys) |ty| {
805             self.emit_ty(ecx, *ty)
806         }
807     }
808
809     fn emit_type_param_def(&self,
810                            ecx: @e::EncodeContext,
811                            type_param_def: &ty::TypeParameterDef) {
812         do self.emit_opaque {
813             tyencode::enc_type_param_def(self.writer, ecx.ty_str_ctxt(),
814                                          type_param_def)
815         }
816     }
817
818     #[cfg(stage0)]
819     fn emit_tpbt(&self, ecx: @e::EncodeContext,
820                  tpbt: ty::ty_param_bounds_and_ty) {
821         do self.emit_struct("ty_param_bounds_and_ty", 2) {
822             do self.emit_field(~"generics", 0) {
823                 do self.emit_struct("Generics", 2) {
824                     do self.emit_field(~"type_param_defs", 0) {
825                         do self.emit_from_vec(*tpbt.generics.type_param_defs)
826                             |type_param_def|
827                         {
828                             self.emit_type_param_def(ecx, type_param_def);
829                         }
830                     }
831                     do self.emit_field(~"region_param", 1) {
832                         tpbt.generics.region_param.encode(self);
833                     }
834                 }
835             }
836             do self.emit_field(~"ty", 1) {
837                 self.emit_ty(ecx, tpbt.ty);
838             }
839         }
840     }
841
842     #[cfg(stage1)]
843     #[cfg(stage2)]
844     #[cfg(stage3)]
845     fn emit_tpbt(&self, ecx: @e::EncodeContext,
846                  tpbt: ty::ty_param_bounds_and_ty) {
847         do self.emit_struct("ty_param_bounds_and_ty", 2) {
848             do self.emit_struct_field("generics", 0) {
849                 do self.emit_struct("Generics", 2) {
850                     do self.emit_struct_field("type_param_defs", 0) {
851                         do self.emit_from_vec(*tpbt.generics.type_param_defs)
852                             |type_param_def|
853                         {
854                             self.emit_type_param_def(ecx, type_param_def);
855                         }
856                     }
857                     do self.emit_struct_field("region_param", 1) {
858                         tpbt.generics.region_param.encode(self);
859                     }
860                 }
861             }
862             do self.emit_struct_field("ty", 1) {
863                 self.emit_ty(ecx, tpbt.ty);
864             }
865         }
866     }
867 }
868
869 trait write_tag_and_id {
870     fn tag(&self, tag_id: c::astencode_tag, f: &fn());
871     fn id(&self, id: ast::node_id);
872 }
873
874 impl write_tag_and_id for writer::Encoder {
875     fn tag(&self, tag_id: c::astencode_tag, f: &fn()) {
876         do self.wr_tag(tag_id as uint) { f() }
877     }
878
879     fn id(&self, id: ast::node_id) {
880         self.wr_tagged_u64(c::tag_table_id as uint, id as u64)
881     }
882 }
883
884 fn encode_side_tables_for_ii(ecx: @e::EncodeContext,
885                              maps: Maps,
886                              ebml_w: &writer::Encoder,
887                              ii: &ast::inlined_item) {
888     do ebml_w.wr_tag(c::tag_table as uint) {
889         let ebml_w = copy *ebml_w;
890         ast_util::visit_ids_for_inlined_item(
891             ii,
892             |id: ast::node_id| {
893                 // Note: this will cause a copy of ebml_w, which is bad as
894                 // it has mut fields.  But I believe it's harmless since
895                 // we generate balanced EBML.
896                 /*let ebml_w = copy ebml_w;*/
897                 encode_side_tables_for_id(ecx, maps, &ebml_w, id)
898             });
899     }
900 }
901
902 fn encode_side_tables_for_id(ecx: @e::EncodeContext,
903                              maps: Maps,
904                              ebml_w: &writer::Encoder,
905                              id: ast::node_id) {
906     let tcx = ecx.tcx;
907
908     debug!("Encoding side tables for id %d", id);
909
910     for tcx.def_map.find(&id).each |def| {
911         do ebml_w.tag(c::tag_table_def) {
912             ebml_w.id(id);
913             do ebml_w.tag(c::tag_table_val) {
914                 (*def).encode(ebml_w)
915             }
916         }
917     }
918
919     for tcx.node_types.find(&(id as uint)).each |&ty| {
920         do ebml_w.tag(c::tag_table_node_type) {
921             ebml_w.id(id);
922             do ebml_w.tag(c::tag_table_val) {
923                 ebml_w.emit_ty(ecx, *ty);
924             }
925         }
926     }
927
928     for tcx.node_type_substs.find(&id).each |tys| {
929         do ebml_w.tag(c::tag_table_node_type_subst) {
930             ebml_w.id(id);
931             do ebml_w.tag(c::tag_table_val) {
932                 // FIXME(#5562): removing this copy causes a segfault
933                 //               before stage2
934                 ebml_w.emit_tys(ecx, /*bad*/copy **tys)
935             }
936         }
937     }
938
939     for tcx.freevars.find(&id).each |&fv| {
940         do ebml_w.tag(c::tag_table_freevars) {
941             ebml_w.id(id);
942             do ebml_w.tag(c::tag_table_val) {
943                 do ebml_w.emit_from_vec(**fv) |fv_entry| {
944                     encode_freevar_entry(ebml_w, *fv_entry)
945                 }
946             }
947         }
948     }
949
950     let lid = ast::def_id { crate: ast::local_crate, node: id };
951     for tcx.tcache.find(&lid).each |&tpbt| {
952         do ebml_w.tag(c::tag_table_tcache) {
953             ebml_w.id(id);
954             do ebml_w.tag(c::tag_table_val) {
955                 ebml_w.emit_tpbt(ecx, *tpbt);
956             }
957         }
958     }
959
960     for tcx.ty_param_defs.find(&id).each |&type_param_def| {
961         do ebml_w.tag(c::tag_table_param_defs) {
962             ebml_w.id(id);
963             do ebml_w.tag(c::tag_table_val) {
964                 ebml_w.emit_type_param_def(ecx, type_param_def)
965             }
966         }
967     }
968
969     if maps.mutbl_map.contains(&id) {
970         do ebml_w.tag(c::tag_table_mutbl) {
971             ebml_w.id(id);
972         }
973     }
974
975     for maps.last_use_map.find(&id).each |&m| {
976         do ebml_w.tag(c::tag_table_last_use) {
977             ebml_w.id(id);
978             do ebml_w.tag(c::tag_table_val) {
979                 do ebml_w.emit_from_vec(/*bad*/ copy **m) |id| {
980                     id.encode(ebml_w);
981                 }
982             }
983         }
984     }
985
986     for maps.method_map.find(&id).each |&mme| {
987         do ebml_w.tag(c::tag_table_method_map) {
988             ebml_w.id(id);
989             do ebml_w.tag(c::tag_table_val) {
990                 encode_method_map_entry(ecx, ebml_w, *mme)
991             }
992         }
993     }
994
995     for maps.vtable_map.find(&id).each |&dr| {
996         do ebml_w.tag(c::tag_table_vtable_map) {
997             ebml_w.id(id);
998             do ebml_w.tag(c::tag_table_val) {
999                 encode_vtable_res(ecx, ebml_w, *dr);
1000             }
1001         }
1002     }
1003
1004     for tcx.adjustments.find(&id).each |adj| {
1005         do ebml_w.tag(c::tag_table_adjustments) {
1006             ebml_w.id(id);
1007             do ebml_w.tag(c::tag_table_val) {
1008                 (**adj).encode(ebml_w)
1009             }
1010         }
1011     }
1012
1013     if maps.moves_map.contains(&id) {
1014         do ebml_w.tag(c::tag_table_moves_map) {
1015             ebml_w.id(id);
1016         }
1017     }
1018
1019     for maps.capture_map.find(&id).each |&cap_vars| {
1020         do ebml_w.tag(c::tag_table_capture_map) {
1021             ebml_w.id(id);
1022             do ebml_w.tag(c::tag_table_val) {
1023                 do ebml_w.emit_from_vec(*cap_vars) |cap_var| {
1024                     cap_var.encode(ebml_w);
1025                 }
1026             }
1027         }
1028     }
1029 }
1030
1031 trait doc_decoder_helpers {
1032     fn as_int(&self) -> int;
1033     fn opt_child(&self, tag: c::astencode_tag) -> Option<ebml::Doc>;
1034 }
1035
1036 impl doc_decoder_helpers for ebml::Doc {
1037     fn as_int(&self) -> int { reader::doc_as_u64(*self) as int }
1038     fn opt_child(&self, tag: c::astencode_tag) -> Option<ebml::Doc> {
1039         reader::maybe_get_doc(*self, tag as uint)
1040     }
1041 }
1042
1043 trait ebml_decoder_decoder_helpers {
1044     fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg;
1045     fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t;
1046     fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t];
1047     fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef;
1048     fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext)
1049                                 -> ty::ty_param_bounds_and_ty;
1050     fn convert_def_id(&self, xcx: @ExtendedDecodeContext,
1051                       source: DefIdSource,
1052                       did: ast::def_id) -> ast::def_id;
1053 }
1054
1055 impl ebml_decoder_decoder_helpers for reader::Decoder {
1056     fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg {
1057         do self.read_opaque |doc| {
1058             tydecode::parse_arg_data(
1059                 doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx,
1060                 |s, a| self.convert_def_id(xcx, s, a))
1061         }
1062     }
1063
1064     fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t {
1065         // Note: regions types embed local node ids.  In principle, we
1066         // should translate these node ids into the new decode
1067         // context.  However, we do not bother, because region types
1068         // are not used during trans.
1069
1070         return do self.read_opaque |doc| {
1071
1072             let ty = tydecode::parse_ty_data(
1073                 doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx,
1074                 |s, a| self.convert_def_id(xcx, s, a));
1075
1076             debug!("read_ty(%s) = %s",
1077                    type_string(doc), ty_to_str(xcx.dcx.tcx, ty));
1078
1079             ty
1080         };
1081
1082         fn type_string(doc: ebml::Doc) -> ~str {
1083             let mut str = ~"";
1084             for uint::range(doc.start, doc.end) |i| {
1085                 str::push_char(&mut str, doc.data[i] as char);
1086             }
1087             str
1088         }
1089     }
1090
1091     fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t] {
1092         self.read_to_vec(|| self.read_ty(xcx) )
1093     }
1094
1095     fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef {
1096         do self.read_opaque |doc| {
1097             tydecode::parse_type_param_def_data(
1098                 doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx,
1099                 |s, a| self.convert_def_id(xcx, s, a))
1100         }
1101     }
1102
1103     #[cfg(stage0)]
1104     fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext)
1105         -> ty::ty_param_bounds_and_ty
1106     {
1107         do self.read_struct("ty_param_bounds_and_ty", 2) {
1108             ty::ty_param_bounds_and_ty {
1109                 generics: do self.read_struct("Generics", 2) {
1110                     ty::Generics {
1111                         type_param_defs: self.read_field("type_param_defs", 0, || {
1112                             @self.read_to_vec(|| self.read_type_param_def(xcx))
1113                         }),
1114                         region_param: self.read_field(~"region_param", 1, || {
1115                             Decodable::decode(self)
1116                         })
1117                     }
1118                 },
1119                 ty: self.read_field(~"ty", 1, || {
1120                     self.read_ty(xcx)
1121                 })
1122             }
1123         }
1124     }
1125
1126     #[cfg(stage1)]
1127     #[cfg(stage2)]
1128     #[cfg(stage3)]
1129     fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext)
1130         -> ty::ty_param_bounds_and_ty
1131     {
1132         do self.read_struct("ty_param_bounds_and_ty", 2) {
1133             ty::ty_param_bounds_and_ty {
1134                 generics: do self.read_struct("Generics", 2) {
1135                     ty::Generics {
1136                         type_param_defs: self.read_struct_field("type_param_defs", 0, || {
1137                             @self.read_to_vec(|| self.read_type_param_def(xcx))
1138                         }),
1139                         region_param: self.read_struct_field(~"region_param", 1, || {
1140                             Decodable::decode(self)
1141                         })
1142                     }
1143                 },
1144                 ty: self.read_struct_field("ty", 1, || {
1145                     self.read_ty(xcx)
1146                 })
1147             }
1148         }
1149     }
1150
1151     fn convert_def_id(&self, xcx: @ExtendedDecodeContext,
1152                       source: tydecode::DefIdSource,
1153                       did: ast::def_id) -> ast::def_id {
1154         /*!
1155          *
1156          * Converts a def-id that appears in a type.  The correct
1157          * translation will depend on what kind of def-id this is.
1158          * This is a subtle point: type definitions are not
1159          * inlined into the current crate, so if the def-id names
1160          * a nominal type or type alias, then it should be
1161          * translated to refer to the source crate.
1162          *
1163          * However, *type parameters* are cloned along with the function
1164          * they are attached to.  So we should translate those def-ids
1165          * to refer to the new, cloned copy of the type parameter.
1166          */
1167
1168         let r = match source {
1169             NominalType | TypeWithId => xcx.tr_def_id(did),
1170             TypeParameter => xcx.tr_intern_def_id(did)
1171         };
1172         debug!("convert_def_id(source=%?, did=%?)=%?", source, did, r);
1173         return r;
1174     }
1175 }
1176
1177 fn decode_side_tables(xcx: @ExtendedDecodeContext,
1178                       ast_doc: ebml::Doc) {
1179     let dcx = xcx.dcx;
1180     let tbl_doc = ast_doc.get(c::tag_table as uint);
1181     for reader::docs(tbl_doc) |tag, entry_doc| {
1182         let id0 = entry_doc.get(c::tag_table_id as uint).as_int();
1183         let id = xcx.tr_id(id0);
1184
1185         debug!(">> Side table document with tag 0x%x \
1186                 found for id %d (orig %d)",
1187                tag, id, id0);
1188
1189         if tag == (c::tag_table_mutbl as uint) {
1190             dcx.maps.mutbl_map.insert(id);
1191         } else if tag == (c::tag_table_moves_map as uint) {
1192             dcx.maps.moves_map.insert(id);
1193         } else {
1194             let val_doc = entry_doc.get(c::tag_table_val as uint);
1195             let val_dsr = &reader::Decoder(val_doc);
1196             if tag == (c::tag_table_def as uint) {
1197                 let def = decode_def(xcx, val_doc);
1198                 dcx.tcx.def_map.insert(id, def);
1199             } else if tag == (c::tag_table_node_type as uint) {
1200                 let ty = val_dsr.read_ty(xcx);
1201                 debug!("inserting ty for node %?: %s",
1202                        id, ty_to_str(dcx.tcx, ty));
1203                 dcx.tcx.node_types.insert(id as uint, ty);
1204             } else if tag == (c::tag_table_node_type_subst as uint) {
1205                 let tys = val_dsr.read_tys(xcx);
1206                 dcx.tcx.node_type_substs.insert(id, tys);
1207             } else if tag == (c::tag_table_freevars as uint) {
1208                 let fv_info = @val_dsr.read_to_vec(|| {
1209                     @val_dsr.read_freevar_entry(xcx)
1210                 });
1211                 dcx.tcx.freevars.insert(id, fv_info);
1212             } else if tag == (c::tag_table_tcache as uint) {
1213                 let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx);
1214                 let lid = ast::def_id { crate: ast::local_crate, node: id };
1215                 dcx.tcx.tcache.insert(lid, tpbt);
1216             } else if tag == (c::tag_table_param_defs as uint) {
1217                 let bounds = val_dsr.read_type_param_def(xcx);
1218                 dcx.tcx.ty_param_defs.insert(id, bounds);
1219             } else if tag == (c::tag_table_last_use as uint) {
1220                 let ids = val_dsr.read_to_vec(|| {
1221                     xcx.tr_id(val_dsr.read_int())
1222                 });
1223                 dcx.maps.last_use_map.insert(id, @mut ids);
1224             } else if tag == (c::tag_table_method_map as uint) {
1225                 dcx.maps.method_map.insert(
1226                     id,
1227                     val_dsr.read_method_map_entry(xcx));
1228             } else if tag == (c::tag_table_vtable_map as uint) {
1229                 dcx.maps.vtable_map.insert(id,
1230                                            val_dsr.read_vtable_res(xcx));
1231             } else if tag == (c::tag_table_adjustments as uint) {
1232                 let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
1233                 adj.tr(xcx);
1234                 dcx.tcx.adjustments.insert(id, adj);
1235             } else if tag == (c::tag_table_capture_map as uint) {
1236                 let cvars =
1237                     at_vec::from_owned(
1238                         val_dsr.read_to_vec(
1239                             || val_dsr.read_capture_var(xcx)));
1240                 dcx.maps.capture_map.insert(id, cvars);
1241             } else {
1242                 xcx.dcx.tcx.sess.bug(
1243                     fmt!("unknown tag found in side tables: %x", tag));
1244             }
1245         }
1246
1247         debug!(">< Side table doc loaded");
1248     }
1249 }
1250
1251 // ______________________________________________________________________
1252 // Testing of astencode_gen
1253
1254 #[cfg(test)]
1255 fn encode_item_ast(ebml_w: &writer::Encoder, item: @ast::item) {
1256     do ebml_w.wr_tag(c::tag_tree as uint) {
1257         (*item).encode(ebml_w)
1258     }
1259 }
1260
1261 #[cfg(test)]
1262 fn decode_item_ast(par_doc: ebml::Doc) -> @ast::item {
1263     let chi_doc = par_doc.get(c::tag_tree as uint);
1264     let d = &reader::Decoder(chi_doc);
1265     @Decodable::decode(d)
1266 }
1267
1268 #[cfg(test)]
1269 trait fake_ext_ctxt {
1270     fn cfg(&self) -> ast::crate_cfg;
1271     fn parse_sess(&self) -> @mut parse::ParseSess;
1272     fn call_site(&self) -> span;
1273     fn ident_of(&self, st: ~str) -> ast::ident;
1274 }
1275
1276 #[cfg(test)]
1277 type fake_session = @mut parse::ParseSess;
1278
1279 #[cfg(test)]
1280 impl fake_ext_ctxt for fake_session {
1281     fn cfg(&self) -> ast::crate_cfg { ~[] }
1282     fn parse_sess(&self) -> @mut parse::ParseSess { *self }
1283     fn call_site(&self) -> span {
1284         codemap::span {
1285             lo: codemap::BytePos(0),
1286             hi: codemap::BytePos(0),
1287             expn_info: None
1288         }
1289     }
1290     fn ident_of(&self, st: ~str) -> ast::ident {
1291         self.interner.intern(@st)
1292     }
1293 }
1294
1295 #[cfg(test)]
1296 fn mk_ctxt() -> @fake_ext_ctxt {
1297     @parse::new_parse_sess(None) as @fake_ext_ctxt
1298 }
1299
1300 #[cfg(test)]
1301 fn roundtrip(in_item: Option<@ast::item>) {
1302     use core::io;
1303
1304     let in_item = in_item.get();
1305     let bytes = do io::with_bytes_writer |wr| {
1306         let ebml_w = writer::Encoder(wr);
1307         encode_item_ast(&ebml_w, in_item);
1308     };
1309     let ebml_doc = reader::Doc(@bytes);
1310     let out_item = decode_item_ast(ebml_doc);
1311
1312     assert_eq!(in_item, out_item);
1313 }
1314
1315 #[test]
1316 fn test_basic() {
1317     let ext_cx = mk_ctxt();
1318     roundtrip(quote_item!(
1319         fn foo() {}
1320     ));
1321 }
1322
1323 #[test]
1324 fn test_smalltalk() {
1325     let ext_cx = mk_ctxt();
1326     roundtrip(quote_item!(
1327         fn foo() -> int { 3 + 4 } // first smalltalk program ever executed.
1328     ));
1329 }
1330
1331 #[test]
1332 fn test_more() {
1333     let ext_cx = mk_ctxt();
1334     roundtrip(quote_item!(
1335         fn foo(x: uint, y: uint) -> uint {
1336             let z = x + y;
1337             return z;
1338         }
1339     ));
1340 }
1341
1342 #[test]
1343 fn test_simplification() {
1344     let ext_cx = mk_ctxt();
1345     let item_in = ast::ii_item(quote_item!(
1346         fn new_int_alist<B:Copy>() -> alist<int, B> {
1347             fn eq_int(&&a: int, &&b: int) -> bool { a == b }
1348             return alist {eq_fn: eq_int, data: ~[]};
1349         }
1350     ).get());
1351     let item_out = simplify_ast(&item_in);
1352     let item_exp = ast::ii_item(quote_item!(
1353         fn new_int_alist<B:Copy>() -> alist<int, B> {
1354             return alist {eq_fn: eq_int, data: ~[]};
1355         }
1356     ).get());
1357     match (item_out, item_exp) {
1358       (ast::ii_item(item_out), ast::ii_item(item_exp)) => {
1359         assert!(pprust::item_to_str(item_out,
1360                                          ext_cx.parse_sess().interner)
1361                      == pprust::item_to_str(item_exp,
1362                                             ext_cx.parse_sess().interner));
1363       }
1364       _ => fail!()
1365     }
1366 }