about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-09-21 19:17:24 -0700
committerGitHub <noreply@github.com>2016-09-21 19:17:24 -0700
commit1cf592fa40ca4104b59b867817881ca056f408ad (patch)
tree19a912a724e96de8d4bf50a02407ef592d21459e /src
parent4f9812a59ab7247f0f52b01ca89b0793a2d289c3 (diff)
parent4ac30013c3402d9349f83888a9d0903f0a68746e (diff)
downloadrust-1cf592fa40ca4104b59b867817881ca056f408ad.tar.gz
rust-1cf592fa40ca4104b59b867817881ca056f408ad.zip
Auto merge of #36551 - eddyb:meta-games, r=nikomatsakis
Refactor away RBML from rustc_metadata.

RBML and `ty{en,de}code` have had their long-overdue purge. Summary of changes:
* Metadata is now a tree encoded in post-order and with relative backward references pointing to children nodes. With auto-deriving and type safety, this makes maintenance and adding new information to metadata painless and bug-free by default. It's also more compact and cache-friendly (cache misses should be proportional to the depth of the node being accessed, not the number of siblings as in EBML/RBML).
* Metadata sizes have been reduced, for `libcore` it went down 16% (`8.38MB` -> `7.05MB`) and for `libstd` 14% (`3.53MB` -> `3.03MB`), while encoding more or less the same information
* Specialization is used in the bundled `libserialize` (crates.io `rustc_serialize` remains unaffected) to customize the encoding (and more importantly, decoding) of various types, most notably those interned in the `TyCtxt`. Some of this abuses a soundness hole pending a fix (cc @aturon), but when that fix arrives, we'll move to macros 1.1 `#[derive]` and custom `TyCtxt`-aware serialization traits.
* Enumerating children of modules from other crates is now orthogonal to describing those items via `Def` - this is a step towards bridging crate-local HIR and cross-crate metadata
* `CrateNum` has been moved to `rustc` and both it and `NodeId` are now newtypes instead of `u32` aliases, for specializing their decoding. This is `[syntax-breaking]` (cc @Manishearth ).

cc @rust-lang/compiler
Diffstat (limited to 'src')
-rw-r--r--src/librbml/Cargo.toml13
-rw-r--r--src/librbml/lib.rs1609
-rw-r--r--src/librustc/Cargo.toml1
-rw-r--r--src/librustc/dep_graph/dep_node.rs15
-rw-r--r--src/librustc/hir/def.rs37
-rw-r--r--src/librustc/hir/def_id.rs64
-rw-r--r--src/librustc/hir/fold.rs1131
-rw-r--r--src/librustc/hir/intravisit.rs6
-rw-r--r--src/librustc/hir/lowering.rs54
-rw-r--r--src/librustc/hir/map/collector.rs16
-rw-r--r--src/librustc/hir/map/def_collector.rs9
-rw-r--r--src/librustc/hir/map/definitions.rs41
-rw-r--r--src/librustc/hir/map/mod.rs128
-rw-r--r--src/librustc/hir/mod.rs1
-rw-r--r--src/librustc/hir/pat_util.rs2
-rw-r--r--src/librustc/infer/region_inference/graphviz.rs5
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/cstore.rs383
-rw-r--r--src/librustc/middle/dataflow.rs4
-rw-r--r--src/librustc/middle/dead.rs13
-rw-r--r--src/librustc/middle/dependency_format.rs30
-rw-r--r--src/librustc/middle/expr_use_visitor.rs8
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/liveness.rs9
-rw-r--r--src/librustc/middle/mem_categorization.rs19
-rw-r--r--src/librustc/middle/region.rs17
-rw-r--r--src/librustc/middle/stability.rs12
-rw-r--r--src/librustc/mir/repr.rs4
-rw-r--r--src/librustc/session/config.rs2
-rw-r--r--src/librustc/session/mod.rs16
-rw-r--r--src/librustc/traits/coherence.rs3
-rw-r--r--src/librustc/traits/mod.rs86
-rw-r--r--src/librustc/traits/select.rs2
-rw-r--r--src/librustc/traits/specialize/mod.rs39
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs63
-rw-r--r--src/librustc/ty/adjustment.rs6
-rw-r--r--src/librustc/ty/context.rs152
-rw-r--r--src/librustc/ty/item_path.rs16
-rw-r--r--src/librustc/ty/layout.rs15
-rw-r--r--src/librustc/ty/maps.rs3
-rw-r--r--src/librustc/ty/mod.rs319
-rw-r--r--src/librustc/ty/structural_impls.rs13
-rw-r--r--src/librustc/ty/sty.rs93
-rw-r--r--src/librustc/ty/subst.rs57
-rw-r--r--src/librustc/ty/trait_def.rs7
-rw-r--r--src/librustc/ty/util.rs45
-rw-r--r--src/librustc/util/ppaux.rs3
-rw-r--r--src/librustc_back/lib.rs1
-rw-r--r--src/librustc_const_eval/check_match.rs142
-rw-r--r--src/librustc_const_eval/eval.rs24
-rw-r--r--src/librustc_driver/pretty.rs1
-rw-r--r--src/librustc_driver/test.rs19
-rw-r--r--src/librustc_incremental/Cargo.toml3
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs1
-rw-r--r--src/librustc_incremental/lib.rs1
-rw-r--r--src/librustc_incremental/persist/directory.rs16
-rw-r--r--src/librustc_incremental/persist/fs.rs7
-rw-r--r--src/librustc_incremental/persist/hash.rs14
-rw-r--r--src/librustc_incremental/persist/load.rs5
-rw-r--r--src/librustc_incremental/persist/save.rs2
-rw-r--r--src/librustc_lint/types.rs2
-rw-r--r--src/librustc_metadata/Cargo.toml2
-rw-r--r--src/librustc_metadata/astencode.rs1420
-rw-r--r--src/librustc_metadata/common.rs241
-rw-r--r--src/librustc_metadata/creader.rs288
-rw-r--r--src/librustc_metadata/csearch.rs419
-rw-r--r--src/librustc_metadata/cstore.rs140
-rw-r--r--src/librustc_metadata/decoder.rs2311
-rw-r--r--src/librustc_metadata/def_key.rs110
-rw-r--r--src/librustc_metadata/encoder.rs2685
-rw-r--r--src/librustc_metadata/index.rs139
-rw-r--r--src/librustc_metadata/index_builder.rs107
-rw-r--r--src/librustc_metadata/lib.rs30
-rw-r--r--src/librustc_metadata/loader.rs68
-rw-r--r--src/librustc_metadata/macros.rs46
-rw-r--r--src/librustc_metadata/schema.rs349
-rw-r--r--src/librustc_metadata/tls_context.rs102
-rw-r--r--src/librustc_metadata/tydecode.rs750
-rw-r--r--src/librustc_metadata/tyencode.rs519
-rw-r--r--src/librustc_mir/build/mod.rs5
-rw-r--r--src/librustc_mir/hair/cx/expr.rs16
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs6
-rw-r--r--src/librustc_mir/transform/type_check.rs3
-rw-r--r--src/librustc_passes/static_recursion.rs14
-rw-r--r--src/librustc_privacy/lib.rs18
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs75
-rw-r--r--src/librustc_resolve/lib.rs26
-rw-r--r--src/librustc_resolve/macros.rs2
-rw-r--r--src/librustc_save_analysis/data.rs4
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs24
-rw-r--r--src/librustc_save_analysis/external_data.rs9
-rw-r--r--src/librustc_save_analysis/json_api_dumper.rs2
-rw-r--r--src/librustc_save_analysis/json_dumper.rs2
-rw-r--r--src/librustc_save_analysis/lib.rs22
-rw-r--r--src/librustc_trans/adt.rs4
-rw-r--r--src/librustc_trans/back/link.rs9
-rw-r--r--src/librustc_trans/back/linker.rs4
-rw-r--r--src/librustc_trans/back/rpath.rs (renamed from src/librustc_back/rpath.rs)5
-rw-r--r--src/librustc_trans/back/symbol_names.rs87
-rw-r--r--src/librustc_trans/base.rs3
-rw-r--r--src/librustc_trans/callee.rs29
-rw-r--r--src/librustc_trans/closure.rs8
-rw-r--r--src/librustc_trans/collector.rs106
-rw-r--r--src/librustc_trans/common.rs38
-rw-r--r--src/librustc_trans/glue.rs22
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_trans/meth.rs234
-rw-r--r--src/librustc_trans/mir/constant.rs14
-rw-r--r--src/librustc_trans/type_of.rs2
-rw-r--r--src/librustc_typeck/astconv.rs53
-rw-r--r--src/librustc_typeck/check/_match.rs3
-rw-r--r--src/librustc_typeck/check/callee.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs4
-rw-r--r--src/librustc_typeck/check/method/mod.rs31
-rw-r--r--src/librustc_typeck/check/method/probe.rs20
-rw-r--r--src/librustc_typeck/check/method/suggest.rs43
-rw-r--r--src/librustc_typeck/check/mod.rs31
-rw-r--r--src/librustc_typeck/check/upvar.rs52
-rw-r--r--src/librustc_typeck/coherence/mod.rs26
-rw-r--r--src/librustc_typeck/coherence/orphan.rs3
-rw-r--r--src/librustc_typeck/coherence/overlap.rs22
-rw-r--r--src/librustc_typeck/collect.rs96
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustdoc/clean/inline.rs116
-rw-r--r--src/librustdoc/clean/mod.rs167
-rw-r--r--src/librustdoc/core.rs38
-rw-r--r--src/librustdoc/doctree.rs5
-rw-r--r--src/librustdoc/html/format.rs3
-rw-r--r--src/librustdoc/html/render.rs9
-rw-r--r--src/librustdoc/test.rs9
-rw-r--r--src/librustdoc/visit_ast.rs3
-rw-r--r--src/librustdoc/visit_lib.rs49
-rw-r--r--src/libserialize/collection_impls.rs4
-rw-r--r--src/libserialize/leb128.rs (renamed from src/librbml/leb128.rs)0
-rw-r--r--src/libserialize/lib.rs11
-rw-r--r--src/libserialize/opaque.rs (renamed from src/librbml/opaque.rs)267
-rw-r--r--src/libserialize/serialize.rs311
-rw-r--r--src/libsyntax/ast.rs48
-rw-r--r--src/libsyntax/attr.rs6
-rw-r--r--src/libsyntax/ext/expand.rs6
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs22
-rw-r--r--src/libsyntax_pos/lib.rs19
-rw-r--r--src/rustc/Cargo.lock12
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs1
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs1
-rw-r--r--src/test/codegen-units/partitioning/vtable-through-const.rs1
-rw-r--r--src/test/compile-fail/auxiliary/issue_19452_aux.rs13
-rw-r--r--src/test/compile-fail/issue-19452.rs7
-rw-r--r--src/test/run-pass-fulldeps/issue-11881.rs12
-rw-r--r--src/test/run-pass/auxiliary/issue-17718-aux.rs3
-rw-r--r--src/test/run-pass/typeid-intrinsic.rs4
152 files changed, 4641 insertions, 12228 deletions
diff --git a/src/librbml/Cargo.toml b/src/librbml/Cargo.toml
deleted file mode 100644
index ab89ac2b7a1..00000000000
--- a/src/librbml/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-name = "rbml"
-version = "0.0.0"
-
-[lib]
-name = "rbml"
-path = "lib.rs"
-crate-type = ["dylib"]
-
-[dependencies]
-log = { path = "../liblog" }
-serialize = { path = "../libserialize" }
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs
deleted file mode 100644
index 5a8a52f7dfc..00000000000
--- a/src/librbml/lib.rs
+++ /dev/null
@@ -1,1609 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Really Bad Markup Language (rbml) is an internal serialization format of rustc.
-//! This is not intended to be used by users.
-//!
-//! Originally based on the Extensible Binary Markup Language
-//! (ebml; http://www.matroska.org/technical/specs/rfc/index.html),
-//! it is now a separate format tuned for the rust object metadata.
-//!
-//! # Encoding
-//!
-//! RBML document consists of the tag, length and data.
-//! The encoded data can contain multiple RBML documents concatenated.
-//!
-//! **Tags** are a hint for the following data.
-//! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved.
-//! Tags less than 0xf0 are encoded in one literal byte.
-//! Tags greater than 0xff are encoded in two big-endian bytes,
-//! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`)
-//!
-//! **Lengths** encode the length of the following data.
-//! It is a variable-length unsigned isize, and one of the following forms:
-//!
-//! - `80` through `fe` for lengths up to 0x7e;
-//! - `40 ff` through `7f ff` for lengths up to 0x3fff;
-//! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff;
-//! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff.
-//!
-//! The "overlong" form is allowed so that the length can be encoded
-//! without the prior knowledge of the encoded data.
-//! For example, the length 0 can be represented either by `80`, `40 00`,
-//! `20 00 00` or `10 00 00 00`.
-//! The encoder tries to minimize the length if possible.
-//! Also, some predefined tags listed below are so commonly used that
-//! their lengths are omitted ("implicit length").
-//!
-//! **Data** can be either binary bytes or zero or more nested RBML documents.
-//! Nested documents cannot overflow, and should be entirely contained
-//! within a parent document.
-//!
-//! # Predefined Tags
-//!
-//! Most RBML tags are defined by the application.
-//! (For the rust object metadata, see also `rustc::metadata::common`.)
-//! RBML itself does define a set of predefined tags however,
-//! intended for the auto-serialization implementation.
-//!
-//! Predefined tags with an implicit length:
-//!
-//! - `U8`  (`00`): 1-byte unsigned integer.
-//! - `U16` (`01`): 2-byte big endian unsigned integer.
-//! - `U32` (`02`): 4-byte big endian unsigned integer.
-//! - `U64` (`03`): 8-byte big endian unsigned integer.
-//!   Any of `U*` tags can be used to encode primitive unsigned integer types,
-//!   as long as it is no greater than the actual size.
-//!   For example, `u8` can only be represented via the `U8` tag.
-//!
-//! - `I8`  (`04`): 1-byte signed integer.
-//! - `I16` (`05`): 2-byte big endian signed integer.
-//! - `I32` (`06`): 4-byte big endian signed integer.
-//! - `I64` (`07`): 8-byte big endian signed integer.
-//!   Similar to `U*` tags. Always uses two's complement encoding.
-//!
-//! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true.
-//!
-//! - `Char` (`09`): 4-byte big endian Unicode scalar value.
-//!   Surrogate pairs or out-of-bound values are invalid.
-//!
-//! - `F32` (`0a`): 4-byte big endian unsigned integer representing
-//!   IEEE 754 binary32 floating-point format.
-//! - `F64` (`0b`): 8-byte big endian unsigned integer representing
-//!   IEEE 754 binary64 floating-point format.
-//!
-//! - `Sub8`  (`0c`): 1-byte unsigned integer for supplementary information.
-//! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information.
-//!   Those two tags normally occur as the first subdocument of certain tags,
-//!   namely `Enum`, `Vec` and `Map`, to provide a variant or size information.
-//!   They can be used interchangeably.
-//!
-//! Predefined tags with an explicit length:
-//!
-//! - `Str` (`10`): A UTF-8-encoded string.
-//!
-//! - `Enum` (`11`): An enum.
-//!   The first subdocument should be `Sub*` tags with a variant ID.
-//!   Subsequent subdocuments, if any, encode variant arguments.
-//!
-//! - `Vec` (`12`): A vector (sequence).
-//! - `VecElt` (`13`): A vector element.
-//!   The first subdocument should be `Sub*` tags with the number of elements.
-//!   Subsequent subdocuments should be `VecElt` tag per each element.
-//!
-//! - `Map` (`14`): A map (associated array).
-//! - `MapKey` (`15`): A key part of the map entry.
-//! - `MapVal` (`16`): A value part of the map entry.
-//!   The first subdocument should be `Sub*` tags with the number of entries.
-//!   Subsequent subdocuments should be an alternating sequence of
-//!   `MapKey` and `MapVal` tags per each entry.
-//!
-//! - `Opaque` (`17`): An opaque, custom-format tag.
-//!   Used to wrap ordinary custom tags or data in the auto-serialized context.
-//!   Rustc typically uses this to encode type information.
-//!
-//! First 0x20 tags are reserved by RBML; custom tags start at 0x20.
-
-#![crate_name = "rbml"]
-#![unstable(feature = "rustc_private", issue = "27812")]
-#![crate_type = "rlib"]
-#![crate_type = "dylib"]
-#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
-       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
-       html_root_url = "https://doc.rust-lang.org/nightly/",
-       html_playground_url = "https://play.rust-lang.org/",
-       test(attr(deny(warnings))))]
-#![cfg_attr(not(stage0), deny(warnings))]
-
-#![feature(rustc_private)]
-#![feature(staged_api)]
-#![feature(question_mark)]
-
-#![cfg_attr(test, feature(test))]
-
-extern crate serialize;
-
-#[cfg(test)]
-extern crate serialize as rustc_serialize; // Used by RustcEncodable
-
-#[macro_use]
-extern crate log;
-
-#[cfg(test)]
-extern crate test;
-
-pub mod opaque;
-pub mod leb128;
-
-pub use self::EbmlEncoderTag::*;
-pub use self::Error::*;
-
-use std::str;
-use std::fmt;
-
-/// Common data structures
-#[derive(Clone, Copy)]
-pub struct Doc<'a> {
-    pub data: &'a [u8],
-    pub start: usize,
-    pub end: usize,
-}
-
-impl<'doc> Doc<'doc> {
-    pub fn new(data: &'doc [u8]) -> Doc<'doc> {
-        Doc {
-            data: data,
-            start: 0,
-            end: data.len(),
-        }
-    }
-
-    pub fn get(&self, tag: usize) -> Doc<'doc> {
-        reader::get_doc(*self, tag)
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.start == self.end
-    }
-
-    pub fn as_str(&self) -> &'doc str {
-        str::from_utf8(&self.data[self.start..self.end]).unwrap()
-    }
-
-    pub fn to_string(&self) -> String {
-        self.as_str().to_string()
-    }
-}
-
-pub struct TaggedDoc<'a> {
-    tag: usize,
-    pub doc: Doc<'a>,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum EbmlEncoderTag {
-    // tags 00..1f are reserved for auto-serialization.
-    // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded.
-    EsU8 = 0x00, // + 1 byte
-    EsU16 = 0x01, // + 2 bytes
-    EsU32 = 0x02, // + 4 bytes
-    EsU64 = 0x03, // + 8 bytes
-    EsI8 = 0x04, // + 1 byte
-    EsI16 = 0x05, // + 2 bytes
-    EsI32 = 0x06, // + 4 bytes
-    EsI64 = 0x07, // + 8 bytes
-    EsBool = 0x08, // + 1 byte
-    EsChar = 0x09, // + 4 bytes
-    EsF32 = 0x0a, // + 4 bytes
-    EsF64 = 0x0b, // + 8 bytes
-    EsSub8 = 0x0c, // + 1 byte
-    EsSub32 = 0x0d, // + 4 bytes
-    // 0x0e and 0x0f are reserved
-    EsStr = 0x10,
-    EsEnum = 0x11, // encodes the variant id as the first EsSub*
-    EsVec = 0x12, // encodes the # of elements as the first EsSub*
-    EsVecElt = 0x13,
-    EsMap = 0x14, // encodes the # of pairs as the first EsSub*
-    EsMapKey = 0x15,
-    EsMapVal = 0x16,
-    EsOpaque = 0x17,
-}
-
-const NUM_TAGS: usize = 0x1000;
-const NUM_IMPLICIT_TAGS: usize = 0x0e;
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [
-    1, 2, 4, 8, // EsU*
-    1, 2, 4, 8, // ESI*
-    1, // EsBool
-    4, // EsChar
-    4, 8, // EsF*
-    1, 4, // EsSub*
-];
-
-#[derive(Debug)]
-pub enum Error {
-    IntTooBig(usize),
-    InvalidTag(usize),
-    Expected(String),
-    IoError(std::io::Error),
-    ApplicationError(String),
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // FIXME: this should be a more useful display form
-        fmt::Debug::fmt(self, f)
-    }
-}
-// --------------------------------------
-
-pub mod reader {
-    use std::char;
-
-    use std::isize;
-    use std::mem::transmute;
-
-    use serialize;
-
-    use super::opaque;
-    use super::{ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
-                EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32,
-                EsChar, EsStr, EsMapVal, EsOpaque, EbmlEncoderTag, Doc, TaggedDoc, Error,
-                IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN};
-
-    pub type DecodeResult<T> = Result<T, Error>;
-    // rbml reading
-
-    macro_rules! try_or {
-        ($e:expr, $r:expr) => (
-            match $e {
-                Ok(e) => e,
-                Err(e) => {
-                    debug!("ignored error: {:?}", e);
-                    return $r
-                }
-            }
-        )
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct Res {
-        pub val: usize,
-        pub next: usize,
-    }
-
-    pub fn tag_at(data: &[u8], start: usize) -> DecodeResult<Res> {
-        let v = data[start] as usize;
-        if v < 0xf0 {
-            Ok(Res {
-                val: v,
-                next: start + 1,
-            })
-        } else if v > 0xf0 {
-            Ok(Res {
-                val: ((v & 0xf) << 8) | data[start + 1] as usize,
-                next: start + 2,
-            })
-        } else {
-            // every tag starting with byte 0xf0 is an overlong form, which is prohibited.
-            Err(InvalidTag(v))
-        }
-    }
-
-    #[inline(never)]
-    fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult<Res> {
-        let a = data[start];
-        if a & 0x80 != 0 {
-            return Ok(Res {
-                val: (a & 0x7f) as usize,
-                next: start + 1,
-            });
-        }
-        if a & 0x40 != 0 {
-            return Ok(Res {
-                val: ((a & 0x3f) as usize) << 8 | (data[start + 1] as usize),
-                next: start + 2,
-            });
-        }
-        if a & 0x20 != 0 {
-            return Ok(Res {
-                val: ((a & 0x1f) as usize) << 16 | (data[start + 1] as usize) << 8 |
-                     (data[start + 2] as usize),
-                next: start + 3,
-            });
-        }
-        if a & 0x10 != 0 {
-            return Ok(Res {
-                val: ((a & 0x0f) as usize) << 24 | (data[start + 1] as usize) << 16 |
-                     (data[start + 2] as usize) << 8 |
-                     (data[start + 3] as usize),
-                next: start + 4,
-            });
-        }
-        Err(IntTooBig(a as usize))
-    }
-
-    pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult<Res> {
-        if data.len() - start < 4 {
-            return vuint_at_slow(data, start);
-        }
-
-        // Lookup table for parsing EBML Element IDs as per
-        // http://ebml.sourceforge.net/specs/ The Element IDs are parsed by
-        // reading a big endian u32 positioned at data[start].  Using the four
-        // most significant bits of the u32 we lookup in the table below how
-        // the element ID should be derived from it.
-        //
-        // The table stores tuples (shift, mask) where shift is the number the
-        // u32 should be right shifted with and mask is the value the right
-        // shifted value should be masked with.  If for example the most
-        // significant bit is set this means it's a class A ID and the u32
-        // should be right shifted with 24 and masked with 0x7f. Therefore we
-        // store (24, 0x7f) at index 0x8 - 0xF (four bit numbers where the most
-        // significant bit is set).
-        //
-        // By storing the number of shifts and masks in a table instead of
-        // checking in order if the most significant bit is set, the second
-        // most significant bit is set etc. we can replace up to three
-        // "and+branch" with a single table lookup which gives us a measured
-        // speedup of around 2x on x86_64.
-        static SHIFT_MASK_TABLE: [(usize, u32); 16] = [(0, 0x0),
-                                                       (0, 0x0fffffff),
-                                                       (8, 0x1fffff),
-                                                       (8, 0x1fffff),
-                                                       (16, 0x3fff),
-                                                       (16, 0x3fff),
-                                                       (16, 0x3fff),
-                                                       (16, 0x3fff),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f),
-                                                       (24, 0x7f)];
-
-        unsafe {
-            let ptr = data.as_ptr().offset(start as isize) as *const u32;
-            let val = u32::from_be(*ptr);
-
-            let i = (val >> 28) as usize;
-            let (shift, mask) = SHIFT_MASK_TABLE[i];
-            Ok(Res {
-                val: ((val >> shift) & mask) as usize,
-                next: start + ((32 - shift) >> 3),
-            })
-        }
-    }
-
-    pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult<Res> {
-        if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 {
-            Ok(Res {
-                val: TAG_IMPLICIT_LEN[tag.val] as usize,
-                next: tag.next,
-            })
-        } else {
-            vuint_at(data, tag.next)
-        }
-    }
-
-    pub fn doc_at<'a>(data: &'a [u8], start: usize) -> DecodeResult<TaggedDoc<'a>> {
-        let elt_tag = tag_at(data, start)?;
-        let elt_size = tag_len_at(data, elt_tag)?;
-        let end = elt_size.next + elt_size.val;
-        Ok(TaggedDoc {
-            tag: elt_tag.val,
-            doc: Doc {
-                data: data,
-                start: elt_size.next,
-                end: end,
-            },
-        })
-    }
-
-    pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option<Doc<'a>> {
-        let mut pos = d.start;
-        while pos < d.end {
-            let elt_tag = try_or!(tag_at(d.data, pos), None);
-            let elt_size = try_or!(tag_len_at(d.data, elt_tag), None);
-            pos = elt_size.next + elt_size.val;
-            if elt_tag.val == tg {
-                return Some(Doc {
-                    data: d.data,
-                    start: elt_size.next,
-                    end: pos,
-                });
-            }
-        }
-        None
-    }
-
-    pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> {
-        match maybe_get_doc(d, tg) {
-            Some(d) => d,
-            None => {
-                error!("failed to find block with tag {:?}", tg);
-                panic!();
-            }
-        }
-    }
-
-    pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> {
-        DocsIterator { d: d }
-    }
-
-    pub struct DocsIterator<'a> {
-        d: Doc<'a>,
-    }
-
-    impl<'a> Iterator for DocsIterator<'a> {
-        type Item = (usize, Doc<'a>);
-
-        fn next(&mut self) -> Option<(usize, Doc<'a>)> {
-            if self.d.start >= self.d.end {
-                return None;
-            }
-
-            let elt_tag = try_or!(tag_at(self.d.data, self.d.start), {
-                self.d.start = self.d.end;
-                None
-            });
-            let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), {
-                self.d.start = self.d.end;
-                None
-            });
-
-            let end = elt_size.next + elt_size.val;
-            let doc = Doc {
-                data: self.d.data,
-                start: elt_size.next,
-                end: end,
-            };
-
-            self.d.start = end;
-            return Some((elt_tag.val, doc));
-        }
-    }
-
-    pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> {
-        TaggedDocsIterator {
-            iter: docs(d),
-            tag: tag,
-        }
-    }
-
-    pub struct TaggedDocsIterator<'a> {
-        iter: DocsIterator<'a>,
-        tag: usize,
-    }
-
-    impl<'a> Iterator for TaggedDocsIterator<'a> {
-        type Item = Doc<'a>;
-
-        fn next(&mut self) -> Option<Doc<'a>> {
-            while let Some((tag, doc)) = self.iter.next() {
-                if tag == self.tag {
-                    return Some(doc);
-                }
-            }
-            None
-        }
-    }
-
-    pub fn with_doc_data<T, F>(d: Doc, f: F) -> T
-        where F: FnOnce(&[u8]) -> T
-    {
-        f(&d.data[d.start..d.end])
-    }
-
-    pub fn doc_as_u8(d: Doc) -> u8 {
-        assert_eq!(d.end, d.start + 1);
-        d.data[d.start]
-    }
-
-    pub fn doc_as_u64(d: Doc) -> u64 {
-        if d.end >= 8 {
-            // For performance, we read 8 big-endian bytes,
-            // and mask off the junk if there is any. This
-            // obviously won't work on the first 8 bytes
-            // of a file - we will fall of the start
-            // of the page and segfault.
-
-            let mut b = [0; 8];
-            b.copy_from_slice(&d.data[d.end - 8..d.end]);
-            let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() };
-            let len = d.end - d.start;
-            if len < 8 {
-                data & ((1 << (len * 8)) - 1)
-            } else {
-                data
-            }
-        } else {
-            let mut result = 0;
-            for b in &d.data[d.start..d.end] {
-                result = (result << 8) + (*b as u64);
-            }
-            result
-        }
-    }
-
-    #[inline]
-    pub fn doc_as_u16(d: Doc) -> u16 {
-        doc_as_u64(d) as u16
-    }
-    #[inline]
-    pub fn doc_as_u32(d: Doc) -> u32 {
-        doc_as_u64(d) as u32
-    }
-
-    #[inline]
-    pub fn doc_as_i8(d: Doc) -> i8 {
-        doc_as_u8(d) as i8
-    }
-    #[inline]
-    pub fn doc_as_i16(d: Doc) -> i16 {
-        doc_as_u16(d) as i16
-    }
-    #[inline]
-    pub fn doc_as_i32(d: Doc) -> i32 {
-        doc_as_u32(d) as i32
-    }
-    #[inline]
-    pub fn doc_as_i64(d: Doc) -> i64 {
-        doc_as_u64(d) as i64
-    }
-
-    pub struct Decoder<'a> {
-        parent: Doc<'a>,
-        pos: usize,
-    }
-
-    impl<'doc> Decoder<'doc> {
-        pub fn new(d: Doc<'doc>) -> Decoder<'doc> {
-            Decoder {
-                parent: d,
-                pos: d.start,
-            }
-        }
-
-        fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> {
-            debug!(". next_doc(exp_tag={:?})", exp_tag);
-            if self.pos >= self.parent.end {
-                return Err(Expected(format!("no more documents in current node!")));
-            }
-            let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?;
-            debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}",
-                   self.parent.start,
-                   self.parent.end,
-                   self.pos,
-                   r_tag,
-                   r_doc.start,
-                   r_doc.end);
-            if r_tag != (exp_tag as usize) {
-                return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}",
-                                            exp_tag,
-                                            r_tag)));
-            }
-            if r_doc.end > self.parent.end {
-                return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
-                                             {:#x}",
-                                            r_doc.end,
-                                            self.parent.end)));
-            }
-            self.pos = r_doc.end;
-            Ok(r_doc)
-        }
-
-        fn push_doc<T, F>(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            let d = self.next_doc(exp_tag)?;
-            let old_parent = self.parent;
-            let old_pos = self.pos;
-            self.parent = d;
-            self.pos = d.start;
-            let r = f(self)?;
-            self.parent = old_parent;
-            self.pos = old_pos;
-            Ok(r)
-        }
-
-        fn _next_sub(&mut self) -> DecodeResult<usize> {
-            // empty vector/map optimization
-            if self.parent.is_empty() {
-                return Ok(0);
-            }
-
-            let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?;
-            let r = if r_tag == (EsSub8 as usize) {
-                doc_as_u8(r_doc) as usize
-            } else if r_tag == (EsSub32 as usize) {
-                doc_as_u32(r_doc) as usize
-            } else {
-                return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but found \
-                                             tag {:?}",
-                                            EsSub8,
-                                            EsSub32,
-                                            r_tag)));
-            };
-            if r_doc.end > self.parent.end {
-                return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
-                                             {:#x}",
-                                            r_doc.end,
-                                            self.parent.end)));
-            }
-            self.pos = r_doc.end;
-            debug!("_next_sub result={:?}", r);
-            Ok(r)
-        }
-
-        // variable-length unsigned integer with different tags.
-        // `first_tag` should be a tag for u8 or i8.
-        // `last_tag` should be the largest allowed integer tag with the matching signedness.
-        // all tags between them should be valid, in the order of u8, u16, u32 and u64.
-        fn _next_int(&mut self,
-                     first_tag: EbmlEncoderTag,
-                     last_tag: EbmlEncoderTag)
-                     -> DecodeResult<u64> {
-            if self.pos >= self.parent.end {
-                return Err(Expected(format!("no more documents in current node!")));
-            }
-
-            let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?;
-            let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize {
-                match r_tag - first_tag as usize {
-                    0 => doc_as_u8(r_doc) as u64,
-                    1 => doc_as_u16(r_doc) as u64,
-                    2 => doc_as_u32(r_doc) as u64,
-                    3 => doc_as_u64(r_doc),
-                    _ => unreachable!(),
-                }
-            } else {
-                return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \
-                                             found tag {:?}",
-                                            first_tag,
-                                            last_tag,
-                                            r_tag)));
-            };
-            if r_doc.end > self.parent.end {
-                return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \
-                                             {:#x}",
-                                            r_doc.end,
-                                            self.parent.end)));
-            }
-            self.pos = r_doc.end;
-            debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r);
-            Ok(r)
-        }
-
-        pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R>
-            where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult<R>
-        {
-            let doc = self.next_doc(EsOpaque)?;
-
-            let result = {
-                let mut opaque_decoder = opaque::Decoder::new(doc.data, doc.start);
-                op(&mut opaque_decoder, doc)?
-            };
-
-            Ok(result)
-        }
-
-        pub fn position(&self) -> usize {
-            self.pos
-        }
-
-        pub fn advance(&mut self, bytes: usize) {
-            self.pos += bytes;
-        }
-    }
-
-    impl<'doc> serialize::Decoder for Decoder<'doc> {
-        type Error = Error;
-        fn read_nil(&mut self) -> DecodeResult<()> {
-            Ok(())
-        }
-
-        fn read_u64(&mut self) -> DecodeResult<u64> {
-            self._next_int(EsU8, EsU64)
-        }
-        fn read_u32(&mut self) -> DecodeResult<u32> {
-            Ok(self._next_int(EsU8, EsU32)? as u32)
-        }
-        fn read_u16(&mut self) -> DecodeResult<u16> {
-            Ok(self._next_int(EsU8, EsU16)? as u16)
-        }
-        fn read_u8(&mut self) -> DecodeResult<u8> {
-            Ok(doc_as_u8(self.next_doc(EsU8)?))
-        }
-        fn read_usize(&mut self) -> DecodeResult<usize> {
-            let v = self._next_int(EsU8, EsU64)?;
-            if v > (::std::usize::MAX as u64) {
-                Err(IntTooBig(v as usize))
-            } else {
-                Ok(v as usize)
-            }
-        }
-
-        fn read_i64(&mut self) -> DecodeResult<i64> {
-            Ok(self._next_int(EsI8, EsI64)? as i64)
-        }
-        fn read_i32(&mut self) -> DecodeResult<i32> {
-            Ok(self._next_int(EsI8, EsI32)? as i32)
-        }
-        fn read_i16(&mut self) -> DecodeResult<i16> {
-            Ok(self._next_int(EsI8, EsI16)? as i16)
-        }
-        fn read_i8(&mut self) -> DecodeResult<i8> {
-            Ok(doc_as_u8(self.next_doc(EsI8)?) as i8)
-        }
-        fn read_isize(&mut self) -> DecodeResult<isize> {
-            let v = self._next_int(EsI8, EsI64)? as i64;
-            if v > (isize::MAX as i64) || v < (isize::MIN as i64) {
-                debug!("FIXME \\#6122: Removing this makes this function miscompile");
-                Err(IntTooBig(v as usize))
-            } else {
-                Ok(v as isize)
-            }
-        }
-
-        fn read_bool(&mut self) -> DecodeResult<bool> {
-            Ok(doc_as_u8(self.next_doc(EsBool)?) != 0)
-        }
-
-        fn read_f64(&mut self) -> DecodeResult<f64> {
-            let bits = doc_as_u64(self.next_doc(EsF64)?);
-            Ok(unsafe { transmute(bits) })
-        }
-        fn read_f32(&mut self) -> DecodeResult<f32> {
-            let bits = doc_as_u32(self.next_doc(EsF32)?);
-            Ok(unsafe { transmute(bits) })
-        }
-        fn read_char(&mut self) -> DecodeResult<char> {
-            Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap())
-        }
-        fn read_str(&mut self) -> DecodeResult<String> {
-            Ok(self.next_doc(EsStr)?.to_string())
-        }
-
-        // Compound types:
-        fn read_enum<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_enum({})", name);
-
-            let doc = self.next_doc(EsEnum)?;
-
-            let (old_parent, old_pos) = (self.parent, self.pos);
-            self.parent = doc;
-            self.pos = self.parent.start;
-
-            let result = f(self)?;
-
-            self.parent = old_parent;
-            self.pos = old_pos;
-            Ok(result)
-        }
-
-        fn read_enum_variant<T, F>(&mut self, _: &[&str], mut f: F) -> DecodeResult<T>
-            where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>
-        {
-            debug!("read_enum_variant()");
-            let idx = self._next_sub()?;
-            debug!("  idx={}", idx);
-
-            f(self, idx)
-        }
-
-        fn read_enum_variant_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_enum_variant_arg(idx={})", idx);
-            f(self)
-        }
-
-        fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], mut f: F) -> DecodeResult<T>
-            where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult<T>
-        {
-            debug!("read_enum_struct_variant()");
-            let idx = self._next_sub()?;
-            debug!("  idx={}", idx);
-
-            f(self, idx)
-        }
-
-        fn read_enum_struct_variant_field<T, F>(&mut self,
-                                                name: &str,
-                                                idx: usize,
-                                                f: F)
-                                                -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx);
-            f(self)
-        }
-
-        fn read_struct<T, F>(&mut self, name: &str, _: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_struct(name={})", name);
-            f(self)
-        }
-
-        fn read_struct_field<T, F>(&mut self, name: &str, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_struct_field(name={}, idx={})", name, idx);
-            f(self)
-        }
-
-        fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_tuple()");
-            self.read_seq(move |d, len| {
-                if len == tuple_len {
-                    f(d)
-                } else {
-                    Err(Expected(format!("Expected tuple of length `{}`, found tuple of length \
-                                          `{}`",
-                                         tuple_len,
-                                         len)))
-                }
-            })
-        }
-
-        fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_tuple_arg(idx={})", idx);
-            self.read_seq_elt(idx, f)
-        }
-
-        fn read_tuple_struct<T, F>(&mut self, name: &str, len: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_tuple_struct(name={})", name);
-            self.read_tuple(len, f)
-        }
-
-        fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_tuple_struct_arg(idx={})", idx);
-            self.read_tuple_arg(idx, f)
-        }
-
-        fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
-            where F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult<T>
-        {
-            debug!("read_option()");
-            self.read_enum("Option", move |this| {
-                this.read_enum_variant(&["None", "Some"], move |this, idx| {
-                    match idx {
-                        0 => f(this, false),
-                        1 => f(this, true),
-                        _ => Err(Expected(format!("Expected None or Some"))),
-                    }
-                })
-            })
-        }
-
-        fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>
-        {
-            debug!("read_seq()");
-            self.push_doc(EsVec, move |d| {
-                let len = d._next_sub()?;
-                debug!("  len={}", len);
-                f(d, len)
-            })
-        }
-
-        fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_seq_elt(idx={})", idx);
-            self.push_doc(EsVecElt, f)
-        }
-
-        fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult<T>
-        {
-            debug!("read_map()");
-            self.push_doc(EsMap, move |d| {
-                let len = d._next_sub()?;
-                debug!("  len={}", len);
-                f(d, len)
-            })
-        }
-
-        fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_map_elt_key(idx={})", idx);
-            self.push_doc(EsMapKey, f)
-        }
-
-        fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-            where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>
-        {
-            debug!("read_map_elt_val(idx={})", idx);
-            self.push_doc(EsMapVal, f)
-        }
-
-        fn error(&mut self, err: &str) -> Error {
-            ApplicationError(err.to_string())
-        }
-    }
-}
-
-pub mod writer {
-    use std::mem;
-    use std::io::prelude::*;
-    use std::io::{self, SeekFrom, Cursor};
-
-    use super::opaque;
-    use super::{EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, EsU64, EsU32, EsU16,
-                EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
-                EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS};
-
-    use serialize;
-
-
-    pub type EncodeResult = io::Result<()>;
-
-    // rbml writing
-    pub struct Encoder<'a> {
-        pub writer: &'a mut Cursor<Vec<u8>>,
-        size_positions: Vec<u64>,
-        relax_limit: u64, // do not move encoded bytes before this position
-    }
-
-    fn write_tag<W: Write>(w: &mut W, n: usize) -> EncodeResult {
-        if n < 0xf0 {
-            w.write_all(&[n as u8])
-        } else if 0x100 <= n && n < NUM_TAGS {
-            w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
-        } else {
-            Err(io::Error::new(io::ErrorKind::Other, &format!("invalid tag: {}", n)[..]))
-        }
-    }
-
-    fn write_sized_vuint<W: Write>(w: &mut W, n: usize, size: usize) -> EncodeResult {
-        match size {
-            1 => w.write_all(&[0x80 | (n as u8)]),
-            2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]),
-            3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, n as u8]),
-            4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]),
-            _ => Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])),
-        }
-    }
-
-    pub fn write_vuint<W: Write>(w: &mut W, n: usize) -> EncodeResult {
-        if n < 0x7f {
-            return write_sized_vuint(w, n, 1);
-        }
-        if n < 0x4000 {
-            return write_sized_vuint(w, n, 2);
-        }
-        if n < 0x200000 {
-            return write_sized_vuint(w, n, 3);
-        }
-        if n < 0x10000000 {
-            return write_sized_vuint(w, n, 4);
-        }
-        Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..]))
-    }
-
-    impl<'a> Encoder<'a> {
-        pub fn new(w: &'a mut Cursor<Vec<u8>>) -> Encoder<'a> {
-            Encoder {
-                writer: w,
-                size_positions: vec![],
-                relax_limit: 0,
-            }
-        }
-
-        pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult {
-            debug!("Start tag {:?}", tag_id);
-            assert!(tag_id >= NUM_IMPLICIT_TAGS);
-
-            // Write the enum ID:
-            write_tag(self.writer, tag_id)?;
-
-            // Write a placeholder four-byte size.
-            let cur_pos = self.writer.seek(SeekFrom::Current(0))?;
-            self.size_positions.push(cur_pos);
-            let zeroes: &[u8] = &[0, 0, 0, 0];
-            self.writer.write_all(zeroes)
-        }
-
-        pub fn end_tag(&mut self) -> EncodeResult {
-            let last_size_pos = self.size_positions.pop().unwrap();
-            let cur_pos = self.writer.seek(SeekFrom::Current(0))?;
-            self.writer.seek(SeekFrom::Start(last_size_pos))?;
-            let size = (cur_pos - last_size_pos - 4) as usize;
-
-            // relax the size encoding for small tags (bigger tags are costly to move).
-            // we should never try to move the stable positions, however.
-            const RELAX_MAX_SIZE: usize = 0x100;
-            if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit {
-                // we can't alter the buffer in place, so have a temporary buffer
-                let mut buf = [0u8; RELAX_MAX_SIZE];
-                {
-                    let last_size_pos = last_size_pos as usize;
-                    let data = &self.writer.get_ref()[last_size_pos + 4..cur_pos as usize];
-                    buf[..size].copy_from_slice(data);
-                }
-
-                // overwrite the size and data and continue
-                write_vuint(self.writer, size)?;
-                self.writer.write_all(&buf[..size])?;
-            } else {
-                // overwrite the size with an overlong encoding and skip past the data
-                write_sized_vuint(self.writer, size, 4)?;
-                self.writer.seek(SeekFrom::Start(cur_pos))?;
-            }
-
-            debug!("End tag (size = {:?})", size);
-            Ok(())
-        }
-
-        pub fn wr_tag<F>(&mut self, tag_id: usize, blk: F) -> EncodeResult
-            where F: FnOnce() -> EncodeResult
-        {
-            self.start_tag(tag_id)?;
-            blk()?;
-            self.end_tag()
-        }
-
-        pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult {
-            assert!(tag_id >= NUM_IMPLICIT_TAGS);
-            write_tag(self.writer, tag_id)?;
-            write_vuint(self.writer, b.len())?;
-            self.writer.write_all(b)
-        }
-
-        pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult {
-            let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) };
-            // tagged integers are emitted in big-endian, with no
-            // leading zeros.
-            let leading_zero_bytes = v.leading_zeros() / 8;
-            self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..])
-        }
-
-        #[inline]
-        pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
-            self.wr_tagged_u64(tag_id, v as u64)
-        }
-
-        #[inline]
-        pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult {
-            self.wr_tagged_u64(tag_id, v as u64)
-        }
-
-        #[inline]
-        pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult {
-            self.wr_tagged_bytes(tag_id, &[v])
-        }
-
-        #[inline]
-        pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult {
-            self.wr_tagged_u64(tag_id, v as u64)
-        }
-
-        #[inline]
-        pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult {
-            self.wr_tagged_u32(tag_id, v as u32)
-        }
-
-        #[inline]
-        pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult {
-            self.wr_tagged_u16(tag_id, v as u16)
-        }
-
-        #[inline]
-        pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult {
-            self.wr_tagged_bytes(tag_id, &[v as u8])
-        }
-
-        pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult {
-            self.wr_tagged_bytes(tag_id, v.as_bytes())
-        }
-
-        // for auto-serialization
-        fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult {
-            write_tag(self.writer, tag_id)?;
-            self.writer.write_all(b)
-        }
-
-        fn wr_tagged_raw_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult {
-            let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) };
-            self.wr_tagged_raw_bytes(tag_id, &bytes)
-        }
-
-        fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
-            let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) };
-            self.wr_tagged_raw_bytes(tag_id, &bytes)
-        }
-
-        fn wr_tagged_raw_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult {
-            let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) };
-            self.wr_tagged_raw_bytes(tag_id, &bytes)
-        }
-
-        fn wr_tagged_raw_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult {
-            self.wr_tagged_raw_bytes(tag_id, &[v])
-        }
-
-        fn wr_tagged_raw_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult {
-            self.wr_tagged_raw_u64(tag_id, v as u64)
-        }
-
-        fn wr_tagged_raw_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult {
-            self.wr_tagged_raw_u32(tag_id, v as u32)
-        }
-
-        fn wr_tagged_raw_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult {
-            self.wr_tagged_raw_u16(tag_id, v as u16)
-        }
-
-        fn wr_tagged_raw_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult {
-            self.wr_tagged_raw_bytes(tag_id, &[v as u8])
-        }
-
-        pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult {
-            debug!("Write {:?} bytes", b.len());
-            self.writer.write_all(b)
-        }
-
-        pub fn wr_str(&mut self, s: &str) -> EncodeResult {
-            debug!("Write str: {:?}", s);
-            self.writer.write_all(s.as_bytes())
-        }
-
-        /// Returns the current position while marking it stable, i.e.
-        /// generated bytes so far wouldn't be affected by relaxation.
-        pub fn mark_stable_position(&mut self) -> u64 {
-            let pos = self.writer.seek(SeekFrom::Current(0)).unwrap();
-            if self.relax_limit < pos {
-                self.relax_limit = pos;
-            }
-            pos
-        }
-    }
-
-    impl<'a> Encoder<'a> {
-        // used internally to emit things like the vector length and so on
-        fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult {
-            if v as u8 as usize == v {
-                self.wr_tagged_raw_u8(EsSub8 as usize, v as u8)
-            } else if v as u32 as usize == v {
-                self.wr_tagged_raw_u32(EsSub32 as usize, v as u32)
-            } else {
-                Err(io::Error::new(io::ErrorKind::Other,
-                                   &format!("length or variant id too big: {}", v)[..]))
-            }
-        }
-
-        pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult
-            where F: FnOnce(&mut opaque::Encoder) -> EncodeResult
-        {
-            self.start_tag(EsOpaque as usize)?;
-
-            {
-                let mut opaque_encoder = opaque::Encoder::new(self.writer);
-                f(&mut opaque_encoder)?;
-            }
-
-            self.mark_stable_position();
-            self.end_tag()
-        }
-    }
-
-    impl<'a> serialize::Encoder for Encoder<'a> {
-        type Error = io::Error;
-
-        fn emit_nil(&mut self) -> EncodeResult {
-            Ok(())
-        }
-
-        fn emit_usize(&mut self, v: usize) -> EncodeResult {
-            self.emit_u64(v as u64)
-        }
-        fn emit_u64(&mut self, v: u64) -> EncodeResult {
-            if v as u32 as u64 == v {
-                self.emit_u32(v as u32)
-            } else {
-                self.wr_tagged_raw_u64(EsU64 as usize, v)
-            }
-        }
-        fn emit_u32(&mut self, v: u32) -> EncodeResult {
-            if v as u16 as u32 == v {
-                self.emit_u16(v as u16)
-            } else {
-                self.wr_tagged_raw_u32(EsU32 as usize, v)
-            }
-        }
-        fn emit_u16(&mut self, v: u16) -> EncodeResult {
-            if v as u8 as u16 == v {
-                self.emit_u8(v as u8)
-            } else {
-                self.wr_tagged_raw_u16(EsU16 as usize, v)
-            }
-        }
-        fn emit_u8(&mut self, v: u8) -> EncodeResult {
-            self.wr_tagged_raw_u8(EsU8 as usize, v)
-        }
-
-        fn emit_isize(&mut self, v: isize) -> EncodeResult {
-            self.emit_i64(v as i64)
-        }
-        fn emit_i64(&mut self, v: i64) -> EncodeResult {
-            if v as i32 as i64 == v {
-                self.emit_i32(v as i32)
-            } else {
-                self.wr_tagged_raw_i64(EsI64 as usize, v)
-            }
-        }
-        fn emit_i32(&mut self, v: i32) -> EncodeResult {
-            if v as i16 as i32 == v {
-                self.emit_i16(v as i16)
-            } else {
-                self.wr_tagged_raw_i32(EsI32 as usize, v)
-            }
-        }
-        fn emit_i16(&mut self, v: i16) -> EncodeResult {
-            if v as i8 as i16 == v {
-                self.emit_i8(v as i8)
-            } else {
-                self.wr_tagged_raw_i16(EsI16 as usize, v)
-            }
-        }
-        fn emit_i8(&mut self, v: i8) -> EncodeResult {
-            self.wr_tagged_raw_i8(EsI8 as usize, v)
-        }
-
-        fn emit_bool(&mut self, v: bool) -> EncodeResult {
-            self.wr_tagged_raw_u8(EsBool as usize, v as u8)
-        }
-
-        fn emit_f64(&mut self, v: f64) -> EncodeResult {
-            let bits = unsafe { mem::transmute(v) };
-            self.wr_tagged_raw_u64(EsF64 as usize, bits)
-        }
-        fn emit_f32(&mut self, v: f32) -> EncodeResult {
-            let bits = unsafe { mem::transmute(v) };
-            self.wr_tagged_raw_u32(EsF32 as usize, bits)
-        }
-        fn emit_char(&mut self, v: char) -> EncodeResult {
-            self.wr_tagged_raw_u32(EsChar as usize, v as u32)
-        }
-
-        fn emit_str(&mut self, v: &str) -> EncodeResult {
-            self.wr_tagged_str(EsStr as usize, v)
-        }
-
-        fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.start_tag(EsEnum as usize)?;
-            f(self)?;
-            self.end_tag()
-        }
-
-        fn emit_enum_variant<F>(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self._emit_tagged_sub(v_id)?;
-            f(self)
-        }
-
-        fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            f(self)
-        }
-
-        fn emit_enum_struct_variant<F>(&mut self,
-                                       v_name: &str,
-                                       v_id: usize,
-                                       cnt: usize,
-                                       f: F)
-                                       -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_enum_variant(v_name, v_id, cnt, f)
-        }
-
-        fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_enum_variant_arg(idx, f)
-        }
-
-        fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            f(self)
-        }
-
-        fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            f(self)
-        }
-
-        fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_seq(len, f)
-        }
-        fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_seq_elt(idx, f)
-        }
-
-        fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_seq(len, f)
-        }
-        fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_seq_elt(idx, f)
-        }
-
-        fn emit_option<F>(&mut self, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.emit_enum("Option", f)
-        }
-        fn emit_option_none(&mut self) -> EncodeResult {
-            self.emit_enum_variant("None", 0, 0, |_| Ok(()))
-        }
-        fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-
-            self.emit_enum_variant("Some", 1, 1, f)
-        }
-
-        fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            if len == 0 {
-                // empty vector optimization
-                return self.wr_tagged_bytes(EsVec as usize, &[]);
-            }
-
-            self.start_tag(EsVec as usize)?;
-            self._emit_tagged_sub(len)?;
-            f(self)?;
-            self.end_tag()
-        }
-
-        fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-
-            self.start_tag(EsVecElt as usize)?;
-            f(self)?;
-            self.end_tag()
-        }
-
-        fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            if len == 0 {
-                // empty map optimization
-                return self.wr_tagged_bytes(EsMap as usize, &[]);
-            }
-
-            self.start_tag(EsMap as usize)?;
-            self._emit_tagged_sub(len)?;
-            f(self)?;
-            self.end_tag()
-        }
-
-        fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-
-            self.start_tag(EsMapKey as usize)?;
-            f(self)?;
-            self.end_tag()
-        }
-
-        fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-            where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-        {
-            self.start_tag(EsMapVal as usize)?;
-            f(self)?;
-            self.end_tag()
-        }
-    }
-}
-
-// ___________________________________________________________________________
-// Testing
-
-#[cfg(test)]
-mod tests {
-    use super::{Doc, reader, writer};
-
-    use serialize::{Encodable, Decodable};
-
-    use std::io::Cursor;
-
-    #[test]
-    fn test_vuint_at() {
-        let data = &[
-            0x80,
-            0xff,
-            0x40, 0x00,
-            0x7f, 0xff,
-            0x20, 0x00, 0x00,
-            0x3f, 0xff, 0xff,
-            0x10, 0x00, 0x00, 0x00,
-            0x1f, 0xff, 0xff, 0xff
-        ];
-
-        let mut res: reader::Res;
-
-        // Class A
-        res = reader::vuint_at(data, 0).unwrap();
-        assert_eq!(res.val, 0);
-        assert_eq!(res.next, 1);
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, (1 << 7) - 1);
-        assert_eq!(res.next, 2);
-
-        // Class B
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, 0);
-        assert_eq!(res.next, 4);
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, (1 << 14) - 1);
-        assert_eq!(res.next, 6);
-
-        // Class C
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, 0);
-        assert_eq!(res.next, 9);
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, (1 << 21) - 1);
-        assert_eq!(res.next, 12);
-
-        // Class D
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, 0);
-        assert_eq!(res.next, 16);
-        res = reader::vuint_at(data, res.next).unwrap();
-        assert_eq!(res.val, (1 << 28) - 1);
-        assert_eq!(res.next, 20);
-    }
-
-    #[test]
-    fn test_option_int() {
-        fn test_v(v: Option<isize>) {
-            debug!("v == {:?}", v);
-            let mut wr = Cursor::new(Vec::new());
-            {
-                let mut rbml_w = writer::Encoder::new(&mut wr);
-                let _ = v.encode(&mut rbml_w);
-            }
-            let rbml_doc = Doc::new(wr.get_ref());
-            let mut deser = reader::Decoder::new(rbml_doc);
-            let v1 = Decodable::decode(&mut deser).unwrap();
-            debug!("v1 == {:?}", v1);
-            assert_eq!(v, v1);
-        }
-
-        test_v(Some(22));
-        test_v(None);
-        test_v(Some(3));
-    }
-}
-
-#[cfg(test)]
-mod bench {
-    #![allow(non_snake_case)]
-    use test::Bencher;
-    use super::reader;
-
-    #[bench]
-    pub fn vuint_at_A_aligned(b: &mut Bencher) {
-        let data = (0..4 * 100)
-                       .map(|i| {
-                           match i % 2 {
-                               0 => 0x80,
-                               _ => i as u8,
-                           }
-                       })
-                       .collect::<Vec<_>>();
-        let mut sum = 0;
-        b.iter(|| {
-            let mut i = 0;
-            while i < data.len() {
-                sum += reader::vuint_at(&data, i).unwrap().val;
-                i += 4;
-            }
-        });
-    }
-
-    #[bench]
-    pub fn vuint_at_A_unaligned(b: &mut Bencher) {
-        let data = (0..4 * 100 + 1)
-                       .map(|i| {
-                           match i % 2 {
-                               1 => 0x80,
-                               _ => i as u8,
-                           }
-                       })
-                       .collect::<Vec<_>>();
-        let mut sum = 0;
-        b.iter(|| {
-            let mut i = 1;
-            while i < data.len() {
-                sum += reader::vuint_at(&data, i).unwrap().val;
-                i += 4;
-            }
-        });
-    }
-
-    #[bench]
-    pub fn vuint_at_D_aligned(b: &mut Bencher) {
-        let data = (0..4 * 100)
-                       .map(|i| {
-                           match i % 4 {
-                               0 => 0x10,
-                               3 => i as u8,
-                               _ => 0,
-                           }
-                       })
-                       .collect::<Vec<_>>();
-        let mut sum = 0;
-        b.iter(|| {
-            let mut i = 0;
-            while i < data.len() {
-                sum += reader::vuint_at(&data, i).unwrap().val;
-                i += 4;
-            }
-        });
-    }
-
-    #[bench]
-    pub fn vuint_at_D_unaligned(b: &mut Bencher) {
-        let data = (0..4 * 100 + 1)
-                       .map(|i| {
-                           match i % 4 {
-                               1 => 0x10,
-                               0 => i as u8,
-                               _ => 0,
-                           }
-                       })
-                       .collect::<Vec<_>>();
-        let mut sum = 0;
-        b.iter(|| {
-            let mut i = 1;
-            while i < data.len() {
-                sum += reader::vuint_at(&data, i).unwrap().val;
-                i += 4;
-            }
-        });
-    }
-}
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index aaef8e8423c..578ef68b003 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -14,7 +14,6 @@ flate = { path = "../libflate" }
 fmt_macros = { path = "../libfmt_macros" }
 graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
-rbml = { path = "../librbml" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_math = { path = "../librustc_const_math" }
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 18179027c25..269f0ebb813 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -103,18 +103,13 @@ pub enum DepNode<D: Clone + Debug> {
     // table in the tcx (or elsewhere) maps to one of these
     // nodes. Often we map multiple tables to the same node if there
     // is no point in distinguishing them (e.g., both the type and
-    // predicates for an item wind up in `ItemSignature`). Other
-    // times, such as `ImplItems` vs `TraitItemDefIds`, tables which
-    // might be mergable are kept distinct because the sets of def-ids
-    // to which they apply are disjoint, and hence we might as well
-    // have distinct labels for easier debugging.
+    // predicates for an item wind up in `ItemSignature`).
     ImplOrTraitItems(D),
     ItemSignature(D),
     FieldTy(D),
     SizedConstraint(D),
-    TraitItemDefIds(D),
+    ImplOrTraitItemDefIds(D),
     InherentImpls(D),
-    ImplItems(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -162,9 +157,8 @@ impl<D: Clone + Debug> DepNode<D> {
             ImplOrTraitItems,
             ItemSignature,
             FieldTy,
-            TraitItemDefIds,
+            ImplOrTraitItemDefIds,
             InherentImpls,
-            ImplItems,
             TraitImpls,
             ReprHints,
         }
@@ -231,9 +225,8 @@ impl<D: Clone + Debug> DepNode<D> {
             ItemSignature(ref d) => op(d).map(ItemSignature),
             FieldTy(ref d) => op(d).map(FieldTy),
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
-            TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
+            ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
-            ImplItems(ref d) => op(d).map(ImplItems),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index a270be4f1df..dec8ea8a29c 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -16,23 +16,20 @@ use hir;
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Def {
     Fn(DefId),
-    SelfTy(Option<DefId> /* trait */, Option<ast::NodeId> /* impl */),
+    SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
     Mod(DefId),
-    ForeignMod(DefId),
     Static(DefId, bool /* is_mutbl */),
     Const(DefId),
     AssociatedConst(DefId),
-    Local(DefId, // def id of variable
-             ast::NodeId), // node id of variable
-    Variant(DefId /* enum */, DefId /* variant */),
+    Local(DefId),
+    Variant(DefId),
     Enum(DefId),
     TyAlias(DefId),
-    AssociatedTy(DefId /* trait */, DefId),
+    AssociatedTy(DefId),
     Trait(DefId),
     PrimTy(hir::PrimTy),
     TyParam(DefId),
     Upvar(DefId,        // def id of closed over local
-             ast::NodeId,  // node id of closed over local
              usize,        // index in the freevars list of the closure
              ast::NodeId), // expr node that creates the closure
 
@@ -94,37 +91,20 @@ pub type DefMap = NodeMap<PathResolution>;
 // within.
 pub type ExportMap = NodeMap<Vec<Export>>;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub struct Export {
     pub name: ast::Name,    // The name of the target.
     pub def_id: DefId, // The definition of the target.
 }
 
 impl Def {
-    pub fn var_id(&self) -> ast::NodeId {
-        match *self {
-            Def::Local(_, id) |
-            Def::Upvar(_, id, ..) => {
-                id
-            }
-
-            Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
-            Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
-            Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) |
-            Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
-            Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
-                bug!("attempted .var_id() on invalid {:?}", self)
-            }
-        }
-    }
-
     pub fn def_id(&self) -> DefId {
         match *self {
-            Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
-            Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
+            Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
+            Def::Variant(id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) |
             Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
             Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
-            Def::Local(id, _) | Def::Upvar(id, ..) => {
+            Def::Local(id) | Def::Upvar(id, ..) => {
                 id
             }
 
@@ -141,7 +121,6 @@ impl Def {
         match *self {
             Def::Fn(..) => "function",
             Def::Mod(..) => "module",
-            Def::ForeignMod(..) => "foreign module",
             Def::Static(..) => "static",
             Def::Variant(..) => "variant",
             Def::Enum(..) => "enum",
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 16afa705e39..399243551d6 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -8,12 +8,69 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::cstore::LOCAL_CRATE;
 use ty;
-use syntax::ast::CrateNum;
+
+use rustc_data_structures::indexed_vec::Idx;
+use serialize::{self, Encoder, Decoder};
+
 use std::fmt;
 use std::u32;
 
+#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)]
+pub struct CrateNum(u32);
+
+impl Idx for CrateNum {
+    fn new(value: usize) -> Self {
+        assert!(value < (u32::MAX) as usize);
+        CrateNum(value as u32)
+    }
+
+    fn index(self) -> usize {
+        self.0 as usize
+    }
+}
+
+/// Item definitions in the currently-compiled crate would have the CrateNum
+/// LOCAL_CRATE in their DefId.
+pub const LOCAL_CRATE: CrateNum = CrateNum(0);
+
+impl CrateNum {
+    pub fn new(x: usize) -> CrateNum {
+        assert!(x < (u32::MAX as usize));
+        CrateNum(x as u32)
+    }
+
+    pub fn from_u32(x: u32) -> CrateNum {
+        CrateNum(x)
+    }
+
+    pub fn as_usize(&self) -> usize {
+        self.0 as usize
+    }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
+}
+
+impl fmt::Display for CrateNum {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
+
+impl serialize::UseSpecializedEncodable for CrateNum {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_u32(self.0)
+    }
+}
+
+impl serialize::UseSpecializedDecodable for CrateNum {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<CrateNum, D::Error> {
+        d.read_u32().map(CrateNum)
+    }
+}
+
 /// A DefIndex is an index into the hir-map for a crate, identifying a
 /// particular definition. It should really be considered an interned
 /// shorthand for a particular DefPath.
@@ -46,8 +103,7 @@ pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
 
 /// A DefId identifies a particular *definition*, by combining a crate
 /// index and a def index.
-#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
-           RustcDecodable, Hash, Copy)]
+#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct DefId {
     pub krate: CrateNum,
     pub index: DefIndex,
diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs
deleted file mode 100644
index 57b5599bd1d..00000000000
--- a/src/librustc/hir/fold.rs
+++ /dev/null
@@ -1,1131 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A Folder represents an HIR->HIR fold; it accepts a HIR piece,
-//! and returns a piece of the same type.
-
-use hir::*;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_};
-use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind};
-use hir;
-use syntax_pos::Span;
-use syntax::codemap::{respan, Spanned};
-use syntax::ptr::P;
-use syntax::parse::token::keywords;
-use syntax::util::move_map::MoveMap;
-
-pub trait Folder : Sized {
-    // Any additions to this trait should happen in form
-    // of a call to a public `noop_*` function that only calls
-    // out to the folder again, not other `noop_*` functions.
-    //
-    // This is a necessary API workaround to the problem of not
-    // being able to call out to the super default method
-    // in an overridden default method.
-
-    fn fold_crate(&mut self, c: Crate) -> Crate {
-        noop_fold_crate(c, self)
-    }
-
-    fn fold_meta_items(&mut self, meta_items: HirVec<P<MetaItem>>) -> HirVec<P<MetaItem>> {
-        noop_fold_meta_items(meta_items, self)
-    }
-
-    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
-        noop_fold_meta_list_item(list_item, self)
-    }
-
-    fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
-        noop_fold_meta_item(meta_item, self)
-    }
-
-    fn fold_view_path(&mut self, view_path: P<ViewPath>) -> P<ViewPath> {
-        noop_fold_view_path(view_path, self)
-    }
-
-    fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem {
-        noop_fold_foreign_item(ni, self)
-    }
-
-    fn fold_item(&mut self, i: Item) -> Item {
-        noop_fold_item(i, self)
-    }
-
-    fn fold_item_id(&mut self, i: ItemId) -> ItemId {
-        noop_fold_item_id(i, self)
-    }
-
-    fn fold_struct_field(&mut self, sf: StructField) -> StructField {
-        noop_fold_struct_field(sf, self)
-    }
-
-    fn fold_item_underscore(&mut self, i: Item_) -> Item_ {
-        noop_fold_item_underscore(i, self)
-    }
-
-    fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem {
-        noop_fold_trait_item(i, self)
-    }
-
-    fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem {
-        noop_fold_impl_item(i, self)
-    }
-
-    fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
-        noop_fold_fn_decl(d, self)
-    }
-
-    fn fold_block(&mut self, b: P<Block>) -> P<Block> {
-        noop_fold_block(b, self)
-    }
-
-    fn fold_stmt(&mut self, s: Stmt) -> Stmt {
-        noop_fold_stmt(s, self)
-    }
-
-    fn fold_arm(&mut self, a: Arm) -> Arm {
-        noop_fold_arm(a, self)
-    }
-
-    fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
-        noop_fold_pat(p, self)
-    }
-
-    fn fold_decl(&mut self, d: P<Decl>) -> P<Decl> {
-        noop_fold_decl(d, self)
-    }
-
-    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
-        e.map(|e| noop_fold_expr(e, self))
-    }
-
-    fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
-        noop_fold_ty(t, self)
-    }
-
-    fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding {
-        noop_fold_ty_binding(t, self)
-    }
-
-    fn fold_mod(&mut self, m: Mod) -> Mod {
-        noop_fold_mod(m, self)
-    }
-
-    fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod {
-        noop_fold_foreign_mod(nm, self)
-    }
-
-    fn fold_variant(&mut self, v: Variant) -> Variant {
-        noop_fold_variant(v, self)
-    }
-
-    fn fold_name(&mut self, n: Name) -> Name {
-        noop_fold_name(n, self)
-    }
-
-    fn fold_usize(&mut self, i: usize) -> usize {
-        noop_fold_usize(i, self)
-    }
-
-    fn fold_path(&mut self, p: Path) -> Path {
-        noop_fold_path(p, self)
-    }
-
-    fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters {
-        noop_fold_path_parameters(p, self)
-    }
-
-    fn fold_angle_bracketed_parameter_data(&mut self,
-                                           p: AngleBracketedParameterData)
-                                           -> AngleBracketedParameterData {
-        noop_fold_angle_bracketed_parameter_data(p, self)
-    }
-
-    fn fold_parenthesized_parameter_data(&mut self,
-                                         p: ParenthesizedParameterData)
-                                         -> ParenthesizedParameterData {
-        noop_fold_parenthesized_parameter_data(p, self)
-    }
-
-    fn fold_local(&mut self, l: P<Local>) -> P<Local> {
-        noop_fold_local(l, self)
-    }
-
-    fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
-        noop_fold_lifetime(l, self)
-    }
-
-    fn fold_lifetime_def(&mut self, l: LifetimeDef) -> LifetimeDef {
-        noop_fold_lifetime_def(l, self)
-    }
-
-    fn fold_attribute(&mut self, at: Attribute) -> Option<Attribute> {
-        noop_fold_attribute(at, self)
-    }
-
-    fn fold_arg(&mut self, a: Arg) -> Arg {
-        noop_fold_arg(a, self)
-    }
-
-    fn fold_generics(&mut self, generics: Generics) -> Generics {
-        noop_fold_generics(generics, self)
-    }
-
-    fn fold_trait_ref(&mut self, p: TraitRef) -> TraitRef {
-        noop_fold_trait_ref(p, self)
-    }
-
-    fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef {
-        noop_fold_poly_trait_ref(p, self)
-    }
-
-    fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData {
-        noop_fold_variant_data(vdata, self)
-    }
-
-    fn fold_lifetimes(&mut self, lts: HirVec<Lifetime>) -> HirVec<Lifetime> {
-        noop_fold_lifetimes(lts, self)
-    }
-
-    fn fold_lifetime_defs(&mut self, lts: HirVec<LifetimeDef>) -> HirVec<LifetimeDef> {
-        noop_fold_lifetime_defs(lts, self)
-    }
-
-    fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
-        noop_fold_ty_param(tp, self)
-    }
-
-    fn fold_ty_params(&mut self, tps: HirVec<TyParam>) -> HirVec<TyParam> {
-        noop_fold_ty_params(tps, self)
-    }
-
-    fn fold_opt_lifetime(&mut self, o_lt: Option<Lifetime>) -> Option<Lifetime> {
-        noop_fold_opt_lifetime(o_lt, self)
-    }
-
-    fn fold_opt_bounds(&mut self,
-                       b: Option<TyParamBounds>)
-                       -> Option<TyParamBounds> {
-        noop_fold_opt_bounds(b, self)
-    }
-
-    fn fold_bounds(&mut self, b: TyParamBounds) -> TyParamBounds {
-        noop_fold_bounds(b, self)
-    }
-
-    fn fold_ty_param_bound(&mut self, tpb: TyParamBound) -> TyParamBound {
-        noop_fold_ty_param_bound(tpb, self)
-    }
-
-    fn fold_mt(&mut self, mt: MutTy) -> MutTy {
-        noop_fold_mt(mt, self)
-    }
-
-    fn fold_field(&mut self, field: Field) -> Field {
-        noop_fold_field(field, self)
-    }
-
-    fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause {
-        noop_fold_where_clause(where_clause, self)
-    }
-
-    fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate {
-        noop_fold_where_predicate(where_predicate, self)
-    }
-
-    /// called for the `id` on each declaration
-    fn new_id(&mut self, i: NodeId) -> NodeId {
-        i
-    }
-
-    /// called for ids that are references (e.g., ItemDef)
-    fn map_id(&mut self, i: NodeId) -> NodeId {
-        i
-    }
-
-    fn new_span(&mut self, sp: Span) -> Span {
-        sp
-    }
-}
-
-pub fn noop_fold_meta_items<T: Folder>(meta_items: HirVec<P<MetaItem>>,
-                                       fld: &mut T)
-                                       -> HirVec<P<MetaItem>> {
-    meta_items.move_map(|x| fld.fold_meta_item(x))
-}
-
-pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<ViewPath> {
-    view_path.map(|Spanned { node, span }| {
-        Spanned {
-            node: match node {
-                ViewPathSimple(name, path) => {
-                    ViewPathSimple(name, fld.fold_path(path))
-                }
-                ViewPathGlob(path) => {
-                    ViewPathGlob(fld.fold_path(path))
-                }
-                ViewPathList(path, path_list_idents) => {
-                    ViewPathList(fld.fold_path(path),
-                                 path_list_idents.move_map(|path_list_ident| {
-                                     Spanned {
-                                         node: PathListItem_ {
-                                             id: fld.new_id(path_list_ident.node.id),
-                                             name: path_list_ident.node.name,
-                                             rename: path_list_ident.node.rename,
-                                         },
-                                         span: fld.new_span(path_list_ident.span),
-                                     }
-                                 }))
-                }
-            },
-            span: fld.new_span(span),
-        }
-    })
-}
-
-pub fn fold_attrs<T, F>(attrs: T, fld: &mut F) -> T
-    where T: Into<Vec<Attribute>> + From<Vec<Attribute>>,
-          F: Folder,
-{
-    attrs.into().move_flat_map(|x| fld.fold_attribute(x)).into()
-}
-
-pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm {
-    Arm {
-        attrs: fold_attrs(attrs, fld),
-        pats: pats.move_map(|x| fld.fold_pat(x)),
-        guard: guard.map(|x| fld.fold_expr(x)),
-        body: fld.fold_expr(body),
-    }
-}
-
-pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> P<Decl> {
-    d.map(|Spanned { node, span }| {
-        match node {
-            DeclLocal(l) => Spanned {
-                node: DeclLocal(fld.fold_local(l)),
-                span: fld.new_span(span),
-            },
-            DeclItem(it) => Spanned {
-                node: DeclItem(fld.fold_item_id(it)),
-                span: fld.new_span(span),
-            },
-        }
-    })
-}
-
-pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
-    TypeBinding {
-        id: fld.new_id(b.id),
-        name: b.name,
-        ty: fld.fold_ty(b.ty),
-        span: fld.new_span(b.span),
-    }
-}
-
-pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
-    t.map(|Ty { id, node, span }| {
-        Ty {
-            id: fld.new_id(id),
-            node: match node {
-                TyInfer => node,
-                TyVec(ty) => TyVec(fld.fold_ty(ty)),
-                TyPtr(mt) => TyPtr(fld.fold_mt(mt)),
-                TyRptr(region, mt) => {
-                    TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
-                }
-                TyBareFn(f) => {
-                    TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| {
-                        BareFnTy {
-                            lifetimes: fld.fold_lifetime_defs(lifetimes),
-                            unsafety: unsafety,
-                            abi: abi,
-                            decl: fld.fold_fn_decl(decl),
-                        }
-                    }))
-                }
-                TyNever => node,
-                TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
-                TyPath(qself, path) => {
-                    let qself = qself.map(|QSelf { ty, position }| {
-                        QSelf {
-                            ty: fld.fold_ty(ty),
-                            position: position,
-                        }
-                    });
-                    TyPath(qself, fld.fold_path(path))
-                }
-                TyObjectSum(ty, bounds) => {
-                    TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds))
-                }
-                TyFixedLengthVec(ty, e) => {
-                    TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
-                }
-                TyTypeof(expr) => {
-                    TyTypeof(fld.fold_expr(expr))
-                }
-                TyPolyTraitRef(bounds) => {
-                    TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
-                }
-                TyImplTrait(bounds) => {
-                    TyImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
-                }
-            },
-            span: fld.new_span(span),
-        }
-    })
-}
-
-pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod { abi, items }: ForeignMod,
-                                        fld: &mut T)
-                                        -> ForeignMod {
-    ForeignMod {
-        abi: abi,
-        items: items.move_map(|x| fld.fold_foreign_item(x)),
-    }
-}
-
-pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
-    Spanned {
-        node: Variant_ {
-            name: v.node.name,
-            attrs: fold_attrs(v.node.attrs, fld),
-            data: fld.fold_variant_data(v.node.data),
-            disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)),
-        },
-        span: fld.new_span(v.span),
-    }
-}
-
-pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name {
-    n
-}
-
-pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
-    i
-}
-
-pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path {
-    Path {
-        global: global,
-        segments: segments.move_map(|PathSegment { name, parameters }| {
-            PathSegment {
-                name: fld.fold_name(name),
-                parameters: fld.fold_path_parameters(parameters),
-            }
-        }),
-        span: fld.new_span(span),
-    }
-}
-
-pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters,
-                                            fld: &mut T)
-                                            -> PathParameters {
-    match path_parameters {
-        AngleBracketedParameters(data) =>
-            AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)),
-        ParenthesizedParameters(data) =>
-            ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)),
-    }
-}
-
-pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
-                                                           fld: &mut T)
-                                                           -> AngleBracketedParameterData {
-    let AngleBracketedParameterData { lifetimes, types, bindings } = data;
-    AngleBracketedParameterData {
-        lifetimes: fld.fold_lifetimes(lifetimes),
-        types: types.move_map(|ty| fld.fold_ty(ty)),
-        bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
-    }
-}
-
-pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
-                                                         fld: &mut T)
-                                                         -> ParenthesizedParameterData {
-    let ParenthesizedParameterData { inputs, output, span } = data;
-    ParenthesizedParameterData {
-        inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
-        output: output.map(|ty| fld.fold_ty(ty)),
-        span: fld.new_span(span),
-    }
-}
-
-pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
-    l.map(|Local { id, pat, ty, init, span, attrs }| {
-        Local {
-            id: fld.new_id(id),
-            ty: ty.map(|t| fld.fold_ty(t)),
-            pat: fld.fold_pat(pat),
-            init: init.map(|e| fld.fold_expr(e)),
-            span: fld.new_span(span),
-            attrs: fold_attrs(attrs, fld),
-        }
-    })
-}
-
-pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Option<Attribute> {
-    let Spanned {node: Attribute_ {id, style, value, is_sugared_doc}, span} = at;
-    Some(Spanned {
-        node: Attribute_ {
-            id: id,
-            style: style,
-            value: fld.fold_meta_item(value),
-            is_sugared_doc: is_sugared_doc,
-        },
-        span: fld.new_span(span),
-    })
-}
-
-pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
-    -> NestedMetaItem {
-    Spanned {
-        node: match li.node {
-            NestedMetaItemKind::MetaItem(mi) =>  {
-                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
-            },
-            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
-        },
-        span: fld.new_span(li.span)
-    }
-}
-
-pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
-    mi.map(|Spanned { node, span }| {
-        Spanned {
-            node: match node {
-                MetaItemKind::Word(id) => MetaItemKind::Word(id),
-                MetaItemKind::List(id, mis) => {
-                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e)))
-                }
-                MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s),
-            },
-            span: fld.new_span(span),
-        }
-    })
-}
-
-pub fn noop_fold_arg<T: Folder>(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg {
-    Arg {
-        id: fld.new_id(id),
-        pat: fld.fold_pat(pat),
-        ty: fld.fold_ty(ty),
-    }
-}
-
-pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
-    decl.map(|FnDecl { inputs, output, variadic }| {
-        FnDecl {
-            inputs: inputs.move_map(|x| fld.fold_arg(x)),
-            output: match output {
-                Return(ty) => Return(fld.fold_ty(ty)),
-                DefaultReturn(span) => DefaultReturn(span),
-            },
-            variadic: variadic,
-        }
-    })
-}
-
-pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound
-    where T: Folder
-{
-    match tpb {
-        TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier),
-        RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
-    }
-}
-
-pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
-    let TyParam {id, name, bounds, default, span} = tp;
-    TyParam {
-        id: fld.new_id(id),
-        name: name,
-        bounds: fld.fold_bounds(bounds),
-        default: default.map(|x| fld.fold_ty(x)),
-        span: span,
-    }
-}
-
-pub fn noop_fold_ty_params<T: Folder>(tps: HirVec<TyParam>,
-                                      fld: &mut T)
-                                      -> HirVec<TyParam> {
-    tps.move_map(|tp| fld.fold_ty_param(tp))
-}
-
-pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
-    Lifetime {
-        id: fld.new_id(l.id),
-        name: l.name,
-        span: fld.new_span(l.span),
-    }
-}
-
-pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T) -> LifetimeDef {
-    LifetimeDef {
-        lifetime: fld.fold_lifetime(l.lifetime),
-        bounds: fld.fold_lifetimes(l.bounds),
-    }
-}
-
-pub fn noop_fold_lifetimes<T: Folder>(lts: HirVec<Lifetime>, fld: &mut T) -> HirVec<Lifetime> {
-    lts.move_map(|l| fld.fold_lifetime(l))
-}
-
-pub fn noop_fold_lifetime_defs<T: Folder>(lts: HirVec<LifetimeDef>,
-                                          fld: &mut T)
-                                          -> HirVec<LifetimeDef> {
-    lts.move_map(|l| fld.fold_lifetime_def(l))
-}
-
-pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) -> Option<Lifetime> {
-    o_lt.map(|lt| fld.fold_lifetime(lt))
-}
-
-pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics,
-                                     fld: &mut T)
-                                     -> Generics {
-    Generics {
-        ty_params: fld.fold_ty_params(ty_params),
-        lifetimes: fld.fold_lifetime_defs(lifetimes),
-        where_clause: fld.fold_where_clause(where_clause),
-        span: fld.new_span(span),
-    }
-}
-
-pub fn noop_fold_where_clause<T: Folder>(WhereClause { id, predicates }: WhereClause,
-                                         fld: &mut T)
-                                         -> WhereClause {
-    WhereClause {
-        id: fld.new_id(id),
-        predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)),
-    }
-}
-
-pub fn noop_fold_where_predicate<T: Folder>(pred: WherePredicate, fld: &mut T) -> WherePredicate {
-    match pred {
-        hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes,
-                                                                     bounded_ty,
-                                                                     bounds,
-                                                                     span}) => {
-            hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
-                bounded_ty: fld.fold_ty(bounded_ty),
-                bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
-                span: fld.new_span(span),
-            })
-        }
-        hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime,
-                                                                       bounds,
-                                                                       span}) => {
-            hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
-                span: fld.new_span(span),
-                lifetime: fld.fold_lifetime(lifetime),
-                bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)),
-            })
-        }
-        hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id,
-                                                               path,
-                                                               ty,
-                                                               span}) => {
-            hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
-                id: fld.new_id(id),
-                path: fld.fold_path(path),
-                ty: fld.fold_ty(ty),
-                span: fld.new_span(span),
-            })
-        }
-    }
-}
-
-pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
-    match vdata {
-        VariantData::Struct(fields, id) => {
-            VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)),
-                                fld.new_id(id))
-        }
-        VariantData::Tuple(fields, id) => {
-            VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)),
-                               fld.new_id(id))
-        }
-        VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)),
-    }
-}
-
-pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
-    let id = fld.new_id(p.ref_id);
-    let TraitRef {
-        path,
-        ref_id: _,
-    } = p;
-    hir::TraitRef {
-        path: fld.fold_path(path),
-        ref_id: id,
-    }
-}
-
-pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
-    hir::PolyTraitRef {
-        bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
-        trait_ref: fld.fold_trait_ref(p.trait_ref),
-        span: fld.new_span(p.span),
-    }
-}
-
-pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructField {
-    StructField {
-        span: fld.new_span(f.span),
-        id: fld.new_id(f.id),
-        name: f.name,
-        vis: f.vis,
-        ty: fld.fold_ty(f.ty),
-        attrs: fold_attrs(f.attrs, fld),
-    }
-}
-
-pub fn noop_fold_field<T: Folder>(Field { name, expr, span }: Field, folder: &mut T) -> Field {
-    Field {
-        name: respan(folder.new_span(name.span), folder.fold_name(name.node)),
-        expr: folder.fold_expr(expr),
-        span: folder.new_span(span),
-    }
-}
-
-pub fn noop_fold_mt<T: Folder>(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy {
-    MutTy {
-        ty: folder.fold_ty(ty),
-        mutbl: mutbl,
-    }
-}
-
-pub fn noop_fold_opt_bounds<T: Folder>(b: Option<TyParamBounds>,
-                                       folder: &mut T)
-                                       -> Option<TyParamBounds> {
-    b.map(|bounds| folder.fold_bounds(bounds))
-}
-
-fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds {
-    bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
-}
-
-pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
-    b.map(|Block { id, stmts, expr, rules, span }| {
-        Block {
-            id: folder.new_id(id),
-            stmts: stmts.move_map(|s| folder.fold_stmt(s)),
-            expr: expr.map(|x| folder.fold_expr(x)),
-            rules: rules,
-            span: folder.new_span(span),
-        }
-    })
-}
-
-pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
-    match i {
-        ItemExternCrate(string) => ItemExternCrate(string),
-        ItemUse(view_path) => {
-            ItemUse(folder.fold_view_path(view_path))
-        }
-        ItemStatic(t, m, e) => {
-            ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
-        }
-        ItemConst(t, e) => {
-            ItemConst(folder.fold_ty(t), folder.fold_expr(e))
-        }
-        ItemFn(decl, unsafety, constness, abi, generics, body) => {
-            ItemFn(folder.fold_fn_decl(decl),
-                   unsafety,
-                   constness,
-                   abi,
-                   folder.fold_generics(generics),
-                   folder.fold_block(body))
-        }
-        ItemMod(m) => ItemMod(folder.fold_mod(m)),
-        ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
-        ItemTy(t, generics) => {
-            ItemTy(folder.fold_ty(t), folder.fold_generics(generics))
-        }
-        ItemEnum(enum_definition, generics) => {
-            ItemEnum(hir::EnumDef {
-                         variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)),
-                     },
-                     folder.fold_generics(generics))
-        }
-        ItemStruct(struct_def, generics) => {
-            let struct_def = folder.fold_variant_data(struct_def);
-            ItemStruct(struct_def, folder.fold_generics(generics))
-        }
-        ItemUnion(struct_def, generics) => {
-            let struct_def = folder.fold_variant_data(struct_def);
-            ItemUnion(struct_def, folder.fold_generics(generics))
-        }
-        ItemDefaultImpl(unsafety, ref trait_ref) => {
-            ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
-        }
-        ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
-            let new_impl_items = impl_items
-                .move_map(|item| folder.fold_impl_item(item));
-            let ifce = match ifce {
-                None => None,
-                Some(ref trait_ref) => {
-                    Some(folder.fold_trait_ref((*trait_ref).clone()))
-                }
-            };
-            ItemImpl(unsafety,
-                     polarity,
-                     folder.fold_generics(generics),
-                     ifce,
-                     folder.fold_ty(ty),
-                     new_impl_items)
-        }
-        ItemTrait(unsafety, generics, bounds, items) => {
-            let bounds = folder.fold_bounds(bounds);
-            let items = items.move_map(|item| folder.fold_trait_item(item));
-            ItemTrait(unsafety, folder.fold_generics(generics), bounds, items)
-        }
-    }
-}
-
-pub fn noop_fold_trait_item<T: Folder>(i: TraitItem,
-                                       folder: &mut T)
-                                       -> TraitItem {
-    TraitItem {
-        id: folder.new_id(i.id),
-        name: folder.fold_name(i.name),
-        attrs: fold_attrs(i.attrs, folder),
-        node: match i.node {
-            ConstTraitItem(ty, default) => {
-                ConstTraitItem(folder.fold_ty(ty), default.map(|x| folder.fold_expr(x)))
-            }
-            MethodTraitItem(sig, body) => {
-                MethodTraitItem(noop_fold_method_sig(sig, folder),
-                                body.map(|x| folder.fold_block(x)))
-            }
-            TypeTraitItem(bounds, default) => {
-                TypeTraitItem(folder.fold_bounds(bounds),
-                              default.map(|x| folder.fold_ty(x)))
-            }
-        },
-        span: folder.new_span(i.span),
-    }
-}
-
-pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> ImplItem {
-    ImplItem {
-        id: folder.new_id(i.id),
-        name: folder.fold_name(i.name),
-        attrs: fold_attrs(i.attrs, folder),
-        vis: i.vis,
-        defaultness: i.defaultness,
-        node: match i.node {
-            ImplItemKind::Const(ty, expr) => {
-                ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
-            }
-            ImplItemKind::Method(sig, body) => {
-                ImplItemKind::Method(noop_fold_method_sig(sig, folder), folder.fold_block(body))
-            }
-            ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)),
-        },
-        span: folder.new_span(i.span),
-    }
-}
-
-pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod {
-    Mod {
-        inner: folder.new_span(inner),
-        item_ids: item_ids.move_map(|x| folder.fold_item_id(x)),
-    }
-}
-
-pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span,
-                                          exported_macros, items }: Crate,
-                                  folder: &mut T)
-                                  -> Crate {
-    let config = folder.fold_meta_items(config);
-
-    let crate_mod = folder.fold_item(hir::Item {
-        name: keywords::Invalid.name(),
-        attrs: attrs,
-        id: DUMMY_NODE_ID,
-        vis: hir::Public,
-        span: span,
-        node: hir::ItemMod(module),
-    });
-
-    let (module, attrs, span) = match crate_mod {
-        hir::Item { attrs, span, node, .. } => {
-            match node {
-                hir::ItemMod(m) => (m, attrs, span),
-                _ => panic!("fold converted a module to not a module"),
-            }
-        }
-    };
-
-    let items = items.into_iter()
-                     .map(|(id, item)| (id, folder.fold_item(item)))
-                     .collect();
-
-    Crate {
-        module: module,
-        attrs: attrs,
-        config: config,
-        span: span,
-        exported_macros: exported_macros,
-        items: items,
-    }
-}
-
-pub fn noop_fold_item_id<T: Folder>(i: ItemId, folder: &mut T) -> ItemId {
-    let id = folder.map_id(i.id);
-    ItemId { id: id }
-}
-
-// fold one item into one item
-pub fn noop_fold_item<T: Folder>(item: Item, folder: &mut T) -> Item {
-    let Item { id, name, attrs, node, vis, span } = item;
-    let id = folder.new_id(id);
-    let node = folder.fold_item_underscore(node);
-
-    Item {
-        id: id,
-        name: folder.fold_name(name),
-        attrs: fold_attrs(attrs, folder),
-        node: node,
-        vis: vis,
-        span: folder.new_span(span),
-    }
-}
-
-pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
-    ForeignItem {
-        id: folder.new_id(ni.id),
-        name: folder.fold_name(ni.name),
-        attrs: fold_attrs(ni.attrs, folder),
-        node: match ni.node {
-            ForeignItemFn(fdec, generics) => {
-                ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics))
-            }
-            ForeignItemStatic(t, m) => {
-                ForeignItemStatic(folder.fold_ty(t), m)
-            }
-        },
-        vis: ni.vis,
-        span: folder.new_span(ni.span),
-    }
-}
-
-pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
-    MethodSig {
-        generics: folder.fold_generics(sig.generics),
-        abi: sig.abi,
-        unsafety: sig.unsafety,
-        constness: sig.constness,
-        decl: folder.fold_fn_decl(sig.decl),
-    }
-}
-
-pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
-    p.map(|Pat { id, node, span }| {
-        Pat {
-            id: folder.new_id(id),
-            node: match node {
-                PatKind::Wild => PatKind::Wild,
-                PatKind::Binding(binding_mode, pth1, sub) => {
-                    PatKind::Binding(binding_mode,
-                             Spanned {
-                                 span: folder.new_span(pth1.span),
-                                 node: folder.fold_name(pth1.node),
-                             },
-                             sub.map(|x| folder.fold_pat(x)))
-                }
-                PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
-                PatKind::TupleStruct(pth, pats, ddpos) => {
-                    PatKind::TupleStruct(folder.fold_path(pth),
-                            pats.move_map(|x| folder.fold_pat(x)), ddpos)
-                }
-                PatKind::Path(opt_qself, pth) => {
-                    let opt_qself = opt_qself.map(|qself| {
-                        QSelf { ty: folder.fold_ty(qself.ty), position: qself.position }
-                    });
-                    PatKind::Path(opt_qself, folder.fold_path(pth))
-                }
-                PatKind::Struct(pth, fields, etc) => {
-                    let pth = folder.fold_path(pth);
-                    let fs = fields.move_map(|f| {
-                        Spanned {
-                            span: folder.new_span(f.span),
-                            node: hir::FieldPat {
-                                name: f.node.name,
-                                pat: folder.fold_pat(f.node.pat),
-                                is_shorthand: f.node.is_shorthand,
-                            },
-                        }
-                    });
-                    PatKind::Struct(pth, fs, etc)
-                }
-                PatKind::Tuple(elts, ddpos) => {
-                    PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
-                }
-                PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
-                PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
-                PatKind::Range(e1, e2) => {
-                    PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
-                }
-                PatKind::Vec(before, slice, after) => {
-                    PatKind::Vec(before.move_map(|x| folder.fold_pat(x)),
-                           slice.map(|x| folder.fold_pat(x)),
-                           after.move_map(|x| folder.fold_pat(x)))
-                }
-            },
-            span: folder.new_span(span),
-        }
-    })
-}
-
-pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr {
-    Expr {
-        id: folder.new_id(id),
-        node: match node {
-            ExprBox(e) => {
-                ExprBox(folder.fold_expr(e))
-            }
-            ExprVec(exprs) => {
-                ExprVec(exprs.move_map(|x| folder.fold_expr(x)))
-            }
-            ExprRepeat(expr, count) => {
-                ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count))
-            }
-            ExprTup(elts) => ExprTup(elts.move_map(|x| folder.fold_expr(x))),
-            ExprCall(f, args) => {
-                ExprCall(folder.fold_expr(f), args.move_map(|x| folder.fold_expr(x)))
-            }
-            ExprMethodCall(name, tps, args) => {
-                ExprMethodCall(respan(folder.new_span(name.span), folder.fold_name(name.node)),
-                               tps.move_map(|x| folder.fold_ty(x)),
-                               args.move_map(|x| folder.fold_expr(x)))
-            }
-            ExprBinary(binop, lhs, rhs) => {
-                ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs))
-            }
-            ExprUnary(binop, ohs) => {
-                ExprUnary(binop, folder.fold_expr(ohs))
-            }
-            ExprLit(l) => ExprLit(l),
-            ExprCast(expr, ty) => {
-                ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
-            }
-            ExprType(expr, ty) => {
-                ExprType(folder.fold_expr(expr), folder.fold_ty(ty))
-            }
-            ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
-            ExprIf(cond, tr, fl) => {
-                ExprIf(folder.fold_expr(cond),
-                       folder.fold_block(tr),
-                       fl.map(|x| folder.fold_expr(x)))
-            }
-            ExprWhile(cond, body, opt_name) => {
-                ExprWhile(folder.fold_expr(cond),
-                          folder.fold_block(body),
-                          opt_name.map(|label| {
-                              respan(folder.new_span(label.span), folder.fold_name(label.node))
-                          }))
-            }
-            ExprLoop(body, opt_name) => {
-                ExprLoop(folder.fold_block(body),
-                         opt_name.map(|label| {
-                             respan(folder.new_span(label.span), folder.fold_name(label.node))
-                         }))
-            }
-            ExprMatch(expr, arms, source) => {
-                ExprMatch(folder.fold_expr(expr),
-                          arms.move_map(|x| folder.fold_arm(x)),
-                          source)
-            }
-            ExprClosure(capture_clause, decl, body, fn_decl_span) => {
-                ExprClosure(capture_clause,
-                            folder.fold_fn_decl(decl),
-                            folder.fold_block(body),
-                            folder.new_span(fn_decl_span))
-            }
-            ExprBlock(blk) => ExprBlock(folder.fold_block(blk)),
-            ExprAssign(el, er) => {
-                ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
-            }
-            ExprAssignOp(op, el, er) => {
-                ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er))
-            }
-            ExprField(el, name) => {
-                ExprField(folder.fold_expr(el),
-                          respan(folder.new_span(name.span), folder.fold_name(name.node)))
-            }
-            ExprTupField(el, index) => {
-                ExprTupField(folder.fold_expr(el),
-                             respan(folder.new_span(index.span), folder.fold_usize(index.node)))
-            }
-            ExprIndex(el, er) => {
-                ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
-            }
-            ExprPath(qself, path) => {
-                let qself = qself.map(|QSelf { ty, position }| {
-                    QSelf {
-                        ty: folder.fold_ty(ty),
-                        position: position,
-                    }
-                });
-                ExprPath(qself, folder.fold_path(path))
-            }
-            ExprBreak(opt_name) => ExprBreak(opt_name.map(|label| {
-                respan(folder.new_span(label.span), folder.fold_name(label.node))
-            })),
-            ExprAgain(opt_name) => ExprAgain(opt_name.map(|label| {
-                respan(folder.new_span(label.span), folder.fold_name(label.node))
-            })),
-            ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
-            ExprInlineAsm(asm, outputs, inputs) => {
-                ExprInlineAsm(asm,
-                              outputs.move_map(|x| folder.fold_expr(x)),
-                              inputs.move_map(|x| folder.fold_expr(x)))
-            }
-            ExprStruct(path, fields, maybe_expr) => {
-                ExprStruct(folder.fold_path(path),
-                           fields.move_map(|x| folder.fold_field(x)),
-                           maybe_expr.map(|x| folder.fold_expr(x)))
-            }
-        },
-        span: folder.new_span(span),
-        attrs: fold_attrs(attrs, folder),
-    }
-}
-
-pub fn noop_fold_stmt<T: Folder>(stmt: Stmt, folder: &mut T) -> Stmt {
-    let span = folder.new_span(stmt.span);
-    match stmt.node {
-        StmtDecl(d, id) => {
-            let id = folder.new_id(id);
-            Spanned {
-                node: StmtDecl(folder.fold_decl(d), id),
-                span: span
-            }
-        }
-        StmtExpr(e, id) => {
-            let id = folder.new_id(id);
-            Spanned {
-                node: StmtExpr(folder.fold_expr(e), id),
-                span: span,
-            }
-        }
-        StmtSemi(e, id) => {
-            let id = folder.new_id(id);
-            Spanned {
-                node: StmtSemi(folder.fold_expr(e), id),
-                span: span,
-            }
-        }
-    }
-}
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index f0caa971d96..726e4e53e23 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -881,8 +881,8 @@ pub struct IdRange {
 impl IdRange {
     pub fn max() -> IdRange {
         IdRange {
-            min: u32::MAX,
-            max: u32::MIN,
+            min: NodeId::from_u32(u32::MAX),
+            max: NodeId::from_u32(u32::MIN),
         }
     }
 
@@ -896,7 +896,7 @@ impl IdRange {
 
     pub fn add(&mut self, id: NodeId) {
         self.min = cmp::min(self.min, id);
-        self.max = cmp::max(self.max, id + 1);
+        self.max = cmp::max(self.max, NodeId::from_u32(id.as_u32() + 1));
     }
 
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 80e034721d6..37b5eac3cce 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -61,7 +61,7 @@ use syntax_pos::Span;
 pub struct LoweringContext<'a> {
     crate_root: Option<&'static str>,
     // Use to assign ids to hir nodes that do not directly correspond to an ast node
-    sess: Option<&'a Session>,
+    sess: &'a Session,
     // As we walk the AST we must keep track of the current 'parent' def id (in
     // the form of a DefIndex) so that if we create a new node which introduces
     // a definition, then we can properly create the def id.
@@ -81,21 +81,7 @@ pub trait Resolver {
 
     // We must keep the set of definitions up to date as we add nodes that weren't in the AST.
     // This should only return `None` during testing.
-    fn definitions(&mut self) -> Option<&mut Definitions>;
-}
-
-pub struct DummyResolver;
-impl Resolver for DummyResolver {
-    fn resolve_generated_global_path(&mut self, _path: &hir::Path, _is_value: bool) -> Def {
-        Def::Err
-    }
-    fn get_resolution(&mut self, _id: NodeId) -> Option<PathResolution> {
-        None
-    }
-    fn record_resolution(&mut self, _id: NodeId, _def: Def) {}
-    fn definitions(&mut self) -> Option<&mut Definitions> {
-        None
-    }
+    fn definitions(&mut self) -> &mut Definitions;
 }
 
 pub fn lower_crate(sess: &Session,
@@ -115,22 +101,13 @@ pub fn lower_crate(sess: &Session,
         } else {
             Some("std")
         },
-        sess: Some(sess),
+        sess: sess,
         parent_def: None,
         resolver: resolver,
     }.lower_crate(krate)
 }
 
 impl<'a> LoweringContext<'a> {
-    pub fn testing_context(resolver: &'a mut Resolver) -> Self {
-        LoweringContext {
-            crate_root: None,
-            sess: None,
-            parent_def: None,
-            resolver: resolver,
-        }
-    }
-
     fn lower_crate(&mut self, c: &Crate) -> hir::Crate {
         struct ItemLowerer<'lcx, 'interner: 'lcx> {
             items: BTreeMap<NodeId, hir::Item>,
@@ -161,12 +138,11 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn next_id(&self) -> NodeId {
-        self.sess.map(Session::next_node_id).unwrap_or(0)
+        self.sess.next_node_id()
     }
 
     fn diagnostic(&self) -> &errors::Handler {
-        self.sess.map(Session::diagnostic)
-                 .unwrap_or_else(|| panic!("this lowerer cannot emit diagnostics"))
+        self.sess.diagnostic()
     }
 
     fn str_to_ident(&self, s: &'static str) -> Name {
@@ -177,9 +153,9 @@ impl<'a> LoweringContext<'a> {
         where F: FnOnce(&mut LoweringContext) -> T
     {
         let old_def = self.parent_def;
-        self.parent_def = match self.resolver.definitions() {
-            Some(defs) => Some(defs.opt_def_index(parent_id).unwrap()),
-            None => old_def,
+        self.parent_def = {
+            let defs = self.resolver.definitions();
+            Some(defs.opt_def_index(parent_id).unwrap())
         };
 
         let result = f(self);
@@ -1719,9 +1695,10 @@ impl<'a> LoweringContext<'a> {
         let expr_path = hir::ExprPath(None, self.path_ident(span, id));
         let expr = self.expr(span, expr_path, ThinVec::new());
 
-        let def = self.resolver.definitions().map(|defs| {
-            Def::Local(defs.local_def_id(binding), binding)
-        }).unwrap_or(Def::Err);
+        let def = {
+            let defs = self.resolver.definitions();
+            Def::Local(defs.local_def_id(binding))
+        };
         self.resolver.record_resolution(expr.id, def);
 
         expr
@@ -1869,11 +1846,12 @@ impl<'a> LoweringContext<'a> {
         let pat = self.pat(span, pat_ident);
 
         let parent_def = self.parent_def;
-        let def = self.resolver.definitions().map(|defs| {
+        let def = {
+            let defs = self.resolver.definitions();
             let def_path_data = DefPathData::Binding(name.as_str());
             let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data);
-            Def::Local(DefId::local(def_index), pat.id)
-        }).unwrap_or(Def::Err);
+            Def::Local(DefId::local(def_index))
+        };
         self.resolver.record_resolution(pat.id, def);
 
         pat
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index d4e1eb70ae8..3d9031a136e 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -27,6 +27,10 @@ pub struct NodeCollector<'ast> {
     pub map: Vec<MapEntry<'ast>>,
     /// The parent of this node
     pub parent_node: NodeId,
+    /// If true, completely ignore nested items. We set this when loading
+    /// HIR from metadata, since in that case we only want the HIR for
+    /// one specific item (and not the ones nested inside of it).
+    pub ignore_nested_items: bool
 }
 
 impl<'ast> NodeCollector<'ast> {
@@ -35,6 +39,7 @@ impl<'ast> NodeCollector<'ast> {
             krate: krate,
             map: vec![],
             parent_node: CRATE_NODE_ID,
+            ignore_nested_items: false
         };
         collector.insert_entry(CRATE_NODE_ID, RootCrate);
 
@@ -52,6 +57,7 @@ impl<'ast> NodeCollector<'ast> {
             krate: krate,
             map: map,
             parent_node: parent_node,
+            ignore_nested_items: true
         };
 
         assert_eq!(parent_def_path.krate, parent_def_id.krate);
@@ -63,10 +69,10 @@ impl<'ast> NodeCollector<'ast> {
     fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
         debug!("ast_map: {:?} => {:?}", id, entry);
         let len = self.map.len();
-        if id as usize >= len {
-            self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
+        if id.as_usize() >= len {
+            self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1));
         }
-        self.map[id as usize] = entry;
+        self.map[id.as_usize()] = entry;
     }
 
     fn insert(&mut self, id: NodeId, node: Node<'ast>) {
@@ -88,7 +94,9 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     /// their outer items.
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
-        self.visit_item(self.krate.item(item.id))
+        if !self.ignore_nested_items {
+            self.visit_item(self.krate.item(item.id))
+        }
     }
 
     fn visit_item(&mut self, i: &'ast Item) {
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 29fb19fd421..ea1f8aac7a5 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -285,15 +285,6 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
 
 // We walk the HIR rather than the AST when reading items from metadata.
 impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
-    /// Because we want to track parent items and so forth, enable
-    /// deep walking so that we walk nested items in the context of
-    /// their outer items.
-    fn visit_nested_item(&mut self, item_id: hir::ItemId) {
-        debug!("visit_nested_item: {:?}", item_id);
-        let item = self.hir_crate.unwrap().item(item_id.id);
-        self.visit_item(item)
-    }
-
     fn visit_item(&mut self, i: &'ast hir::Item) {
         debug!("visit_item: {:?}", i);
 
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 901a489728e..f404f60cc9c 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::cstore::LOCAL_CRATE;
-use hir::def_id::{DefId, DefIndex};
+use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use hir::map::def_collector::DefCollector;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fmt::Write;
 use std::hash::{Hash, Hasher, SipHasher};
 use syntax::{ast, visit};
-use syntax::parse::token::InternedString;
+use syntax::parse::token::{self, InternedString};
 use ty::TyCtxt;
 use util::nodemap::NodeMap;
 
@@ -70,7 +69,7 @@ pub struct DefPath {
     pub data: Vec<DisambiguatedDefPathData>,
 
     /// what krate root is this path relative to?
-    pub krate: ast::CrateNum,
+    pub krate: CrateNum,
 }
 
 impl DefPath {
@@ -78,7 +77,7 @@ impl DefPath {
         self.krate == LOCAL_CRATE
     }
 
-    pub fn make<FN>(start_krate: ast::CrateNum,
+    pub fn make<FN>(start_krate: CrateNum,
                     start_index: DefIndex,
                     mut get_key: FN) -> DefPath
         where FN: FnMut(DefIndex) -> DefKey
@@ -116,11 +115,7 @@ impl DefPath {
     pub fn to_string(&self, tcx: TyCtxt) -> String {
         let mut s = String::with_capacity(self.data.len() * 16);
 
-        if self.krate == LOCAL_CRATE {
-            s.push_str(&tcx.crate_name(self.krate));
-        } else {
-            s.push_str(&tcx.sess.cstore.original_crate_name(self.krate));
-        }
+        s.push_str(&tcx.original_crate_name(self.krate));
         s.push_str("/");
         s.push_str(&tcx.crate_disambiguator(self.krate));
 
@@ -142,7 +137,7 @@ impl DefPath {
     }
 
     pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
-        tcx.crate_name(self.krate).hash(state);
+        tcx.original_crate_name(self.krate).hash(state);
         tcx.crate_disambiguator(self.krate).hash(state);
         self.data.hash(state);
     }
@@ -327,6 +322,30 @@ impl Definitions {
 }
 
 impl DefPathData {
+    pub fn get_opt_name(&self) -> Option<ast::Name> {
+        use self::DefPathData::*;
+        match *self {
+            TypeNs(ref name) |
+            ValueNs(ref name) |
+            Module(ref name) |
+            MacroDef(ref name) |
+            TypeParam(ref name) |
+            LifetimeDef(ref name) |
+            EnumVariant(ref name) |
+            Binding(ref name) |
+            Field(ref name) => Some(token::intern(name)),
+
+            Impl |
+            CrateRoot |
+            InlinedRoot(_) |
+            Misc |
+            ClosureExpr |
+            StructCtor |
+            Initializer |
+            ImplTrait => None
+        }
+    }
+
     pub fn as_interned_str(&self) -> InternedString {
         use self::DefPathData::*;
         match *self {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 5c302d927a7..b351bd427ac 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -22,17 +22,15 @@ use middle::cstore::InlinedItem as II;
 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
-use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
+use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
 
 use hir::*;
-use hir::fold::Folder;
 use hir::print as pprust;
 
 use arena::TypedArena;
 use std::cell::RefCell;
-use std::cmp;
 use std::io;
 use std::mem;
 
@@ -240,7 +238,7 @@ impl<'ast> Map<'ast> {
         let mut id = id0;
         if !self.is_inlined_node_id(id) {
             loop {
-                match map[id as usize] {
+                match map[id.as_usize()] {
                     EntryItem(_, item) => {
                         let def_id = self.local_def_id(item.id);
                         // NB                          ^~~~~~~
@@ -295,7 +293,7 @@ impl<'ast> Map<'ast> {
             // reading from an inlined def-id is really a read out of
             // the metadata from which we loaded the item.
             loop {
-                match map[id as usize] {
+                match map[id.as_usize()] {
                     EntryItem(p, _) |
                     EntryForeignItem(p, _) |
                     EntryTraitItem(p, _) |
@@ -373,7 +371,7 @@ impl<'ast> Map<'ast> {
     }
 
     fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
-        self.map.borrow().get(id as usize).cloned()
+        self.map.borrow().get(id.as_usize()).cloned()
     }
 
     pub fn krate(&self) -> &'ast Crate {
@@ -456,8 +454,8 @@ impl<'ast> Map<'ast> {
         let mut id = start_id;
         loop {
             let parent_node = self.get_parent_node(id);
-            if parent_node == 0 {
-                return Ok(0);
+            if parent_node == CRATE_NODE_ID {
+                return Ok(CRATE_NODE_ID);
             }
             if parent_node == id {
                 return Err(id);
@@ -582,22 +580,24 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData {
+    pub fn expect_variant_data(&self, id: NodeId) -> &'ast VariantData {
         match self.find(id) {
             Some(NodeItem(i)) => {
                 match i.node {
-                    ItemStruct(ref struct_def, _) => struct_def,
-                    _ => bug!("struct ID bound to non-struct")
+                    ItemStruct(ref struct_def, _) |
+                    ItemUnion(ref struct_def, _) => struct_def,
+                    _ => {
+                        bug!("struct ID bound to non-struct {}",
+                             self.node_to_string(id));
+                    }
                 }
             }
-            Some(NodeVariant(variant)) => {
-                if variant.node.data.is_struct() {
-                    &variant.node.data
-                } else {
-                    bug!("struct ID bound to enum variant that isn't struct-like")
-                }
+            Some(NodeStructCtor(data)) => data,
+            Some(NodeVariant(variant)) => &variant.node.data,
+            _ => {
+                bug!("expected struct or variant, found {}",
+                     self.node_to_string(id));
             }
-            _ => bug!("expected struct, found {}", self.node_to_string(id)),
         }
     }
 
@@ -680,7 +680,7 @@ impl<'ast> Map<'ast> {
             map: self,
             item_name: parts.last().unwrap(),
             in_which: &parts[..parts.len() - 1],
-            idx: 0,
+            idx: CRATE_NODE_ID,
         }
     }
 
@@ -801,10 +801,10 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
     fn next(&mut self) -> Option<NodeId> {
         loop {
             let idx = self.idx;
-            if idx as usize >= self.map.entry_count() {
+            if idx.as_usize() >= self.map.entry_count() {
                 return None;
             }
-            self.idx += 1;
+            self.idx = NodeId::from_u32(self.idx.as_u32() + 1);
             let name = match self.map.find_entry(idx) {
                 Some(EntryItem(_, n))       => n.name(),
                 Some(EntryForeignItem(_, n))=> n.name(),
@@ -832,57 +832,6 @@ impl Named for Variant_ { fn name(&self) -> Name { self.name } }
 impl Named for TraitItem { fn name(&self) -> Name { self.name } }
 impl Named for ImplItem { fn name(&self) -> Name { self.name } }
 
-pub trait FoldOps {
-    fn new_id(&self, id: NodeId) -> NodeId {
-        id
-    }
-    fn new_def_id(&self, def_id: DefId) -> DefId {
-        def_id
-    }
-    fn new_span(&self, span: Span) -> Span {
-        span
-    }
-}
-
-/// A Folder that updates IDs and Span's according to fold_ops.
-pub struct IdAndSpanUpdater<F> {
-    fold_ops: F,
-    min_id_assigned: NodeId,
-    max_id_assigned: NodeId,
-}
-
-impl<F: FoldOps> IdAndSpanUpdater<F> {
-    pub fn new(fold_ops: F) -> IdAndSpanUpdater<F> {
-        IdAndSpanUpdater {
-            fold_ops: fold_ops,
-            min_id_assigned: ::std::u32::MAX,
-            max_id_assigned: ::std::u32::MIN,
-        }
-    }
-
-    pub fn id_range(&self) -> intravisit::IdRange {
-        intravisit::IdRange {
-            min: self.min_id_assigned,
-            max: self.max_id_assigned + 1,
-        }
-    }
-}
-
-impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
-    fn new_id(&mut self, id: NodeId) -> NodeId {
-        let id = self.fold_ops.new_id(id);
-
-        self.min_id_assigned = cmp::min(self.min_id_assigned, id);
-        self.max_id_assigned = cmp::max(self.max_id_assigned, id);
-
-        id
-    }
-
-    fn new_span(&mut self, span: Span) -> Span {
-        self.fold_ops.new_span(span)
-    }
-}
-
 pub fn map_crate<'ast>(forest: &'ast mut Forest,
                        definitions: Definitions)
                        -> Map<'ast> {
@@ -906,7 +855,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
               entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
     }
 
-    let local_node_id_watermark = map.len() as NodeId;
+    let local_node_id_watermark = NodeId::new(map.len());
     let local_def_id_watermark = definitions.len();
 
     Map {
@@ -921,36 +870,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
 
 /// Used for items loaded from external crate that are being inlined into this
 /// crate.
-pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
-                                          parent_def_path: DefPath,
-                                          parent_def_id: DefId,
-                                          ii: InlinedItem,
-                                          fold_ops: F)
-                                          -> &'ast InlinedItem {
+pub fn map_decoded_item<'ast>(map: &Map<'ast>,
+                              parent_def_path: DefPath,
+                              parent_def_id: DefId,
+                              ii: InlinedItem,
+                              ii_parent_id: NodeId)
+                              -> &'ast InlinedItem {
     let _ignore = map.forest.dep_graph.in_ignore();
 
-    let mut fld = IdAndSpanUpdater::new(fold_ops);
-    let ii = match ii {
-        II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d),
-                                   i.map(|i| fld.fold_item(i))),
-        II::TraitItem(d, ti) => {
-            II::TraitItem(fld.fold_ops.new_def_id(d),
-                          ti.map(|ti| fld.fold_trait_item(ti)))
-        }
-        II::ImplItem(d, ii) => {
-            II::ImplItem(fld.fold_ops.new_def_id(d),
-                         ii.map(|ii| fld.fold_impl_item(ii)))
-        }
-    };
-
     let ii = map.forest.inlined_items.alloc(ii);
-    let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
-
-    // Assert that the ii_parent_id is the last NodeId in our reserved range
-    assert!(ii_parent_id == fld.max_id_assigned);
-    // Assert that we did not violate the invariant that all inlined HIR items
-    // have NodeIds greater than or equal to `local_node_id_watermark`
-    assert!(fld.min_id_assigned >= map.local_node_id_watermark);
 
     let defs = &mut *map.definitions.borrow_mut();
     let mut def_collector = DefCollector::extend(ii_parent_id,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index e22c9869ab1..0cfdbae1a50 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -67,7 +67,6 @@ macro_rules! hir_vec {
 pub mod check_attr;
 pub mod def;
 pub mod def_id;
-pub mod fold;
 pub mod intravisit;
 pub mod lowering;
 pub mod map;
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index a63bf14cb02..dec41fdfc3b 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -174,7 +174,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
             PatKind::Path(..) |
             PatKind::Struct(..) => {
                 match dm.get(&p.id) {
-                    Some(&PathResolution { base_def: Def::Variant(_, id), .. }) => {
+                    Some(&PathResolution { base_def: Def::Variant(id), .. }) => {
                         variants.push(id);
                     }
                     _ => ()
diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs
index 1c64ebc0537..289f7d6c738 100644
--- a/src/librustc/infer/region_inference/graphviz.rs
+++ b/src/librustc/infer/region_inference/graphviz.rs
@@ -63,9 +63,8 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
         return;
     }
 
-    let requested_node: Option<ast::NodeId> = env::var("RUST_REGION_GRAPH_NODE")
-                                                  .ok()
-                                                  .and_then(|s| s.parse().ok());
+    let requested_node = env::var("RUST_REGION_GRAPH_NODE")
+        .ok().and_then(|s| s.parse().map(ast::NodeId::new).ok());
 
     if requested_node.is_some() && requested_node != Some(subject_node) {
         return;
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index d2a2f8a972d..c34286f0195 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -50,7 +50,6 @@ extern crate fmt_macros;
 extern crate getopts;
 extern crate graphviz;
 extern crate libc;
-extern crate rbml;
 extern crate rustc_llvm as llvm;
 extern crate rustc_back;
 extern crate rustc_data_structures;
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index b2c293a290a..e57e116cea7 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -23,19 +23,18 @@
 // probably get a better home if someone can find one.
 
 use hir::def::{self, Def};
-use hir::def_id::{DefId, DefIndex};
+use hir::def_id::{CrateNum, DefId, DefIndex};
 use hir::map as hir_map;
 use hir::map::definitions::DefKey;
 use hir::svh::Svh;
 use middle::lang_items;
-use ty::{self, Ty, TyCtxt, VariantKind};
+use ty::{self, Ty, TyCtxt};
 use mir::repr::Mir;
 use mir::mir_map::MirMap;
 use session::Session;
 use session::config::PanicStrategy;
 use session::search_paths::PathKind;
-use util::nodemap::{FnvHashMap, NodeSet, DefIdMap};
-use std::rc::Rc;
+use util::nodemap::{NodeSet, DefIdMap};
 use std::path::PathBuf;
 use syntax::ast;
 use syntax::attr;
@@ -47,7 +46,6 @@ use rustc_back::target::Target;
 use hir;
 use hir::intravisit::Visitor;
 
-pub use self::DefLike::{DlDef, DlField, DlImpl};
 pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
 
 // lonely orphan structs and enums looking for a better home
@@ -64,30 +62,20 @@ pub struct LinkMeta {
 pub struct CrateSource {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
-    pub cnum: ast::CrateNum,
+    pub cnum: CrateNum,
 }
 
-#[derive(Copy, Debug, PartialEq, Clone)]
+#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
 pub enum LinkagePreference {
     RequireDynamic,
     RequireStatic,
 }
 
-enum_from_u32! {
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub enum NativeLibraryKind {
-        NativeStatic,    // native static library (.a archive)
-        NativeFramework, // OSX-specific
-        NativeUnknown,   // default way to specify a dynamic library
-    }
-}
-
-// Something that a name can resolve to.
-#[derive(Copy, Clone, Debug)]
-pub enum DefLike {
-    DlDef(Def),
-    DlImpl(DefId),
-    DlField
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub enum NativeLibraryKind {
+    NativeStatic,    // native static library (.a archive)
+    NativeFramework, // OSX-specific
+    NativeUnknown,   // default way to specify a dynamic library
 }
 
 /// The data we save and restore about an inlined item or method.  This is not
@@ -101,24 +89,13 @@ pub enum InlinedItem {
 }
 
 /// A borrowed version of `hir::InlinedItem`.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)]
 pub enum InlinedItemRef<'a> {
     Item(DefId, &'a hir::Item),
     TraitItem(DefId, &'a hir::TraitItem),
     ImplItem(DefId, &'a hir::ImplItem)
 }
 
-/// Item definitions in the currently-compiled crate would have the CrateNum
-/// LOCAL_CRATE in their DefId.
-pub const LOCAL_CRATE: ast::CrateNum = 0;
-
-#[derive(Copy, Clone)]
-pub struct ChildItem {
-    pub def: DefLike,
-    pub name: ast::Name,
-    pub vis: ty::Visibility,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub struct ExternCrate {
     /// def_id of an `extern crate` in the current crate that caused
@@ -144,6 +121,7 @@ pub struct ExternCrate {
 /// can be accessed.
 pub trait CrateStore<'tcx> {
     // item info
+    fn describe_def(&self, def: DefId) -> Option<Def>;
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
     fn visibility(&self, def: DefId) -> ty::Visibility;
@@ -151,40 +129,31 @@ pub trait CrateStore<'tcx> {
     fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                       -> ty::ClosureTy<'tcx>;
     fn item_variances(&self, def: DefId) -> Vec<ty::Variance>;
-    fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> Ty<'tcx>;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
-    fn item_name(&self, def: DefId) -> ast::Name;
-    fn opt_item_name(&self, def: DefId) -> Option<ast::Name>;
     fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                            -> ty::GenericPredicates<'tcx>;
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx>;
     fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> &'tcx ty::Generics<'tcx>;
+                         -> ty::Generics<'tcx>;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>;
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>;
-    fn method_arg_names(&self, did: DefId) -> Vec<String>;
+    fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
 
     // trait info
-    fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId>;
-    fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                  -> Vec<Rc<ty::Method<'tcx>>>;
-    fn trait_item_def_ids(&self, def: DefId)
-                          -> Vec<ty::ImplOrTraitItemId>;
+    fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>;
+    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>;
     fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                           -> Option<ty::TraitRef<'tcx>>;
-    fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity>;
+    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
     fn custom_coerce_unsized_kind(&self, def: DefId)
                                   -> Option<ty::adjustment::CustomCoerceUnsized>;
-    fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                             -> Vec<Rc<ty::AssociatedConst<'tcx>>>;
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
@@ -195,53 +164,46 @@ pub trait CrateStore<'tcx> {
     // flags
     fn is_const_fn(&self, did: DefId) -> bool;
     fn is_defaulted_trait(&self, did: DefId) -> bool;
-    fn is_impl(&self, did: DefId) -> bool;
     fn is_default_impl(&self, impl_did: DefId) -> bool;
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool;
     fn is_foreign_item(&self, did: DefId) -> bool;
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool;
-    fn is_typedef(&self, did: DefId) -> bool;
 
     // crate metadata
-    fn dylib_dependency_formats(&self, cnum: ast::CrateNum)
-                                    -> Vec<(ast::CrateNum, LinkagePreference)>;
-    fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>;
-    fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec<lang_items::LangItem>;
-    fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
-    fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
-    fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
-    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool;
-    fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool;
-    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy;
-    fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
-    fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
+    fn dylib_dependency_formats(&self, cnum: CrateNum)
+                                    -> Vec<(CrateNum, LinkagePreference)>;
+    fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>;
+    fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>;
+    fn is_staged_api(&self, cnum: CrateNum) -> bool;
+    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool;
+    fn is_allocator(&self, cnum: CrateNum) -> bool;
+    fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
+    fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
+    fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy;
+    fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>;
     /// The name of the crate as it is referred to in source code of the current
     /// crate.
-    fn crate_name(&self, cnum: ast::CrateNum) -> InternedString;
+    fn crate_name(&self, cnum: CrateNum) -> InternedString;
     /// The name of the crate as it is stored in the crate's metadata.
-    fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString;
-    fn crate_hash(&self, cnum: ast::CrateNum) -> Svh;
-    fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString;
-    fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-                                -> FnvHashMap<DefId, Vec<ast::Attribute>>;
-    fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>;
-    fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>;
-    fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
-    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool;
+    fn original_crate_name(&self, cnum: CrateNum) -> InternedString;
+    fn crate_hash(&self, cnum: CrateNum) -> Svh;
+    fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString;
+    fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>;
+    fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>;
+    fn is_no_builtins(&self, cnum: CrateNum) -> bool;
 
     // resolve
     fn def_index_for_def_key(&self,
-                             cnum: ast::CrateNum,
+                             cnum: CrateNum,
                              def: DefKey)
                              -> Option<DefIndex>;
     fn def_key(&self, def: DefId) -> hir_map::DefKey;
     fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath>;
-    fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
+    fn variant_kind(&self, def_id: DefId) -> Option<ty::VariantKind>;
     fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
-    fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
-    fn item_children(&self, did: DefId) -> Vec<ChildItem>;
-    fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec<ChildItem>;
+    fn item_children(&self, did: DefId) -> Vec<def::Export>;
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -255,27 +217,21 @@ pub trait CrateStore<'tcx> {
 
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
-    fn crates(&self) -> Vec<ast::CrateNum>;
+    fn crates(&self) -> Vec<CrateNum>;
     fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>;
     fn used_link_args(&self) -> Vec<String>;
 
     // utility functions
     fn metadata_filename(&self) -> &str;
     fn metadata_section_name(&self, target: &Target) -> &str;
-    fn encode_type<'a>(&self,
-                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                       ty: Ty<'tcx>,
-                       def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
-                       -> Vec<u8>;
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>;
-    fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource;
-    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>;
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>;
+    fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
+    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
-                           mir_map: &MirMap<'tcx>,
-                           krate: &hir::Crate) -> Vec<u8>;
+                           mir_map: &MirMap<'tcx>) -> Vec<u8>;
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
@@ -324,59 +280,51 @@ pub struct DummyCrateStore;
 #[allow(unused_variables)]
 impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     // item info
+    fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") }
     fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
     fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
-    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind  { bug!("closure_kind") }
+    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") }
     fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                       -> ty::ClosureTy<'tcx>  { bug!("closure_ty") }
     fn item_variances(&self, def: DefId) -> Vec<ty::Variance> { bug!("item_variances") }
-    fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> Ty<'tcx> { bug!("item_type") }
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
-    fn item_name(&self, def: DefId) -> ast::Name { bug!("item_name") }
-    fn opt_item_name(&self, def: DefId) -> Option<ast::Name> { bug!("opt_item_name") }
     fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                            -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
     fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> &'tcx ty::Generics<'tcx> { bug!("item_generics") }
+                         -> ty::Generics<'tcx> { bug!("item_generics") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>
         { bug!("trait_def") }
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>
         { bug!("adt_def") }
-    fn method_arg_names(&self, did: DefId) -> Vec<String> { bug!("method_arg_names") }
+    fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
 
     // trait info
-    fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId> { vec![] }
-    fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                  -> Vec<Rc<ty::Method<'tcx>>> { bug!("provided_trait_methods") }
-    fn trait_item_def_ids(&self, def: DefId)
-                          -> Vec<ty::ImplOrTraitItemId> { bug!("trait_item_def_ids") }
+    fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
     fn def_index_for_def_key(&self,
-                             cnum: ast::CrateNum,
+                             cnum: CrateNum,
                              def: DefKey)
                              -> Option<DefIndex> {
         None
     }
 
     // impl info
-    fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>
-        { bug!("impl_items") }
+    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>
+        { bug!("impl_or_trait_items") }
     fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                           -> Option<ty::TraitRef<'tcx>> { bug!("impl_trait_ref") }
-    fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity> { bug!("impl_polarity") }
+    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
     fn custom_coerce_unsized_kind(&self, def: DefId)
                                   -> Option<ty::adjustment::CustomCoerceUnsized>
         { bug!("custom_coerce_unsized_kind") }
-    fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                             -> Vec<Rc<ty::AssociatedConst<'tcx>>> { bug!("associated_consts") }
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
@@ -387,64 +335,53 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     // flags
     fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
     fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
-    fn is_impl(&self, did: DefId) -> bool { bug!("is_impl") }
     fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool
         { bug!("is_extern_item") }
     fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false }
-    fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") }
 
     // crate metadata
-    fn dylib_dependency_formats(&self, cnum: ast::CrateNum)
-                                    -> Vec<(ast::CrateNum, LinkagePreference)>
+    fn dylib_dependency_formats(&self, cnum: CrateNum)
+                                    -> Vec<(CrateNum, LinkagePreference)>
         { bug!("dylib_dependency_formats") }
-    fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>
+    fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
         { bug!("lang_items") }
-    fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec<lang_items::LangItem>
+    fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>
         { bug!("missing_lang_items") }
-    fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { bug!("is_staged_api") }
-    fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") }
-    fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") }
-    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") }
-    fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_compiler_builtins") }
-    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
+    fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") }
+    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") }
+    fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }
+    fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") }
+    fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") }
+    fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
         bug!("panic_strategy")
     }
-    fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { bug!("extern_crate") }
-    fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
-        { bug!("crate_attrs") }
-    fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { bug!("crate_name") }
-    fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString {
+    fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate> { bug!("extern_crate") }
+    fn crate_name(&self, cnum: CrateNum) -> InternedString { bug!("crate_name") }
+    fn original_crate_name(&self, cnum: CrateNum) -> InternedString {
         bug!("original_crate_name")
     }
-    fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { bug!("crate_hash") }
-    fn crate_disambiguator(&self, cnum: ast::CrateNum)
+    fn crate_hash(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") }
+    fn crate_disambiguator(&self, cnum: CrateNum)
                            -> InternedString { bug!("crate_disambiguator") }
-    fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-                                -> FnvHashMap<DefId, Vec<ast::Attribute>>
-        { bug!("crate_struct_field_attrs") }
-    fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>
+    fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
         { bug!("plugin_registrar_fn") }
-    fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
         { bug!("native_libraries") }
-    fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
-    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_no_builtins") }
+    fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
+    fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") }
 
     // resolve
     fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") }
     fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath> {
         bug!("relative_def_path")
     }
-    fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { bug!("variant_kind") }
+    fn variant_kind(&self, def_id: DefId) -> Option<ty::VariantKind> { bug!("variant_kind") }
     fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
         { bug!("struct_ctor_def_id") }
-    fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
-        { bug!("tuple_struct_definition_if_ctor") }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
-    fn item_children(&self, did: DefId) -> Vec<ChildItem> { bug!("item_children") }
-    fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec<ChildItem>
-        { bug!("crate_top_level_items") }
+    fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
 
     // misc. metadata
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@@ -466,187 +403,25 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
-    fn crates(&self) -> Vec<ast::CrateNum> { vec![] }
+    fn crates(&self) -> Vec<CrateNum> { vec![] }
     fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] }
     fn used_link_args(&self) -> Vec<String> { vec![] }
 
     // utility functions
     fn metadata_filename(&self) -> &str { bug!("metadata_filename") }
     fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") }
-    fn encode_type<'a>(&self,
-                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                       ty: Ty<'tcx>,
-                       def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
-                       -> Vec<u8> {
-        bug!("encode_type")
-    }
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
         { vec![] }
-    fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource { bug!("used_crate_source") }
-    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum> { None }
+    fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
+    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
-                           mir_map: &MirMap<'tcx>,
-                           krate: &hir::Crate) -> Vec<u8> { vec![] }
+                           mir_map: &MirMap<'tcx>) -> Vec<u8> { vec![] }
     fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
 }
 
 pub trait MacroLoader {
      fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
 }
-
-/// Metadata encoding and decoding can make use of thread-local encoding and
-/// decoding contexts. These allow implementers of serialize::Encodable and
-/// Decodable to access information and datastructures that would otherwise not
-/// be available to them. For example, we can automatically translate def-id and
-/// span information during decoding because the decoding context knows which
-/// crate the data is decoded from. Or it allows to make ty::Ty decodable
-/// because the context has access to the TyCtxt that is needed for creating
-/// ty::Ty instances.
-///
-/// Note, however, that this only works for RBML-based encoding and decoding at
-/// the moment.
-pub mod tls {
-    use rbml::opaque::Encoder as OpaqueEncoder;
-    use rbml::opaque::Decoder as OpaqueDecoder;
-    use serialize;
-    use std::cell::Cell;
-    use std::mem;
-    use ty::{self, Ty, TyCtxt};
-    use ty::subst::Substs;
-    use hir::def_id::DefId;
-
-    pub trait EncodingContext<'tcx> {
-        fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
-        fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: Ty<'tcx>);
-        fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>);
-    }
-
-    /// Marker type used for the TLS slot.
-    /// The type context cannot be used directly because the TLS
-    /// in libstd doesn't allow types generic over lifetimes.
-    struct TlsPayload;
-
-    thread_local! {
-        static TLS_ENCODING: Cell<Option<*const TlsPayload>> = Cell::new(None)
-    }
-
-    /// Execute f after pushing the given EncodingContext onto the TLS stack.
-    pub fn enter_encoding_context<'tcx, F, R>(ecx: &EncodingContext<'tcx>,
-                                              encoder: &mut OpaqueEncoder,
-                                              f: F) -> R
-        where F: FnOnce(&EncodingContext<'tcx>, &mut OpaqueEncoder) -> R
-    {
-        let tls_payload = (ecx as *const _, encoder as *mut _);
-        let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
-        TLS_ENCODING.with(|tls| {
-            let prev = tls.get();
-            tls.set(Some(tls_ptr));
-            let ret = f(ecx, encoder);
-            tls.set(prev);
-            return ret
-        })
-    }
-
-    /// Execute f with access to the thread-local encoding context and
-    /// rbml encoder. This function will panic if the encoder passed in and the
-    /// context encoder are not the same.
-    ///
-    /// Note that this method is 'practically' safe due to its checking that the
-    /// encoder passed in is the same as the one in TLS, but it would still be
-    /// possible to construct cases where the EncodingContext is exchanged
-    /// while the same encoder is used, thus working with a wrong context.
-    pub fn with_encoding_context<'tcx, E, F, R>(encoder: &mut E, f: F) -> R
-        where F: FnOnce(&EncodingContext<'tcx>, &mut OpaqueEncoder) -> R,
-              E: serialize::Encoder
-    {
-        unsafe {
-            unsafe_with_encoding_context(|ecx, tls_encoder| {
-                assert!(encoder as *mut _ as usize == tls_encoder as *mut _ as usize);
-
-                let ecx: &EncodingContext<'tcx> = mem::transmute(ecx);
-
-                f(ecx, tls_encoder)
-            })
-        }
-    }
-
-    /// Execute f with access to the thread-local encoding context and
-    /// rbml encoder.
-    pub unsafe fn unsafe_with_encoding_context<F, R>(f: F) -> R
-        where F: FnOnce(&EncodingContext, &mut OpaqueEncoder) -> R
-    {
-        TLS_ENCODING.with(|tls| {
-            let tls = tls.get().unwrap();
-            let tls_payload = tls as *mut (&EncodingContext, &mut OpaqueEncoder);
-            f((*tls_payload).0, (*tls_payload).1)
-        })
-    }
-
-    pub trait DecodingContext<'tcx> {
-        fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
-        fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>;
-        fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>;
-        fn translate_def_id(&self, def_id: DefId) -> DefId;
-    }
-
-    thread_local! {
-        static TLS_DECODING: Cell<Option<*const TlsPayload>> = Cell::new(None)
-    }
-
-    /// Execute f after pushing the given DecodingContext onto the TLS stack.
-    pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>,
-                                              decoder: &mut OpaqueDecoder,
-                                              f: F) -> R
-        where F: FnOnce(&DecodingContext<'tcx>, &mut OpaqueDecoder) -> R
-    {
-        let tls_payload = (dcx as *const _, decoder as *mut _);
-        let tls_ptr = &tls_payload as *const _ as *const TlsPayload;
-        TLS_DECODING.with(|tls| {
-            let prev = tls.get();
-            tls.set(Some(tls_ptr));
-            let ret = f(dcx, decoder);
-            tls.set(prev);
-            return ret
-        })
-    }
-
-    /// Execute f with access to the thread-local decoding context and
-    /// rbml decoder. This function will panic if the decoder passed in and the
-    /// context decoder are not the same.
-    ///
-    /// Note that this method is 'practically' safe due to its checking that the
-    /// decoder passed in is the same as the one in TLS, but it would still be
-    /// possible to construct cases where the DecodingContext is exchanged
-    /// while the same decoder is used, thus working with a wrong context.
-    pub fn with_decoding_context<'decoder, 'tcx, D, F, R>(d: &'decoder mut D, f: F) -> R
-        where D: serialize::Decoder,
-              F: FnOnce(&DecodingContext<'tcx>,
-                        &mut OpaqueDecoder) -> R,
-              'tcx: 'decoder
-    {
-        unsafe {
-            unsafe_with_decoding_context(|dcx, decoder| {
-                assert!((d as *mut _ as usize) == (decoder as *mut _ as usize));
-
-                let dcx: &DecodingContext<'tcx> = mem::transmute(dcx);
-
-                f(dcx, decoder)
-            })
-        }
-    }
-
-    /// Execute f with access to the thread-local decoding context and
-    /// rbml decoder.
-    pub unsafe fn unsafe_with_decoding_context<F, R>(f: F) -> R
-        where F: FnOnce(&DecodingContext, &mut OpaqueDecoder) -> R
-    {
-        TLS_DECODING.with(|tls| {
-            let tls = tls.get().unwrap();
-            let tls_payload = tls as *mut (&DecodingContext, &mut OpaqueDecoder);
-            f((*tls_payload).0, (*tls_payload).1)
-        })
-    }
-}
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index fc1294c86c4..7f3a58808c2 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -112,10 +112,10 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
            ps: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
         let id = match node {
-            pprust::NodeName(_) => 0,
+            pprust::NodeName(_) => ast::CRATE_NODE_ID,
             pprust::NodeExpr(expr) => expr.id,
             pprust::NodeBlock(blk) => blk.id,
-            pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
+            pprust::NodeItem(_) | pprust::NodeSubItem(_) => ast::CRATE_NODE_ID,
             pprust::NodePat(pat) => pat.id
         };
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 9db6ac1dcef..30a0c6a9dc9 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -108,8 +108,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             _ if self.ignore_non_const_paths => (),
             Def::PrimTy(_) => (),
             Def::SelfTy(..) => (),
-            Def::Variant(enum_id, variant_id) => {
-                self.check_def_id(enum_id);
+            Def::Variant(variant_id) => {
+                if let Some(enum_id) = self.tcx.parent_def_id(variant_id) {
+                    self.check_def_id(enum_id);
+                }
                 if !self.ignore_variant_stack.contains(&variant_id) {
                     self.check_def_id(variant_id);
                 }
@@ -470,13 +472,12 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
         // This is done to handle the case where, for example, the static
         // method of a private type is used, but the type itself is never
         // called directly.
-        let impl_items = self.tcx.impl_items.borrow();
+        let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
         if let Some(impl_list) =
                 self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
             for impl_did in impl_list.iter() {
-                for item_did in impl_items.get(impl_did).unwrap().iter() {
-                    if let Some(item_node_id) =
-                            self.tcx.map.as_local_node_id(item_did.def_id()) {
+                for &item_did in &impl_items[impl_did][..] {
+                    if let Some(item_node_id) = self.tcx.map.as_local_node_id(item_did) {
                         if self.live_symbols.contains(&item_node_id) {
                             return true;
                         }
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index 7822fe2536f..c6908e11ed2 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -61,7 +61,7 @@
 //! Additionally, the algorithm is geared towards finding *any* solution rather
 //! than finding a number of solutions (there are normally quite a few).
 
-use syntax::ast;
+use hir::def_id::CrateNum;
 
 use session;
 use session::config::{self, PanicStrategy};
@@ -169,9 +169,9 @@ fn calculate_type(sess: &session::Session,
     }
 
     // Collect what we've got so far in the return vector.
-    let last_crate = sess.cstore.crates().len() as ast::CrateNum;
+    let last_crate = sess.cstore.crates().len();
     let mut ret = (1..last_crate+1).map(|cnum| {
-        match formats.get(&cnum) {
+        match formats.get(&CrateNum::new(cnum)) {
             Some(&RequireDynamic) => Linkage::Dynamic,
             Some(&RequireStatic) => Linkage::IncludedFromDylib,
             None => Linkage::NotLinked,
@@ -191,7 +191,7 @@ fn calculate_type(sess: &session::Session,
             assert!(src.rlib.is_some());
             info!("adding staticlib: {}", sess.cstore.crate_name(cnum));
             add_library(sess, cnum, RequireStatic, &mut formats);
-            ret[cnum as usize - 1] = Linkage::Static;
+            ret[cnum.as_usize() - 1] = Linkage::Static;
         }
     }
 
@@ -213,7 +213,7 @@ fn calculate_type(sess: &session::Session,
     // For situations like this, we perform one last pass over the dependencies,
     // making sure that everything is available in the requested format.
     for (cnum, kind) in ret.iter().enumerate() {
-        let cnum = (cnum + 1) as ast::CrateNum;
+        let cnum = CrateNum::new(cnum + 1);
         let src = sess.cstore.used_crate_source(cnum);
         match *kind {
             Linkage::NotLinked |
@@ -237,9 +237,9 @@ fn calculate_type(sess: &session::Session,
 }
 
 fn add_library(sess: &session::Session,
-               cnum: ast::CrateNum,
+               cnum: CrateNum,
                link: LinkagePreference,
-               m: &mut FnvHashMap<ast::CrateNum, LinkagePreference>) {
+               m: &mut FnvHashMap<CrateNum, LinkagePreference>) {
     match m.get(&cnum) {
         Some(&link2) => {
             // If the linkages differ, then we'd have two copies of the library
@@ -269,9 +269,9 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
 
     // All crates are available in an rlib format, so we're just going to link
     // everything in explicitly so long as it's actually required.
-    let last_crate = sess.cstore.crates().len() as ast::CrateNum;
+    let last_crate = sess.cstore.crates().len();
     let mut ret = (1..last_crate+1).map(|cnum| {
-        if sess.cstore.is_explicitly_linked(cnum) {
+        if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) {
             Linkage::Static
         } else {
             Linkage::NotLinked
@@ -298,11 +298,11 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
 // a required dependency) in one of the session's field. If this field is not
 // set then this compilation doesn't actually need the dependency and we can
 // also skip this step entirely.
-fn activate_injected_dep(injected: Option<ast::CrateNum>,
+fn activate_injected_dep(injected: Option<CrateNum>,
                          list: &mut DependencyList,
-                         replaces_injected: &Fn(ast::CrateNum) -> bool) {
+                         replaces_injected: &Fn(CrateNum) -> bool) {
     for (i, slot) in list.iter().enumerate() {
-        let cnum = (i + 1) as ast::CrateNum;
+        let cnum = CrateNum::new(i + 1);
         if !replaces_injected(cnum) {
             continue
         }
@@ -311,7 +311,7 @@ fn activate_injected_dep(injected: Option<ast::CrateNum>,
         }
     }
     if let Some(injected) = injected {
-        let idx = injected as usize - 1;
+        let idx = injected.as_usize() - 1;
         assert_eq!(list[idx], Linkage::NotLinked);
         list[idx] = Linkage::Static;
     }
@@ -329,7 +329,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
         if let Linkage::NotLinked = *linkage {
             continue
         }
-        let cnum = (i + 1) as ast::CrateNum;
+        let cnum = CrateNum::new(i + 1);
         if sess.cstore.is_allocator(cnum) {
             if let Some(prev) = allocator {
                 let prev_name = sess.cstore.crate_name(prev);
@@ -380,7 +380,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
             if desired_strategy == PanicStrategy::Abort {
                 continue
             }
-            let cnum = (i + 1) as ast::CrateNum;
+            let cnum = CrateNum::new(i + 1);
             let found_strategy = sess.cstore.panic_strategy(cnum);
             if desired_strategy == found_strategy {
                 continue
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 9f05dde4e66..5b5c3da8f05 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -1003,7 +1003,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         // the leaves of the pattern tree structure.
         return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
             match tcx.expect_def_or_none(pat.id) {
-                Some(Def::Variant(enum_did, variant_did)) => {
+                Some(Def::Variant(variant_did)) => {
+                    let enum_did = tcx.parent_def_id(variant_did).unwrap();
                     let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() {
                         cmt_pat
                     } else {
@@ -1029,7 +1030,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
         self.tcx().with_freevars(closure_expr.id, |freevars| {
             for freevar in freevars {
-                let id_var = freevar.def.var_id();
+                let def_id = freevar.def.def_id();
+                let id_var = self.tcx().map.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: id_var,
                                              closure_expr_id: closure_expr.id };
                 let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap();
@@ -1061,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                         -> mc::McResult<mc::cmt<'tcx>> {
         // Create the cmt for the variable being borrowed, from the
         // caller's perspective
-        let var_id = upvar_def.var_id();
+        let var_id = self.tcx().map.as_local_node_id(upvar_def.def_id()).unwrap();
         let var_ty = self.mc.infcx.node_ty(var_id)?;
         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
     }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index d1769d5cbc5..078cce9c49f 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -43,7 +43,7 @@ macro_rules! language_item_table {
 
 
 enum_from_u32! {
-    #[derive(Copy, Clone, PartialEq, Eq, Hash)]
+    #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
     pub enum LangItem {
         $($variant,)*
     }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index b579c69cd05..db9dd82d492 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -465,7 +465,8 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         let mut call_caps = Vec::new();
         ir.tcx.with_freevars(expr.id, |freevars| {
             for fv in freevars {
-                if let Def::Local(_, rv) = fv.def {
+                if let Def::Local(def_id) = fv.def {
+                    let rv = ir.tcx.map.as_local_node_id(def_id).unwrap();
                     let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
                     call_caps.push(CaptureInfo {ln: fv_ln,
                                                 var_nid: rv});
@@ -1270,7 +1271,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                    -> LiveNode {
         match self.ir.tcx.expect_def(expr.id) {
-          Def::Local(_, nid) => {
+          Def::Local(def_id) => {
+            let nid = self.ir.tcx.map.as_local_node_id(def_id).unwrap();
             let ln = self.live_node(expr.id, expr.span);
             if acc != 0 {
                 self.init_from_succ(ln, succ);
@@ -1529,11 +1531,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
             hir::ExprPath(..) => {
-                if let Def::Local(_, nid) = self.ir.tcx.expect_def(expr.id) {
+                if let Def::Local(def_id) = self.ir.tcx.expect_def(expr.id) {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
                     // mutable, then check for a reassignment to flag the mutability
                     // as being used.
+                    let nid = self.ir.tcx.map.as_local_node_id(def_id).unwrap();
                     let ln = self.live_node(expr.id, expr.span);
                     let var = self.variable(nid, expr.span);
                     self.warn_about_dead_assign(expr.span, expr.id, ln, var);
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index c419f96e820..340a5ac8f87 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -529,7 +529,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                 Ok(self.cat_rvalue_node(id, span, expr_ty))
           }
 
-          Def::Mod(_) | Def::ForeignMod(_) |
+          Def::Mod(_) |
           Def::Trait(_) | Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(_) |
           Def::TyParam(..) |
           Def::Label(_) | Def::SelfTy(..) |
@@ -549,7 +549,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
               }))
           }
 
-          Def::Upvar(_, var_id, _, fn_node_id) => {
+          Def::Upvar(def_id, _, fn_node_id) => {
+              let var_id = self.tcx().map.as_local_node_id(def_id).unwrap();
               let ty = self.node_ty(fn_node_id)?;
               match ty.sty {
                   ty::TyClosure(closure_id, _) => {
@@ -585,7 +586,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
               }
           }
 
-          Def::Local(_, vid) => {
+          Def::Local(def_id) => {
+            let vid = self.tcx().map.as_local_node_id(def_id).unwrap();
             Ok(Rc::new(cmt_ {
                 id: id,
                 span: span,
@@ -1075,18 +1077,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // alone) because PatKind::Struct can also refer to variants.
         let cmt = match self.tcx().expect_def_or_none(pat.id) {
             Some(Def::Err) => return Err(()),
-            Some(Def::Variant(enum_did, variant_did))
+            Some(Def::Variant(variant_did)) => {
                 // univariant enums do not need downcasts
-                if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
+                let enum_did = self.tcx().parent_def_id(variant_did).unwrap();
+                if !self.tcx().lookup_adt_def(enum_did).is_univariant() {
                     self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
+                } else {
+                    cmt
                 }
+            }
             _ => cmt
         };
 
         match pat.node {
           PatKind::TupleStruct(_, ref subpats, ddpos) => {
             let expected_len = match self.tcx().expect_def(pat.id) {
-                Def::Variant(enum_def, def_id) => {
+                Def::Variant(def_id) => {
+                    let enum_def = self.tcx().parent_def_id(def_id).unwrap();
                     self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len()
                 }
                 Def::Struct(..) => {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index fb99820f7c8..33110c61e8f 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -20,7 +20,6 @@ use dep_graph::DepNode;
 use hir::map as ast_map;
 use session::Session;
 use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
-use middle::cstore::InlinedItem;
 use ty;
 
 use std::cell::RefCell;
@@ -1256,19 +1255,3 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
     }
     return maps;
 }
-
-pub fn resolve_inlined_item(sess: &Session,
-                            region_maps: &RegionMaps,
-                            item: &InlinedItem) {
-    let mut visitor = RegionResolutionVisitor {
-        sess: sess,
-        region_maps: region_maps,
-        cx: Context {
-            root_id: None,
-            parent: ROOT_CODE_EXTENT,
-            var_parent: ROOT_CODE_EXTENT
-        },
-        terminating_scopes: NodeSet()
-    };
-    item.visit(&mut visitor);
-}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9a56959de38..2c768db47f1 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -17,9 +17,8 @@ use dep_graph::DepNode;
 use hir::map as hir_map;
 use session::Session;
 use lint;
-use middle::cstore::LOCAL_CRATE;
 use hir::def::Def;
-use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
+use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE};
 use ty::{self, TyCtxt, AdtKind};
 use middle::privacy::AccessLevels;
 use syntax::parse::token::InternedString;
@@ -103,7 +102,7 @@ pub struct Index<'tcx> {
     depr_map: DefIdMap<Option<DeprecationEntry>>,
 
     /// Maps for each crate whether it is part of the staged API.
-    staged_api: FnvHashMap<ast::CrateNum, bool>
+    staged_api: FnvHashMap<CrateNum, bool>
 }
 
 // A private tree-walker for producing an Index.
@@ -696,10 +695,9 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool {
 
 fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool {
     match tcx.trait_item_of_item(id) {
-        Some(ty::MethodTraitItemId(trait_method_id))
-            if trait_method_id != id => {
-                is_staged_api(tcx, trait_method_id)
-            }
+        Some(trait_method_id) if trait_method_id != id => {
+            is_staged_api(tcx, trait_method_id)
+        }
         _ => {
             *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
                 || tcx.sess.cstore.is_staged_api(id.krate))
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index be761c95b61..6ad6251d584 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -1154,7 +1154,9 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 
                             tcx.with_freevars(node_id, |freevars| {
                                 for (freevar, lv) in freevars.iter().zip(lvs) {
-                                    let var_name = tcx.local_var_name_str(freevar.def.var_id());
+                                    let def_id = freevar.def.def_id();
+                                    let var_id = tcx.map.as_local_node_id(def_id).unwrap();
+                                    let var_name = tcx.local_var_name_str(var_id);
                                     struct_fmt.field(&var_name, lv);
                                 }
                             });
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 2009e18f6ee..8dd5d4d45f7 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -493,7 +493,7 @@ impl Passes {
     }
 }
 
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub enum PanicStrategy {
     Unwind,
     Abort,
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 49686d63ee4..268dbd70bb5 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepGraph;
-use hir::def_id::DefIndex;
+use hir::def_id::{CrateNum, DefIndex};
 use hir::svh::Svh;
 use lint;
 use middle::cstore::CrateStore;
@@ -93,8 +93,8 @@ pub struct Session {
     /// The metadata::creader module may inject an allocator/panic_runtime
     /// dependency if it didn't already find one, and this tracks what was
     /// injected.
-    pub injected_allocator: Cell<Option<ast::CrateNum>>,
-    pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
+    pub injected_allocator: Cell<Option<CrateNum>>,
+    pub injected_panic_runtime: Cell<Option<CrateNum>>,
 
     /// Map from imported macro spans (which consist of
     /// the localized span for the macro body) to the
@@ -266,11 +266,13 @@ impl Session {
         }
         lints.insert(id, vec!((lint_id, sp, msg)));
     }
-    pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
+    pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
         let id = self.next_node_id.get();
 
-        match id.checked_add(count) {
-            Some(next) => self.next_node_id.set(next),
+        match id.as_usize().checked_add(count) {
+            Some(next) => {
+                self.next_node_id.set(ast::NodeId::new(next));
+            }
             None => bug!("Input too large, ran out of node ids!")
         }
 
@@ -545,7 +547,7 @@ pub fn build_session_(sopts: config::Options,
         crate_disambiguator: RefCell::new(token::intern("").as_str()),
         features: RefCell::new(feature_gate::Features::new()),
         recursion_limit: Cell::new(64),
-        next_node_id: Cell::new(1),
+        next_node_id: Cell::new(NodeId::new(1)),
         injected_allocator: Cell::new(None),
         injected_panic_runtime: Cell::new(None),
         imported_macro_spans: RefCell::new(HashMap::new()),
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 83774f0cf7e..68c88249ec0 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -12,8 +12,7 @@
 
 use super::{SelectionContext, Obligation, ObligationCause};
 
-use middle::cstore::LOCAL_CRATE;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use ty::{self, Ty, TyCtxt};
 use infer::{InferCtxt, TypeOrigin};
 use syntax_pos::DUMMY_SP;
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b86a54f01cf..7ba10d9c0a5 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
 pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
 pub use self::select::{MethodMatchedData}; // intentionally don't export variants
 pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
-pub use self::specialize::{SpecializesCache};
+pub use self::specialize::{SpecializesCache, find_method};
 pub use self::util::elaborate_predicates;
 pub use self::util::supertraits;
 pub use self::util::Supertraits;
@@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     Ok(resolved_value)
 }
 
+/// Normalizes the predicates and checks whether they hold.  If this
+/// returns false, then either normalize encountered an error or one
+/// of the predicates did not hold. Used when creating vtables to
+/// check for unsatisfiable methods.
+pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               predicates: Vec<ty::Predicate<'tcx>>)
+                                               -> bool
+{
+    debug!("normalize_and_test_predicates(predicates={:?})",
+           predicates);
+
+    tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+        let mut selcx = SelectionContext::new(&infcx);
+        let mut fulfill_cx = FulfillmentContext::new();
+        let cause = ObligationCause::dummy();
+        let Normalized { value: predicates, obligations } =
+            normalize(&mut selcx, cause.clone(), &predicates);
+        for obligation in obligations {
+            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+        }
+        for predicate in predicates {
+            let obligation = Obligation::new(cause.clone(), predicate);
+            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+        }
+
+        fulfill_cx.select_all_or_error(&infcx).is_ok()
+    })
+}
+
+/// Given a trait `trait_ref`, iterates the vtable entries
+/// that come from `trait_ref`, including its supertraits.
+#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+pub fn get_vtable_methods<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>)
+    -> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
+{
+    debug!("get_vtable_methods({:?})", trait_ref);
+
+    supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+        tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
+
+        let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
+        let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
+            match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
+                ty::MethodTraitItem(m) => Some(m),
+                _ => None
+            }
+        });
+
+        // Now list each method's DefId and Substs (for within its trait).
+        // If the method can never be called from this object, produce None.
+        trait_methods.map(move |trait_method| {
+            debug!("get_vtable_methods: trait_method={:?}", trait_method);
+
+            // Some methods cannot be called on an object; skip those.
+            if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
+                debug!("get_vtable_methods: not vtable safe");
+                return None;
+            }
+
+            // the method may have some early-bound lifetimes, add
+            // regions for those
+            let substs = Substs::for_item(tcx, trait_method.def_id,
+                                            |_, _| tcx.mk_region(ty::ReErased),
+                                            |def, _| trait_ref.substs().type_for_def(def));
+
+            // It's possible that the method relies on where clauses that
+            // do not hold for this particular set of type parameters.
+            // Note that this method could then never be called, so we
+            // do not want to try and trans it, in that case (see #23435).
+            let predicates = trait_method.predicates.instantiate_own(tcx, substs);
+            if !normalize_and_test_predicates(tcx, predicates.predicates) {
+                debug!("get_vtable_methods: predicates do not hold");
+                return None;
+            }
+
+            Some((trait_method.def_id, substs))
+        })
+    })
+}
+
 impl<'tcx,O> Obligation<'tcx,O> {
     pub fn new(cause: ObligationCause<'tcx>,
                trait_ref: O)
@@ -571,7 +653,7 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 
     pub fn dummy() -> ObligationCause<'tcx> {
-        ObligationCause { span: DUMMY_SP, body_id: 0, code: MiscObligation }
+        ObligationCause { span: DUMMY_SP, body_id: ast::CRATE_NODE_ID, code: MiscObligation }
     }
 }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 94dba7d12a8..9d7131dc96c 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -814,7 +814,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
                              -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
         if let ImplCandidate(def_id) = candidate {
-            if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) {
+            if self.tcx().trait_impl_polarity(def_id) == hir::ImplPolarity::Negative {
                 return Err(Unimplemented)
             }
         }
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 2f63526bf6c..e37425901c8 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -26,9 +26,11 @@ use infer::{InferCtxt, TypeOrigin};
 use middle::region;
 use ty::subst::{Subst, Substs};
 use traits::{self, Reveal, ObligationCause, Normalized};
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, TypeFoldable};
 use syntax_pos::DUMMY_SP;
 
+use syntax::ast;
+
 pub mod specialization_graph;
 
 /// Information pertinent to an overlapping impl error.
@@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
 }
 
+/// Given a selected impl described by `impl_data`, returns the
+/// definition and substitions for the method with the name `name`,
+/// and trait method substitutions `substs`, in that impl, a less
+/// specialized impl, or the trait default, whichever applies.
+pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             name: ast::Name,
+                             substs: &'tcx Substs<'tcx>,
+                             impl_data: &super::VtableImplData<'tcx, ()>)
+                             -> (DefId, &'tcx Substs<'tcx>)
+{
+    assert!(!substs.needs_infer());
+
+    let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
+    let trait_def = tcx.lookup_trait_def(trait_def_id);
+
+    match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
+        Some(node_item) => {
+            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+                let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
+                let substs = translate_substs(&infcx, impl_data.impl_def_id,
+                                              substs, node_item.node);
+                tcx.lift(&substs).unwrap_or_else(|| {
+                    bug!("find_method: translate_substs \
+                          returned {:?} which contains inference types/regions",
+                         substs);
+                })
+            });
+            (node_item.item.def_id, substs)
+        }
+        None => {
+            bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
+        }
+    }
+}
+
 /// Is impl1 a specialization of impl2?
 ///
 /// Specialization is determined by the sets of types to which the impls apply;
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 13193e1b2d7..1374719ef49 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cell;
 use std::rc::Rc;
 
 use super::{OverlapError, specializes};
@@ -287,21 +286,10 @@ impl<'a, 'gcx, 'tcx> Node {
 
     /// Iterate over the items defined directly by the given (impl or trait) node.
     pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeItems<'a, 'gcx> {
-        match *self {
-            Node::Impl(impl_def_id) => {
-                NodeItems::Impl {
-                    tcx: tcx.global_tcx(),
-                    items: cell::Ref::map(tcx.impl_items.borrow(),
-                                          |impl_items| &impl_items[&impl_def_id]),
-                    idx: 0,
-                }
-            }
-            Node::Trait(trait_def_id) => {
-                NodeItems::Trait {
-                    items: tcx.trait_items(trait_def_id).clone(),
-                    idx: 0,
-                }
-            }
+        NodeItems {
+            tcx: tcx.global_tcx(),
+            items: tcx.impl_or_trait_items(self.def_id()),
+            idx: 0,
         }
     }
 
@@ -314,42 +302,23 @@ impl<'a, 'gcx, 'tcx> Node {
 }
 
 /// An iterator over the items defined within a trait or impl.
-pub enum NodeItems<'a, 'tcx: 'a> {
-    Impl {
-        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-        items: cell::Ref<'a, Vec<ty::ImplOrTraitItemId>>,
-        idx: usize,
-    },
-    Trait {
-        items: Rc<Vec<ImplOrTraitItem<'tcx>>>,
-        idx: usize,
-    },
+pub struct NodeItems<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    items: Rc<Vec<DefId>>,
+    idx: usize
 }
 
 impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> {
     type Item = ImplOrTraitItem<'tcx>;
     fn next(&mut self) -> Option<ImplOrTraitItem<'tcx>> {
-        match *self {
-            NodeItems::Impl { tcx, ref items, ref mut idx } => {
-                let items_table = tcx.impl_or_trait_items.borrow();
-                if *idx < items.len() {
-                    let item_def_id = items[*idx].def_id();
-                    let item = items_table[&item_def_id].clone();
-                    *idx += 1;
-                    Some(item)
-                } else {
-                    None
-                }
-            }
-            NodeItems::Trait { ref items, ref mut idx } => {
-                if *idx < items.len() {
-                    let item = items[*idx].clone();
-                    *idx += 1;
-                    Some(item)
-                } else {
-                    None
-                }
-            }
+        if self.idx < self.items.len() {
+            let item_def_id = self.items[self.idx];
+            let items_table = self.tcx.impl_or_trait_items.borrow();
+            let item = items_table[&item_def_id].clone();
+            self.idx += 1;
+            Some(item)
+        } else {
+            None
         }
     }
 }
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 3386d894196..cfe370343ae 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -19,7 +19,7 @@ use syntax_pos::Span;
 
 use hir;
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum AutoAdjustment<'tcx> {
     AdjustNeverToAny(Ty<'tcx>), // go from ! to any type
     AdjustReifyFnPointer,       // go from a fn-item type to a fn-pointer type
@@ -90,7 +90,7 @@ pub enum AutoAdjustment<'tcx> {
 ///     unsize: Some(Box<[i32]>),
 /// }
 /// ```
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub struct AutoDerefRef<'tcx> {
     /// Step 1. Apply a number of dereferences, producing an lvalue.
     pub autoderefs: usize,
@@ -122,7 +122,7 @@ impl<'tcx> AutoDerefRef<'tcx> {
 }
 
 
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum AutoRef<'tcx> {
     /// Convert from T to &T.
     AutoPtr(&'tcx ty::Region, hir::Mutability),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6d7a2d6cba1..d5e5f4402bb 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -13,10 +13,9 @@
 use dep_graph::{DepGraph, DepTrackingMap};
 use session::Session;
 use middle;
-use middle::cstore::LOCAL_CRATE;
 use hir::TraitMap;
 use hir::def::DefMap;
-use hir::def_id::{DefId, DefIndex};
+use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use hir::map as ast_map;
 use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
 use middle::free_region::FreeRegionMap;
@@ -26,7 +25,7 @@ use middle::stability;
 use ty::subst::Substs;
 use traits;
 use ty::{self, TraitRef, Ty, TypeAndMut};
-use ty::{TyS, TypeVariants};
+use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
 use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject};
@@ -93,7 +92,7 @@ pub struct CtxtInterners<'tcx> {
     /// Specifically use a speedy hash algorithm for these hash sets,
     /// they're accessed quite often.
     type_: RefCell<FnvHashSet<Interned<'tcx, TyS<'tcx>>>>,
-    type_list: RefCell<FnvHashSet<Interned<'tcx, [Ty<'tcx>]>>>,
+    type_list: RefCell<FnvHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
     substs: RefCell<FnvHashSet<Interned<'tcx, Substs<'tcx>>>>,
     bare_fn: RefCell<FnvHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
     region: RefCell<FnvHashSet<Interned<'tcx, Region>>>,
@@ -331,8 +330,8 @@ pub struct GlobalCtxt<'tcx> {
     /// Maps from a trait item to the trait item "descriptor"
     pub impl_or_trait_items: RefCell<DepTrackingMap<maps::ImplOrTraitItems<'tcx>>>,
 
-    /// Maps from a trait def-id to a list of the def-ids of its trait items
-    pub trait_item_def_ids: RefCell<DepTrackingMap<maps::TraitItemDefIds<'tcx>>>,
+    /// Maps from an impl/trait def-id to a list of the def-ids of its items
+    pub impl_or_trait_item_def_ids: RefCell<DepTrackingMap<maps::ImplOrTraitItemDefIds<'tcx>>>,
 
     /// A cache for the trait_items() routine; note that the routine
     /// itself pushes the `TraitItems` dependency node.
@@ -393,12 +392,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Methods in these implementations don't need to be exported.
     pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
 
-    /// Maps a DefId of an impl to a list of its items.
-    /// Note that this contains all of the impls that we know about,
-    /// including ones in other crates. It's not clear that this is the best
-    /// way to do it.
-    pub impl_items: RefCell<DepTrackingMap<maps::ImplItems<'tcx>>>,
-
     /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     /// present in this set can be warned about.
     pub used_unsafe: RefCell<NodeSet>,
@@ -512,7 +505,7 @@ impl<'tcx> GlobalCtxt<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn crate_name(self, cnum: ast::CrateNum) -> token::InternedString {
+    pub fn crate_name(self, cnum: CrateNum) -> token::InternedString {
         if cnum == LOCAL_CRATE {
             self.crate_name.clone()
         } else {
@@ -520,7 +513,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString {
+    pub fn original_crate_name(self, cnum: CrateNum) -> token::InternedString {
+        if cnum == LOCAL_CRATE {
+            self.crate_name.clone()
+        } else {
+            self.sess.cstore.original_crate_name(cnum)
+        }
+    }
+
+    pub fn crate_disambiguator(self, cnum: CrateNum) -> token::InternedString {
         if cnum == LOCAL_CRATE {
             self.sess.local_crate_disambiguator()
         } else {
@@ -533,7 +534,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// relative to `krate`.
     ///
     /// Returns `None` if there is no `DefIndex` with that key.
-    pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey)
+    pub fn def_index_for_def_key(self, krate: CrateNum, key: DefKey)
                                  -> Option<DefIndex> {
         if krate == LOCAL_CRATE {
             self.map.def_index_for_def_key(key)
@@ -735,13 +736,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             rcache: RefCell::new(FnvHashMap()),
             tc_cache: RefCell::new(FnvHashMap()),
             impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            impl_or_trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FnvHashMap()),
             lang_items: lang_items,
             inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             used_unsafe: RefCell::new(NodeSet()),
             used_mut_nodes: RefCell::new(NodeSet()),
             used_trait_imports: RefCell::new(NodeSet()),
@@ -848,10 +848,11 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Region {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] {
-    type Lifted = &'tcx [Ty<'tcx>];
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx [Ty<'tcx>]> {
-        if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(*self) {
+impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
+    type Lifted = &'tcx Slice<Ty<'tcx>>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+                             -> Option<&'tcx Slice<Ty<'tcx>>> {
+        if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(&self[..]) {
             if *self as *const _ == list as *const _ {
                 return Some(list);
             }
@@ -1068,9 +1069,24 @@ impl<'tcx: 'lcx, 'lcx> Borrow<TypeVariants<'lcx>> for Interned<'tcx, TyS<'tcx>>
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, [Ty<'tcx>]> {
+// NB: An Interned<Slice<T>> compares and hashes as its elements.
+impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, Slice<T>> {
+    fn eq(&self, other: &Interned<'tcx, Slice<T>>) -> bool {
+        self.0[..] == other.0[..]
+    }
+}
+
+impl<'tcx, T: Eq> Eq for Interned<'tcx, Slice<T>> {}
+
+impl<'tcx, T: Hash> Hash for Interned<'tcx, Slice<T>> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        self.0[..].hash(s)
+    }
+}
+
+impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice<Ty<'tcx>>> {
     fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] {
-        self.0
+        &self.0[..]
     }
 }
 
@@ -1092,32 +1108,23 @@ impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
     }
 }
 
-macro_rules! items { ($($item:item)+) => ($($item)+) }
-macro_rules! impl_interners {
-    ($lt_tcx:tt, $($name:ident: $method:ident($alloc:ty, $needs_infer:expr)-> $ty:ty),+) => {
-        items!($(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> {
-            fn eq(&self, other: &Self) -> bool {
-                self.0 == other.0
-            }
-        }
-
-        impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {}
-
-        impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> {
-            fn hash<H: Hasher>(&self, s: &mut H) {
-                self.0.hash(s)
-            }
-        }
-
+macro_rules! intern_method {
+    ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
+                                            $alloc_to_key:expr,
+                                            $alloc_to_ret:expr,
+                                            $needs_infer:expr) -> $ty:ty) => {
         impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
             pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
-                if let Some(i) = self.interners.$name.borrow().get::<$ty>(&v) {
-                    return i.0;
-                }
-                if !self.is_global() {
-                    if let Some(i) = self.global_interners.$name.borrow().get::<$ty>(&v) {
+                {
+                    let key = ($alloc_to_key)(&v);
+                    if let Some(i) = self.interners.$name.borrow().get(key) {
                         return i.0;
                     }
+                    if !self.is_global() {
+                        if let Some(i) = self.global_interners.$name.borrow().get(key) {
+                            return i.0;
+                        }
+                    }
                 }
 
                 // HACK(eddyb) Depend on flags being accurate to
@@ -1128,7 +1135,7 @@ macro_rules! impl_interners {
                         let v = unsafe {
                             mem::transmute(v)
                         };
-                        let i = self.global_interners.arenas.$name.alloc(v);
+                        let i = ($alloc_to_ret)(self.global_interners.arenas.$name.alloc(v));
                         self.global_interners.$name.borrow_mut().insert(Interned(i));
                         return i;
                     }
@@ -1142,11 +1149,31 @@ macro_rules! impl_interners {
                     }
                 }
 
-                let i = self.interners.arenas.$name.alloc(v);
+                let i = ($alloc_to_ret)(self.interners.arenas.$name.alloc(v));
                 self.interners.$name.borrow_mut().insert(Interned(i));
                 i
             }
-        })+);
+        }
+    }
+}
+
+macro_rules! direct_interners {
+    ($lt_tcx:tt, $($name:ident: $method:ident($needs_infer:expr) -> $ty:ty),+) => {
+        $(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> {
+            fn eq(&self, other: &Self) -> bool {
+                self.0 == other.0
+            }
+        }
+
+        impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {}
+
+        impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> {
+            fn hash<H: Hasher>(&self, s: &mut H) {
+                self.0.hash(s)
+            }
+        }
+
+        intern_method!($lt_tcx, $name: $method($ty, |x| x, |x| x, $needs_infer) -> $ty);)+
     }
 }
 
@@ -1154,15 +1181,14 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
     x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX)
 }
 
-impl_interners!('tcx,
-    type_list: mk_type_list(Vec<Ty<'tcx>>, keep_local) -> [Ty<'tcx>],
-    substs: mk_substs(Substs<'tcx>, |substs: &Substs| {
+direct_interners!('tcx,
+    substs: mk_substs(|substs: &Substs| {
         substs.params().iter().any(keep_local)
     }) -> Substs<'tcx>,
-    bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| {
+    bare_fn: mk_bare_fn(|fty: &BareFnTy| {
         keep_local(&fty.sig)
     }) -> BareFnTy<'tcx>,
-    region: mk_region(Region, |r| {
+    region: mk_region(|r| {
         match r {
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
             _ => false
@@ -1170,6 +1196,12 @@ impl_interners!('tcx,
     }) -> Region
 );
 
+intern_method!('tcx,
+    type_list: mk_type_list(Vec<Ty<'tcx>>, Deref::deref, |xs: &[Ty]| -> &Slice<Ty> {
+        unsafe { mem::transmute(xs) }
+    }, keep_local) -> Slice<Ty<'tcx>>
+);
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
     pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
@@ -1370,9 +1402,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn trait_items(self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'gcx>>> {
         self.trait_items_cache.memoize(trait_did, || {
-            let def_ids = self.trait_item_def_ids(trait_did);
+            let def_ids = self.impl_or_trait_items(trait_did);
             Rc::new(def_ids.iter()
-                           .map(|d| self.impl_or_trait_item(d.def_id()))
+                           .map(|&def_id| self.impl_or_trait_item(def_id))
                            .collect())
         })
     }
@@ -1380,13 +1412,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Obtain the representation annotation for a struct definition.
     pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
         self.repr_hint_cache.memoize(did, || {
-            Rc::new(if did.is_local() {
-                self.get_attrs(did).iter().flat_map(|meta| {
-                    attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
-                }).collect()
-            } else {
-                self.sess.cstore.repr_attrs(did)
-            })
+            Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
+                attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
+            }).collect())
         })
     }
 }
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index b6b55fc0e33..fdf5185eb69 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use hir::map::DefPathData;
-use middle::cstore::LOCAL_CRATE;
-use hir::def_id::{DefId, CRATE_DEF_INDEX};
+use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use ty::{self, Ty, TyCtxt};
 use syntax::ast;
 use syntax::parse::token;
@@ -67,7 +66,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns the "path" to a particular crate. This can proceed in
     /// various ways, depending on the `root_mode` of the `buffer`.
     /// (See `RootMode` enum for more details.)
-    pub fn push_krate_path<T>(self, buffer: &mut T, cnum: ast::CrateNum)
+    pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
         where T: ItemPathBuffer
     {
         match *buffer.root_mode() {
@@ -102,11 +101,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             RootMode::Absolute => {
                 // In absolute mode, just write the crate name
                 // unconditionally.
-                if cnum == LOCAL_CRATE {
-                    buffer.push(&self.crate_name(cnum));
-                } else {
-                    buffer.push(&self.sess.cstore.original_crate_name(cnum));
-                }
+                buffer.push(&self.original_crate_name(cnum));
             }
         }
     }
@@ -139,7 +134,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            cur_path.push(self.sess.cstore.opt_item_name(cur_def).unwrap_or_else(||
+            cur_path.push(self.sess.cstore.def_key(cur_def)
+                              .disambiguated_data.data.get_opt_name().unwrap_or_else(||
                 token::intern("<unnamed>")));
             match visible_parent_map.get(&cur_def) {
                 Some(&def) => cur_def = def,
@@ -304,7 +300,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns the def-id of `def_id`'s parent in the def tree. If
     /// this returns `None`, then `def_id` represents a crate root or
     /// inlined root.
-    fn parent_def_id(&self, def_id: DefId) -> Option<DefId> {
+    pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
         let key = self.def_key(def_id);
         key.parent.map(|index| DefId { krate: def_id.krate, index: index })
     }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 6fec698cfac..5e7a2bc0266 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -367,7 +367,7 @@ impl Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    pub fn repr_discr(tcx: TyCtxt, hint: attr::ReprAttr, min: i64, max: i64)
+    pub fn repr_discr(tcx: TyCtxt, ty: Ty, hint: attr::ReprAttr, min: i64, max: i64)
                       -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
@@ -377,11 +377,12 @@ impl Integer {
         let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
 
         let at_least = match hint {
-            attr::ReprInt(span, ity) => {
+            attr::ReprInt(ity) => {
                 let discr = Integer::from_attr(&tcx.data_layout, ity);
                 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
                 if discr < fit {
-                    span_bug!(span, "representation hint insufficient for discriminant range")
+                    bug!("Integer::repr_discr: `#[repr]` hint too small for \
+                          discriminant range of enum `{}", ty)
                 }
                 return (discr, ity.is_signed());
             }
@@ -397,10 +398,10 @@ impl Integer {
             }
             attr::ReprAny => I8,
             attr::ReprPacked => {
-                bug!("Integer::repr_discr: found #[repr(packed)] on an enum");
+                bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty);
             }
             attr::ReprSimd => {
-                bug!("Integer::repr_discr: found #[repr(simd)] on an enum");
+                bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty);
             }
         };
 
@@ -962,7 +963,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         if x > max { max = x; }
                     }
 
-                    let (discr, signed) = Integer::repr_discr(tcx, hint, min, max);
+                    let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max);
                     return success(CEnum {
                         discr: discr,
                         signed: signed,
@@ -1052,7 +1053,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 // The general case.
                 let discr_max = (variants.len() - 1) as i64;
                 assert!(discr_max >= 0);
-                let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max);
+                let (min_ity, _) = Integer::repr_discr(tcx, ty, hint, 0, discr_max);
 
                 let mut align = dl.aggregate_align;
                 let mut size = Size::from_bytes(0);
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 5772d16c6d4..3a552a8b437 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -34,13 +34,12 @@ dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> }
 dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> }
 dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
 dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc<Vec<ty::ImplOrTraitItemId>> }
+dep_map_ty! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc<Vec<DefId>> }
 dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
 dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> }
 dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> }
 dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
 dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
-dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
 dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> }
 dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
 dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 14eb2fb7914..9eb87fa2ed4 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::ImplOrTraitItemId::*;
 pub use self::Variance::*;
 pub use self::DtorKind::*;
 pub use self::ImplOrTraitItemContainer::*;
@@ -21,9 +20,8 @@ pub use self::fold::TypeFoldable;
 use dep_graph::{self, DepNode};
 use hir::map as ast_map;
 use middle;
-use middle::cstore::{self, LOCAL_CRATE};
 use hir::def::{Def, PathResolution, ExportMap};
-use hir::def_id::DefId;
+use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
 use traits;
@@ -34,23 +32,23 @@ use util::common::MemoizationMap;
 use util::nodemap::NodeSet;
 use util::nodemap::FnvHashMap;
 
-use serialize::{Encodable, Encoder, Decodable, Decoder};
+use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::hash::{Hash, Hasher};
 use std::iter;
+use std::ops::Deref;
 use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
-use syntax::ast::{self, CrateNum, Name, NodeId};
+use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
-use syntax::parse::token::InternedString;
+use syntax::parse::token::{self, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
 
 use rustc_const_math::ConstInt;
 
 use hir;
-use hir::{ItemImpl, ItemTrait, PatKind};
 use hir::intravisit::Visitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
@@ -191,23 +189,11 @@ pub enum ImplOrTraitItem<'tcx> {
 }
 
 impl<'tcx> ImplOrTraitItem<'tcx> {
-    fn id(&self) -> ImplOrTraitItemId {
-        match *self {
-            ConstTraitItem(ref associated_const) => {
-                ConstTraitItemId(associated_const.def_id)
-            }
-            MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
-            TypeTraitItem(ref associated_type) => {
-                TypeTraitItemId(associated_type.def_id)
-            }
-        }
-    }
-
     pub fn def(&self) -> Def {
         match *self {
             ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id),
             MethodTraitItem(ref method) => Def::Method(method.def_id),
-            TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id),
+            TypeTraitItem(ref ty) => Def::AssociatedTy(ty.def_id),
         }
     }
 
@@ -251,24 +237,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, Debug)]
-pub enum ImplOrTraitItemId {
-    ConstTraitItemId(DefId),
-    MethodTraitItemId(DefId),
-    TypeTraitItemId(DefId),
-}
-
-impl ImplOrTraitItemId {
-    pub fn def_id(&self) -> DefId {
-        match *self {
-            ConstTraitItemId(def_id) => def_id,
-            MethodTraitItemId(def_id) => def_id,
-            TypeTraitItemId(def_id) => def_id,
-        }
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Copy)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
 pub enum Visibility {
     /// Visible everywhere (including in other crates).
     Public,
@@ -346,34 +315,12 @@ pub struct Method<'tcx> {
     pub explicit_self: ExplicitSelfCategory<'tcx>,
     pub vis: Visibility,
     pub defaultness: hir::Defaultness,
+    pub has_body: bool,
     pub def_id: DefId,
     pub container: ImplOrTraitItemContainer,
 }
 
 impl<'tcx> Method<'tcx> {
-    pub fn new(name: Name,
-               generics: &'tcx ty::Generics<'tcx>,
-               predicates: GenericPredicates<'tcx>,
-               fty: &'tcx BareFnTy<'tcx>,
-               explicit_self: ExplicitSelfCategory<'tcx>,
-               vis: Visibility,
-               defaultness: hir::Defaultness,
-               def_id: DefId,
-               container: ImplOrTraitItemContainer)
-               -> Method<'tcx> {
-        Method {
-            name: name,
-            generics: generics,
-            predicates: predicates,
-            fty: fty,
-            explicit_self: explicit_self,
-            vis: vis,
-            defaultness: defaultness,
-            def_id: def_id,
-            container: container,
-        }
-    }
-
     pub fn container_id(&self) -> DefId {
         match self.container {
             TraitContainer(id) => id,
@@ -425,7 +372,7 @@ pub enum Variance {
     Bivariant,      // T<A> <: T<B>            -- e.g., unused type parameter
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
 pub struct MethodCallee<'tcx> {
     /// Impl method ID, for inherent methods, or trait method ID, otherwise.
     pub def_id: DefId,
@@ -567,23 +514,47 @@ impl<'tcx> Hash for TyS<'tcx> {
 
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-impl<'tcx> Encodable for Ty<'tcx> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
-            ecx.encode_ty(rbml_w, *self);
-            Ok(())
-        })
+impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}
+
+/// A wrapper for slices with the additioanl invariant
+/// that the slice is interned and no other slice with
+/// the same contents can exist in the same context.
+/// This means we can use pointer + length for both
+/// equality comparisons and hashing.
+#[derive(Debug, RustcEncodable)]
+pub struct Slice<T>([T]);
+
+impl<T> PartialEq for Slice<T> {
+    #[inline]
+    fn eq(&self, other: &Slice<T>) -> bool {
+        (&self.0 as *const [T]) == (&other.0 as *const [T])
     }
 }
+impl<T> Eq for Slice<T> {}
 
-impl<'tcx> Decodable for Ty<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Ty<'tcx>, D::Error> {
-        cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
-            Ok(dcx.decode_ty(rbml_r))
-        })
+impl<T> Hash for Slice<T> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        (self.as_ptr(), self.len()).hash(s)
     }
 }
 
+impl<T> Deref for Slice<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] {
+        &self.0
+    }
+}
+
+impl<'a, T> IntoIterator for &'a Slice<T> {
+    type Item = &'a T;
+    type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
+    fn into_iter(self) -> Self::IntoIter {
+        self[..].iter()
+    }
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice<Ty<'tcx>> {}
 
 /// Upvars do not get their own node-id. Instead, we use the pair of
 /// the original var id (that is, the root variable that is referenced
@@ -642,7 +613,7 @@ pub enum BorrowKind {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy)]
+#[derive(PartialEq, Clone, Debug, Copy, RustcEncodable, RustcDecodable)]
 pub enum UpvarCapture<'tcx> {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
@@ -653,7 +624,7 @@ pub enum UpvarCapture<'tcx> {
     ByRef(UpvarBorrow<'tcx>),
 }
 
-#[derive(PartialEq, Clone, Copy)]
+#[derive(PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)]
 pub struct UpvarBorrow<'tcx> {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
@@ -684,7 +655,7 @@ pub enum IntVarValue {
 /// from `T:'a` annotations appearing in the type definition.  If
 /// this is `None`, then the default is inherited from the
 /// surrounding context. See RFC #599 for details.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum ObjectLifetimeDefault<'tcx> {
     /// Require an explicit annotation. Occurs when multiple
     /// `T:'a` constraints are found.
@@ -697,7 +668,7 @@ pub enum ObjectLifetimeDefault<'tcx> {
     Specific(&'tcx Region),
 }
 
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct TypeParameterDef<'tcx> {
     pub name: Name,
     pub def_id: DefId,
@@ -707,7 +678,7 @@ pub struct TypeParameterDef<'tcx> {
     pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
 }
 
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct RegionParameterDef<'tcx> {
     pub name: Name,
     pub def_id: DefId,
@@ -735,7 +706,7 @@ impl<'tcx> RegionParameterDef<'tcx> {
 
 /// Information about the formal type/lifetime parameters associated
 /// with an item or method. Analogous to hir::Generics.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Generics<'tcx> {
     pub parent: Option<DefId>,
     pub parent_regions: u32,
@@ -766,6 +737,9 @@ pub struct GenericPredicates<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
+impl<'tcx> serialize::UseSpecializedEncodable for GenericPredicates<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for GenericPredicates<'tcx> {}
+
 impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
     pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>)
                        -> InstantiatedPredicates<'tcx> {
@@ -802,7 +776,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum Predicate<'tcx> {
     /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
@@ -926,7 +900,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>
 }
@@ -983,11 +957,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1`
 pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>;
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
 pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
 pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region,
@@ -1006,7 +980,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, &'tcx
 /// equality between arbitrary types. Processing an instance of Form
 /// #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
     pub ty: Ty<'tcx>,
@@ -1496,23 +1470,13 @@ impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> {
     }
 }
 
-impl<'tcx> Encodable for AdtDef<'tcx> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl<'tcx> serialize::UseSpecializedEncodable for AdtDef<'tcx> {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         self.did.encode(s)
     }
 }
 
-impl<'tcx> Decodable for AdtDef<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<AdtDef<'tcx>, D::Error> {
-        let def_id: DefId = Decodable::decode(d)?;
-
-        cstore::tls::with_decoding_context(d, |dcx, _| {
-            let def_id = dcx.translate_def_id(def_id);
-            Ok(dcx.tcx().lookup_adt_def(def_id))
-        })
-    }
-}
-
+impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {}
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
@@ -1705,7 +1669,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
 
     pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> {
         match def {
-            Def::Variant(_, vid) => self.variant_with_id(vid),
+            Def::Variant(vid) => self.variant_with_id(vid),
             Def::Struct(..) | Def::Union(..) |
             Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
             _ => bug!("unexpected def {:?} in variant_of_def", def)
@@ -1965,7 +1929,7 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> {
 
 /// Records the substitutions used to translate the polytype for an
 /// item into the monotype of an item reference.
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct ItemSubsts<'tcx> {
     pub substs: &'tcx Substs<'tcx>,
 }
@@ -2222,7 +2186,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         match self.map.find(id) {
             Some(ast_map::NodeLocal(pat)) => {
                 match pat.node {
-                    PatKind::Binding(_, ref path1, _) => path1.node.as_str(),
+                    hir::PatKind::Binding(_, ref path1, _) => path1.node.as_str(),
                     _ => {
                         bug!("Variable id {} maps to {:?}, not local", id, pat);
                     },
@@ -2285,84 +2249,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn provided_trait_methods(self, id: DefId) -> Vec<Rc<Method<'gcx>>> {
-        if let Some(id) = self.map.as_local_node_id(id) {
-            if let ItemTrait(.., ref ms) = self.map.expect_item(id).node {
-                ms.iter().filter_map(|ti| {
-                    if let hir::MethodTraitItem(_, Some(_)) = ti.node {
-                        match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
-                            MethodTraitItem(m) => Some(m),
-                            _ => {
-                                bug!("provided_trait_methods(): \
-                                      non-method item found from \
-                                      looking up provided method?!")
-                            }
-                        }
-                    } else {
-                        None
-                    }
-                }).collect()
-            } else {
-                bug!("provided_trait_methods: `{:?}` is not a trait", id)
+        self.impl_or_trait_items(id).iter().filter_map(|&def_id| {
+            match self.impl_or_trait_item(def_id) {
+                MethodTraitItem(ref m) if m.has_body => Some(m.clone()),
+                _ => None
             }
-        } else {
-            self.sess.cstore.provided_trait_methods(self.global_tcx(), id)
-        }
+        }).collect()
     }
 
-    pub fn associated_consts(self, id: DefId) -> Vec<Rc<AssociatedConst<'gcx>>> {
+    pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity {
         if let Some(id) = self.map.as_local_node_id(id) {
             match self.map.expect_item(id).node {
-                ItemTrait(.., ref tis) => {
-                    tis.iter().filter_map(|ti| {
-                        if let hir::ConstTraitItem(..) = ti.node {
-                            match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
-                                ConstTraitItem(ac) => Some(ac),
-                                _ => {
-                                    bug!("associated_consts(): \
-                                          non-const item found from \
-                                          looking up a constant?!")
-                                }
-                            }
-                        } else {
-                            None
-                        }
-                    }).collect()
-                }
-                ItemImpl(.., ref iis) => {
-                    iis.iter().filter_map(|ii| {
-                        if let hir::ImplItemKind::Const(..) = ii.node {
-                            match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
-                                ConstTraitItem(ac) => Some(ac),
-                                _ => {
-                                    bug!("associated_consts(): \
-                                          non-const item found from \
-                                          looking up a constant?!")
-                                }
-                            }
-                        } else {
-                            None
-                        }
-                    }).collect()
-                }
-                _ => {
-                    bug!("associated_consts: `{:?}` is not a trait or impl", id)
-                }
-            }
-        } else {
-            self.sess.cstore.associated_consts(self.global_tcx(), id)
-        }
-    }
-
-    pub fn trait_impl_polarity(self, id: DefId) -> Option<hir::ImplPolarity> {
-        if let Some(id) = self.map.as_local_node_id(id) {
-            match self.map.find(id) {
-                Some(ast_map::NodeItem(item)) => {
-                    match item.node {
-                        hir::ItemImpl(_, polarity, ..) => Some(polarity),
-                        _ => None
-                    }
-                }
-                _ => None
+                hir::ItemImpl(_, polarity, ..) => polarity,
+                ref item => bug!("trait_impl_polarity: {:?} not an impl", item)
             }
         } else {
             self.sess.cstore.impl_polarity(id)
@@ -2395,10 +2294,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                    .expect("missing ImplOrTraitItem in metadata"))
     }
 
-    pub fn trait_item_def_ids(self, id: DefId) -> Rc<Vec<ImplOrTraitItemId>> {
+    pub fn impl_or_trait_items(self, id: DefId) -> Rc<Vec<DefId>> {
         lookup_locally_or_in_crate_store(
-            "trait_item_def_ids", id, &self.trait_item_def_ids,
-            || Rc::new(self.sess.cstore.trait_item_def_ids(id)))
+            "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids,
+            || Rc::new(self.sess.cstore.impl_or_trait_items(id)))
     }
 
     /// Returns the trait-ref corresponding to a given impl, or None if it is
@@ -2409,20 +2308,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             || self.sess.cstore.impl_trait_ref(self.global_tcx(), id))
     }
 
-    /// Returns whether this DefId refers to an impl
-    pub fn is_impl(self, id: DefId) -> bool {
-        if let Some(id) = self.map.as_local_node_id(id) {
-            if let Some(ast_map::NodeItem(
-                &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) {
-                true
-            } else {
-                false
-            }
-        } else {
-            self.sess.cstore.is_impl(id)
-        }
-    }
-
     /// Returns a path resolution for node id if it exists, panics otherwise.
     pub fn expect_resolution(self, id: NodeId) -> PathResolution {
         *self.def_map.borrow().get(&id).expect("no def-map entry for node id")
@@ -2443,7 +2328,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // or variant or their constructors, panics otherwise.
     pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> {
         match def {
-            Def::Variant(enum_did, did) => {
+            Def::Variant(did) => {
+                let enum_did = self.parent_def_id(did).unwrap();
                 self.lookup_adt_def(enum_did).variant_with_id(did)
             }
             Def::Struct(did) | Def::Union(did) => {
@@ -2504,8 +2390,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn item_name(self, id: DefId) -> ast::Name {
         if let Some(id) = self.map.as_local_node_id(id) {
             self.map.name(id)
+        } else if id.index == CRATE_DEF_INDEX {
+            token::intern(&self.sess.cstore.original_crate_name(id.krate))
         } else {
-            self.sess.cstore.item_name(id)
+            let def_key = self.sess.cstore.def_key(id);
+            // The name of a StructCtor is that of its struct parent.
+            if let ast_map::DefPathData::StructCtor = def_key.disambiguated_data.data {
+                self.item_name(DefId {
+                    krate: id.krate,
+                    index: def_key.parent.unwrap()
+                })
+            } else {
+                def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
+                    bug!("item_name: no name for {:?}", self.def_path(id));
+                })
+            }
         }
     }
 
@@ -2572,7 +2471,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> {
         lookup_locally_or_in_crate_store(
             "generics", did, &self.generics,
-            || self.sess.cstore.item_generics(self.global_tcx(), did))
+            || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did)))
     }
 
     /// Given the did of an item, returns its full set of predicates.
@@ -2685,10 +2584,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}",
                primitive_def_id);
 
-        let impl_items = self.sess.cstore.impl_items(primitive_def_id);
+        let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id);
 
         // Store the implementation info.
-        self.impl_items.borrow_mut().insert(primitive_def_id, impl_items);
+        self.impl_or_trait_item_def_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items));
         self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id);
     }
 
@@ -2714,8 +2613,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
         for &impl_def_id in &inherent_impls {
             // Store the implementation info.
-            let impl_items = self.sess.cstore.impl_items(impl_def_id);
-            self.impl_items.borrow_mut().insert(impl_def_id, impl_items);
+            let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id);
+            self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items));
         }
 
         self.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
@@ -2744,28 +2643,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             self.record_trait_has_default_impl(trait_id);
         }
 
-        for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) {
-            let impl_items = self.sess.cstore.impl_items(impl_def_id);
+        for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
+            let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id);
             let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
 
             // Record the trait->implementation mapping.
-            if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) {
-                def.record_remote_impl(self, impl_def_id, trait_ref, parent);
-            } else {
-                def.record_remote_impl(self, impl_def_id, trait_ref, trait_id);
-            }
+            let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id);
+            def.record_remote_impl(self, impl_def_id, trait_ref, parent);
 
             // For any methods that use a default implementation, add them to
             // the map. This is a bit unfortunate.
-            for impl_item_def_id in &impl_items {
-                let method_def_id = impl_item_def_id.def_id();
+            for &impl_item_def_id in &impl_items {
                 // load impl items eagerly for convenience
                 // FIXME: we may want to load these lazily
-                self.impl_or_trait_item(method_def_id);
+                self.impl_or_trait_item(impl_item_def_id);
             }
 
             // Store the implementation info.
-            self.impl_items.borrow_mut().insert(impl_def_id, impl_items);
+            self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items));
         }
 
         def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
@@ -2854,19 +2749,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// is already that of the original trait method, then the return value is
     /// the same).
     /// Otherwise, return `None`.
-    pub fn trait_item_of_item(self, def_id: DefId) -> Option<ImplOrTraitItemId> {
+    pub fn trait_item_of_item(self, def_id: DefId) -> Option<DefId> {
         let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) {
             Some(m) => m.clone(),
             None => return None,
         };
         match impl_or_trait_item.container() {
-            TraitContainer(_) => Some(impl_or_trait_item.id()),
+            TraitContainer(_) => Some(impl_or_trait_item.def_id()),
             ImplContainer(def_id) => {
                 self.trait_id_of_impl(def_id).and_then(|trait_did| {
                     let name = impl_or_trait_item.name();
                     self.trait_items(trait_did).iter()
                         .find(|item| item.name() == name)
-                        .map(|item| item.id())
+                        .map(|item| item.def_id())
                 })
             }
         }
@@ -2998,7 +2893,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 /// The category of explicit self.
-#[derive(Clone, Copy, Eq, PartialEq, Debug)]
+#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum ExplicitSelfCategory<'tcx> {
     Static,
     ByValue,
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 6c3dabfe113..5a87ea1473d 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -14,7 +14,6 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use std::rc::Rc;
 use syntax::abi;
-use syntax::ptr::P;
 
 use hir;
 
@@ -437,16 +436,6 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
     }
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|t| t.fold_with(folder)).collect()
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::TraitObject {
@@ -464,7 +453,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx [Ty<'tcx>] {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         let tys = self.iter().map(|t| t.fold_with(folder)).collect();
         folder.tcx().mk_type_list(tys)
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 5fdc7abc0af..302cab0446c 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -10,29 +10,28 @@
 
 //! This module contains TypeVariants and its major components
 
-use middle::cstore;
 use hir::def_id::DefId;
 use middle::region;
 use ty::subst::Substs;
-use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TyS, TypeFoldable};
+use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable};
+use ty::{Slice, TyS};
 use util::common::ErrorReported;
 
 use collections::enum_set::{self, EnumSet, CLike};
 use std::fmt;
-use std::mem;
 use std::ops;
 use syntax::abi;
 use syntax::ast::{self, Name};
 use syntax::parse::token::{keywords, InternedString};
 
-use serialize::{Decodable, Decoder, Encodable, Encoder};
+use serialize;
 
 use hir;
 
 use self::InferTy::*;
 use self::TypeVariants::*;
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct TypeAndMut<'tcx> {
     pub ty: Ty<'tcx>,
     pub mutbl: hir::Mutability,
@@ -88,7 +87,7 @@ pub enum Issue32330 {
 
 // NB: If you change this, you'll probably want to change the corresponding
 // AST structure in libsyntax/ast.rs as well.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum TypeVariants<'tcx> {
     /// The primitive boolean type. Written as `bool`.
     TyBool,
@@ -156,7 +155,7 @@ pub enum TypeVariants<'tcx> {
     TyNever,
 
     /// A tuple type.  For example, `(i32, bool)`.
-    TyTuple(&'tcx [Ty<'tcx>]),
+    TyTuple(&'tcx Slice<Ty<'tcx>>),
 
     /// The projection of an associated type.  For example,
     /// `<T as Trait<..>>::N`.
@@ -253,7 +252,7 @@ pub enum TypeVariants<'tcx> {
 /// closure C wind up influencing the decisions we ought to make for
 /// closure C (which would then require fixed point iteration to
 /// handle). Plus it fixes an ICE. :P
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function.
     /// These are separated out because trans wants to pass them around
@@ -263,28 +262,10 @@ pub struct ClosureSubsts<'tcx> {
     /// The types of the upvars. The list parallels the freevars and
     /// `upvar_borrows` lists. These are kept distinct so that we can
     /// easily index into them.
-    pub upvar_tys: &'tcx [Ty<'tcx>]
+    pub upvar_tys: &'tcx Slice<Ty<'tcx>>
 }
 
-impl<'tcx> Encodable for ClosureSubsts<'tcx> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        (self.func_substs, self.upvar_tys).encode(s)
-    }
-}
-
-impl<'tcx> Decodable for ClosureSubsts<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<ClosureSubsts<'tcx>, D::Error> {
-        let (func_substs, upvar_tys) = Decodable::decode(d)?;
-        cstore::tls::with_decoding_context(d, |dcx, _| {
-            Ok(ClosureSubsts {
-                func_substs: func_substs,
-                upvar_tys: dcx.tcx().mk_type_list(upvar_tys)
-            })
-        })
-    }
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TraitObject<'tcx> {
     pub principal: PolyExistentialTraitRef<'tcx>,
     pub region_bound: &'tcx ty::Region,
@@ -307,7 +288,7 @@ pub struct TraitObject<'tcx> {
 /// Note that a `TraitRef` introduces a level of region binding, to
 /// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
 /// U>` or higher-ranked object types.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: &'tcx Substs<'tcx>,
@@ -347,7 +328,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
 ///
 /// The substitutions don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct ExistentialTraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: &'tcx Substs<'tcx>,
@@ -383,7 +364,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
 /// erase, or otherwise "discharge" these bound regions, we change the
 /// type from `Binder<T>` to just `T` (see
 /// e.g. `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Binder<T>(pub T);
 
 impl<T> Binder<T> {
@@ -431,7 +412,7 @@ impl fmt::Debug for TypeFlags {
 
 /// Represents the projection of an associated type. In explicit UFCS
 /// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ProjectionTy<'tcx> {
     /// The trait reference `T as Trait<..>`.
     pub trait_ref: ty::TraitRef<'tcx>,
@@ -440,14 +421,16 @@ pub struct ProjectionTy<'tcx> {
     pub item_name: Name,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct BareFnTy<'tcx> {
     pub unsafety: hir::Unsafety,
     pub abi: abi::Abi,
     pub sig: PolyFnSig<'tcx>,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash)]
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx BareFnTy<'tcx> {}
+
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct ClosureTy<'tcx> {
     pub unsafety: hir::Unsafety,
     pub abi: abi::Abi,
@@ -460,7 +443,7 @@ pub struct ClosureTy<'tcx> {
 /// - `inputs` is the list of arguments and their modes.
 /// - `output` is the return type.
 /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct FnSig<'tcx> {
     pub inputs: Vec<Ty<'tcx>>,
     pub output: Ty<'tcx>,
@@ -484,7 +467,7 @@ impl<'tcx> PolyFnSig<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct ParamTy {
     pub idx: u32,
     pub name: Name,
@@ -663,14 +646,7 @@ pub enum Region {
     ReErased,
 }
 
-impl<'tcx> Decodable for &'tcx Region {
-    fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Region, D::Error> {
-        let r = Decodable::decode(d)?;
-        cstore::tls::with_decoding_context(d, |dcx, _| {
-            Ok(dcx.tcx().mk_region(r))
-        })
-    }
-}
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Region {}
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub struct EarlyBoundRegion {
@@ -678,17 +654,17 @@ pub struct EarlyBoundRegion {
     pub name: Name,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TyVid {
     pub index: u32,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct IntVid {
     pub index: u32
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct FloatVid {
     pub index: u32
 }
@@ -703,7 +679,7 @@ pub struct SkolemizedRegionVid {
     pub index: u32
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum InferTy {
     TyVar(TyVid),
     IntVar(IntVid),
@@ -718,7 +694,7 @@ pub enum InferTy {
 }
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ExistentialProjection<'tcx> {
     pub trait_ref: ExistentialTraitRef<'tcx>,
     pub item_name: Name,
@@ -763,7 +739,7 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct BuiltinBounds(EnumSet<BuiltinBound>);
 
 impl<'a, 'gcx, 'tcx> BuiltinBounds {
@@ -806,12 +782,11 @@ impl<'a> IntoIterator for &'a BuiltinBounds {
 
 #[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
            Debug, Copy)]
-#[repr(usize)]
 pub enum BuiltinBound {
-    Send,
-    Sized,
-    Copy,
-    Sync,
+    Send = 0,
+    Sized = 1,
+    Copy = 2,
+    Sync = 3,
 }
 
 impl CLike for BuiltinBound {
@@ -819,7 +794,13 @@ impl CLike for BuiltinBound {
         *self as usize
     }
     fn from_usize(v: usize) -> BuiltinBound {
-        unsafe { mem::transmute(v) }
+        match v {
+            0 => BuiltinBound::Send,
+            1 => BuiltinBound::Sized,
+            2 => BuiltinBound::Copy,
+            3 => BuiltinBound::Sync,
+            _ => bug!("{} is not a valid BuiltinBound", v)
+        }
     }
 }
 
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 0ccfea23309..6911d217426 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -10,12 +10,11 @@
 
 // Type substitutions.
 
-use middle::cstore;
 use hir::def_id::DefId;
 use ty::{self, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
-use serialize::{Encodable, Encoder, Decodable, Decoder};
+use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
 
 use core::nonzero::NonZero;
@@ -129,8 +128,40 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
     }
 }
 
+impl<'tcx> Encodable for Kind<'tcx> {
+    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+        e.emit_enum("Kind", |e| {
+            if let Some(ty) = self.as_type() {
+                e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
+                    e.emit_enum_variant_arg(0, |e| ty.encode(e))
+                })
+            } else if let Some(r) = self.as_region() {
+                e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
+                    e.emit_enum_variant_arg(0, |e| r.encode(e))
+                })
+            } else {
+                bug!()
+            }
+        })
+    }
+}
+
+impl<'tcx> Decodable for Kind<'tcx> {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Kind<'tcx>, D::Error> {
+        d.read_enum("Kind", |d| {
+            d.read_enum_variant(&["Ty", "Region"], |d, tag| {
+                match tag {
+                    TYPE_TAG => Ty::decode(d).map(Kind::from),
+                    REGION_TAG => <&ty::Region>::decode(d).map(Kind::from),
+                    _ => Err(d.error("invalid Kind tag"))
+                }
+            })
+        })
+    }
+}
+
 /// A substitution mapping type/region parameters to new values.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
 pub struct Substs<'tcx> {
     params: Vec<Kind<'tcx>>
 }
@@ -298,25 +329,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     }
 }
 
-impl<'tcx> Encodable for &'tcx Substs<'tcx> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
-            ecx.encode_substs(rbml_w, self);
-            Ok(())
-        })
-    }
-}
-
-impl<'tcx> Decodable for &'tcx Substs<'tcx> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> {
-        let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
-            dcx.decode_substs(rbml_r)
-        });
-
-        Ok(substs)
-    }
-}
-
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 
 ///////////////////////////////////////////////////////////////////////////
 // Public trait `Subst`
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index 268b2fcaa4a..3ff2ed76e57 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -15,7 +15,6 @@ use ty;
 use ty::fast_reject;
 use ty::{Ty, TyCtxt, TraitRef};
 use std::cell::{Cell, RefCell};
-use syntax::ast::Name;
 use hir;
 use util::nodemap::FnvHashMap;
 
@@ -38,10 +37,6 @@ pub struct TraitDef<'tcx> {
 
     pub trait_ref: ty::TraitRef<'tcx>,
 
-    /// A list of the associated types defined in this trait. Useful
-    /// for resolving `X::Foo` type markers.
-    pub associated_type_names: Vec<Name>,
-
     // Impls of a trait. To allow for quicker lookup, the impls are indexed by a
     // simplified version of their `Self` type: impls with a simplifiable `Self`
     // are stored in `nonblanket_impls` keyed by it, while all other impls are
@@ -82,7 +77,6 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> {
                paren_sugar: bool,
                generics: &'tcx ty::Generics<'tcx>,
                trait_ref: ty::TraitRef<'tcx>,
-               associated_type_names: Vec<Name>,
                def_path_hash: u64)
                -> TraitDef<'tcx> {
         TraitDef {
@@ -90,7 +84,6 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> {
             unsafety: unsafety,
             generics: generics,
             trait_ref: trait_ref,
-            associated_type_names: associated_type_names,
             nonblanket_impls: RefCell::new(FnvHashMap()),
             blanket_impls: RefCell::new(vec![]),
             flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index d34fdaa7d71..d834a7d485a 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -240,7 +240,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
         match opt_hint {
             // Feed in the given type
-            Some(&attr::ReprInt(_, int_t)) => int_t,
+            Some(&attr::ReprInt(int_t)) => int_t,
             // ... but provide sensible default if none provided
             //
             // NB. Historically `fn enum_variants` generate i64 here, while
@@ -352,12 +352,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Creates a hash of the type `Ty` which will be the same no matter what crate
     /// context it's calculated within. This is used by the `type_id` intrinsic.
     pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
-        let mut hasher = TypeIdHasher {
-            tcx: self,
-            state: SipHasher::new()
-        };
+        let mut hasher = TypeIdHasher::new(self, SipHasher::new());
         hasher.visit_ty(ty);
-        hasher.state.finish()
+        hasher.finish()
     }
 
     /// Returns true if this ADT is a dtorck type.
@@ -391,16 +388,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    state: SipHasher
+    state: H
 }
 
-impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> {
-    fn hash<T: Hash>(&mut self, x: T) {
+impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self {
+        TypeIdHasher {
+            tcx: tcx,
+            state: state
+        }
+    }
+
+    pub fn hash<T: Hash>(&mut self, x: T) {
         x.hash(&mut self.state);
     }
 
+    pub fn finish(self) -> u64 {
+        self.state.finish()
+    }
+
     fn hash_discriminant_u8<T>(&mut self, x: &T) {
         let v = unsafe {
             intrinsics::discriminant_value(x)
@@ -419,7 +427,7 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, H> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         // Distinguish between the Ty variants uniformly.
         self.hash_discriminant_u8(&ty.sty);
@@ -428,17 +436,18 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             TyInt(i) => self.hash(i),
             TyUint(u) => self.hash(u),
             TyFloat(f) => self.hash(f),
-            TyAdt(d, _) => self.def_id(d.did),
             TyArray(_, n) => self.hash(n),
             TyRawPtr(m) |
             TyRef(_, m) => self.hash(m.mutbl),
             TyClosure(def_id, _) |
             TyAnon(def_id, _) |
             TyFnDef(def_id, ..) => self.def_id(def_id),
+            TyAdt(d, _) => self.def_id(d.did),
             TyFnPtr(f) => {
                 self.hash(f.unsafety);
                 self.hash(f.abi);
                 self.hash(f.sig.variadic());
+                self.hash(f.sig.inputs().skip_binder().len());
             }
             TyTrait(ref data) => {
                 self.def_id(data.principal.def_id());
@@ -460,9 +469,10 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             TyChar |
             TyStr |
             TyBox(_) |
-            TySlice(_) |
-            TyError => {}
-            TyInfer(_) => bug!()
+            TySlice(_) => {}
+
+            TyError |
+            TyInfer(_) => bug!("TypeIdHasher: unexpected type {}", ty)
         }
 
         ty.super_visit_with(self)
@@ -470,7 +480,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
 
     fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
         match *r {
-            ty::ReStatic | ty::ReErased => {
+            ty::ReErased => {
                 self.hash::<u32>(0);
             }
             ty::ReLateBound(db, ty::BrAnon(i)) => {
@@ -478,6 +488,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
                 self.hash::<u32>(db.depth);
                 self.hash(i);
             }
+            ty::ReStatic |
             ty::ReEmpty |
             ty::ReEarlyBound(..) |
             ty::ReLateBound(..) |
@@ -485,7 +496,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             ty::ReScope(..) |
             ty::ReVar(..) |
             ty::ReSkolemized(..) => {
-                bug!("unexpected region found when hashing a type")
+                bug!("TypeIdHasher: unexpected region {:?}", r)
             }
         }
         false
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 3b84ff86ab9..1df0cf2d5cd 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -920,7 +920,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     let mut sep = " ";
                     tcx.with_freevars(node_id, |freevars| {
                         for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) {
-                            let node_id = freevar.def.var_id();
+                            let def_id = freevar.def.def_id();
+                            let node_id = tcx.map.as_local_node_id(def_id).unwrap();
                             write!(f,
                                         "{}{}:{}",
                                         sep,
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index 6a7bc51d15a..f7ae47d2e5e 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -46,7 +46,6 @@ extern crate serialize;
 #[macro_use] extern crate log;
 
 pub mod tempdir;
-pub mod rpath;
 pub mod sha2;
 pub mod target;
 pub mod slice;
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index a1e7d0a1e34..eb74936d8c9 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -26,8 +26,7 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization::{cmt};
 use rustc::hir::pat_util::*;
 use rustc::traits::Reveal;
-use rustc::ty::*;
-use rustc::ty;
+use rustc::ty::{self, Ty, TyCtxt};
 use std::cmp::Ordering;
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator, repeat};
@@ -40,11 +39,10 @@ use rustc_back::slice;
 use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
 use syntax::codemap::Spanned;
 use syntax_pos::{Span, DUMMY_SP};
-use rustc::hir::fold::{Folder, noop_fold_pat};
 use rustc::hir::print::pat_to_string;
 use syntax::ptr::P;
+use syntax::util::move_map::MoveMap;
 use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::FnvHashMap;
 
 pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
     id: DUMMY_NODE_ID,
@@ -111,7 +109,7 @@ impl<'a, 'tcx> FromIterator<Vec<(&'a Pat, Option<Ty<'tcx>>)>> for Matrix<'a, 'tc
 //NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
 pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub param_env: ParameterEnvironment<'tcx>,
+    pub param_env: ty::ParameterEnvironment<'tcx>,
 }
 
 #[derive(Clone, Debug, PartialEq)]
@@ -182,7 +180,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
                 }
             }
 
-            let mut static_inliner = StaticInliner::new(cx.tcx, None);
+            let mut static_inliner = StaticInliner::new(cx.tcx);
             let inlined_arms = arms.iter().map(|arm| {
                 (arm.pats.iter().map(|pat| {
                     static_inliner.fold_pat((*pat).clone())
@@ -249,7 +247,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
                 if edef.is_enum() {
                     if let Def::Local(..) = cx.tcx.expect_def(p.id) {
                         if edef.variants.iter().any(|variant| {
-                            variant.name == name.node && variant.kind == VariantKind::Unit
+                            variant.name == name.node && variant.kind == ty::VariantKind::Unit
                         }) {
                             let ty_path = cx.tcx.item_path_str(edef.did);
                             let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
@@ -460,60 +458,37 @@ fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
         _ => bug!()
     };
     P(hir::Expr {
-        id: 0,
+        id: DUMMY_NODE_ID,
         node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
         span: DUMMY_SP,
         attrs: ast::ThinVec::new(),
     })
 }
 
-pub struct StaticInliner<'a, 'tcx: 'a> {
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub failed: bool,
-    pub renaming_map: Option<&'a mut FnvHashMap<(NodeId, Span), NodeId>>,
+struct StaticInliner<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    failed: bool
 }
 
 impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
-    pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
-                   renaming_map: Option<&'b mut FnvHashMap<(NodeId, Span), NodeId>>)
-                   -> StaticInliner<'b, 'tcx> {
+    pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> StaticInliner<'b, 'tcx> {
         StaticInliner {
             tcx: tcx,
-            failed: false,
-            renaming_map: renaming_map
+            failed: false
         }
     }
 }
 
-struct RenamingRecorder<'map> {
-    substituted_node_id: NodeId,
-    origin_span: Span,
-    renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId>
-}
-
-impl<'v, 'map> Visitor<'v> for RenamingRecorder<'map> {
-    fn visit_id(&mut self, node_id: NodeId) {
-        let key = (node_id, self.origin_span);
-        self.renaming_map.insert(key, self.substituted_node_id);
-    }
-}
-
-impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
+impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
     fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
-        return match pat.node {
+        match pat.node {
             PatKind::Path(..) => {
                 match self.tcx.expect_def(pat.id) {
                     Def::AssociatedConst(did) | Def::Const(did) => {
                         let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
                         if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
                             match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) {
-                                Ok(new_pat) => {
-                                    if let Some(ref mut map) = self.renaming_map {
-                                        // Record any renamings we do here
-                                        record_renamings(const_expr, &pat, map);
-                                    }
-                                    new_pat
-                                }
+                                Ok(new_pat) => return new_pat,
                                 Err(def_id) => {
                                     self.failed = true;
                                     self.tcx.sess.span_err(
@@ -521,33 +496,62 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
                                         &format!("constants of the type `{}` \
                                                   cannot be used in patterns",
                                                  self.tcx.item_path_str(def_id)));
-                                    pat
                                 }
                             }
                         } else {
                             self.failed = true;
                             span_err!(self.tcx.sess, pat.span, E0158,
                                 "statics cannot be referenced in patterns");
-                            pat
                         }
                     }
-                    _ => noop_fold_pat(pat, self)
+                    _ => {}
                 }
             }
-            _ => noop_fold_pat(pat, self)
-        };
+            _ => {}
+        }
 
-        fn record_renamings(const_expr: &hir::Expr,
-                            substituted_pat: &hir::Pat,
-                            renaming_map: &mut FnvHashMap<(NodeId, Span), NodeId>) {
-            let mut renaming_recorder = RenamingRecorder {
-                substituted_node_id: substituted_pat.id,
-                origin_span: substituted_pat.span,
-                renaming_map: renaming_map,
+        pat.map(|Pat { id, node, span }| {
+            let node = match node {
+                PatKind::Binding(binding_mode, pth1, sub) => {
+                    PatKind::Binding(binding_mode, pth1, sub.map(|x| self.fold_pat(x)))
+                }
+                PatKind::TupleStruct(pth, pats, ddpos) => {
+                    PatKind::TupleStruct(pth, pats.move_map(|x| self.fold_pat(x)), ddpos)
+                }
+                PatKind::Struct(pth, fields, etc) => {
+                    let fs = fields.move_map(|f| {
+                        Spanned {
+                            span: f.span,
+                            node: hir::FieldPat {
+                                name: f.node.name,
+                                pat: self.fold_pat(f.node.pat),
+                                is_shorthand: f.node.is_shorthand,
+                            },
+                        }
+                    });
+                    PatKind::Struct(pth, fs, etc)
+                }
+                PatKind::Tuple(elts, ddpos) => {
+                    PatKind::Tuple(elts.move_map(|x| self.fold_pat(x)), ddpos)
+                }
+                PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)),
+                PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl),
+                PatKind::Vec(before, slice, after) => {
+                    PatKind::Vec(before.move_map(|x| self.fold_pat(x)),
+                                 slice.map(|x| self.fold_pat(x)),
+                                 after.move_map(|x| self.fold_pat(x)))
+                }
+                PatKind::Wild |
+                PatKind::Lit(_) |
+                PatKind::Range(..) |
+                PatKind::Path(..) => node
             };
-
-            renaming_recorder.visit_expr(const_expr);
-        }
+            Pat {
+                id: id,
+                node: node,
+                span: span
+            }
+        })
     }
 }
 
@@ -574,7 +578,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
         ty::TyAdt(adt, _) => {
             let v = ctor.variant_for_adt(adt);
             match v.kind {
-                VariantKind::Struct => {
+                ty::VariantKind::Struct => {
                     let field_pats: hir::HirVec<_> = v.fields.iter()
                         .zip(pats)
                         .filter(|&(_, ref pat)| pat.node != PatKind::Wild)
@@ -589,10 +593,10 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
                     let has_more_fields = field_pats.len() < pats_len;
                     PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields)
                 }
-                VariantKind::Tuple => {
+                ty::VariantKind::Tuple => {
                     PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None)
                 }
-                VariantKind::Unit => {
+                ty::VariantKind::Unit => {
                     PatKind::Path(None, def_to_path(cx.tcx, v.did))
                 }
             }
@@ -625,7 +629,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
     };
 
     P(hir::Pat {
-        id: 0,
+        id: DUMMY_NODE_ID,
         node: pat,
         span: DUMMY_SP
     })
@@ -634,7 +638,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
 impl Constructor {
     fn variant_for_adt<'tcx, 'container, 'a>(&self,
                                              adt: &'a ty::AdtDefData<'tcx, 'container>)
-                                             -> &'a VariantDefData<'tcx, 'container> {
+                                             -> &'a ty::VariantDefData<'tcx, 'container> {
         match self {
             &Variant(vid) => adt.variant_with_id(vid),
             _ => adt.struct_variant()
@@ -797,7 +801,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
     match pat.node {
         PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
             match cx.tcx.expect_def(pat.id) {
-                Def::Variant(_, id) => vec![Variant(id)],
+                Def::Variant(id) => vec![Variant(id)],
                 Def::Struct(..) | Def::Union(..) |
                 Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
                 Def::Const(..) | Def::AssociatedConst(..) =>
@@ -873,7 +877,7 @@ fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
     let pat_ty = cx.tcx.pat_ty(pat);
     (pat, Some(match pat.node {
         PatKind::Binding(hir::BindByRef(..), ..) => {
-            pat_ty.builtin_deref(false, NoPreference).unwrap().ty
+            pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty
         }
         _ => pat_ty
     }))
@@ -909,7 +913,7 @@ pub fn specialize<'a, 'b, 'tcx>(
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat_span, "const pattern should've \
                                          been rewritten"),
-                Def::Variant(_, id) if *constructor != Variant(id) => None,
+                Def::Variant(id) if *constructor != Variant(id) => None,
                 Def::Variant(..) | Def::Struct(..) => Some(Vec::new()),
                 def => span_bug!(pat_span, "specialize: unexpected \
                                           definition {:?}", def),
@@ -921,7 +925,7 @@ pub fn specialize<'a, 'b, 'tcx>(
                 Def::Const(..) | Def::AssociatedConst(..) =>
                     span_bug!(pat_span, "const pattern should've \
                                          been rewritten"),
-                Def::Variant(_, id) if *constructor != Variant(id) => None,
+                Def::Variant(id) if *constructor != Variant(id) => None,
                 Def::Variant(..) | Def::Struct(..) => {
                     match ddpos {
                         Some(ddpos) => {
@@ -1047,7 +1051,7 @@ pub fn specialize<'a, 'b, 'tcx>(
 fn check_local(cx: &mut MatchCheckCtxt, loc: &hir::Local) {
     intravisit::walk_local(cx, loc);
 
-    let pat = StaticInliner::new(cx.tcx, None).fold_pat(loc.pat.clone());
+    let pat = StaticInliner::new(cx.tcx).fold_pat(loc.pat.clone());
     check_irrefutable(cx, &pat, false);
 
     // Check legality of move bindings and `@` patterns.
@@ -1063,7 +1067,7 @@ fn check_fn(cx: &mut MatchCheckCtxt,
             fn_id: NodeId) {
     match kind {
         FnKind::Closure(_) => {}
-        _ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id),
+        _ => cx.param_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_id),
     }
 
     intravisit::walk_fn(cx, kind, decl, body, sp, fn_id);
@@ -1182,17 +1186,17 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
               _: NodeId,
               span: Span,
               _: cmt,
-              _: &'tcx Region,
-              kind: BorrowKind,
+              _: &'tcx ty::Region,
+              kind:ty:: BorrowKind,
               _: LoanCause) {
         match kind {
-            MutBorrow => {
+            ty::MutBorrow => {
                 struct_span_err!(self.cx.tcx.sess, span, E0301,
                           "cannot mutably borrow in a pattern guard")
                     .span_label(span, &format!("borrowed mutably in pattern guard"))
                     .emit();
             }
-            ImmBorrow | UniqueImmBorrow => {}
+            ty::ImmBorrow | ty::UniqueImmBorrow => {}
         }
     }
     fn decl_without_init(&mut self, _: NodeId, _: Span) {}
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 4ced9d87f0a..dce3882004c 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -57,7 +57,6 @@ macro_rules! math {
 }
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  enum_def: DefId,
                                   variant_def: DefId)
                                   -> Option<&'tcx Expr> {
     fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
@@ -70,8 +69,8 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         None
     }
 
-    if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
-        let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
+    if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
+        let enum_node_id = tcx.map.get_parent(variant_node_id);
         match tcx.map.find(enum_node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
@@ -289,7 +288,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
             let path = match def {
                 Def::Struct(def_id) => def_to_path(tcx, def_id),
-                Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
+                Def::Variant(variant_did) => def_to_path(tcx, variant_did),
                 Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
                     id: expr.id,
                     node: PatKind::Lit(P(expr.clone())),
@@ -808,8 +807,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Variant(enum_def, variant_def) => {
-                  if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) {
+              Def::Variant(variant_def) => {
+                  if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) {
                       match eval_const_expr_partial(tcx, const_expr, ty_hint, None) {
                           Ok(val) => val,
                           Err(err) => {
@@ -824,7 +823,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Def::Struct(..) => {
                   ConstVal::Struct(e.id)
               }
-              Def::Local(_, id) => {
+              Def::Local(def_id) => {
+                  let id = tcx.map.as_local_node_id(def_id).unwrap();
                   debug!("Def::Local({:?}): {:?}", id, fn_args);
                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
                       val.clone()
@@ -1079,8 +1079,14 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
-                match tcx.associated_consts(impl_data.impl_def_id)
-                        .iter().find(|ic| ic.name == ti.name) {
+                let ac = tcx.impl_or_trait_items(impl_data.impl_def_id)
+                    .iter().filter_map(|&def_id| {
+                        match tcx.impl_or_trait_item(def_id) {
+                            ty::ConstTraitItem(ic) => Some(ic),
+                            _ => None
+                        }
+                    }).find(|ic| ic.name == ti.name);
+                match ac {
                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
                     None => match ti.node {
                         hir::ConstTraitItem(ref ty, Some(ref expr)) => {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 1ffeaf322bf..215287f8439 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -539,6 +539,7 @@ impl FromStr for UserIdentifiedItem {
     type Err = ();
     fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
         Ok(s.parse()
+            .map(ast::NodeId::new)
             .map(ItemViaNode)
             .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
     }
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 8569ff64f91..f6772b87718 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -166,16 +166,17 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     pub fn create_simple_region_hierarchy(&self) {
         // creates a region hierarchy where 1 is root, 10 and 11 are
         // children of 1, etc
+
+        let node = ast::NodeId::from_u32;
         let dscope = self.infcx
                          .tcx
                          .region_maps
-                         .intern_code_extent(CodeExtentData::DestructionScope(1),
+                         .intern_code_extent(CodeExtentData::DestructionScope(node(1)),
                                              region::ROOT_CODE_EXTENT);
         self.create_region_hierarchy(&RH {
-                                         id: 1,
-                                         sub: &[RH { id: 10, sub: &[] }, RH { id: 11, sub: &[] }],
-                                     },
-                                     dscope);
+            id: node(1),
+            sub: &[RH { id: node(10), sub: &[] }, RH { id: node(11), sub: &[] }],
+        }, dscope);
     }
 
     #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
@@ -315,8 +316,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
-    pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
-        let r = ty::ReScope(self.tcx().region_maps.node_extent(id));
+    pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
+        let r = ty::ReScope(self.tcx().region_maps.node_extent(ast::NodeId::from_u32(id)));
         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
     }
 
@@ -327,8 +328,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         }))
     }
 
-    pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
-        let r = self.re_free(nid, id);
+    pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> {
+        let r = self.re_free(ast::NodeId::from_u32(nid), id);
         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml
index 7db1a6348b2..e3ee7527545 100644
--- a/src/librustc_incremental/Cargo.toml
+++ b/src/librustc_incremental/Cargo.toml
@@ -10,10 +10,9 @@ crate-type = ["dylib"]
 
 [dependencies]
 graphviz = { path = "../libgraphviz" }
-rbml = { path = "../librbml" }
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 serialize = { path = "../libserialize" }
 log = { path = "../liblog" }
 syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
\ No newline at end of file
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index af8ec6c6257..9950f470a82 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -602,7 +602,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             // def-id is the same, so it suffices to hash the def-id
             Def::Fn(..) |
             Def::Mod(..) |
-            Def::ForeignMod(..) |
             Def::Static(..) |
             Def::Variant(..) |
             Def::Enum(..) |
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 1f823eedda0..42b5657e212 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -27,7 +27,6 @@
 #![feature(core_intrinsics)]
 
 extern crate graphviz;
-extern crate rbml;
 #[macro_use] extern crate rustc;
 extern crate rustc_data_structures;
 extern crate serialize as rustc_serialize;
diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs
index 89a79d1a487..cca364f442d 100644
--- a/src/librustc_incremental/persist/directory.rs
+++ b/src/librustc_incremental/persist/directory.rs
@@ -15,13 +15,11 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::DefPath;
-use rustc::hir::def_id::DefId;
-use rustc::middle::cstore::LOCAL_CRATE;
+use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::ty::TyCtxt;
 use rustc::util::nodemap::DefIdMap;
 use std::fmt::{self, Debug};
 use std::iter::once;
-use syntax::ast;
 
 /// Index into the DefIdDirectory
 #[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
@@ -43,7 +41,7 @@ pub struct DefIdDirectory {
 
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct CrateInfo {
-    krate: ast::CrateNum,
+    krate: CrateNum,
     name: String,
     disambiguator: String,
 }
@@ -53,7 +51,7 @@ impl DefIdDirectory {
         DefIdDirectory { paths: vec![], krates: krates }
     }
 
-    fn max_current_crate(&self, tcx: TyCtxt) -> ast::CrateNum {
+    fn max_current_crate(&self, tcx: TyCtxt) -> CrateNum {
         tcx.sess.cstore.crates()
                        .into_iter()
                        .max()
@@ -72,8 +70,8 @@ impl DefIdDirectory {
 
     pub fn krate_still_valid(&self,
                              tcx: TyCtxt,
-                             max_current_crate: ast::CrateNum,
-                             krate: ast::CrateNum) -> bool {
+                             max_current_crate: CrateNum,
+                             krate: CrateNum) -> bool {
         // Check that the crate-number still matches. For now, if it
         // doesn't, just return None. We could do better, such as
         // finding the new number.
@@ -81,7 +79,7 @@ impl DefIdDirectory {
         if krate > max_current_crate {
             false
         } else {
-            let old_info = &self.krates[krate as usize];
+            let old_info = &self.krates[krate.as_usize()];
             assert_eq!(old_info.krate, krate);
             let old_name: &str = &old_info.name;
             let old_disambiguator: &str = &old_info.disambiguator;
@@ -101,7 +99,7 @@ impl DefIdDirectory {
                                 } else {
                                     debug!("crate {} changed from {:?} to {:?}/{:?}",
                                            path.krate,
-                                           self.krates[path.krate as usize],
+                                           self.krates[path.krate.as_usize()],
                                            tcx.crate_name(path.krate),
                                            tcx.crate_disambiguator(path.krate));
                                     None
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 8166045be5f..c9cfaf4f661 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -114,8 +114,8 @@
 //! unsupported file system and emit a warning in that case. This is not yet
 //! implemented.
 
+use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc::hir::svh::Svh;
-use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc::util::fs as fs_util;
@@ -129,7 +129,6 @@ use std::mem;
 use std::path::{Path, PathBuf};
 use std::time::{UNIX_EPOCH, SystemTime, Duration};
 use std::__rand::{thread_rng, Rng};
-use syntax::ast;
 
 const LOCK_FILE_EXT: &'static str = ".lock";
 const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin";
@@ -580,7 +579,7 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
     Ok(UNIX_EPOCH + duration)
 }
 
-fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf {
+fn crate_path_tcx(tcx: TyCtxt, cnum: CrateNum) -> PathBuf {
     crate_path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum))
 }
 
@@ -592,7 +591,7 @@ fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf {
 /// crate's (name, disambiguator) pair. The metadata hashes are only valid for
 /// the exact version of the binary we are reading from now (i.e. the hashes
 /// are part of the dependency graph of a specific compilation session).
-pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
+pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: CrateNum) -> Option<PathBuf> {
     let crate_directory = crate_path_tcx(tcx, cnum);
 
     if !crate_directory.exists() {
diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs
index bafaafd4afa..5a4716e45f6 100644
--- a/src/librustc_incremental/persist/hash.rs
+++ b/src/librustc_incremental/persist/hash.rs
@@ -8,18 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rbml::Error;
-use rbml::opaque::Decoder;
 use rustc::dep_graph::DepNode;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{CrateNum, DefId};
 use rustc::hir::svh::Svh;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc_data_structures::flock;
 use rustc_serialize::Decodable;
+use rustc_serialize::opaque::Decoder;
 use std::io::{ErrorKind, Read};
 use std::fs::File;
-use syntax::ast;
 
 use IncrementalHashesMap;
 use super::data::*;
@@ -29,7 +27,7 @@ pub struct HashContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     incremental_hashes_map: &'a IncrementalHashesMap,
     item_metadata_hashes: FnvHashMap<DefId, u64>,
-    crate_hashes: FnvHashMap<ast::CrateNum, Svh>,
+    crate_hashes: FnvHashMap<CrateNum, Svh>,
 }
 
 impl<'a, 'tcx> HashContext<'a, 'tcx> {
@@ -121,7 +119,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
         }
     }
 
-    fn load_data(&mut self, cnum: ast::CrateNum) {
+    fn load_data(&mut self, cnum: CrateNum) {
         debug!("load_data(cnum={})", cnum);
 
         let svh = self.tcx.sess.cstore.crate_hash(cnum);
@@ -187,9 +185,9 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
     }
 
     fn load_from_data(&mut self,
-                      cnum: ast::CrateNum,
+                      cnum: CrateNum,
                       data: &[u8],
-                      expected_svh: Svh) -> Result<(), Error> {
+                      expected_svh: Svh) -> Result<(), String> {
         debug!("load_from_data(cnum={})", cnum);
 
         // Load up the hashes for the def-ids from this crate.
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index 6e6464e4968..b051e6c5ab7 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -10,14 +10,13 @@
 
 //! Code to save/load the dep-graph from files.
 
-use rbml::Error;
-use rbml::opaque::Decoder;
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashSet;
 use rustc_serialize::Decodable as RustcDecodable;
+use rustc_serialize::opaque::Decoder;
 use std::io::Read;
 use std::fs::{self, File};
 use std::path::{Path};
@@ -121,7 +120,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   incremental_hashes_map: &IncrementalHashesMap,
                                   dep_graph_data: &[u8],
                                   work_products_data: &[u8])
-                                  -> Result<(), Error>
+                                  -> Result<(), String>
 {
     // Decode the list of work_products
     let mut work_product_decoder = Decoder::new(work_products_data, 0);
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 41212d8e138..5b45874840f 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rbml::opaque::Encoder;
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
@@ -16,6 +15,7 @@ use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc_serialize::Encodable as RustcEncodable;
+use rustc_serialize::opaque::Encoder;
 use std::hash::{Hash, Hasher, SipHasher};
 use std::io::{self, Cursor, Write};
 use std::fs::{self, File};
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index e8d9e90456e..1209ced8dd3 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -92,7 +92,7 @@ pub struct TypeLimits {
 impl TypeLimits {
     pub fn new() -> TypeLimits {
         TypeLimits {
-            negated_expr_id: !0,
+            negated_expr_id: ast::DUMMY_NODE_ID,
         }
     }
 }
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index d70510896b9..680d55955bb 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -11,10 +11,8 @@ crate-type = ["dylib"]
 [dependencies]
 flate = { path = "../libflate" }
 log = { path = "../liblog" }
-rbml = { path = "../librbml" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
-rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index fb7e1c0f789..c9dbedacbc1 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -8,1369 +8,151 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-// FIXME: remove this after snapshot, and Results are handled
-#![allow(unused_must_use)]
-
 use rustc::hir::map as ast_map;
-use rustc::session::Session;
 
-use rustc::hir;
-use rustc::hir::fold;
-use rustc::hir::fold::Folder;
 use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange};
 
-use common as c;
-use cstore;
-use decoder;
-use encoder as e;
-use tydecode;
-use tyencode;
+use cstore::CrateMetadata;
+use encoder::EncodeContext;
+use schema::*;
 
-use middle::cstore::{InlinedItem, InlinedItemRef};
-use rustc::ty::adjustment;
-use rustc::ty::cast;
-use middle::const_qualif::ConstQualif;
+use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
+use rustc::middle::const_qualif::ConstQualif;
 use rustc::hir::def::{self, Def};
 use rustc::hir::def_id::DefId;
-use middle::region;
-use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, TyCtxt, Ty};
 
 use syntax::ast;
-use syntax::ptr::P;
-use syntax_pos;
-
-use std::cell::Cell;
-use std::io::SeekFrom;
-use std::io::prelude::*;
-use std::fmt::Debug;
-
-use rbml::reader;
-use rbml::writer::Encoder;
-use rbml;
-use rustc_serialize as serialize;
-use rustc_serialize::{Decodable, Decoder, DecoderHelpers};
-use rustc_serialize::{Encodable, EncoderHelpers};
-
-#[cfg(test)] use std::io::Cursor;
-#[cfg(test)] use syntax::parse;
-#[cfg(test)] use rustc::hir::print as pprust;
-#[cfg(test)] use rustc::hir::lowering::{LoweringContext, DummyResolver};
-
-struct DecodeContext<'a, 'b, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    cdata: &'b cstore::CrateMetadata,
-    from_id_range: IdRange,
-    to_id_range: IdRange,
-    // Cache the last used filemap for translating spans as an optimization.
-    last_filemap_index: Cell<usize>,
-}
-
-trait tr {
-    fn tr(&self, dcx: &DecodeContext) -> Self;
-}
-
-// ______________________________________________________________________
-// Top-level methods.
-
-pub fn encode_inlined_item(ecx: &e::EncodeContext,
-                           rbml_w: &mut Encoder,
-                           ii: InlinedItemRef) {
-    let id = match ii {
-        InlinedItemRef::Item(_, i) => i.id,
-        InlinedItemRef::TraitItem(_, ti) => ti.id,
-        InlinedItemRef::ImplItem(_, ii) => ii.id,
-    };
-    debug!("> Encoding inlined item: {} ({:?})",
-           ecx.tcx.node_path_str(id),
-           rbml_w.writer.seek(SeekFrom::Current(0)));
-
-    // Folding could be avoided with a smarter encoder.
-    let (ii, expected_id_range) = simplify_ast(ii);
-    let id_range = inlined_item_id_range(&ii);
-    assert_eq!(expected_id_range, id_range);
-
-    rbml_w.start_tag(c::tag_ast as usize);
-    id_range.encode(rbml_w);
-    encode_ast(rbml_w, &ii);
-    encode_side_tables_for_ii(ecx, rbml_w, &ii);
-    rbml_w.end_tag();
-
-    debug!("< Encoded inlined fn: {} ({:?})",
-           ecx.tcx.node_path_str(id),
-           rbml_w.writer.seek(SeekFrom::Current(0)));
-}
-
-impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> {
-    fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
-        if id == ast::DUMMY_NODE_ID {
-            // Used by ast_map to map the NodeInlinedParent.
-            self.tcx.sess.next_node_id()
-        } else {
-            self.tr_id(id)
-        }
-    }
-    fn new_def_id(&self, def_id: DefId) -> DefId {
-        self.tr_def_id(def_id)
-    }
-    fn new_span(&self, span: syntax_pos::Span) -> syntax_pos::Span {
-        self.tr_span(span)
-    }
-}
-
-/// Decodes an item from its AST in the cdata's metadata and adds it to the
-/// ast-map.
-pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata,
-                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     parent_def_path: ast_map::DefPath,
-                                     parent_did: DefId,
-                                     ast_doc: rbml::Doc,
-                                     orig_did: DefId)
-                                     -> &'tcx InlinedItem {
-    debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
-    let mut ast_dsr = reader::Decoder::new(ast_doc);
-    let from_id_range = Decodable::decode(&mut ast_dsr).unwrap();
-    let to_id_range = reserve_id_range(&tcx.sess, from_id_range);
-    let dcx = &DecodeContext {
-        cdata: cdata,
-        tcx: tcx,
-        from_id_range: from_id_range,
-        to_id_range: to_id_range,
-        last_filemap_index: Cell::new(0)
-    };
-    let ii = ast_map::map_decoded_item(&dcx.tcx.map,
-                                       parent_def_path,
-                                       parent_did,
-                                       decode_ast(ast_doc),
-                                       dcx);
-    let name = match *ii {
-        InlinedItem::Item(_, ref i) => i.name,
-        InlinedItem::TraitItem(_, ref ti) => ti.name,
-        InlinedItem::ImplItem(_, ref ii) => ii.name
-    };
-    debug!("Fn named: {}", name);
-    debug!("< Decoded inlined fn: {}::{}",
-            tcx.item_path_str(parent_did),
-            name);
-    region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii);
-    decode_side_tables(dcx, ast_doc);
-    copy_item_types(dcx, ii, orig_did);
-    if let InlinedItem::Item(_, ref i) = *ii {
-        debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<",
-               ::rustc::hir::print::item_to_string(&i));
-    }
-
-    ii
-}
-
-// ______________________________________________________________________
-// Enumerating the IDs which appear in an AST
-
-fn reserve_id_range(sess: &Session,
-                    from_id_range: IdRange) -> IdRange {
-    // Handle the case of an empty range:
-    if from_id_range.empty() { return from_id_range; }
-    let cnt = from_id_range.max - from_id_range.min;
-    let to_id_min = sess.reserve_node_ids(cnt);
-    let to_id_max = to_id_min + cnt;
-    IdRange { min: to_id_min, max: to_id_max }
-}
-
-impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
-    /// Translates an internal id, meaning a node id that is known to refer to some part of the
-    /// item currently being inlined, such as a local variable or argument.  All naked node-ids
-    /// that appear in types have this property, since if something might refer to an external item
-    /// we would use a def-id to allow for the possibility that the item resides in another crate.
-    pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
-        // from_id_range should be non-empty
-        assert!(!self.from_id_range.empty());
-        // Make sure that translating the NodeId will actually yield a
-        // meaningful result
-        assert!(self.from_id_range.contains(id));
-
-        // Use wrapping arithmetic because otherwise it introduces control flow.
-        // Maybe we should just have the control flow? -- aatch
-        (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min))
-    }
-
-    /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded
-    /// data to the current crate numbers..  By external, I mean that it be translated to a
-    /// reference to the item in its original crate, as opposed to being translated to a reference
-    /// to the inlined version of the item.  This is typically, but not always, what you want,
-    /// because most def-ids refer to external things like types or other fns that may or may not
-    /// be inlined.  Note that even when the inlined function is referencing itself recursively, we
-    /// would want `tr_def_id` for that reference--- conceptually the function calls the original,
-    /// non-inlined version, and trans deals with linking that recursive call to the inlined copy.
-    pub fn tr_def_id(&self, did: DefId) -> DefId {
-        decoder::translate_def_id(self.cdata, did)
-    }
-
-    /// Translates a `Span` from an extern crate to the corresponding `Span`
-    /// within the local crate's codemap.
-    pub fn tr_span(&self, span: syntax_pos::Span) -> syntax_pos::Span {
-        decoder::translate_span(self.cdata,
-                                self.tcx.sess.codemap(),
-                                &self.last_filemap_index,
-                                span)
-    }
-}
-
-impl tr for DefId {
-    fn tr(&self, dcx: &DecodeContext) -> DefId {
-        dcx.tr_def_id(*self)
-    }
-}
-
-impl tr for Option<DefId> {
-    fn tr(&self, dcx: &DecodeContext) -> Option<DefId> {
-        self.map(|d| dcx.tr_def_id(d))
-    }
-}
-
-impl tr for syntax_pos::Span {
-    fn tr(&self, dcx: &DecodeContext) -> syntax_pos::Span {
-        dcx.tr_span(*self)
-    }
-}
-
-trait def_id_encoder_helpers {
-    fn emit_def_id(&mut self, did: DefId);
-}
-
-impl<S:serialize::Encoder> def_id_encoder_helpers for S
-    where <S as serialize::Encoder>::Error: Debug
-{
-    fn emit_def_id(&mut self, did: DefId) {
-        did.encode(self).unwrap()
-    }
-}
-
-trait def_id_decoder_helpers {
-    fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId;
-    fn read_def_id_nodcx(&mut self,
-                         cdata: &cstore::CrateMetadata) -> DefId;
-}
-
-impl<D:serialize::Decoder> def_id_decoder_helpers for D
-    where <D as serialize::Decoder>::Error: Debug
-{
-    fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId {
-        let did: DefId = Decodable::decode(self).unwrap();
-        did.tr(dcx)
-    }
-
-    fn read_def_id_nodcx(&mut self,
-                         cdata: &cstore::CrateMetadata)
-                         -> DefId {
-        let did: DefId = Decodable::decode(self).unwrap();
-        decoder::translate_def_id(cdata, did)
-    }
-}
-
-// ______________________________________________________________________
-// Encoding and decoding the AST itself
-//
-// When decoding, we have to renumber the AST so that the node ids that
-// appear within are disjoint from the node ids in our existing ASTs.
-// We also have to adjust the spans: for now we just insert a dummy span,
-// but eventually we should add entries to the local codemap as required.
-
-fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) {
-    rbml_w.start_tag(c::tag_tree as usize);
-    rbml_w.emit_opaque(|this| item.encode(this));
-    rbml_w.end_tag();
-}
-
-struct NestedItemsDropper {
-    id_range: IdRange
-}
-
-impl Folder for NestedItemsDropper {
-
-    // The unit tests below run on HIR with NodeIds not properly assigned. That
-    // causes an integer overflow. So we just don't track the id_range when
-    // building the unit tests.
-    #[cfg(not(test))]
-    fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
-        // Record the range of NodeIds we are visiting, so we can do a sanity
-        // check later
-        self.id_range.add(id);
-        id
-    }
-
-    fn fold_block(&mut self, blk: P<hir::Block>) -> P<hir::Block> {
-        blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
-            let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
-                let use_stmt = match stmt.node {
-                    hir::StmtExpr(..) | hir::StmtSemi(..) => true,
-                    hir::StmtDecl(ref decl, _) => {
-                        match decl.node {
-                            hir::DeclLocal(_) => true,
-                            hir::DeclItem(_) => false,
-                        }
-                    }
-                };
-                if use_stmt {
-                    Some(stmt)
-                } else {
-                    None
-                }
-            }).collect();
-            let blk_sans_items = P(hir::Block {
-                stmts: stmts_sans_items,
-                expr: expr,
-                id: id,
-                rules: rules,
-                span: span,
-            });
-            fold::noop_fold_block(blk_sans_items, self)
-        })
-    }
-}
-
-// Produces a simplified copy of the AST which does not include things
-// that we do not need to or do not want to export.  For example, we
-// do not include any nested items: if these nested items are to be
-// inlined, their AST will be exported separately (this only makes
-// sense because, in Rust, nested items are independent except for
-// their visibility).
-//
-// As it happens, trans relies on the fact that we do not export
-// nested items, as otherwise it would get confused when translating
-// inlined items.
-fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
-    let mut fld = NestedItemsDropper {
-        id_range: IdRange::max()
-    };
-
-    let ii = match ii {
-        // HACK we're not dropping items.
-        InlinedItemRef::Item(d, i) => {
-            InlinedItem::Item(d, P(fold::noop_fold_item(i.clone(), &mut fld)))
-        }
-        InlinedItemRef::TraitItem(d, ti) => {
-            InlinedItem::TraitItem(d, P(fold::noop_fold_trait_item(ti.clone(), &mut fld)))
-        }
-        InlinedItemRef::ImplItem(d, ii) => {
-            InlinedItem::ImplItem(d, P(fold::noop_fold_impl_item(ii.clone(), &mut fld)))
-        }
-    };
-
-    (ii, fld.id_range)
-}
-
-fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
-    let chi_doc = item_doc.get(c::tag_tree as usize);
-    let mut rbml_r = reader::Decoder::new(chi_doc);
-    rbml_r.read_opaque(|decoder, _| Decodable::decode(decoder)).unwrap()
-}
-
-// ______________________________________________________________________
-// Encoding and decoding of ast::def
-
-fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> Def {
-    let def: Def = Decodable::decode(dsr).unwrap();
-    def.tr(dcx)
-}
-
-impl tr for Def {
-    fn tr(&self, dcx: &DecodeContext) -> Def {
-        match *self {
-          Def::Fn(did) => Def::Fn(did.tr(dcx)),
-          Def::Method(did) => Def::Method(did.tr(dcx)),
-          Def::SelfTy(opt_did, impl_id) => {
-              // Since the impl_id will never lie within the reserved range of
-              // imported NodeIds, it does not make sense to translate it.
-              // The result would not make any sense within the importing crate.
-              // We also don't allow for impl items to be inlined (just their
-              // members), so even if we had a DefId here, we wouldn't be able
-              // to do much with it.
-              // So, we set the id to DUMMY_NODE_ID. That way we make it
-              // explicit that this is no usable NodeId.
-              Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
-                          impl_id.map(|_| ast::DUMMY_NODE_ID))
-          }
-          Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
-          Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
-          Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
-          Def::Const(did) => { Def::Const(did.tr(dcx)) }
-          Def::AssociatedConst(did) => Def::AssociatedConst(did.tr(dcx)),
-          Def::Local(_, nid) => {
-              let nid = dcx.tr_id(nid);
-              let did = dcx.tcx.map.local_def_id(nid);
-              Def::Local(did, nid)
-          }
-          Def::Variant(e_did, v_did) => Def::Variant(e_did.tr(dcx), v_did.tr(dcx)),
-          Def::Trait(did) => Def::Trait(did.tr(dcx)),
-          Def::Enum(did) => Def::Enum(did.tr(dcx)),
-          Def::TyAlias(did) => Def::TyAlias(did.tr(dcx)),
-          Def::AssociatedTy(trait_did, did) =>
-              Def::AssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
-          Def::PrimTy(p) => Def::PrimTy(p),
-          Def::TyParam(did) => Def::TyParam(did.tr(dcx)),
-          Def::Upvar(_, nid1, index, nid2) => {
-              let nid1 = dcx.tr_id(nid1);
-              let nid2 = dcx.tr_id(nid2);
-              let did1 = dcx.tcx.map.local_def_id(nid1);
-              Def::Upvar(did1, nid1, index, nid2)
-          }
-          Def::Struct(did) => Def::Struct(did.tr(dcx)),
-          Def::Union(did) => Def::Union(did.tr(dcx)),
-          Def::Label(nid) => Def::Label(dcx.tr_id(nid)),
-          Def::Err => Def::Err,
-        }
-    }
-}
-
-// ______________________________________________________________________
-// Encoding and decoding of freevar information
-
-fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &hir::Freevar) {
-    (*fv).encode(rbml_w).unwrap();
-}
-
-trait rbml_decoder_helper {
-    fn read_freevar_entry(&mut self, dcx: &DecodeContext)
-                          -> hir::Freevar;
-    fn read_capture_mode(&mut self) -> hir::CaptureClause;
-}
-
-impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
-    fn read_freevar_entry(&mut self, dcx: &DecodeContext)
-                          -> hir::Freevar {
-        let fv: hir::Freevar = Decodable::decode(self).unwrap();
-        fv.tr(dcx)
-    }
-
-    fn read_capture_mode(&mut self) -> hir::CaptureClause {
-        let cm: hir::CaptureClause = Decodable::decode(self).unwrap();
-        cm
-    }
-}
-
-impl tr for hir::Freevar {
-    fn tr(&self, dcx: &DecodeContext) -> hir::Freevar {
-        hir::Freevar {
-            def: self.def.tr(dcx),
-            span: self.span.tr(dcx),
-        }
-    }
-}
-
-// ______________________________________________________________________
-// Encoding and decoding of MethodCallee
-
-trait read_method_callee_helper<'tcx> {
-    fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                  -> (u32, ty::MethodCallee<'tcx>);
-}
-
-fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
-                                  rbml_w: &mut Encoder,
-                                  autoderef: u32,
-                                  method: &ty::MethodCallee<'tcx>) {
-    use rustc_serialize::Encoder;
-
-    rbml_w.emit_struct("MethodCallee", 4, |rbml_w| {
-        rbml_w.emit_struct_field("autoderef", 0, |rbml_w| {
-            autoderef.encode(rbml_w)
-        });
-        rbml_w.emit_struct_field("def_id", 1, |rbml_w| {
-            Ok(rbml_w.emit_def_id(method.def_id))
-        });
-        rbml_w.emit_struct_field("ty", 2, |rbml_w| {
-            Ok(rbml_w.emit_ty(ecx, method.ty))
-        });
-        rbml_w.emit_struct_field("substs", 3, |rbml_w| {
-            Ok(rbml_w.emit_substs(ecx, &method.substs))
-        })
-    }).unwrap();
-}
-
-impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
-    fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                  -> (u32, ty::MethodCallee<'tcx>) {
-
-        self.read_struct("MethodCallee", 4, |this| {
-            let autoderef = this.read_struct_field("autoderef", 0,
-                                                   Decodable::decode).unwrap();
-            Ok((autoderef, ty::MethodCallee {
-                def_id: this.read_struct_field("def_id", 1, |this| {
-                    Ok(this.read_def_id(dcx))
-                }).unwrap(),
-                ty: this.read_struct_field("ty", 2, |this| {
-                    Ok(this.read_ty(dcx))
-                }).unwrap(),
-                substs: this.read_struct_field("substs", 3, |this| {
-                    Ok(this.read_substs(dcx))
-                }).unwrap()
-            }))
-        }).unwrap()
-    }
-}
-
-pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
-    kind.encode(ebml_w).unwrap();
-}
-
-// ______________________________________________________________________
-// Encoding and decoding the side tables
-
-trait rbml_writer_helpers<'tcx> {
-    fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region);
-    fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
-    fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                       substs: &Substs<'tcx>);
-    fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture);
-    fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                                adj: &adjustment::AutoAdjustment<'tcx>);
-    fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                        autoref: &adjustment::AutoRef<'tcx>);
-    fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                               auto_deref_ref: &adjustment::AutoDerefRef<'tcx>);
-}
-
-impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
-    fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) {
-        self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor,
-                                                        &ecx.ty_str_ctxt(),
-                                                        r)));
-    }
-
-    fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) {
-        self.emit_opaque(|this| Ok(tyencode::enc_ty(&mut this.cursor,
-                                                    &ecx.ty_str_ctxt(),
-                                                    ty)));
-    }
-
-    fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) {
-        use rustc_serialize::Encoder;
-
-        self.emit_enum("UpvarCapture", |this| {
-            match *capture {
-                ty::UpvarCapture::ByValue => {
-                    this.emit_enum_variant("ByValue", 1, 0, |_| Ok(()))
-                }
-                ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => {
-                    this.emit_enum_variant("ByRef", 2, 0, |this| {
-                        this.emit_enum_variant_arg(0,
-                            |this| kind.encode(this));
-                        this.emit_enum_variant_arg(1,
-                            |this| Ok(this.emit_region(ecx, region)))
-                    })
-                }
-            }
-        }).unwrap()
-    }
-
-    fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                       substs: &Substs<'tcx>) {
-        self.emit_opaque(|this| Ok(tyencode::enc_substs(&mut this.cursor,
-                                                        &ecx.ty_str_ctxt(),
-                                                        substs)));
-    }
-
-    fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                                adj: &adjustment::AutoAdjustment<'tcx>) {
-        use rustc_serialize::Encoder;
-
-        self.emit_enum("AutoAdjustment", |this| {
-            match *adj {
-                adjustment::AdjustReifyFnPointer => {
-                    this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(()))
-                }
-
-                adjustment::AdjustUnsafeFnPointer => {
-                    this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| {
-                        Ok(())
-                    })
-                }
-
-                adjustment::AdjustMutToConstPointer => {
-                    this.emit_enum_variant("AdjustMutToConstPointer", 3, 0, |_| {
-                        Ok(())
-                    })
-                }
-
-                adjustment::AdjustDerefRef(ref auto_deref_ref) => {
-                    this.emit_enum_variant("AdjustDerefRef", 4, 2, |this| {
-                        this.emit_enum_variant_arg(0,
-                            |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
-                    })
-                }
 
-                adjustment::AdjustNeverToAny(ref ty) => {
-                    this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, ty)))
-                    })
-                }
-            }
-        });
-    }
-
-    fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                        autoref: &adjustment::AutoRef<'tcx>) {
-        use rustc_serialize::Encoder;
-
-        self.emit_enum("AutoRef", |this| {
-            match autoref {
-                &adjustment::AutoPtr(r, m) => {
-                    this.emit_enum_variant("AutoPtr", 0, 2, |this| {
-                        this.emit_enum_variant_arg(0,
-                            |this| Ok(this.emit_region(ecx, r)));
-                        this.emit_enum_variant_arg(1, |this| m.encode(this))
-                    })
-                }
-                &adjustment::AutoUnsafe(m) => {
-                    this.emit_enum_variant("AutoUnsafe", 1, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| m.encode(this))
-                    })
-                }
-            }
-        });
-    }
-
-    fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
-                               auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) {
-        use rustc_serialize::Encoder;
-
-        self.emit_struct("AutoDerefRef", 2, |this| {
-            this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this));
+use rustc_serialize::Encodable;
 
-            this.emit_struct_field("autoref", 1, |this| {
-                this.emit_option(|this| {
-                    match auto_deref_ref.autoref {
-                        None => this.emit_option_none(),
-                        Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))),
-                    }
-                })
-            });
-
-            this.emit_struct_field("unsize", 2, |this| {
-                this.emit_option(|this| {
-                    match auto_deref_ref.unsize {
-                        None => this.emit_option_none(),
-                        Some(target) => this.emit_option_some(|this| {
-                            Ok(this.emit_ty(ecx, target))
-                        })
-                    }
-                })
-            })
-        });
-    }
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct Ast<'tcx> {
+    id_range: IdRange,
+    item: Lazy<InlinedItem>,
+    side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>
 }
 
-trait write_tag_and_id {
-    fn tag<F>(&mut self, tag_id: c::astencode_tag, f: F) where F: FnOnce(&mut Self);
-    fn id(&mut self, id: ast::NodeId);
+#[derive(RustcEncodable, RustcDecodable)]
+enum TableEntry<'tcx> {
+    Def(Def),
+    NodeType(Ty<'tcx>),
+    ItemSubsts(ty::ItemSubsts<'tcx>),
+    Adjustment(ty::adjustment::AutoAdjustment<'tcx>),
+    ConstQualif(ConstQualif)
 }
 
-impl<'a> write_tag_and_id for Encoder<'a> {
-    fn tag<F>(&mut self,
-              tag_id: c::astencode_tag,
-              f: F) where
-        F: FnOnce(&mut Encoder<'a>),
-    {
-        self.start_tag(tag_id as usize);
-        f(self);
-        self.end_tag();
-    }
-
-    fn id(&mut self, id: ast::NodeId) {
-        id.encode(self).unwrap();
-    }
-}
-
-struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
-    ecx: &'a e::EncodeContext<'c, 'tcx>,
-    rbml_w: &'a mut Encoder<'b>,
-}
-
-impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for
-        SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> {
-    fn visit_id(&mut self, id: ast::NodeId) {
-        encode_side_tables_for_id(self.ecx, self.rbml_w, id)
-    }
-}
-
-fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
-                             rbml_w: &mut Encoder,
-                             ii: &InlinedItem) {
-    rbml_w.start_tag(c::tag_table as usize);
-    ii.visit(&mut SideTableEncodingIdVisitor {
-        ecx: ecx,
-        rbml_w: rbml_w
-    });
-    rbml_w.end_tag();
-}
-
-fn encode_side_tables_for_id(ecx: &e::EncodeContext,
-                             rbml_w: &mut Encoder,
-                             id: ast::NodeId) {
-    let tcx = ecx.tcx;
-
-    debug!("Encoding side tables for id {}", id);
-
-    if let Some(def) = tcx.expect_def_or_none(id) {
-        rbml_w.tag(c::tag_table_def, |rbml_w| {
-            rbml_w.id(id);
-            def.encode(rbml_w).unwrap();
-        })
-    }
-
-    if let Some(ty) = tcx.node_types().get(&id) {
-        rbml_w.tag(c::tag_table_node_type, |rbml_w| {
-            rbml_w.id(id);
-            rbml_w.emit_ty(ecx, *ty);
-        })
-    }
-
-    if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) {
-        rbml_w.tag(c::tag_table_item_subst, |rbml_w| {
-            rbml_w.id(id);
-            rbml_w.emit_substs(ecx, &item_substs.substs);
-        })
-    }
-
-    if let Some(fv) = tcx.freevars.borrow().get(&id) {
-        rbml_w.tag(c::tag_table_freevars, |rbml_w| {
-            rbml_w.id(id);
-            rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| {
-                Ok(encode_freevar_entry(rbml_w, fv_entry))
-            });
-        });
-
-        for freevar in fv {
-            rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
-                rbml_w.id(id);
-
-                let var_id = freevar.def.var_id();
-                let upvar_id = ty::UpvarId {
-                    var_id: var_id,
-                    closure_expr_id: id
-                };
-                let upvar_capture = tcx.tables
-                                       .borrow()
-                                       .upvar_capture_map
-                                       .get(&upvar_id)
-                                       .unwrap()
-                                       .clone();
-                var_id.encode(rbml_w);
-                rbml_w.emit_upvar_capture(ecx, &upvar_capture);
-            })
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    pub fn encode_inlined_item(&mut self, ii: InlinedItemRef) -> Lazy<Ast<'tcx>> {
+        let mut id_visitor = IdRangeComputingVisitor::new();
+        match ii {
+            InlinedItemRef::Item(_, i) => id_visitor.visit_item(i),
+            InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti),
+            InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii)
         }
-    }
 
-    let method_call = ty::MethodCall::expr(id);
-    if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
-        rbml_w.tag(c::tag_table_method_map, |rbml_w| {
-            rbml_w.id(id);
-            encode_method_callee(ecx, rbml_w, method_call.autoderef, method)
-        })
-    }
-
-    if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) {
-        match *adjustment {
-            adjustment::AdjustDerefRef(ref adj) => {
-                for autoderef in 0..adj.autoderefs {
-                    let method_call = ty::MethodCall::autoderef(id, autoderef as u32);
-                    if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
-                        rbml_w.tag(c::tag_table_method_map, |rbml_w| {
-                            rbml_w.id(id);
-                            encode_method_callee(ecx, rbml_w,
-                                                 method_call.autoderef, method)
-                        })
-                    }
-                }
+        let ii_pos = self.position();
+        ii.encode(self).unwrap();
+
+        let tables_pos = self.position();
+        let tables_count = {
+            let mut visitor = SideTableEncodingIdVisitor {
+                ecx: self,
+                count: 0
+            };
+            match ii {
+                InlinedItemRef::Item(_, i) => visitor.visit_item(i),
+                InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti),
+                InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii)
             }
-            _ => {}
-        }
-
-        rbml_w.tag(c::tag_table_adjustments, |rbml_w| {
-            rbml_w.id(id);
-            rbml_w.emit_auto_adjustment(ecx, adjustment);
-        })
-    }
-
-    if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
-        rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
-            rbml_w.id(id);
-            encode_cast_kind(rbml_w, *cast_kind)
-        })
-    }
+            visitor.count
+        };
 
-    if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) {
-        rbml_w.tag(c::tag_table_const_qualif, |rbml_w| {
-            rbml_w.id(id);
-            qualif.encode(rbml_w).unwrap()
+        self.lazy(&Ast {
+            id_range: id_visitor.result(),
+            item: Lazy::with_position(ii_pos),
+            side_tables: LazySeq::with_position_and_length(tables_pos, tables_count)
         })
     }
 }
 
-trait doc_decoder_helpers: Sized {
-    fn as_int(&self) -> isize;
-    fn opt_child(&self, tag: c::astencode_tag) -> Option<Self>;
+struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> {
+    ecx: &'a mut EncodeContext<'b, 'tcx>,
+    count: usize
 }
 
-impl<'a> doc_decoder_helpers for rbml::Doc<'a> {
-    fn as_int(&self) -> isize { reader::doc_as_u64(*self) as isize }
-    fn opt_child(&self, tag: c::astencode_tag) -> Option<rbml::Doc<'a>> {
-        reader::maybe_get_doc(*self, tag as usize)
-    }
-}
-
-trait rbml_decoder_decoder_helpers<'tcx> {
-    fn read_ty_encoded<'a, 'b, F, R>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>,
-                                     f: F) -> R
-        where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R;
-
-    fn read_region<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx ty::Region;
-    fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
-    fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
-    fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                              -> ty::TraitRef<'tcx>;
-    fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                   -> ty::PolyTraitRef<'tcx>;
-    fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                              -> ty::Predicate<'tcx>;
-    fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                           -> &'tcx Substs<'tcx>;
-    fn read_upvar_capture<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                  -> ty::UpvarCapture<'tcx>;
-    fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                    -> adjustment::AutoAdjustment<'tcx>;
-    fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                 -> cast::CastKind;
-    fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                   -> adjustment::AutoDerefRef<'tcx>;
-    fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                            -> adjustment::AutoRef<'tcx>;
-
-    // Versions of the type reading functions that don't need the full
-    // DecodeContext.
-    fn read_ty_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         cdata: &cstore::CrateMetadata) -> Ty<'tcx>;
-    fn read_tys_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          cdata: &cstore::CrateMetadata) -> Vec<Ty<'tcx>>;
-    fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             cdata: &cstore::CrateMetadata)
-                             -> &'tcx Substs<'tcx>;
-}
-
-impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
-    fn read_ty_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>,
-                         cdata: &cstore::CrateMetadata)
-                         -> Ty<'tcx> {
-        self.read_opaque(|_, doc| {
-            Ok(
-                tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                                              &mut |id| decoder::translate_def_id(cdata, id))
-                    .parse_ty())
-        }).unwrap()
-    }
-
-    fn read_tys_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>,
-                          cdata: &cstore::CrateMetadata) -> Vec<Ty<'tcx>> {
-        self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) )
-            .unwrap()
-            .into_iter()
-            .collect()
-    }
-
-    fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>,
-                             cdata: &cstore::CrateMetadata)
-                             -> &'tcx Substs<'tcx>
-    {
-        self.read_opaque(|_, doc| {
-            Ok(
-                tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                                              &mut |id| decoder::translate_def_id(cdata, id))
-                    .parse_substs())
-        }).unwrap()
-    }
-
-    fn read_ty_encoded<'b, 'c, F, R>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>, op: F) -> R
-        where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R
-    {
-        return self.read_opaque(|_, doc| {
-            debug!("read_ty_encoded({})", type_string(doc));
-            Ok(op(
-                &mut tydecode::TyDecoder::with_doc(
-                    dcx.tcx, dcx.cdata.cnum, doc,
-                    &mut |d| convert_def_id(dcx, d))))
-        }).unwrap();
+impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
+    fn visit_id(&mut self, id: ast::NodeId) {
+        debug!("Encoding side tables for id {}", id);
 
-        fn type_string(doc: rbml::Doc) -> String {
-            let mut str = String::new();
-            for i in doc.start..doc.end {
-                str.push(doc.data[i] as char);
+        let tcx = self.ecx.tcx;
+        let mut encode = |entry: Option<TableEntry>| {
+            if let Some(entry) = entry {
+                (id, entry).encode(self.ecx).unwrap();
+                self.count += 1;
             }
-            str
-        }
-    }
-    fn read_region<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> &'tcx ty::Region {
-        // Note: regions types embed local node ids.  In principle, we
-        // should translate these node ids into the new decode
-        // context.  However, we do not bother, because region types
-        // are not used during trans. This also applies to read_ty.
-        return self.read_ty_encoded(dcx, |decoder| decoder.parse_region());
-    }
-    fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
-        return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty());
-    }
+        };
 
-    fn read_tys<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                        -> Vec<Ty<'tcx>> {
-        self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().into_iter().collect()
-    }
-
-    fn read_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                              -> ty::TraitRef<'tcx> {
-        self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())
-    }
-
-    fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                   -> ty::PolyTraitRef<'tcx> {
-        ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()))
-    }
-
-    fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                              -> ty::Predicate<'tcx>
-    {
-        self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate())
-    }
-
-    fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                           -> &'tcx Substs<'tcx> {
-        self.read_opaque(|_, doc| {
-            Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc,
-                                             &mut |d| convert_def_id(dcx, d))
-               .parse_substs())
-        }).unwrap()
-    }
-    fn read_upvar_capture<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                  -> ty::UpvarCapture<'tcx> {
-        self.read_enum("UpvarCapture", |this| {
-            let variants = ["ByValue", "ByRef"];
-            this.read_enum_variant(&variants, |this, i| {
-                Ok(match i {
-                    1 => ty::UpvarCapture::ByValue,
-                    2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                        kind: this.read_enum_variant_arg(0,
-                                  |this| Decodable::decode(this)).unwrap(),
-                        region: this.read_enum_variant_arg(1,
-                                    |this| Ok(this.read_region(dcx))).unwrap()
-                    }),
-                    _ => bug!("bad enum variant for ty::UpvarCapture")
-                })
-            })
-        }).unwrap()
-    }
-    fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                    -> adjustment::AutoAdjustment<'tcx> {
-        self.read_enum("AutoAdjustment", |this| {
-            let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer",
-                            "AdjustMutToConstPointer", "AdjustDerefRef",
-                            "AdjustNeverToAny"];
-            this.read_enum_variant(&variants, |this, i| {
-                Ok(match i {
-                    1 => adjustment::AdjustReifyFnPointer,
-                    2 => adjustment::AdjustUnsafeFnPointer,
-                    3 => adjustment::AdjustMutToConstPointer,
-                    4 => {
-                        let auto_deref_ref: adjustment::AutoDerefRef =
-                            this.read_enum_variant_arg(0,
-                                |this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
-
-                        adjustment::AdjustDerefRef(auto_deref_ref)
-                    }
-                    5 => {
-                        let ty: Ty<'tcx> = this.read_enum_variant_arg(0, |this| {
-                            Ok(this.read_ty(dcx))
-                        }).unwrap();
-
-                        adjustment::AdjustNeverToAny(ty)
-                    }
-                    _ => bug!("bad enum variant for adjustment::AutoAdjustment")
-                })
-            })
-        }).unwrap()
-    }
-
-    fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                   -> adjustment::AutoDerefRef<'tcx> {
-        self.read_struct("AutoDerefRef", 2, |this| {
-            Ok(adjustment::AutoDerefRef {
-                autoderefs: this.read_struct_field("autoderefs", 0, |this| {
-                    Decodable::decode(this)
-                }).unwrap(),
-                autoref: this.read_struct_field("autoref", 1, |this| {
-                    this.read_option(|this, b| {
-                        if b {
-                            Ok(Some(this.read_autoref(dcx)))
-                        } else {
-                            Ok(None)
-                        }
-                    })
-                }).unwrap(),
-                unsize: this.read_struct_field("unsize", 2, |this| {
-                    this.read_option(|this, b| {
-                        if b {
-                            Ok(Some(this.read_ty(dcx)))
-                        } else {
-                            Ok(None)
-                        }
-                    })
-                }).unwrap(),
-            })
-        }).unwrap()
-    }
-
-    fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                            -> adjustment::AutoRef<'tcx> {
-        self.read_enum("AutoRef", |this| {
-            let variants = ["AutoPtr", "AutoUnsafe"];
-            this.read_enum_variant(&variants, |this, i| {
-                Ok(match i {
-                    0 => {
-                        let r: &'tcx ty::Region =
-                            this.read_enum_variant_arg(0, |this| {
-                                Ok(this.read_region(dcx))
-                            }).unwrap();
-                        let m: hir::Mutability =
-                            this.read_enum_variant_arg(1, |this| {
-                                Decodable::decode(this)
-                            }).unwrap();
-
-                        adjustment::AutoPtr(r, m)
-                    }
-                    1 => {
-                        let m: hir::Mutability =
-                            this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
-
-                        adjustment::AutoUnsafe(m)
-                    }
-                    _ => bug!("bad enum variant for adjustment::AutoRef")
-                })
-            })
-        }).unwrap()
-    }
-
-    fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-                              -> cast::CastKind
-    {
-        Decodable::decode(self).unwrap()
+        encode(tcx.expect_def_or_none(id).map(TableEntry::Def));
+        encode(tcx.node_types().get(&id).cloned().map(TableEntry::NodeType));
+        encode(tcx.tables.borrow().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
+        encode(tcx.tables.borrow().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
+        encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
     }
 }
 
-// Converts a def-id that appears in a type.  The correct
-// translation will depend on what kind of def-id this is.
-// This is a subtle point: type definitions are not
-// inlined into the current crate, so if the def-id names
-// a nominal type or type alias, then it should be
-// translated to refer to the source crate.
-//
-// However, *type parameters* are cloned along with the function
-// they are attached to.  So we should translate those def-ids
-// to refer to the new, cloned copy of the type parameter.
-// We only see references to free type parameters in the body of
-// an inlined function. In such cases, we need the def-id to
-// be a local id so that the TypeContents code is able to lookup
-// the relevant info in the ty_param_defs table.
-//
-// *Region parameters*, unfortunately, are another kettle of fish.
-// In such cases, def_id's can appear in types to distinguish
-// shadowed bound regions and so forth. It doesn't actually
-// matter so much what we do to these, since regions are erased
-// at trans time, but it's good to keep them consistent just in
-// case. We translate them with `tr_def_id()` which will map
-// the crate numbers back to the original source crate.
-//
-// Scopes will end up as being totally bogus. This can actually
-// be fixed though.
-//
-// Unboxed closures are cloned along with the function being
-// inlined, and all side tables use interned node IDs, so we
-// translate their def IDs accordingly.
-//
-// It'd be really nice to refactor the type repr to not include
-// def-ids so that all these distinctions were unnecessary.
-fn convert_def_id(dcx: &DecodeContext,
-                  did: DefId)
-                  -> DefId {
-    let r = dcx.tr_def_id(did);
-    debug!("convert_def_id(did={:?})={:?}", did, r);
-    return r;
-}
-
-fn decode_side_tables(dcx: &DecodeContext,
-                      ast_doc: rbml::Doc) {
-    let tbl_doc = ast_doc.get(c::tag_table as usize);
-    for (tag, entry_doc) in reader::docs(tbl_doc) {
-        let mut entry_dsr = reader::Decoder::new(entry_doc);
-        let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap();
-        let id = dcx.tr_id(id0);
-
-        debug!(">> Side table document with tag 0x{:x} \
-                found for id {} (orig {})",
-               tag, id, id0);
-        let tag = tag as u32;
-        let decoded_tag: Option<c::astencode_tag> = c::astencode_tag::from_u32(tag);
-        match decoded_tag {
-            None => {
-                bug!("unknown tag found in side tables: {:x}", tag);
-            }
-            Some(value) => {
-                let val_dsr = &mut entry_dsr;
-
-                match value {
-                    c::tag_table_def => {
-                        let def = decode_def(dcx, val_dsr);
-                        dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def));
-                    }
-                    c::tag_table_node_type => {
-                        let ty = val_dsr.read_ty(dcx);
-                        debug!("inserting ty for node {}: {:?}",
-                               id,  ty);
-                        dcx.tcx.node_type_insert(id, ty);
-                    }
-                    c::tag_table_item_subst => {
-                        let item_substs = ty::ItemSubsts {
-                            substs: val_dsr.read_substs(dcx)
-                        };
-                        dcx.tcx.tables.borrow_mut().item_substs.insert(
-                            id, item_substs);
-                    }
-                    c::tag_table_freevars => {
-                        let fv_info = val_dsr.read_to_vec(|val_dsr| {
-                            Ok(val_dsr.read_freevar_entry(dcx))
-                        }).unwrap().into_iter().collect();
-                        dcx.tcx.freevars.borrow_mut().insert(id, fv_info);
-                    }
-                    c::tag_table_upvar_capture_map => {
-                        let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap();
-                        let upvar_id = ty::UpvarId {
-                            var_id: dcx.tr_id(var_id),
-                            closure_expr_id: id
-                        };
-                        let ub = val_dsr.read_upvar_capture(dcx);
-                        dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub);
-                    }
-                    c::tag_table_method_map => {
-                        let (autoderef, method) = val_dsr.read_method_callee(dcx);
-                        let method_call = ty::MethodCall {
-                            expr_id: id,
-                            autoderef: autoderef
-                        };
-                        dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method);
-                    }
-                    c::tag_table_adjustments => {
-                        let adj =
-                            val_dsr.read_auto_adjustment(dcx);
-                        dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj);
-                    }
-                    c::tag_table_cast_kinds => {
-                        let cast_kind =
-                            val_dsr.read_cast_kind(dcx);
-                        dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind);
-                    }
-                    c::tag_table_const_qualif => {
-                        let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap();
-                        dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif);
-                    }
-                    _ => {
-                        bug!("unknown tag found in side tables: {:x}", tag);
-                    }
-                }
-            }
-        }
+/// Decodes an item from its AST in the cdata's metadata and adds it to the
+/// ast-map.
+pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
+                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     parent_def_path: ast_map::DefPath,
+                                     parent_did: DefId,
+                                     ast: Ast<'tcx>,
+                                     orig_did: DefId)
+                                     -> &'tcx InlinedItem {
+    debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
 
-        debug!(">< Side table doc loaded");
-    }
-}
+    let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
+    let start = tcx.sess.reserve_node_ids(cnt);
+    let id_ranges = [ast.id_range, IdRange {
+        min: start,
+        max: ast::NodeId::new(start.as_usize() + cnt)
+    }];
 
-// copy the tcache entries from the original item to the new
-// inlined item
-fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) {
-    fn copy_item_type(dcx: &DecodeContext,
-                      inlined_id: ast::NodeId,
-                      remote_did: DefId) {
-        let inlined_did = dcx.tcx.map.local_def_id(inlined_id);
-        dcx.tcx.register_item_type(inlined_did,
-                                   dcx.tcx.lookup_item_type(remote_did));
+    let ii = ast.item.decode((cdata, tcx, id_ranges));
+    let ii = ast_map::map_decoded_item(&tcx.map,
+                                       parent_def_path,
+                                       parent_did,
+                                       ii,
+                                       tcx.sess.next_node_id());
 
-    }
-    // copy the entry for the item itself
     let item_node_id = match ii {
         &InlinedItem::Item(_, ref i) => i.id,
         &InlinedItem::TraitItem(_, ref ti) => ti.id,
         &InlinedItem::ImplItem(_, ref ii) => ii.id
     };
-    copy_item_type(dcx, item_node_id, orig_did);
+    let inlined_did = tcx.map.local_def_id(item_node_id);
+    tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did));
 
-    // copy the entries of inner items
-    if let &InlinedItem::Item(_, ref item) = ii {
-        match item.node {
-            hir::ItemEnum(ref def, _) => {
-                let orig_def = dcx.tcx.lookup_adt_def(orig_did);
-                for (i_variant, orig_variant) in
-                    def.variants.iter().zip(orig_def.variants.iter())
-                {
-                    debug!("astencode: copying variant {:?} => {:?}",
-                           orig_variant.did, i_variant.node.data.id());
-                    copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did);
-                }
+    for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
+        match entry {
+            TableEntry::Def(def) => {
+                tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def));
             }
-            hir::ItemStruct(ref def, _) => {
-                if !def.is_struct() {
-                    let ctor_did = dcx.tcx.lookup_adt_def(orig_did)
-                        .struct_variant().did;
-                    debug!("astencode: copying ctor {:?} => {:?}", ctor_did,
-                           def.id());
-                    copy_item_type(dcx, def.id(), ctor_did);
-                }
+            TableEntry::NodeType(ty) => {
+                tcx.node_type_insert(id, ty);
             }
-            _ => {}
-        }
-    }
-}
-
-fn inlined_item_id_range(ii: &InlinedItem) -> IdRange {
-    let mut visitor = IdRangeComputingVisitor::new();
-    ii.visit(&mut visitor);
-    visitor.result()
-}
-
-// ______________________________________________________________________
-// Testing of astencode_gen
-
-#[cfg(test)]
-fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) {
-    rbml_w.start_tag(c::tag_tree as usize);
-    (*item).encode(rbml_w);
-    rbml_w.end_tag();
-}
-
-#[cfg(test)]
-fn decode_item_ast(item_doc: rbml::Doc) -> hir::Item {
-    let chi_doc = item_doc.get(c::tag_tree as usize);
-    let mut d = reader::Decoder::new(chi_doc);
-    Decodable::decode(&mut d).unwrap()
-}
-
-#[cfg(test)]
-trait FakeExtCtxt {
-    fn call_site(&self) -> syntax_pos::Span;
-    fn cfg(&self) -> ast::CrateConfig;
-    fn ident_of(&self, st: &str) -> ast::Ident;
-    fn name_of(&self, st: &str) -> ast::Name;
-    fn parse_sess(&self) -> &parse::ParseSess;
-}
-
-#[cfg(test)]
-impl FakeExtCtxt for parse::ParseSess {
-    fn call_site(&self) -> syntax_pos::Span {
-        syntax_pos::Span {
-            lo: syntax_pos::BytePos(0),
-            hi: syntax_pos::BytePos(0),
-            expn_id: syntax_pos::NO_EXPANSION,
-        }
-    }
-    fn cfg(&self) -> ast::CrateConfig { Vec::new() }
-    fn ident_of(&self, st: &str) -> ast::Ident {
-        parse::token::str_to_ident(st)
-    }
-    fn name_of(&self, st: &str) -> ast::Name {
-        parse::token::intern(st)
-    }
-    fn parse_sess(&self) -> &parse::ParseSess { self }
-}
-
-#[cfg(test)]
-fn mk_ctxt() -> parse::ParseSess {
-    parse::ParseSess::new()
-}
-
-#[cfg(test)]
-fn with_testing_context<T, F: FnOnce(&mut LoweringContext) -> T>(f: F) -> T {
-    let mut resolver = DummyResolver;
-    let mut lcx = LoweringContext::testing_context(&mut resolver);
-    f(&mut lcx)
-}
-
-#[cfg(test)]
-fn roundtrip(in_item: hir::Item) {
-    let mut wr = Cursor::new(Vec::new());
-    encode_item_ast(&mut Encoder::new(&mut wr), &in_item);
-    let rbml_doc = rbml::Doc::new(wr.get_ref());
-    let out_item = decode_item_ast(rbml_doc);
-
-    assert!(in_item == out_item);
-}
-
-#[test]
-fn test_basic() {
-    let cx = mk_ctxt();
-    with_testing_context(|lcx| {
-        roundtrip(lcx.lower_item(&quote_item!(&cx,
-            fn foo() {}
-        ).unwrap()));
-    });
-}
-
-#[test]
-fn test_smalltalk() {
-    let cx = mk_ctxt();
-    with_testing_context(|lcx| {
-        roundtrip(lcx.lower_item(&quote_item!(&cx,
-            fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
-        ).unwrap()));
-    });
-}
-
-#[test]
-fn test_more() {
-    let cx = mk_ctxt();
-    with_testing_context(|lcx| {
-        roundtrip(lcx.lower_item(&quote_item!(&cx,
-            fn foo(x: usize, y: usize) -> usize {
-                let z = x + y;
-                return z;
+            TableEntry::ItemSubsts(item_substs) => {
+                tcx.tables.borrow_mut().item_substs.insert(id, item_substs);
             }
-        ).unwrap()));
-    });
-}
-
-#[test]
-fn test_simplification() {
-    use middle::cstore::LOCAL_CRATE;
-    use rustc::hir::def_id::CRATE_DEF_INDEX;
-
-    let cx = mk_ctxt();
-    let item = quote_item!(&cx,
-        fn new_int_alist<B>() -> alist<isize, B> {
-            fn eq_int(a: isize, b: isize) -> bool { a == b }
-            return alist {eq_fn: eq_int, data: Vec::new()};
-        }
-    ).unwrap();
-    let cx = mk_ctxt();
-    with_testing_context(|lcx| {
-        let hir_item = lcx.lower_item(&item);
-        let def_id = DefId { krate: LOCAL_CRATE, index: CRATE_DEF_INDEX }; // dummy
-        let item_in = InlinedItemRef::Item(def_id, &hir_item);
-        let (item_out, _) = simplify_ast(item_in);
-        let item_exp = InlinedItem::Item(def_id, P(lcx.lower_item(&quote_item!(&cx,
-            fn new_int_alist<B>() -> alist<isize, B> {
-                return alist {eq_fn: eq_int, data: Vec::new()};
+            TableEntry::Adjustment(adj) => {
+                tcx.tables.borrow_mut().adjustments.insert(id, adj);
             }
-        ).unwrap())));
-        match (item_out, item_exp) {
-            (InlinedItem::Item(_, item_out), InlinedItem::Item(_, item_exp)) => {
-                 assert!(pprust::item_to_string(&item_out) ==
-                         pprust::item_to_string(&item_exp));
+            TableEntry::ConstQualif(qualif) => {
+                tcx.const_qualif_map.borrow_mut().insert(id, qualif);
             }
-            _ => bug!()
         }
-    });
+    }
+
+    ii
 }
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
deleted file mode 100644
index 29b9cc0d1d9..00000000000
--- a/src/librustc_metadata/common.rs
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(non_camel_case_types, non_upper_case_globals)]
-
-pub use self::astencode_tag::*;
-
-// RBML enum definitions and utils shared by the encoder and decoder
-//
-// 0x00..0x1f: reserved for RBML generic type tags
-// 0x20..0xef: free for use, preferred for frequent tags
-// 0xf0..0xff: internally used by RBML to encode 0x100..0xfff in two bytes
-// 0x100..0xfff: free for use, preferred for infrequent tags
-
-pub const tag_items: usize = 0x100; // top-level only
-
-pub const tag_paths_data_name: usize = 0x20;
-
-pub const tag_def_id: usize = 0x21;
-
-pub const tag_items_data: usize = 0x22;
-
-pub const tag_items_data_item: usize = 0x23;
-
-pub const tag_items_data_item_family: usize = 0x24;
-
-pub const tag_items_data_item_type: usize = 0x25;
-
-// GAP 0x26
-
-pub const tag_items_data_item_variant: usize = 0x27;
-
-pub const tag_items_data_parent_item: usize = 0x28;
-
-pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29;
-
-pub const tag_items_closure_kind: usize = 0x2a;
-pub const tag_items_closure_ty: usize = 0x2b;
-pub const tag_def_key: usize = 0x2c;
-
-// GAP 0x2d 0x34
-
-pub const tag_index: usize = 0x110; // top-level only
-pub const tag_xref_index: usize = 0x111; // top-level only
-pub const tag_xref_data: usize = 0x112; // top-level only
-pub const tag_attributes: usize = 0x101; // top-level only
-
-// The list of crates that this crate depends on
-pub const tag_crate_deps: usize = 0x102; // top-level only
-
-// A single crate dependency
-pub const tag_crate_dep: usize = 0x35;
-
-pub const tag_crate_hash: usize = 0x103; // top-level only
-pub const tag_crate_crate_name: usize = 0x104; // top-level only
-pub const tag_crate_disambiguator: usize = 0x113; // top-level only
-
-pub const tag_crate_dep_crate_name: usize = 0x36;
-pub const tag_crate_dep_hash: usize = 0x37;
-pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only
-
-pub const tag_item_trait_item: usize = 0x3a;
-
-pub const tag_item_trait_ref: usize = 0x3b;
-
-// discriminator value for variants
-pub const tag_disr_val: usize = 0x3c;
-
-// GAP 0x3d, 0x3e, 0x3f, 0x40
-
-pub const tag_item_field: usize = 0x41;
-// GAP 0x42
-pub const tag_item_variances: usize = 0x43;
-/*
-  trait items contain tag_item_trait_item elements,
-  impl items contain tag_item_impl_item elements, and classes
-  have both. That's because some code treats classes like traits,
-  and other code treats them like impls. Because classes can contain
-  both, tag_item_trait_item and tag_item_impl_item have to be two
-  different tags.
- */
-pub const tag_item_impl_item: usize = 0x44;
-pub const tag_item_trait_method_explicit_self: usize = 0x45;
-
-
-// Reexports are found within module tags. Each reexport contains def_ids
-// and names.
-pub const tag_items_data_item_reexport: usize = 0x46;
-pub const tag_items_data_item_reexport_def_id: usize = 0x47;
-pub const tag_items_data_item_reexport_name: usize = 0x48;
-
-// used to encode crate_ctxt side tables
-enum_from_u32! {
-    #[derive(Copy, Clone, PartialEq)]
-    #[repr(usize)]
-    pub enum astencode_tag { // Reserves 0x50 -- 0x6f
-        tag_ast = 0x50,
-
-        tag_tree = 0x51,
-
-        tag_mir = 0x52,
-
-        tag_table = 0x53,
-        // GAP 0x54, 0x55
-        tag_table_def = 0x56,
-        tag_table_node_type = 0x57,
-        tag_table_item_subst = 0x58,
-        tag_table_freevars = 0x59,
-        // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e
-        tag_table_method_map = 0x5f,
-        // GAP 0x60
-        tag_table_adjustments = 0x61,
-        // GAP 0x62, 0x63, 0x64, 0x65
-        tag_table_upvar_capture_map = 0x66,
-        // GAP 0x67, 0x68
-        tag_table_const_qualif = 0x69,
-        tag_table_cast_kinds = 0x6a,
-    }
-}
-
-pub const tag_item_trait_item_sort: usize = 0x70;
-
-pub const tag_crate_triple: usize = 0x105; // top-level only
-
-pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only
-
-// Language items are a top-level directory (for speed). Hierarchy:
-//
-// tag_lang_items
-// - tag_lang_items_item
-//   - tag_lang_items_item_id: u32
-//   - tag_lang_items_item_index: u32
-
-pub const tag_lang_items: usize = 0x107; // top-level only
-pub const tag_lang_items_item: usize = 0x73;
-pub const tag_lang_items_item_id: usize = 0x74;
-pub const tag_lang_items_item_index: usize = 0x75;
-pub const tag_lang_items_missing: usize = 0x76;
-
-pub const tag_item_unnamed_field: usize = 0x77;
-pub const tag_items_data_item_visibility: usize = 0x78;
-pub const tag_items_data_item_inherent_impl: usize = 0x79;
-// GAP 0x7a
-pub const tag_mod_child: usize = 0x7b;
-// GAP 0x7c
-
-// GAP 0x108
-pub const tag_impls: usize = 0x109; // top-level only
-pub const tag_impls_trait: usize = 0x7d;
-pub const tag_impls_trait_impl: usize = 0x7e;
-
-// GAP 0x7f, 0x80, 0x81
-
-pub const tag_native_libraries: usize = 0x10a; // top-level only
-pub const tag_native_libraries_lib: usize = 0x82;
-pub const tag_native_libraries_name: usize = 0x83;
-pub const tag_native_libraries_kind: usize = 0x84;
-
-pub const tag_plugin_registrar_fn: usize = 0x10b; // top-level only
-
-pub const tag_method_argument_names: usize = 0x85;
-pub const tag_method_argument_name: usize = 0x86;
-
-pub const tag_reachable_ids: usize = 0x10c; // top-level only
-pub const tag_reachable_id: usize = 0x87;
-
-pub const tag_items_data_item_stability: usize = 0x88;
-
-pub const tag_items_data_item_repr: usize = 0x89;
-
-pub const tag_struct_fields: usize = 0x10d; // top-level only
-pub const tag_struct_field: usize = 0x8a;
-
-pub const tag_items_data_item_struct_ctor: usize = 0x8b;
-pub const tag_attribute_is_sugared_doc: usize = 0x8c;
-// GAP 0x8d
-pub const tag_items_data_region: usize = 0x8e;
-
-pub const tag_item_generics: usize = 0x8f;
-// GAP 0x90, 0x91, 0x92, 0x93, 0x94
-
-pub const tag_item_predicates: usize = 0x95;
-// GAP 0x96
-
-pub const tag_predicate: usize = 0x97;
-// GAP 0x98, 0x99
-
-pub const tag_unsafety: usize = 0x9a;
-
-pub const tag_associated_type_names: usize = 0x9b;
-pub const tag_associated_type_name: usize = 0x9c;
-
-pub const tag_polarity: usize = 0x9d;
-
-pub const tag_macro_defs: usize = 0x10e; // top-level only
-pub const tag_macro_def: usize = 0x9e;
-pub const tag_macro_def_body: usize = 0x9f;
-pub const tag_macro_def_span_lo: usize = 0xa8;
-pub const tag_macro_def_span_hi: usize = 0xa9;
-
-pub const tag_paren_sugar: usize = 0xa0;
-
-pub const tag_codemap: usize = 0xa1;
-pub const tag_codemap_filemap: usize = 0xa2;
-
-pub const tag_item_super_predicates: usize = 0xa3;
-
-pub const tag_defaulted_trait: usize = 0xa4;
-
-pub const tag_impl_coerce_unsized_kind: usize = 0xa5;
-
-pub const tag_items_data_item_constness: usize = 0xa6;
-
-pub const tag_items_data_item_deprecation: usize = 0xa7;
-
-pub const tag_items_data_item_defaultness: usize = 0xa8;
-
-pub const tag_items_data_parent_impl: usize = 0xa9;
-
-pub const tag_rustc_version: usize = 0x10f;
-pub fn rustc_version() -> String {
-    format!(
-        "rustc {}",
-        option_env!("CFG_VERSION").unwrap_or("unknown version")
-    )
-}
-
-pub const tag_panic_strategy: usize = 0x114;
-
-pub const tag_macro_derive_registrar: usize = 0x115;
-
-// NB: increment this if you change the format of metadata such that
-// rustc_version can't be found.
-pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2];
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index a1ade43f647..95be77c24f4 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -8,15 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
 //! Validates all used crates and extern libraries and loads their metadata
 
 use cstore::{self, CStore, CrateSource, MetadataBlob};
-use decoder;
 use loader::{self, CratePaths};
+use schema::CrateRoot;
 
-use rustc::hir::def_id::DefIndex;
+use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
 use rustc::dep_graph::{DepGraph, DepNode};
 use rustc::session::{config, Session};
@@ -27,18 +25,18 @@ use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc::hir::map as hir_map;
 
 use std::cell::{RefCell, Cell};
+use std::ops::Deref;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::fs;
 
 use syntax::ast;
 use syntax::abi::Abi;
-use syntax::codemap;
 use syntax::parse;
 use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax::visit;
-use syntax_pos::{self, Span, mk_sp, Pos};
+use syntax_pos::{self, Span, mk_sp};
 use log;
 
 struct LocalCrateReader<'a> {
@@ -52,7 +50,7 @@ struct LocalCrateReader<'a> {
 pub struct CrateReader<'a> {
     sess: &'a Session,
     cstore: &'a CStore,
-    next_crate_num: ast::CrateNum,
+    next_crate_num: CrateNum,
     foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
     local_crate_name: String,
     local_crate_config: ast::CrateConfig,
@@ -85,7 +83,7 @@ fn should_link(i: &ast::Item) -> bool {
 }
 
 #[derive(Debug)]
-struct CrateInfo {
+struct ExternCrateInfo {
     ident: String,
     name: String,
     id: ast::NodeId,
@@ -142,17 +140,19 @@ enum PMDSource {
     Owned(loader::Library),
 }
 
-impl PMDSource {
-    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
+impl Deref for PMDSource {
+    type Target = MetadataBlob;
+
+    fn deref(&self) -> &MetadataBlob {
         match *self {
-            PMDSource::Registered(ref cmd) => cmd.data(),
-            PMDSource::Owned(ref lib) => lib.metadata.as_slice(),
+            PMDSource::Registered(ref cmd) => &cmd.blob,
+            PMDSource::Owned(ref lib) => &lib.metadata
         }
     }
 }
 
 enum LoadResult {
-    Previous(ast::CrateNum),
+    Previous(CrateNum),
     Loaded(loader::Library),
 }
 
@@ -183,7 +183,7 @@ impl<'a> CrateReader<'a> {
         }
     }
 
-    fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
+    fn extract_crate_info(&self, i: &ast::Item) -> Option<ExternCrateInfo> {
         match i.node {
             ast::ItemKind::ExternCrate(ref path_opt) => {
                 debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
@@ -196,7 +196,7 @@ impl<'a> CrateReader<'a> {
                     }
                     None => i.ident.to_string(),
                 };
-                Some(CrateInfo {
+                Some(ExternCrateInfo {
                     ident: i.ident.to_string(),
                     name: name,
                     id: i.id,
@@ -208,7 +208,7 @@ impl<'a> CrateReader<'a> {
     }
 
     fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
-                      -> Option<ast::CrateNum> {
+                      -> Option<CrateNum> {
         let mut ret = None;
         self.cstore.iter_crate_data(|cnum, data| {
             if data.name != name { return }
@@ -258,32 +258,28 @@ impl<'a> CrateReader<'a> {
 
     fn verify_no_symbol_conflicts(&self,
                                   span: Span,
-                                  metadata: &MetadataBlob) {
-        let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice());
-        let crate_name = decoder::get_crate_name(metadata.as_slice());
-
+                                  root: &CrateRoot) {
         // Check for (potential) conflicts with the local crate
-        if self.local_crate_name == crate_name &&
-           self.sess.local_crate_disambiguator() == disambiguator {
+        if self.local_crate_name == root.name &&
+           self.sess.local_crate_disambiguator() == &root.disambiguator[..] {
             span_fatal!(self.sess, span, E0519,
                         "the current crate is indistinguishable from one of its \
                          dependencies: it has the same crate-name `{}` and was \
                          compiled with the same `-C metadata` arguments. This \
                          will result in symbol conflicts between the two.",
-                        crate_name)
+                        root.name)
         }
 
-        let svh = decoder::get_crate_hash(metadata.as_slice());
         // Check for conflicts with any crate loaded so far
         self.cstore.iter_crate_data(|_, other| {
-            if other.name() == crate_name && // same crate-name
-               other.disambiguator() == disambiguator &&  // same crate-disambiguator
-               other.hash() != svh { // but different SVH
+            if other.name() == root.name && // same crate-name
+               other.disambiguator() == root.disambiguator &&  // same crate-disambiguator
+               other.hash() != root.hash { // but different SVH
                 span_fatal!(self.sess, span, E0523,
                         "found two different crates with name `{}` that are \
                          not distinguished by differing `-C metadata`. This \
                          will result in symbol conflicts between the two.",
-                        crate_name)
+                        root.name)
             }
         });
     }
@@ -295,14 +291,15 @@ impl<'a> CrateReader<'a> {
                       span: Span,
                       lib: loader::Library,
                       explicitly_linked: bool)
-                      -> (ast::CrateNum, Rc<cstore::CrateMetadata>,
+                      -> (CrateNum, Rc<cstore::CrateMetadata>,
                           cstore::CrateSource) {
         info!("register crate `extern crate {} as {}`", name, ident);
-        self.verify_no_symbol_conflicts(span, &lib.metadata);
+        let crate_root = lib.metadata.get_root();
+        self.verify_no_symbol_conflicts(span, &crate_root);
 
         // Claim this crate number and cache it
         let cnum = self.next_crate_num;
-        self.next_crate_num += 1;
+        self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1);
 
         // Stash paths for top-most crate locally if necessary.
         let crate_paths = if root.is_none() {
@@ -319,28 +316,25 @@ impl<'a> CrateReader<'a> {
 
         let loader::Library { dylib, rlib, metadata } = lib;
 
-        let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span);
-        let staged_api = self.is_staged_api(metadata.as_slice());
+        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span);
+
+        if crate_root.macro_derive_registrar.is_some() {
+            self.sess.span_err(span, "crates of the `rustc-macro` crate type \
+                                      cannot be linked at runtime");
+        }
 
         let cmeta = Rc::new(cstore::CrateMetadata {
             name: name.to_string(),
             extern_crate: Cell::new(None),
-            index: decoder::load_index(metadata.as_slice()),
-            xref_index: decoder::load_xrefs(metadata.as_slice()),
-            key_map: decoder::load_key_map(metadata.as_slice()),
-            data: metadata,
+            key_map: metadata.load_key_map(crate_root.index),
+            root: crate_root,
+            blob: metadata,
             cnum_map: RefCell::new(cnum_map),
             cnum: cnum,
             codemap_import_info: RefCell::new(vec![]),
-            staged_api: staged_api,
             explicitly_linked: Cell::new(explicitly_linked),
         });
 
-        if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() {
-            self.sess.span_err(span, "crates of the `rustc-macro` crate type \
-                                      cannot be linked at runtime");
-        }
-
         let source = cstore::CrateSource {
             dylib: dylib,
             rlib: rlib,
@@ -352,16 +346,6 @@ impl<'a> CrateReader<'a> {
         (cnum, cmeta, source)
     }
 
-    fn is_staged_api(&self, data: &[u8]) -> bool {
-        let attrs = decoder::get_crate_attributes(data);
-        for attr in &attrs {
-            if attr.name() == "stable" || attr.name() == "unstable" {
-                return true
-            }
-        }
-        false
-    }
-
     fn resolve_crate(&mut self,
                      root: &Option<CratePaths>,
                      ident: &str,
@@ -370,7 +354,7 @@ impl<'a> CrateReader<'a> {
                      span: Span,
                      kind: PathKind,
                      explicitly_linked: bool)
-                     -> (ast::CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
+                     -> (CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
         info!("resolving crate `extern crate {} as {}`", name, ident);
         let result = match self.existing_match(name, hash, kind) {
             Some(cnum) => LoadResult::Previous(cnum),
@@ -428,13 +412,11 @@ impl<'a> CrateReader<'a> {
         // Note that we only do this for target triple crates, though, as we
         // don't want to match a host crate against an equivalent target one
         // already loaded.
+        let root = library.metadata.get_root();
         if loader.triple == self.sess.opts.target_triple {
-            let meta_hash = decoder::get_crate_hash(library.metadata.as_slice());
-            let meta_name = decoder::get_crate_name(library.metadata.as_slice())
-                                    .to_string();
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
-                if data.name() == meta_name && meta_hash == data.hash() {
+                if data.name() == root.name && root.hash == data.hash() {
                     assert!(loader.hash.is_none());
                     info!("load success, going to previous cnum: {}", cnum);
                     result = LoadResult::Previous(cnum);
@@ -447,9 +429,9 @@ impl<'a> CrateReader<'a> {
     }
 
     fn update_extern_crate(&mut self,
-                           cnum: ast::CrateNum,
+                           cnum: CrateNum,
                            mut extern_crate: ExternCrate,
-                           visited: &mut FnvHashSet<(ast::CrateNum, bool)>)
+                           visited: &mut FnvHashSet<(CrateNum, bool)>)
     {
         if !visited.insert((cnum, extern_crate.direct)) { return }
 
@@ -481,33 +463,37 @@ impl<'a> CrateReader<'a> {
     // Go through the crate metadata and load any crates that it references
     fn resolve_crate_deps(&mut self,
                           root: &Option<CratePaths>,
-                          cdata: &[u8],
-                          krate: ast::CrateNum,
+                          crate_root: &CrateRoot,
+                          metadata: &MetadataBlob,
+                          krate: CrateNum,
                           span: Span)
                           -> cstore::CrateNumMap {
         debug!("resolving deps of external crate");
         // The map from crate numbers in the crate we're resolving to local crate
         // numbers
-        let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| {
+        let deps = crate_root.crate_deps.decode(metadata);
+        let map: FnvHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| {
             debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
             let (local_cnum, ..) = self.resolve_crate(root,
-                                                        &dep.name,
-                                                        &dep.name,
+                                                        &dep.name.as_str(),
+                                                        &dep.name.as_str(),
                                                         Some(&dep.hash),
                                                         span,
                                                         PathKind::Dependency,
                                                         dep.explicitly_linked);
-            (dep.cnum, local_cnum)
+            (CrateNum::new(crate_num + 1), local_cnum)
         }).collect();
 
-        let max_cnum = map.values().cloned().max().unwrap_or(0);
+        let max_cnum = map.values().cloned().max().map(|cnum| cnum.as_u32()).unwrap_or(0);
 
         // we map 0 and all other holes in the map to our parent crate. The "additional"
         // self-dependencies should be harmless.
-        (0..max_cnum+1).map(|cnum| map.get(&cnum).cloned().unwrap_or(krate)).collect()
+        (0..max_cnum+1).map(|cnum| {
+            map.get(&CrateNum::from_u32(cnum)).cloned().unwrap_or(krate)
+        }).collect()
     }
 
-    fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
+    fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
         info!("read extension crate {} `extern crate {} as {}` linked={}",
               info.id, info.name, info.ident, info.should_link);
         let target_triple = &self.sess.opts.target_triple[..];
@@ -580,21 +566,21 @@ impl<'a> CrateReader<'a> {
         let ci = self.extract_crate_info(item).unwrap();
         let ekrate = self.read_extension_crate(item.span, &ci);
 
+        let root = ekrate.metadata.get_root();
         let source_name = format!("<{} macros>", item.ident);
         let mut ret = Macros {
             macro_rules: Vec::new(),
             custom_derive_registrar: None,
-            svh: decoder::get_crate_hash(ekrate.metadata.as_slice()),
+            svh: root.hash,
             dylib: None,
         };
-        decoder::each_exported_macro(ekrate.metadata.as_slice(),
-                                     |name, attrs, span, body| {
+        for def in root.macro_defs.decode(&*ekrate.metadata) {
             // NB: Don't use parse::parse_tts_from_source_str because it parses with
             // quote_depth > 0.
             let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
                                                           self.local_crate_config.clone(),
                                                           source_name.clone(),
-                                                          body);
+                                                          def.body);
             let lo = p.span.lo;
             let body = match p.parse_all_token_trees() {
                 Ok(body) => body,
@@ -607,13 +593,13 @@ impl<'a> CrateReader<'a> {
             let local_span = mk_sp(lo, p.last_span.hi);
 
             // Mark the attrs as used
-            for attr in &attrs {
+            for attr in &def.attrs {
                 attr::mark_used(attr);
             }
 
             ret.macro_rules.push(ast::MacroDef {
-                ident: ast::Ident::with_empty_ctxt(name),
-                attrs: attrs,
+                ident: ast::Ident::with_empty_ctxt(def.name),
+                attrs: def.attrs,
                 id: ast::DUMMY_NODE_ID,
                 span: local_span,
                 imported_from: Some(item.ident),
@@ -625,11 +611,10 @@ impl<'a> CrateReader<'a> {
                 body: body,
             });
             self.sess.imported_macro_spans.borrow_mut()
-                .insert(local_span, (name.as_str().to_string(), span));
-            true
-        });
+                .insert(local_span, (def.name.as_str().to_string(), def.span));
+        }
 
-        match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) {
+        match root.macro_derive_registrar {
             Some(id) => ret.custom_derive_registrar = Some(id),
 
             // If this crate is not a rustc-macro crate then we might be able to
@@ -666,7 +651,7 @@ impl<'a> CrateReader<'a> {
     /// SVH and DefIndex of the registrar function.
     pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
                                  -> Option<(PathBuf, Svh, DefIndex)> {
-        let ekrate = self.read_extension_crate(span, &CrateInfo {
+        let ekrate = self.read_extension_crate(span, &ExternCrateInfo {
              name: name.to_string(),
              ident: name.to_string(),
              id: ast::DUMMY_NODE_ID,
@@ -683,13 +668,10 @@ impl<'a> CrateReader<'a> {
             span_fatal!(self.sess, span, E0456, "{}", &message[..]);
         }
 
-        let svh = decoder::get_crate_hash(ekrate.metadata.as_slice());
-        let registrar =
-            decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice());
-
-        match (ekrate.dylib.as_ref(), registrar) {
+        let root = ekrate.metadata.get_root();
+        match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) {
             (Some(dylib), Some(reg)) => {
-                Some((dylib.to_path_buf(), svh, reg))
+                Some((dylib.to_path_buf(), root.hash, reg))
             }
             (None, Some(_)) => {
                 span_err!(self.sess, span, E0457,
@@ -875,7 +857,7 @@ impl<'a> CrateReader<'a> {
     }
 
     fn inject_dependency_if(&self,
-                            krate: ast::CrateNum,
+                            krate: CrateNum,
                             what: &str,
                             needs_dep: &Fn(&cstore::CrateMetadata) -> bool) {
         // don't perform this validation if the session has errors, as one of
@@ -1101,133 +1083,3 @@ pub fn read_local_crates(sess: & Session,
                          dep_graph: &DepGraph) {
     LocalCrateReader::new(sess, cstore, defs, krate, local_crate_name).read_crates(dep_graph)
 }
-
-/// Imports the codemap from an external crate into the codemap of the crate
-/// currently being compiled (the "local crate").
-///
-/// The import algorithm works analogous to how AST items are inlined from an
-/// external crate's metadata:
-/// For every FileMap in the external codemap an 'inline' copy is created in the
-/// local codemap. The correspondence relation between external and local
-/// FileMaps is recorded in the `ImportedFileMap` objects returned from this
-/// function. When an item from an external crate is later inlined into this
-/// crate, this correspondence information is used to translate the span
-/// information of the inlined item so that it refers the correct positions in
-/// the local codemap (see `astencode::DecodeContext::tr_span()`).
-///
-/// The import algorithm in the function below will reuse FileMaps already
-/// existing in the local codemap. For example, even if the FileMap of some
-/// source file of libstd gets imported many times, there will only ever be
-/// one FileMap object for the corresponding file in the local codemap.
-///
-/// Note that imported FileMaps do not actually contain the source code of the
-/// file they represent, just information about length, line breaks, and
-/// multibyte characters. This information is enough to generate valid debuginfo
-/// for items inlined from other crates.
-pub fn import_codemap(local_codemap: &codemap::CodeMap,
-                      metadata: &MetadataBlob)
-                      -> Vec<cstore::ImportedFileMap> {
-    let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());
-
-    let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
-        // Try to find an existing FileMap that can be reused for the filemap to
-        // be imported. A FileMap is reusable if it is exactly the same, just
-        // positioned at a different offset within the codemap.
-        let reusable_filemap = {
-            local_codemap.files
-                         .borrow()
-                         .iter()
-                         .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
-                         .map(|rc| rc.clone())
-        };
-
-        match reusable_filemap {
-            Some(fm) => {
-                cstore::ImportedFileMap {
-                    original_start_pos: filemap_to_import.start_pos,
-                    original_end_pos: filemap_to_import.end_pos,
-                    translated_filemap: fm
-                }
-            }
-            None => {
-                // We can't reuse an existing FileMap, so allocate a new one
-                // containing the information we need.
-                let syntax_pos::FileMap {
-                    name,
-                    abs_path,
-                    start_pos,
-                    end_pos,
-                    lines,
-                    multibyte_chars,
-                    ..
-                } = filemap_to_import;
-
-                let source_length = (end_pos - start_pos).to_usize();
-
-                // Translate line-start positions and multibyte character
-                // position into frame of reference local to file.
-                // `CodeMap::new_imported_filemap()` will then translate those
-                // coordinates to their new global frame of reference when the
-                // offset of the FileMap is known.
-                let mut lines = lines.into_inner();
-                for pos in &mut lines {
-                    *pos = *pos - start_pos;
-                }
-                let mut multibyte_chars = multibyte_chars.into_inner();
-                for mbc in &mut multibyte_chars {
-                    mbc.pos = mbc.pos - start_pos;
-                }
-
-                let local_version = local_codemap.new_imported_filemap(name,
-                                                                       abs_path,
-                                                                       source_length,
-                                                                       lines,
-                                                                       multibyte_chars);
-                cstore::ImportedFileMap {
-                    original_start_pos: start_pos,
-                    original_end_pos: end_pos,
-                    translated_filemap: local_version
-                }
-            }
-        }
-    }).collect();
-
-    return imported_filemaps;
-
-    fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap,
-                                 fm2: &syntax_pos::FileMap)
-                                 -> bool {
-        if fm1.name != fm2.name {
-            return false;
-        }
-
-        let lines1 = fm1.lines.borrow();
-        let lines2 = fm2.lines.borrow();
-
-        if lines1.len() != lines2.len() {
-            return false;
-        }
-
-        for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
-            if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
-                return false;
-            }
-        }
-
-        let multibytes1 = fm1.multibyte_chars.borrow();
-        let multibytes2 = fm2.multibyte_chars.borrow();
-
-        if multibytes1.len() != multibytes2.len() {
-            return false;
-        }
-
-        for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
-            if (mb1.bytes != mb2.bytes) ||
-               ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
-                return false;
-            }
-        }
-
-        true
-    }
-}
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 21cf3240321..1f25136ffe1 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -9,28 +9,25 @@
 // except according to those terms.
 
 use cstore;
-use common;
-use decoder;
 use encoder;
 use loader;
+use schema;
 
-use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike};
-use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
-use rustc::hir::def;
-use middle::lang_items;
-use rustc::ty::{self, Ty, TyCtxt, VariantKind};
-use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate};
+use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
+use rustc::hir::def::{self, Def};
+use rustc::middle::lang_items;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
 use rustc::hir::map::DefKey;
 use rustc::mir::repr::Mir;
 use rustc::mir::mir_map::MirMap;
-use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap};
+use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc::session::config::PanicStrategy;
 
-use std::cell::RefCell;
-use std::rc::Rc;
 use std::path::PathBuf;
 use syntax::ast;
 use syntax::attr;
@@ -40,255 +37,183 @@ use rustc_back::target::Target;
 use rustc::hir;
 
 impl<'tcx> CrateStore<'tcx> for cstore::CStore {
+    fn describe_def(&self, def: DefId) -> Option<Def> {
+        self.dep_graph.read(DepNode::MetaData(def));
+        self.get_crate_data(def.krate).get_def(def.index)
+    }
+
     fn stability(&self, def: DefId) -> Option<attr::Stability> {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_stability(&cdata, def.index)
+        self.get_crate_data(def.krate).get_stability(def.index)
     }
 
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_deprecation(&cdata, def.index)
+        self.get_crate_data(def.krate).get_deprecation(def.index)
     }
 
     fn visibility(&self, def: DefId) -> ty::Visibility {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_visibility(&cdata, def.index)
+        self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
     fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
     {
         assert!(!def_id.is_local());
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::closure_kind(&cdata, def_id.index)
+        self.get_crate_data(def_id.krate).closure_kind(def_id.index)
     }
 
     fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
         assert!(!def_id.is_local());
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::closure_ty(&cdata, def_id.index, tcx)
+        self.get_crate_data(def_id.krate).closure_ty(def_id.index, tcx)
     }
 
     fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_item_variances(&cdata, def.index)
-    }
-
-    fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_repr_attrs(&cdata, def.index)
+        self.get_crate_data(def.krate).get_item_variances(def.index)
     }
 
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> Ty<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_type(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_type(def.index, tcx)
     }
 
     fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                            -> ty::GenericPredicates<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_predicates(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_predicates(def.index, tcx)
     }
 
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_super_predicates(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_super_predicates(def.index, tcx)
     }
 
     fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> &'tcx ty::Generics<'tcx>
+                         -> ty::Generics<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_generics(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_generics(def.index, tcx)
     }
 
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::get_item_attrs(&cdata, def_id.index)
+        self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
     }
 
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_trait_def(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_trait_def(def.index, tcx)
     }
 
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_adt_def(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_adt_def(def.index, tcx)
     }
 
-    fn method_arg_names(&self, did: DefId) -> Vec<String>
+    fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
     {
         self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::get_method_arg_names(&cdata, did.index)
-    }
-
-    fn item_name(&self, def: DefId) -> ast::Name {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_item_name(&cdata, def.index)
-    }
-
-    fn opt_item_name(&self, def: DefId) -> Option<ast::Name> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::maybe_get_item_name(&cdata, def.index)
+        self.get_crate_data(did.krate).get_fn_arg_names(did.index)
     }
 
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let mut result = vec![];
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::each_inherent_implementation_for_type(&cdata, def_id.index,
-                                                       |iid| result.push(iid));
-        result
+        self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index)
     }
 
-    fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId>
+    fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
     {
-        self.dep_graph.read(DepNode::MetaData(def_id));
+        if let Some(def_id) = filter {
+            self.dep_graph.read(DepNode::MetaData(def_id));
+        }
         let mut result = vec![];
         self.iter_crate_data(|_, cdata| {
-            decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| {
-                result.push(iid)
-            })
+            cdata.get_implementations_for_trait(filter, &mut result)
         });
         result
     }
 
-    fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                  -> Vec<Rc<ty::Method<'tcx>>>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_provided_trait_methods(&cdata, def.index, tcx)
-    }
-
-    fn trait_item_def_ids(&self, def: DefId)
-                          -> Vec<ty::ImplOrTraitItemId>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_trait_item_def_ids(&cdata, def.index)
-    }
-
-    fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>
-    {
-        self.dep_graph.read(DepNode::MetaData(impl_def_id));
-        let cdata = self.get_crate_data(impl_def_id.krate);
-        decoder::get_impl_items(&cdata, impl_def_id.index)
+    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId> {
+        self.dep_graph.read(DepNode::MetaData(def_id));
+        let mut result = vec![];
+        self.get_crate_data(def_id.krate)
+            .each_child_of_item(def_id.index, |child| result.push(child.def_id));
+        result
     }
 
-    fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity>
+    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_impl_polarity(&cdata, def.index)
+        self.get_crate_data(def.krate).get_impl_polarity(def.index)
     }
 
     fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                           -> Option<ty::TraitRef<'tcx>>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_impl_trait(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_impl_trait(def.index, tcx)
     }
 
     fn custom_coerce_unsized_kind(&self, def: DefId)
                                   -> Option<ty::adjustment::CustomCoerceUnsized>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_custom_coerce_unsized_kind(&cdata, def.index)
-    }
-
-    // FIXME: killme
-    fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                             -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_associated_consts(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_custom_coerce_unsized_kind(def.index)
     }
 
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(impl_def));
-        let cdata = self.get_crate_data(impl_def.krate);
-        decoder::get_parent_impl(&*cdata, impl_def.index)
+        self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
     }
 
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::get_trait_of_item(&cdata, def_id.index)
+        self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
     }
 
     fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<ty::ImplOrTraitItem<'tcx>>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_impl_or_trait_item(&cdata, def.index, tcx)
+        self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx)
     }
 
     fn is_const_fn(&self, did: DefId) -> bool
     {
         self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::is_const_fn(&cdata, did.index)
+        self.get_crate_data(did.krate).is_const_fn(did.index)
     }
 
     fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
     {
         self.dep_graph.read(DepNode::MetaData(trait_def_id));
-        let cdata = self.get_crate_data(trait_def_id.krate);
-        decoder::is_defaulted_trait(&cdata, trait_def_id.index)
-    }
-
-    fn is_impl(&self, did: DefId) -> bool
-    {
-        self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::is_impl(&cdata, did.index)
+        self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index)
     }
 
     fn is_default_impl(&self, impl_did: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(impl_did));
-        let cdata = self.get_crate_data(impl_did.krate);
-        decoder::is_default_impl(&cdata, impl_did.index)
+        self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
     }
 
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::is_extern_item(&cdata, did.index, tcx)
+        self.get_crate_data(did.krate).is_extern_item(did.index, tcx)
     }
 
     fn is_foreign_item(&self, did: DefId) -> bool {
-        let cdata = self.get_crate_data(did.krate);
-        decoder::is_foreign_item(&cdata, did.index)
+        self.get_crate_data(did.krate).is_foreign_item(did.index)
     }
 
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool
@@ -296,129 +221,100 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         self.do_is_statically_included_foreign_item(id)
     }
 
-    fn is_typedef(&self, did: DefId) -> bool {
-        self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::is_typedef(&cdata, did.index)
-    }
-
-    fn dylib_dependency_formats(&self, cnum: ast::CrateNum)
-                                -> Vec<(ast::CrateNum, LinkagePreference)>
+    fn dylib_dependency_formats(&self, cnum: CrateNum)
+                                -> Vec<(CrateNum, LinkagePreference)>
     {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_dylib_dependency_formats(&cdata)
+        self.get_crate_data(cnum).get_dylib_dependency_formats()
     }
 
-    fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>
+    fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>
     {
-        let mut result = vec![];
-        let crate_data = self.get_crate_data(cnum);
-        decoder::each_lang_item(&crate_data, |did, lid| {
-            result.push((did, lid)); true
-        });
-        result
+        self.get_crate_data(cnum).get_lang_items()
     }
 
-    fn missing_lang_items(&self, cnum: ast::CrateNum)
+    fn missing_lang_items(&self, cnum: CrateNum)
                           -> Vec<lang_items::LangItem>
     {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_missing_lang_items(&cdata)
+        self.get_crate_data(cnum).get_missing_lang_items()
     }
 
-    fn is_staged_api(&self, cnum: ast::CrateNum) -> bool
+    fn is_staged_api(&self, cnum: CrateNum) -> bool
     {
-        self.get_crate_data(cnum).staged_api
+        self.get_crate_data(cnum).is_staged_api()
     }
 
-    fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool
+    fn is_explicitly_linked(&self, cnum: CrateNum) -> bool
     {
         self.get_crate_data(cnum).explicitly_linked.get()
     }
 
-    fn is_allocator(&self, cnum: ast::CrateNum) -> bool
+    fn is_allocator(&self, cnum: CrateNum) -> bool
     {
         self.get_crate_data(cnum).is_allocator()
     }
 
-    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool
+    fn is_panic_runtime(&self, cnum: CrateNum) -> bool
     {
         self.get_crate_data(cnum).is_panic_runtime()
     }
 
-    fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool {
+    fn is_compiler_builtins(&self, cnum: CrateNum) -> bool {
         self.get_crate_data(cnum).is_compiler_builtins()
     }
 
-    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
+    fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy {
         self.get_crate_data(cnum).panic_strategy()
     }
 
-    fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
-    {
-        decoder::get_crate_attributes(self.get_crate_data(cnum).data())
-    }
-
-    fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
+    fn crate_name(&self, cnum: CrateNum) -> token::InternedString
     {
         token::intern_and_get_ident(&self.get_crate_data(cnum).name[..])
     }
 
-    fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
+    fn original_crate_name(&self, cnum: CrateNum) -> token::InternedString
     {
         token::intern_and_get_ident(&self.get_crate_data(cnum).name())
     }
 
-    fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>
+    fn extern_crate(&self, cnum: CrateNum) -> Option<ExternCrate>
     {
         self.get_crate_data(cnum).extern_crate.get()
     }
 
-    fn crate_hash(&self, cnum: ast::CrateNum) -> Svh
+    fn crate_hash(&self, cnum: CrateNum) -> Svh
     {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_crate_hash(cdata.data())
+        self.get_crate_hash(cnum)
     }
 
-    fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString
+    fn crate_disambiguator(&self, cnum: CrateNum) -> token::InternedString
     {
-        let cdata = self.get_crate_data(cnum);
-        token::intern_and_get_ident(decoder::get_crate_disambiguator(cdata.data()))
+        token::intern_and_get_ident(&self.get_crate_data(cnum).disambiguator())
     }
 
-    fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-                                -> FnvHashMap<DefId, Vec<ast::Attribute>>
+    fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
     {
-        decoder::get_struct_field_attrs(&self.get_crate_data(cnum))
-    }
-
-    fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>
-    {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_plugin_registrar_fn(cdata.data()).map(|index| DefId {
+        self.get_crate_data(cnum).root.plugin_registrar_fn.map(|index| DefId {
             krate: cnum,
             index: index
         })
     }
 
-    fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>
+    fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>
     {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_native_libraries(&cdata)
+        self.get_crate_data(cnum).get_native_libraries()
     }
 
-    fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>
+    fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>
     {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_reachable_ids(&cdata)
+        self.get_crate_data(cnum).get_reachable_ids()
     }
 
-    fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool {
-        attr::contains_name(&self.crate_attrs(cnum), "no_builtins")
+    fn is_no_builtins(&self, cnum: CrateNum) -> bool {
+        self.get_crate_data(cnum).is_no_builtins()
     }
 
     fn def_index_for_def_key(&self,
-                             cnum: ast::CrateNum,
+                             cnum: CrateNum,
                              def: DefKey)
                              -> Option<DefIndex> {
         let cdata = self.get_crate_data(cnum);
@@ -435,8 +331,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         // canonical name for an item.
         //
         // self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::def_key(&cdata, def.index)
+        self.get_crate_data(def.krate).def_key(def.index)
     }
 
     fn relative_def_path(&self, def: DefId) -> Option<hir_map::DefPath> {
@@ -444,57 +339,33 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         // commented out:
         //
         // self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::def_path(&cdata, def.index)
+        self.get_crate_data(def.krate).def_path(def.index)
     }
 
-    fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
+    fn variant_kind(&self, def_id: DefId) -> Option<ty::VariantKind>
+    {
         self.dep_graph.read(DepNode::MetaData(def_id));
-        let cdata = self.get_crate_data(def_id.krate);
-        decoder::get_variant_kind(&cdata, def_id.index)
+        self.get_crate_data(def_id.krate).get_variant_kind(def_id.index)
     }
 
     fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
     {
         self.dep_graph.read(DepNode::MetaData(struct_def_id));
-        let cdata = self.get_crate_data(struct_def_id.krate);
-        decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index)
-    }
-
-    fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
-    {
-        self.dep_graph.read(DepNode::MetaData(did));
-        let cdata = self.get_crate_data(did.krate);
-        decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index)
+        self.get_crate_data(struct_def_id.krate).get_struct_ctor_def_id(struct_def_id.index)
     }
 
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_struct_field_names(&cdata, def.index)
+        self.get_crate_data(def.krate).get_struct_field_names(def.index)
     }
 
-    fn item_children(&self, def_id: DefId) -> Vec<ChildItem>
+    fn item_children(&self, def_id: DefId) -> Vec<def::Export>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
         let mut result = vec![];
-        let crate_data = self.get_crate_data(def_id.krate);
-        let get_crate_data = |cnum| self.get_crate_data(cnum);
-        decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, |def, name, vis| {
-            result.push(ChildItem { def: def, name: name, vis: vis });
-        });
-        result
-    }
-
-    fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec<ChildItem>
-    {
-        let mut result = vec![];
-        let crate_data = self.get_crate_data(cnum);
-        let get_crate_data = |cnum| self.get_crate_data(cnum);
-        decoder::each_top_level_item_of_crate(&crate_data, get_crate_data, |def, name, vis| {
-            result.push(ChildItem { def: def, name: name, vis: vis });
-        });
+        self.get_crate_data(def_id.krate)
+            .each_child_of_item(def_id.index, |child| result.push(child));
         result
     }
 
@@ -523,8 +394,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
         debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id));
 
-        let cdata = self.get_crate_data(def_id.krate);
-        let inlined = decoder::maybe_get_item_ast(&cdata, tcx, def_id.index);
+        let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index);
 
         let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
             let cache_entry = cstore::CachedInlinedItem {
@@ -557,45 +427,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         };
 
         match inlined {
-            decoder::FoundAst::NotFound => {
+            None => {
                 self.inlined_item_cache
                     .borrow_mut()
                     .insert(def_id, None);
             }
-            decoder::FoundAst::Found(&InlinedItem::Item(d, ref item)) => {
+            Some(&InlinedItem::Item(d, ref item)) => {
                 assert_eq!(d, def_id);
                 let inlined_root_node_id = find_inlined_item_root(item.id);
                 cache_inlined_item(def_id, item.id, inlined_root_node_id);
             }
-            decoder::FoundAst::FoundParent(parent_did, item) => {
-                let inlined_root_node_id = find_inlined_item_root(item.id);
-                cache_inlined_item(parent_did, item.id, inlined_root_node_id);
-
-                match item.node {
-                    hir::ItemEnum(ref ast_def, _) => {
-                        let ast_vs = &ast_def.variants;
-                        let ty_vs = &tcx.lookup_adt_def(parent_did).variants;
-                        assert_eq!(ast_vs.len(), ty_vs.len());
-                        for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
-                            cache_inlined_item(ty_v.did,
-                                               ast_v.node.data.id(),
-                                               inlined_root_node_id);
-                        }
-                    }
-                    hir::ItemStruct(ref struct_def, _) => {
-                        if struct_def.is_struct() {
-                            bug!("instantiate_inline: called on a non-tuple struct")
-                        } else {
-                            cache_inlined_item(def_id,
-                                               struct_def.id(),
-                                               inlined_root_node_id);
-                        }
-                    }
-                    _ => bug!("instantiate_inline: item has a \
-                               non-enum, non-struct parent")
-                }
-            }
-            decoder::FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => {
+            Some(&InlinedItem::TraitItem(_, ref trait_item)) => {
                 let inlined_root_node_id = find_inlined_item_root(trait_item.id);
                 cache_inlined_item(def_id, trait_item.id, inlined_root_node_id);
 
@@ -608,7 +450,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                 tcx.impl_or_trait_items.borrow_mut()
                    .insert(trait_item_def_id, ty_trait_item);
             }
-            decoder::FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => {
+            Some(&InlinedItem::ImplItem(_, ref impl_item)) => {
                 let inlined_root_node_id = find_inlined_item_root(impl_item.id);
                 cache_inlined_item(def_id, impl_item.id, inlined_root_node_id);
             }
@@ -640,17 +482,15 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<Mir<'tcx>> {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::maybe_get_item_mir(&cdata, tcx, def.index)
+        self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index)
     }
 
     fn is_item_mir_available(&self, def: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::is_item_mir_available(&cdata, def.index)
+        self.get_crate_data(def.krate).is_item_mir_available(def.index)
     }
 
-    fn crates(&self) -> Vec<ast::CrateNum>
+    fn crates(&self) -> Vec<CrateNum>
     {
         let mut result = vec![];
         self.iter_crate_data(|cnum, _| result.push(cnum));
@@ -676,26 +516,18 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     {
         loader::meta_section_name(target)
     }
-    fn encode_type<'a>(&self,
-                       tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                       ty: Ty<'tcx>,
-                       def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
-                       -> Vec<u8>
-    {
-        encoder::encoded_ty(tcx, ty, def_id_to_string)
-    }
 
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
     {
         self.do_get_used_crates(prefer)
     }
 
-    fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource
+    fn used_crate_source(&self, cnum: CrateNum) -> CrateSource
     {
         self.opt_used_crate_source(cnum).unwrap()
     }
 
-    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>
+    fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>
     {
         self.do_extern_mod_stmt_cnum(emod_id)
     }
@@ -704,26 +536,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                            reexports: &def::ExportMap,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
-                           mir_map: &MirMap<'tcx>,
-                           krate: &hir::Crate) -> Vec<u8>
-    {
-        let ecx = encoder::EncodeContext {
-            diag: tcx.sess.diagnostic(),
-            tcx: tcx,
-            reexports: reexports,
-            link_meta: link_meta,
-            cstore: self,
-            reachable: reachable,
-            mir_map: mir_map,
-            type_abbrevs: RefCell::new(FnvHashMap()),
-        };
-        encoder::encode_metadata(ecx, krate)
-
+                           mir_map: &MirMap<'tcx>) -> Vec<u8>
+    {
+        encoder::encode_metadata(tcx, self, reexports, link_meta, reachable, mir_map)
     }
 
     fn metadata_encoding_version(&self) -> &[u8]
     {
-        common::metadata_encoding_version
+        schema::METADATA_HEADER
     }
 
     /// Returns a map from a sufficiently visible external item (i.e. an external item that is
@@ -733,10 +553,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         let mut visible_parent_map = self.visible_parent_map.borrow_mut();
         if !visible_parent_map.is_empty() { return visible_parent_map; }
 
-        use rustc::middle::cstore::ChildItem;
         use std::collections::vec_deque::VecDeque;
         use std::collections::hash_map::Entry;
-        for cnum in 1 .. self.next_crate_num() {
+        for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) {
             let cdata = self.get_crate_data(cnum);
 
             match cdata.extern_crate.get() {
@@ -746,11 +565,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             }
 
             let mut bfs_queue = &mut VecDeque::new();
-            let mut add_child = |bfs_queue: &mut VecDeque<_>, child: ChildItem, parent: DefId| {
-                let child = match child.def {
-                    DefLike::DlDef(def) if child.vis == ty::Visibility::Public => def.def_id(),
-                    _ => return,
-                };
+            let mut add_child = |bfs_queue: &mut VecDeque<_>, child: def::Export, parent: DefId| {
+                let child = child.def_id;
+
+                if self.visibility(child) != ty::Visibility::Public {
+                    return;
+                }
 
                 match visible_parent_map.entry(child) {
                     Entry::Occupied(mut entry) => {
@@ -767,10 +587,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                 }
             };
 
-            let croot = DefId { krate: cnum, index: CRATE_DEF_INDEX };
-            for child in self.crate_top_level_items(cnum) {
-                add_child(bfs_queue, child, croot);
-            }
+            bfs_queue.push_back(DefId {
+                krate: cnum,
+                index: CRATE_DEF_INDEX
+            });
             while let Some(def) = bfs_queue.pop_front() {
                 for child in self.item_children(def) {
                     add_child(bfs_queue, child, def);
@@ -781,4 +601,3 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         visible_parent_map
     }
 }
-
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index bc3d92c11a1..0a1ff70a049 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -8,21 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
 // The crate store - a central repo for information collected about external
 // crates and libraries
 
-pub use self::MetadataBlob::*;
-
-use common;
-use creader;
-use decoder;
-use index;
 use loader;
+use schema;
 
 use rustc::dep_graph::DepGraph;
-use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
 use rustc::hir::map::DefKey;
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::ExternCrate;
@@ -30,32 +23,31 @@ use rustc::session::config::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
 
-use std::cell::{RefCell, Ref, Cell};
+use std::cell::{RefCell, Cell};
 use std::rc::Rc;
 use std::path::PathBuf;
 use flate::Bytes;
 use syntax::ast::{self, Ident};
 use syntax::attr;
-use syntax::codemap;
 use syntax_pos;
 
-pub use middle::cstore::{NativeLibraryKind, LinkagePreference};
-pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
-pub use middle::cstore::{CrateSource, LinkMeta};
+pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference};
+pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
+pub use rustc::middle::cstore::{CrateSource, LinkMeta};
 
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
 // crate may refer to types in other external crates, and each has their
 // own crate numbers.
-pub type CrateNumMap = IndexVec<ast::CrateNum, ast::CrateNum>;
+pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
 
 pub enum MetadataBlob {
-    MetadataVec(Bytes),
-    MetadataArchive(loader::ArchiveMetadata),
+    Inflated(Bytes),
+    Archive(loader::ArchiveMetadata),
 }
 
 /// Holds information about a syntax_pos::FileMap imported from another crate.
-/// See creader::import_codemap() for more information.
+/// See `imported_filemaps()` for more information.
 pub struct ImportedFileMap {
     /// This FileMap's byte-offset within the codemap of its original crate
     pub original_start_pos: syntax_pos::BytePos,
@@ -73,14 +65,12 @@ pub struct CrateMetadata {
     /// (e.g., by the allocator)
     pub extern_crate: Cell<Option<ExternCrate>>,
 
-    pub data: MetadataBlob,
+    pub blob: MetadataBlob,
     pub cnum_map: RefCell<CrateNumMap>,
-    pub cnum: ast::CrateNum,
+    pub cnum: CrateNum,
     pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
-    pub staged_api: bool,
 
-    pub index: index::Index,
-    pub xref_index: index::DenseIndex,
+    pub root: schema::CrateRoot,
 
     /// For each public item in this crate, we encode a key.  When the
     /// crate is loaded, we read all the keys and put them in this
@@ -105,9 +95,9 @@ pub struct CachedInlinedItem {
 
 pub struct CStore {
     pub dep_graph: DepGraph,
-    metas: RefCell<FnvHashMap<ast::CrateNum, Rc<CrateMetadata>>>,
+    metas: RefCell<FnvHashMap<CrateNum, Rc<CrateMetadata>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
-    extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
+    extern_mod_crate_map: RefCell<NodeMap<CrateNum>>,
     used_crate_sources: RefCell<Vec<CrateSource>>,
     used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
     used_link_args: RefCell<Vec<String>>,
@@ -135,25 +125,24 @@ impl CStore {
         }
     }
 
-    pub fn next_crate_num(&self) -> ast::CrateNum {
-        self.metas.borrow().len() as ast::CrateNum + 1
+    pub fn next_crate_num(&self) -> CrateNum {
+        CrateNum::new(self.metas.borrow().len() + 1)
     }
 
-    pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc<CrateMetadata> {
+    pub fn get_crate_data(&self, cnum: CrateNum) -> Rc<CrateMetadata> {
         self.metas.borrow().get(&cnum).unwrap().clone()
     }
 
-    pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh {
-        let cdata = self.get_crate_data(cnum);
-        decoder::get_crate_hash(cdata.data())
+    pub fn get_crate_hash(&self, cnum: CrateNum) -> Svh {
+        self.get_crate_data(cnum).hash()
     }
 
-    pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc<CrateMetadata>) {
+    pub fn set_crate_data(&self, cnum: CrateNum, data: Rc<CrateMetadata>) {
         self.metas.borrow_mut().insert(cnum, data);
     }
 
     pub fn iter_crate_data<I>(&self, mut i: I) where
-        I: FnMut(ast::CrateNum, &Rc<CrateMetadata>),
+        I: FnMut(CrateNum, &Rc<CrateMetadata>),
     {
         for (&k, v) in self.metas.borrow().iter() {
             i(k, v);
@@ -162,7 +151,7 @@ impl CStore {
 
     /// Like `iter_crate_data`, but passes source paths (if available) as well.
     pub fn iter_crate_data_origins<I>(&self, mut i: I) where
-        I: FnMut(ast::CrateNum, &CrateMetadata, Option<CrateSource>),
+        I: FnMut(CrateNum, &CrateMetadata, Option<CrateSource>),
     {
         for (&k, v) in self.metas.borrow().iter() {
             let origin = self.opt_used_crate_source(k);
@@ -178,7 +167,7 @@ impl CStore {
         }
     }
 
-    pub fn opt_used_crate_source(&self, cnum: ast::CrateNum)
+    pub fn opt_used_crate_source(&self, cnum: CrateNum)
                                  -> Option<CrateSource> {
         self.used_crate_sources.borrow_mut()
             .iter().find(|source| source.cnum == cnum).cloned()
@@ -193,7 +182,7 @@ impl CStore {
         self.statically_included_foreign_items.borrow_mut().clear();
     }
 
-    pub fn crate_dependencies_in_rpo(&self, krate: ast::CrateNum) -> Vec<ast::CrateNum>
+    pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum>
     {
         let mut ordering = Vec::new();
         self.push_dependencies_in_postorder(&mut ordering, krate);
@@ -202,8 +191,8 @@ impl CStore {
     }
 
     pub fn push_dependencies_in_postorder(&self,
-                                          ordering: &mut Vec<ast::CrateNum>,
-                                          krate: ast::CrateNum)
+                                          ordering: &mut Vec<CrateNum>,
+                                          krate: CrateNum)
     {
         if ordering.contains(&krate) { return }
 
@@ -227,7 +216,7 @@ impl CStore {
     // topological sort of all crates putting the leaves at the right-most
     // positions.
     pub fn do_get_used_crates(&self, prefer: LinkagePreference)
-                              -> Vec<(ast::CrateNum, Option<PathBuf>)> {
+                              -> Vec<(CrateNum, Option<PathBuf>)> {
         let mut ordering = Vec::new();
         for (&num, _) in self.metas.borrow().iter() {
             self.push_dependencies_in_postorder(&mut ordering, num);
@@ -272,7 +261,7 @@ impl CStore {
 
     pub fn add_extern_mod_stmt_cnum(&self,
                                     emod_id: ast::NodeId,
-                                    cnum: ast::CrateNum) {
+                                    cnum: CrateNum) {
         self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
     }
 
@@ -284,7 +273,7 @@ impl CStore {
         self.statically_included_foreign_items.borrow().contains(&id)
     }
 
-    pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>
+    pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>
     {
         self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
     }
@@ -299,80 +288,47 @@ impl CStore {
 }
 
 impl CrateMetadata {
-    pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
-    pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) }
-    pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
-    pub fn disambiguator(&self) -> &str {
-        decoder::get_crate_disambiguator(self.data())
-    }
-    pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
-                                 -> Ref<'a, Vec<ImportedFileMap>> {
-        let filemaps = self.codemap_import_info.borrow();
-        if filemaps.is_empty() {
-            drop(filemaps);
-            let filemaps = creader::import_codemap(codemap, &self.data);
-
-            // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
-            *self.codemap_import_info.borrow_mut() = filemaps;
-            self.codemap_import_info.borrow()
-        } else {
-            filemaps
-        }
+    pub fn name(&self) -> &str { &self.root.name }
+    pub fn hash(&self) -> Svh { self.root.hash }
+    pub fn disambiguator(&self) -> &str { &self.root.disambiguator }
+
+    pub fn is_staged_api(&self) -> bool {
+        self.get_item_attrs(CRATE_DEF_INDEX).iter().any(|attr| {
+            attr.name() == "stable" || attr.name() == "unstable"
+        })
     }
 
     pub fn is_allocator(&self) -> bool {
-        let attrs = decoder::get_crate_attributes(self.data());
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "allocator")
     }
 
     pub fn needs_allocator(&self) -> bool {
-        let attrs = decoder::get_crate_attributes(self.data());
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "needs_allocator")
     }
 
     pub fn is_panic_runtime(&self) -> bool {
-        let attrs = decoder::get_crate_attributes(self.data());
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "panic_runtime")
     }
 
     pub fn needs_panic_runtime(&self) -> bool {
-        let attrs = decoder::get_crate_attributes(self.data());
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "needs_panic_runtime")
     }
 
     pub fn is_compiler_builtins(&self) -> bool {
-        let attrs = decoder::get_crate_attributes(self.data());
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
         attr::contains_name(&attrs, "compiler_builtins")
     }
 
-    pub fn panic_strategy(&self) -> PanicStrategy {
-        decoder::get_panic_strategy(self.data())
+    pub fn is_no_builtins(&self) -> bool {
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
+        attr::contains_name(&attrs, "no_builtins")
     }
-}
 
-impl MetadataBlob {
-    pub fn as_slice_raw<'a>(&'a self) -> &'a [u8] {
-        match *self {
-            MetadataVec(ref vec) => &vec[..],
-            MetadataArchive(ref ar) => ar.as_slice(),
-        }
-    }
-
-    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
-        let slice = self.as_slice_raw();
-        let len_offset = 4 + common::metadata_encoding_version.len();
-        if slice.len() < len_offset+4 {
-            &[] // corrupt metadata
-        } else {
-            let len = (((slice[len_offset+0] as u32) << 24) |
-                       ((slice[len_offset+1] as u32) << 16) |
-                       ((slice[len_offset+2] as u32) << 8) |
-                       ((slice[len_offset+3] as u32) << 0)) as usize;
-            if len <= slice.len() - 4 - len_offset {
-                &slice[len_offset + 4..len_offset + len + 4]
-            } else {
-                &[] // corrupt or old metadata
-            }
-        }
+    pub fn panic_strategy(&self) -> PanicStrategy {
+        self.root.panic_strategy.clone()
     }
 }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 624bffb7e03..3e4a2542b27 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -10,1637 +10,1132 @@
 
 // Decoding metadata from a single crate's metadata
 
-#![allow(non_camel_case_types)]
-
-use self::Family::*;
-
 use astencode::decode_inlined_item;
-use cstore::{self, CrateMetadata};
-use common::*;
-use def_key;
-use encoder::def_to_u64;
-use index;
-use tls_context;
-use tydecode::TyDecoder;
-
-use rustc::hir::def_id::CRATE_DEF_INDEX;
-use rustc::hir::svh::Svh;
+use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind};
+use index::Index;
+use schema::*;
+
 use rustc::hir::map as hir_map;
-use rustc::hir::map::DefKey;
+use rustc::hir::map::{DefKey, DefPathData};
 use rustc::util::nodemap::FnvHashMap;
 use rustc::hir;
-use rustc::session::config::PanicStrategy;
+use rustc::hir::intravisit::IdRange;
 
-use middle::cstore::{InlinedItem, LinkagePreference};
-use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
-use rustc::hir::def::Def;
-use rustc::hir::def_id::{DefId, DefIndex};
-use middle::lang_items;
-use rustc::ty::{ImplContainer, TraitContainer};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind};
+use rustc::middle::cstore::{InlinedItem, LinkagePreference};
+use rustc::hir::def::{self, Def};
+use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
+use rustc::middle::lang_items;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 
 use rustc_const_math::ConstInt;
 
-use rustc::mir;
-use rustc::mir::visit::MutVisitor;
-use rustc::mir::repr::Location;
+use rustc::mir::repr::Mir;
 
-use std::cell::Cell;
+use std::cell::Ref;
 use std::io;
+use std::mem;
 use std::rc::Rc;
 use std::str;
+use std::u32;
 
-use rbml::reader;
-use rbml;
-use rustc_serialize::Decodable;
+use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
-use syntax::parse::token;
-use syntax::ast;
+use syntax::ast::{self, NodeId};
 use syntax::codemap;
-use syntax::print::pprust;
-use syntax_pos::{self, Span, BytePos, NO_EXPANSION};
+use syntax_pos::{self, Span, BytePos, Pos};
 
-pub type Cmd<'a> = &'a CrateMetadata;
+pub struct DecodeContext<'a, 'tcx: 'a> {
+    opaque: opaque::Decoder<'a>,
+    tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
+    cdata: Option<&'a CrateMetadata>,
+    from_id_range: IdRange,
+    to_id_range: IdRange,
 
-impl CrateMetadata {
-    fn get_item(&self, item_id: DefIndex) -> Option<rbml::Doc> {
-        self.index.lookup_item(self.data(), item_id).map(|pos| {
-            reader::doc_at(self.data(), pos as usize).unwrap().doc
-        })
-    }
+    // Cache the last used filemap for translating spans as an optimization.
+    last_filemap_index: usize,
 
-    fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
-        match self.get_item(item_id) {
-            None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}",
-                         item_id,
-                         self.name,
-                         self.cnum),
-            Some(d) => d
-        }
-    }
+    lazy_state: LazyState
 }
 
-pub fn load_index(data: &[u8]) -> index::Index {
-    let index = reader::get_doc(rbml::Doc::new(data), tag_index);
-    index::Index::from_rbml(index)
-}
+/// Abstract over the various ways one can create metadata decoders.
+pub trait Metadata<'a, 'tcx>: Copy {
+    fn raw_bytes(self) -> &'a [u8];
+    fn cdata(self) -> Option<&'a CrateMetadata> { None }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None }
 
-pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
-    let doc = rbml::Doc::new(data);
-    reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string())
+    fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
+        let id_range = IdRange {
+            min: NodeId::from_u32(u32::MIN),
+            max: NodeId::from_u32(u32::MAX)
+        };
+        DecodeContext {
+            opaque: opaque::Decoder::new(self.raw_bytes(), pos),
+            cdata: self.cdata(),
+            tcx: self.tcx(),
+            from_id_range: id_range,
+            to_id_range: id_range,
+            last_filemap_index: 0,
+            lazy_state: LazyState::NoNode
+        }
+    }
 }
 
-pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
-    let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index);
-    index::DenseIndex::from_buf(index.data, index.start, index.end)
+impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
+    fn raw_bytes(self) -> &'a [u8] {
+        match *self {
+            MetadataBlob::Inflated(ref vec) => &vec[..],
+            MetadataBlob::Archive(ref ar) => ar.as_slice(),
+        }
+    }
 }
 
-// Go through each item in the metadata and create a map from that
-// item's def-key to the item's DefIndex.
-pub fn load_key_map(data: &[u8]) -> FnvHashMap<DefKey, DefIndex> {
-    let root_doc = rbml::Doc::new(data);
-    let items_doc = reader::get_doc(root_doc, tag_items);
-    let items_data_doc = reader::get_doc(items_doc, tag_items_data);
-    reader::docs(items_data_doc)
-        .filter(|&(tag, _)| tag == tag_items_data_item)
-        .map(|(_, item_doc)| {
-            // load def-key from item
-            let key = item_def_key(item_doc);
-
-            // load def-index from item; we only encode the full def-id,
-            // so just pull out the index
-            let def_id_doc = reader::get_doc(item_doc, tag_def_id);
-            let def_id = untranslated_def_id(def_id_doc);
-            assert!(def_id.is_local()); // local to the crate we are decoding, that is
-
-            (key, def_id.index)
-        })
-        .collect()
+impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata {
+    fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self) }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum Family {
-    ImmStatic,             // c
-    MutStatic,             // b
-    Fn,                    // f
-    StaticMethod,          // F
-    Method,                // h
-    Type,                  // y
-    Mod,                   // m
-    ForeignMod,            // n
-    Enum,                  // t
-    Variant(VariantKind),  // V, v, w
-    Impl,                  // i
-    DefaultImpl,           // d
-    Trait,                 // I
-    Struct(VariantKind),   // S, s, u
-    Union,                 // U
-    PublicField,           // g
-    InheritedField,        // N
-    Constant,              // C
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) {
+    fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { Some(self.1) }
 }
 
-fn item_family(item: rbml::Doc) -> Family {
-    let fam = reader::get_doc(item, tag_items_data_item_family);
-    match reader::doc_as_u8(fam) as char {
-      'C' => Constant,
-      'c' => ImmStatic,
-      'b' => MutStatic,
-      'f' => Fn,
-      'F' => StaticMethod,
-      'h' => Method,
-      'y' => Type,
-      'm' => Mod,
-      'n' => ForeignMod,
-      't' => Enum,
-      'V' => Variant(VariantKind::Struct),
-      'v' => Variant(VariantKind::Tuple),
-      'w' => Variant(VariantKind::Unit),
-      'i' => Impl,
-      'd' => DefaultImpl,
-      'I' => Trait,
-      'S' => Struct(VariantKind::Struct),
-      's' => Struct(VariantKind::Tuple),
-      'u' => Struct(VariantKind::Unit),
-      'U' => Union,
-      'g' => PublicField,
-      'N' => InheritedField,
-       c => bug!("unexpected family char: {}", c)
+// HACK(eddyb) Only used by astencode to customize the from/to IdRange's.
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) {
+    fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { Some(self.1) }
+
+    fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
+        let mut dcx = (self.0, self.1).decoder(pos);
+        dcx.from_id_range = self.2[0];
+        dcx.to_id_range = self.2[1];
+        dcx
     }
 }
 
-fn item_visibility(item: rbml::Doc) -> ty::Visibility {
-    match reader::maybe_get_doc(item, tag_items_data_item_visibility) {
-        None => ty::Visibility::Public,
-        Some(visibility_doc) => {
-            match reader::doc_as_u8(visibility_doc) as char {
-                'y' => ty::Visibility::Public,
-                'i' => ty::Visibility::PrivateExternal,
-                _ => bug!("unknown visibility character")
-            }
-        }
+impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
+    pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
+        let mut dcx = meta.decoder(self.position);
+        dcx.lazy_state = LazyState::NodeStart(self.position);
+        T::decode(&mut dcx).unwrap()
     }
 }
 
-fn fn_constness(item: rbml::Doc) -> hir::Constness {
-    match reader::maybe_get_doc(item, tag_items_data_item_constness) {
-        None => hir::Constness::NotConst,
-        Some(constness_doc) => {
-            match reader::doc_as_u8(constness_doc) as char {
-                'c' => hir::Constness::Const,
-                'n' => hir::Constness::NotConst,
-                _ => bug!("unknown constness character")
-            }
-        }
+impl<'a, 'tcx: 'a, T: Decodable> LazySeq<T> {
+    pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> impl Iterator<Item=T> + 'a {
+        let mut dcx = meta.decoder(self.position);
+        dcx.lazy_state = LazyState::NodeStart(self.position);
+        (0..self.len).map(move |_| {
+            T::decode(&mut dcx).unwrap()
+        })
     }
 }
 
-fn item_defaultness(item: rbml::Doc) -> hir::Defaultness {
-    match reader::maybe_get_doc(item, tag_items_data_item_defaultness) {
-        None => hir::Defaultness::Default, // should occur only for default impls on traits
-        Some(defaultness_doc) => {
-            match reader::doc_as_u8(defaultness_doc) as char {
-                'd' => hir::Defaultness::Default,
-                'f' => hir::Defaultness::Final,
-                _ => bug!("unknown defaultness character")
-            }
-        }
+impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx.expect("missing TyCtxt in DecodeContext")
     }
-}
 
-fn item_sort(item: rbml::Doc) -> Option<char> {
-    reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
-        doc.as_str().as_bytes()[0] as char
-    })
-}
+    pub fn cdata(&self) -> &'a CrateMetadata {
+        self.cdata.expect("missing CrateMetadata in DecodeContext")
+    }
 
-fn untranslated_def_id(d: rbml::Doc) -> DefId {
-    let id = reader::doc_as_u64(d);
-    let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
-    DefId { krate: (id >> 32) as u32, index: index }
-}
+    fn with_position<F: FnOnce(&mut Self) -> R, R>(&mut self, pos: usize, f: F) -> R {
+        let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
+        let old_opaque = mem::replace(&mut self.opaque, new_opaque);
+        let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
+        let r = f(self);
+        self.opaque = old_opaque;
+        self.lazy_state = old_state;
+        r
+    }
 
-fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
-    let def_id = untranslated_def_id(d);
-    translate_def_id(cdata, def_id)
+    fn read_lazy_distance(&mut self, min_size: usize)
+                          -> Result<usize, <Self as Decoder>::Error> {
+        let distance = self.read_usize()?;
+        let position = match self.lazy_state {
+            LazyState::NoNode => {
+                bug!("read_lazy_distance: outside of a metadata node")
+            }
+            LazyState::NodeStart(start) => {
+                assert!(distance + min_size <= start);
+                start - distance - min_size
+            }
+            LazyState::Previous(last_min_end) => {
+                last_min_end + distance
+            }
+        };
+        self.lazy_state = LazyState::Previous(position + min_size);
+        Ok(position)
+    }
 }
 
-fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option<DefId> {
-    reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| {
-        translated_def_id(cdata, did)
-    })
+macro_rules! decoder_methods {
+    ($($name:ident -> $ty:ty;)*) => {
+        $(fn $name(&mut self) -> Result<$ty, Self::Error> {
+            self.opaque.$name()
+        })*
+    }
 }
 
-fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId {
-    translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item))
-}
+impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
+    type Error = <opaque::Decoder<'doc> as Decoder>::Error;
 
-fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId {
-    translated_def_id(cdata, reader::get_doc(d, tag_def_id))
-}
+    decoder_methods! {
+        read_nil -> ();
 
-fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
-    reader::tagged_docs(d, tag_items_data_item_reexport)
-}
+        read_u64 -> u64;
+        read_u32 -> u32;
+        read_u16 -> u16;
+        read_u8 -> u8;
+        read_usize -> usize;
 
-fn variant_disr_val(d: rbml::Doc) -> u64 {
-    let val_doc = reader::get_doc(d, tag_disr_val);
-    reader::with_doc_data(val_doc, |data| {
-        str::from_utf8(data).unwrap().parse().unwrap()
-    })
-}
+        read_i64 -> i64;
+        read_i32 -> i32;
+        read_i16 -> i16;
+        read_i8 -> i8;
+        read_isize -> isize;
 
-fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> {
-    let tp = reader::get_doc(doc, tag_items_data_item_type);
-    TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                        &mut |did| translate_def_id(cdata, did))
-        .parse_ty()
-}
+        read_bool -> bool;
+        read_f64 -> f64;
+        read_f32 -> f32;
+        read_char -> char;
+        read_str -> String;
+    }
 
-fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                            -> Option<Ty<'tcx>> {
-    reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
-        TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                            &mut |did| translate_def_id(cdata, did))
-            .parse_ty()
-    })
+    fn error(&mut self, err: &str) -> Self::Error {
+        self.opaque.error(err)
+    }
 }
 
-fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                           -> ty::TraitRef<'tcx> {
-    TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                        &mut |did| translate_def_id(cdata, did))
-        .parse_trait_ref()
+impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> {
+        Ok(Lazy::with_position(self.read_lazy_distance(Lazy::<T>::min_size())?))
+    }
 }
 
-fn item_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                            -> ty::TraitRef<'tcx> {
-    let tp = reader::get_doc(doc, tag_item_trait_ref);
-    doc_trait_ref(tp, tcx, cdata)
+impl<'a, 'tcx, T> SpecializedDecoder<LazySeq<T>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<LazySeq<T>, Self::Error> {
+        let len = self.read_usize()?;
+        let position = if len == 0 {
+            0
+        } else {
+            self.read_lazy_distance(LazySeq::<T>::min_size(len))?
+        };
+        Ok(LazySeq::with_position_and_length(position, len))
+    }
 }
 
-fn item_name(item: rbml::Doc) -> ast::Name {
-    maybe_item_name(item).expect("no item in item_name")
-}
+impl<'a, 'tcx> SpecializedDecoder<NodeId> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
+        let id = u32::decode(self)?;
 
-fn maybe_item_name(item: rbml::Doc) -> Option<ast::Name> {
-    reader::maybe_get_doc(item, tag_paths_data_name).map(|name| {
-        let string = name.as_str();
-        token::intern(string)
-    })
-}
+        // from_id_range should be non-empty
+        assert!(!self.from_id_range.empty());
+        // Make sure that translating the NodeId will actually yield a
+        // meaningful result
+        if !self.from_id_range.contains(NodeId::from_u32(id)) {
+            bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})",
+                 id, self.from_id_range, self.to_id_range);
+        }
 
-fn family_to_variant_kind<'tcx>(family: Family) -> Option<ty::VariantKind> {
-    match family {
-        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) | Union =>
-            Some(ty::VariantKind::Struct),
-        Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
-            Some(ty::VariantKind::Tuple),
-        Struct(VariantKind::Unit) | Variant(VariantKind::Unit) =>
-            Some(ty::VariantKind::Unit),
-        _ => None,
+        // Use wrapping arithmetic because otherwise it introduces control flow.
+        // Maybe we should just have the control flow? -- aatch
+        Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32())
+                              .wrapping_add(self.to_id_range.min.as_u32())))
     }
 }
 
-fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
-    let fam = item_family(item);
-    match fam {
-        Constant  => {
-            // Check whether we have an associated const item.
-            match item_sort(item) {
-                Some('C') | Some('c') => {
-                    DlDef(Def::AssociatedConst(did))
-                }
-                _ => {
-                    // Regular const item.
-                    DlDef(Def::Const(did))
-                }
-            }
-        }
-        ImmStatic => DlDef(Def::Static(did, false)),
-        MutStatic => DlDef(Def::Static(did, true)),
-        Struct(..) => DlDef(Def::Struct(did)),
-        Union => DlDef(Def::Union(did)),
-        Fn        => DlDef(Def::Fn(did)),
-        Method | StaticMethod => {
-            DlDef(Def::Method(did))
-        }
-        Type => {
-            if item_sort(item) == Some('t') {
-                let trait_did = item_require_parent_item(cdata, item);
-                DlDef(Def::AssociatedTy(trait_did, did))
-            } else {
-                DlDef(Def::TyAlias(did))
-            }
-        }
-        Mod => DlDef(Def::Mod(did)),
-        ForeignMod => DlDef(Def::ForeignMod(did)),
-        Variant(..) => {
-            let enum_did = item_require_parent_item(cdata, item);
-            DlDef(Def::Variant(enum_did, did))
+impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
+        let cnum = CrateNum::from_u32(u32::decode(self)?);
+        if cnum == LOCAL_CRATE {
+            Ok(self.cdata().cnum)
+        } else {
+            Ok(self.cdata().cnum_map.borrow()[cnum])
         }
-        Trait => DlDef(Def::Trait(did)),
-        Enum => DlDef(Def::Enum(did)),
-        Impl | DefaultImpl => DlImpl(did),
-        PublicField | InheritedField => DlField,
     }
 }
 
-fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety {
-    let unsafety_doc = reader::get_doc(item_doc, tag_unsafety);
-    if reader::doc_as_u8(unsafety_doc) != 0 {
-        hir::Unsafety::Unsafe
-    } else {
-        hir::Unsafety::Normal
-    }
-}
+impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
+        let lo = BytePos::decode(self)?;
+        let hi = BytePos::decode(self)?;
 
-fn parse_paren_sugar(item_doc: rbml::Doc) -> bool {
-    let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar);
-    reader::doc_as_u8(paren_sugar_doc) != 0
-}
+        let tcx = if let Some(tcx) = self.tcx {
+            tcx
+        } else {
+            return Ok(syntax_pos::mk_sp(lo, hi));
+        };
 
-fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity {
-    let polarity_doc = reader::get_doc(item_doc, tag_polarity);
-    if reader::doc_as_u8(polarity_doc) != 0 {
-        hir::ImplPolarity::Negative
-    } else {
-        hir::ImplPolarity::Positive
-    }
-}
+        let (lo, hi) = if lo > hi {
+            // Currently macro expansion sometimes produces invalid Span values
+            // where lo > hi. In order not to crash the compiler when trying to
+            // translate these values, let's transform them into something we
+            // can handle (and which will produce useful debug locations at
+            // least some of the time).
+            // This workaround is only necessary as long as macro expansion is
+            // not fixed. FIXME(#23480)
+            (lo, lo)
+        } else {
+            (lo, hi)
+        };
 
-fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
-    let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
-    reader::tagged_docs(names_doc, tag_associated_type_name)
-        .map(|name_doc| token::intern(name_doc.as_str()))
-        .collect()
-}
+        let imported_filemaps = self.cdata().imported_filemaps(&tcx.sess.codemap());
+        let filemap = {
+            // Optimize for the case that most spans within a translated item
+            // originate from the same filemap.
+            let last_filemap = &imported_filemaps[self.last_filemap_index];
+
+            if lo >= last_filemap.original_start_pos &&
+            lo <= last_filemap.original_end_pos &&
+            hi >= last_filemap.original_start_pos &&
+            hi <= last_filemap.original_end_pos {
+                last_filemap
+            } else {
+                let mut a = 0;
+                let mut b = imported_filemaps.len();
 
-pub fn get_trait_def<'a, 'tcx>(cdata: Cmd,
-                               item_id: DefIndex,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    let generics = doc_generics(item_doc, tcx, cdata);
-    let unsafety = parse_unsafety(item_doc);
-    let associated_type_names = parse_associated_type_names(item_doc);
-    let paren_sugar = parse_paren_sugar(item_doc);
-    let def_path = def_path(cdata, item_id).unwrap();
-
-    ty::TraitDef::new(unsafety,
-                      paren_sugar,
-                      generics,
-                      item_trait_ref(item_doc, tcx, cdata),
-                      associated_type_names,
-                      def_path.deterministic_hash(tcx))
-}
+                while b - a > 1 {
+                    let m = (a + b) / 2;
+                    if imported_filemaps[m].original_start_pos > lo {
+                        b = m;
+                    } else {
+                        a = m;
+                    }
+                }
 
-pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
-                             item_id: DefIndex,
-                             tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                             -> ty::AdtDefMaster<'tcx>
-{
-    fn expect_variant_kind(family: Family) -> ty::VariantKind {
-        match family_to_variant_kind(family) {
-            Some(kind) => kind,
-            _ => bug!("unexpected family: {:?}", family),
-        }
-    }
-    fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec<ty::VariantDefData<'tcx, 'tcx>> {
-        reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
-            let did = translated_def_id(cdata, p);
-            let item = cdata.lookup_item(did.index);
-            let disr = variant_disr_val(item);
-            ty::VariantDefData {
-                did: did,
-                name: item_name(item),
-                fields: get_variant_fields(cdata, item),
-                disr_val: ConstInt::Infer(disr),
-                kind: expect_variant_kind(item_family(item)),
+                self.last_filemap_index = a;
+                &imported_filemaps[a]
             }
-        }).collect()
-    }
-    fn get_variant_fields<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec<ty::FieldDefData<'tcx, 'tcx>> {
-        let mut index = 0;
-        reader::tagged_docs(doc, tag_item_field).map(|f| {
-            let ff = item_family(f);
-            match ff {
-                PublicField | InheritedField => {},
-                _ => bug!("expected field, found {:?}", ff)
-            };
-            ty::FieldDefData::new(item_def_id(f, cdata),
-                                  item_name(f),
-                                  struct_field_family_to_visibility(ff))
-        }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| {
-            let ff = item_family(f);
-            let name = token::with_ident_interner(|interner| interner.intern(index.to_string()));
-            index += 1;
-            ty::FieldDefData::new(item_def_id(f, cdata), name,
-                                  struct_field_family_to_visibility(ff))
-        })).collect()
-    }
-    fn get_struct_variant<'tcx>(cdata: Cmd,
-                                doc: rbml::Doc,
-                                did: DefId) -> ty::VariantDefData<'tcx, 'tcx> {
-        ty::VariantDefData {
-            did: did,
-            name: item_name(doc),
-            fields: get_variant_fields(cdata, doc),
-            disr_val: ConstInt::Infer(0),
-            kind: expect_variant_kind(item_family(doc)),
-        }
+        };
+
+        let lo = (lo - filemap.original_start_pos) +
+                  filemap.translated_filemap.start_pos;
+        let hi = (hi - filemap.original_start_pos) +
+                  filemap.translated_filemap.start_pos;
+
+        Ok(syntax_pos::mk_sp(lo, hi))
     }
+}
 
-    let doc = cdata.lookup_item(item_id);
-    let did = DefId { krate: cdata.cnum, index: item_id };
-    let mut ctor_did = None;
-    let (kind, variants) = match item_family(doc) {
-        Enum => {
-            (AdtKind::Enum, get_enum_variants(cdata, doc))
-        }
-        Struct(..) => {
-            // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
-            ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| {
-                translated_def_id(cdata, ctor_doc)
-            });
-            (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
-        }
-        Union => {
-            (AdtKind::Union, vec![get_struct_variant(cdata, doc, did)])
-        }
-        _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did)
-    };
-
-    let adt = tcx.intern_adt_def(did, kind, variants);
-    if let Some(ctor_did) = ctor_did {
-        // Make adt definition available through constructor id as well.
-        tcx.insert_adt_def(ctor_did, adt);
-    }
-
-    // this needs to be done *after* the variant is interned,
-    // to support recursive structures
-    for variant in &adt.variants {
-        if variant.kind == ty::VariantKind::Tuple && adt.is_enum() {
-            // tuple-like enum variant fields aren't real items - get the types
-            // from the ctor.
-            debug!("evaluating the ctor-type of {:?}",
-                   variant.name);
-            let ctor_ty = get_type(cdata, variant.did.index, tcx);
-            debug!("evaluating the ctor-type of {:?}.. {:?}",
-                   variant.name,
-                   ctor_ty);
-            let field_tys = match ctor_ty.sty {
-                ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-                    ref inputs, ..
-                }), ..}) => {
-                    // tuple-struct constructors don't have escaping regions
-                    assert!(!inputs.has_escaping_regions());
-                    inputs
-                },
-                _ => bug!("tuple-variant ctor is not an ADT")
+// FIXME(#36588) These impls are horribly unsound as they allow
+// the caller to pick any lifetime for 'tcx, including 'static,
+// by using the unspecialized proxies to them.
+
+impl<'a, 'tcx> SpecializedDecoder<Ty<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Ty<'tcx>, Self::Error> {
+        let tcx = self.tcx();
+
+        // Handle shorthands first, if we have an usize > 0x80.
+        if self.opaque.data[self.opaque.position()] & 0x80 != 0 {
+            let pos = self.read_usize()?;
+            assert!(pos >= SHORTHAND_OFFSET);
+            let key = ty::CReaderCacheKey {
+                cnum: self.cdata().cnum,
+                pos: pos - SHORTHAND_OFFSET
             };
-            for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) {
-                field.fulfill_ty(ty);
+            if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() {
+                return Ok(ty);
             }
+
+            let ty = self.with_position(key.pos, Ty::decode)?;
+            tcx.rcache.borrow_mut().insert(key, ty);
+            Ok(ty)
         } else {
-            for field in &variant.fields {
-                debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
-                let ty = get_type(cdata, field.did.index, tcx);
-                field.fulfill_ty(ty);
-                debug!("evaluating the type of {:?}::{:?}: {:?}",
-                       variant.name, field.name, ty);
-            }
+            Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?))
         }
     }
-
-    adt
 }
 
-pub fn get_predicates<'a, 'tcx>(cdata: Cmd,
-                                item_id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> ty::GenericPredicates<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    doc_predicates(item_doc, tcx, cdata, tag_item_predicates)
-}
 
-pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd,
-                                      item_id: DefIndex,
-                                      tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                      -> ty::GenericPredicates<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
-}
+impl<'a, 'tcx> SpecializedDecoder<ty::GenericPredicates<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ty::GenericPredicates<'tcx>, Self::Error> {
+        Ok(ty::GenericPredicates {
+            parent: Decodable::decode(self)?,
+            predicates: (0..self.read_usize()?).map(|_| {
+                // Handle shorthands first, if we have an usize > 0x80.
+                if self.opaque.data[self.opaque.position()] & 0x80 != 0 {
+                    let pos = self.read_usize()?;
+                    assert!(pos >= SHORTHAND_OFFSET);
+                    let pos = pos - SHORTHAND_OFFSET;
 
-pub fn get_generics<'a, 'tcx>(cdata: Cmd,
-                              item_id: DefIndex,
-                              tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                              -> &'tcx ty::Generics<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    doc_generics(item_doc, tcx, cdata)
+                    self.with_position(pos, ty::Predicate::decode)
+                } else {
+                    ty::Predicate::decode(self)
+                }
+            }).collect::<Result<Vec<_>, _>>()?
+        })
+    }
 }
 
-pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                          -> Ty<'tcx>
-{
-    let item_doc = cdata.lookup_item(id);
-    doc_type(item_doc, tcx, cdata)
+impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> {
+        Ok(self.tcx().mk_substs(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> {
+        Ok(self.tcx().mk_region(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option<attr::Deprecation> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
+        Ok(self.tcx().mk_type_list(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility {
-    item_visibility(cdata.lookup_item(id))
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> {
+        Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option<DefId> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| {
-        translated_def_id(cdata, doc)
-    })
+impl<'a, 'tcx> SpecializedDecoder<ty::AdtDef<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ty::AdtDef<'tcx>, Self::Error> {
+        let def_id = DefId::decode(self)?;
+        Ok(self.tcx().lookup_adt_def(def_id))
+    }
 }
 
-pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
-    let item = cdata.lookup_item(id);
-    match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    }) {
-        Some(attrs) => attrs,
-        None => Vec::new(),
+impl<'a, 'tcx> MetadataBlob {
+    pub fn is_compatible(&self) -> bool {
+        self.raw_bytes().starts_with(METADATA_HEADER)
     }
-}
 
-pub fn get_impl_polarity<'tcx>(cdata: Cmd,
-                               id: DefIndex)
-                               -> Option<hir::ImplPolarity>
-{
-    let item_doc = cdata.lookup_item(id);
-    let fam = item_family(item_doc);
-    match fam {
-        Family::Impl => {
-            Some(parse_polarity(item_doc))
-        }
-        _ => None
+    pub fn get_root(&self) -> CrateRoot {
+        let slice = self.raw_bytes();
+        let offset = METADATA_HEADER.len();
+        let pos = (((slice[offset + 0] as u32) << 24) |
+                   ((slice[offset + 1] as u32) << 16) |
+                   ((slice[offset + 2] as u32) << 8) |
+                   ((slice[offset + 3] as u32) << 0)) as usize;
+        Lazy::with_position(pos).decode(self)
     }
-}
 
-pub fn get_custom_coerce_unsized_kind<'tcx>(
-    cdata: Cmd,
-    id: DefIndex)
-    -> Option<ty::adjustment::CustomCoerceUnsized>
-{
-    let item_doc = cdata.lookup_item(id);
-    reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
-        let mut decoder = reader::Decoder::new(kind_doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
-}
+    /// Go through each item in the metadata and create a map from that
+    /// item's def-key to the item's DefIndex.
+    pub fn load_key_map(&self, index: LazySeq<Index>) -> FnvHashMap<DefKey, DefIndex> {
+        index.iter_enumerated(self.raw_bytes()).map(|(index, item)| {
+            (item.decode(self).def_key.decode(self), index)
+        }).collect()
+    }
 
-pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd,
-                                id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> Option<ty::TraitRef<'tcx>>
-{
-    let item_doc = cdata.lookup_item(id);
-    let fam = item_family(item_doc);
-    match fam {
-        Family::Impl | Family::DefaultImpl => {
-            reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
-                doc_trait_ref(tp, tcx, cdata)
-            })
+    pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> {
+        write!(out, "=External Dependencies=\n")?;
+        let root = self.get_root();
+        for (i, dep) in root.crate_deps.decode(self).enumerate() {
+            write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?;
         }
-        _ => None
+        write!(out, "\n")?;
+        Ok(())
     }
 }
 
-/// Iterates over the language items in the given crate.
-pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
-    F: FnMut(DefIndex, usize) -> bool,
-{
-    let root = rbml::Doc::new(cdata.data());
-    let lang_items = reader::get_doc(root, tag_lang_items);
-    reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
-        let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
-        let id = reader::doc_as_u32(id_doc) as usize;
-        let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index);
-        let index = DefIndex::from_u32(reader::doc_as_u32(index_doc));
-
-        f(index, id)
-    })
+impl<'tcx> EntryKind<'tcx> {
+    fn to_def(&self, did: DefId) -> Option<Def> {
+        Some(match *self {
+            EntryKind::Const  => Def::Const(did),
+            EntryKind::AssociatedConst(_) => Def::AssociatedConst(did),
+            EntryKind::ImmStatic |
+            EntryKind::ForeignImmStatic => Def::Static(did, false),
+            EntryKind::MutStatic |
+            EntryKind::ForeignMutStatic => Def::Static(did, true),
+            EntryKind::Struct(_) => Def::Struct(did),
+            EntryKind::Union(_) => Def::Union(did),
+            EntryKind::Fn(_) |
+            EntryKind::ForeignFn(_) => Def::Fn(did),
+            EntryKind::Method(_) => Def::Method(did),
+            EntryKind::Type => Def::TyAlias(did),
+            EntryKind::AssociatedType(_) => Def::AssociatedTy(did),
+            EntryKind::Mod(_) => Def::Mod(did),
+            EntryKind::Variant(_) => Def::Variant(did),
+            EntryKind::Trait(_) => Def::Trait(did),
+            EntryKind::Enum => Def::Enum(did),
+
+            EntryKind::ForeignMod |
+            EntryKind::Impl(_) |
+            EntryKind::DefaultImpl(_) |
+            EntryKind::Field |
+            EntryKind::Closure (_) => {
+                return None
+            }
+        })
+    }
 }
 
-fn each_child_of_item_or_crate<F, G>(cdata: Cmd,
-                                     item_doc: rbml::Doc,
-                                     mut get_crate_data: G,
-                                     mut callback: F) where
-    F: FnMut(DefLike, ast::Name, ty::Visibility),
-    G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    // Iterate over all children.
-    for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) {
-        let child_def_id = translated_def_id(cdata, child_info_doc);
-
-        // This item may be in yet another crate if it was the child of a
-        // reexport.
-        let crate_data = if child_def_id.krate == cdata.cnum {
-            None
-        } else {
-            Some(get_crate_data(child_def_id.krate))
-        };
-        let crate_data = match crate_data {
-            Some(ref cdata) => &**cdata,
-            None => cdata
-        };
+impl<'a, 'tcx> CrateMetadata {
+    fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
+        self.root.index.lookup(self.blob.raw_bytes(), item_id)
+    }
 
-        // Get the item.
-        if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
-            // Hand off the item to the callback.
-            let child_name = item_name(child_item_doc);
-            let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
-            let visibility = item_visibility(child_item_doc);
-            callback(def_like, child_name, visibility);
+    fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
+        match self.maybe_entry(item_id) {
+            None => bug!("entry: id not found: {:?} in crate {:?} with number {}",
+                         item_id,
+                         self.name,
+                         self.cnum),
+            Some(d) => d.decode(self)
         }
     }
 
-    for reexport_doc in reexports(item_doc) {
-        let def_id_doc = reader::get_doc(reexport_doc,
-                                         tag_items_data_item_reexport_def_id);
-        let child_def_id = translated_def_id(cdata, def_id_doc);
-
-        let name_doc = reader::get_doc(reexport_doc,
-                                       tag_items_data_item_reexport_name);
-        let name = name_doc.as_str();
-
-        // This reexport may be in yet another crate.
-        let crate_data = if child_def_id.krate == cdata.cnum {
-            None
-        } else {
-            Some(get_crate_data(child_def_id.krate))
-        };
-        let crate_data = match crate_data {
-            Some(ref cdata) => &**cdata,
-            None => cdata
-        };
-
-        // Get the item.
-        if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
-            // Hand off the item to the callback.
-            let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
-            // These items have a public visibility because they're part of
-            // a public re-export.
-            callback(def_like, token::intern(name), ty::Visibility::Public);
+    fn local_def_id(&self, index: DefIndex) -> DefId {
+        DefId {
+            krate: self.cnum,
+            index: index
         }
     }
-}
 
-/// Iterates over each child of the given item.
-pub fn each_child_of_item<F, G>(cdata: Cmd, id: DefIndex, get_crate_data: G, callback: F)
-    where F: FnMut(DefLike, ast::Name, ty::Visibility),
-          G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    // Find the item.
-    let item_doc = match cdata.get_item(id) {
-        None => return,
-        Some(item_doc) => item_doc,
-    };
-
-    each_child_of_item_or_crate(cdata, item_doc, get_crate_data, callback)
-}
-
-/// Iterates over all the top-level crate items.
-pub fn each_top_level_item_of_crate<F, G>(cdata: Cmd, get_crate_data: G, callback: F)
-    where F: FnMut(DefLike, ast::Name, ty::Visibility),
-          G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    each_child_of_item(cdata, CRATE_DEF_INDEX, get_crate_data, callback)
-}
-
-pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name {
-    item_name(cdata.lookup_item(id))
-}
-
-pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option<ast::Name> {
-    maybe_item_name(cdata.lookup_item(id))
-}
-
-pub enum FoundAst<'ast> {
-    Found(&'ast InlinedItem),
-    FoundParent(DefId, &'ast hir::Item),
-    NotFound,
-}
-
-pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
-                                    -> FoundAst<'tcx> {
-    debug!("Looking up item: {:?}", id);
-    let item_doc = cdata.lookup_item(id);
-    let item_did = item_def_id(item_doc, cdata);
-    let parent_def_id = DefId {
-        krate: cdata.cnum,
-        index: def_key(cdata, id).parent.unwrap()
-    };
-    let mut parent_def_path = def_path(cdata, id).unwrap();
-    parent_def_path.data.pop();
-    if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) {
-        let ii = decode_inlined_item(cdata,
-                                     tcx,
-                                     parent_def_path,
-                                     parent_def_id,
-                                     ast_doc,
-                                     item_did);
-        return FoundAst::Found(ii);
-    } else if let Some(parent_did) = item_parent_item(cdata, item_doc) {
-        // Remove the last element from the paths, since we are now
-        // trying to inline the parent.
-        let grandparent_def_id = DefId {
-            krate: cdata.cnum,
-            index: def_key(cdata, parent_def_id.index).parent.unwrap()
-        };
-        let mut grandparent_def_path = parent_def_path;
-        grandparent_def_path.data.pop();
-        let parent_doc = cdata.lookup_item(parent_did.index);
-        if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) {
-            let ii = decode_inlined_item(cdata,
-                                         tcx,
-                                         grandparent_def_path,
-                                         grandparent_def_id,
-                                         ast_doc,
-                                         parent_did);
-            if let &InlinedItem::Item(_, ref i) = ii {
-                return FoundAst::FoundParent(parent_did, i);
-            }
-        }
+    fn item_name(&self, item: &Entry<'tcx>) -> ast::Name {
+        item.def_key.decode(self).disambiguated_data.data.get_opt_name()
+            .expect("no name in item_name")
     }
-    FoundAst::NotFound
-}
 
-pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool {
-    if let Some(item_doc) = cdata.get_item(id) {
-        return reader::maybe_get_doc(item_doc, tag_mir as usize).is_some();
+    pub fn get_def(&self, index: DefIndex) -> Option<Def> {
+        self.entry(index).kind.to_def(self.local_def_id(index))
     }
 
-    false
-}
+    pub fn get_trait_def(&self,
+                         item_id: DefIndex,
+                         tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> {
+        let data = match self.entry(item_id).kind {
+            EntryKind::Trait(data) => data.decode(self),
+            _ => bug!()
+        };
 
-pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd,
-                                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    id: DefIndex)
-                                    -> Option<mir::repr::Mir<'tcx>> {
-    let item_doc = cdata.lookup_item(id);
+        ty::TraitDef::new(data.unsafety, data.paren_sugar,
+                          tcx.lookup_generics(self.local_def_id(item_id)),
+                          data.trait_ref.decode((self, tcx)),
+                          self.def_path(item_id).unwrap().deterministic_hash(tcx))
+    }
 
-    return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| {
-        let dcx = tls_context::DecodingContext {
-            crate_metadata: cdata,
-            tcx: tcx,
+    fn get_variant(&self, item: &Entry<'tcx>, index: DefIndex)
+                   -> (ty::VariantDefData<'tcx, 'tcx>, Option<DefIndex>) {
+        let data = match item.kind {
+            EntryKind::Variant(data) |
+            EntryKind::Struct(data) |
+            EntryKind::Union(data) => data.decode(self),
+            _ => bug!()
         };
-        let mut decoder = reader::Decoder::new(mir_doc);
 
-        let mut mir = decoder.read_opaque(|opaque_decoder, _| {
-            tls::enter_decoding_context(&dcx, opaque_decoder, |_, opaque_decoder| {
-                Decodable::decode(opaque_decoder)
-            })
-        }).unwrap();
-
-        assert!(decoder.position() == mir_doc.end);
+        let fields = item.children.decode(self).map(|index| {
+            let f = self.entry(index);
+            ty::FieldDefData::new(self.local_def_id(index),
+                                  self.item_name(&f),
+                                  f.visibility)
+        }).collect();
+
+        (ty::VariantDefData {
+            did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
+            name: self.item_name(item),
+            fields: fields,
+            disr_val: ConstInt::Infer(data.disr),
+            kind: data.kind,
+        }, data.struct_ctor)
+    }
 
-        let mut def_id_and_span_translator = MirDefIdAndSpanTranslator {
-            crate_metadata: cdata,
-            codemap: tcx.sess.codemap(),
-            last_filemap_index_hint: Cell::new(0),
+    pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                       -> ty::AdtDefMaster<'tcx> {
+        let item = self.entry(item_id);
+        let did = self.local_def_id(item_id);
+        let mut ctor_index = None;
+        let variants = if let EntryKind::Enum = item.kind {
+            item.children.decode(self).map(|index| {
+                let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
+                assert_eq!(struct_ctor, None);
+                variant
+            }).collect()
+        } else{
+            let (variant, struct_ctor) = self.get_variant(&item, item_id);
+            ctor_index = struct_ctor;
+            vec![variant]
+        };
+        let kind = match item.kind {
+            EntryKind::Enum => ty::AdtKind::Enum,
+            EntryKind::Struct(_) => ty::AdtKind::Struct,
+            EntryKind::Union(_) => ty::AdtKind::Union,
+            _ => bug!("get_adt_def called on a non-ADT {:?}", did)
         };
 
-        def_id_and_span_translator.visit_mir(&mut mir);
-        for promoted in &mut mir.promoted {
-            def_id_and_span_translator.visit_mir(promoted);
+        let adt = tcx.intern_adt_def(did, kind, variants);
+        if let Some(ctor_index) = ctor_index {
+            // Make adt definition available through constructor id as well.
+            tcx.insert_adt_def(self.local_def_id(ctor_index), adt);
         }
 
-        mir
-    });
+        // this needs to be done *after* the variant is interned,
+        // to support recursive structures
+        for variant in &adt.variants {
+            for field in &variant.fields {
+                debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
+                let ty = self.get_type(field.did.index, tcx);
+                field.fulfill_ty(ty);
+                debug!("evaluating the type of {:?}::{:?}: {:?}",
+                       variant.name, field.name, ty);
+            }
+        }
 
-    struct MirDefIdAndSpanTranslator<'cdata, 'codemap> {
-        crate_metadata: Cmd<'cdata>,
-        codemap: &'codemap codemap::CodeMap,
-        last_filemap_index_hint: Cell<usize>
+        adt
     }
 
-    impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v>
-        for MirDefIdAndSpanTranslator<'cdata, 'codemap>
-    {
-        fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) {
-            *def_id = translate_def_id(self.crate_metadata, *def_id);
-        }
-
-        fn visit_span(&mut self, span: &mut Span) {
-            *span = translate_span(self.crate_metadata,
-                                   self.codemap,
-                                   &self.last_filemap_index_hint,
-                                   *span);
-        }
+    pub fn get_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> ty::GenericPredicates<'tcx> {
+        self.entry(item_id).predicates.unwrap().decode((self, tcx))
     }
-}
 
-fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                               -> ty::ExplicitSelfCategory<'tcx> {
-    fn get_mutability(ch: u8) -> hir::Mutability {
-        match ch as char {
-            'i' => hir::MutImmutable,
-            'm' => hir::MutMutable,
-            _ => bug!("unknown mutability character: `{}`", ch as char),
+    pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                -> ty::GenericPredicates<'tcx> {
+        match self.entry(item_id).kind {
+            EntryKind::Trait(data) => {
+                data.decode(self).super_predicates.decode((self, tcx))
+            }
+            _ => bug!()
         }
     }
 
-    let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
-    let string = explicit_self_doc.as_str();
+    pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                        -> ty::Generics<'tcx> {
+        self.entry(item_id).generics.unwrap().decode((self, tcx))
+    }
 
-    let explicit_self_kind = string.as_bytes()[0];
-    match explicit_self_kind as char {
-        's' => ty::ExplicitSelfCategory::Static,
-        'v' => ty::ExplicitSelfCategory::ByValue,
-        '~' => ty::ExplicitSelfCategory::ByBox,
-        // FIXME(#4846) expl. region
-        '&' => {
-            ty::ExplicitSelfCategory::ByReference(
-                tcx.mk_region(ty::ReEmpty),
-                get_mutability(string.as_bytes()[1]))
-        }
-        _ => bug!("unknown self type code: `{}`", explicit_self_kind as char)
+    pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+        self.entry(id).ty.unwrap().decode((self, tcx))
     }
-}
 
-/// Returns the def IDs of all the items in the given implementation.
-pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex)
-                      -> Vec<ty::ImplOrTraitItemId> {
-    reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| {
-        let def_id = item_def_id(doc, cdata);
-        match item_sort(doc) {
-            Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
-            Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
-            Some('t') => ty::TypeTraitItemId(def_id),
-            _ => bug!("unknown impl item sort"),
-        }
-    }).collect()
-}
+    pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
+        self.entry(id).stability.map(|stab| stab.decode(self))
+    }
 
-pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name {
-    let doc = cdata.lookup_item(id);
-    item_name(doc)
-}
+    pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
+        self.entry(id).deprecation.map(|depr| depr.decode(self))
+    }
 
-pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                        -> Option<ty::ImplOrTraitItem<'tcx>> {
-    let item_doc = cdata.lookup_item(id);
-
-    let def_id = item_def_id(item_doc, cdata);
-
-    let container_id = if let Some(id) = item_parent_item(cdata, item_doc) {
-        id
-    } else {
-        return None;
-    };
-    let container_doc = cdata.lookup_item(container_id.index);
-    let container = match item_family(container_doc) {
-        Trait => TraitContainer(container_id),
-        _ => ImplContainer(container_id),
-    };
-
-    let name = item_name(item_doc);
-    let vis = item_visibility(item_doc);
-    let defaultness = item_defaultness(item_doc);
-
-    Some(match item_sort(item_doc) {
-        sort @ Some('C') | sort @ Some('c') => {
-            let ty = doc_type(item_doc, tcx, cdata);
-            ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
-                name: name,
-                ty: ty,
-                vis: vis,
-                defaultness: defaultness,
-                def_id: def_id,
-                container: container,
-                has_value: sort == Some('C')
-            }))
-        }
-        Some('r') | Some('p') => {
-            let generics = doc_generics(item_doc, tcx, cdata);
-            let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates);
-            let ity = tcx.lookup_item_type(def_id).ty;
-            let fty = match ity.sty {
-                ty::TyFnDef(.., fty) => fty,
-                _ => bug!(
-                    "the type {:?} of the method {:?} is not a function?",
-                    ity, name)
-            };
-            let explicit_self = get_explicit_self(item_doc, tcx);
-
-            ty::MethodTraitItem(Rc::new(ty::Method::new(name,
-                                                        generics,
-                                                        predicates,
-                                                        fty,
-                                                        explicit_self,
-                                                        vis,
-                                                        defaultness,
-                                                        def_id,
-                                                        container)))
-        }
-        Some('t') => {
-            let ty = maybe_doc_type(item_doc, tcx, cdata);
-            ty::TypeTraitItem(Rc::new(ty::AssociatedType {
-                name: name,
-                ty: ty,
-                vis: vis,
-                defaultness: defaultness,
-                def_id: def_id,
-                container: container,
-            }))
-        }
-        _ => return None
-    })
-}
+    pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
+        self.entry(id).visibility
+    }
 
-pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex)
-                              -> Vec<ty::ImplOrTraitItemId> {
-    let item = cdata.lookup_item(id);
-    reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
-        let def_id = item_def_id(mth, cdata);
-        match item_sort(mth) {
-            Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
-            Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
-            Some('t') => ty::TypeTraitItemId(def_id),
-            _ => bug!("unknown trait item sort"),
+    fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> {
+        match self.entry(id).kind {
+            EntryKind::Impl(data) => data.decode(self),
+            _ => bug!()
         }
-    }).collect()
-}
+    }
 
-pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec<ty::Variance> {
-    let item_doc = cdata.lookup_item(id);
-    let variance_doc = reader::get_doc(item_doc, tag_item_variances);
-    let mut decoder = reader::Decoder::new(variance_doc);
-    Decodable::decode(&mut decoder).unwrap()
-}
+    pub fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
+        self.get_impl_data(id).parent_impl
+    }
 
-pub fn get_provided_trait_methods<'a, 'tcx>(cdata: Cmd,
-                                            id: DefIndex,
-                                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                            -> Vec<Rc<ty::Method<'tcx>>> {
-    let item = cdata.lookup_item(id);
+    pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity {
+        self.get_impl_data(id).polarity
+    }
 
-    reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
-        let did = item_def_id(mth_id, cdata);
-        let mth = cdata.lookup_item(did.index);
+    pub fn get_custom_coerce_unsized_kind(&self, id: DefIndex)
+                                          -> Option<ty::adjustment::CustomCoerceUnsized> {
+        self.get_impl_data(id).coerce_unsized_kind
+    }
 
-        if item_sort(mth) == Some('p') {
-            let trait_item = get_impl_or_trait_item(cdata, did.index, tcx);
-            if let Some(ty::MethodTraitItem(ref method)) = trait_item {
-                Some((*method).clone())
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }).collect()
-}
+    pub fn get_impl_trait(&self,
+                          id: DefIndex,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> Option<ty::TraitRef<'tcx>> {
+        self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx)))
+    }
 
-pub fn get_associated_consts<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                       -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
-    let item = cdata.lookup_item(id);
+    /// Iterates over the language items in the given crate.
+    pub fn get_lang_items(&self) -> Vec<(DefIndex, usize)> {
+        self.root.lang_items.decode(self).collect()
+    }
 
-    [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
-        reader::tagged_docs(item, tag).filter_map(|ac_id| {
-            let did = item_def_id(ac_id, cdata);
-            let ac_doc = cdata.lookup_item(did.index);
+    /// Iterates over each child of the given item.
+    pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
+        where F: FnMut(def::Export)
+    {
+        // Find the item.
+        let item = match self.maybe_entry(id) {
+            None => return,
+            Some(item) => item.decode(self),
+        };
 
-            match item_sort(ac_doc) {
-                Some('C') | Some('c') => {
-                    let trait_item = get_impl_or_trait_item(cdata, did.index, tcx);
-                    if let Some(ty::ConstTraitItem(ref ac)) = trait_item {
-                        Some((*ac).clone())
-                    } else {
-                        None
+        // Iterate over all children.
+        for child_index in item.children.decode(self) {
+            // Get the item.
+            if let Some(child) = self.maybe_entry(child_index) {
+                let child = child.decode(self);
+                // Hand off the item to the callback.
+                match child.kind {
+                    // FIXME(eddyb) Don't encode these in children.
+                    EntryKind::ForeignMod => {
+                        for child_index in child.children.decode(self) {
+                            callback(def::Export {
+                                def_id: self.local_def_id(child_index),
+                                name: self.item_name(&self.entry(child_index))
+                            });
+                        }
+                        continue;
                     }
+                    EntryKind::Impl(_) | EntryKind::DefaultImpl(_) => continue,
+
+                    _ => {}
+                }
+
+                let def_key = child.def_key.decode(self);
+                if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
+                    callback(def::Export {
+                        def_id: self.local_def_id(child_index),
+                        name: name
+                    });
                 }
-                _ => None
             }
-        })
-    }).collect()
-}
+        }
 
-pub fn get_variant_kind(cdata: Cmd, node_id: DefIndex) -> Option<VariantKind>
-{
-    let item = cdata.lookup_item(node_id);
-    family_to_variant_kind(item_family(item))
-}
+        if let EntryKind::Mod(data) = item.kind {
+            for exp in data.decode(self).reexports.decode(self) {
+                callback(exp);
+            }
+        }
+    }
 
-pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option<DefId>
-{
-    let item = cdata.lookup_item(node_id);
-    reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).
-        map(|ctor_doc| translated_def_id(cdata, ctor_doc))
-}
+    pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
+                              -> Option<&'tcx InlinedItem> {
+        debug!("Looking up item: {:?}", id);
+        let item_doc = self.entry(id);
+        let item_did = self.local_def_id(id);
+        let parent_def_id = self.local_def_id(self.def_key(id).parent.unwrap());
+        let mut parent_def_path = self.def_path(id).unwrap();
+        parent_def_path.data.pop();
+        item_doc.ast.map(|ast| {
+            let ast = ast.decode(self);
+            decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast, item_did)
+        })
+    }
 
-/// If node_id is the constructor of a tuple struct, retrieve the NodeId of
-/// the actual type definition, otherwise, return None
-pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
-                                           node_id: DefIndex)
-    -> Option<DefId>
-{
-    let item = cdata.lookup_item(node_id);
-    reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| {
-        item_require_parent_item(cdata, item)
-    })
-}
+    pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
+        self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
+    }
 
-pub fn get_item_attrs(cdata: Cmd,
-                      orig_node_id: DefIndex)
-                      -> Vec<ast::Attribute> {
-    // The attributes for a tuple struct are attached to the definition, not the ctor;
-    // we assume that someone passing in a tuple struct ctor is actually wanting to
-    // look at the definition
-    let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
-    let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id);
-    let item = cdata.lookup_item(node_id);
-    get_attributes(item)
-}
+    pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
+                              -> Option<Mir<'tcx>> {
+        self.entry(id).mir.map(|mir| mir.decode((self, tcx)))
+    }
 
-pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<DefId, Vec<ast::Attribute>> {
-    let data = rbml::Doc::new(cdata.data());
-    let fields = reader::get_doc(data, tag_struct_fields);
-    reader::tagged_docs(fields, tag_struct_field).map(|field| {
-        let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id));
-        let attrs = get_attributes(field);
-        (def_id, attrs)
-    }).collect()
-}
+    pub fn get_impl_or_trait_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                  -> Option<ty::ImplOrTraitItem<'tcx>> {
+        let item = self.entry(id);
+        let parent_and_name = || {
+            let def_key = item.def_key.decode(self);
+            (self.local_def_id(def_key.parent.unwrap()),
+             def_key.disambiguated_data.data.get_opt_name().unwrap())
+        };
 
-fn struct_field_family_to_visibility(family: Family) -> ty::Visibility {
-    match family {
-        PublicField => ty::Visibility::Public,
-        InheritedField => ty::Visibility::PrivateExternal,
-        _ => bug!()
+        Some(match item.kind {
+            EntryKind::AssociatedConst(container) => {
+                let (parent, name) = parent_and_name();
+                ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+                    name: name,
+                    ty: item.ty.unwrap().decode((self, tcx)),
+                    vis: item.visibility,
+                    defaultness: container.defaultness(),
+                    def_id: self.local_def_id(id),
+                    container: container.with_def_id(parent),
+                    has_value: container.has_body(),
+                }))
+            }
+            EntryKind::Method(data) => {
+                let (parent, name) = parent_and_name();
+                let ity = item.ty.unwrap().decode((self, tcx));
+                let fty = match ity.sty {
+                    ty::TyFnDef(.., fty) => fty,
+                    _ => bug!(
+                        "the type {:?} of the method {:?} is not a function?",
+                        ity, name)
+                };
+
+                let data = data.decode(self);
+                ty::MethodTraitItem(Rc::new(ty::Method {
+                    name: name,
+                    generics: tcx.lookup_generics(self.local_def_id(id)),
+                    predicates: item.predicates.unwrap().decode((self, tcx)),
+                    fty: fty,
+                    explicit_self: data.explicit_self.decode((self, tcx)),
+                    vis: item.visibility,
+                    defaultness: data.container.defaultness(),
+                    has_body: data.container.has_body(),
+                    def_id: self.local_def_id(id),
+                    container: data.container.with_def_id(parent),
+                }))
+            }
+            EntryKind::AssociatedType(container) => {
+                let (parent, name) = parent_and_name();
+                ty::TypeTraitItem(Rc::new(ty::AssociatedType {
+                    name: name,
+                    ty: item.ty.map(|ty| ty.decode((self, tcx))),
+                    vis: item.visibility,
+                    defaultness: container.defaultness(),
+                    def_id: self.local_def_id(id),
+                    container: container.with_def_id(parent),
+                }))
+            }
+            _ => return None
+        })
     }
-}
-
-pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec<ast::Name> {
-    let item = cdata.lookup_item(id);
-    let mut index = 0;
-    reader::tagged_docs(item, tag_item_field).map(|an_item| {
-        item_name(an_item)
-    }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| {
-        let name = token::with_ident_interner(|interner| interner.intern(index.to_string()));
-        index += 1;
-        name
-    })).collect()
-}
 
-fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
-    reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| {
-        let mut decoder = reader::Decoder::new(attrs_doc);
-        let mut attrs: Vec<ast::Attribute> = decoder.read_opaque(|opaque_decoder, _| {
-            Decodable::decode(opaque_decoder)
-        }).unwrap();
+    pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
+        self.entry(id).variances.decode(self).collect()
+    }
 
-        // Need new unique IDs: old thread-local IDs won't map to new threads.
-        for attr in attrs.iter_mut() {
-            attr.node.id = attr::mk_attr_id();
+    pub fn get_variant_kind(&self, node_id: DefIndex) -> Option<ty::VariantKind> {
+        match self.entry(node_id).kind {
+            EntryKind::Struct(data) |
+            EntryKind::Union(data) |
+            EntryKind::Variant(data) => Some(data.decode(self).kind),
+            _ => None
         }
-
-        attrs
-    })
-}
-
-fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
-                         out: &mut io::Write) -> io::Result<()> {
-    write!(out, "=Crate Attributes ({})=\n", *hash)?;
-
-    let r = get_attributes(md);
-    for attr in &r {
-        write!(out, "{}\n", pprust::attribute_to_string(attr))?;
     }
 
-    write!(out, "\n\n")
-}
-
-pub fn get_crate_attributes(data: &[u8]) -> Vec<ast::Attribute> {
-    get_attributes(rbml::Doc::new(data))
-}
-
-#[derive(Clone)]
-pub struct CrateDep {
-    pub cnum: ast::CrateNum,
-    pub name: String,
-    pub hash: Svh,
-    pub explicitly_linked: bool,
-}
-
-pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
-    let cratedoc = rbml::Doc::new(data);
-    let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
-
-    fn docstr(doc: rbml::Doc, tag_: usize) -> String {
-        let d = reader::get_doc(doc, tag_);
-        d.as_str().to_string()
-    }
-
-    reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
-        let name = docstr(depdoc, tag_crate_dep_crate_name);
-        let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash)));
-        let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
-        let explicitly_linked = reader::doc_as_u8(doc) != 0;
-        CrateDep {
-            cnum: crate_num as u32 + 1,
-            name: name,
-            hash: hash,
-            explicitly_linked: explicitly_linked,
+    pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
+        match self.entry(node_id).kind {
+            EntryKind::Struct(data) => {
+                data.decode(self).struct_ctor.map(|index| self.local_def_id(index))
+            }
+            _ => None
         }
-    }).collect()
-}
-
-fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
-    write!(out, "=External Dependencies=\n")?;
-    for dep in &get_crate_deps(data) {
-        write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)?;
     }
-    write!(out, "\n")?;
-    Ok(())
-}
-
-pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
-    let cratedoc = rbml::Doc::new(data);
-    reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
-        Svh::new(reader::doc_as_u64(doc))
-    })
-}
-
-pub fn get_crate_hash(data: &[u8]) -> Svh {
-    let cratedoc = rbml::Doc::new(data);
-    let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
-    Svh::new(reader::doc_as_u64(hashdoc))
-}
 
-pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
-    let cratedoc = rbml::Doc::new(data);
-    reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
-        doc.as_str()
-    })
-}
-
-pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
-    let crate_doc = rbml::Doc::new(data);
-    let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
-    let slice: &'a str = disambiguator_doc.as_str();
-    slice
-}
-
-pub fn get_crate_triple(data: &[u8]) -> Option<String> {
-    let cratedoc = rbml::Doc::new(data);
-    let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
-    triple_doc.map(|s| s.as_str().to_string())
-}
-
-pub fn get_crate_name(data: &[u8]) -> &str {
-    maybe_get_crate_name(data).expect("no crate name in crate")
-}
-
-pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> {
-    let hash = get_crate_hash(bytes);
-    let md = rbml::Doc::new(bytes);
-    list_crate_attributes(md, &hash, out)?;
-    list_crate_deps(bytes, out)
-}
-
-// Translates a def_id from an external crate to a def_id for the current
-// compilation environment. We use this when trying to load types from
-// external crates - if those types further refer to types in other crates
-// then we must translate the crate number from that encoded in the external
-// crate to the correct local crate number.
-pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
-    if did.is_local() {
-        return DefId { krate: cdata.cnum, index: did.index };
+    pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
+        // The attributes for a tuple struct are attached to the definition, not the ctor;
+        // we assume that someone passing in a tuple struct ctor is actually wanting to
+        // look at the definition
+        let mut item = self.entry(node_id);
+        let def_key = item.def_key.decode(self);
+        if def_key.disambiguated_data.data == DefPathData::StructCtor {
+            item = self.entry(def_key.parent.unwrap());
+        }
+        self.get_attributes(&item)
     }
 
-    DefId {
-        krate: cdata.cnum_map.borrow()[did.krate],
-        index: did.index
+    pub fn get_struct_field_names(&self, id: DefIndex) -> Vec<ast::Name> {
+        self.entry(id).children.decode(self).map(|index| {
+            self.item_name(&self.entry(index))
+        }).collect()
     }
-}
 
-// Translate a DefId from the current compilation environment to a DefId
-// for an external crate.
-fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
-    for (local, &global) in cdata.cnum_map.borrow().iter_enumerated() {
-        if global == did.krate {
-            return Some(DefId { krate: local, index: did.index });
-        }
+    fn get_attributes(&self, item: &Entry<'tcx>) -> Vec<ast::Attribute> {
+        item.attributes.decode(self).map(|mut attr| {
+            // Need new unique IDs: old thread-local IDs won't map to new threads.
+            attr.node.id = attr::mk_attr_id();
+            attr
+        }).collect()
     }
 
-    None
-}
-
-/// Translates a `Span` from an extern crate to the corresponding `Span`
-/// within the local crate's codemap.
-pub fn translate_span(cdata: Cmd,
-                      codemap: &codemap::CodeMap,
-                      last_filemap_index_hint: &Cell<usize>,
-                      span: syntax_pos::Span)
-                      -> syntax_pos::Span {
-    let span = if span.lo > span.hi {
-        // Currently macro expansion sometimes produces invalid Span values
-        // where lo > hi. In order not to crash the compiler when trying to
-        // translate these values, let's transform them into something we
-        // can handle (and which will produce useful debug locations at
-        // least some of the time).
-        // This workaround is only necessary as long as macro expansion is
-        // not fixed. FIXME(#23480)
-        syntax_pos::mk_sp(span.lo, span.lo)
-    } else {
-        span
-    };
-
-    let imported_filemaps = cdata.imported_filemaps(&codemap);
-    let filemap = {
-        // Optimize for the case that most spans within a translated item
-        // originate from the same filemap.
-        let last_filemap_index = last_filemap_index_hint.get();
-        let last_filemap = &imported_filemaps[last_filemap_index];
-
-        if span.lo >= last_filemap.original_start_pos &&
-           span.lo <= last_filemap.original_end_pos &&
-           span.hi >= last_filemap.original_start_pos &&
-           span.hi <= last_filemap.original_end_pos {
-            last_filemap
-        } else {
-            let mut a = 0;
-            let mut b = imported_filemaps.len();
-
-            while b - a > 1 {
-                let m = (a + b) / 2;
-                if imported_filemaps[m].original_start_pos > span.lo {
-                    b = m;
-                } else {
-                    a = m;
-                }
+    // Translate a DefId from the current compilation environment to a DefId
+    // for an external crate.
+    fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
+        for (local, &global) in self.cnum_map.borrow().iter_enumerated() {
+            if global == did.krate {
+                return Some(DefId { krate: local, index: did.index });
             }
-
-            last_filemap_index_hint.set(a);
-            &imported_filemaps[a]
         }
-    };
-
-    let lo = (span.lo - filemap.original_start_pos) +
-              filemap.translated_filemap.start_pos;
-    let hi = (span.hi - filemap.original_start_pos) +
-              filemap.translated_filemap.start_pos;
 
-    syntax_pos::mk_sp(lo, hi)
-}
+        None
+    }
 
-pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
-                                                id: DefIndex,
-                                                mut callback: F)
-    where F: FnMut(DefId),
-{
-    let item_doc = cdata.lookup_item(id);
-    for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) {
-        if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() {
-            callback(item_def_id(impl_doc, cdata));
-        }
+    pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec<DefId> {
+        self.entry(id).inherent_impls.decode(self).map(|index| {
+            self.local_def_id(index)
+        }).collect()
     }
-}
 
-pub fn each_implementation_for_trait<F>(cdata: Cmd,
-                                        def_id: DefId,
-                                        mut callback: F) where
-    F: FnMut(DefId),
-{
-    // Do a reverse lookup beforehand to avoid touching the crate_num
-    // hash map in the loop below.
-    if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) {
-        let def_id_u64 = def_to_u64(crate_local_did);
-
-        let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
-        for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) {
-            let trait_def_id = reader::get_doc(trait_doc, tag_def_id);
-            if reader::doc_as_u64(trait_def_id) != def_id_u64 {
+    pub fn get_implementations_for_trait(&self, filter: Option<DefId>, result: &mut Vec<DefId>) {
+        // Do a reverse lookup beforehand to avoid touching the crate_num
+        // hash map in the loop below.
+        let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
+            Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
+            Some(None) => return,
+            None => None
+        };
+
+        // FIXME(eddyb) Make this O(1) instead of O(n).
+        for trait_impls in self.root.impls.decode(self) {
+            if filter.is_some() && filter != Some(trait_impls.trait_id) {
                 continue;
             }
-            for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) {
-                callback(translated_def_id(cdata, impl_doc));
+
+            result.extend(trait_impls.impls.decode(self).map(|index| {
+                self.local_def_id(index)
+            }));
+
+            if filter.is_some() {
+                break;
             }
         }
     }
-}
 
-pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option<DefId> {
-    let item_doc = cdata.lookup_item(id);
-    let parent_item_id = match item_parent_item(cdata, item_doc) {
-        None => return None,
-        Some(item_id) => item_id,
-    };
-    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
-    match item_family(parent_item_doc) {
-        Trait => Some(item_def_id(parent_item_doc, cdata)),
-        _ => None
+    pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
+        self.entry(id).def_key.decode(self).parent.and_then(|parent_index| {
+            match self.entry(parent_index).kind {
+                EntryKind::Trait(_) => Some(self.local_def_id(parent_index)),
+                _ => None
+            }
+        })
     }
-}
 
 
-pub fn get_native_libraries(cdata: Cmd)
-                            -> Vec<(cstore::NativeLibraryKind, String)> {
-    let libraries = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                    tag_native_libraries);
-    reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| {
-        let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
-        let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
-        let kind: cstore::NativeLibraryKind =
-            cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
-        let name = name_doc.as_str().to_string();
-        (kind, name)
-    }).collect()
-}
+    pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> {
+        self.root.native_libraries.decode(self).collect()
+    }
 
-pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
-    reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
-        .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
-}
+    pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> {
+        self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| {
+            let cnum = CrateNum::new(i + 1);
+            link.map(|link| (self.cnum_map.borrow()[cnum], link))
+        }).collect()
+    }
 
-pub fn each_exported_macro<F>(data: &[u8], mut f: F) where
-    F: FnMut(ast::Name, Vec<ast::Attribute>, Span, String) -> bool,
-{
-    let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
-    for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
-        let name = item_name(macro_doc);
-        let attrs = get_attributes(macro_doc);
-        let span = get_macro_span(macro_doc);
-        let body = reader::get_doc(macro_doc, tag_macro_def_body);
-        if !f(name, attrs, span, body.as_str().to_string()) {
-            break;
-        }
+    pub fn get_missing_lang_items(&self) -> Vec<lang_items::LangItem> {
+        self.root.lang_items_missing.decode(self).collect()
     }
-}
 
-pub fn get_derive_registrar_fn(data: &[u8]) -> Option<DefIndex> {
-    reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar)
-        .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
-}
+    pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec<ast::Name> {
+        let arg_names = match self.entry(id).kind {
+            EntryKind::Fn(data) |
+            EntryKind::ForeignFn(data) => data.decode(self).arg_names,
+            EntryKind::Method(data) => data.decode(self).fn_data.arg_names,
+            _ => LazySeq::empty()
+        };
+        arg_names.decode(self).collect()
+    }
 
-pub fn get_macro_span(doc: rbml::Doc) -> Span {
-    let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
-    let lo = BytePos(reader::doc_as_u32(lo_doc));
-    let hi_doc = reader::get_doc(doc, tag_macro_def_span_hi);
-    let hi = BytePos(reader::doc_as_u32(hi_doc));
-    return Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
-}
+    pub fn get_reachable_ids(&self) -> Vec<DefId> {
+        self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect()
+    }
 
-pub fn get_dylib_dependency_formats(cdata: Cmd)
-    -> Vec<(ast::CrateNum, LinkagePreference)>
-{
-    let formats = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                  tag_dylib_dependency_formats);
-    let mut result = Vec::new();
-
-    debug!("found dylib deps: {}", formats.as_str());
-    for spec in formats.as_str().split(',') {
-        if spec.is_empty() { continue }
-        let mut split = spec.split(':');
-        let cnum = split.next().unwrap();
-        let link = split.next().unwrap();
-        let cnum: ast::CrateNum = cnum.parse().unwrap();
-        let cnum = cdata.cnum_map.borrow()[cnum];
-        result.push((cnum, if link == "d" {
-            LinkagePreference::RequireDynamic
-        } else {
-            LinkagePreference::RequireStatic
-        }));
+    pub fn is_const_fn(&self, id: DefIndex) -> bool {
+        let constness = match self.entry(id).kind {
+            EntryKind::Method(data) => data.decode(self).fn_data.constness,
+            EntryKind::Fn(data) => data.decode(self).constness,
+            _ => hir::Constness::NotConst
+        };
+        constness == hir::Constness::Const
     }
-    return result;
-}
 
-pub fn get_missing_lang_items(cdata: Cmd)
-    -> Vec<lang_items::LangItem>
-{
-    let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items);
-    reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| {
-        lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap()
-    }).collect()
-}
+    pub fn is_extern_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+        let item = match self.maybe_entry(id) {
+            Some(item) => item.decode(self),
+            None => return false,
+        };
+        let applicable = match item.kind {
+            EntryKind::ImmStatic |
+            EntryKind::MutStatic |
+            EntryKind::ForeignImmStatic |
+            EntryKind::ForeignMutStatic => true,
+
+            EntryKind::Fn(_) | EntryKind::ForeignFn(_) => {
+                self.get_generics(id, tcx).types.is_empty()
+            }
 
-pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
-    let method_doc = cdata.lookup_item(id);
-    match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
-        Some(args_doc) => {
-            reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
-                name_doc.as_str().to_string()
-            }).collect()
-        },
-        None => vec![],
-    }
-}
+            _ => false,
+        };
 
-pub fn get_reachable_ids(cdata: Cmd) -> Vec<DefId> {
-    let items = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                tag_reachable_ids);
-    reader::tagged_docs(items, tag_reachable_id).map(|doc| {
-        DefId {
-            krate: cdata.cnum,
-            index: DefIndex::from_u32(reader::doc_as_u32(doc)),
+        if applicable {
+            attr::contains_extern_indicator(tcx.sess.diagnostic(),
+                                            &self.get_attributes(&item))
+        } else {
+            false
         }
-    }).collect()
-}
-
-pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match item_family(item_doc) {
-        Type => true,
-        _ => false,
     }
-}
 
-pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match fn_constness(item_doc) {
-        hir::Constness::Const => true,
-        hir::Constness::NotConst => false,
+    pub fn is_foreign_item(&self, id: DefIndex) -> bool {
+        match self.entry(id).kind {
+            EntryKind::ForeignImmStatic |
+            EntryKind::ForeignMutStatic |
+            EntryKind::ForeignFn(_) => true,
+            _ => false
+        }
     }
-}
 
-pub fn is_extern_item<'a, 'tcx>(cdata: Cmd,
-                                id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> bool {
-    let item_doc = match cdata.get_item(id) {
-        Some(doc) => doc,
-        None => return false,
-    };
-    let applicable = match item_family(item_doc) {
-        ImmStatic | MutStatic => true,
-        Fn => get_generics(cdata, id, tcx).types.is_empty(),
-        _ => false,
-    };
-
-    if applicable {
-        attr::contains_extern_indicator(tcx.sess.diagnostic(),
-                                        &get_attributes(item_doc))
-    } else {
-        false
+    pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
+        match self.entry(trait_id).kind {
+            EntryKind::Trait(data) => data.decode(self).has_default_impl,
+            _ => bug!()
+        }
     }
-}
 
-pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    let parent_item_id = match item_parent_item(cdata, item_doc) {
-        None => return false,
-        Some(item_id) => item_id,
-    };
-    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
-    item_family(parent_item_doc) == ForeignMod
-}
+    pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
+        match self.entry(impl_id).kind  {
+            EntryKind::DefaultImpl(_) => true,
+            _ => false
+        }
+    }
 
-pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match item_family(item_doc) {
-        Impl => true,
-        _ => false,
+    pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind {
+        match self.entry(closure_id).kind {
+            EntryKind::Closure(data) => data.decode(self).kind,
+            _ => bug!()
+        }
     }
-}
 
-fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          cdata: Cmd)
-                          -> &'tcx ty::Generics<'tcx>
-{
-    let doc = reader::get_doc(base_doc, tag_item_generics);
-    TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                        &mut |did| translate_def_id(cdata, did))
-        .parse_generics()
-}
+    pub fn closure_ty(&self, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                      -> ty::ClosureTy<'tcx> {
+        match self.entry(closure_id).kind {
+            EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
+            _ => bug!()
+        }
+    }
 
-fn doc_predicate<'a, 'tcx>(cdata: Cmd,
-                           doc: rbml::Doc,
-                           tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                           -> ty::Predicate<'tcx>
-{
-    let predicate_pos = cdata.xref_index.lookup(
-        cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize;
-    TyDecoder::new(
-        cdata.data(), cdata.cnum, predicate_pos, tcx,
-        &mut |did| translate_def_id(cdata, did)
-    ).parse_predicate()
-}
+    pub fn def_key(&self, id: DefIndex) -> hir_map::DefKey {
+        debug!("def_key: id={:?}", id);
+        self.entry(id).def_key.decode(self)
+    }
 
-fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc,
-                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            cdata: Cmd,
-                            tag: usize)
-                            -> ty::GenericPredicates<'tcx>
-{
-    let doc = reader::get_doc(base_doc, tag);
-
-    ty::GenericPredicates {
-        parent: item_parent_item(cdata, doc),
-        predicates: reader::tagged_docs(doc, tag_predicate).map(|predicate_doc| {
-            doc_predicate(cdata, predicate_doc, tcx)
-        }).collect()
+    // Returns the path leading to the thing with this `id`. Note that
+    // some def-ids don't wind up in the metadata, so `def_path` sometimes
+    // returns `None`
+    pub fn def_path(&self, id: DefIndex) -> Option<hir_map::DefPath> {
+        debug!("def_path(id={:?})", id);
+        if self.maybe_entry(id).is_some() {
+            Some(hir_map::DefPath::make(self.cnum, id, |parent| self.def_key(parent)))
+        } else {
+            None
+        }
     }
-}
 
-pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool {
-    let trait_doc = cdata.lookup_item(trait_id);
-    assert!(item_family(trait_doc) == Family::Trait);
-    let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
-    reader::doc_as_u8(defaulted_doc) != 0
-}
+    /// Imports the codemap from an external crate into the codemap of the crate
+    /// currently being compiled (the "local crate").
+    ///
+    /// The import algorithm works analogous to how AST items are inlined from an
+    /// external crate's metadata:
+    /// For every FileMap in the external codemap an 'inline' copy is created in the
+    /// local codemap. The correspondence relation between external and local
+    /// FileMaps is recorded in the `ImportedFileMap` objects returned from this
+    /// function. When an item from an external crate is later inlined into this
+    /// crate, this correspondence information is used to translate the span
+    /// information of the inlined item so that it refers the correct positions in
+    /// the local codemap (see `<decoder::DecodeContext as SpecializedDecoder<Span>>`).
+    ///
+    /// The import algorithm in the function below will reuse FileMaps already
+    /// existing in the local codemap. For example, even if the FileMap of some
+    /// source file of libstd gets imported many times, there will only ever be
+    /// one FileMap object for the corresponding file in the local codemap.
+    ///
+    /// Note that imported FileMaps do not actually contain the source code of the
+    /// file they represent, just information about length, line breaks, and
+    /// multibyte characters. This information is enough to generate valid debuginfo
+    /// for items inlined from other crates.
+    pub fn imported_filemaps(&'a self, local_codemap: &codemap::CodeMap)
+                             -> Ref<'a, Vec<cstore::ImportedFileMap>> {
+        {
+            let filemaps = self.codemap_import_info.borrow();
+            if !filemaps.is_empty() {
+                return filemaps;
+            }
+        }
 
-pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool {
-    let impl_doc = cdata.lookup_item(impl_id);
-    item_family(impl_doc) == Family::DefaultImpl
-}
+        let external_codemap = self.root.codemap.decode(self);
+
+        let imported_filemaps = external_codemap.map(|filemap_to_import| {
+            // Try to find an existing FileMap that can be reused for the filemap to
+            // be imported. A FileMap is reusable if it is exactly the same, just
+            // positioned at a different offset within the codemap.
+            let reusable_filemap = {
+                local_codemap.files
+                             .borrow()
+                             .iter()
+                             .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
+                             .map(|rc| rc.clone())
+            };
 
-pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<syntax_pos::FileMap> {
-    let crate_doc = rbml::Doc::new(metadata);
-    let cm_doc = reader::get_doc(crate_doc, tag_codemap);
+            match reusable_filemap {
+                Some(fm) => {
+                    cstore::ImportedFileMap {
+                        original_start_pos: filemap_to_import.start_pos,
+                        original_end_pos: filemap_to_import.end_pos,
+                        translated_filemap: fm
+                    }
+                }
+                None => {
+                    // We can't reuse an existing FileMap, so allocate a new one
+                    // containing the information we need.
+                    let syntax_pos::FileMap {
+                        name,
+                        abs_path,
+                        start_pos,
+                        end_pos,
+                        lines,
+                        multibyte_chars,
+                        ..
+                    } = filemap_to_import;
+
+                    let source_length = (end_pos - start_pos).to_usize();
+
+                    // Translate line-start positions and multibyte character
+                    // position into frame of reference local to file.
+                    // `CodeMap::new_imported_filemap()` will then translate those
+                    // coordinates to their new global frame of reference when the
+                    // offset of the FileMap is known.
+                    let mut lines = lines.into_inner();
+                    for pos in &mut lines {
+                        *pos = *pos - start_pos;
+                    }
+                    let mut multibyte_chars = multibyte_chars.into_inner();
+                    for mbc in &mut multibyte_chars {
+                        mbc.pos = mbc.pos - start_pos;
+                    }
 
-    reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| {
-        let mut decoder = reader::Decoder::new(filemap_doc);
-        decoder.read_opaque(|opaque_decoder, _| {
-            Decodable::decode(opaque_decoder)
-        }).unwrap()
-    }).collect()
-}
+                    let local_version = local_codemap.new_imported_filemap(name,
+                                                                           abs_path,
+                                                                           source_length,
+                                                                           lines,
+                                                                           multibyte_chars);
+                    cstore::ImportedFileMap {
+                        original_start_pos: start_pos,
+                        original_end_pos: end_pos,
+                        translated_filemap: local_version
+                    }
+                }
+            }
+        }).collect();
 
-pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind {
-    let closure_doc = cdata.lookup_item(closure_id);
-    let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind);
-    let mut decoder = reader::Decoder::new(closure_kind_doc);
-    ty::ClosureKind::decode(&mut decoder).unwrap()
+        // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
+        *self.codemap_import_info.borrow_mut() = imported_filemaps;
+        self.codemap_import_info.borrow()
+    }
 }
 
-pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                            -> ty::ClosureTy<'tcx> {
-    let closure_doc = cdata.lookup_item(closure_id);
-    let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty);
-    TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did))
-        .parse_closure_ty()
-}
+fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap, fm2: &syntax_pos::FileMap) -> bool {
+    if fm1.name != fm2.name {
+        return false;
+    }
 
-pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
-    debug!("def_key: id={:?}", id);
-    let item_doc = cdata.lookup_item(id);
-    item_def_key(item_doc)
-}
+    let lines1 = fm1.lines.borrow();
+    let lines2 = fm2.lines.borrow();
 
-fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
-    match reader::maybe_get_doc(item_doc, tag_def_key) {
-        Some(def_key_doc) => {
-            let mut decoder = reader::Decoder::new(def_key_doc);
-            let simple_key = def_key::DefKey::decode(&mut decoder).unwrap();
-            let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| {
-                token::intern(name.as_str()).as_str()
-            });
-            def_key::recover_def_key(simple_key, name)
-        }
-        None => {
-            bug!("failed to find block with tag {:?} for item with family {:?}",
-                   tag_def_key,
-                   item_family(item_doc))
+    if lines1.len() != lines2.len() {
+        return false;
+    }
+
+    for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
+        if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
+            return false;
         }
     }
-}
 
-// Returns the path leading to the thing with this `id`. Note that
-// some def-ids don't wind up in the metadata, so `def_path` sometimes
-// returns `None`
-pub fn def_path(cdata: Cmd, id: DefIndex) -> Option<hir_map::DefPath> {
-    debug!("def_path(id={:?})", id);
-    if cdata.get_item(id).is_some() {
-        Some(hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)))
-    } else {
-        None
+    let multibytes1 = fm1.multibyte_chars.borrow();
+    let multibytes2 = fm2.multibyte_chars.borrow();
+
+    if multibytes1.len() != multibytes2.len() {
+        return false;
     }
-}
 
-pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy {
-    let crate_doc = rbml::Doc::new(data);
-    let strat_doc = reader::get_doc(crate_doc, tag_panic_strategy);
-    match reader::doc_as_u8(strat_doc) {
-        b'U' => PanicStrategy::Unwind,
-        b'A' => PanicStrategy::Abort,
-        b => panic!("unknown panic strategy in metadata: {}", b),
+    for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
+        if (mb1.bytes != mb2.bytes) ||
+            ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
+            return false;
+        }
     }
+
+    true
 }
diff --git a/src/librustc_metadata/def_key.rs b/src/librustc_metadata/def_key.rs
deleted file mode 100644
index 285ca2e4d4d..00000000000
--- a/src/librustc_metadata/def_key.rs
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::hir::def_id::DefIndex;
-use rustc::hir::map as hir_map;
-use syntax::parse::token::InternedString;
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct DefKey {
-    pub parent: Option<DefIndex>,
-    pub disambiguated_data: DisambiguatedDefPathData,
-}
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct DisambiguatedDefPathData {
-    pub data: DefPathData,
-    pub disambiguator: u32,
-}
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub enum DefPathData {
-    CrateRoot,
-    Misc,
-    Impl,
-    TypeNs,
-    ValueNs,
-    Module,
-    MacroDef,
-    ClosureExpr,
-    TypeParam,
-    LifetimeDef,
-    EnumVariant,
-    Field,
-    StructCtor,
-    Initializer,
-    Binding,
-    ImplTrait,
-}
-
-pub fn simplify_def_key(key: hir_map::DefKey) -> DefKey {
-    let data = DisambiguatedDefPathData {
-        data: simplify_def_path_data(key.disambiguated_data.data),
-        disambiguator: key.disambiguated_data.disambiguator,
-    };
-    DefKey {
-        parent: key.parent,
-        disambiguated_data: data,
-    }
-}
-
-fn simplify_def_path_data(data: hir_map::DefPathData) -> DefPathData {
-    match data {
-        hir_map::DefPathData::CrateRoot => DefPathData::CrateRoot,
-        hir_map::DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"),
-        hir_map::DefPathData::Misc => DefPathData::Misc,
-        hir_map::DefPathData::Impl => DefPathData::Impl,
-        hir_map::DefPathData::TypeNs(_) => DefPathData::TypeNs,
-        hir_map::DefPathData::ValueNs(_) => DefPathData::ValueNs,
-        hir_map::DefPathData::Module(_) => DefPathData::Module,
-        hir_map::DefPathData::MacroDef(_) => DefPathData::MacroDef,
-        hir_map::DefPathData::ClosureExpr => DefPathData::ClosureExpr,
-        hir_map::DefPathData::TypeParam(_) => DefPathData::TypeParam,
-        hir_map::DefPathData::LifetimeDef(_) => DefPathData::LifetimeDef,
-        hir_map::DefPathData::EnumVariant(_) => DefPathData::EnumVariant,
-        hir_map::DefPathData::Field(_) => DefPathData::Field,
-        hir_map::DefPathData::StructCtor => DefPathData::StructCtor,
-        hir_map::DefPathData::Initializer => DefPathData::Initializer,
-        hir_map::DefPathData::Binding(_) => DefPathData::Binding,
-        hir_map::DefPathData::ImplTrait => DefPathData::ImplTrait,
-    }
-}
-
-pub fn recover_def_key(key: DefKey, name: Option<InternedString>) -> hir_map::DefKey {
-    let data = hir_map::DisambiguatedDefPathData {
-        data: recover_def_path_data(key.disambiguated_data.data, name),
-        disambiguator: key.disambiguated_data.disambiguator,
-    };
-    hir_map::DefKey {
-        parent: key.parent,
-        disambiguated_data: data,
-    }
-}
-
-fn recover_def_path_data(data: DefPathData, name: Option<InternedString>) -> hir_map::DefPathData {
-    match data {
-        DefPathData::CrateRoot => hir_map::DefPathData::CrateRoot,
-        DefPathData::Misc => hir_map::DefPathData::Misc,
-        DefPathData::Impl => hir_map::DefPathData::Impl,
-        DefPathData::TypeNs => hir_map::DefPathData::TypeNs(name.unwrap()),
-        DefPathData::ValueNs => hir_map::DefPathData::ValueNs(name.unwrap()),
-        DefPathData::Module => hir_map::DefPathData::Module(name.unwrap()),
-        DefPathData::MacroDef => hir_map::DefPathData::MacroDef(name.unwrap()),
-        DefPathData::ClosureExpr => hir_map::DefPathData::ClosureExpr,
-        DefPathData::TypeParam => hir_map::DefPathData::TypeParam(name.unwrap()),
-        DefPathData::LifetimeDef => hir_map::DefPathData::LifetimeDef(name.unwrap()),
-        DefPathData::EnumVariant => hir_map::DefPathData::EnumVariant(name.unwrap()),
-        DefPathData::Field => hir_map::DefPathData::Field(name.unwrap()),
-        DefPathData::StructCtor => hir_map::DefPathData::StructCtor,
-        DefPathData::Initializer => hir_map::DefPathData::Initializer,
-        DefPathData::Binding => hir_map::DefPathData::Binding(name.unwrap()),
-        DefPathData::ImplTrait => hir_map::DefPathData::ImplTrait,
-    }
-}
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e228bf74302..0f067270b80 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -8,209 +8,242 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Metadata encoding
-
-#![allow(unused_must_use)] // everything is just a MemWriter, can't fail
-#![allow(non_camel_case_types)]
-
-use astencode::encode_inlined_item;
-use common::*;
 use cstore;
-use decoder;
-use def_key;
-use tyencode;
-use index::{self, IndexData};
+use index::Index;
+use schema::*;
 
-use middle::cstore::{InlinedItemRef, LinkMeta, tls};
+use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
+use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
 use rustc::hir::def;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use middle::dependency_format::Linkage;
-use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
+use rustc::middle::dependency_format::Linkage;
+use rustc::middle::lang_items;
+use rustc::mir;
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt};
 
-use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
-use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro};
+use rustc::session::config::{self, CrateTypeRustcMacro};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
-use rustc_serialize::Encodable;
-use std::cell::RefCell;
+use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
+use std::hash::Hash;
+use std::intrinsics;
 use std::io::prelude::*;
-use std::io::{Cursor, SeekFrom};
+use std::io::Cursor;
 use std::rc::Rc;
 use std::u32;
-use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
+use syntax::ast::{self, CRATE_NODE_ID};
 use syntax::attr;
-use errors::Handler;
 use syntax;
-use syntax_pos::BytePos;
-use rbml::writer::Encoder;
+use syntax_pos;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::Visitor;
 use rustc::hir::intravisit;
-use rustc::hir::map::DefKey;
 
-use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef};
+use super::index_builder::{FromId, IndexBuilder, Untracked};
 
 pub struct EncodeContext<'a, 'tcx: 'a> {
-    pub diag: &'a Handler,
+    opaque: opaque::Encoder<'a>,
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub reexports: &'a def::ExportMap,
-    pub link_meta: &'a LinkMeta,
-    pub cstore: &'a cstore::CStore,
-    pub type_abbrevs: tyencode::abbrev_map<'tcx>,
-    pub reachable: &'a NodeSet,
-    pub mir_map: &'a MirMap<'tcx>,
+    reexports: &'a def::ExportMap,
+    link_meta: &'a LinkMeta,
+    cstore: &'a cstore::CStore,
+    reachable: &'a NodeSet,
+    mir_map: &'a MirMap<'tcx>,
+
+    lazy_state: LazyState,
+    type_shorthands: FnvHashMap<Ty<'tcx>, usize>,
+    predicate_shorthands: FnvHashMap<ty::Predicate<'tcx>, usize>,
 }
 
-impl<'a, 'tcx> EncodeContext<'a,'tcx> {
-    fn local_id(&self, def_id: DefId) -> NodeId {
-        self.tcx.map.as_local_node_id(def_id).unwrap()
+macro_rules! encoder_methods {
+    ($($name:ident($ty:ty);)*) => {
+        $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
+            self.opaque.$name(value)
+        })*
     }
 }
 
-fn encode_name(rbml_w: &mut Encoder, name: Name) {
-    rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
-}
+impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
+    type Error = <opaque::Encoder<'a> as Encoder>::Error;
 
-fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
-    rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
-}
+    fn emit_nil(&mut self) -> Result<(), Self::Error> {
+        Ok(())
+    }
 
-fn encode_def_key(rbml_w: &mut Encoder, key: DefKey) {
-    let simple_key = def_key::simplify_def_key(key);
-    rbml_w.start_tag(tag_def_key);
-    simple_key.encode(rbml_w);
-    rbml_w.end_tag();
-}
+    encoder_methods! {
+        emit_usize(usize);
+        emit_u64(u64);
+        emit_u32(u32);
+        emit_u16(u16);
+        emit_u8(u8);
 
-/// For every DefId that we create a metadata item for, we include a
-/// serialized copy of its DefKey, which allows us to recreate a path.
-fn encode_def_id_and_key(ecx: &EncodeContext,
-                         rbml_w: &mut Encoder,
-                         def_id: DefId)
-{
-    encode_def_id(rbml_w, def_id);
-    let def_key = ecx.tcx.map.def_key(def_id);
-    encode_def_key(rbml_w, def_key);
-}
+        emit_isize(isize);
+        emit_i64(i64);
+        emit_i32(i32);
+        emit_i16(i16);
+        emit_i8(i8);
 
-fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
-                              ecx: &EncodeContext<'a, 'tcx>,
-                              trait_ref: ty::TraitRef<'tcx>,
-                              tag: usize) {
-    rbml_w.start_tag(tag);
-    tyencode::enc_trait_ref(rbml_w.writer, &ecx.ty_str_ctxt(), trait_ref);
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
+        emit_bool(bool);
+        emit_f64(f64);
+        emit_f32(f32);
+        emit_char(char);
+        emit_str(&str);
+    }
 }
 
-// Item info table encoding
-fn encode_family(rbml_w: &mut Encoder, c: char) {
-    rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8);
+impl<'a, 'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
+        self.emit_lazy_distance(lazy.position, Lazy::<T>::min_size())
+    }
 }
 
-pub fn def_to_u64(did: DefId) -> u64 {
-    assert!(did.index.as_u32() < u32::MAX);
-    (did.krate as u64) << 32 | (did.index.as_usize() as u64)
+impl<'a, 'tcx, T> SpecializedEncoder<LazySeq<T>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, seq: &LazySeq<T>) -> Result<(), Self::Error> {
+        self.emit_usize(seq.len)?;
+        if seq.len == 0 {
+            return Ok(());
+        }
+        self.emit_lazy_distance(seq.position, LazySeq::<T>::min_size(seq.len))
+    }
 }
 
-pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String {
-    format!("{}:{}", did.krate, did.index.as_usize())
+impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
+        self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands)
+    }
 }
 
-fn encode_item_variances(rbml_w: &mut Encoder,
-                         ecx: &EncodeContext,
-                         id: NodeId) {
-    let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
-    rbml_w.start_tag(tag_item_variances);
-    v.encode(rbml_w);
-    rbml_w.end_tag();
+impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>)
+                          -> Result<(), Self::Error> {
+        predicates.parent.encode(self)?;
+        predicates.predicates.len().encode(self)?;
+        for predicate in &predicates.predicates {
+            self.encode_with_shorthand(predicate, predicate, |ecx| &mut ecx.predicate_shorthands)?
+        }
+        Ok(())
+    }
 }
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_bounds_and_type_for_item(&mut self,
-                                       id: NodeId) {
-        let ecx = self.ecx();
-        self.encode_bounds_and_type(&ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
-                                    &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    pub fn position(&self) -> usize {
+        self.opaque.position()
     }
 
-    fn encode_bounds_and_type(&mut self,
-                              scheme: &ty::TypeScheme<'tcx>,
-                              predicates: &ty::GenericPredicates<'tcx>) {
-        self.encode_generics(&scheme.generics, &predicates);
-        self.encode_type(scheme.ty);
+    fn emit_node<F: FnOnce(&mut Self, usize) -> R, R>(&mut self, f: F) -> R {
+        assert_eq!(self.lazy_state, LazyState::NoNode);
+        let pos = self.position();
+        self.lazy_state = LazyState::NodeStart(pos);
+        let r = f(self, pos);
+        self.lazy_state = LazyState::NoNode;
+        r
     }
-}
 
-fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
-    let id = def_to_u64(vid);
-    rbml_w.wr_tagged_u64(tag_items_data_item_variant, id);
-    rbml_w.wr_tagged_u64(tag_mod_child, id);
-}
+    fn emit_lazy_distance(&mut self, position: usize, min_size: usize)
+                          -> Result<(), <Self as Encoder>::Error> {
+        let min_end = position + min_size;
+        let distance = match self.lazy_state {
+            LazyState::NoNode => {
+                bug!("emit_lazy_distance: outside of a metadata node")
+            }
+            LazyState::NodeStart(start) => {
+                assert!(min_end <= start);
+                start - min_end
+            }
+            LazyState::Previous(last_min_end) => {
+                assert!(last_min_end <= position);
+                position - last_min_end
+            }
+        };
+        self.lazy_state = LazyState::Previous(min_end);
+        self.emit_usize(distance)
+    }
 
-fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                            rbml_w: &mut Encoder,
-                            closure_type: &ty::ClosureTy<'tcx>) {
-    tyencode::enc_closure_ty(rbml_w.writer, &ecx.ty_str_ctxt(), closure_type);
-    rbml_w.mark_stable_position();
-}
+    pub fn lazy<T: Encodable>(&mut self, value: &T) -> Lazy<T> {
+        self.emit_node(|ecx, pos| {
+            value.encode(ecx).unwrap();
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_type(&mut self,
-                   typ: Ty<'tcx>) {
-        let ecx = self.ecx;
-        self.rbml_w.start_tag(tag_items_data_item_type);
-        tyencode::enc_ty(self.rbml_w.writer, &ecx.ty_str_ctxt(), typ);
-        self.rbml_w.mark_stable_position();
-        self.rbml_w.end_tag();
+            assert!(pos + Lazy::<T>::min_size() <= ecx.position());
+            Lazy::with_position(pos)
+        })
     }
 
-    fn encode_disr_val(&mut self,
-                       disr_val: ty::Disr) {
-        // convert to u64 so just the number is printed, without any type info
-        self.rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
+    fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
+    where I: IntoIterator<Item=T>, T: Encodable {
+        self.emit_node(|ecx, pos| {
+            let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
+
+            assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+            LazySeq::with_position_and_length(pos, len)
+        })
     }
 
-    fn encode_parent_item(&mut self, id: DefId) {
-        self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
+    fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq<T>
+    where I: IntoIterator<Item=&'b T>, T: 'b + Encodable {
+        self.emit_node(|ecx, pos| {
+            let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
+
+            assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+            LazySeq::with_position_and_length(pos, len)
+        })
     }
 
-    fn encode_struct_fields(&mut self,
-                            variant: ty::VariantDef) {
-        for f in &variant.fields {
-            if variant.kind == ty::VariantKind::Tuple {
-                self.rbml_w.start_tag(tag_item_unnamed_field);
-            } else {
-                self.rbml_w.start_tag(tag_item_field);
-                encode_name(self.rbml_w, f.name);
-            }
-            self.encode_struct_field_family(f.vis);
-            encode_def_id(self.rbml_w, f.did);
-            self.rbml_w.end_tag();
+    /// Encode the given value or a previously cached shorthand.
+    fn encode_with_shorthand<T, U, M>(&mut self, value: &T, variant: &U, map: M)
+                                      -> Result<(), <Self as Encoder>::Error>
+    where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap<T, usize>,
+          T: Clone + Eq + Hash,
+          U: Encodable {
+        let existing_shorthand = map(self).get(value).cloned();
+        if let Some(shorthand) = existing_shorthand {
+            return self.emit_usize(shorthand);
         }
-    }
-}
 
-impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
-    fn encode_enum_variant_infos(&mut self,
-                                 enum_did: DefId) {
-        debug!("encode_enum_variant_info(enum_did={:?})", enum_did);
-        let ecx = self.ecx();
-        let def = ecx.tcx.lookup_adt_def(enum_did);
-        self.encode_fields(enum_did);
-        for (i, variant) in def.variants.iter().enumerate() {
-            self.record(variant.did,
-                        ItemContentBuilder::encode_enum_variant_info,
-                        (enum_did, Untracked(i)));
+        let start = self.position();
+        variant.encode(self)?;
+        let len = self.position() - start;
+
+        // The shorthand encoding uses the same usize as the
+        // discriminant, with an offset so they can't conflict.
+        let discriminant = unsafe {
+            intrinsics::discriminant_value(variant)
+        };
+        assert!(discriminant < SHORTHAND_OFFSET as u64);
+        let shorthand = start + SHORTHAND_OFFSET;
+
+        // Get the number of bits that leb128 could fit
+        // in the same space as the fully encoded type.
+        let leb128_bits = len * 7;
+
+        // Check that the shorthand is a not longer than the
+        // full encoding itself, i.e. it's an obvious win.
+        if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
+            map(self).insert(value.clone(), shorthand);
         }
+
+        Ok(())
+    }
+
+    /// For every DefId that we create a metadata item for, we include a
+    /// serialized copy of its DefKey, which allows us to recreate a path.
+    fn encode_def_key(&mut self, def_id: DefId) -> Lazy<hir::map::DefKey> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.map.def_key(def_id))
+    }
+
+    fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
+        let tcx = self.tcx;
+        self.lazy_seq(tcx.item_variances(def_id).iter().cloned())
+    }
+
+    fn encode_item_type(&mut self, def_id: DefId) -> Lazy<Ty<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.lookup_item_type(def_id).ty)
     }
-}
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
     /// Encode data for the given variant of the given ADT. The
     /// index of the variant is untracked: this is ok because we
     /// will have to lookup the adt-def by its id, and that gives us
@@ -218,191 +251,122 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
     /// e.g., the length of the various vectors).
     fn encode_enum_variant_info(&mut self,
                                 (enum_did, Untracked(index)):
-                                (DefId, Untracked<usize>)) {
-        let ecx = self.ecx;
-        let def = ecx.tcx.lookup_adt_def(enum_did);
+                                (DefId, Untracked<usize>)) -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let def = tcx.lookup_adt_def(enum_did);
         let variant = &def.variants[index];
-        let vid = variant.did;
-        let variant_node_id = ecx.local_id(vid);
-        encode_def_id_and_key(ecx, self.rbml_w, vid);
-        encode_family(self.rbml_w, match variant.kind {
-            ty::VariantKind::Struct => 'V',
-            ty::VariantKind::Tuple => 'v',
-            ty::VariantKind::Unit => 'w',
-        });
-        encode_name(self.rbml_w, variant.name);
-        self.encode_parent_item(enum_did);
-
-        let enum_id = ecx.tcx.map.as_local_node_id(enum_did).unwrap();
-        let enum_vis = &ecx.tcx.map.expect_item(enum_id).vis;
-        self.encode_visibility(enum_vis);
-
-        let attrs = ecx.tcx.get_attrs(vid);
-        encode_attributes(self.rbml_w, &attrs);
-        self.encode_repr_attrs(&attrs);
-
-        let stab = ecx.tcx.lookup_stability(vid);
-        let depr = ecx.tcx.lookup_deprecation(vid);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        self.encode_struct_fields(variant);
-        self.encode_disr_val(variant.disr_val);
-        self.encode_bounds_and_type_for_item(variant_node_id);
-    }
-}
-
-fn encode_reexports(ecx: &EncodeContext,
-                    rbml_w: &mut Encoder,
-                    id: NodeId) {
-    debug!("(encoding info for module) encoding reexports for {}", id);
-    match ecx.reexports.get(&id) {
-        Some(exports) => {
-            debug!("(encoding info for module) found reexports for {}", id);
-            for exp in exports {
-                debug!("(encoding info for module) reexport '{}' ({:?}) for \
-                        {}",
-                       exp.name,
-                       exp.def_id,
-                       id);
-                rbml_w.start_tag(tag_items_data_item_reexport);
-                rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
-                                     def_to_u64(exp.def_id));
-                rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
-                                     &exp.name.as_str());
-                rbml_w.end_tag();
-            }
-        },
-        None => debug!("(encoding info for module) found no reexports for {}", id),
+        let def_id = variant.did;
+
+        let data = VariantData {
+            kind: variant.kind,
+            disr: variant.disr_val.to_u64_unchecked(),
+            struct_ctor: None
+        };
+
+        let enum_id = tcx.map.as_local_node_id(enum_did).unwrap();
+        let enum_vis = &tcx.map.expect_item(enum_id).vis;
+
+        Entry {
+            kind: EntryKind::Variant(self.lazy(&data)),
+            visibility: enum_vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+            children: self.lazy_seq(variant.fields.iter().map(|f| {
+                assert!(f.did.is_local());
+                f.did.index
+            })),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
+        }
     }
-}
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
     fn encode_info_for_mod(&mut self,
-                           FromId(id, (md, attrs, name, vis)):
-                           FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) {
-        let ecx = self.ecx();
-
-        encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id));
-        encode_family(self.rbml_w, 'm');
-        encode_name(self.rbml_w, name);
-        debug!("(encoding info for module) encoding info for module ID {}", id);
-
-        // Encode info about all the module children.
-        for item_id in &md.item_ids {
-            self.rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-        }
-
-        self.encode_visibility(vis);
-
-        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id));
-        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id));
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        // Encode the reexports of this module, if this module is public.
-        if *vis == hir::Public {
-            debug!("(encoding info for module) encoding reexports for {}", id);
-            encode_reexports(ecx, self.rbml_w, id);
+                           FromId(id, (md, attrs, vis)):
+                           FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>)
+                           -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let def_id = tcx.map.local_def_id(id);
+
+        let data = ModData {
+            reexports: match self.reexports.get(&id) {
+                Some(exports) if *vis == hir::Public => {
+                    self.lazy_seq_ref(exports)
+                }
+                _ => LazySeq::empty()
+            }
+        };
+
+        Entry {
+            kind: EntryKind::Mod(self.lazy(&data)),
+            visibility: vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(attrs),
+            children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
+                tcx.map.local_def_id(item_id.id).index
+            })),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: None,
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+
+            ast: None,
+            mir: None
         }
-        encode_attributes(self.rbml_w, attrs);
-    }
-
-    fn encode_struct_field_family(&mut self,
-                                  visibility: ty::Visibility) {
-        encode_family(self.rbml_w, if visibility.is_public() { 'g' } else { 'N' });
-    }
-
-    fn encode_visibility<T: HasVisibility>(&mut self, visibility: T) {
-        let ch = if visibility.is_public() { 'y' } else { 'i' };
-        self.rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
     }
 }
 
-trait HasVisibility: Sized {
-    fn is_public(self) -> bool;
+trait Visibility {
+    fn simplify(&self) -> ty::Visibility;
 }
 
-impl<'a> HasVisibility for &'a hir::Visibility {
-    fn is_public(self) -> bool {
-        *self == hir::Public
-    }
-}
-
-impl HasVisibility for ty::Visibility {
-    fn is_public(self) -> bool {
-        self == ty::Visibility::Public
-    }
-}
-
-fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
-    rbml_w.start_tag(tag_items_data_item_constness);
-    let ch = match constness {
-        hir::Constness::Const => 'c',
-        hir::Constness::NotConst => 'n',
-    };
-    rbml_w.wr_str(&ch.to_string());
-    rbml_w.end_tag();
-}
-
-fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) {
-    let ch = match defaultness {
-        hir::Defaultness::Default => 'd',
-        hir::Defaultness::Final => 'f',
-    };
-    rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
-}
-
-fn encode_explicit_self(rbml_w: &mut Encoder,
-                        explicit_self: &ty::ExplicitSelfCategory) {
-    let tag = tag_item_trait_method_explicit_self;
-
-    // Encode the base self type.
-    match *explicit_self {
-        ty::ExplicitSelfCategory::Static => {
-            rbml_w.wr_tagged_bytes(tag, &['s' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByValue => {
-            rbml_w.wr_tagged_bytes(tag, &['v' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByBox => {
-            rbml_w.wr_tagged_bytes(tag, &['~' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByReference(_, m) => {
-            // FIXME(#4846) encode custom lifetime
-            let ch = encode_mutability(m);
-            rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]);
+impl Visibility for hir::Visibility {
+    fn simplify(&self) -> ty::Visibility {
+        if *self == hir::Public {
+            ty::Visibility::Public
+        } else {
+            ty::Visibility::PrivateExternal
         }
     }
+}
 
-    fn encode_mutability(m: hir::Mutability) -> u8 {
-        match m {
-            hir::MutImmutable => 'i' as u8,
-            hir::MutMutable => 'm' as u8,
+impl Visibility for ty::Visibility {
+    fn simplify(&self) -> ty::Visibility {
+        if *self == ty::Visibility::Public {
+            ty::Visibility::Public
+        } else {
+            ty::Visibility::PrivateExternal
         }
     }
 }
 
-fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
-    rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
-}
-
-impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     fn encode_fields(&mut self,
                      adt_def_id: DefId) {
-        let def = self.ecx().tcx.lookup_adt_def(adt_def_id);
+        let def = self.tcx.lookup_adt_def(adt_def_id);
         for (variant_index, variant) in def.variants.iter().enumerate() {
             for (field_index, field) in variant.fields.iter().enumerate() {
                 self.record(field.did,
-                            ItemContentBuilder::encode_field,
+                            EncodeContext::encode_field,
                             (adt_def_id, Untracked((variant_index, field_index))));
             }
         }
     }
 }
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     /// Encode data for the given field of the given variant of the
     /// given ADT. The indices of the variant/field are untracked:
     /// this is ok because we will have to lookup the adt-def by its
@@ -411,755 +375,491 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
     /// vectors).
     fn encode_field(&mut self,
                     (adt_def_id, Untracked((variant_index, field_index))):
-                    (DefId, Untracked<(usize, usize)>)) {
-        let ecx = self.ecx();
-        let def = ecx.tcx.lookup_adt_def(adt_def_id);
-        let variant = &def.variants[variant_index];
+                    (DefId, Untracked<(usize, usize)>)) -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index];
         let field = &variant.fields[field_index];
 
-        let nm = field.name;
-        let id = ecx.local_id(field.did);
-        debug!("encode_field: encoding {} {}", nm, id);
-
-        self.encode_struct_field_family(field.vis);
-        encode_name(self.rbml_w, nm);
-        self.encode_bounds_and_type_for_item(id);
-        encode_def_id_and_key(ecx, self.rbml_w, field.did);
-
-        let stab = ecx.tcx.lookup_stability(field.did);
-        let depr = ecx.tcx.lookup_deprecation(field.did);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-    }
-}
-
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_struct_ctor(&mut self,
-                          (struct_def_id, struct_node_id, ctor_node_id):
-                          (DefId, ast::NodeId, ast::NodeId)) {
-        let ecx = self.ecx();
-        let def = ecx.tcx.lookup_adt_def(struct_def_id);
-        let variant = def.struct_variant();
-        let item = ecx.tcx.map.expect_item(struct_node_id);
-        let ctor_def_id = ecx.tcx.map.local_def_id(ctor_node_id);
-        encode_def_id_and_key(ecx, self.rbml_w, ctor_def_id);
-        encode_family(self.rbml_w, match variant.kind {
-            ty::VariantKind::Struct => 'S',
-            ty::VariantKind::Tuple => 's',
-            ty::VariantKind::Unit => 'u',
-        });
-        self.encode_bounds_and_type_for_item(ctor_node_id);
-        encode_name(self.rbml_w, item.name);
-        self.encode_parent_item(struct_def_id);
-
-        let stab = ecx.tcx.lookup_stability(ctor_def_id);
-        let depr = ecx.tcx.lookup_deprecation(ctor_def_id);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        // indicate that this is a tuple struct ctor, because
-        // downstream users will normally want the tuple struct
-        // definition, but without this there is no way for them
-        // to tell that they actually have a ctor rather than a
-        // normal function
-        self.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
-    }
-}
-
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_generics(&mut self,
-                       generics: &ty::Generics<'tcx>,
-                       predicates: &ty::GenericPredicates<'tcx>)
-    {
-        let ecx = self.ecx();
-        self.rbml_w.start_tag(tag_item_generics);
-        tyencode::enc_generics(self.rbml_w.writer, &ecx.ty_str_ctxt(), generics);
-        self.rbml_w.mark_stable_position();
-        self.rbml_w.end_tag();
-        self.encode_predicates(predicates, tag_item_predicates);
-    }
-
-    fn encode_predicates(&mut self,
-                         predicates: &ty::GenericPredicates<'tcx>,
-                         tag: usize) {
-        self.rbml_w.start_tag(tag);
-        if let Some(def_id) = predicates.parent {
-            self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id));
+        let def_id = field.did;
+        let variant_id = tcx.map.as_local_node_id(variant.did).unwrap();
+        let variant_data = tcx.map.expect_variant_data(variant_id);
+
+        Entry {
+            kind: EntryKind::Field,
+            visibility: field.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
         }
-        for predicate in &predicates.predicates {
-            let xref = self.add_xref(XRef::Predicate(predicate.clone()));
-            self.rbml_w.wr_tagged_u32(tag_predicate, xref);
-        }
-        self.rbml_w.end_tag();
     }
 
-    fn encode_method_ty_fields(&mut self,
-                               method_ty: &ty::Method<'tcx>) {
-        let ecx = self.ecx();
-        encode_def_id_and_key(ecx, self.rbml_w, method_ty.def_id);
-        encode_name(self.rbml_w, method_ty.name);
-        self.encode_generics(&method_ty.generics, &method_ty.predicates);
-        self.encode_visibility(method_ty.vis);
-        encode_explicit_self(self.rbml_w, &method_ty.explicit_self);
-        match method_ty.explicit_self {
-            ty::ExplicitSelfCategory::Static => {
-                encode_family(self.rbml_w, STATIC_METHOD_FAMILY);
-            }
-            _ => encode_family(self.rbml_w, METHOD_FAMILY)
+    fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId))
+                          -> Entry<'tcx> {
+        let variant = self.tcx.lookup_adt_def(adt_def_id).struct_variant();
+
+        let data = VariantData {
+            kind: variant.kind,
+            disr: variant.disr_val.to_u64_unchecked(),
+            struct_ctor: Some(def_id.index)
+        };
+
+        Entry {
+            kind: EntryKind::Struct(self.lazy(&data)),
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
         }
     }
-}
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_info_for_trait_item(&mut self,
-                                  (trait_def_id, item_def_id, trait_item):
-                                  (DefId, DefId, &hir::TraitItem)) {
-        let ecx = self.ecx;
-        let tcx = ecx.tcx;
-
-        self.encode_parent_item(trait_def_id);
+    fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(tcx.lookup_generics(def_id))
+    }
 
-        let stab = tcx.lookup_stability(item_def_id);
-        let depr = tcx.lookup_deprecation(item_def_id);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
+    fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.lookup_predicates(def_id))
+    }
 
-        let trait_item_type =
-            tcx.impl_or_trait_item(item_def_id);
-        let is_nonstatic_method;
-        match trait_item_type {
-            ty::ConstTraitItem(associated_const) => {
-                encode_name(self.rbml_w, associated_const.name);
-                encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id);
-                self.encode_visibility(associated_const.vis);
+    fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-                encode_family(self.rbml_w, 'C');
+        let node_id = tcx.map.as_local_node_id(def_id).unwrap();
+        let ast_item = tcx.map.expect_trait_item(node_id);
+        let trait_item = tcx.impl_or_trait_item(def_id);
 
-                self.encode_bounds_and_type_for_item(
-                    ecx.local_id(associated_const.def_id));
+        let container = |has_body| if has_body {
+            AssociatedContainer::TraitWithDefault
+        } else {
+            AssociatedContainer::TraitRequired
+        };
 
-                is_nonstatic_method = false;
+        let kind = match trait_item {
+            ty::ConstTraitItem(ref associated_const) => {
+                EntryKind::AssociatedConst(container(associated_const.has_value))
             }
-            ty::MethodTraitItem(method_ty) => {
-                let method_def_id = item_def_id;
-
-                self.encode_method_ty_fields(&method_ty);
-
-                match method_ty.explicit_self {
-                    ty::ExplicitSelfCategory::Static => {
-                        encode_family(self.rbml_w,
-                                      STATIC_METHOD_FAMILY);
-                    }
-                    _ => {
-                        encode_family(self.rbml_w,
-                                      METHOD_FAMILY);
+            ty::MethodTraitItem(ref method_ty) => {
+                let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+                    FnData {
+                        constness: hir::Constness::NotConst,
+                        arg_names: self.encode_fn_arg_names(&sig.decl)
                     }
-                }
-                self.encode_bounds_and_type_for_item(ecx.local_id(method_def_id));
-
-                is_nonstatic_method = method_ty.explicit_self !=
-                    ty::ExplicitSelfCategory::Static;
-            }
-            ty::TypeTraitItem(associated_type) => {
-                encode_name(self.rbml_w, associated_type.name);
-                encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id);
-                encode_item_sort(self.rbml_w, 't');
-                encode_family(self.rbml_w, 'y');
-
-                if let Some(ty) = associated_type.ty {
-                    self.encode_type(ty);
-                }
-
-                is_nonstatic_method = false;
-            }
-        }
-
-        encode_attributes(self.rbml_w, &trait_item.attrs);
-        match trait_item.node {
-            hir::ConstTraitItem(_, ref default) => {
-                if default.is_some() {
-                    encode_item_sort(self.rbml_w, 'C');
                 } else {
-                    encode_item_sort(self.rbml_w, 'c');
-                }
-
-                encode_inlined_item(ecx, self.rbml_w,
-                                    InlinedItemRef::TraitItem(trait_def_id, trait_item));
-                self.encode_mir(trait_item.id);
+                    bug!()
+                };
+                let data = MethodData {
+                    fn_data: fn_data,
+                    container: container(method_ty.has_body),
+                    explicit_self: self.lazy(&method_ty.explicit_self)
+                };
+                EntryKind::Method(self.lazy(&data))
+            }
+            ty::TypeTraitItem(_) => {
+                EntryKind::AssociatedType(container(false))
             }
-            hir::MethodTraitItem(ref sig, ref body) => {
-                // If this is a static method, we've already
-                // encoded self.
-                if is_nonstatic_method {
-                    self.encode_bounds_and_type_for_item(
-                        ecx.local_id(item_def_id));
+        };
+
+        Entry {
+            kind: kind,
+            visibility: trait_item.vis().simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&ast_item.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match trait_item {
+                ty::ConstTraitItem(_) |
+                ty::MethodTraitItem(_) => {
+                    Some(self.encode_item_type(def_id))
                 }
-
-                if body.is_some() {
-                    encode_item_sort(self.rbml_w, 'p');
-                    self.encode_mir(trait_item.id);
-                } else {
-                    encode_item_sort(self.rbml_w, 'r');
+                ty::TypeTraitItem(ref associated_type) => {
+                    associated_type.ty.map(|ty| self.lazy(&ty))
                 }
-                self.encode_method_argument_names(&sig.decl);
-            }
-
-            hir::TypeTraitItem(..) => {}
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: if let ty::ConstTraitItem(_) = trait_item {
+                let trait_def_id = trait_item.container().id();
+                Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
+            } else {
+                None
+            },
+            mir: self.encode_mir(def_id)
         }
     }
 
-    fn encode_info_for_impl_item(&mut self,
-                                 (impl_id, impl_item_def_id, ast_item):
-                                 (NodeId, DefId, Option<&hir::ImplItem>)) {
-        match self.ecx.tcx.impl_or_trait_item(impl_item_def_id) {
-            ty::ConstTraitItem(ref associated_const) => {
-                self.encode_info_for_associated_const(&associated_const,
-                                                      impl_id,
-                                                      ast_item)
+    fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
+        let ast_item = self.tcx.map.expect_impl_item(node_id);
+        let impl_item = self.tcx.impl_or_trait_item(def_id);
+        let impl_def_id = impl_item.container().id();
+
+        let container = match ast_item.defaultness {
+            hir::Defaultness::Default => AssociatedContainer::ImplDefault,
+            hir::Defaultness::Final => AssociatedContainer::ImplFinal
+        };
+
+        let kind = match impl_item {
+            ty::ConstTraitItem(_) => {
+                EntryKind::AssociatedConst(container)
             }
-            ty::MethodTraitItem(ref method_type) => {
-                self.encode_info_for_method(&method_type,
-                                            false,
-                                            impl_id,
-                                            ast_item)
+            ty::MethodTraitItem(ref method_ty) => {
+                let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+                    FnData {
+                        constness: sig.constness,
+                        arg_names: self.encode_fn_arg_names(&sig.decl)
+                    }
+                } else {
+                    bug!()
+                };
+                let data = MethodData {
+                    fn_data: fn_data,
+                    container: container,
+                    explicit_self: self.lazy(&method_ty.explicit_self)
+                };
+                EntryKind::Method(self.lazy(&data))
             }
-            ty::TypeTraitItem(ref associated_type) => {
-                self.encode_info_for_associated_type(&associated_type,
-                                                     impl_id,
-                                                     ast_item)
+            ty::TypeTraitItem(_) => {
+                EntryKind::AssociatedType(container)
             }
-        }
-    }
-
-    fn encode_info_for_associated_const(&mut self,
-                                        associated_const: &ty::AssociatedConst,
-                                        parent_id: NodeId,
-                                        impl_item_opt: Option<&hir::ImplItem>) {
-        let ecx = self.ecx();
-        debug!("encode_info_for_associated_const({:?},{:?})",
-               associated_const.def_id,
-               associated_const.name);
-
-        encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id);
-        encode_name(self.rbml_w, associated_const.name);
-        self.encode_visibility(associated_const.vis);
-        encode_family(self.rbml_w, 'C');
-
-        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
-        encode_item_sort(self.rbml_w, 'C');
-
-        self.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id));
-
-        let stab = ecx.tcx.lookup_stability(associated_const.def_id);
-        let depr = ecx.tcx.lookup_deprecation(associated_const.def_id);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        if let Some(ii) = impl_item_opt {
-            encode_attributes(self.rbml_w, &ii.attrs);
-            encode_defaultness(self.rbml_w, ii.defaultness);
-            encode_inlined_item(ecx,
-                                self.rbml_w,
-                                InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                         ii));
-            self.encode_mir(ii.id);
-        }
-    }
-
-    fn encode_info_for_method(&mut self,
-                              m: &ty::Method<'tcx>,
-                              is_default_impl: bool,
-                              parent_id: NodeId,
-                              impl_item_opt: Option<&hir::ImplItem>) {
-        let ecx = self.ecx();
-
-        debug!("encode_info_for_method: {:?} {:?}", m.def_id,
-               m.name);
-        self.encode_method_ty_fields(m);
-        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
-        encode_item_sort(self.rbml_w, 'r');
-
-        let stab = ecx.tcx.lookup_stability(m.def_id);
-        let depr = ecx.tcx.lookup_deprecation(m.def_id);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        let m_node_id = ecx.local_id(m.def_id);
-        self.encode_bounds_and_type_for_item(m_node_id);
-
-        if let Some(impl_item) = impl_item_opt {
-            if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
-                encode_attributes(self.rbml_w, &impl_item.attrs);
-                let generics = ecx.tcx.lookup_generics(m.def_id);
-                let types = generics.parent_types as usize + generics.types.len();
-                let needs_inline = types > 0 || is_default_impl ||
-                    attr::requests_inline(&impl_item.attrs);
-                if sig.constness == hir::Constness::Const {
-                    encode_inlined_item(
-                        ecx,
-                        self.rbml_w,
-                        InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                 impl_item));
+        };
+
+        let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item {
+            (true, true)
+        } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+            let generics = self.tcx.lookup_generics(def_id);
+            let types = generics.parent_types as usize + generics.types.len();
+            let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
+            let is_const_fn = sig.constness == hir::Constness::Const;
+            (is_const_fn, needs_inline || is_const_fn)
+        } else {
+            (false, false)
+        };
+
+        Entry {
+            kind: kind,
+            visibility: impl_item.vis().simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&ast_item.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match impl_item {
+                ty::ConstTraitItem(_) |
+                ty::MethodTraitItem(_) => {
+                    Some(self.encode_item_type(def_id))
                 }
-                if needs_inline || sig.constness == hir::Constness::Const {
-                    self.encode_mir(impl_item.id);
+                ty::TypeTraitItem(ref associated_type) => {
+                    associated_type.ty.map(|ty| self.lazy(&ty))
                 }
-                encode_constness(self.rbml_w, sig.constness);
-                encode_defaultness(self.rbml_w, impl_item.defaultness);
-                self.encode_method_argument_names(&sig.decl);
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: if ast {
+                Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
+            } else {
+                None
+            },
+            mir: if mir {
+                self.encode_mir(def_id)
+            } else {
+                None
             }
         }
     }
 
-    fn encode_info_for_associated_type(&mut self,
-                                       associated_type: &ty::AssociatedType<'tcx>,
-                                       parent_id: NodeId,
-                                       impl_item_opt: Option<&hir::ImplItem>) {
-        let ecx = self.ecx();
-        debug!("encode_info_for_associated_type({:?},{:?})",
-               associated_type.def_id,
-               associated_type.name);
-
-        encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id);
-        encode_name(self.rbml_w, associated_type.name);
-        self.encode_visibility(associated_type.vis);
-        encode_family(self.rbml_w, 'y');
-        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
-        encode_item_sort(self.rbml_w, 't');
-
-        let stab = ecx.tcx.lookup_stability(associated_type.def_id);
-        let depr = ecx.tcx.lookup_deprecation(associated_type.def_id);
-        encode_stability(self.rbml_w, stab);
-        encode_deprecation(self.rbml_w, depr);
-
-        if let Some(ii) = impl_item_opt {
-            encode_attributes(self.rbml_w, &ii.attrs);
-            encode_defaultness(self.rbml_w, ii.defaultness);
-        }
-
-        if let Some(ty) = associated_type.ty {
-            self.encode_type(ty);
-        }
-    }
-}
-
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_method_argument_names(&mut self,
-                                    decl: &hir::FnDecl) {
-        self.rbml_w.start_tag(tag_method_argument_names);
-        for arg in &decl.inputs {
-            let tag = tag_method_argument_name;
+    fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
+        self.lazy_seq(decl.inputs.iter().map(|arg| {
             if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
-                let name = path1.node.as_str();
-                self.rbml_w.wr_tagged_bytes(tag, name.as_bytes());
+                path1.node
             } else {
-                self.rbml_w.wr_tagged_bytes(tag, &[]);
+                syntax::parse::token::intern("")
             }
-        }
-        self.rbml_w.end_tag();
-    }
-
-    fn encode_repr_attrs(&mut self,
-                         attrs: &[ast::Attribute]) {
-        let ecx = self.ecx();
-        let mut repr_attrs = Vec::new();
-        for attr in attrs {
-            repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
-                                                    attr));
-        }
-        self.rbml_w.start_tag(tag_items_data_item_repr);
-        repr_attrs.encode(self.rbml_w);
-        self.rbml_w.end_tag();
+        }))
     }
 
-    fn encode_mir(&mut self, node_id: NodeId) {
-        let ecx = self.ecx();
-        let def_id = ecx.tcx.map.local_def_id(node_id);
-        if let Some(mir) = ecx.mir_map.map.get(&def_id) {
-            self.rbml_w.start_tag(tag_mir as usize);
-            self.rbml_w.emit_opaque(|opaque_encoder| {
-                tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
-                    Encodable::encode(mir, opaque_encoder)
-                })
-            }).unwrap();
-            self.rbml_w.end_tag();
-        }
+    fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::repr::Mir<'tcx>>> {
+        self.mir_map.map.get(&def_id).map(|mir| self.lazy(mir))
     }
-}
 
-const FN_FAMILY: char = 'f';
-const STATIC_METHOD_FAMILY: char = 'F';
-const METHOD_FAMILY: char = 'h';
-
-// Encodes the inherent implementations of a structure, enumeration, or trait.
-fn encode_inherent_implementations(ecx: &EncodeContext,
-                                   rbml_w: &mut Encoder,
-                                   def_id: DefId) {
-    match ecx.tcx.inherent_impls.borrow().get(&def_id) {
-        None => {}
-        Some(implementations) => {
-            for &impl_def_id in implementations.iter() {
-                rbml_w.start_tag(tag_items_data_item_inherent_impl);
-                encode_def_id(rbml_w, impl_def_id);
-                rbml_w.end_tag();
+    // Encodes the inherent implementations of a structure, enumeration, or trait.
+    fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
+        match self.tcx.inherent_impls.borrow().get(&def_id) {
+            None => LazySeq::empty(),
+            Some(implementations) => {
+                self.lazy_seq(implementations.iter().map(|&def_id| {
+                    assert!(def_id.is_local());
+                    def_id.index
+                }))
             }
         }
     }
-}
-
-fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
-    stab_opt.map(|stab| {
-        rbml_w.start_tag(tag_items_data_item_stability);
-        stab.encode(rbml_w).unwrap();
-        rbml_w.end_tag();
-    });
-}
-
-fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>) {
-    depr_opt.map(|depr| {
-        rbml_w.start_tag(tag_items_data_item_deprecation);
-        depr.encode(rbml_w).unwrap();
-        rbml_w.end_tag();
-    });
-}
 
-fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
-    parent_opt.map(|parent| {
-        rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
-    });
-}
-
-fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                          rbml_w: &mut Encoder,
-                          xrefs: FnvHashMap<XRef<'tcx>, u32>)
-{
-    let mut xref_positions = vec![0; xrefs.len()];
-
-    // Encode XRefs sorted by their ID
-    let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect();
-    sorted_xrefs.sort_by_key(|&(_, id)| id);
-
-    rbml_w.start_tag(tag_xref_data);
-    for (xref, id) in sorted_xrefs.into_iter() {
-        xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
-        match xref {
-            XRef::Predicate(p) => {
-                tyencode::enc_predicate(rbml_w.writer, &ecx.ty_str_ctxt(), &p)
-            }
-        }
+    fn encode_stability(&mut self, def_id: DefId) -> Option<Lazy<attr::Stability>> {
+        self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab))
     }
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
 
-    rbml_w.start_tag(tag_xref_index);
-    index::write_dense_index(xref_positions, rbml_w.writer);
-    rbml_w.end_tag();
-}
+    fn encode_deprecation(&mut self, def_id: DefId) -> Option<Lazy<attr::Deprecation>> {
+        self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
+    }
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
     fn encode_info_for_item(&mut self,
-                            (def_id, item): (DefId, &hir::Item)) {
-        let ecx = self.ecx();
-        let tcx = ecx.tcx;
+                            (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> {
+        let tcx = self.tcx;
 
         debug!("encoding info for item at {}",
                tcx.sess.codemap().span_to_string(item.span));
 
-        let vis = &item.vis;
-
-        let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
-            (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
-             tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
-        });
+        let kind = match item.node {
+            hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
+            hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
+            hir::ItemConst(..) => EntryKind::Const,
+            hir::ItemFn(ref decl, _, constness, ..) => {
+                let data = FnData {
+                    constness: constness,
+                    arg_names: self.encode_fn_arg_names(&decl)
+                };
 
-        match item.node {
-            hir::ItemStatic(_, m, _) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                if m == hir::MutMutable {
-                    encode_family(self.rbml_w, 'b');
-                } else {
-                    encode_family(self.rbml_w, 'c');
-                }
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                encode_attributes(self.rbml_w, &item.attrs);
-            }
-            hir::ItemConst(..) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'C');
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
-                self.encode_mir(item.id);
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-            }
-            hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, FN_FAMILY);
-                let tps_len = generics.ty_params.len();
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
-                if constness == hir::Constness::Const {
-                    encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
-                }
-                if needs_inline || constness == hir::Constness::Const {
-                    self.encode_mir(item.id);
-                }
-                encode_constness(self.rbml_w, constness);
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                self.encode_method_argument_names(&decl);
+                EntryKind::Fn(self.lazy(&data))
             }
             hir::ItemMod(ref m) => {
-                self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis)));
-            }
-            hir::ItemForeignMod(ref fm) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'n');
-                encode_name(self.rbml_w, item.name);
-
-                // Encode all the items in self module.
-                for foreign_item in &fm.items {
-                    self.rbml_w.wr_tagged_u64(
-                        tag_mod_child,
-                        def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
-                }
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-            }
-            hir::ItemTy(..) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'y');
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-            }
-            hir::ItemEnum(ref enum_definition, _) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 't');
-                encode_item_variances(self.rbml_w, ecx, item.id);
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                self.encode_repr_attrs(&item.attrs);
-                for v in &enum_definition.variants {
-                    encode_variant_id(self.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
-                }
-
-                // Encode inherent implementations for self enumeration.
-                encode_inherent_implementations(ecx, self.rbml_w, def_id);
-
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
+                return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis)));
             }
+            hir::ItemForeignMod(_) => EntryKind::ForeignMod,
+            hir::ItemTy(..) => EntryKind::Type,
+            hir::ItemEnum(..) => EntryKind::Enum,
             hir::ItemStruct(ref struct_def, _) => {
-                /* Index the class*/
-                let def = ecx.tcx.lookup_adt_def(def_id);
-                let variant = def.struct_variant();
-
-                /* Now, make an item for the class itself */
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, match *struct_def {
-                    hir::VariantData::Struct(..) => 'S',
-                    hir::VariantData::Tuple(..) => 's',
-                    hir::VariantData::Unit(..) => 'u',
-                });
-                self.encode_bounds_and_type_for_item(item.id);
-
-                encode_item_variances(self.rbml_w, ecx, item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                self.encode_visibility(vis);
-                self.encode_repr_attrs(&item.attrs);
+                let variant = tcx.lookup_adt_def(def_id).struct_variant();
 
                 /* Encode def_ids for each field and method
                 for methods, write all the stuff get_trait_method
                 needs to know*/
-                self.encode_struct_fields(variant);
-
-                // Encode inherent implementations for self structure.
-                encode_inherent_implementations(ecx, self.rbml_w, def_id);
-
-                if !struct_def.is_struct() {
-                    let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
-                    self.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
-                                              def_to_u64(ctor_did));
-                }
+                let struct_ctor = if !struct_def.is_struct() {
+                    Some(tcx.map.local_def_id(struct_def.id()).index)
+                } else {
+                    None
+                };
+                EntryKind::Struct(self.lazy(&VariantData {
+                    kind: variant.kind,
+                    disr: variant.disr_val.to_u64_unchecked(),
+                    struct_ctor: struct_ctor
+                }))
             }
             hir::ItemUnion(..) => {
-                let def = ecx.tcx.lookup_adt_def(def_id);
-                let variant = def.struct_variant();
-
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'U');
-                self.encode_bounds_and_type_for_item(item.id);
-
-                encode_item_variances(self.rbml_w, ecx, item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                self.encode_visibility(vis);
-                self.encode_repr_attrs(&item.attrs);
-
-                /* Encode def_ids for each field and method
-                for methods, write all the stuff get_trait_method
-                needs to know*/
-                self.encode_struct_fields(variant);
-
-                encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
-                self.encode_mir(item.id);
+                let variant = tcx.lookup_adt_def(def_id).struct_variant();
 
-                // Encode inherent implementations for self union.
-                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+                EntryKind::Union(self.lazy(&VariantData {
+                    kind: variant.kind,
+                    disr: variant.disr_val.to_u64_unchecked(),
+                    struct_ctor: None
+                }))
             }
-            hir::ItemDefaultImpl(unsafety, _) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'd');
-                encode_name(self.rbml_w, item.name);
-                encode_unsafety(self.rbml_w, unsafety);
-
-                let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
-                encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
-            }
-            hir::ItemImpl(unsafety, polarity, ..) => {
-                // We need to encode information about the default methods we
-                // have inherited, so we drive self based on the impl structure.
-                let impl_items = tcx.impl_items.borrow();
-                let items = &impl_items[&def_id];
-
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'i');
-                self.encode_bounds_and_type_for_item(item.id);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                encode_unsafety(self.rbml_w, unsafety);
-                encode_polarity(self.rbml_w, polarity);
-
-                match
-                    tcx.custom_coerce_unsized_kinds
-                       .borrow()
-                       .get(&ecx.tcx.map.local_def_id(item.id))
-                {
-                    Some(&kind) => {
-                        self.rbml_w.start_tag(tag_impl_coerce_unsized_kind);
-                        kind.encode(self.rbml_w);
-                        self.rbml_w.end_tag();
-                    }
-                    None => {}
-                }
+            hir::ItemDefaultImpl(..) => {
+                let data = ImplData {
+                    polarity: hir::ImplPolarity::Positive,
+                    parent_impl: None,
+                    coerce_unsized_kind: None,
+                    trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref))
+                };
 
-                for &item_def_id in items {
-                    self.rbml_w.start_tag(tag_item_impl_item);
-                    match item_def_id {
-                        ty::ConstTraitItemId(item_def_id) => {
-                            encode_def_id(self.rbml_w, item_def_id);
-                            encode_item_sort(self.rbml_w, 'C');
-                        }
-                        ty::MethodTraitItemId(item_def_id) => {
-                            encode_def_id(self.rbml_w, item_def_id);
-                            encode_item_sort(self.rbml_w, 'r');
-                        }
-                        ty::TypeTraitItemId(item_def_id) => {
-                            encode_def_id(self.rbml_w, item_def_id);
-                            encode_item_sort(self.rbml_w, 't');
+                EntryKind::DefaultImpl(self.lazy(&data))
+            }
+            hir::ItemImpl(_, polarity, ..) => {
+                let trait_ref = tcx.impl_trait_ref(def_id);
+                let parent = if let Some(trait_ref) = trait_ref {
+                    let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+                    trait_def.ancestors(def_id).skip(1).next().and_then(|node| {
+                        match node {
+                            specialization_graph::Node::Impl(parent) => Some(parent),
+                            _ => None,
                         }
-                    }
-                    self.rbml_w.end_tag();
-                }
+                    })
+                } else {
+                    None
+                };
 
-                let did = ecx.tcx.map.local_def_id(item.id);
-                if let Some(trait_ref) = tcx.impl_trait_ref(did) {
-                    encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
+                let data = ImplData {
+                    polarity: polarity,
+                    parent_impl: parent,
+                    coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow()
+                                            .get(&def_id).cloned(),
+                    trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref))
+                };
 
-                    let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
-                    let parent = trait_def.ancestors(did)
-                                          .skip(1)
-                                          .next()
-                                          .and_then(|node| match node {
-                                              specialization_graph::Node::Impl(parent) =>
-                                                  Some(parent),
-                                              _ => None,
-                                          });
-                    encode_parent_impl(self.rbml_w, parent);
-                }
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
+                EntryKind::Impl(self.lazy(&data))
             }
             hir::ItemTrait(..) => {
-                encode_def_id_and_key(ecx, self.rbml_w, def_id);
-                encode_family(self.rbml_w, 'I');
-                encode_item_variances(self.rbml_w, ecx, item.id);
                 let trait_def = tcx.lookup_trait_def(def_id);
-                let trait_predicates = tcx.lookup_predicates(def_id);
-                encode_unsafety(self.rbml_w, trait_def.unsafety);
-                encode_paren_sugar(self.rbml_w, trait_def.paren_sugar);
-                encode_defaulted(self.rbml_w, tcx.trait_has_default_impl(def_id));
-                encode_associated_type_names(self.rbml_w, &trait_def.associated_type_names);
-                self.encode_generics(&trait_def.generics, &trait_predicates);
-                self.encode_predicates(&tcx.lookup_super_predicates(def_id),
-                                       tag_item_super_predicates);
-                encode_trait_ref(self.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
-                encode_name(self.rbml_w, item.name);
-                encode_attributes(self.rbml_w, &item.attrs);
-                self.encode_visibility(vis);
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
-                    self.rbml_w.start_tag(tag_item_trait_item);
-                    match method_def_id {
-                        ty::ConstTraitItemId(const_def_id) => {
-                            encode_def_id(self.rbml_w, const_def_id);
-                            encode_item_sort(self.rbml_w, 'C');
-                        }
-                        ty::MethodTraitItemId(method_def_id) => {
-                            encode_def_id(self.rbml_w, method_def_id);
-                            encode_item_sort(self.rbml_w, 'r');
-                        }
-                        ty::TypeTraitItemId(type_def_id) => {
-                            encode_def_id(self.rbml_w, type_def_id);
-                            encode_item_sort(self.rbml_w, 't');
-                        }
-                    }
-                    self.rbml_w.end_tag();
-
-                    self.rbml_w.wr_tagged_u64(tag_mod_child,
-                                              def_to_u64(method_def_id.def_id()));
-                }
+                let data = TraitData {
+                    unsafety: trait_def.unsafety,
+                    paren_sugar: trait_def.paren_sugar,
+                    has_default_impl: tcx.trait_has_default_impl(def_id),
+                    trait_ref: self.lazy(&trait_def.trait_ref),
+                    super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id))
+                };
 
-                // Encode inherent implementations for self trait.
-                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+                EntryKind::Trait(self.lazy(&data))
             }
             hir::ItemExternCrate(_) | hir::ItemUse(_) => {
                 bug!("cannot encode info for item {:?}", item)
             }
+        };
+
+        Entry {
+            kind: kind,
+            visibility: item.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&item.attrs),
+            children: match item.node {
+                hir::ItemForeignMod(ref fm) => {
+                    self.lazy_seq(fm.items.iter().map(|foreign_item| {
+                        tcx.map.local_def_id(foreign_item.id).index
+                    }))
+                }
+                hir::ItemEnum(..) => {
+                    let def = self.tcx.lookup_adt_def(def_id);
+                    self.lazy_seq(def.variants.iter().map(|v| {
+                        assert!(v.did.is_local());
+                        v.did.index
+                    }))
+                }
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) => {
+                    let def = self.tcx.lookup_adt_def(def_id);
+                    self.lazy_seq(def.struct_variant().fields.iter().map(|f| {
+                        assert!(f.did.is_local());
+                        f.did.index
+                    }))
+                }
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| {
+                        assert!(def_id.is_local());
+                        def_id.index
+                    }))
+                }
+                _ => LazySeq::empty()
+            },
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) => {
+                    Some(self.encode_item_type(def_id))
+                }
+                _ => None
+            },
+            inherent_impls: self.encode_inherent_implementations(def_id),
+            variances: match item.node {
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemTrait(..) => {
+                    self.encode_item_variances(def_id)
+                }
+                _ => LazySeq::empty()
+            },
+            generics: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    Some(self.encode_generics(def_id))
+                }
+                _ => None
+            },
+            predicates: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    Some(self.encode_predicates(def_id))
+                }
+                _ => None
+            },
+
+            ast: match item.node {
+                hir::ItemConst(..) |
+                hir::ItemFn(_, _, hir::Constness::Const, ..) => {
+                    Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
+                }
+                _ => None
+            },
+            mir: match item.node {
+                hir::ItemConst(..) => {
+                    self.encode_mir(def_id)
+                }
+                hir::ItemFn(_, _, constness, _, ref generics, _) => {
+                    let tps_len = generics.ty_params.len();
+                    let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
+                    if needs_inline || constness == hir::Constness::Const {
+                        self.encode_mir(def_id)
+                    } else {
+                        None
+                    }
+                }
+                _ => None
+            }
         }
     }
 }
 
-impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     /// In some cases, along with the item itself, we also
     /// encode some sub-items. Usually we want some info from the item
     /// so it's easier to do that here then to wait until we would encounter
     /// normally in the visitor walk.
     fn encode_addl_info_for_item(&mut self,
                                  item: &hir::Item) {
-        let def_id = self.ecx().tcx.map.local_def_id(item.id);
+        let def_id = self.tcx.map.local_def_id(item.id);
         match item.node {
             hir::ItemStatic(..) |
             hir::ItemConst(..) |
@@ -1173,162 +873,120 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                 // no sub-item recording needed in these cases
             }
             hir::ItemEnum(..) => {
-                self.encode_enum_variant_infos(def_id);
+                self.encode_fields(def_id);
+
+                let def = self.tcx.lookup_adt_def(def_id);
+                for (i, variant) in def.variants.iter().enumerate() {
+                    self.record(variant.did,
+                                EncodeContext::encode_enum_variant_info,
+                                (def_id, Untracked(i)));
+                }
             }
             hir::ItemStruct(ref struct_def, _) => {
-                self.encode_addl_struct_info(def_id, struct_def.id(), item);
+                self.encode_fields(def_id);
+
+                // If this is a tuple-like struct, encode the type of the constructor.
+                match self.tcx.lookup_adt_def(def_id).struct_variant().kind {
+                    ty::VariantKind::Struct => {
+                        // no value for structs like struct Foo { ... }
+                    }
+                    ty::VariantKind::Tuple | ty::VariantKind::Unit => {
+                        // there is a value for structs like `struct
+                        // Foo()` and `struct Foo`
+                        let ctor_def_id = self.tcx.map.local_def_id(struct_def.id());
+                        self.record(ctor_def_id,
+                                    EncodeContext::encode_struct_ctor,
+                                    (def_id, ctor_def_id));
+                    }
+                }
             }
             hir::ItemUnion(..) => {
-                self.encode_addl_union_info(def_id);
-            }
-            hir::ItemImpl(.., ref ast_items) => {
-                self.encode_addl_impl_info(def_id, item.id, ast_items);
+                self.encode_fields(def_id);
             }
-            hir::ItemTrait(.., ref trait_items) => {
-                self.encode_addl_trait_info(def_id, trait_items);
-            }
-        }
-    }
-
-    fn encode_addl_struct_info(&mut self,
-                               def_id: DefId,
-                               struct_node_id: ast::NodeId,
-                               item: &hir::Item) {
-        let ecx = self.ecx();
-        let def = ecx.tcx.lookup_adt_def(def_id);
-        let variant = def.struct_variant();
-
-        self.encode_fields(def_id);
-
-        // If this is a tuple-like struct, encode the type of the constructor.
-        match variant.kind {
-            ty::VariantKind::Struct => {
-                // no value for structs like struct Foo { ... }
+            hir::ItemImpl(..) => {
+                for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                    self.record(trait_item_def_id,
+                                EncodeContext::encode_info_for_impl_item,
+                                trait_item_def_id);
+                }
             }
-            ty::VariantKind::Tuple | ty::VariantKind::Unit => {
-                // there is a value for structs like `struct
-                // Foo()` and `struct Foo`
-                let ctor_def_id = ecx.tcx.map.local_def_id(struct_node_id);
-                self.record(ctor_def_id,
-                            ItemContentBuilder::encode_struct_ctor,
-                            (def_id, item.id, struct_node_id));
+            hir::ItemTrait(..) => {
+                for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                    self.record(item_def_id,
+                                EncodeContext::encode_info_for_trait_item,
+                                item_def_id);
+                }
             }
         }
     }
-
-    fn encode_addl_union_info(&mut self, def_id: DefId) {
-        self.encode_fields(def_id);
-    }
-
-    fn encode_addl_impl_info(&mut self,
-                             def_id: DefId,
-                             impl_id: ast::NodeId,
-                             ast_items: &[hir::ImplItem]) {
-        let ecx = self.ecx();
-        let impl_items = ecx.tcx.impl_items.borrow();
-        let items = &impl_items[&def_id];
-
-        // Iterate down the trait items, emitting them. We rely on the
-        // assumption that all of the actually implemented trait items
-        // appear first in the impl structure, in the same order they do
-        // in the ast. This is a little sketchy.
-        let num_implemented_methods = ast_items.len();
-        for (i, &trait_item_def_id) in items.iter().enumerate() {
-            let ast_item = if i < num_implemented_methods {
-                Some(&ast_items[i])
-            } else {
-                None
-            };
-
-            let trait_item_def_id = trait_item_def_id.def_id();
-            self.record(trait_item_def_id,
-                        ItemContentBuilder::encode_info_for_impl_item,
-                        (impl_id, trait_item_def_id, ast_item));
-        }
-    }
-
-    fn encode_addl_trait_info(&mut self,
-                              def_id: DefId,
-                              trait_items: &[hir::TraitItem]) {
-        // Now output the trait item info for each trait item.
-        let tcx = self.ecx().tcx;
-        let r = tcx.trait_item_def_ids(def_id);
-        for (item_def_id, trait_item) in r.iter().zip(trait_items) {
-            let item_def_id = item_def_id.def_id();
-            assert!(item_def_id.is_local());
-            self.record(item_def_id,
-                        ItemContentBuilder::encode_info_for_trait_item,
-                        (def_id, item_def_id, trait_item));
-        }
-    }
 }
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_info_for_foreign_item(&mut self,
-                                    (def_id, nitem): (DefId, &hir::ForeignItem)) {
-        let ecx = self.ecx();
+                                    (def_id, nitem): (DefId, &hir::ForeignItem))
+                                    -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-        debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
+        debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
 
-        encode_def_id_and_key(ecx, self.rbml_w, def_id);
-        let parent_id = ecx.tcx.map.get_parent(nitem.id);
-        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
-        self.encode_visibility(&nitem.vis);
-        match nitem.node {
+        let kind = match nitem.node {
             hir::ForeignItemFn(ref fndecl, _) => {
-                encode_family(self.rbml_w, FN_FAMILY);
-                self.encode_bounds_and_type_for_item(nitem.id);
-                encode_name(self.rbml_w, nitem.name);
-                encode_attributes(self.rbml_w, &nitem.attrs);
-                let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-                let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                self.encode_method_argument_names(&fndecl);
-            }
-            hir::ForeignItemStatic(_, mutbl) => {
-                if mutbl {
-                    encode_family(self.rbml_w, 'b');
-                } else {
-                    encode_family(self.rbml_w, 'c');
-                }
-                self.encode_bounds_and_type_for_item(nitem.id);
-                encode_attributes(self.rbml_w, &nitem.attrs);
-                let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-                let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-                encode_stability(self.rbml_w, stab);
-                encode_deprecation(self.rbml_w, depr);
-                encode_name(self.rbml_w, nitem.name);
+                let data = FnData {
+                    constness: hir::Constness::NotConst,
+                    arg_names: self.encode_fn_arg_names(&fndecl)
+                };
+                EntryKind::ForeignFn(self.lazy(&data))
             }
+            hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic,
+            hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic
+        };
+
+        Entry {
+            kind: kind,
+            visibility: nitem.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&nitem.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
         }
     }
 }
 
-struct EncodeVisitor<'a, 'ecx: 'a, 'tcx: 'ecx, 'encoder: 'ecx> {
-    index: &'a mut IndexBuilder<'ecx, 'tcx, 'encoder>,
+struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> {
+    index: IndexBuilder<'a, 'b, 'tcx>,
 }
 
-impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, 'encoder> {
+impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         intravisit::walk_expr(self, ex);
         self.index.encode_info_for_expr(ex);
     }
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         intravisit::walk_item(self, item);
-        let def_id = self.index.ecx().tcx.map.local_def_id(item.id);
+        let def_id = self.index.tcx.map.local_def_id(item.id);
         match item.node {
             hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these
             _ => self.index.record(def_id,
-                                   ItemContentBuilder::encode_info_for_item,
+                                   EncodeContext::encode_info_for_item,
                                    (def_id, item)),
         }
         self.index.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
         intravisit::walk_foreign_item(self, ni);
-        let def_id = self.index.ecx().tcx.map.local_def_id(ni.id);
+        let def_id = self.index.tcx.map.local_def_id(ni.id);
         self.index.record(def_id,
-                          ItemContentBuilder::encode_info_for_foreign_item,
+                          EncodeContext::encode_info_for_foreign_item,
                           (def_id, ni));
     }
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
@@ -1337,297 +995,187 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, '
     }
 }
 
-impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
-        let ecx = self.ecx();
         if let hir::TyImplTrait(_) = ty.node {
-            let def_id = ecx.tcx.map.local_def_id(ty.id);
+            let def_id = self.tcx.map.local_def_id(ty.id);
             self.record(def_id,
-                        ItemContentBuilder::encode_info_for_anon_ty,
-                        (def_id, ty.id));
+                        EncodeContext::encode_info_for_anon_ty,
+                        def_id);
         }
     }
 
     fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
-        let ecx = self.ecx();
-
         match expr.node {
             hir::ExprClosure(..) => {
-                let def_id = ecx.tcx.map.local_def_id(expr.id);
+                let def_id = self.tcx.map.local_def_id(expr.id);
                 self.record(def_id,
-                            ItemContentBuilder::encode_info_for_closure,
-                            (def_id, expr.id));
+                            EncodeContext::encode_info_for_closure,
+                            def_id);
             }
             _ => { }
         }
     }
 }
 
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    fn encode_info_for_anon_ty(&mut self, (def_id, ty_id): (DefId, NodeId)) {
-        let ecx = self.ecx;
-        encode_def_id_and_key(ecx, self.rbml_w, def_id);
-        encode_family(self.rbml_w, 'y');
-        self.encode_bounds_and_type_for_item(ty_id);
-    }
-
-    fn encode_info_for_closure(&mut self, (def_id, expr_id): (DefId, NodeId)) {
-        let ecx = self.ecx;
-        encode_def_id_and_key(ecx, self.rbml_w, def_id);
-        encode_name(self.rbml_w, syntax::parse::token::intern("<closure>"));
-
-        self.rbml_w.start_tag(tag_items_closure_ty);
-        write_closure_type(ecx,
-                           self.rbml_w,
-                           &ecx.tcx.tables.borrow().closure_tys[&def_id]);
-        self.rbml_w.end_tag();
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
+        Entry {
+            kind: EntryKind::Type,
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
 
-        self.rbml_w.start_tag(tag_items_closure_kind);
-        ecx.tcx.closure_kind(def_id).encode(self.rbml_w).unwrap();
-        self.rbml_w.end_tag();
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
 
-        assert!(ecx.mir_map.map.contains_key(&def_id));
-        self.encode_mir(expr_id);
+            ast: None,
+            mir: None
+        }
     }
-}
-
-fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                   rbml_w: &mut Encoder)
-                                   -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
-    let krate = ecx.tcx.map.krate();
 
-    rbml_w.start_tag(tag_items_data);
+    fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-    let fields = {
-        let mut index = IndexBuilder::new(ecx, rbml_w);
-        index.record(DefId::local(CRATE_DEF_INDEX),
-                     ItemContentBuilder::encode_info_for_mod,
-                     FromId(CRATE_NODE_ID, (&krate.module,
-                                            &[],
-                                            syntax::parse::token::intern(&ecx.link_meta.crate_name),
-                                            &hir::Public)));
-        krate.visit_all_items(&mut EncodeVisitor {
-            index: &mut index,
-        });
-        index.into_fields()
-    };
+        let data = ClosureData {
+            kind: tcx.closure_kind(def_id),
+            ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id])
+        };
 
-    rbml_w.end_tag();
+        Entry {
+            kind: EntryKind::Closure(self.lazy(&data)),
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
 
-    fields
-}
+            ty: None,
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
 
-fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
-    rbml_w.start_tag(tag_index);
-    index.write_index(rbml_w.writer);
-    rbml_w.end_tag();
-}
-
-fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
-    rbml_w.start_tag(tag_attributes);
-    rbml_w.emit_opaque(|opaque_encoder| {
-        attrs.encode(opaque_encoder)
-    }).unwrap();
-    rbml_w.end_tag();
-}
-
-fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) {
-    let byte: u8 = match unsafety {
-        hir::Unsafety::Normal => 0,
-        hir::Unsafety::Unsafe => 1,
-    };
-    rbml_w.wr_tagged_u8(tag_unsafety, byte);
-}
-
-fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) {
-    let byte: u8 = if paren_sugar {1} else {0};
-    rbml_w.wr_tagged_u8(tag_paren_sugar, byte);
-}
-
-fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) {
-    let byte: u8 = if is_defaulted {1} else {0};
-    rbml_w.wr_tagged_u8(tag_defaulted_trait, byte);
-}
-
-fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) {
-    rbml_w.start_tag(tag_associated_type_names);
-    for &name in names {
-        rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str());
-    }
-    rbml_w.end_tag();
-}
-
-fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) {
-    let byte: u8 = match polarity {
-        hir::ImplPolarity::Positive => 0,
-        hir::ImplPolarity::Negative => 1,
-    };
-    rbml_w.wr_tagged_u8(tag_polarity, byte);
-}
-
-fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
-    fn get_ordered_deps(cstore: &cstore::CStore)
-                        -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
-        // Pull the cnums and name,vers,hash out of cstore
-        let mut deps = Vec::new();
-        cstore.iter_crate_data(|cnum, val| {
-            deps.push((cnum, val.clone()));
-        });
-
-        // Sort by cnum
-        deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
-
-        // Sanity-check the crate numbers
-        let mut expected_cnum = 1;
-        for &(n, _) in &deps {
-            assert_eq!(n, expected_cnum);
-            expected_cnum += 1;
+            ast: None,
+            mir: self.encode_mir(def_id)
         }
-
-        deps
-    }
-
-    // We're just going to write a list of crate 'name-hash-version's, with
-    // the assumption that they are numbered 1 to n.
-    // FIXME (#2166): This is not nearly enough to support correct versioning
-    // but is enough to get transitive crate dependencies working.
-    rbml_w.start_tag(tag_crate_deps);
-    for (_cnum, dep) in get_ordered_deps(cstore) {
-        encode_crate_dep(rbml_w, &dep);
     }
-    rbml_w.end_tag();
-}
-
-fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_lang_items);
 
-    for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() {
-        if let Some(def_id) = opt_def_id {
-            if def_id.is_local() {
-                rbml_w.start_tag(tag_lang_items_item);
-                rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
-                rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
-                rbml_w.end_tag();
+    fn encode_info_for_items(&mut self) -> Index {
+        let krate = self.tcx.map.krate();
+        let mut index = IndexBuilder::new(self);
+        index.record(DefId::local(CRATE_DEF_INDEX),
+                     EncodeContext::encode_info_for_mod,
+                     FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
+        let mut visitor = EncodeVisitor {
+            index: index,
+        };
+        krate.visit_all_items(&mut visitor);
+        visitor.index.into_items()
+    }
+
+    fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
+        self.lazy_seq_ref(attrs)
+    }
+
+    fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
+        fn get_ordered_deps(cstore: &cstore::CStore)
+                            -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
+            // Pull the cnums and name,vers,hash out of cstore
+            let mut deps = Vec::new();
+            cstore.iter_crate_data(|cnum, val| {
+                deps.push((cnum, val.clone()));
+            });
+
+            // Sort by cnum
+            deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
+
+            // Sanity-check the crate numbers
+            let mut expected_cnum = 1;
+            for &(n, _) in &deps {
+                assert_eq!(n, CrateNum::new(expected_cnum));
+                expected_cnum += 1;
             }
+
+            deps
         }
-    }
 
-    for i in &ecx.tcx.lang_items.missing {
-        rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32);
+        // We're just going to write a list of crate 'name-hash-version's, with
+        // the assumption that they are numbered 1 to n.
+        // FIXME (#2166): This is not nearly enough to support correct versioning
+        // but is enough to get transitive crate dependencies working.
+        let deps = get_ordered_deps(self.cstore);
+        self.lazy_seq(deps.iter().map(|&(_, ref dep)| {
+            CrateDep {
+                name: syntax::parse::token::intern(dep.name()),
+                hash: dep.hash(),
+                explicitly_linked: dep.explicitly_linked.get()
+            }
+        }))
     }
 
-    rbml_w.end_tag();   // tag_lang_items
-}
-
-fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_native_libraries);
-
-    for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() {
-        match kind {
-            cstore::NativeStatic => {} // these libraries are not propagated
-            cstore::NativeFramework | cstore::NativeUnknown => {
-                rbml_w.start_tag(tag_native_libraries_lib);
-                rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32);
-                rbml_w.wr_tagged_str(tag_native_libraries_name, lib);
-                rbml_w.end_tag();
+    fn encode_lang_items(&mut self)
+                         -> (LazySeq<(DefIndex, usize)>, LazySeq<lang_items::LangItem>) {
+        let tcx = self.tcx;
+        let lang_items = tcx.lang_items.items().iter();
+        (self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
+            if let Some(def_id) = opt_def_id {
+                if def_id.is_local() {
+                    return Some((def_id.index, i));
+                }
             }
-        }
+            None
+        })), self.lazy_seq_ref(&tcx.lang_items.missing))
     }
 
-    rbml_w.end_tag();
-}
-
-fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    match ecx.tcx.sess.plugin_registrar_fn.get() {
-        Some(id) => {
-            let def_id = ecx.tcx.map.local_def_id(id);
-            rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
-        }
-        None => {}
+    fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> {
+        let used_libraries = self.tcx.sess.cstore.used_libraries();
+        self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| {
+            match kind {
+                cstore::NativeStatic => None, // these libraries are not propagated
+                cstore::NativeFramework | cstore::NativeUnknown => {
+                    Some((kind, lib))
+                }
+            }
+        }))
     }
-}
-
-fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_codemap);
-    let codemap = ecx.tcx.sess.codemap();
 
-    for filemap in &codemap.files.borrow()[..] {
-
-        if filemap.lines.borrow().is_empty() || filemap.is_imported() {
+    fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
+        let codemap = self.tcx.sess.codemap();
+        let all_filemaps = codemap.files.borrow();
+        self.lazy_seq_ref(all_filemaps.iter().filter(|filemap| {
             // No need to export empty filemaps, as they can't contain spans
             // that need translation.
             // Also no need to re-export imported filemaps, as any downstream
             // crate will import them from their original source.
-            continue;
-        }
-
-        rbml_w.start_tag(tag_codemap_filemap);
-        rbml_w.emit_opaque(|opaque_encoder| {
-            filemap.encode(opaque_encoder)
-        }).unwrap();
-        rbml_w.end_tag();
-    }
-
-    rbml_w.end_tag();
-}
-
-/// Serialize the text of the exported macros
-fn encode_macro_defs(rbml_w: &mut Encoder,
-                     krate: &hir::Crate,
-                     tcx: TyCtxt) {
-    rbml_w.start_tag(tag_macro_defs);
-    for def in &krate.exported_macros {
-        rbml_w.start_tag(tag_macro_def);
-
-        encode_name(rbml_w, def.name);
-        encode_attributes(rbml_w, &def.attrs);
-        let &BytePos(lo) = &def.span.lo;
-        let &BytePos(hi) = &def.span.hi;
-        rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo);
-        rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi);
-
-        rbml_w.wr_tagged_str(tag_macro_def_body,
-                             &::syntax::print::pprust::tts_to_string(&def.body));
-
-        rbml_w.end_tag();
-    }
-    rbml_w.end_tag();
-
-    if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) {
-        let id = tcx.sess.derive_registrar_fn.get().unwrap();
-        let did = tcx.map.local_def_id(id);
-        rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32());
-    }
-}
-
-fn encode_struct_field_attrs(ecx: &EncodeContext,
-                             rbml_w: &mut Encoder,
-                             krate: &hir::Crate) {
-    struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
-        ecx: &'a EncodeContext<'b, 'tcx>,
-        rbml_w: &'a mut Encoder<'c>,
-    }
-
-    impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> {
-        fn visit_struct_field(&mut self, field: &hir::StructField) {
-            self.rbml_w.start_tag(tag_struct_field);
-            let def_id = self.ecx.tcx.map.local_def_id(field.id);
-            encode_def_id(self.rbml_w, def_id);
-            encode_attributes(self.rbml_w, &field.attrs);
-            self.rbml_w.end_tag();
-        }
+            !filemap.lines.borrow().is_empty() && !filemap.is_imported()
+        }).map(|filemap| &**filemap))
+    }
+
+    /// Serialize the text of the exported macros
+    fn encode_macro_defs(&mut self) -> LazySeq<MacroDef> {
+        let tcx = self.tcx;
+        self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| {
+            MacroDef {
+                name: def.name,
+                attrs: def.attrs.to_vec(),
+                span: def.span,
+                body: ::syntax::print::pprust::tts_to_string(&def.body)
+            }
+        }))
     }
-
-    rbml_w.start_tag(tag_struct_fields);
-    krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w });
-    rbml_w.end_tag();
 }
 
-
-
 struct ImplVisitor<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    impls: FnvHashMap<DefId, Vec<DefId>>
+    impls: FnvHashMap<DefId, Vec<DefIndex>>
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
@@ -1637,308 +1185,221 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) {
                 self.impls.entry(trait_ref.def_id)
                     .or_insert(vec![])
-                    .push(impl_id);
+                    .push(impl_id.index);
             }
         }
     }
 }
 
-/// Encodes an index, mapping each trait to its (local) implementations.
-fn encode_impls<'a>(ecx: &'a EncodeContext,
-                    krate: &hir::Crate,
-                    rbml_w: &'a mut Encoder) {
-    let mut visitor = ImplVisitor {
-        tcx: ecx.tcx,
-        impls: FnvHashMap()
-    };
-    krate.visit_all_items(&mut visitor);
-
-    rbml_w.start_tag(tag_impls);
-    for (trait_, trait_impls) in visitor.impls {
-        rbml_w.start_tag(tag_impls_trait);
-        encode_def_id(rbml_w, trait_);
-        for impl_ in trait_impls {
-            rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_));
-        }
-        rbml_w.end_tag();
-    }
-    rbml_w.end_tag();
-}
-
-// Encodes all reachable symbols in this crate into the metadata.
-//
-// This pass is seeded off the reachability list calculated in the
-// middle::reachable module but filters out items that either don't have a
-// symbol associated with them (they weren't translated) or if they're an FFI
-// definition (as that's not defined in this crate).
-fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_reachable_ids);
-    for &id in ecx.reachable {
-        let def_id = ecx.tcx.map.local_def_id(id);
-        rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
-    }
-    rbml_w.end_tag();
-}
-
-fn encode_crate_dep(rbml_w: &mut Encoder,
-                    dep: &cstore::CrateMetadata) {
-    rbml_w.start_tag(tag_crate_dep);
-    rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
-    let hash = decoder::get_crate_hash(dep.data());
-    rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
-    rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
-                        dep.explicitly_linked.get() as u8);
-    rbml_w.end_tag();
-}
-
-fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
-    rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
-}
-
-fn encode_rustc_version(rbml_w: &mut Encoder) {
-    rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version());
-}
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    /// Encodes an index, mapping each trait to its (local) implementations.
+    fn encode_impls(&mut self) -> LazySeq<TraitImpls> {
+        let mut visitor = ImplVisitor {
+            tcx: self.tcx,
+            impls: FnvHashMap()
+        };
+        self.tcx.map.krate().visit_all_items(&mut visitor);
 
-fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
-    rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
-}
-
-fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) {
-    rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator);
-}
-
-fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
-    rbml_w.wr_tagged_str(tag_crate_triple, triple);
-}
+        let all_impls: Vec<_> = visitor.impls.into_iter().map(|(trait_def_id, impls)| {
+            TraitImpls {
+                trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
+                impls: self.lazy_seq(impls)
+            }
+        }).collect();
 
-fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
-    let tag = tag_dylib_dependency_formats;
-    match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
-        Some(arr) => {
-            let s = arr.iter().enumerate().filter_map(|(i, slot)| {
-                let kind = match *slot {
-                    Linkage::NotLinked |
-                    Linkage::IncludedFromDylib => return None,
-                    Linkage::Dynamic => "d",
-                    Linkage::Static => "s",
-                };
-                Some(format!("{}:{}", i + 1, kind))
-            }).collect::<Vec<String>>();
-            rbml_w.wr_tagged_str(tag, &s.join(","));
-        }
-        None => {
-            rbml_w.wr_tagged_str(tag, "");
-        }
+        self.lazy_seq(all_impls)
     }
-}
 
-fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
-    match ecx.tcx.sess.opts.cg.panic {
-        PanicStrategy::Unwind => {
-            rbml_w.wr_tagged_u8(tag_panic_strategy, b'U');
-        }
-        PanicStrategy::Abort => {
-            rbml_w.wr_tagged_u8(tag_panic_strategy, b'A');
+    // Encodes all reachable symbols in this crate into the metadata.
+    //
+    // This pass is seeded off the reachability list calculated in the
+    // middle::reachable module but filters out items that either don't have a
+    // symbol associated with them (they weren't translated) or if they're an FFI
+    // definition (as that's not defined in this crate).
+    fn encode_reachable(&mut self) -> LazySeq<DefIndex> {
+        let reachable = self.reachable;
+        let tcx = self.tcx;
+        self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index))
+    }
+
+    fn encode_dylib_dependency_formats(&mut self) -> LazySeq<Option<LinkagePreference>> {
+        match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
+            Some(arr) => {
+                self.lazy_seq(arr.iter().map(|slot| {
+                    match *slot {
+                        Linkage::NotLinked |
+                        Linkage::IncludedFromDylib => None,
+
+                        Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
+                        Linkage::Static => Some(LinkagePreference::RequireStatic),
+                    }
+                }))
+            }
+            None => LazySeq::empty()
         }
     }
-}
-
-pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> {
-    let mut wr = Cursor::new(Vec::new());
 
-    {
-        let mut rbml_w = Encoder::new(&mut wr);
-        encode_metadata_inner(&mut rbml_w, &ecx, krate)
-    }
+    fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
+        let mut i = self.position();
+        let crate_deps = self.encode_crate_deps();
+        let dylib_dependency_formats = self.encode_dylib_dependency_formats();
+        let dep_bytes = self.position() - i;
+
+        // Encode the language items.
+        i = self.position();
+        let (lang_items, lang_items_missing) = self.encode_lang_items();
+        let lang_item_bytes = self.position() - i;
+
+        // Encode the native libraries used
+        i = self.position();
+        let native_libraries = self.encode_native_libraries();
+        let native_lib_bytes = self.position() - i;
+
+        // Encode codemap
+        i = self.position();
+        let codemap = self.encode_codemap();
+        let codemap_bytes = self.position() - i;
+
+        // Encode macro definitions
+        i = self.position();
+        let macro_defs = self.encode_macro_defs();
+        let macro_defs_bytes = self.position() - i;
+
+        // Encode the def IDs of impls, for coherence checking.
+        i = self.position();
+        let impls = self.encode_impls();
+        let impl_bytes = self.position() - i;
+
+        // Encode reachability info.
+        i = self.position();
+        let reachable_ids = self.encode_reachable();
+        let reachable_bytes = self.position() - i;
+
+        // Encode and index the items.
+        i = self.position();
+        let items = self.encode_info_for_items();
+        let item_bytes = self.position() - i;
+
+        i = self.position();
+        let index = items.write_index(&mut self.opaque.cursor);
+        let index_bytes = self.position() - i;
+
+        let tcx = self.tcx;
+        let link_meta = self.link_meta;
+        let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro);
+        let root = self.lazy(&CrateRoot {
+            rustc_version: RUSTC_VERSION.to_string(),
+            name: link_meta.crate_name.clone(),
+            triple: tcx.sess.opts.target_triple.clone(),
+            hash: link_meta.crate_hash,
+            disambiguator: tcx.sess.local_crate_disambiguator().to_string(),
+            panic_strategy: tcx.sess.opts.cg.panic.clone(),
+            plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| {
+                tcx.map.local_def_id(id).index
+            }),
+            macro_derive_registrar: if is_rustc_macro {
+                let id = tcx.sess.derive_registrar_fn.get().unwrap();
+                Some(tcx.map.local_def_id(id).index)
+            } else {
+                None
+            },
+
+            crate_deps: crate_deps,
+            dylib_dependency_formats: dylib_dependency_formats,
+            lang_items: lang_items,
+            lang_items_missing: lang_items_missing,
+            native_libraries: native_libraries,
+            codemap: codemap,
+            macro_defs: macro_defs,
+            impls: impls,
+            reachable_ids: reachable_ids,
+            index: index,
+        });
 
-    // RBML compacts the encoded bytes whenever appropriate,
-    // so there are some garbages left after the end of the data.
-    let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize;
-    let mut v = wr.into_inner();
-    v.truncate(metalen);
-    assert_eq!(v.len(), metalen);
-
-    // And here we run into yet another obscure archive bug: in which metadata
-    // loaded from archives may have trailing garbage bytes. Awhile back one of
-    // our tests was failing sporadically on the OSX 64-bit builders (both nopt
-    // and opt) by having rbml generate an out-of-bounds panic when looking at
-    // metadata.
-    //
-    // Upon investigation it turned out that the metadata file inside of an rlib
-    // (and ar archive) was being corrupted. Some compilations would generate a
-    // metadata file which would end in a few extra bytes, while other
-    // compilations would not have these extra bytes appended to the end. These
-    // extra bytes were interpreted by rbml as an extra tag, so they ended up
-    // being interpreted causing the out-of-bounds.
-    //
-    // The root cause of why these extra bytes were appearing was never
-    // discovered, and in the meantime the solution we're employing is to insert
-    // the length of the metadata to the start of the metadata. Later on this
-    // will allow us to slice the metadata to the precise length that we just
-    // generated regardless of trailing bytes that end up in it.
-    //
-    // We also need to store the metadata encoding version here, because
-    // rlibs don't have it. To get older versions of rustc to ignore
-    // this metadata, there are 4 zero bytes at the start, which are
-    // treated as a length of 0 by old compilers.
-
-    let len = v.len();
-    let mut result = vec![];
-    result.push(0);
-    result.push(0);
-    result.push(0);
-    result.push(0);
-    result.extend(metadata_encoding_version.iter().cloned());
-    result.push((len >> 24) as u8);
-    result.push((len >> 16) as u8);
-    result.push((len >>  8) as u8);
-    result.push((len >>  0) as u8);
-    result.extend(v);
-    result
-}
+        let total_bytes = self.position();
 
-fn encode_metadata_inner(rbml_w: &mut Encoder,
-                         ecx: &EncodeContext,
-                         krate: &hir::Crate) {
-    struct Stats {
-        attr_bytes: u64,
-        dep_bytes: u64,
-        lang_item_bytes: u64,
-        native_lib_bytes: u64,
-        plugin_registrar_fn_bytes: u64,
-        codemap_bytes: u64,
-        macro_defs_bytes: u64,
-        impl_bytes: u64,
-        reachable_bytes: u64,
-        item_bytes: u64,
-        index_bytes: u64,
-        xref_bytes: u64,
-        zero_bytes: u64,
-        total_bytes: u64,
-    }
-    let mut stats = Stats {
-        attr_bytes: 0,
-        dep_bytes: 0,
-        lang_item_bytes: 0,
-        native_lib_bytes: 0,
-        plugin_registrar_fn_bytes: 0,
-        codemap_bytes: 0,
-        macro_defs_bytes: 0,
-        impl_bytes: 0,
-        reachable_bytes: 0,
-        item_bytes: 0,
-        index_bytes: 0,
-        xref_bytes: 0,
-        zero_bytes: 0,
-        total_bytes: 0,
-    };
-
-    encode_rustc_version(rbml_w);
-    encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
-    encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
-    encode_hash(rbml_w, &ecx.link_meta.crate_hash);
-    encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator());
-    encode_dylib_dependency_formats(rbml_w, &ecx);
-    encode_panic_strategy(rbml_w, &ecx);
-
-    let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_attributes(rbml_w, &krate.attrs);
-    stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_crate_deps(rbml_w, ecx.cstore);
-    stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the language items.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_lang_items(&ecx, rbml_w);
-    stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the native libraries used
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_native_libraries(&ecx, rbml_w);
-    stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the plugin registrar function
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_plugin_registrar_fn(&ecx, rbml_w);
-    stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode codemap
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_codemap(&ecx, rbml_w);
-    stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode macro definitions
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_macro_defs(rbml_w, krate, ecx.tcx);
-    stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the def IDs of impls, for coherence checking.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_impls(&ecx, krate, rbml_w);
-    stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode reachability info.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_reachable(&ecx, rbml_w);
-    stats.reachable_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode and index the items.
-    rbml_w.start_tag(tag_items);
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    let (items, xrefs) = encode_info_for_items(&ecx, rbml_w);
-    stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-    rbml_w.end_tag();
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_item_index(rbml_w, items);
-    stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_xrefs(&ecx, rbml_w, xrefs);
-    stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    encode_struct_field_attrs(&ecx, rbml_w, krate);
-
-    stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-
-    if ecx.tcx.sess.meta_stats() {
-        for e in rbml_w.writer.get_ref() {
-            if *e == 0 {
-                stats.zero_bytes += 1;
+        if self.tcx.sess.meta_stats() {
+            let mut zero_bytes = 0;
+            for e in self.opaque.cursor.get_ref() {
+                if *e == 0 {
+                    zero_bytes += 1;
+                }
             }
+
+            println!("metadata stats:");
+            println!("             dep bytes: {}", dep_bytes);
+            println!("       lang item bytes: {}", lang_item_bytes);
+            println!("          native bytes: {}", native_lib_bytes);
+            println!("         codemap bytes: {}", codemap_bytes);
+            println!("       macro def bytes: {}", macro_defs_bytes);
+            println!("            impl bytes: {}", impl_bytes);
+            println!("       reachable bytes: {}", reachable_bytes);
+            println!("            item bytes: {}", item_bytes);
+            println!("           index bytes: {}", index_bytes);
+            println!("            zero bytes: {}", zero_bytes);
+            println!("           total bytes: {}", total_bytes);
         }
 
-        println!("metadata stats:");
-        println!("       attribute bytes: {}", stats.attr_bytes);
-        println!("             dep bytes: {}", stats.dep_bytes);
-        println!("       lang item bytes: {}", stats.lang_item_bytes);
-        println!("          native bytes: {}", stats.native_lib_bytes);
-        println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
-        println!("         codemap bytes: {}", stats.codemap_bytes);
-        println!("       macro def bytes: {}", stats.macro_defs_bytes);
-        println!("            impl bytes: {}", stats.impl_bytes);
-        println!("       reachable bytes: {}", stats.reachable_bytes);
-        println!("            item bytes: {}", stats.item_bytes);
-        println!("           index bytes: {}", stats.index_bytes);
-        println!("            xref bytes: {}", stats.xref_bytes);
-        println!("            zero bytes: {}", stats.zero_bytes);
-        println!("           total bytes: {}", stats.total_bytes);
+        root
     }
 }
 
-// Get the encoded string for a type
-pub fn encoded_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            t: Ty<'tcx>,
-                            def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
-                            -> Vec<u8> {
-    let mut wr = Cursor::new(Vec::new());
-    tyencode::enc_ty(&mut wr, &tyencode::ctxt {
-        diag: tcx.sess.diagnostic(),
-        ds: def_id_to_string,
+// NOTE(eddyb) The following comment was preserved for posterity, even
+// though it's no longer relevant as EBML (which uses nested & tagged
+// "documents") was replaced with a scheme that can't go out of bounds.
+//
+// And here we run into yet another obscure archive bug: in which metadata
+// loaded from archives may have trailing garbage bytes. Awhile back one of
+// our tests was failing sporadically on the OSX 64-bit builders (both nopt
+// and opt) by having ebml generate an out-of-bounds panic when looking at
+// metadata.
+//
+// Upon investigation it turned out that the metadata file inside of an rlib
+// (and ar archive) was being corrupted. Some compilations would generate a
+// metadata file which would end in a few extra bytes, while other
+// compilations would not have these extra bytes appended to the end. These
+// extra bytes were interpreted by ebml as an extra tag, so they ended up
+// being interpreted causing the out-of-bounds.
+//
+// The root cause of why these extra bytes were appearing was never
+// discovered, and in the meantime the solution we're employing is to insert
+// the length of the metadata to the start of the metadata. Later on this
+// will allow us to slice the metadata to the precise length that we just
+// generated regardless of trailing bytes that end up in it.
+
+pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 cstore: &cstore::CStore,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet,
+                                 mir_map: &MirMap<'tcx>) -> Vec<u8> {
+    let mut cursor = Cursor::new(vec![]);
+    cursor.write_all(METADATA_HEADER).unwrap();
+
+    // Will be filed with the root position after encoding everything.
+    cursor.write_all(&[0, 0, 0, 0]).unwrap();
+
+    let root = EncodeContext {
+        opaque: opaque::Encoder::new(&mut cursor),
         tcx: tcx,
-        abbrevs: &RefCell::new(FnvHashMap())
-    }, t);
-    wr.into_inner()
+        reexports: reexports,
+        link_meta: link_meta,
+        cstore: cstore,
+        reachable: reachable,
+        mir_map: mir_map,
+        lazy_state: LazyState::NoNode,
+        type_shorthands: Default::default(),
+        predicate_shorthands: Default::default()
+    }.encode_crate_root();
+    let mut result = cursor.into_inner();
+
+    // Encode the root position.
+    let header = METADATA_HEADER.len();
+    let pos = root.position;
+    result[header + 0] = (pos >> 24) as u8;
+    result[header + 1] = (pos >> 16) as u8;
+    result[header + 2] = (pos >>  8) as u8;
+    result[header + 3] = (pos >>  0) as u8;
+
+    result
 }
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
index b850073462f..ef83251f51e 100644
--- a/src/librustc_metadata/index.rs
+++ b/src/librustc_metadata/index.rs
@@ -8,53 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use schema::*;
+
 use rustc::hir::def_id::{DefId, DefIndex};
-use rbml;
 use std::io::{Cursor, Write};
 use std::slice;
 use std::u32;
 
-/// As part of the metadata, we generate an index that stores, for
-/// each DefIndex, the position of the corresponding RBML document (if
-/// any).  This is just a big `[u32]` slice, where an entry of
-/// `u32::MAX` indicates that there is no RBML document. This little
-/// struct just stores the offsets within the metadata of the start
-/// and end of this slice. These are actually part of an RBML
-/// document, but for looking things up in the metadata, we just
-/// discard the RBML positioning and jump directly to the data.
-pub struct Index {
-    data_start: usize,
-    data_end: usize,
-}
-
-impl Index {
-    /// Given the RBML doc representing the index, save the offests
-    /// for later.
-    pub fn from_rbml(index: rbml::Doc) -> Index {
-        Index { data_start: index.start, data_end: index.end }
-    }
-
-    /// Given the metadata, extract out the offset of a particular
-    /// DefIndex (if any).
-    #[inline(never)]
-    pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
-        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
-        let index = def_index.as_usize();
-
-        debug!("lookup_item: index={:?} words.len={:?}",
-               index, words.len());
-
-        let position = u32::from_be(words[index]);
-        if position == u32::MAX {
-            debug!("lookup_item: position=u32::MAX");
-            None
-        } else {
-            debug!("lookup_item: position={:?}", position);
-            Some(position)
-        }
-    }
-}
-
 /// While we are generating the metadata, we also track the position
 /// of each DefIndex. It is not required that all definitions appear
 /// in the metadata, nor that they are serialized in order, and
@@ -62,84 +22,81 @@ impl Index {
 /// `u32::MAX`. Whenever an index is visited, we fill in the
 /// appropriate spot by calling `record_position`. We should never
 /// visit the same index twice.
-pub struct IndexData {
+pub struct Index {
     positions: Vec<u32>,
 }
 
-impl IndexData {
-    pub fn new(max_index: usize) -> IndexData {
-        IndexData {
+impl Index {
+    pub fn new(max_index: usize) -> Index {
+        Index {
             positions: vec![u32::MAX; max_index]
         }
     }
 
-    pub fn record(&mut self, def_id: DefId, position: u64) {
+    pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry>) {
         assert!(def_id.is_local());
-        self.record_index(def_id.index, position);
+        self.record_index(def_id.index, entry);
     }
 
-    pub fn record_index(&mut self, item: DefIndex, position: u64) {
+    pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry>) {
         let item = item.as_usize();
 
-        assert!(position < (u32::MAX as u64));
-        let position = position as u32;
+        assert!(entry.position < (u32::MAX as usize));
+        let position = entry.position as u32;
 
         assert!(self.positions[item] == u32::MAX,
                 "recorded position for item {:?} twice, first at {:?} and now at {:?}",
                 item, self.positions[item], position);
 
-        self.positions[item] = position;
+        self.positions[item] = position.to_le();
     }
 
-    pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
-        for &position in &self.positions {
-            write_be_u32(buf, position);
-        }
+    pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) -> LazySeq<Index> {
+        let pos = buf.position();
+        buf.write_all(words_to_bytes(&self.positions)).unwrap();
+        LazySeq::with_position_and_length(pos as usize, self.positions.len())
     }
 }
 
-/// A dense index with integer keys. Different API from IndexData (should
-/// these be merged?)
-pub struct DenseIndex {
-    start: usize,
-    end: usize
-}
+impl<'tcx> LazySeq<Index> {
+    /// Given the metadata, extract out the offset of a particular
+    /// DefIndex (if any).
+    #[inline(never)]
+    pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
+        let words = &bytes_to_words(&bytes[self.position..])[..self.len];
+        let index = def_index.as_usize();
 
-impl DenseIndex {
-    pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> {
-        let data = bytes_to_words(&buf[self.start..self.end]);
-        data.get(ix as usize).map(|d| u32::from_be(*d))
-    }
-    pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
-        assert!((end-start)%4 == 0 && start <= end && end <= buf.len());
-        DenseIndex {
-            start: start,
-            end: end
+        debug!("Index::lookup: index={:?} words.len={:?}",
+               index, words.len());
+
+        let position = u32::from_le(words[index]);
+        if position == u32::MAX {
+            debug!("Index::lookup: position=u32::MAX");
+            None
+        } else {
+            debug!("Index::lookup: position={:?}", position);
+            Some(Lazy::with_position(position as usize))
         }
     }
-}
-
-pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) {
-    let elen = entries.len();
-    assert!(elen < u32::MAX as usize);
 
-    for entry in entries {
-        write_be_u32(buf, entry);
+    pub fn iter_enumerated<'a>(&self, bytes: &'a [u8])
+                               -> impl Iterator<Item=(DefIndex, Lazy<Entry<'tcx>>)> + 'a {
+        let words = &bytes_to_words(&bytes[self.position..])[..self.len];
+        words.iter().enumerate().filter_map(|(index, &position)| {
+            if position == u32::MAX {
+                None
+            } else {
+                let position = u32::from_le(position) as usize;
+                Some((DefIndex::new(index), Lazy::with_position(position)))
+            }
+        })
     }
-
-    info!("write_dense_index: {} entries", elen);
 }
 
-fn write_be_u32<W: Write>(w: &mut W, u: u32) {
-    let _ = w.write_all(&[
-        (u >> 24) as u8,
-        (u >> 16) as u8,
-        (u >>  8) as u8,
-        (u >>  0) as u8,
-    ]);
+fn bytes_to_words(b: &[u8]) -> &[u32] {
+    unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len() / 4) }
 }
 
-fn bytes_to_words(b: &[u8]) -> &[u32] {
-    assert!(b.len() % 4 == 0);
-    unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
+fn words_to_bytes(w: &[u32]) -> &[u8] {
+    unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) }
 }
diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs
index 1d3d09d6bc2..aeb6f63252c 100644
--- a/src/librustc_metadata/index_builder.rs
+++ b/src/librustc_metadata/index_builder.rs
@@ -28,10 +28,9 @@
 //! incremental compilation purposes.
 //!
 //! The `IndexBuilder` facilitates both of these. It is created
-//! with an RBML encoder isntance (`rbml_w`) along with an
-//! `EncodingContext` (`ecx`), which it encapsulates. It has one main
-//! method, `record()`. You invoke `record` like so to create a new
-//! `data_item` element in the list:
+//! with an `EncodingContext` (`ecx`), which it encapsulates.
+//! It has one main method, `record()`. You invoke `record`
+//! like so to create a new `data_item` element in the list:
 //!
 //! ```
 //! index.record(some_def_id, callback_fn, data)
@@ -39,17 +38,11 @@
 //!
 //! What record will do is to (a) record the current offset, (b) emit
 //! the `common::data_item` tag, and then call `callback_fn` with the
-//! given data as well as an `ItemContentBuilder`. Once `callback_fn`
+//! given data as well as the `EncodingContext`. Once `callback_fn`
 //! returns, the `common::data_item` tag will be closed.
 //!
-//! The `ItemContentBuilder` is another type that just offers access
-//! to the `ecx` and `rbml_w` that were given in, as well as
-//! maintaining a list of `xref` instances, which are used to extract
-//! common data so it is not re-serialized.
-//!
-//! `ItemContentBuilder` is a distinct type which does not offer the
-//! `record` method, so that we can ensure that `common::data_item` elements
-//! are never nested.
+//! `EncodingContext` does not offer the `record` method, so that we
+//! can ensure that `common::data_item` elements are never nested.
 //!
 //! In addition, while the `callback_fn` is executing, we will push a
 //! task `MetaData(some_def_id)`, which can then observe the
@@ -62,59 +55,51 @@
 //! give a callback fn, rather than taking a closure: it allows us to
 //! easily control precisely what data is given to that fn.
 
-use common::tag_items_data_item;
 use encoder::EncodeContext;
-use index::IndexData;
-use rbml::writer::Encoder;
+use index::Index;
+use schema::*;
+
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::fnv::FnvHashMap;
+use rustc::ty::TyCtxt;
 use syntax::ast;
 
+use std::ops::{Deref, DerefMut};
+
 /// Builder that can encode new items, adding them into the index.
 /// Item encoding cannot be nested.
-pub struct IndexBuilder<'a, 'tcx: 'a, 'encoder: 'a> {
-    items: IndexData,
-    builder: ItemContentBuilder<'a, 'tcx, 'encoder>,
+pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> {
+    items: Index,
+    pub ecx: &'a mut EncodeContext<'b, 'tcx>,
 }
 
-/// Builder that can encode the content of items, but can't start a
-/// new item itself. Most code is attached to here.
-pub struct ItemContentBuilder<'a, 'tcx: 'a, 'encoder: 'a> {
-    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
-    pub ecx: &'a EncodeContext<'a, 'tcx>,
-    pub rbml_w: &'a mut Encoder<'encoder>,
+impl<'a, 'b, 'tcx> Deref for IndexBuilder<'a, 'b, 'tcx> {
+    type Target = EncodeContext<'b, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        self.ecx
+    }
 }
 
-/// "interned" entries referenced by id
-#[derive(PartialEq, Eq, Hash)]
-pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
+impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.ecx
+    }
+}
 
-impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
-    pub fn new(ecx: &'a EncodeContext<'a, 'tcx>,
-               rbml_w: &'a mut Encoder<'encoder>)
-               -> Self {
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self {
         IndexBuilder {
-            items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
-            builder: ItemContentBuilder {
-                ecx: ecx,
-                xrefs: FnvHashMap(),
-                rbml_w: rbml_w,
-            },
+            items: Index::new(ecx.tcx.map.num_local_def_ids()),
+            ecx: ecx,
         }
     }
 
-    pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> {
-        self.builder.ecx()
-    }
-
     /// Emit the data for a def-id to the metadata. The function to
     /// emit the data is `op`, and it will be given `data` as
-    /// arguments. This `record` function will start/end an RBML tag
-    /// and record the current offset for use in the index, calling
-    /// `op` to generate the data in the RBML tag.
+    /// arguments. This `record` function will call `op` to generate
+    /// the `Entry` (which may point to other encoded information)
+    /// and will then record the `Lazy<Entry>` for use in the index.
     ///
     /// In addition, it will setup a dep-graph task to track what data
     /// `op` accesses to generate the metadata, which is later used by
@@ -129,32 +114,18 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
     /// content system.
     pub fn record<DATA>(&mut self,
                         id: DefId,
-                        op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA),
+                        op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>,
                         data: DATA)
         where DATA: DepGraphRead
     {
-        let position = self.builder.rbml_w.mark_stable_position();
-        self.items.record(id, position);
-        let _task = self.ecx().tcx.dep_graph.in_task(DepNode::MetaData(id));
-        self.builder.rbml_w.start_tag(tag_items_data_item).unwrap();
-        data.read(self.ecx().tcx);
-        op(&mut self.builder, data);
-        self.builder.rbml_w.end_tag().unwrap();
-    }
-
-    pub fn into_fields(self) -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
-        (self.items, self.builder.xrefs)
-    }
-}
-
-impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
-    pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> {
-        self.ecx
+        let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id));
+        data.read(self.tcx);
+        let entry = op(&mut self.ecx, data);
+        self.items.record(id, self.ecx.lazy(&entry));
     }
 
-    pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
-        let old_len = self.xrefs.len() as u32;
-        *self.xrefs.entry(xref).or_insert(old_len)
+    pub fn into_items(self) -> Index {
+        self.items
     }
 }
 
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 9fb61934009..4fc5a46762d 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -17,23 +17,23 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(conservative_impl_trait)]
+#![feature(core_intrinsics)]
 #![feature(box_patterns)]
 #![feature(dotdot_in_tuple_patterns)]
-#![feature(enumset)]
 #![feature(question_mark)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_macro_lib)]
 #![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
+#![feature(specialization)]
 #![feature(staged_api)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
-#[macro_use] #[no_link] extern crate rustc_bitflags;
 extern crate syntax_pos;
 extern crate flate;
-extern crate rbml;
 extern crate serialize as rustc_serialize; // used by deriving
 extern crate rustc_errors as errors;
 extern crate syntax_ext;
@@ -46,27 +46,19 @@ extern crate rustc_llvm;
 extern crate rustc_macro;
 extern crate rustc_const_math;
 
-pub use rustc::middle;
+mod diagnostics;
 
-#[macro_use]
-mod macros;
-
-pub mod diagnostics;
-
-pub mod astencode;
-pub mod common;
-pub mod def_key;
-pub mod tyencode;
-pub mod tydecode;
-pub mod encoder;
+mod astencode;
 mod index_builder;
-pub mod decoder;
+mod index;
+mod encoder;
+mod decoder;
+mod csearch;
+mod schema;
+
 pub mod creader;
-pub mod csearch;
 pub mod cstore;
-pub mod index;
 pub mod loader;
 pub mod macro_import;
-pub mod tls_context;
 
 __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index a4f8ee47799..fc94cec916a 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -212,9 +212,8 @@
 //! no means all of the necessary details. Take a look at the rest of
 //! metadata::loader or metadata::creader for all the juicy details!
 
-use cstore::{MetadataBlob, MetadataVec, MetadataArchive};
-use common::{metadata_encoding_version, rustc_version};
-use decoder;
+use cstore::MetadataBlob;
+use schema::{METADATA_HEADER, RUSTC_VERSION};
 
 use rustc::hir::svh::Svh;
 use rustc::session::Session;
@@ -383,7 +382,7 @@ impl<'a> Context<'a> {
         }
         if !self.rejected_via_version.is_empty() {
             err.help(&format!("please recompile that crate using this compiler ({})",
-                              rustc_version()));
+                              RUSTC_VERSION));
             let mismatches = self.rejected_via_version.iter();
             for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() {
                 err.note(&format!("crate `{}` path #{}: {} compiled by {:?}",
@@ -511,9 +510,7 @@ impl<'a> Context<'a> {
                     if let Some((ref p, _)) = lib.rlib {
                         err.note(&format!("path: {}", p.display()));
                     }
-                    let data = lib.metadata.as_slice();
-                    let name = decoder::get_crate_name(data);
-                    note_crate_name(&mut err, &name);
+                    note_crate_name(&mut err, &lib.metadata.get_root().name);
                 }
                 err.emit();
                 None
@@ -551,7 +548,7 @@ impl<'a> Context<'a> {
             info!("{} reading metadata from: {}", flavor, lib.display());
             let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib) {
                 Ok(blob) => {
-                    if let Some(h) = self.crate_matches(blob.as_slice(), &lib) {
+                    if let Some(h) = self.crate_matches(&blob, &lib) {
                         (h, blob)
                     } else {
                         info!("metadata mismatch");
@@ -598,45 +595,38 @@ impl<'a> Context<'a> {
         }
     }
 
-    fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option<Svh> {
-        let crate_rustc_version = decoder::crate_rustc_version(crate_data);
-        if crate_rustc_version != Some(rustc_version()) {
-            let message = crate_rustc_version.unwrap_or(format!("an unknown compiler"));
-            info!("Rejecting via version: expected {} got {}", rustc_version(), message);
+    fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
+        let root = metadata.get_root();
+        if root.rustc_version != RUSTC_VERSION {
+            info!("Rejecting via version: expected {} got {}",
+                  RUSTC_VERSION, root.rustc_version);
             self.rejected_via_version.push(CrateMismatch {
                 path: libpath.to_path_buf(),
-                got: message
+                got: root.rustc_version
             });
             return None;
         }
 
         if self.should_match_name {
-            match decoder::maybe_get_crate_name(crate_data) {
-                Some(ref name) if self.crate_name == *name => {}
-                _ => { info!("Rejecting via crate name"); return None }
+            if self.crate_name != root.name {
+                info!("Rejecting via crate name"); return None;
             }
         }
-        let hash = match decoder::maybe_get_crate_hash(crate_data) {
-            None => { info!("Rejecting via lack of crate hash"); return None; }
-            Some(h) => h,
-        };
 
-        let triple = match decoder::get_crate_triple(crate_data) {
-            None => { debug!("triple not present"); return None }
-            Some(t) => t,
-        };
-        if triple != self.triple {
-            info!("Rejecting via crate triple: expected {} got {}", self.triple, triple);
+        if root.triple != self.triple {
+            info!("Rejecting via crate triple: expected {} got {}",
+                  self.triple, root.triple);
             self.rejected_via_triple.push(CrateMismatch {
                 path: libpath.to_path_buf(),
-                got: triple.to_string()
+                got: root.triple
             });
             return None;
         }
 
         if let Some(myhash) = self.hash {
-            if *myhash != hash {
-                info!("Rejecting via hash: expected {} got {}", *myhash, hash);
+            if *myhash != root.hash {
+                info!("Rejecting via hash: expected {} got {}",
+                      *myhash, root.hash);
                 self.rejected_via_hash.push(CrateMismatch {
                     path: libpath.to_path_buf(),
                     got: myhash.to_string()
@@ -645,7 +635,7 @@ impl<'a> Context<'a> {
             }
         }
 
-        Some(hash)
+        Some(root.hash)
     }
 
 
@@ -766,11 +756,7 @@ impl ArchiveMetadata {
 fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path)
                                         -> Result<(), String>
 {
-    let data = blob.as_slice_raw();
-    if data.len() < 4+metadata_encoding_version.len() ||
-        !<[u8]>::eq(&data[..4], &[0, 0, 0, 0]) ||
-        &data[4..4+metadata_encoding_version.len()] != metadata_encoding_version
-    {
+    if !blob.is_compatible() {
         Err((format!("incompatible metadata version found: '{}'",
                      filename.display())))
     } else {
@@ -805,7 +791,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
                                    filename.display()));
             }
         };
-        return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) {
+        return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) {
             None => Err(format!("failed to read rlib metadata: '{}'",
                                 filename.display())),
             Some(blob) => {
@@ -840,12 +826,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
                 let cbuf = llvm::LLVMGetSectionContents(si.llsi);
                 let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
                 let cvbuf: *const u8 = cbuf as *const u8;
-                let vlen = metadata_encoding_version.len();
+                let vlen = METADATA_HEADER.len();
                 debug!("checking {} bytes of metadata-version stamp",
                        vlen);
                 let minsz = cmp::min(vlen, csz);
                 let buf0 = slice::from_raw_parts(cvbuf, minsz);
-                let version_ok = buf0 == metadata_encoding_version;
+                let version_ok = buf0 == METADATA_HEADER;
                 if !version_ok {
                     return Err((format!("incompatible metadata version found: '{}'",
                                         filename.display())));
@@ -857,7 +843,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
                 let bytes = slice::from_raw_parts(cvbuf1, csz - vlen);
                 match flate::inflate_bytes(bytes) {
                     Ok(inflated) => {
-                        let blob = MetadataVec(inflated);
+                        let blob = MetadataBlob::Inflated(inflated);
                         verify_decompressed_encoding_version(&blob, filename)?;
                         return Ok(blob);
                     }
@@ -902,7 +888,7 @@ pub fn list_file_metadata(target: &Target, path: &Path,
     let filename = path.file_name().unwrap().to_str().unwrap();
     let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib };
     match get_metadata_section(target, flavor, path) {
-        Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
+        Ok(metadata) => metadata.list_crate_metadata(out),
         Err(msg) => {
             write!(out, "{}\n", msg)
         }
diff --git a/src/librustc_metadata/macros.rs b/src/librustc_metadata/macros.rs
deleted file mode 100644
index ed764ebd9f9..00000000000
--- a/src/librustc_metadata/macros.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-macro_rules! enum_from_u32 {
-    ($(#[$attr:meta])* pub enum $name:ident {
-        $($variant:ident = $e:expr,)*
-    }) => {
-        $(#[$attr])*
-        pub enum $name {
-            $($variant = $e),*
-        }
-
-        impl $name {
-            pub fn from_u32(u: u32) -> Option<$name> {
-                $(if u == $name::$variant as u32 {
-                    return Some($name::$variant)
-                })*
-                None
-            }
-        }
-    };
-    ($(#[$attr:meta])* pub enum $name:ident {
-        $($variant:ident,)*
-    }) => {
-        $(#[$attr])*
-        pub enum $name {
-            $($variant,)*
-        }
-
-        impl $name {
-            pub fn from_u32(u: u32) -> Option<$name> {
-                $(if u == $name::$variant as u32 {
-                    return Some($name::$variant)
-                })*
-                None
-            }
-        }
-    }
-}
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
new file mode 100644
index 00000000000..f4d1e8e17f8
--- /dev/null
+++ b/src/librustc_metadata/schema.rs
@@ -0,0 +1,349 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use astencode;
+use index;
+
+use rustc::hir;
+use rustc::hir::def;
+use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
+use rustc::middle::lang_items;
+use rustc::mir;
+use rustc::ty::{self, Ty};
+use rustc::session::config::PanicStrategy;
+
+use rustc_serialize as serialize;
+use syntax::{ast, attr};
+use syntax_pos::{self, Span};
+
+use std::marker::PhantomData;
+
+#[cfg(not(test))]
+pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION"));
+
+#[cfg(test)]
+pub const RUSTC_VERSION: &'static str = "rustc 0.0.0-unit-test";
+
+/// Metadata encoding version.
+/// NB: increment this if you change the format of metadata such that
+/// the rustc version can't be found to compare with `RUSTC_VERSION`.
+pub const METADATA_VERSION: u8 = 3;
+
+/// Metadata header which includes `METADATA_VERSION`.
+/// To get older versions of rustc to ignore this metadata,
+/// there are 4 zero bytes at the start, which are treated
+/// as a length of 0 by old compilers.
+///
+/// This header is followed by the position of the `CrateRoot`.
+pub const METADATA_HEADER: &'static [u8; 12] = &[
+    0, 0, 0, 0,
+    b'r', b'u', b's', b't',
+    0, 0, 0, METADATA_VERSION
+];
+
+/// The shorthand encoding uses an enum's variant index `usize`
+/// and is offset by this value so it never matches a real variant.
+/// This offset is also chosen so that the first byte is never < 0x80.
+pub const SHORTHAND_OFFSET: usize = 0x80;
+
+/// A value of type T referred to by its absolute position
+/// in the metadata, and which can be decoded lazily.
+///
+/// Metadata is effective a tree, encoded in post-order,
+/// and with the root's position written next to the header.
+/// That means every single `Lazy` points to some previous
+/// location in the metadata and is part of a larger node.
+///
+/// The first `Lazy` in a node is encoded as the backwards
+/// distance from the position where the containing node
+/// starts and where the `Lazy` points to, while the rest
+/// use the forward distance from the previous `Lazy`.
+/// Distances start at 1, as 0-byte nodes are invalid.
+/// Also invalid are nodes being referred in a different
+/// order than they were encoded in.
+#[must_use]
+pub struct Lazy<T> {
+    pub position: usize,
+    _marker: PhantomData<T>
+}
+
+impl<T> Lazy<T> {
+    pub fn with_position(position: usize) -> Lazy<T> {
+        Lazy {
+            position: position,
+            _marker: PhantomData
+        }
+    }
+
+    /// Returns the minimum encoded size of a value of type `T`.
+    // FIXME(eddyb) Give better estimates for certain types.
+    pub fn min_size() -> usize {
+        1
+    }
+}
+
+impl<T> Copy for Lazy<T> {}
+impl<T> Clone for Lazy<T> {
+    fn clone(&self) -> Self { *self }
+}
+
+impl<T> serialize::UseSpecializedEncodable for Lazy<T> {}
+impl<T> serialize::UseSpecializedDecodable for Lazy<T> {}
+
+/// A sequence of type T referred to by its absolute position
+/// in the metadata and length, and which can be decoded lazily.
+/// The sequence is a single node for the purposes of `Lazy`.
+///
+/// Unlike `Lazy<Vec<T>>`, the length is encoded next to the
+/// position, not at the position, which means that the length
+/// doesn't need to be known before encoding all the elements.
+///
+/// If the length is 0, no position is encoded, but otherwise,
+/// the encoding is that of `Lazy`, with the distinction that
+/// the minimal distance the length of the sequence, i.e.
+/// it's assumed there's no 0-byte element in the sequence.
+#[must_use]
+pub struct LazySeq<T> {
+    pub len: usize,
+    pub position: usize,
+    _marker: PhantomData<T>
+}
+
+impl<T> LazySeq<T> {
+    pub fn empty() -> LazySeq<T> {
+        LazySeq::with_position_and_length(0, 0)
+    }
+
+    pub fn with_position_and_length(position: usize, len: usize) -> LazySeq<T> {
+        LazySeq {
+            len: len,
+            position: position,
+            _marker: PhantomData
+        }
+    }
+
+    /// Returns the minimum encoded size of `length` values of type `T`.
+    pub fn min_size(length: usize) -> usize {
+        length
+    }
+}
+
+impl<T> Copy for LazySeq<T> {}
+impl<T> Clone for LazySeq<T> {
+    fn clone(&self) -> Self { *self }
+}
+
+impl<T> serialize::UseSpecializedEncodable for LazySeq<T> {}
+impl<T> serialize::UseSpecializedDecodable for LazySeq<T> {}
+
+/// Encoding / decoding state for `Lazy` and `LazySeq`.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum LazyState {
+    /// Outside of a metadata node.
+    NoNode,
+
+    /// Inside a metadata node, and before any `Lazy` or `LazySeq`.
+    /// The position is that of the node itself.
+    NodeStart(usize),
+
+    /// Inside a metadata node, with a previous `Lazy` or `LazySeq`.
+    /// The position is a conservative estimate of where that
+    /// previous `Lazy` / `LazySeq` would end (see their comments).
+    Previous(usize)
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct CrateRoot {
+    pub rustc_version: String,
+    pub name: String,
+    pub triple: String,
+    pub hash: hir::svh::Svh,
+    pub disambiguator: String,
+    pub panic_strategy: PanicStrategy,
+    pub plugin_registrar_fn: Option<DefIndex>,
+    pub macro_derive_registrar: Option<DefIndex>,
+
+    pub crate_deps: LazySeq<CrateDep>,
+    pub dylib_dependency_formats: LazySeq<Option<LinkagePreference>>,
+    pub lang_items: LazySeq<(DefIndex, usize)>,
+    pub lang_items_missing: LazySeq<lang_items::LangItem>,
+    pub native_libraries: LazySeq<(NativeLibraryKind, String)>,
+    pub codemap: LazySeq<syntax_pos::FileMap>,
+    pub macro_defs: LazySeq<MacroDef>,
+    pub impls: LazySeq<TraitImpls>,
+    pub reachable_ids: LazySeq<DefIndex>,
+    pub index: LazySeq<index::Index>,
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct CrateDep {
+    pub name: ast::Name,
+    pub hash: hir::svh::Svh,
+    pub explicitly_linked: bool
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct TraitImpls {
+    pub trait_id: (u32, DefIndex),
+    pub impls: LazySeq<DefIndex>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct MacroDef {
+    pub name: ast::Name,
+    pub attrs: Vec<ast::Attribute>,
+    pub span: Span,
+    pub body: String
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct Entry<'tcx> {
+    pub kind: EntryKind<'tcx>,
+    pub visibility: ty::Visibility,
+    pub def_key: Lazy<hir::map::DefKey>,
+    pub attributes: LazySeq<ast::Attribute>,
+    pub children: LazySeq<DefIndex>,
+    pub stability: Option<Lazy<attr::Stability>>,
+    pub deprecation: Option<Lazy<attr::Deprecation>>,
+
+    pub ty: Option<Lazy<Ty<'tcx>>>,
+    pub inherent_impls: LazySeq<DefIndex>,
+    pub variances: LazySeq<ty::Variance>,
+    pub generics: Option<Lazy<ty::Generics<'tcx>>>,
+    pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
+
+    pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
+    pub mir: Option<Lazy<mir::repr::Mir<'tcx>>>
+}
+
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub enum EntryKind<'tcx> {
+    Const,
+    ImmStatic,
+    MutStatic,
+    ForeignImmStatic,
+    ForeignMutStatic,
+    ForeignMod,
+    Type,
+    Enum,
+    Field,
+    Variant(Lazy<VariantData>),
+    Struct(Lazy<VariantData>),
+    Union(Lazy<VariantData>),
+    Fn(Lazy<FnData>),
+    ForeignFn(Lazy<FnData>),
+    Mod(Lazy<ModData>),
+    Closure(Lazy<ClosureData<'tcx>>),
+    Trait(Lazy<TraitData<'tcx>>),
+    Impl(Lazy<ImplData<'tcx>>),
+    DefaultImpl(Lazy<ImplData<'tcx>>),
+    Method(Lazy<MethodData<'tcx>>),
+    AssociatedType(AssociatedContainer),
+    AssociatedConst(AssociatedContainer)
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct ModData {
+    pub reexports: LazySeq<def::Export>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct FnData {
+    pub constness: hir::Constness,
+    pub arg_names: LazySeq<ast::Name>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct VariantData {
+    pub kind: ty::VariantKind,
+    pub disr: u64,
+
+    /// If this is a struct's only variant, this
+    /// is the index of the "struct ctor" item.
+    pub struct_ctor: Option<DefIndex>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct TraitData<'tcx> {
+    pub unsafety: hir::Unsafety,
+    pub paren_sugar: bool,
+    pub has_default_impl: bool,
+    pub trait_ref: Lazy<ty::TraitRef<'tcx>>,
+    pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct ImplData<'tcx> {
+    pub polarity: hir::ImplPolarity,
+    pub parent_impl: Option<DefId>,
+    pub coerce_unsized_kind: Option<ty::adjustment::CustomCoerceUnsized>,
+    pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>
+}
+
+/// Describes whether the container of an associated item
+/// is a trait or an impl and whether, in a trait, it has
+/// a default, or an in impl, whether it's marked "default".
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub enum AssociatedContainer {
+    TraitRequired,
+    TraitWithDefault,
+    ImplDefault,
+    ImplFinal
+}
+
+impl AssociatedContainer {
+    pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer {
+        match *self {
+            AssociatedContainer::TraitRequired |
+            AssociatedContainer::TraitWithDefault => {
+                ty::TraitContainer(def_id)
+            }
+
+            AssociatedContainer::ImplDefault |
+            AssociatedContainer::ImplFinal => {
+                ty::ImplContainer(def_id)
+            }
+        }
+    }
+
+    pub fn has_body(&self) -> bool {
+        match *self {
+            AssociatedContainer::TraitRequired => false,
+
+            AssociatedContainer::TraitWithDefault |
+            AssociatedContainer::ImplDefault |
+            AssociatedContainer::ImplFinal => true
+        }
+    }
+
+    pub fn defaultness(&self) -> hir::Defaultness {
+        match *self {
+            AssociatedContainer::TraitRequired |
+            AssociatedContainer::TraitWithDefault |
+            AssociatedContainer::ImplDefault => hir::Defaultness::Default,
+
+            AssociatedContainer::ImplFinal => hir::Defaultness::Final
+        }
+    }
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct MethodData<'tcx> {
+    pub fn_data: FnData,
+    pub container: AssociatedContainer,
+    pub explicit_self: Lazy<ty::ExplicitSelfCategory<'tcx>>
+}
+
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct ClosureData<'tcx> {
+    pub kind: ty::ClosureKind,
+    pub ty: Lazy<ty::ClosureTy<'tcx>>
+}
diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs
deleted file mode 100644
index 6e78cbcd28e..00000000000
--- a/src/librustc_metadata/tls_context.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This module provides implementations for the thread-local encoding and
-// decoding context traits in rustc::middle::cstore::tls.
-
-use rbml::opaque::Encoder as OpaqueEncoder;
-use rbml::opaque::Decoder as OpaqueDecoder;
-use rustc::middle::cstore::tls;
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
-use rustc::ty::{self, TyCtxt};
-
-use decoder::{self, Cmd};
-use encoder;
-use tydecode::TyDecoder;
-use tyencode;
-
-impl<'a, 'tcx: 'a> tls::EncodingContext<'tcx> for encoder::EncodeContext<'a, 'tcx> {
-
-    fn tcx<'s>(&'s self) -> TyCtxt<'s, 'tcx, 'tcx> {
-        self.tcx
-    }
-
-    fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: ty::Ty<'tcx>) {
-        tyencode::enc_ty(encoder.cursor, &self.ty_str_ctxt(), t);
-    }
-
-    fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>) {
-        tyencode::enc_substs(encoder.cursor, &self.ty_str_ctxt(), substs);
-    }
-}
-
-pub struct DecodingContext<'a, 'tcx: 'a> {
-    pub crate_metadata: Cmd<'a>,
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-}
-
-impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> {
-
-    fn tcx<'s>(&'s self) -> TyCtxt<'s, 'tcx, 'tcx> {
-        self.tcx
-    }
-
-    fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx> {
-        let def_id_convert = &mut |did| {
-            decoder::translate_def_id(self.crate_metadata, did)
-        };
-
-        let starting_position = decoder.position();
-
-        let mut ty_decoder = TyDecoder::new(
-            self.crate_metadata.data.as_slice(),
-            self.crate_metadata.cnum,
-            starting_position,
-            self.tcx,
-            def_id_convert);
-
-        let ty = ty_decoder.parse_ty();
-
-        let end_position = ty_decoder.position();
-
-        // We can just reuse the tydecode implementation for parsing types, but
-        // we have to make sure to leave the rbml reader at the position just
-        // after the type.
-        decoder.advance(end_position - starting_position);
-        ty
-    }
-
-    fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx> {
-        let def_id_convert = &mut |did| {
-            decoder::translate_def_id(self.crate_metadata, did)
-        };
-
-        let starting_position = decoder.position();
-
-        let mut ty_decoder = TyDecoder::new(
-            self.crate_metadata.data.as_slice(),
-            self.crate_metadata.cnum,
-            starting_position,
-            self.tcx,
-            def_id_convert);
-
-        let substs = ty_decoder.parse_substs();
-
-        let end_position = ty_decoder.position();
-
-        decoder.advance(end_position - starting_position);
-        substs
-    }
-
-    fn translate_def_id(&self, def_id: DefId) -> DefId {
-        decoder::translate_def_id(self.crate_metadata, def_id)
-    }
-}
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
deleted file mode 100644
index bcaf1640bc4..00000000000
--- a/src/librustc_metadata/tydecode.rs
+++ /dev/null
@@ -1,750 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-// Type decoding
-
-// tjc note: Would be great to have a `match check` macro equivalent
-// for some of these
-
-#![allow(non_camel_case_types)]
-
-use rustc::hir;
-
-use rustc::hir::def_id::{DefId, DefIndex};
-use middle::region;
-use rustc::ty::subst::{Kind, Substs};
-use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
-
-use rbml;
-use rbml::leb128;
-use std::str;
-use syntax::abi;
-use syntax::ast;
-use syntax::parse::token;
-
-// Compact string representation for Ty values. API TyStr &
-// parse_from_str. Extra parameters are for converting to/from def_ids in the
-// data buffer. Whatever format you choose should not contain pipe characters.
-
-pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId;
-
-pub struct TyDecoder<'a, 'tcx: 'a> {
-    data: &'a [u8],
-    krate: ast::CrateNum,
-    pos: usize,
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    conv_def_id: DefIdConvert<'a>,
-}
-
-impl<'a,'tcx> TyDecoder<'a,'tcx> {
-    pub fn with_doc(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    crate_num: ast::CrateNum,
-                    doc: rbml::Doc<'a>,
-                    conv: DefIdConvert<'a>)
-                    -> TyDecoder<'a,'tcx> {
-        TyDecoder::new(doc.data, crate_num, doc.start, tcx, conv)
-    }
-
-    pub fn new(data: &'a [u8],
-               crate_num: ast::CrateNum,
-               pos: usize,
-               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               conv: DefIdConvert<'a>)
-               -> TyDecoder<'a, 'tcx> {
-        TyDecoder {
-            data: data,
-            krate: crate_num,
-            pos: pos,
-            tcx: tcx,
-            conv_def_id: conv,
-        }
-    }
-
-    pub fn position(&self) -> usize {
-        self.pos
-    }
-
-    fn peek(&self) -> char {
-        self.data[self.pos] as char
-    }
-
-    fn next(&mut self) -> char {
-        let ch = self.data[self.pos] as char;
-        self.pos = self.pos + 1;
-        return ch;
-    }
-
-    fn next_byte(&mut self) -> u8 {
-        let b = self.data[self.pos];
-        self.pos = self.pos + 1;
-        return b;
-    }
-
-    fn scan<F>(&mut self, mut is_last: F) -> &'a [u8]
-        where F: FnMut(char) -> bool,
-    {
-        let start_pos = self.pos;
-        debug!("scan: '{}' (start)", self.data[self.pos] as char);
-        while !is_last(self.data[self.pos] as char) {
-            self.pos += 1;
-            debug!("scan: '{}'", self.data[self.pos] as char);
-        }
-        let end_pos = self.pos;
-        self.pos += 1;
-        return &self.data[start_pos..end_pos];
-    }
-
-    fn parse_vuint(&mut self) -> usize {
-        let (value, bytes_read) = leb128::read_unsigned_leb128(self.data,
-                                                               self.pos);
-        self.pos += bytes_read;
-        value as usize
-    }
-
-    fn parse_name(&mut self, last: char) -> ast::Name {
-        fn is_last(b: char, c: char) -> bool { return c == b; }
-        let bytes = self.scan(|a| is_last(last, a));
-        token::intern(str::from_utf8(bytes).unwrap())
-    }
-
-    fn parse_size(&mut self) -> Option<usize> {
-        assert_eq!(self.next(), '/');
-
-        if self.peek() == '|' {
-            assert_eq!(self.next(), '|');
-            None
-        } else {
-            let n = self.parse_uint();
-            assert_eq!(self.next(), '|');
-            Some(n)
-        }
-    }
-
-    pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> {
-        let mut params = vec![];
-        assert_eq!(self.next(), '[');
-        while self.peek() != ']' {
-            let k = match self.next() {
-                'r' => Kind::from(self.parse_region()),
-                't' => Kind::from(self.parse_ty()),
-                _ => bug!()
-            };
-            params.push(k);
-        }
-        assert_eq!(self.next(), ']');
-
-        Substs::new(self.tcx, params)
-    }
-
-    pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> {
-        let parent = self.parse_opt(|this| this.parse_def());
-        let parent_regions = self.parse_u32();
-        assert_eq!(self.next(), '|');
-        let parent_types = self.parse_u32();
-
-        let mut regions = vec![];
-        let mut types = vec![];
-        assert_eq!(self.next(), '[');
-        while self.peek() != '|' {
-            regions.push(self.parse_region_param_def());
-        }
-        assert_eq!(self.next(), '|');
-        while self.peek() != ']' {
-            types.push(self.parse_type_param_def());
-        }
-        assert_eq!(self.next(), ']');
-
-        self.tcx.alloc_generics(ty::Generics {
-            parent: parent,
-            parent_regions: parent_regions,
-            parent_types: parent_types,
-            regions: regions,
-            types: types,
-            has_self: self.next() == 'S'
-        })
-    }
-
-    fn parse_bound_region(&mut self) -> ty::BoundRegion {
-        match self.next() {
-            'a' => {
-                let id = self.parse_u32();
-                assert_eq!(self.next(), '|');
-                ty::BrAnon(id)
-            }
-            '[' => {
-                let def = self.parse_def();
-                let name = token::intern(&self.parse_str('|'));
-                let issue32330 = match self.next() {
-                    'n' => {
-                        assert_eq!(self.next(), ']');
-                        ty::Issue32330::WontChange
-                    }
-                    'y' => {
-                        ty::Issue32330::WillChange {
-                            fn_def_id: self.parse_def(),
-                            region_name: token::intern(&self.parse_str(']')),
-                        }
-                    }
-                    c => panic!("expected n or y not {}", c)
-                };
-                ty::BrNamed(def, name, issue32330)
-            }
-            'f' => {
-                let id = self.parse_u32();
-                assert_eq!(self.next(), '|');
-                ty::BrFresh(id)
-            }
-            'e' => ty::BrEnv,
-            _ => bug!("parse_bound_region: bad input")
-        }
-    }
-
-    pub fn parse_region(&mut self) -> &'tcx ty::Region {
-        self.tcx.mk_region(match self.next() {
-            'b' => {
-                assert_eq!(self.next(), '[');
-                let id = ty::DebruijnIndex::new(self.parse_u32());
-                assert_eq!(self.next(), '|');
-                let br = self.parse_bound_region();
-                assert_eq!(self.next(), ']');
-                ty::ReLateBound(id, br)
-            }
-            'B' => {
-                assert_eq!(self.next(), '[');
-                let index = self.parse_u32();
-                assert_eq!(self.next(), '|');
-                let name = token::intern(&self.parse_str(']'));
-                ty::ReEarlyBound(ty::EarlyBoundRegion {
-                    index: index,
-                    name: name
-                })
-            }
-            'f' => {
-                assert_eq!(self.next(), '[');
-                let scope = self.parse_scope();
-                assert_eq!(self.next(), '|');
-                let br = self.parse_bound_region();
-                assert_eq!(self.next(), ']');
-                ty::ReFree(ty::FreeRegion { scope: scope,
-                                            bound_region: br})
-            }
-            's' => {
-                let scope = self.parse_scope();
-                assert_eq!(self.next(), '|');
-                ty::ReScope(scope)
-            }
-            't' => ty::ReStatic,
-            'e' => ty::ReEmpty,
-            'E' => ty::ReErased,
-            _ => bug!("parse_region: bad input")
-        })
-    }
-
-    fn parse_scope(&mut self) -> region::CodeExtent {
-        self.tcx.region_maps.bogus_code_extent(match self.next() {
-            // This creates scopes with the wrong NodeId. This isn't
-            // actually a problem because scopes only exist *within*
-            // functions, and functions aren't loaded until trans which
-            // doesn't care about regions.
-            //
-            // May still be worth fixing though.
-            'C' => {
-                assert_eq!(self.next(), '[');
-                let fn_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), '|');
-                let body_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), ']');
-                region::CodeExtentData::CallSiteScope {
-                    fn_id: fn_id, body_id: body_id
-                }
-            }
-            // This creates scopes with the wrong NodeId. (See note above.)
-            'P' => {
-                assert_eq!(self.next(), '[');
-                let fn_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), '|');
-                let body_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), ']');
-                region::CodeExtentData::ParameterScope {
-                    fn_id: fn_id, body_id: body_id
-                }
-            }
-            'M' => {
-                let node_id = self.parse_uint() as ast::NodeId;
-                region::CodeExtentData::Misc(node_id)
-            }
-            'D' => {
-                let node_id = self.parse_uint() as ast::NodeId;
-                region::CodeExtentData::DestructionScope(node_id)
-            }
-            'B' => {
-                assert_eq!(self.next(), '[');
-                let node_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), '|');
-                let first_stmt_index = self.parse_u32();
-                assert_eq!(self.next(), ']');
-                let block_remainder = region::BlockRemainder {
-                    block: node_id, first_statement_index: first_stmt_index,
-                };
-                region::CodeExtentData::Remainder(block_remainder)
-            }
-            _ => bug!("parse_scope: bad input")
-        })
-    }
-
-    fn parse_opt<T, F>(&mut self, f: F) -> Option<T>
-        where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T,
-    {
-        match self.next() {
-            'n' => None,
-            's' => Some(f(self)),
-            _ => bug!("parse_opt: bad input")
-        }
-    }
-
-    fn parse_str(&mut self, term: char) -> String {
-        let mut result = String::new();
-        while self.peek() != term {
-            unsafe {
-                result.as_mut_vec().extend_from_slice(&[self.next_byte()])
-            }
-        }
-        self.next();
-        result
-    }
-
-    pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> {
-        ty::TraitRef {
-            def_id: self.parse_def(),
-            substs: self.parse_substs()
-        }
-    }
-
-    pub fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> {
-        ty::ExistentialTraitRef {
-            def_id: self.parse_def(),
-            substs: self.parse_substs()
-        }
-    }
-
-    pub fn parse_ty(&mut self) -> Ty<'tcx> {
-        let tcx = self.tcx;
-        match self.next() {
-            'b' => return tcx.types.bool,
-            '!' => return tcx.types.never,
-            'i' => { /* eat the s of is */ self.next(); return tcx.types.isize },
-            'u' => { /* eat the s of us */ self.next(); return tcx.types.usize },
-            'M' => {
-                match self.next() {
-                    'b' => return tcx.types.u8,
-                    'w' => return tcx.types.u16,
-                    'l' => return tcx.types.u32,
-                    'd' => return tcx.types.u64,
-                    'B' => return tcx.types.i8,
-                    'W' => return tcx.types.i16,
-                    'L' => return tcx.types.i32,
-                    'D' => return tcx.types.i64,
-                    'f' => return tcx.types.f32,
-                    'F' => return tcx.types.f64,
-                    _ => bug!("parse_ty: bad numeric type")
-                }
-            }
-            'c' => return tcx.types.char,
-            'x' => {
-                assert_eq!(self.next(), '[');
-                let trait_ref = ty::Binder(self.parse_existential_trait_ref());
-                let builtin_bounds = self.parse_builtin_bounds();
-                let region_bound = self.parse_region();
-                let mut projection_bounds = Vec::new();
-
-                loop {
-                    match self.next() {
-                        'P' => {
-                            let bound = self.parse_existential_projection();
-                            projection_bounds.push(ty::Binder(bound));
-                        }
-                        '.' => { break; }
-                        c => {
-                            bug!("parse_bounds: bad bounds ('{}')", c)
-                        }
-                    }
-                }
-                assert_eq!(self.next(), ']');
-                return tcx.mk_trait(ty::TraitObject {
-                    principal: trait_ref,
-                    region_bound: region_bound,
-                    builtin_bounds: builtin_bounds,
-                    projection_bounds: projection_bounds
-                });
-            }
-            'p' => {
-                assert_eq!(self.next(), '[');
-                let index = self.parse_u32();
-                assert_eq!(self.next(), '|');
-                let name = token::intern(&self.parse_str(']'));
-                return tcx.mk_param(index, name);
-            }
-            '~' => return tcx.mk_box(self.parse_ty()),
-            '*' => return tcx.mk_ptr(self.parse_mt()),
-            '&' => {
-                return tcx.mk_ref(self.parse_region(), self.parse_mt());
-            }
-            'V' => {
-                let t = self.parse_ty();
-                return match self.parse_size() {
-                    Some(n) => tcx.mk_array(t, n),
-                    None => tcx.mk_slice(t)
-                };
-            }
-            'v' => {
-                return tcx.mk_str();
-            }
-            'T' => {
-                assert_eq!(self.next(), '[');
-                let mut params = Vec::new();
-                while self.peek() != ']' { params.push(self.parse_ty()); }
-                self.pos = self.pos + 1;
-                return tcx.mk_tup(params);
-            }
-            'F' => {
-                let def_id = self.parse_def();
-                let substs = self.parse_substs();
-                return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty());
-            }
-            'G' => {
-                return tcx.mk_fn_ptr(self.parse_bare_fn_ty());
-            }
-            '#' => {
-                // This is a hacky little caching scheme. The idea is that if we encode
-                // the same type twice, the second (and third, and fourth...) time we will
-                // just write `#123`, where `123` is the offset in the metadata of the
-                // first appearance. Now when we are *decoding*, if we see a `#123`, we
-                // can first check a cache (`tcx.rcache`) for that offset. If we find something,
-                // we return it (modulo closure types, see below). But if not, then we
-                // jump to offset 123 and read the type from there.
-
-                let pos = self.parse_vuint();
-                let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos };
-                if let Some(tt) = tcx.rcache.borrow().get(&key).cloned() {
-                    // If there is a closure buried in the type some where, then we
-                    // need to re-convert any def ids (see case 'k', below). That means
-                    // we can't reuse the cached version.
-                    if !tt.has_closure_types() {
-                        return tt;
-                    }
-                }
-
-                let mut substate = TyDecoder::new(self.data,
-                                                  self.krate,
-                                                  pos,
-                                                  self.tcx,
-                                                  self.conv_def_id);
-                let tt = substate.parse_ty();
-                tcx.rcache.borrow_mut().insert(key, tt);
-                return tt;
-            }
-            '\"' => {
-                let _ = self.parse_def();
-                let inner = self.parse_ty();
-                inner
-            }
-            'a' => {
-                assert_eq!(self.next(), '[');
-                let did = self.parse_def();
-                let substs = self.parse_substs();
-                assert_eq!(self.next(), ']');
-                let def = self.tcx.lookup_adt_def(did);
-                return self.tcx.mk_adt(def, substs);
-            }
-            'k' => {
-                assert_eq!(self.next(), '[');
-                let did = self.parse_def();
-                let substs = self.parse_substs();
-                let mut tys = vec![];
-                while self.peek() != '.' {
-                    tys.push(self.parse_ty());
-                }
-                assert_eq!(self.next(), '.');
-                assert_eq!(self.next(), ']');
-                return self.tcx.mk_closure(did, substs, tys);
-            }
-            'P' => {
-                assert_eq!(self.next(), '[');
-                let trait_ref = self.parse_trait_ref();
-                let name = token::intern(&self.parse_str(']'));
-                return tcx.mk_projection(trait_ref, name);
-            }
-            'A' => {
-                assert_eq!(self.next(), '[');
-                let def_id = self.parse_def();
-                let substs = self.parse_substs();
-                assert_eq!(self.next(), ']');
-                return self.tcx.mk_anon(def_id, substs);
-            }
-            'e' => {
-                return tcx.types.err;
-            }
-            c => { bug!("unexpected char in type string: {}", c);}
-        }
-    }
-
-    fn parse_mutability(&mut self) -> hir::Mutability {
-        match self.peek() {
-            'm' => { self.next(); hir::MutMutable }
-            _ => { hir::MutImmutable }
-        }
-    }
-
-    fn parse_mt(&mut self) -> ty::TypeAndMut<'tcx> {
-        let m = self.parse_mutability();
-        ty::TypeAndMut { ty: self.parse_ty(), mutbl: m }
-    }
-
-    fn parse_def(&mut self) -> DefId {
-        let def_id = parse_defid(self.scan(|c| c == '|'));
-        return (self.conv_def_id)(def_id);
-    }
-
-    fn parse_uint(&mut self) -> usize {
-        let mut n = 0;
-        loop {
-            let cur = self.peek();
-            if cur < '0' || cur > '9' { return n; }
-            self.pos = self.pos + 1;
-            n *= 10;
-            n += (cur as usize) - ('0' as usize);
-        };
-    }
-
-    fn parse_u32(&mut self) -> u32 {
-        let n = self.parse_uint();
-        let m = n as u32;
-        assert_eq!(m as usize, n);
-        m
-    }
-
-    fn parse_abi_set(&mut self) -> abi::Abi {
-        assert_eq!(self.next(), '[');
-        let bytes = self.scan(|c| c == ']');
-        let abi_str = str::from_utf8(bytes).unwrap();
-        abi::lookup(&abi_str[..]).expect(abi_str)
-    }
-
-    pub fn parse_closure_ty(&mut self) -> ty::ClosureTy<'tcx> {
-        let unsafety = parse_unsafety(self.next());
-        let sig = self.parse_sig();
-        let abi = self.parse_abi_set();
-        ty::ClosureTy {
-            unsafety: unsafety,
-            sig: sig,
-            abi: abi,
-        }
-    }
-
-    pub fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> {
-        let unsafety = parse_unsafety(self.next());
-        let abi = self.parse_abi_set();
-        let sig = self.parse_sig();
-        self.tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: sig
-        })
-    }
-
-    fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> {
-        assert_eq!(self.next(), '[');
-        let mut inputs = Vec::new();
-        while self.peek() != ']' {
-            inputs.push(self.parse_ty());
-        }
-        self.pos += 1; // eat the ']'
-        let variadic = match self.next() {
-            'V' => true,
-            'N' => false,
-            r => bug!("bad variadic: {}", r),
-        };
-        let output = self.parse_ty();
-        ty::Binder(ty::FnSig {inputs: inputs,
-                              output: output,
-                              variadic: variadic})
-    }
-
-    pub fn parse_predicate(&mut self) -> ty::Predicate<'tcx> {
-        match self.next() {
-            't' => ty::Binder(self.parse_trait_ref()).to_predicate(),
-            'e' => ty::Binder(ty::EquatePredicate(self.parse_ty(),
-                                                  self.parse_ty())).to_predicate(),
-            'r' => ty::Binder(ty::OutlivesPredicate(self.parse_region(),
-                                                    self.parse_region())).to_predicate(),
-            'o' => ty::Binder(ty::OutlivesPredicate(self.parse_ty(),
-                                                    self.parse_region())).to_predicate(),
-            'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(),
-            'w' => ty::Predicate::WellFormed(self.parse_ty()),
-            'O' => {
-                let def_id = self.parse_def();
-                assert_eq!(self.next(), '|');
-                ty::Predicate::ObjectSafe(def_id)
-            }
-            'c' => {
-                let def_id = self.parse_def();
-                assert_eq!(self.next(), '|');
-                let kind = match self.next() {
-                    'f' => ty::ClosureKind::Fn,
-                    'm' => ty::ClosureKind::FnMut,
-                    'o' => ty::ClosureKind::FnOnce,
-                    c => bug!("Encountered invalid character in metadata: {}", c)
-                };
-                assert_eq!(self.next(), '|');
-                ty::Predicate::ClosureKind(def_id, kind)
-            }
-            c => bug!("Encountered invalid character in metadata: {}", c)
-        }
-    }
-
-    fn parse_projection_predicate(&mut self) -> ty::ProjectionPredicate<'tcx> {
-        ty::ProjectionPredicate {
-            projection_ty: ty::ProjectionTy {
-                trait_ref: self.parse_trait_ref(),
-                item_name: token::intern(&self.parse_str('|')),
-            },
-            ty: self.parse_ty(),
-        }
-    }
-
-    fn parse_existential_projection(&mut self) -> ty::ExistentialProjection<'tcx> {
-        ty::ExistentialProjection {
-            trait_ref: self.parse_existential_trait_ref(),
-            item_name: token::intern(&self.parse_str('|')),
-            ty: self.parse_ty(),
-        }
-    }
-
-    fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
-        let name = self.parse_name(':');
-        let def_id = self.parse_def();
-        let index = self.parse_u32();
-        assert_eq!(self.next(), '|');
-        let default_def_id = self.parse_def();
-        let default = self.parse_opt(|this| this.parse_ty());
-        let object_lifetime_default = self.parse_object_lifetime_default();
-
-        ty::TypeParameterDef {
-            name: name,
-            def_id: def_id,
-            index: index,
-            default_def_id: default_def_id,
-            default: default,
-            object_lifetime_default: object_lifetime_default,
-        }
-    }
-
-    fn parse_region_param_def(&mut self) -> ty::RegionParameterDef<'tcx> {
-        let name = self.parse_name(':');
-        let def_id = self.parse_def();
-        let index = self.parse_u32();
-        assert_eq!(self.next(), '|');
-        let mut bounds = vec![];
-        loop {
-            match self.next() {
-                'R' => bounds.push(self.parse_region()),
-                '.' => { break; }
-                c => {
-                    bug!("parse_region_param_def: bad bounds ('{}')", c)
-                }
-            }
-        }
-        ty::RegionParameterDef {
-            name: name,
-            def_id: def_id,
-            index: index,
-            bounds: bounds,
-        }
-    }
-
-
-    fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault<'tcx> {
-        match self.next() {
-            'a' => ty::ObjectLifetimeDefault::Ambiguous,
-            'b' => ty::ObjectLifetimeDefault::BaseDefault,
-            's' => {
-                let region = self.parse_region();
-                ty::ObjectLifetimeDefault::Specific(region)
-            }
-            _ => bug!("parse_object_lifetime_default: bad input")
-        }
-    }
-
-    fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds {
-        let mut builtin_bounds = ty::BuiltinBounds::empty();
-        loop {
-            match self.next() {
-                'S' => {
-                    builtin_bounds.insert(ty::BoundSend);
-                }
-                'Z' => {
-                    builtin_bounds.insert(ty::BoundSized);
-                }
-                'P' => {
-                    builtin_bounds.insert(ty::BoundCopy);
-                }
-                'T' => {
-                    builtin_bounds.insert(ty::BoundSync);
-                }
-                '.' => {
-                    return builtin_bounds;
-                }
-                c => {
-                    bug!("parse_bounds: bad builtin bounds ('{}')", c)
-                }
-            }
-        }
-    }
-}
-
-// Rust metadata parsing
-fn parse_defid(buf: &[u8]) -> DefId {
-    let mut colon_idx = 0;
-    let len = buf.len();
-    while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1; }
-    if colon_idx == len {
-        error!("didn't find ':' when parsing def id");
-        bug!();
-    }
-
-    let crate_part = &buf[0..colon_idx];
-    let def_part = &buf[colon_idx + 1..len];
-
-    let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| {
-        s.parse::<usize>().ok()
-    }) {
-        Some(cn) => cn as ast::CrateNum,
-        None => bug!("internal error: parse_defid: crate number expected, found {:?}",
-                       crate_part)
-    };
-    let def_num = match str::from_utf8(def_part).ok().and_then(|s| {
-        s.parse::<usize>().ok()
-    }) {
-        Some(dn) => dn,
-        None => bug!("internal error: parse_defid: id expected, found {:?}",
-                       def_part)
-    };
-    let index = DefIndex::new(def_num);
-    DefId { krate: crate_num, index: index }
-}
-
-fn parse_unsafety(c: char) -> hir::Unsafety {
-    match c {
-        'u' => hir::Unsafety::Unsafe,
-        'n' => hir::Unsafety::Normal,
-        _ => bug!("parse_unsafety: bad unsafety {}", c)
-    }
-}
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
deleted file mode 100644
index dbefd3eacc2..00000000000
--- a/src/librustc_metadata/tyencode.rs
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Type encoding
-
-#![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter
-#![allow(non_camel_case_types)]
-
-use std::cell::RefCell;
-use std::io::Cursor;
-use std::io::prelude::*;
-
-use rustc::hir::def_id::DefId;
-use middle::region;
-use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::nodemap::FnvHashMap;
-
-use rustc::hir;
-
-use syntax::abi::Abi;
-use syntax::ast;
-use errors::Handler;
-
-use rbml::leb128;
-use encoder;
-
-pub struct ctxt<'a, 'tcx: 'a> {
-    pub diag: &'a Handler,
-    // Def -> str Callback:
-    pub ds: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String,
-    // The type context.
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub abbrevs: &'a abbrev_map<'tcx>
-}
-
-impl<'a, 'tcx> encoder::EncodeContext<'a, 'tcx> {
-    pub fn ty_str_ctxt<'b>(&'b self) -> ctxt<'b, 'tcx> {
-        ctxt {
-            diag: self.tcx.sess.diagnostic(),
-            ds: encoder::def_to_string,
-            tcx: self.tcx,
-            abbrevs: &self.type_abbrevs
-        }
-    }
-}
-
-// Compact string representation for Ty values. API TyStr & parse_from_str.
-// Extra parameters are for converting to/from def_ids in the string rep.
-// Whatever format you choose should not contain pipe characters.
-pub struct ty_abbrev {
-    s: Vec<u8>
-}
-
-pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
-
-pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
-    if let Some(a) = cx.abbrevs.borrow_mut().get(&t) {
-        w.write_all(&a.s);
-        return;
-    }
-
-    let pos = w.position();
-
-    match t.sty {
-        ty::TyBool => { write!(w, "b"); }
-        ty::TyChar => { write!(w, "c"); }
-        ty::TyNever => { write!(w, "!"); }
-        ty::TyInt(t) => {
-            match t {
-                ast::IntTy::Is => write!(w, "is"),
-                ast::IntTy::I8 => write!(w, "MB"),
-                ast::IntTy::I16 => write!(w, "MW"),
-                ast::IntTy::I32 => write!(w, "ML"),
-                ast::IntTy::I64 => write!(w, "MD")
-            };
-        }
-        ty::TyUint(t) => {
-            match t {
-                ast::UintTy::Us => write!(w, "us"),
-                ast::UintTy::U8 => write!(w, "Mb"),
-                ast::UintTy::U16 => write!(w, "Mw"),
-                ast::UintTy::U32 => write!(w, "Ml"),
-                ast::UintTy::U64 => write!(w, "Md")
-            };
-        }
-        ty::TyFloat(t) => {
-            match t {
-                ast::FloatTy::F32 => write!(w, "Mf"),
-                ast::FloatTy::F64 => write!(w, "MF"),
-            };
-        }
-        ty::TyTrait(ref obj) => {
-            write!(w, "x[");
-            enc_existential_trait_ref(w, cx, obj.principal.0);
-            enc_builtin_bounds(w, cx, &obj.builtin_bounds);
-
-            enc_region(w, cx, obj.region_bound);
-
-            for tp in &obj.projection_bounds {
-                write!(w, "P");
-                enc_existential_projection(w, cx, &tp.0);
-            }
-
-            write!(w, ".");
-            write!(w, "]");
-        }
-        ty::TyTuple(ts) => {
-            write!(w, "T[");
-            for t in ts { enc_ty(w, cx, *t); }
-            write!(w, "]");
-        }
-        ty::TyBox(typ) => { write!(w, "~"); enc_ty(w, cx, typ); }
-        ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); }
-        ty::TyRef(r, mt) => {
-            write!(w, "&");
-            enc_region(w, cx, r);
-            enc_mt(w, cx, mt);
-        }
-        ty::TyArray(t, sz) => {
-            write!(w, "V");
-            enc_ty(w, cx, t);
-            write!(w, "/{}|", sz);
-        }
-        ty::TySlice(t) => {
-            write!(w, "V");
-            enc_ty(w, cx, t);
-            write!(w, "/|");
-        }
-        ty::TyStr => {
-            write!(w, "v");
-        }
-        ty::TyFnDef(def_id, substs, f) => {
-            write!(w, "F");
-            write!(w, "{}|", (cx.ds)(cx.tcx, def_id));
-            enc_substs(w, cx, substs);
-            enc_bare_fn_ty(w, cx, f);
-        }
-        ty::TyFnPtr(f) => {
-            write!(w, "G");
-            enc_bare_fn_ty(w, cx, f);
-        }
-        ty::TyInfer(_) => {
-            bug!("cannot encode inference variable types");
-        }
-        ty::TyParam(p) => {
-            write!(w, "p[{}|{}]", p.idx, p.name);
-        }
-        ty::TyAdt(def, substs) => {
-            write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did));
-            enc_substs(w, cx, substs);
-            write!(w, "]");
-        }
-        ty::TyClosure(def, substs) => {
-            write!(w, "k[{}|", (cx.ds)(cx.tcx, def));
-            enc_substs(w, cx, substs.func_substs);
-            for ty in substs.upvar_tys {
-                enc_ty(w, cx, ty);
-            }
-            write!(w, ".");
-            write!(w, "]");
-        }
-        ty::TyProjection(ref data) => {
-            write!(w, "P[");
-            enc_trait_ref(w, cx, data.trait_ref);
-            write!(w, "{}]", data.item_name);
-        }
-        ty::TyAnon(def_id, substs) => {
-            write!(w, "A[{}|", (cx.ds)(cx.tcx, def_id));
-            enc_substs(w, cx, substs);
-            write!(w, "]");
-        }
-        ty::TyError => {
-            write!(w, "e");
-        }
-    }
-
-    let end = w.position();
-    let len = end - pos;
-
-    let mut abbrev = Cursor::new(Vec::with_capacity(16));
-    abbrev.write_all(b"#");
-    {
-        let start_position = abbrev.position() as usize;
-        let bytes_written = leb128::write_unsigned_leb128(abbrev.get_mut(),
-                                                          start_position,
-                                                          pos);
-        abbrev.set_position((start_position + bytes_written) as u64);
-    }
-
-    cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
-        s: if abbrev.position() < len {
-            abbrev.get_ref()[..abbrev.position() as usize].to_owned()
-        } else {
-            // if the abbreviation is longer than the real type,
-            // don't use #-notation. However, insert it here so
-            // other won't have to `mark_stable_position`
-            w.get_ref()[pos as usize .. end as usize].to_owned()
-        }
-    });
-}
-
-fn enc_mutability(w: &mut Cursor<Vec<u8>>, mt: hir::Mutability) {
-    match mt {
-        hir::MutImmutable => (),
-        hir::MutMutable => {
-            write!(w, "m");
-        }
-    };
-}
-
-fn enc_mt<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                    mt: ty::TypeAndMut<'tcx>) {
-    enc_mutability(w, mt.mutbl);
-    enc_ty(w, cx, mt.ty);
-}
-
-fn enc_opt<T, F>(w: &mut Cursor<Vec<u8>>, t: Option<T>, enc_f: F) where
-    F: FnOnce(&mut Cursor<Vec<u8>>, T),
-{
-    match t {
-        None => {
-            write!(w, "n");
-        }
-        Some(v) => {
-            write!(w, "s");
-            enc_f(w, v);
-        }
-    }
-}
-
-pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                            substs: &Substs<'tcx>) {
-    write!(w, "[");
-    for &k in substs.params() {
-        if let Some(ty) = k.as_type() {
-            write!(w, "t");
-            enc_ty(w, cx, ty);
-        } else if let Some(r) = k.as_region() {
-            write!(w, "r");
-            enc_region(w, cx, r);
-        } else {
-            bug!()
-        }
-    }
-    write!(w, "]");
-}
-
-pub fn enc_generics<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                              generics: &ty::Generics<'tcx>) {
-    enc_opt(w, generics.parent, |w, def_id| {
-        write!(w, "{}|", (cx.ds)(cx.tcx, def_id));
-    });
-    write!(w, "{}|{}[",
-           generics.parent_regions,
-           generics.parent_types);
-
-    for r in &generics.regions {
-        enc_region_param_def(w, cx, r)
-    }
-    write!(w, "|");
-    for t in &generics.types {
-        enc_type_param_def(w, cx, t);
-    }
-    write!(w, "]");
-
-    if generics.has_self {
-        write!(w, "S");
-    } else {
-        write!(w, "N");
-    }
-}
-
-pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: &ty::Region) {
-    match *r {
-        ty::ReLateBound(id, br) => {
-            write!(w, "b[{}|", id.depth);
-            enc_bound_region(w, cx, br);
-            write!(w, "]");
-        }
-        ty::ReEarlyBound(ref data) => {
-            write!(w, "B[{}|{}]",
-                   data.index,
-                   data.name);
-        }
-        ty::ReFree(ref fr) => {
-            write!(w, "f[");
-            enc_scope(w, cx, fr.scope);
-            write!(w, "|");
-            enc_bound_region(w, cx, fr.bound_region);
-            write!(w, "]");
-        }
-        ty::ReScope(scope) => {
-            write!(w, "s");
-            enc_scope(w, cx, scope);
-            write!(w, "|");
-        }
-        ty::ReStatic => {
-            write!(w, "t");
-        }
-        ty::ReEmpty => {
-            write!(w, "e");
-        }
-        ty::ReErased => {
-            write!(w, "E");
-        }
-        ty::ReVar(_) | ty::ReSkolemized(..) => {
-            // these should not crop up after typeck
-            bug!("cannot encode region variables");
-        }
-    }
-}
-
-fn enc_scope(w: &mut Cursor<Vec<u8>>, cx: &ctxt, scope: region::CodeExtent) {
-    match cx.tcx.region_maps.code_extent_data(scope) {
-        region::CodeExtentData::CallSiteScope {
-            fn_id, body_id } => write!(w, "C[{}|{}]", fn_id, body_id),
-        region::CodeExtentData::ParameterScope {
-            fn_id, body_id } => write!(w, "P[{}|{}]", fn_id, body_id),
-        region::CodeExtentData::Misc(node_id) => write!(w, "M{}", node_id),
-        region::CodeExtentData::Remainder(region::BlockRemainder {
-            block: b, first_statement_index: i }) => write!(w, "B[{}|{}]", b, i),
-        region::CodeExtentData::DestructionScope(node_id) => write!(w, "D{}", node_id),
-    };
-}
-
-fn enc_bound_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, br: ty::BoundRegion) {
-    match br {
-        ty::BrAnon(idx) => {
-            write!(w, "a{}|", idx);
-        }
-        ty::BrNamed(d, name, issue32330) => {
-            write!(w, "[{}|{}|",
-                   (cx.ds)(cx.tcx, d),
-                   name);
-
-            match issue32330 {
-                ty::Issue32330::WontChange =>
-                    write!(w, "n]"),
-                ty::Issue32330::WillChange { fn_def_id, region_name } =>
-                    write!(w, "y{}|{}]", (cx.ds)(cx.tcx, fn_def_id), region_name),
-            };
-        }
-        ty::BrFresh(id) => {
-            write!(w, "f{}|", id);
-        }
-        ty::BrEnv => {
-            write!(w, "e|");
-        }
-    }
-}
-
-pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                               s: ty::TraitRef<'tcx>) {
-    write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id));
-    enc_substs(w, cx, s.substs);
-}
-
-fn enc_existential_trait_ref<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                                       s: ty::ExistentialTraitRef<'tcx>) {
-    write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id));
-    enc_substs(w, cx, s.substs);
-}
-
-fn enc_unsafety(w: &mut Cursor<Vec<u8>>, p: hir::Unsafety) {
-    match p {
-        hir::Unsafety::Normal => write!(w, "n"),
-        hir::Unsafety::Unsafe => write!(w, "u"),
-    };
-}
-
-fn enc_abi(w: &mut Cursor<Vec<u8>>, abi: Abi) {
-    write!(w, "[");
-    write!(w, "{}", abi.name());
-    write!(w, "]");
-}
-
-pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                                ft: &ty::BareFnTy<'tcx>) {
-    enc_unsafety(w, ft.unsafety);
-    enc_abi(w, ft.abi);
-    enc_fn_sig(w, cx, &ft.sig);
-}
-
-pub fn enc_closure_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                                ft: &ty::ClosureTy<'tcx>) {
-    enc_unsafety(w, ft.unsafety);
-    enc_fn_sig(w, cx, &ft.sig);
-    enc_abi(w, ft.abi);
-}
-
-fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                        fsig: &ty::PolyFnSig<'tcx>) {
-    write!(w, "[");
-    for ty in &fsig.0.inputs {
-        enc_ty(w, cx, *ty);
-    }
-    write!(w, "]");
-    if fsig.0.variadic {
-        write!(w, "V");
-    } else {
-        write!(w, "N");
-    }
-    enc_ty(w, cx, fsig.0.output);
-}
-
-fn enc_builtin_bounds(w: &mut Cursor<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBounds) {
-    for bound in bs {
-        match bound {
-            ty::BoundSend => write!(w, "S"),
-            ty::BoundSized => write!(w, "Z"),
-            ty::BoundCopy => write!(w, "P"),
-            ty::BoundSync => write!(w, "T"),
-        };
-    }
-
-    write!(w, ".");
-}
-
-fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
-                                v: &ty::TypeParameterDef<'tcx>) {
-    write!(w, "{}:{}|{}|{}|",
-           v.name, (cx.ds)(cx.tcx, v.def_id),
-           v.index, (cx.ds)(cx.tcx, v.default_def_id));
-    enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
-    enc_object_lifetime_default(w, cx, v.object_lifetime_default);
-}
-
-fn enc_region_param_def(w: &mut Cursor<Vec<u8>>, cx: &ctxt,
-                        v: &ty::RegionParameterDef) {
-    write!(w, "{}:{}|{}|",
-           v.name, (cx.ds)(cx.tcx, v.def_id), v.index);
-    for &r in &v.bounds {
-        write!(w, "R");
-        enc_region(w, cx, r);
-    }
-    write!(w, ".");
-}
-
-fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
-                                         cx: &ctxt<'a, 'tcx>,
-                                         default: ty::ObjectLifetimeDefault)
-{
-    match default {
-        ty::ObjectLifetimeDefault::Ambiguous => {
-            write!(w, "a");
-        }
-        ty::ObjectLifetimeDefault::BaseDefault => {
-            write!(w, "b");
-        }
-        ty::ObjectLifetimeDefault::Specific(r) => {
-            write!(w, "s");
-            enc_region(w, cx, r);
-        }
-    }
-}
-
-pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
-                               cx: &ctxt<'a, 'tcx>,
-                               p: &ty::Predicate<'tcx>)
-{
-    match *p {
-        ty::Predicate::Trait(ref trait_ref) => {
-            write!(w, "t");
-            enc_trait_ref(w, cx, trait_ref.0.trait_ref);
-        }
-        ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
-            write!(w, "e");
-            enc_ty(w, cx, a);
-            enc_ty(w, cx, b);
-        }
-        ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
-            write!(w, "r");
-            enc_region(w, cx, a);
-            enc_region(w, cx, b);
-        }
-        ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
-            write!(w, "o");
-            enc_ty(w, cx, a);
-            enc_region(w, cx, b);
-        }
-        ty::Predicate::Projection(ty::Binder(ref data)) => {
-            write!(w, "p");
-            enc_trait_ref(w, cx, data.projection_ty.trait_ref);
-            write!(w, "{}|", data.projection_ty.item_name);
-            enc_ty(w, cx, data.ty);
-        }
-        ty::Predicate::WellFormed(data) => {
-            write!(w, "w");
-            enc_ty(w, cx, data);
-        }
-        ty::Predicate::ObjectSafe(trait_def_id) => {
-            write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id));
-        }
-        ty::Predicate::ClosureKind(closure_def_id, kind) => {
-            let kind_char = match kind {
-                ty::ClosureKind::Fn => 'f',
-                ty::ClosureKind::FnMut => 'm',
-                ty::ClosureKind::FnOnce => 'o',
-            };
-            write!(w, "c{}|{}|", (cx.ds)(cx.tcx, closure_def_id), kind_char);
-        }
-    }
-}
-
-fn enc_existential_projection<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
-                                        cx: &ctxt<'a, 'tcx>,
-                                        data: &ty::ExistentialProjection<'tcx>) {
-    enc_existential_trait_ref(w, cx, data.trait_ref);
-    write!(w, "{}|", data.item_name);
-    enc_ty(w, cx, data.ty);
-}
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 59d6cf11859..23591f05b87 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -197,8 +197,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     // Gather the upvars of a closure, if any.
     let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
         freevars.iter().map(|fv| {
+            let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap();
             let by_ref = tcx.upvar_capture(ty::UpvarId {
-                var_id: fv.def.var_id(),
+                var_id: var_id,
                 closure_expr_id: fn_id
             }).map_or(false, |capture| match capture {
                 ty::UpvarCapture::ByValue => false,
@@ -208,7 +209,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                 debug_name: keywords::Invalid.name(),
                 by_ref: by_ref
             };
-            if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) {
+            if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(var_id) {
                 if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
                     decl.debug_name = ident.node;
                 }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 4518f8cb373..6283ff2187a 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -271,7 +271,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     // Tuple-like ADTs are represented as ExprCall. We convert them here.
                     expr_ty.ty_adt_def().and_then(|adt_def|{
                         match cx.tcx.expect_def(fun.id) {
-                            Def::Variant(_, variant_id) => {
+                            Def::Variant(variant_id) => {
                                 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
                             },
                             Def::Struct(..) => {
@@ -480,8 +480,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     }
                     AdtKind::Enum => {
                         match cx.tcx.expect_def(expr.id) {
-                            Def::Variant(enum_id, variant_id) => {
-                                debug_assert!(adt.did == enum_id);
+                            Def::Variant(variant_id) => {
                                 assert!(base.is_none());
 
                                 let index = adt.variant_index_with_id(variant_id);
@@ -688,13 +687,12 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             },
             ref sty => bug!("unexpected sty: {:?}", sty)
         },
-        Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
+        Def::Variant(variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
             // A variant constructor. Should only be reached if not called in the same
             // expression.
             ty::TyFnDef(..) => variant_id,
             // A unit variant, similar special case to the struct case above.
             ty::TyAdt(adt_def, substs) => {
-                debug_assert!(adt_def.did == enum_id);
                 let index = adt_def.variant_index_with_id(variant_id);
                 return ExprKind::Adt {
                     adt_def: adt_def,
@@ -729,13 +727,15 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
     match def {
-        Def::Local(_, node_id) => {
+        Def::Local(def_id) => {
+            let node_id = cx.tcx.map.as_local_node_id(def_id).unwrap();
             ExprKind::VarRef {
                 id: node_id,
             }
         }
 
-        Def::Upvar(_, id_var, index, closure_expr_id) => {
+        Def::Upvar(def_id, index, closure_expr_id) => {
+            let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap();
             debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
             let var_ty = cx.tcx.node_id_to_type(id_var);
 
@@ -974,7 +974,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    freevar: &hir::Freevar,
                                    freevar_ty: Ty<'tcx>)
                                    -> ExprRef<'tcx> {
-    let id_var = freevar.def.var_id();
+    let id_var = cx.tcx.map.as_local_node_id(freevar.def.def_id()).unwrap();
     let upvar_id = ty::UpvarId {
         var_id: id_var,
         closure_expr_id: closure_expr.id,
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 3639b165eb5..7b8446b184f 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -158,7 +158,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
             }
 
             PatKind::Binding(bm, ref ident, ref sub) => {
-                let id = self.cx.tcx.expect_def(pat.id).var_id();
+                let def_id = self.cx.tcx.expect_def(pat.id).def_id();
+                let id = self.cx.tcx.map.as_local_node_id(def_id).unwrap();
                 let var_ty = self.cx.tcx.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
                     ty::TyRef(r, _) => Some(r),
@@ -300,7 +301,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                        subpatterns: Vec<FieldPattern<'tcx>>)
                        -> PatternKind<'tcx> {
         match self.cx.tcx.expect_def(pat.id) {
-            Def::Variant(enum_id, variant_id) => {
+            Def::Variant(variant_id) => {
+                let enum_id = self.cx.tcx.parent_def_id(variant_id).unwrap();
                 let adt_def = self.cx.tcx.lookup_adt_def(enum_id);
                 if adt_def.variants.len() > 1 {
                     PatternKind::Variant {
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 412759cd5b2..7b6a2f55808 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -20,6 +20,7 @@ use rustc::mir::tcx::LvalueTy;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
 use rustc::mir::visit::{self, Visitor};
 use std::fmt;
+use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -674,7 +675,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         where T: fmt::Debug + TypeFoldable<'tcx>
     {
         let mut selcx = traits::SelectionContext::new(self.infcx);
-        let cause = traits::ObligationCause::misc(self.last_span, 0);
+        let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
         let traits::Normalized { value, obligations } =
             traits::normalize(&mut selcx, cause, value);
 
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index d23f77af321..0ab8e2d7fcd 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -272,15 +272,13 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
                     // affect the specific variant used, but we need to check
                     // the whole enum definition to see what expression that
                     // might be (if any).
-                    Some(Def::Variant(enum_id, variant_id)) => {
-                        if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
-                            if let hir::ItemEnum(ref enum_def, ref generics) = self.ast_map
-                                .expect_item(enum_node_id)
-                                .node {
+                    Some(Def::Variant(variant_id)) => {
+                        if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) {
+                            let variant = self.ast_map.expect_variant(variant_id);
+                            let enum_id = self.ast_map.get_parent(variant_id);
+                            let enum_item = self.ast_map.expect_item(enum_id);
+                            if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node {
                                 self.populate_enum_discriminants(enum_def);
-                                let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
-                                let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
-                                let variant = self.ast_map.expect_variant(variant_id);
                                 self.visit_variant(variant, generics, enum_id);
                             } else {
                                 span_bug!(e.span,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 4012c1cb348..1b119fd0085 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -323,8 +323,13 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
             let def = self.ev.tcx.expect_def(ty.id);
             match def {
                 Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
-                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
-                    if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
+                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => {
+                    if let Some(mut node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
+                        // Check the trait for associated types.
+                        if let hir::map::NodeTraitItem(_) = self.ev.tcx.map.get(node_id) {
+                            node_id = self.ev.tcx.map.get_parent(node_id);
+                        }
+
                         let item = self.ev.tcx.map.expect_item(node_id);
                         if let Def::TyAlias(..) = def {
                             // Type aliases are substituted. Associated type aliases are not
@@ -947,9 +952,14 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
                     return
                 }
                 Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
-                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
+                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => {
                     // Non-local means public (private items can't leave their crate, modulo bugs)
-                    if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+                    if let Some(mut node_id) = self.tcx.map.as_local_node_id(def_id) {
+                        // Check the trait for associated types.
+                        if let hir::map::NodeTraitItem(_) = self.tcx.map.get(node_id) {
+                            node_id = self.tcx.map.get_parent(node_id);
+                        }
+
                         let item = self.tcx.map.expect_item(node_id);
                         let vis = match self.substituted_alias_visibility(item, path) {
                             Some(vis) => vis,
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 83f03e7cfc5..c9591c31831 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -21,10 +21,10 @@ use ParentLink::{ModuleParentLink, BlockParentLink};
 use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
-use rustc::middle::cstore::{ChildItem, DlDef};
 use rustc::hir::def::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::ty::{self, VariantKind};
+use rustc::hir::map::DefPathData;
+use rustc::ty;
 
 use std::cell::Cell;
 
@@ -201,7 +201,7 @@ impl<'b> Resolver<'b> {
                     let module = self.new_extern_crate_module(parent_link, def, item.id);
                     self.define(parent, name, TypeNS, (module, sp, vis));
 
-                    self.build_reduced_graph_for_external_crate(module);
+                    self.populate_module_if_necessary(module);
                 }
             }
 
@@ -250,8 +250,7 @@ impl<'b> Resolver<'b> {
                 self.define(parent, name, TypeNS, (module, sp, vis));
 
                 for variant in &(*enum_definition).variants {
-                    let item_def_id = self.definitions.local_def_id(item.id);
-                    self.build_reduced_graph_for_variant(variant, item_def_id, module, vis);
+                    self.build_reduced_graph_for_variant(variant, module, vis);
                 }
             }
 
@@ -314,7 +313,7 @@ impl<'b> Resolver<'b> {
                             is_static_method = !sig.decl.has_self();
                             (Def::Method(item_def_id), ValueNS)
                         }
-                        TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS),
+                        TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
                         TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
                     };
 
@@ -334,7 +333,6 @@ impl<'b> Resolver<'b> {
     // type and value namespaces.
     fn build_reduced_graph_for_variant(&mut self,
                                        variant: &Variant,
-                                       item_id: DefId,
                                        parent: Module<'b>,
                                        vis: ty::Visibility) {
         let name = variant.node.name.name;
@@ -346,7 +344,7 @@ impl<'b> Resolver<'b> {
 
         // Variants are always treated as importable to allow them to be glob used.
         // All variants are defined in both type and value namespaces as future-proofing.
-        let def = Def::Variant(item_id, self.definitions.local_def_id(variant.node.data.id()));
+        let def = Def::Variant(self.definitions.local_def_id(variant.node.data.id()));
         self.define(parent, name, ValueNS, (def, variant.span, vis));
         self.define(parent, name, TypeNS, (def, variant.span, vis));
     }
@@ -388,38 +386,38 @@ impl<'b> Resolver<'b> {
     }
 
     /// Builds the reduced graph for a single item in an external crate.
-    fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcdef: ChildItem) {
-        let def = match xcdef.def {
-            DlDef(def) => def,
-            _ => return,
-        };
-
-        if let Def::ForeignMod(def_id) = def {
-            // Foreign modules have no names. Recur and populate eagerly.
-            for child in self.session.cstore.item_children(def_id) {
-                self.build_reduced_graph_for_external_crate_def(parent, child);
-            }
+    fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>,
+                                                  child: Export) {
+        let def_id = child.def_id;
+        let name = child.name;
+
+        let def = if let Some(def) = self.session.cstore.describe_def(def_id) {
+            def
+        } else {
             return;
-        }
+        };
 
-        let name = xcdef.name;
-        let vis = if parent.is_trait() { ty::Visibility::Public } else { xcdef.vis };
+        let vis = if parent.is_trait() {
+            ty::Visibility::Public
+        } else {
+            self.session.cstore.visibility(def_id)
+        };
 
         match def {
-            Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => {
+            Def::Mod(_) | Def::Enum(..) => {
                 debug!("(building reduced graph for external crate) building module {} {:?}",
                        name, vis);
                 let parent_link = ModuleParentLink(parent, name);
                 let module = self.new_module(parent_link, Some(def), None);
                 let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
             }
-            Def::Variant(_, variant_id) => {
+            Def::Variant(variant_id) => {
                 debug!("(building reduced graph for external crate) building variant {}", name);
                 // Variants are always treated as importable to allow them to be glob used.
                 // All variants are defined in both type and value namespaces as future-proofing.
                 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
                 let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis));
-                if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
+                if self.session.cstore.variant_kind(variant_id) == Some(ty::VariantKind::Struct) {
                     // Not adding fields for variants as they are not accessed with a self receiver
                     self.structs.insert(variant_id, Vec::new());
                 }
@@ -433,16 +431,18 @@ impl<'b> Resolver<'b> {
                        name);
                 let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis));
             }
-            Def::Trait(def_id) => {
+            Def::Trait(_) => {
                 debug!("(building reduced graph for external crate) building type {}", name);
 
                 // If this is a trait, add all the trait item names to the trait
                 // info.
 
-                let trait_item_def_ids = self.session.cstore.trait_item_def_ids(def_id);
-                for trait_item_def in &trait_item_def_ids {
+                let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id);
+                for &trait_item_def in &trait_item_def_ids {
                     let trait_item_name =
-                        self.session.cstore.item_name(trait_item_def.def_id());
+                        self.session.cstore.def_key(trait_item_def)
+                            .disambiguated_data.data.get_opt_name()
+                            .expect("opt_item_name returned None for trait");
 
                     debug!("(building reduced graph for external crate) ... adding trait item \
                             '{}'",
@@ -459,8 +459,10 @@ impl<'b> Resolver<'b> {
                 debug!("(building reduced graph for external crate) building type {}", name);
                 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
             }
-            Def::Struct(def_id)
-                if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => {
+            Def::Struct(_)
+                if self.session.cstore.def_key(def_id).disambiguated_data.data !=
+                   DefPathData::StructCtor
+                => {
                 debug!("(building reduced graph for external crate) building type and value for {}",
                        name);
                 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
@@ -473,7 +475,7 @@ impl<'b> Resolver<'b> {
                 let fields = self.session.cstore.struct_field_names(def_id);
                 self.structs.insert(def_id, fields);
             }
-            Def::Union(def_id) => {
+            Def::Union(_) => {
                 let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
 
                 // Record the def ID and fields of this union.
@@ -493,15 +495,6 @@ impl<'b> Resolver<'b> {
         }
     }
 
-    /// Builds the reduced graph rooted at the 'use' directive for an external
-    /// crate.
-    fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
-        let root_cnum = root.def_id().unwrap().krate;
-        for child in self.session.cstore.crate_top_level_items(root_cnum) {
-            self.build_reduced_graph_for_external_crate_def(root, child);
-        }
-    }
-
     /// Ensures that the reduced graph rooted at the given external module
     /// is built, building it if it is not.
     pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 912b39cafff..016b621eabd 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -49,14 +49,14 @@ use rustc::middle::cstore::MacroLoader;
 use rustc::session::Session;
 use rustc::lint;
 use rustc::hir::def::*;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty;
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
 
 use syntax::ext::hygiene::Mark;
 use syntax::ast::{self, FloatTy};
-use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
+use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
 use syntax::parse::token::{self, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 
@@ -1151,8 +1151,8 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
         self.def_map.insert(id, PathResolution::new(def));
     }
 
-    fn definitions(&mut self) -> Option<&mut Definitions> {
-        Some(&mut self.definitions)
+    fn definitions(&mut self) -> &mut Definitions {
+        &mut self.definitions
     }
 }
 
@@ -1275,6 +1275,7 @@ impl<'a> Resolver<'a> {
                                -> Module<'a> {
         let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id));
         module.extern_crate_id = Some(local_node_id);
+        module.populated.set(false);
         self.arenas.modules.alloc(module)
     }
 
@@ -1959,7 +1960,8 @@ impl<'a> Resolver<'a> {
                 // Resolve the self type.
                 this.visit_ty(self_type);
 
-                this.with_self_rib(Def::SelfTy(trait_id, Some(item_id)), |this| {
+                let item_def_id = this.definitions.local_def_id(item_id);
+                this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| {
                     this.with_current_self_type(self_type, |this| {
                         for impl_item in impl_items {
                             this.resolve_visibility(&impl_item.vis);
@@ -2243,7 +2245,7 @@ impl<'a> Resolver<'a> {
         // must not add it if it's in the bindings map
         // because that breaks the assumptions later
         // passes make about or-patterns.)
-        let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
+        let mut def = Def::Local(self.definitions.local_def_id(pat_id));
         match bindings.get(&ident.node).cloned() {
             Some(id) if id == outer_pat_id => {
                 // `Variant(a, a)`, error
@@ -2559,7 +2561,7 @@ impl<'a> Resolver<'a> {
             Def::Upvar(..) => {
                 span_bug!(span, "unexpected {:?} in bindings", def)
             }
-            Def::Local(_, node_id) => {
+            Def::Local(def_id) => {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
@@ -2567,13 +2569,13 @@ impl<'a> Resolver<'a> {
                         }
                         ClosureRibKind(function_id) => {
                             let prev_def = def;
-                            let node_def_id = self.definitions.local_def_id(node_id);
+                            let node_id = self.definitions.as_local_node_id(def_id).unwrap();
 
                             let seen = self.freevars_seen
                                            .entry(function_id)
                                            .or_insert_with(|| NodeMap());
                             if let Some(&index) = seen.get(&node_id) {
-                                def = Def::Upvar(node_def_id, node_id, index, function_id);
+                                def = Def::Upvar(def_id, index, function_id);
                                 continue;
                             }
                             let vec = self.freevars
@@ -2585,7 +2587,7 @@ impl<'a> Resolver<'a> {
                                 span: span,
                             });
 
-                            def = Def::Upvar(node_def_id, node_id, depth, function_id);
+                            def = Def::Upvar(def_id, depth, function_id);
                             seen.insert(node_id, depth);
                         }
                         ItemRibKind | MethodRibKind(_) => {
@@ -2755,7 +2757,7 @@ impl<'a> Resolver<'a> {
             if let Some(resolution) = self.def_map.get(&node_id) {
                 match resolution.base_def {
                     Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) |
-                    Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => {
+                    Def::Struct(did) | Def::Variant(did) if resolution.depth == 0 => {
                         if let Some(fields) = self.structs.get(&did) {
                             if fields.iter().any(|&field_name| name == field_name) {
                                 return Field;
@@ -2824,7 +2826,7 @@ impl<'a> Resolver<'a> {
                 if let Some(path_res) = self.resolve_possibly_assoc_item(expr.id,
                                                             maybe_qself.as_ref(), path, ValueNS) {
                     // Check if struct variant
-                    let is_struct_variant = if let Def::Variant(_, variant_id) = path_res.base_def {
+                    let is_struct_variant = if let Def::Variant(variant_id) = path_res.base_def {
                         self.structs.contains_key(&variant_id)
                     } else {
                         false
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 67ee4c307d3..e452a44cea5 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -135,7 +135,7 @@ struct ExpansionVisitor<'b, 'a: 'b> {
 
 impl<'a, 'b> ExpansionVisitor<'a, 'b> {
     fn visit_invoc(&mut self, id: ast::NodeId) {
-        assert_eq!(id, self.resolver.expansion_data.len() as u32);
+        assert_eq!(id.as_u32(), self.resolver.expansion_data.len() as u32);
         self.resolver.expansion_data.push(ExpansionData {
             module: self.current_module.clone(),
         });
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index 4e03ea4218f..fc235aaf927 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -14,8 +14,8 @@
 //! retrieve the data from a crate.
 
 use rustc::hir;
-use rustc::hir::def_id::DefId;
-use syntax::ast::{self, CrateNum, NodeId};
+use rustc::hir::def_id::{CrateNum, DefId};
+use syntax::ast::{self, NodeId};
 use syntax_pos::Span;
 
 pub struct CrateData {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 8820f3616d5..79fcff7d8a1 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -29,7 +29,7 @@
 
 use rustc::hir;
 use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir::map::{Node, NodeItem};
 use rustc::session::Session;
 use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer};
@@ -37,7 +37,7 @@ use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer};
 use std::collections::HashSet;
 use std::hash::*;
 
-use syntax::ast::{self, NodeId, PatKind, Attribute};
+use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
 use syntax::parse::token::{self, keywords};
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
@@ -95,7 +95,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             analysis: analysis,
             dumper: dumper,
             span: span_utils.clone(),
-            cur_scope: 0,
+            cur_scope: CRATE_NODE_ID,
             mac_defs: HashSet::new(),
             mac_uses: HashSet::new(),
         }
@@ -124,7 +124,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo);
             ExternalCrateData {
                 name: c.name,
-                num: c.number,
+                num: CrateNum::from_u32(c.number),
                 file_name: SpanUtils::make_path_string(&lo_loc.file.name),
             }
         }).collect();
@@ -252,7 +252,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             ref_id: None,
             span: *span,
             qualname: qualname.to_owned(),
-            scope: 0
+            scope: CRATE_NODE_ID
         }.lower(self.tcx));
 
         // write the other sub-paths
@@ -293,8 +293,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
         let def = self.tcx.expect_def(ref_id);
         match def {
-            Def::Mod(_) |
-            Def::ForeignMod(_) => {
+            Def::Mod(_) => {
                 self.dumper.mod_ref(ModRefData {
                     span: sub_span.expect("No span found for mod ref"),
                     ref_id: Some(def_id),
@@ -368,7 +367,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         qualname: format!("{}::{}", qualname, path_to_string(p)),
                         type_value: typ,
                         value: String::new(),
-                        scope: 0,
+                        scope: CRATE_NODE_ID,
                         parent: None,
                         visibility: Visibility::Inherited,
                         docs: String::new(),
@@ -1044,7 +1043,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     qualname: format!("{}${}", path_to_string(p), id),
                     value: value,
                     type_value: typ,
-                    scope: 0,
+                    scope: CRATE_NODE_ID,
                     parent: None,
                     visibility: Visibility::Inherited,
                     docs: String::new(),
@@ -1239,7 +1238,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 let alias_span = self.span.span_for_last_ident(item.span);
                 let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) {
                     Some(cnum) => cnum,
-                    None => 0,
+                    None => LOCAL_CRATE,
                 };
 
                 if !self.span.filter_generated(alias_span, item.span) {
@@ -1456,7 +1455,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
         // process collected paths
         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
             match self.tcx.expect_def(id) {
-                Def::Local(_, id) => {
+                Def::Local(def_id) => {
+                    let id = self.tcx.map.as_local_node_id(def_id).unwrap();
                     let mut value = if immut == ast::Mutability::Immutable {
                         self.span.snippet(p.span).to_string()
                     } else {
@@ -1478,7 +1478,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                             qualname: format!("{}${}", path_to_string(p), id),
                             value: value,
                             type_value: typ,
-                            scope: 0,
+                            scope: CRATE_NODE_ID,
                             parent: None,
                             visibility: Visibility::Inherited,
                             docs: String::new(),
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index 32280a5c926..58475757423 100644
--- a/src/librustc_save_analysis/external_data.rs
+++ b/src/librustc_save_analysis/external_data.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir::def_id::{DefId, DefIndex};
+use rustc::hir::def_id::{CrateNum, DefId, DefIndex};
 use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
-use syntax::ast::{CrateNum, NodeId};
+use syntax::ast::NodeId;
 use syntax::codemap::CodeMap;
 use syntax_pos::Span;
 
@@ -28,7 +28,10 @@ pub fn make_def_id(id: NodeId, map: &Map) -> DefId {
 }
 
 pub fn null_def_id() -> DefId {
-    DefId { krate: u32::max_value(), index: DefIndex::from_u32(u32::max_value()) }
+    DefId {
+        krate: CrateNum::from_u32(u32::max_value()),
+        index: DefIndex::from_u32(u32::max_value())
+    }
 }
 
 #[derive(Clone, Debug, RustcEncodable)]
diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs
index 78eaa65872a..d56aae18a7c 100644
--- a/src/librustc_save_analysis/json_api_dumper.rs
+++ b/src/librustc_save_analysis/json_api_dumper.rs
@@ -117,7 +117,7 @@ struct Id {
 impl From<DefId> for Id {
     fn from(id: DefId) -> Id {
         Id {
-            krate: id.krate,
+            krate: id.krate.as_u32(),
             index: id.index.as_u32(),
         }
     }
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index 75abff8d37e..0378d75cc6e 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -120,7 +120,7 @@ struct Id {
 impl From<DefId> for Id {
     fn from(id: DefId) -> Id {
         Id {
-            krate: id.krate,
+            krate: id.krate.as_u32(),
             index: id.index.as_u32(),
         }
     }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 51274068b26..aa68a873120 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -52,7 +52,7 @@ use std::env;
 use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 
-use syntax::ast::{self, NodeId, PatKind, Attribute};
+use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
 use syntax::parse::lexer::comments::strip_doc_comment_decoration;
 use syntax::parse::token::{self, keywords, InternedString};
 use syntax::visit::{self, Visitor};
@@ -120,7 +120,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             };
             result.push(CrateData {
                 name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(),
-                number: n,
+                number: n.as_u32(),
                 span: span,
             });
         }
@@ -374,8 +374,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let qualname = format!("{}::{}", qualname, name);
 
         let def_id = self.tcx.map.local_def_id(id);
-        let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| {
-            let new_def_id = new_id.def_id();
+        let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_def_id| {
             if new_def_id != def_id {
                 Some(new_def_id)
             } else {
@@ -543,16 +542,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                 .map(|mr| mr.def_id())
                         }
                         ty::ImplContainer(def_id) => {
-                            let impl_items = self.tcx.impl_items.borrow();
-                            Some(impl_items.get(&def_id)
-                                           .unwrap()
-                                           .iter()
-                                           .find(|mr| {
-                                               self.tcx.impl_or_trait_item(mr.def_id()).name() ==
-                                               ti.name()
-                                           })
-                                           .unwrap()
-                                           .def_id())
+                            Some(*self.tcx.impl_or_trait_items(def_id).iter().find(|&&mr| {
+                                self.tcx.impl_or_trait_item(mr).name() == ti.name()
+                            }).unwrap())
                         }
                     }
                 } else {
@@ -676,7 +668,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     #[inline]
     pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
-        self.tcx.map.get_enclosing_scope(id).unwrap_or(0)
+        self.tcx.map.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID)
     }
 }
 
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 0fd208c95d4..fdbee50992d 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -557,9 +557,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp
 
     let attempts;
     match hint {
-        attr::ReprInt(span, ity) => {
+        attr::ReprInt(ity) => {
             if !bounds_usable(cx, ity, bounds) {
-                span_bug!(span, "representation hint insufficient for discriminant range")
+                bug!("representation hint insufficient for discriminant range")
             }
             return ity;
         }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 288249a7d99..201e1e5f2ec 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -26,6 +26,7 @@ use CrateTranslation;
 use util::common::time;
 use util::fs::fix_windows_verbatim_for_gcc;
 use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::CrateNum;
 use rustc::hir::svh::Svh;
 use rustc_back::tempdir::TempDir;
 use rustc_incremental::IncrementalHashesMap;
@@ -288,7 +289,7 @@ pub fn filename_for_input(sess: &Session,
 }
 
 pub fn each_linked_rlib(sess: &Session,
-                        f: &mut FnMut(ast::CrateNum, &Path)) {
+                        f: &mut FnMut(CrateNum, &Path)) {
     let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter();
     let fmts = sess.dependency_formats.borrow();
     let fmts = fmts.get(&config::CrateTypeExecutable)
@@ -299,7 +300,7 @@ pub fn each_linked_rlib(sess: &Session,
         bug!("could not find formats for rlibs")
     });
     for (cnum, path) in crates {
-        match fmts[cnum as usize - 1] {
+        match fmts[cnum.as_usize() - 1] {
             Linkage::NotLinked | Linkage::IncludedFromDylib => continue,
             _ => {}
         }
@@ -933,7 +934,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
         // appear statically in an existing dylib, meaning we'll pick up all the
         // symbols from the dylib.
         let src = sess.cstore.used_crate_source(cnum);
-        match data[cnum as usize - 1] {
+        match data[cnum.as_usize() - 1] {
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
             _ if sess.cstore.is_compiler_builtins(cnum) => {
@@ -1003,7 +1004,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                         sess: &Session,
                         tmpdir: &Path,
                         crate_type: config::CrateType,
-                        cnum: ast::CrateNum) {
+                        cnum: CrateNum) {
         let src = sess.cstore.used_crate_source(cnum);
         let cratepath = &src.rlib.unwrap().0;
         if !sess.lto() && crate_type != config::CrateTypeDylib {
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 58cad5c117f..dd14f98c920 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -21,10 +21,10 @@ use monomorphize::Instance;
 
 use back::archive;
 use middle::dependency_format::Linkage;
+use rustc::hir::def_id::CrateNum;
 use session::Session;
 use session::config::CrateType;
 use session::config;
-use syntax::ast;
 
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
@@ -473,7 +473,7 @@ fn exported_symbols(scx: &SharedCrateContext,
     let deps = formats[&crate_type].iter();
     symbols.extend(deps.enumerate().filter_map(|(i, f)| {
         if *f == Linkage::Static {
-            Some((i + 1) as ast::CrateNum)
+            Some(CrateNum::new(i + 1))
         } else {
             None
         }
diff --git a/src/librustc_back/rpath.rs b/src/librustc_trans/back/rpath.rs
index 6cba27fcf34..4ed860bd40d 100644
--- a/src/librustc_back/rpath.rs
+++ b/src/librustc_trans/back/rpath.rs
@@ -12,10 +12,11 @@ use std::collections::HashSet;
 use std::env;
 use std::path::{Path, PathBuf};
 use std::fs;
-use syntax::ast;
+
+use rustc::hir::def_id::CrateNum;
 
 pub struct RPathConfig<'a> {
-    pub used_crates: Vec<(ast::CrateNum, Option<PathBuf>)>,
+    pub used_crates: Vec<(CrateNum, Option<PathBuf>)>,
     pub out_filename: PathBuf,
     pub is_like_osx: bool,
     pub has_rpath: bool,
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 76d83eee4bb..0a668db0690 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -97,14 +97,15 @@
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use common::{CrateContext, SharedCrateContext, gensym_name};
+use common::SharedCrateContext;
 use monomorphize::Instance;
 use util::sha2::{Digest, Sha256};
 
-use rustc::middle::{cstore, weak_lang_items};
-use rustc::hir::def_id::DefId;
+use rustc::middle::weak_lang_items;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::hir::map as hir_map;
-use rustc::ty::{Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::fold::TypeVisitor;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::subst::Substs;
 use rustc::hir::map::definitions::{DefPath, DefPathData};
@@ -114,9 +115,18 @@ use syntax::attr;
 use syntax::parse::token::{self, InternedString};
 use serialize::hex::ToHex;
 
-pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> String {
-    let def_path = tcx.def_path(def_id);
-    def_path.to_string(tcx)
+use std::hash::Hasher;
+
+struct Sha256Hasher<'a>(&'a mut Sha256);
+
+impl<'a> Hasher for Sha256Hasher<'a> {
+    fn write(&mut self, msg: &[u8]) {
+        self.0.input(msg)
+    }
+
+    fn finish(&self) -> u64 {
+        bug!("Sha256Hasher::finish should not be called");
+    }
 }
 
 fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
@@ -132,53 +142,46 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
                              // values for generic type parameters,
                              // if any.
-                             substs: Option<&Substs<'tcx>>)
+                             substs: Option<&'tcx Substs<'tcx>>)
                              -> String {
     debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
            def_path, substs);
 
     let tcx = scx.tcx();
 
-    return record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
-        let mut hash_state = scx.symbol_hasher().borrow_mut();
-
+    let mut hash_state = scx.symbol_hasher().borrow_mut();
+    record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
         hash_state.reset();
+        let mut hasher = Sha256Hasher(&mut hash_state);
 
         // the main symbol name is not necessarily unique; hash in the
         // compiler's internal def-path, guaranteeing each symbol has a
         // truly unique path
-        hash_state.input_str(&def_path.to_string(tcx));
+        def_path.deterministic_hash_to(tcx, &mut hasher);
 
         // Include the main item-type. Note that, in this case, the
         // assertions about `needs_subst` may not hold, but this item-type
         // ought to be the same for every reference anyway.
+        let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
         assert!(!item_type.has_erasable_regions());
-        let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string);
-        hash_state.input(&encoded_item_type[..]);
+        hasher.visit_ty(item_type);
 
         // also include any type parameters (for generic items)
         if let Some(substs) = substs {
-            for t in substs.types() {
-                assert!(!t.has_erasable_regions());
-                assert!(!t.needs_subst());
-                let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
-                hash_state.input(&encoded_type[..]);
-            }
+            assert!(!substs.has_erasable_regions());
+            assert!(!substs.needs_subst());
+            substs.visit_with(&mut hasher);
         }
-
-        format!("h{}", truncated_hash_result(&mut *hash_state))
     });
 
-    fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
-        let output = symbol_hasher.result_bytes();
-        // 64 bits should be enough to avoid collisions.
-        output[.. 8].to_hex()
-    }
+    // 64 bits should be enough to avoid collisions.
+    let output = hash_state.result_bytes();
+    format!("h{}", output[..8].to_hex())
 }
 
 impl<'a, 'tcx> Instance<'tcx> {
     pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
-        let Instance { def: def_id, ref substs } = self;
+        let Instance { def: def_id, substs } = self;
 
         debug!("symbol_name(def_id={:?}, substs={:?})",
                def_id, substs);
@@ -273,7 +276,7 @@ impl<'a, 'tcx> Instance<'tcx> {
             scx.tcx().push_item_path(&mut buffer, def_id);
         });
 
-        mangle(buffer.names.into_iter(), Some(&hash[..]))
+        mangle(buffer.names.into_iter(), &hash)
     }
 }
 
@@ -298,27 +301,11 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
                                                     -> String {
     let empty_def_path = DefPath {
         data: vec![],
-        krate: cstore::LOCAL_CRATE,
+        krate: LOCAL_CRATE,
     };
     let hash = get_symbol_hash(scx, &empty_def_path, t, None);
     let path = [token::intern_and_get_ident(prefix)];
-    mangle(path.iter().cloned(), Some(&hash[..]))
-}
-
-/// Only symbols that are invisible outside their compilation unit should use a
-/// name generated by this function.
-pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                                    t: Ty<'tcx>,
-                                                    suffix: &str)
-                                                    -> String {
-    let path = [token::intern(&t.to_string()).as_str(),
-                gensym_name(suffix).as_str()];
-    let def_path = DefPath {
-        data: vec![],
-        krate: cstore::LOCAL_CRATE,
-    };
-    let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
-    mangle(path.iter().cloned(), Some(&hash[..]))
+    mangle(path.iter().cloned(), &hash)
 }
 
 // Name sanitation. LLVM will happily accept identifiers with weird names, but
@@ -371,7 +358,7 @@ pub fn sanitize(s: &str) -> String {
     return result;
 }
 
-pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
+fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
     // Follow C++ namespace-mangling style, see
     // http://en.wikipedia.org/wiki/Name_mangling for more info.
     //
@@ -398,9 +385,7 @@ pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -
         push(&mut n, &data);
     }
 
-    if let Some(s) = hash {
-        push(&mut n, s)
-    }
+    push(&mut n, hash);
 
     n.push('E'); // End name-sequence.
     n
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 2c3880d21ad..1e05b31eead 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1346,8 +1346,7 @@ fn write_metadata(cx: &SharedCrateContext,
                                           cx.export_map(),
                                           cx.link_meta(),
                                           reachable_ids,
-                                          cx.mir_map(),
-                                          cx.tcx().map.krate());
+                                          cx.mir_map());
     let mut compressed = cstore.metadata_encoding_version().to_vec();
     compressed.extend_from_slice(&flate::deflate_bytes(&metadata));
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 9785ee24557..8822287a0e7 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -17,7 +17,6 @@
 pub use self::CalleeData::*;
 
 use arena::TypedArena;
-use back::symbol_names;
 use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
@@ -133,26 +132,25 @@ impl<'tcx> Callee<'tcx> {
         let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
         match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
             traits::VtableImpl(vtable_impl) => {
-                let impl_did = vtable_impl.impl_def_id;
-                let mname = tcx.item_name(def_id);
-                // create a concatenated set of substitutions which includes
-                // those from the impl and those from the method:
-                let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
+                let name = tcx.item_name(def_id);
+                let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
 
                 // Translate the function, bypassing Callee::def.
                 // That is because default methods have the same ID as the
                 // trait method used to look up the impl method that ended
                 // up here, so calling Callee::def would infinitely recurse.
-                let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
+                let (llfn, ty) = get_fn(ccx, def_id, substs);
                 Callee::ptr(llfn, ty)
             }
             traits::VtableClosure(vtable_closure) => {
                 // The substitutions should have no type parameters remaining
                 // after passing through fulfill_obligation
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
+                let instance = Instance::new(def_id, substs);
                 let llfn = closure::trans_closure_method(ccx,
                                                          vtable_closure.closure_def_id,
                                                          vtable_closure.substs,
+                                                         instance,
                                                          trait_closure_kind);
 
                 let method_ty = def_ty(ccx.shared(), def_id, substs);
@@ -160,7 +158,10 @@ impl<'tcx> Callee<'tcx> {
             }
             traits::VtableFnPointer(vtable_fn_pointer) => {
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
-                let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
+                let instance = Instance::new(def_id, substs);
+                let llfn = trans_fn_pointer_shim(ccx, instance,
+                                                 trait_closure_kind,
+                                                 vtable_fn_pointer.fn_ty);
 
                 let method_ty = def_ty(ccx.shared(), def_id, substs);
                 Callee::ptr(llfn, method_ty)
@@ -217,9 +218,7 @@ impl<'tcx> Callee<'tcx> {
     pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         match self.data {
             Fn(llfn) => llfn,
-            Virtual(idx) => {
-                meth::trans_object_shim(ccx, self.ty, idx)
-            }
+            Virtual(_) => meth::trans_object_shim(ccx, self),
             NamedTupleConstructor(disr) => match self.ty.sty {
                 ty::TyFnDef(def_id, substs, _) => {
                     let instance = Instance::new(def_id, substs);
@@ -264,8 +263,9 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
 /// ```
 ///
 /// but for the bare function type given.
-pub fn trans_fn_pointer_shim<'a, 'tcx>(
+fn trans_fn_pointer_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
+    method_instance: Instance<'tcx>,
     closure_kind: ty::ClosureKind,
     bare_fn_ty: Ty<'tcx>)
     -> ValueRef
@@ -345,10 +345,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
-    let function_name =
-        symbol_names::internal_name_from_type_and_suffix(ccx,
-                                                         bare_fn_ty,
-                                                         "fn_pointer_shim");
+    let function_name = method_instance.symbol_name(ccx.shared());
     let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
     //
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 83882c27e8e..c0692e8085f 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use arena::TypedArena;
-use back::symbol_names;
 use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
 use abi::{Abi, FnType};
@@ -152,6 +151,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                                       closure_def_id: DefId,
                                       substs: ty::ClosureSubsts<'tcx>,
+                                      method_instance: Instance<'tcx>,
                                       trait_closure_kind: ty::ClosureKind)
                                       -> ValueRef
 {
@@ -199,7 +199,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
             //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
             //
             // These are both the same at trans time.
-            trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
+            trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
         }
         _ => {
             bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
@@ -213,6 +213,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
     closure_def_id: DefId,
     substs: ty::ClosureSubsts<'tcx>,
+    method_instance: Instance<'tcx>,
     llreffn: ValueRef)
     -> ValueRef
 {
@@ -255,8 +256,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     }));
 
     // Create the by-value helper.
-    let function_name =
-        symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
+    let function_name = method_instance.symbol_name(ccx.shared());
     let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, lloncefn);
 
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 91ffe5044ce..1b2f861a522 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -210,9 +210,8 @@ use errors;
 use syntax_pos::DUMMY_SP;
 use base::custom_coerce_unsize_info;
 use context::SharedCrateContext;
-use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
+use common::{fulfill_obligation, type_is_sized};
 use glue::{self, DropGlueKind};
-use meth;
 use monomorphize::{self, Instance};
 use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
 
@@ -627,25 +626,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                               def_id: DefId)
                                               -> bool {
-            if !match tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyFnDef(def_id, ..) => {
+            match tcx.lookup_item_type(def_id).ty.sty {
+                ty::TyFnDef(def_id, _, f) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in
                     // translation item. Same for FFI functions.
-                    match tcx.map.get_if_local(def_id) {
-                        Some(hir_map::NodeVariant(_))    |
-                        Some(hir_map::NodeStructCtor(_)) |
-                        Some(hir_map::NodeForeignItem(_)) => false,
-                        Some(_) => true,
-                        None => {
-                            tcx.sess.cstore.variant_kind(def_id).is_none()
+                    if let Some(hir_map::NodeForeignItem(_)) = tcx.map.get_if_local(def_id) {
+                        return false;
+                    }
+
+                    if let Some(adt_def) = f.sig.output().skip_binder().ty_adt_def() {
+                        if adt_def.variants.iter().any(|v| def_id == v.did) {
+                            return false;
                         }
                     }
                 }
-                ty::TyClosure(..) => true,
-                _ => false
-            } {
-                return false;
+                ty::TyClosure(..) => {}
+                _ => return false
             }
 
             can_have_local_instance(tcx, def_id)
@@ -901,17 +898,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
     match vtbl {
-        traits::VtableImpl(traits::VtableImplData {
-            impl_def_id: impl_did,
-            substs: impl_substs,
-            nested: _ }) =>
-        {
-            let impl_method = meth::get_impl_method(tcx,
-                                                    rcvr_substs,
-                                                    impl_did,
-                                                    impl_substs,
-                                                    trait_method.name);
-            Some((impl_method.method.def_id, &impl_method.substs))
+        traits::VtableImpl(impl_data) => {
+            Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
         }
         // If we have a closure or a function pointer, we will also encounter
         // the concrete closure/function somewhere else (during closure or fn
@@ -1045,43 +1033,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
 
     if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
         let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty);
+        let param_substs = Substs::empty(scx.tcx());
 
         // Walk all methods of the trait, including those of its supertraits
-        for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) {
-            let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
-            match vtable {
-                traits::VtableImpl(
-                    traits::VtableImplData {
-                        impl_def_id,
-                        substs,
-                        nested: _ }) => {
-                    let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs)
-                        .into_iter()
-                        // filter out None values
-                        .filter_map(|opt_impl_method| opt_impl_method)
-                        // create translation items
-                        .filter_map(|impl_method| {
-                            if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
-                                Some(create_fn_trans_item(scx,
-                                    impl_method.method.def_id,
-                                    impl_method.substs,
-                                    Substs::empty(scx.tcx())))
-                            } else {
-                                None
-                            }
-                        });
-
-                    output.extend(items);
-                }
-                _ => { /* */ }
-            }
-        }
+        let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
+        let methods = methods.filter_map(|method| method)
+            .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs))
+            .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
+            .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
+        output.extend(methods);
 
         // Also add the destructor
         let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
-        if glue::type_needs_drop(scx.tcx(), dg_type) {
-            output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
-        }
+        output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
     }
 }
 
@@ -1241,25 +1205,27 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
                     let impl_substs = Substs::for_item(tcx, impl_def_id,
                                                        |_, _| tcx.mk_region(ty::ReErased),
                                                        |_, _| tcx.types.err);
-                    let mth = meth::get_impl_method(tcx,
-                                                    callee_substs,
-                                                    impl_def_id,
-                                                    impl_substs,
-                                                    method.name);
-
-                    assert!(mth.is_provided);
-
-                    let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
-                    if !normalize_and_test_predicates(tcx, predicates) {
+                    let impl_data = traits::VtableImplData {
+                        impl_def_id: impl_def_id,
+                        substs: impl_substs,
+                        nested: vec![]
+                    };
+                    let (def_id, substs) = traits::find_method(tcx,
+                                                               method.name,
+                                                               callee_substs,
+                                                               &impl_data);
+
+                    let predicates = tcx.lookup_predicates(def_id).predicates
+                                        .subst(tcx, substs);
+                    if !traits::normalize_and_test_predicates(tcx, predicates) {
                         continue;
                     }
 
                     if can_have_local_instance(tcx, method.def_id) {
-                        let empty_substs = tcx.erase_regions(&mth.substs);
                         let item = create_fn_trans_item(scx,
                                                         method.def_id,
                                                         callee_substs,
-                                                        empty_substs);
+                                                        tcx.erase_regions(&substs));
                         output.push(item);
                     }
                 }
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index e0de04d150c..db1a5419190 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -150,15 +150,6 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
     llsize_of_alloc(ccx, llty) == 0
 }
 
-/// Generates a unique symbol based off the name given. This is used to create
-/// unique symbols for things like closures.
-pub fn gensym_name(name: &str) -> ast::Name {
-    let num = token::gensym(name).0;
-    // use one colon which will get translated to a period by the mangler, and
-    // we're guaranteed that `num` is globally unique for this crate.
-    token::gensym(&format!("{}:{}", name, num))
-}
-
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
 *
@@ -1002,35 +993,6 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     })
 }
 
-/// Normalizes the predicates and checks whether they hold.  If this
-/// returns false, then either normalize encountered an error or one
-/// of the predicates did not hold. Used when creating vtables to
-/// check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                               predicates: Vec<ty::Predicate<'tcx>>)
-                                               -> bool
-{
-    debug!("normalize_and_test_predicates(predicates={:?})",
-           predicates);
-
-    tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
-        let mut selcx = SelectionContext::new(&infcx);
-        let mut fulfill_cx = traits::FulfillmentContext::new();
-        let cause = traits::ObligationCause::dummy();
-        let traits::Normalized { value: predicates, obligations } =
-            traits::normalize(&mut selcx, cause.clone(), &predicates);
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
-        }
-        for predicate in predicates {
-            let obligation = traits::Obligation::new(cause.clone(), predicate);
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
-        }
-
-        fulfill_cx.select_all_or_error(&infcx).is_ok()
-    })
-}
-
 pub fn langcall(tcx: TyCtxt,
                 span: Option<Span>,
                 msg: &str,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 3073b1dbfae..2a20728f09b 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -92,6 +92,8 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     t: Ty<'tcx>) -> Ty<'tcx> {
     assert!(t.is_normalized_for_trans());
 
+    let t = tcx.erase_regions(&t);
+
     // Even if there is no dtor for t, there might be one deeper down and we
     // might need to pass in the vtable ptr.
     if !type_is_sized(tcx, t) {
@@ -214,30 +216,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 g: DropGlueKind<'tcx>) -> ValueRef {
     let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t));
     match ccx.drop_glues().borrow().get(&g) {
-        Some(&(glue, _)) => return glue,
+        Some(&(glue, _)) => glue,
         None => {
-            debug!("Could not find drop glue for {:?} -- {} -- {}. \
-                    Falling back to on-demand instantiation.",
+            bug!("Could not find drop glue for {:?} -- {} -- {}.",
                     g,
                     TransItem::DropGlue(g).to_raw_string(),
                     ccx.codegen_unit().name());
         }
     }
-
-    // FIXME: #34151
-    // Normally, getting here would indicate a bug in trans::collector,
-    // since it seems to have missed a translation item. When we are
-    // translating with non-MIR-based trans, however, the results of the
-    // collector are not entirely reliable since it bases its analysis
-    // on MIR. Thus, we'll instantiate the missing function on demand in
-    // this codegen unit, so that things keep working.
-
-    TransItem::DropGlue(g).predefine(ccx, llvm::InternalLinkage);
-    TransItem::DropGlue(g).define(ccx);
-
-    // Now that we made sure that the glue function is in ccx.drop_glues,
-    // give it another try
-    get_drop_glue_core(ccx, g)
 }
 
 pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 3e60369acbf..41c8d565d41 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -69,7 +69,6 @@ pub use base::trans_crate;
 pub use disr::Disr;
 
 pub mod back {
-    pub use rustc_back::rpath;
     pub use rustc::hir::svh;
 
     pub mod archive;
@@ -79,6 +78,7 @@ pub mod back {
     pub mod symbol_names;
     pub mod write;
     pub mod msvc;
+    pub mod rpath;
 }
 
 pub mod diagnostics;
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index ee2f24d21e0..e8dcaf71f2d 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -8,33 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
-
 use attributes;
 use arena::TypedArena;
-use back::symbol_names;
 use llvm::{ValueRef, get_params};
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::{Subst, Substs};
-use rustc::traits::{self, Reveal};
+use rustc::traits;
 use abi::FnType;
 use base::*;
 use build::*;
-use callee::{Callee, Virtual, trans_fn_pointer_shim};
-use closure;
+use callee::Callee;
 use common::*;
 use consts;
 use debuginfo::DebugLoc;
 use declare;
 use glue;
 use machine;
+use monomorphize::Instance;
 use type_::Type;
 use type_of::*;
 use value::Value;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-
-use syntax::ast::Name;
-use syntax_pos::DUMMY_SP;
+use rustc::ty;
 
 // drop_glue pointer, size, align.
 const VTABLE_OFFSET: usize = 3;
@@ -73,23 +65,26 @@ pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// In fact, all virtual calls can be thought of as normal trait calls
 /// that go through this shim function.
 pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
-                                   method_ty: Ty<'tcx>,
-                                   vtable_index: usize)
+                                   callee: Callee<'tcx>)
                                    -> ValueRef {
     let _icx = push_ctxt("trans_object_shim");
     let tcx = ccx.tcx();
 
-    debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
-           vtable_index,
-           method_ty);
+    debug!("trans_object_shim({:?})", callee);
+
+    let (sig, abi, function_name) = match callee.ty.sty {
+        ty::TyFnDef(def_id, substs, f) => {
+            let instance = Instance::new(def_id, substs);
+            (&f.sig, f.abi, instance.symbol_name(ccx.shared()))
+        }
+        _ => bug!()
+    };
 
-    let sig = tcx.erase_late_bound_regions(&method_ty.fn_sig());
+    let sig = tcx.erase_late_bound_regions(sig);
     let sig = tcx.normalize_associated_type(&sig);
-    let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]);
+    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
-    let function_name =
-        symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim");
-    let llfn = declare::define_internal_fn(ccx, &function_name, method_ty);
+    let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
     attributes::set_frame_pointer_elimination(ccx, llfn);
 
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
@@ -98,16 +93,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     let mut bcx = fcx.init(false);
 
     let dest = fcx.llretslotptr.get();
-
-    debug!("trans_object_shim: method_offset_in_vtable={}",
-           vtable_index);
-
     let llargs = get_params(fcx.llfn);
-
-    let callee = Callee {
-        data: Virtual(vtable_index),
-        ty: method_ty
-    };
     bcx = callee.call(bcx, DebugLoc::None,
                       &llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
 
@@ -140,72 +126,23 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     // Not in the cache. Build it.
-    let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
-        let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone());
-        match vtable {
-            // Should default trait error here?
-            traits::VtableDefaultImpl(_) |
-            traits::VtableBuiltin(_) => {
-                Vec::new().into_iter()
-            }
-            traits::VtableImpl(
-                traits::VtableImplData {
-                    impl_def_id: id,
-                    substs,
-                    nested: _ }) => {
-                let nullptr = C_null(Type::nil(ccx).ptr_to());
-                get_vtable_methods(tcx, id, substs)
-                    .into_iter()
-                    .map(|opt_mth| opt_mth.map_or(nullptr, |mth| {
-                        Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx)
-                    }))
-                    .collect::<Vec<_>>()
-                    .into_iter()
-            }
-            traits::VtableClosure(
-                traits::VtableClosureData {
-                    closure_def_id,
-                    substs,
-                    nested: _ }) => {
-                let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
-                let llfn = closure::trans_closure_method(ccx,
-                                                         closure_def_id,
-                                                         substs,
-                                                         trait_closure_kind);
-                vec![llfn].into_iter()
-            }
-            traits::VtableFnPointer(
-                traits::VtableFnPointerData {
-                    fn_ty: bare_fn_ty,
-                    nested: _ }) => {
-                let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
-                vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
-            }
-            traits::VtableObject(ref data) => {
-                // this would imply that the Self type being erased is
-                // an object type; this cannot happen because we
-                // cannot cast an unsized type into a trait object
-                bug!("cannot get vtable for an object type: {:?}",
-                     data);
-            }
-            traits::VtableParam(..) => {
-                bug!("resolved vtable for {:?} to bad vtable {:?} in trans",
-                     trait_ref,
-                     vtable);
-            }
-        }
+    let nullptr = C_null(Type::nil(ccx).ptr_to());
+    let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
+        opt_mth.map_or(nullptr, |(def_id, substs)| {
+            Callee::def(ccx, def_id, substs).reify(ccx)
+        })
     });
 
     let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
     let size = machine::llsize_of_alloc(ccx, size_ty);
     let align = align_of(ccx, trait_ref.self_ty());
 
-    let components: Vec<_> = vec![
+    let components: Vec<_> = [
         // Generate a destructor for the vtable.
         glue::get_drop_glue(ccx, trait_ref.self_ty()),
         C_uint(ccx, size),
         C_uint(ccx, align)
-    ].into_iter().chain(methods).collect();
+    ].iter().cloned().chain(methods).collect();
 
     let vtable_const = C_struct(ccx, &components, false);
     let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
@@ -214,126 +151,3 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     ccx.vtables().borrow_mut().insert(trait_ref, vtable);
     vtable
 }
-
-pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    impl_id: DefId,
-                                    substs: &'tcx Substs<'tcx>)
-                                    -> Vec<Option<ImplMethod<'tcx>>>
-{
-    debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
-
-    let trait_id = match tcx.impl_trait_ref(impl_id) {
-        Some(t_id) => t_id.def_id,
-        None       => bug!("make_impl_vtable: don't know how to \
-                            make a vtable for a type impl!")
-    };
-
-    tcx.populate_implementations_for_trait_if_necessary(trait_id);
-
-    let trait_item_def_ids = tcx.trait_item_def_ids(trait_id);
-    trait_item_def_ids
-        .iter()
-
-        // Filter out non-method items.
-        .filter_map(|item_def_id| {
-            match *item_def_id {
-                ty::MethodTraitItemId(def_id) => Some(def_id),
-                _ => None,
-            }
-        })
-
-        // Now produce pointers for each remaining method. If the
-        // method could never be called from this object, just supply
-        // null.
-        .map(|trait_method_def_id| {
-            debug!("get_vtable_methods: trait_method_def_id={:?}",
-                   trait_method_def_id);
-
-            let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) {
-                ty::MethodTraitItem(m) => m,
-                _ => bug!("should be a method, not other assoc item"),
-            };
-            let name = trait_method_type.name;
-
-            // Some methods cannot be called on an object; skip those.
-            if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) {
-                debug!("get_vtable_methods: not vtable safe");
-                return None;
-            }
-
-            debug!("get_vtable_methods: trait_method_type={:?}",
-                   trait_method_type);
-
-            // the method may have some early-bound lifetimes, add
-            // regions for those
-            let method_substs = Substs::for_item(tcx, trait_method_def_id,
-                                                 |_, _| tcx.mk_region(ty::ReErased),
-                                                 |_, _| tcx.types.err);
-
-            // The substitutions we have are on the impl, so we grab
-            // the method type from the impl to substitute into.
-            let mth = get_impl_method(tcx, method_substs, impl_id, substs, name);
-
-            debug!("get_vtable_methods: mth={:?}", mth);
-
-            // If this is a default method, it's possible that it
-            // relies on where clauses that do not hold for this
-            // particular set of type parameters. Note that this
-            // method could then never be called, so we do not want to
-            // try and trans it, in that case. Issue #23435.
-            if mth.is_provided {
-                let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
-                if !normalize_and_test_predicates(tcx, predicates) {
-                    debug!("get_vtable_methods: predicates do not hold");
-                    return None;
-                }
-            }
-
-            Some(mth)
-        })
-        .collect()
-}
-
-#[derive(Debug)]
-pub struct ImplMethod<'tcx> {
-    pub method: Rc<ty::Method<'tcx>>,
-    pub substs: &'tcx Substs<'tcx>,
-    pub is_provided: bool
-}
-
-/// Locates the applicable definition of a method, given its name.
-pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 substs: &'tcx Substs<'tcx>,
-                                 impl_def_id: DefId,
-                                 impl_substs: &'tcx Substs<'tcx>,
-                                 name: Name)
-                                 -> ImplMethod<'tcx>
-{
-    assert!(!substs.needs_infer());
-
-    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
-    let trait_def = tcx.lookup_trait_def(trait_def_id);
-
-    match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
-        Some(node_item) => {
-            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
-                let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
-                let substs = traits::translate_substs(&infcx, impl_def_id,
-                                                      substs, node_item.node);
-                tcx.lift(&substs).unwrap_or_else(|| {
-                    bug!("trans::meth::get_impl_method: translate_substs \
-                          returned {:?} which contains inference types/regions",
-                         substs);
-                })
-            });
-            ImplMethod {
-                method: node_item.item,
-                substs: substs,
-                is_provided: node_item.node.is_from_trait(),
-            }
-        }
-        None => {
-            bug!("method {:?} not found in {:?}", name, impl_def_id)
-        }
-    }
-}
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 70d0a618404..f00da120799 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -247,11 +247,15 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
             let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
             if let traits::VtableImpl(vtable_impl) = vtable {
                 let name = ccx.tcx().item_name(instance.def);
-                for ac in ccx.tcx().associated_consts(vtable_impl.impl_def_id) {
-                    if ac.name == name {
-                        instance = Instance::new(ac.def_id, vtable_impl.substs);
-                        break;
-                    }
+                let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id)
+                    .iter().filter_map(|&def_id| {
+                        match ccx.tcx().impl_or_trait_item(def_id) {
+                            ty::ConstTraitItem(ac) => Some(ac),
+                            _ => None
+                        }
+                    }).find(|ic| ic.name == name);
+                if let Some(ac) = ac {
+                    instance = Instance::new(ac.def_id, vtable_impl.substs);
                 }
             }
         }
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 3873c24a9f6..141b8506c39 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -356,7 +356,7 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         format!("{}<{}>", base, strings.join(", "))
     };
 
-    if did.krate == 0 {
+    if did.is_local() {
         tstr
     } else {
         format!("{}.{}", did.krate, tstr)
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 334b7a5063a..cbdce3229c7 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1134,16 +1134,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             return tcx.types.err;
         }
 
-        let mut associated_types: FnvHashSet<(DefId, ast::Name)> =
-            traits::supertraits(tcx, principal)
-            .flat_map(|tr| {
-                let trait_def = tcx.lookup_trait_def(tr.def_id());
-                trait_def.associated_type_names
-                    .clone()
-                    .into_iter()
-                    .map(move |associated_type_name| (tr.def_id(), associated_type_name))
-            })
-            .collect();
+        let mut associated_types = FnvHashSet::default();
+        for tr in traits::supertraits(tcx, principal) {
+            if let Some(trait_id) = tcx.map.as_local_node_id(tr.def_id()) {
+                use collect::trait_associated_type_names;
+
+                associated_types.extend(trait_associated_type_names(tcx, trait_id)
+                    .map(|name| (tr.def_id(), name)))
+            } else {
+                let trait_items = tcx.impl_or_trait_items(tr.def_id());
+                associated_types.extend(trait_items.iter().filter_map(|&def_id| {
+                    match tcx.impl_or_trait_item(def_id) {
+                        ty::TypeTraitItem(ref item) => Some(item.name),
+                        _ => None
+                    }
+                }).map(|name| (tr.def_id(), name)));
+            }
+        }
 
         for projection_bound in &projection_bounds {
             let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
@@ -1284,23 +1291,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&ty.sty, ty_path_def) {
-            (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => {
-                // For Def::SelfTy() values inlined from another crate, the
-                // impl_id will be DUMMY_NODE_ID, which would cause problems
-                // here. But we should never run into an impl from another crate
-                // in this pass.
-                assert!(impl_id != ast::DUMMY_NODE_ID);
-
+            (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
                 // `Self` in an impl of a trait - we have a concrete self type and a
                 // trait reference.
-                let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
+                let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_ref = if let Some(free_substs) = self.get_free_substs() {
                     trait_ref.subst(tcx, free_substs)
                 } else {
                     trait_ref
                 };
 
-                if self.ensure_super_predicates(span, trait_did).is_err() {
+                if self.ensure_super_predicates(span, trait_ref.def_id).is_err() {
                     return (tcx.types.err, Def::Err);
                 }
 
@@ -1372,7 +1373,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             item.expect("missing associated type").def_id()
         };
 
-        (ty, Def::AssociatedTy(trait_did, item_did))
+        (ty, Def::AssociatedTy(item_did))
     }
 
     fn qpath_to_ty(&self,
@@ -1504,16 +1505,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     tcx.types.err
                 }
             }
-            Def::SelfTy(_, Some(impl_id)) => {
+            Def::SelfTy(_, Some(def_id)) => {
                 // Self in impl (we know the concrete type).
 
-                // For Def::SelfTy() values inlined from another crate, the
-                // impl_id will be DUMMY_NODE_ID, which would cause problems
-                // here. But we should never run into an impl from another crate
-                // in this pass.
-                assert!(impl_id != ast::DUMMY_NODE_ID);
-
                 tcx.prohibit_type_params(base_segments);
+                let impl_id = tcx.map.as_local_node_id(def_id).unwrap();
                 let ty = tcx.node_id_to_type(impl_id);
                 if let Some(free_substs) = self.get_free_substs() {
                     ty.subst(tcx, free_substs)
@@ -1526,8 +1522,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 tcx.prohibit_type_params(base_segments);
                 tcx.mk_self_type()
             }
-            Def::AssociatedTy(trait_did, _) => {
+            Def::AssociatedTy(def_id) => {
                 tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]);
+                let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(rscope,
                                  span,
                                  param_mode,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index dd3ac6ff2d4..de7ca479b0b 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -134,7 +134,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // what the type of the binding `x` ought to be
                 match tcx.expect_def(pat.id) {
                     Def::Err => {}
-                    Def::Local(_, var_id) => {
+                    Def::Local(def_id) => {
+                        let var_id = tcx.map.as_local_node_id(def_id).unwrap();
                         if var_id != pat.id {
                             let vt = self.local_ty(pat.span, var_id);
                             self.demand_eqtype(pat.span, vt, typ);
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 5bd4f13a111..d1fb0736d21 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -12,9 +12,8 @@ use super::{DeferredCallResolution, Expectation, FnCtxt,
             TupleArgumentsFlag};
 
 use CrateCtxt;
-use middle::cstore::LOCAL_CRATE;
 use hir::def::Def;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::parse::token;
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index faad3f9b000..4a631493398 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -577,7 +577,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 assoc::normalize_associated_types_in(&infcx,
                                                      &mut fulfillment_cx,
                                                      impl_c_span,
-                                                     0,
+                                                     ast::CRATE_NODE_ID,
                                                      &impl_ty);
 
             debug!("compare_const_impl: impl_ty={:?}",
@@ -587,7 +587,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 assoc::normalize_associated_types_in(&infcx,
                                                      &mut fulfillment_cx,
                                                      impl_c_span,
-                                                     0,
+                                                     ast::CRATE_NODE_ID,
                                                      &trait_ty);
 
             debug!("compare_const_impl: trait_ty={:?}",
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index bcb410e1b8d..73caf79c9f8 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Trait must have a method named `m_name` and it should not have
         // type parameters or early-bound regions.
         let tcx = self.tcx;
-        let method_item = self.trait_item(trait_def_id, m_name).unwrap();
+        let method_item = self.impl_or_trait_item(trait_def_id, m_name).unwrap();
         let method_ty = method_item.as_opt_method().unwrap();
         assert_eq!(method_ty.generics.types.len(), 0);
         assert_eq!(method_ty.generics.regions.len(), 0);
@@ -359,29 +359,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         Ok(def)
     }
 
-    /// Find item with name `item_name` defined in `trait_def_id`
-    /// and return it, or `None`, if no such item.
-    pub fn trait_item(&self,
-                      trait_def_id: DefId,
-                      item_name: ast::Name)
-                      -> Option<ty::ImplOrTraitItem<'tcx>>
+    /// Find item with name `item_name` defined in impl/trait `def_id`
+    /// and return it, or `None`, if no such item was defined there.
+    pub fn impl_or_trait_item(&self,
+                              def_id: DefId,
+                              item_name: ast::Name)
+                              -> Option<ty::ImplOrTraitItem<'tcx>>
     {
-        let trait_items = self.tcx.trait_items(trait_def_id);
-        trait_items.iter()
-                   .find(|item| item.name() == item_name)
-                   .cloned()
-    }
-
-    pub fn impl_item(&self,
-                     impl_def_id: DefId,
-                     item_name: ast::Name)
-                     -> Option<ty::ImplOrTraitItem<'tcx>>
-    {
-        let impl_items = self.tcx.impl_items.borrow();
-        let impl_items = impl_items.get(&impl_def_id).unwrap();
-        impl_items
+        self.tcx.impl_or_trait_items(def_id)
             .iter()
-            .map(|&did| self.tcx.impl_or_trait_item(did.def_id()))
+            .map(|&did| self.tcx.impl_or_trait_item(did))
             .find(|m| m.name() == item_name)
     }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 81e95c91e7f..9fba9bcb757 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -403,7 +403,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
 
-        let item = match self.impl_item(impl_def_id) {
+        let item = match self.impl_or_trait_item(impl_def_id) {
             Some(m) => m,
             None => { return; } // No method with correct name on this impl
         };
@@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let tcx = self.tcx;
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let item = match self.trait_item(bound_trait_ref.def_id()) {
+            let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) {
                 Some(v) => v,
                 None => { continue; }
             };
@@ -1292,18 +1292,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         self.tcx.erase_late_bound_regions(value)
     }
 
-    fn impl_item(&self, impl_def_id: DefId)
-                 -> Option<ty::ImplOrTraitItem<'tcx>>
+    /// Find item with name `item_name` defined in impl/trait `def_id`
+    /// and return it, or `None`, if no such item was defined there.
+    fn impl_or_trait_item(&self, def_id: DefId)
+                          -> Option<ty::ImplOrTraitItem<'tcx>>
     {
-        self.fcx.impl_item(impl_def_id, self.item_name)
-    }
-
-    /// Find item with name `item_name` defined in `trait_def_id`
-    /// and return it, or `None`, if no such item.
-    fn trait_item(&self, trait_def_id: DefId)
-                  -> Option<ty::ImplOrTraitItem<'tcx>>
-    {
-        self.fcx.trait_item(trait_def_id, self.item_name)
+        self.fcx.impl_or_trait_item(def_id, self.item_name)
     }
 }
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 3692d6fbf73..34bcd2ba046 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -16,9 +16,8 @@ use CrateCtxt;
 use check::{FnCtxt};
 use rustc::hir::map as hir_map;
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
-use middle::cstore;
 use hir::def::Def;
-use hir::def_id::DefId;
+use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
 use rustc::ty::subst::Substs;
 use rustc::traits::{Obligation, SelectionContext};
@@ -92,9 +91,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = self.impl_item(impl_did, item_name)
+                        let item = self.impl_or_trait_item(impl_did, item_name)
                             .or_else(|| {
-                                self.trait_item(
+                                self.impl_or_trait_item(
                                     self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
 
                                     item_name
@@ -127,7 +126,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item = self.trait_item(trait_did, item_name).unwrap();
+                        let item = self.impl_or_trait_item(trait_did, item_name).unwrap();
                         let item_span = self.tcx.map.def_id_span(item.def_id(), span);
                         span_note!(err, item_span,
                                    "candidate #{} is defined in the trait `{}`",
@@ -321,7 +320,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // implementing a trait would be legal but is rejected
                 // here).
                 (type_is_local || info.def_id.is_local())
-                    && self.trait_item(info.def_id, item_name).is_some()
+                    && self.impl_or_trait_item(info.def_id, item_name).is_some()
             })
             .collect::<Vec<_>>();
 
@@ -449,34 +448,30 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
 
         // Cross-crate:
         let mut external_mods = FnvHashSet();
-        fn handle_external_def(traits: &mut AllTraitsVec,
+        fn handle_external_def(ccx: &CrateCtxt,
+                               traits: &mut AllTraitsVec,
                                external_mods: &mut FnvHashSet<DefId>,
-                               ccx: &CrateCtxt,
-                               cstore: &for<'a> cstore::CrateStore<'a>,
-                               dl: cstore::DefLike) {
-            match dl {
-                cstore::DlDef(Def::Trait(did)) => {
-                    traits.push(TraitInfo::new(did));
+                               def_id: DefId) {
+            match ccx.tcx.sess.cstore.describe_def(def_id) {
+                Some(Def::Trait(_)) => {
+                    traits.push(TraitInfo::new(def_id));
                 }
-                cstore::DlDef(Def::Mod(did)) => {
-                    if !external_mods.insert(did) {
+                Some(Def::Mod(_)) => {
+                    if !external_mods.insert(def_id) {
                         return;
                     }
-                    for child in cstore.item_children(did) {
-                        handle_external_def(traits, external_mods,
-                                            ccx, cstore, child.def)
+                    for child in ccx.tcx.sess.cstore.item_children(def_id) {
+                        handle_external_def(ccx, traits, external_mods, child.def_id)
                     }
                 }
                 _ => {}
             }
         }
-        let cstore = &*ccx.tcx.sess.cstore;
-
         for cnum in ccx.tcx.sess.cstore.crates() {
-            for child in cstore.crate_top_level_items(cnum) {
-                handle_external_def(&mut traits, &mut external_mods,
-                                    ccx, cstore, child.def)
-            }
+            handle_external_def(ccx, &mut traits, &mut external_mods, DefId {
+                krate: cnum,
+                index: CRATE_DEF_INDEX
+            });
         }
 
         *ccx.all_traits.borrow_mut() = Some(traits);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index baa084212a2..e38b865842e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -83,9 +83,8 @@ use self::TupleArgumentsFlag::*;
 use astconv::{AstConv, ast_region_to_region, PathParamMode};
 use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
-use middle::cstore::LOCAL_CRATE;
 use hir::def::{Def, PathResolution};
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
 use rustc::ty::subst::{Subst, Substs};
@@ -1349,8 +1348,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
                                            assoc_name: ast::Name)
                                            -> bool
     {
-        let trait_def = self.tcx().lookup_trait_def(trait_def_id);
-        trait_def.associated_type_names.contains(&assoc_name)
+        self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| {
+            match self.tcx().impl_or_trait_item(def_id) {
+                ty::TypeTraitItem(ref item) => item.name == assoc_name,
+                _ => false
+            }
+        })
     }
 
     fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
@@ -1450,7 +1453,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             writeback_errors: Cell::new(false),
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_ty: rty,
-            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)),
+            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
+                                                     ast::CRATE_NODE_ID)),
             inh: inh,
         }
     }
@@ -2117,7 +2121,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             .unwrap_or(type_variable::Default {
                                 ty: self.next_ty_var(),
                                 origin_span: syntax_pos::DUMMY_SP,
-                                def_id: self.tcx.map.local_def_id(0) // what do I put here?
+                                // what do I put here?
+                                def_id: self.tcx.map.local_def_id(ast::CRATE_NODE_ID)
                             });
 
                     // This is to ensure that we elimnate any non-determinism from the error
@@ -3219,7 +3224,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.set_tainted_by_errors();
                 return None;
             }
-            Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => {
+            Def::Variant(did) => {
+                let type_did = self.tcx.parent_def_id(did).unwrap();
+                Some((type_did, self.tcx.expect_variant_def(def)))
+            }
+            Def::Struct(type_did) | Def::Union(type_did) => {
                 Some((type_did, self.tcx.expect_variant_def(def)))
             }
             Def::TyAlias(did) => {
@@ -4110,10 +4119,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Case 1 and 1b. Reference to a *type* or *enum variant*.
             Def::Struct(def_id) |
             Def::Union(def_id) |
-            Def::Variant(_, def_id) |
+            Def::Variant(def_id) |
             Def::Enum(def_id) |
             Def::TyAlias(def_id) |
-            Def::AssociatedTy(_, def_id) |
+            Def::AssociatedTy(def_id) |
             Def::Trait(def_id) => {
                 // Everything but the final segment should have no
                 // parameters at all.
@@ -4161,7 +4170,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // here. If they do, an error will have been reported
             // elsewhere. (I hope)
             Def::Mod(..) |
-            Def::ForeignMod(..) |
             Def::PrimTy(..) |
             Def::SelfTy(..) |
             Def::TyParam(..) |
@@ -4187,7 +4195,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
 
         match def {
-            Def::Local(_, nid) | Def::Upvar(_, nid, ..) => {
+            Def::Local(def_id) | Def::Upvar(def_id, ..) => {
+                let nid = self.tcx.map.as_local_node_id(def_id).unwrap();
                 let ty = self.local_ty(span, nid);
                 let ty = self.normalize_associated_types_in(span, &ty);
                 self.write_ty(node_id, ty);
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index f4a0df4611d..aa221c33b5d 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -120,7 +120,8 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
 
         self.fcx.tcx.with_freevars(expr.id, |freevars| {
             for freevar in freevars {
-                let var_node_id = freevar.def.var_id();
+                let def_id = freevar.def.def_id();
+                let var_node_id = self.fcx.tcx.map.as_local_node_id(def_id).unwrap();
                 let upvar_id = ty::UpvarId { var_id: var_node_id,
                                              closure_expr_id: expr.id };
                 debug!("seed upvar_id {:?}", upvar_id);
@@ -236,31 +237,30 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         // implemented.
         let tcx = self.fcx.tcx;
         tcx.with_freevars(closure_id, |freevars| {
-            freevars.iter()
-                    .map(|freevar| {
-                        let freevar_node_id = freevar.def.var_id();
-                        let freevar_ty = self.fcx.node_ty(freevar_node_id);
-                        let upvar_id = ty::UpvarId {
-                            var_id: freevar_node_id,
-                            closure_expr_id: closure_id
-                        };
-                        let capture = self.fcx.upvar_capture(upvar_id).unwrap();
-
-                        debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}",
-                               freevar_node_id, freevar_ty, capture);
-
-                        match capture {
-                            ty::UpvarCapture::ByValue => freevar_ty,
-                            ty::UpvarCapture::ByRef(borrow) =>
-                                tcx.mk_ref(borrow.region,
-                                           ty::TypeAndMut {
-                                               ty: freevar_ty,
-                                               mutbl: borrow.kind.to_mutbl_lossy(),
-                                           }),
-                        }
-                    })
-                    .collect()
-            })
+            freevars.iter().map(|freevar| {
+                let def_id = freevar.def.def_id();
+                let var_id = tcx.map.as_local_node_id(def_id).unwrap();
+                let freevar_ty = self.fcx.node_ty(var_id);
+                let upvar_id = ty::UpvarId {
+                    var_id: var_id,
+                    closure_expr_id: closure_id
+                };
+                let capture = self.fcx.upvar_capture(upvar_id).unwrap();
+
+                debug!("var_id={:?} freevar_ty={:?} capture={:?}",
+                       var_id, freevar_ty, capture);
+
+                match capture {
+                    ty::UpvarCapture::ByValue => freevar_ty,
+                    ty::UpvarCapture::ByRef(borrow) =>
+                        tcx.mk_ref(borrow.region,
+                                    ty::TypeAndMut {
+                                        ty: freevar_ty,
+                                        mutbl: borrow.kind.to_mutbl_lossy(),
+                                    }),
+                }
+            }).collect()
+        })
     }
 
     fn adjust_upvar_borrow_kind_for_consume(&mut self,
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 26c33c00b9c..3b4c98fc71e 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -20,8 +20,7 @@ use middle::lang_items::UnsizeTraitLangItem;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc::traits::{self, Reveal};
-use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId};
-use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
+use rustc::ty::{ParameterEnvironment};
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
 use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
@@ -39,6 +38,8 @@ use rustc::hir::intravisit;
 use rustc::hir::{Item, ItemImpl};
 use rustc::hir;
 
+use std::rc::Rc;
+
 mod orphan;
 mod overlap;
 mod unsafety;
@@ -156,7 +157,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
             }
         }
 
-        tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
+        tcx.impl_or_trait_item_def_ids.borrow_mut().insert(impl_did, Rc::new(impl_items));
     }
 
     fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
@@ -172,22 +173,11 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
     }
 
     // Converts an implementation in the AST to a vector of items.
-    fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
+    fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
         match item.node {
             ItemImpl(.., ref impl_items) => {
                 impl_items.iter().map(|impl_item| {
-                    let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id);
-                    match impl_item.node {
-                        hir::ImplItemKind::Const(..) => {
-                            ConstTraitItemId(impl_def_id)
-                        }
-                        hir::ImplItemKind::Method(..) => {
-                            MethodTraitItemId(impl_def_id)
-                        }
-                        hir::ImplItemKind::Type(_) => {
-                            TypeTraitItemId(impl_def_id)
-                        }
-                    }
+                    self.crate_context.tcx.map.local_def_id(impl_item.id)
                 }).collect()
             }
             _ => {
@@ -208,7 +198,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         tcx.populate_implementations_for_trait_if_necessary(drop_trait);
         let drop_trait = tcx.lookup_trait_def(drop_trait);
 
-        let impl_items = tcx.impl_items.borrow();
+        let impl_items = tcx.impl_or_trait_item_def_ids.borrow();
 
         drop_trait.for_each_impl(tcx, |impl_did| {
             let items = impl_items.get(&impl_did).unwrap();
@@ -221,7 +211,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
             let self_type = tcx.lookup_item_type(impl_did);
             match self_type.ty.sty {
                 ty::TyAdt(type_def, _) => {
-                    type_def.set_destructor(method_def_id.def_id());
+                    type_def.set_destructor(method_def_id);
                 }
                 _ => {
                     // Destructors only work on nominal types.
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index d1eb0f995de..70342a0cd25 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -11,8 +11,7 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use middle::cstore::LOCAL_CRATE;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::traits;
 use rustc::ty::{self, TyCtxt};
 use syntax::ast;
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 890b6c72e6f..c42b8f88400 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -44,29 +44,29 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
         enum Namespace { Type, Value }
 
         fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        item: &ty::ImplOrTraitItemId)
+                                        def_id: DefId)
                                         -> (ast::Name, Namespace)
         {
-            let name = tcx.impl_or_trait_item(item.def_id()).name();
-            (name, match *item {
-                ty::TypeTraitItemId(..) => Namespace::Type,
-                ty::ConstTraitItemId(..) => Namespace::Value,
-                ty::MethodTraitItemId(..) => Namespace::Value,
+            let item = tcx.impl_or_trait_item(def_id);
+            (item.name(), match item {
+                ty::TypeTraitItem(..) => Namespace::Type,
+                ty::ConstTraitItem(..) => Namespace::Value,
+                ty::MethodTraitItem(..) => Namespace::Value,
             })
         }
 
-        let impl_items = self.tcx.impl_items.borrow();
+        let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
 
-        for item1 in &impl_items[&impl1] {
+        for &item1 in &impl_items[&impl1][..] {
             let (name, namespace) = name_and_namespace(self.tcx, item1);
 
-            for item2 in &impl_items[&impl2] {
+            for &item2 in &impl_items[&impl2][..] {
                 if (name, namespace) == name_and_namespace(self.tcx, item2) {
                     let msg = format!("duplicate definitions with name `{}`", name);
-                    let node_id = self.tcx.map.as_local_node_id(item1.def_id()).unwrap();
+                    let node_id = self.tcx.map.as_local_node_id(item1).unwrap();
                     self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
                                            node_id,
-                                           self.tcx.span_of_impl(item1.def_id()).unwrap(),
+                                           self.tcx.span_of_impl(item1).unwrap(),
                                            msg);
                 }
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 04aca8c0947..e5d4d4a9dae 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -361,10 +361,15 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
                                            -> bool
     {
         if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) {
-            trait_defines_associated_type_named(self.ccx, trait_id, assoc_name)
+            trait_associated_type_names(self.tcx(), trait_id)
+                .any(|name| name == assoc_name)
         } else {
-            let trait_def = self.tcx().lookup_trait_def(trait_def_id);
-            trait_def.associated_type_names.contains(&assoc_name)
+            self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| {
+                match self.tcx().impl_or_trait_item(def_id) {
+                    ty::TypeTraitItem(ref item) => item.name == assoc_name,
+                    _ => false
+                }
+            })
         }
     }
 
@@ -563,6 +568,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             vis: &hir::Visibility,
                             sig: &hir::MethodSig,
                             defaultness: hir::Defaultness,
+                            has_body: bool,
                             untransformed_rcvr_ty: Ty<'tcx>,
                             rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
     let def_id = ccx.tcx.map.local_def_id(id);
@@ -580,15 +586,18 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                               sig, untransformed_rcvr_ty, anon_scope)
     };
 
-    let ty_method = ty::Method::new(name,
-                                    ty_generics,
-                                    ty_generic_predicates,
-                                    fty,
-                                    explicit_self_category,
-                                    ty::Visibility::from_hir(vis, id, ccx.tcx),
-                                    defaultness,
-                                    def_id,
-                                    container);
+    let ty_method = ty::Method {
+        name: name,
+        generics: ty_generics,
+        predicates: ty_generic_predicates,
+        fty: fty,
+        explicit_self: explicit_self_category,
+        vis: ty::Visibility::from_hir(vis, id, ccx.tcx),
+        defaultness: defaultness,
+        has_body: has_body,
+        def_id: def_id,
+        container: container,
+    };
 
     let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
                                 ccx.tcx.map.span(id), def_id);
@@ -665,6 +674,13 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                      defaultness: hir::Defaultness,
                                      ty: Option<Ty<'tcx>>)
 {
+    let predicates = ty::GenericPredicates {
+        parent: Some(container.id()),
+        predicates: vec![]
+    };
+    ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id),
+                                           predicates);
+
     let associated_type = Rc::new(ty::AssociatedType {
         name: name,
         vis: ty::Visibility::from_hir(vis, id, ccx.tcx),
@@ -822,6 +838,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             // Convert all the associated types.
             for impl_item in impl_items {
                 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
+                    let type_def_id = ccx.tcx.map.local_def_id(impl_item.id);
+                    generics_of_def_id(ccx, type_def_id);
+
                     if opt_trait_ref.is_none() {
                         span_err!(tcx.sess, impl_item.span, E0202,
                                   "associated types are not allowed in inherent impls");
@@ -843,7 +862,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     convert_method(ccx, ImplContainer(def_id),
                                    impl_item.name, impl_item.id, method_vis,
-                                   sig, impl_item.defaultness, selfty,
+                                   sig, impl_item.defaultness, true, selfty,
                                    &ty_predicates);
                 }
             }
@@ -889,6 +908,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             // Convert all the associated types.
             for trait_item in trait_items {
                 if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
+                    let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+                    generics_of_def_id(ccx, type_def_id);
+
                     let typ = opt_ty.as_ref().map({
                         |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
                     });
@@ -905,7 +927,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             // Convert all the methods
             for trait_item in trait_items {
-                if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
+                if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node {
                     convert_method(ccx,
                                    container,
                                    trait_item.name,
@@ -913,6 +935,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                    &hir::Inherited,
                                    sig,
                                    hir::Defaultness::Default,
+                                   body.is_some(),
                                    tcx.mk_self_type(),
                                    &trait_predicates);
 
@@ -921,15 +944,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             // Add an entry mapping
             let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
-                let def_id = ccx.tcx.map.local_def_id(trait_item.id);
-                match trait_item.node {
-                    hir::ConstTraitItem(..) => ty::ConstTraitItemId(def_id),
-                    hir::MethodTraitItem(..) => ty::MethodTraitItemId(def_id),
-                    hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id)
-                }
+                ccx.tcx.map.local_def_id(trait_item.id)
             }).collect());
-            tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
-                                                       trait_item_def_ids);
+            tcx.impl_or_trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+                                                               trait_item_def_ids);
         },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
@@ -1261,9 +1279,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return def.clone();
     }
 
-    let (unsafety, generics, items) = match it.node {
-        hir::ItemTrait(unsafety, ref generics, _, ref items) => {
-            (unsafety, generics, items)
+    let (unsafety, generics) = match it.node {
+        hir::ItemTrait(unsafety, ref generics, _, _) => {
+            (unsafety, generics)
         }
         _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"),
     };
@@ -1283,32 +1301,20 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let ty_generics = generics_of_def_id(ccx, def_id);
     let substs = mk_item_substs(&ccx.icx(generics), it.span, def_id);
 
-    let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| {
-        match trait_item.node {
-            hir::TypeTraitItem(..) => Some(trait_item.name),
-            _ => None,
-        }
-    }).collect();
-
     let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
 
     let trait_ref = ty::TraitRef::new(def_id, substs);
-    let trait_def = ty::TraitDef::new(unsafety,
-                                      paren_sugar,
-                                      ty_generics,
-                                      trait_ref,
-                                      associated_type_names,
+    let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref,
                                       def_path_hash);
 
     tcx.intern_trait_def(trait_def)
 }
 
-fn trait_defines_associated_type_named(ccx: &CrateCtxt,
-                                       trait_node_id: ast::NodeId,
-                                       assoc_name: ast::Name)
-                                       -> bool
+pub fn trait_associated_type_names<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                                   trait_node_id: ast::NodeId)
+                                                   -> impl Iterator<Item=ast::Name> + 'a
 {
-    let item = match ccx.tcx.map.get(trait_node_id) {
+    let item = match tcx.map.get(trait_node_id) {
         hir_map::NodeItem(item) => item,
         _ => bug!("trait_node_id {} is not an item", trait_node_id)
     };
@@ -1318,10 +1324,10 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt,
         _ => bug!("trait_node_id {} is not a trait", trait_node_id)
     };
 
-    trait_items.iter().any(|trait_item| {
+    trait_items.iter().filter_map(|trait_item| {
         match trait_item.node {
-            hir::TypeTraitItem(..) => trait_item.name == assoc_name,
-            _ => false,
+            hir::TypeTraitItem(..) => Some(trait_item.name),
+            _ => None,
         }
     })
 }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index d2e2d578fce..1f34cee5143 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(conservative_impl_trait)]
 #![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 709e3698924..c4d6ff43eff 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,9 +15,9 @@ use std::iter::once;
 use syntax::ast;
 use rustc::hir;
 
-use rustc::middle::cstore;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
+use rustc::hir::map::DefPathData;
 use rustc::hir::print as pprust;
 use rustc::ty::{self, TyCtxt, VariantKind};
 use rustc::util::nodemap::FnvHashSet;
@@ -83,7 +83,7 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         Def::Struct(did)
                 // If this is a struct constructor, we skip it
-                if tcx.sess.cstore.tuple_struct_definition_if_ctor(did).is_none() => {
+                if tcx.def_key(did).disambiguated_data.data != DefPathData::StructCtor => {
             record_extern_fqn(cx, did, clean::TypeStruct);
             ret.extend(build_impls(cx, tcx, did));
             clean::StructItem(build_struct(cx, tcx, did))
@@ -96,12 +96,12 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Def::TyAlias(did) => {
             record_extern_fqn(cx, did, clean::TypeTypedef);
             ret.extend(build_impls(cx, tcx, did));
-            build_type(cx, tcx, did)
+            clean::TypedefItem(build_type_alias(cx, tcx, did), false)
         }
         Def::Enum(did) => {
             record_extern_fqn(cx, did, clean::TypeEnum);
             ret.extend(build_impls(cx, tcx, did));
-            build_type(cx, tcx, did)
+            clean::EnumItem(build_enum(cx, tcx, did))
         }
         // Assume that the enum type is reexported next to the variant, and
         // variants don't show up in documentation specially.
@@ -200,6 +200,18 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx
     }
 }
 
+fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        did: DefId) -> clean::Enum {
+    let t = tcx.lookup_item_type(did);
+    let predicates = tcx.lookup_predicates(did);
+
+    clean::Enum {
+        generics: (t.generics, &predicates).clean(cx),
+        variants_stripped: false,
+        variants: tcx.lookup_adt_def(did).variants.clean(cx),
+    }
+}
+
 fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           did: DefId) -> clean::Struct {
     let t = tcx.lookup_item_type(did);
@@ -232,25 +244,15 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        did: DefId) -> clean::ItemEnum {
+fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              did: DefId) -> clean::Typedef {
     let t = tcx.lookup_item_type(did);
     let predicates = tcx.lookup_predicates(did);
-    match t.ty.sty {
-        ty::TyAdt(edef, _) if edef.is_enum() && !tcx.sess.cstore.is_typedef(did) => {
-            return clean::EnumItem(clean::Enum {
-                generics: (t.generics, &predicates).clean(cx),
-                variants_stripped: false,
-                variants: edef.variants.clean(cx),
-            })
-        }
-        _ => {}
-    }
 
-    clean::TypedefItem(clean::Typedef {
+    clean::Typedef {
         type_: t.ty.clean(cx),
         generics: (t.generics, &predicates).clean(cx),
-    }, false)
+    }
 }
 
 pub fn build_impls<'a, 'tcx>(cx: &DocContext,
@@ -264,32 +266,49 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,
             build_impl(cx, tcx, did, &mut impls);
         }
     }
-
-    // If this is the first time we've inlined something from this crate, then
-    // we inline *all* impls from the crate into this crate. Note that there's
+    // If this is the first time we've inlined something from another crate, then
+    // we inline *all* impls from all the crates into this crate. Note that there's
     // currently no way for us to filter this based on type, and we likely need
     // many impls for a variety of reasons.
     //
     // Primarily, the impls will be used to populate the documentation for this
     // type being inlined, but impls can also be used when generating
     // documentation for primitives (no way to find those specifically).
-    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
-        for item in tcx.sess.cstore.crate_top_level_items(did.krate) {
-            populate_impls(cx, tcx, item.def, &mut impls);
-        }
+    if cx.populated_all_crate_impls.get() {
+        return impls;
+    }
 
-        fn populate_impls<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    def: cstore::DefLike,
-                                    impls: &mut Vec<clean::Item>) {
-            match def {
-                cstore::DlImpl(did) => build_impl(cx, tcx, did, impls),
-                cstore::DlDef(Def::Mod(did)) => {
-                    for item in tcx.sess.cstore.item_children(did) {
-                        populate_impls(cx, tcx, item.def, impls)
-                    }
-                }
-                _ => {}
-            }
+    cx.populated_all_crate_impls.set(true);
+
+    for did in tcx.sess.cstore.implementations_of_trait(None) {
+        build_impl(cx, tcx, did, &mut impls);
+    }
+
+    // Also try to inline primitive impls from other crates.
+    let primitive_impls = [
+        tcx.lang_items.isize_impl(),
+        tcx.lang_items.i8_impl(),
+        tcx.lang_items.i16_impl(),
+        tcx.lang_items.i32_impl(),
+        tcx.lang_items.i64_impl(),
+        tcx.lang_items.usize_impl(),
+        tcx.lang_items.u8_impl(),
+        tcx.lang_items.u16_impl(),
+        tcx.lang_items.u32_impl(),
+        tcx.lang_items.u64_impl(),
+        tcx.lang_items.f32_impl(),
+        tcx.lang_items.f64_impl(),
+        tcx.lang_items.char_impl(),
+        tcx.lang_items.str_impl(),
+        tcx.lang_items.slice_impl(),
+        tcx.lang_items.slice_impl(),
+        tcx.lang_items.const_ptr_impl()
+    ];
+
+    for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
+        if !def_id.is_local() {
+            tcx.populate_implementations_for_primitive_if_necessary(def_id);
+            build_impl(cx, tcx, def_id, &mut impls);
         }
     }
 
@@ -348,12 +367,10 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
     }
 
     let predicates = tcx.lookup_predicates(did);
-    let trait_items = tcx.sess.cstore.impl_items(did)
+    let trait_items = tcx.sess.cstore.impl_or_trait_items(did)
             .iter()
-            .filter_map(|did| {
-        let did = did.def_id();
-        let impl_item = tcx.impl_or_trait_item(did);
-        match impl_item {
+            .filter_map(|&did| {
+        match tcx.impl_or_trait_item(did) {
             ty::ConstTraitItem(ref assoc_const) => {
                 let did = assoc_const.def_id;
                 let type_scheme = tcx.lookup_item_type(did);
@@ -453,7 +470,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
             for_: for_,
             generics: (ty.generics, &predicates).clean(cx),
             items: trait_items,
-            polarity: polarity.map(|p| { p.clean(cx) }),
+            polarity: Some(polarity.clean(cx)),
         }),
         source: clean::Span::empty(),
         name: None,
@@ -481,20 +498,13 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // visit each node at most once.
         let mut visited = FnvHashSet();
         for item in tcx.sess.cstore.item_children(did) {
-            match item.def {
-                cstore::DlDef(Def::ForeignMod(did)) => {
-                    fill_in(cx, tcx, did, items);
-                }
-                cstore::DlDef(def) if item.vis == ty::Visibility::Public => {
-                    if !visited.insert(def) { continue }
+            if tcx.sess.cstore.visibility(item.def_id) == ty::Visibility::Public {
+                if !visited.insert(item.def_id) { continue }
+                if let Some(def) = tcx.sess.cstore.describe_def(item.def_id) {
                     if let Some(i) = try_inline_def(cx, tcx, def) {
                         items.extend(i)
                     }
                 }
-                cstore::DlDef(..) => {}
-                // All impls were inlined above
-                cstore::DlImpl(..) => {}
-                cstore::DlField => panic!("unimplemented field"),
             }
         }
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b9dc75cdd9f..0ae059509bd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -33,12 +33,10 @@ use syntax::print::pprust as syntax_pprust;
 use syntax_pos::{self, DUMMY_SP, Pos};
 
 use rustc_trans::back::link;
-use rustc::middle::cstore;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::resolve_lifetime::DefRegion::*;
 use rustc::hir::def::Def;
-use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
-use rustc::hir::fold::Folder;
+use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::print as pprust;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind};
@@ -116,7 +114,7 @@ pub struct Crate {
     pub name: String,
     pub src: PathBuf,
     pub module: Option<Item>,
-    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
+    pub externs: Vec<(def_id::CrateNum, ExternalCrate)>,
     pub primitives: Vec<PrimitiveType>,
     pub access_levels: Arc<AccessLevels<DefId>>,
     // These are later on moved into `CACHEKEY`, leaving the map empty.
@@ -124,7 +122,7 @@ pub struct Crate {
     pub external_traits: FnvHashMap<DefId, Trait>,
 }
 
-struct CrateNum(ast::CrateNum);
+struct CrateNum(def_id::CrateNum);
 
 impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
     fn clean(&self, cx: &DocContext) -> Crate {
@@ -239,19 +237,16 @@ pub struct ExternalCrate {
 impl Clean<ExternalCrate> for CrateNum {
     fn clean(&self, cx: &DocContext) -> ExternalCrate {
         let mut primitives = Vec::new();
+        let root = DefId { krate: self.0, index: CRATE_DEF_INDEX };
         cx.tcx_opt().map(|tcx| {
-            for item in tcx.sess.cstore.crate_top_level_items(self.0) {
-                let did = match item.def {
-                    cstore::DlDef(Def::Mod(did)) => did,
-                    _ => continue
-                };
-                let attrs = inline::load_attrs(cx, tcx, did);
+            for item in tcx.sess.cstore.item_children(root) {
+                let attrs = inline::load_attrs(cx, tcx, item.def_id);
                 PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
             }
         });
         ExternalCrate {
             name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(),
-            attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx),
+            attrs: cx.sess().cstore.item_attrs(root).clean(cx),
             primitives: primitives,
         }
     }
@@ -774,7 +769,20 @@ impl Lifetime {
 }
 
 impl Clean<Lifetime> for hir::Lifetime {
-    fn clean(&self, _: &DocContext) -> Lifetime {
+    fn clean(&self, cx: &DocContext) -> Lifetime {
+        if let Some(tcx) = cx.tcx_opt() {
+            let def = tcx.named_region_map.defs.get(&self.id).cloned();
+            match def {
+                Some(DefEarlyBoundRegion(_, node_id)) |
+                Some(DefLateBoundRegion(_, node_id)) |
+                Some(DefFreeRegion(_, node_id)) => {
+                    if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
+                        return lt;
+                    }
+                }
+                _ => {}
+            }
+        }
         Lifetime(self.name.to_string())
     }
 }
@@ -1149,7 +1157,7 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
         let mut names = if cx.map.as_local_node_id(did).is_some() {
             vec![].into_iter()
         } else {
-            cx.tcx().sess.cstore.method_arg_names(did).into_iter()
+            cx.tcx().sess.cstore.fn_arg_names(did).into_iter()
         }.peekable();
         FnDecl {
             output: Return(sig.0.output.clean(cx)),
@@ -1159,8 +1167,8 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
                 values: sig.0.inputs.iter().map(|t| {
                     Argument {
                         type_: t.clean(cx),
-                        id: 0,
-                        name: names.next().unwrap_or("".to_string()),
+                        id: ast::CRATE_NODE_ID,
+                        name: names.next().map_or("".to_string(), |name| name.to_string()),
                     }
                 }).collect(),
             },
@@ -1629,42 +1637,6 @@ impl From<ast::FloatTy> for PrimitiveType {
     }
 }
 
-// Poor man's type parameter substitution at HIR level.
-// Used to replace private type aliases in public signatures with their aliased types.
-struct SubstAlias<'a, 'tcx: 'a> {
-    tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>,
-    // Table type parameter definition -> substituted type
-    ty_substs: FnvHashMap<Def, hir::Ty>,
-    // Table node id of lifetime parameter definition -> substituted lifetime
-    lt_substs: FnvHashMap<ast::NodeId, hir::Lifetime>,
-}
-
-impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> {
-    fn fold_ty(&mut self, ty: P<hir::Ty>) -> P<hir::Ty> {
-        if let hir::TyPath(..) = ty.node {
-            let def = self.tcx.expect_def(ty.id);
-            if let Some(new_ty) = self.ty_substs.get(&def).cloned() {
-                return P(new_ty);
-            }
-        }
-        hir::fold::noop_fold_ty(ty, self)
-    }
-    fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime {
-        let def = self.tcx.named_region_map.defs.get(&lt.id).cloned();
-        match def {
-            Some(DefEarlyBoundRegion(_, node_id)) |
-            Some(DefLateBoundRegion(_, node_id)) |
-            Some(DefFreeRegion(_, node_id)) => {
-                if let Some(lt) = self.lt_substs.get(&node_id).cloned() {
-                    return lt;
-                }
-            }
-            _ => {}
-        }
-        hir::fold::noop_fold_lifetime(lt, self)
-    }
-}
-
 impl Clean<Type> for hir::Ty {
     fn clean(&self, cx: &DocContext) -> Type {
         use rustc::hir::*;
@@ -1696,43 +1668,47 @@ impl Clean<Type> for hir::Ty {
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(None, ref path) => {
-                if let Some(tcx) = cx.tcx_opt() {
-                    // Substitute private type aliases
-                    let def = tcx.expect_def(self.id);
+                let tcx_and_def = cx.tcx_opt().map(|tcx| (tcx, tcx.expect_def(self.id)));
+                if let Some((_, def)) = tcx_and_def {
+                    if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() {
+                        return new_ty;
+                    }
+                }
+
+                let tcx_and_alias = tcx_and_def.and_then(|(tcx, def)| {
                     if let Def::TyAlias(def_id) = def {
-                        if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+                        // Substitute private type aliases
+                        tcx.map.as_local_node_id(def_id).and_then(|node_id| {
                             if !cx.access_levels.borrow().is_exported(def_id) {
-                                let item = tcx.map.expect_item(node_id);
-                                if let hir::ItemTy(ref ty, ref generics) = item.node {
-                                    let provided_params = &path.segments.last().unwrap().parameters;
-                                    let mut ty_substs = FnvHashMap();
-                                    let mut lt_substs = FnvHashMap();
-                                    for (i, ty_param) in generics.ty_params.iter().enumerate() {
-                                        let ty_param_def = tcx.expect_def(ty_param.id);
-                                        if let Some(ty) = provided_params.types().get(i).cloned()
-                                                                                        .cloned() {
-                                            ty_substs.insert(ty_param_def, ty.unwrap());
-                                        } else if let Some(default) = ty_param.default.clone() {
-                                            ty_substs.insert(ty_param_def, default.unwrap());
-                                        }
-                                    }
-                                    for (i, lt_param) in generics.lifetimes.iter().enumerate() {
-                                        if let Some(lt) = provided_params.lifetimes().get(i)
-                                                                                     .cloned()
-                                                                                     .cloned() {
-                                            lt_substs.insert(lt_param.lifetime.id, lt);
-                                        }
-                                    }
-                                    let mut subst_alias = SubstAlias {
-                                        tcx: &tcx,
-                                        ty_substs: ty_substs,
-                                        lt_substs: lt_substs
-                                    };
-                                    return subst_alias.fold_ty(ty.clone()).clean(cx);
-                                }
+                                Some((tcx, &tcx.map.expect_item(node_id).node))
+                            } else {
+                                None
                             }
+                        })
+                    } else {
+                        None
+                    }
+                });
+                if let Some((tcx, &hir::ItemTy(ref ty, ref generics))) = tcx_and_alias {
+                    let provided_params = &path.segments.last().unwrap().parameters;
+                    let mut ty_substs = FnvHashMap();
+                    let mut lt_substs = FnvHashMap();
+                    for (i, ty_param) in generics.ty_params.iter().enumerate() {
+                        let ty_param_def = tcx.expect_def(ty_param.id);
+                        if let Some(ty) = provided_params.types().get(i).cloned()
+                                                                        .cloned() {
+                            ty_substs.insert(ty_param_def, ty.unwrap().clean(cx));
+                        } else if let Some(default) = ty_param.default.clone() {
+                            ty_substs.insert(ty_param_def, default.unwrap().clean(cx));
+                        }
+                    }
+                    for (i, lt_param) in generics.lifetimes.iter().enumerate() {
+                        if let Some(lt) = provided_params.lifetimes().get(i).cloned()
+                                                                            .cloned() {
+                            lt_substs.insert(lt_param.lifetime.id, lt.clean(cx));
                         }
                     }
+                    return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
                 }
                 resolve_type(cx, path.clean(cx), self.id)
             }
@@ -1808,7 +1784,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                     type_params: Vec::new(),
                     where_predicates: Vec::new()
                 },
-                decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
+                decl: (cx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
                 abi: fty.abi,
             }),
             ty::TyAdt(def, substs) => {
@@ -1897,11 +1873,9 @@ impl Clean<Item> for hir::StructField {
 
 impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
     fn clean(&self, cx: &DocContext) -> Item {
-        // FIXME: possible O(n^2)-ness! Not my fault.
-        let attr_map = cx.tcx().sess.cstore.crate_struct_field_attrs(self.did.krate);
         Item {
             name: Some(self.name).clean(cx),
-            attrs: attr_map.get(&self.did).unwrap_or(&Vec::new()).clean(cx),
+            attrs: cx.tcx().get_attrs(self.did).clean(cx),
             source: Span::empty(),
             visibility: self.vis.clean(cx),
             stability: get_stability(cx, self.did),
@@ -2590,7 +2564,7 @@ impl Clean<Vec<Item>> for doctree::Import {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: cx.map.local_def_id(0),
+            def_id: cx.map.local_def_id(ast::CRATE_NODE_ID),
             visibility: self.vis.clean(cx),
             stability: None,
             deprecation: None,
@@ -2779,6 +2753,8 @@ fn resolve_type(cx: &DocContext,
 fn register_def(cx: &DocContext, def: Def) -> DefId {
     debug!("register_def({:?})", def);
 
+    let tcx = cx.tcx();
+
     let (did, kind) = match def {
         Def::Fn(i) => (i, TypeFunction),
         Def::TyAlias(i) => (i, TypeTypedef),
@@ -2788,21 +2764,14 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
         Def::Union(i) => (i, TypeUnion),
         Def::Mod(i) => (i, TypeModule),
         Def::Static(i, _) => (i, TypeStatic),
-        Def::Variant(i, _) => (i, TypeEnum),
+        Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeEnum),
         Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait),
-        Def::SelfTy(_, Some(impl_id)) => {
-            // For Def::SelfTy() values inlined from another crate, the
-            // impl_id will be DUMMY_NODE_ID, which would cause problems.
-            // But we should never run into an impl from another crate here.
-            return cx.map.local_def_id(impl_id)
+        Def::SelfTy(_, Some(impl_def_id)) => {
+            return impl_def_id
         }
         _ => return def.def_id()
     };
     if did.is_local() { return did }
-    let tcx = match cx.tcx_opt() {
-        Some(tcx) => tcx,
-        None => return did
-    };
     inline::record_extern_fqn(cx, did, kind);
     if let TypeTrait = kind {
         let t = inline::build_external_trait(cx, tcx, did);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 1e3804955e9..c52497dc89b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -14,11 +14,12 @@ use rustc_driver::{driver, target_features, abort_on_err};
 use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config};
 use rustc::hir::def_id::DefId;
+use rustc::hir::def::Def;
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, TyCtxt};
 use rustc::hir::map as hir_map;
 use rustc::lint;
-use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
+use rustc::util::nodemap::FnvHashMap;
 use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
@@ -29,6 +30,7 @@ use errors;
 use errors::emitter::ColorConfig;
 
 use std::cell::{RefCell, Cell};
+use std::mem;
 use std::rc::Rc;
 
 use visit_ast::RustdocVisitor;
@@ -51,7 +53,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub map: &'a hir_map::Map<'tcx>,
     pub maybe_typed: MaybeTyped<'a, 'tcx>,
     pub input: Input,
-    pub populated_crate_impls: RefCell<FnvHashSet<ast::CrateNum>>,
+    pub populated_all_crate_impls: Cell<bool>,
     pub deref_trait_did: Cell<Option<DefId>>,
     pub deref_mut_trait_did: Cell<Option<DefId>>,
     // Note that external items for which `doc(hidden)` applies to are shown as
@@ -63,6 +65,14 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
     pub external_traits: RefCell<FnvHashMap<DefId, clean::Trait>>,
+
+    // The current set of type and lifetime substitutions,
+    // for expanding type aliases at the HIR level:
+
+    /// Table type parameter definition -> substituted type
+    pub ty_substs: RefCell<FnvHashMap<Def, clean::Type>>,
+    /// Table node id of lifetime parameter definition -> substituted lifetime
+    pub lt_substs: RefCell<FnvHashMap<ast::NodeId, clean::Lifetime>>,
 }
 
 impl<'b, 'tcx> DocContext<'b, 'tcx> {
@@ -84,6 +94,22 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> {
         let tcx_opt = self.tcx_opt();
         tcx_opt.expect("tcx not present")
     }
+
+    /// Call the closure with the given parameters set as
+    /// the substitutions for a type alias' RHS.
+    pub fn enter_alias<F, R>(&self,
+                             ty_substs: FnvHashMap<Def, clean::Type>,
+                             lt_substs: FnvHashMap<ast::NodeId, clean::Lifetime>,
+                             f: F) -> R
+    where F: FnOnce() -> R {
+        let (old_tys, old_lts) =
+            (mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
+             mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs));
+        let r = f();
+        *self.ty_substs.borrow_mut() = old_tys;
+        *self.lt_substs.borrow_mut() = old_lts;
+        r
+    }
 }
 
 pub trait DocAccessLevels {
@@ -179,12 +205,14 @@ pub fn run_core(search_paths: SearchPaths,
             map: &tcx.map,
             maybe_typed: Typed(tcx),
             input: input,
-            populated_crate_impls: RefCell::new(FnvHashSet()),
+            populated_all_crate_impls: Cell::new(false),
             deref_trait_did: Cell::new(None),
             deref_mut_trait_did: Cell::new(None),
             access_levels: RefCell::new(access_levels),
-            external_traits: RefCell::new(FnvHashMap()),
-            renderinfo: RefCell::new(Default::default()),
+            external_traits: Default::default(),
+            renderinfo: Default::default(),
+            ty_substs: Default::default(),
+            lt_substs: Default::default(),
         };
         debug!("crate: {:?}", ctxt.map.krate());
 
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index c2404f4294e..609ae0c0e6d 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -21,6 +21,7 @@ use syntax::ptr::P;
 use syntax_pos::{self, Span};
 
 use rustc::hir;
+use rustc::hir::def_id::CrateNum;
 
 pub struct Module {
     pub name: Option<Name>,
@@ -53,7 +54,7 @@ impl Module {
     pub fn new(name: Option<Name>) -> Module {
         Module {
             name       : name,
-            id: 0,
+            id: ast::CRATE_NODE_ID,
             vis: hir::Inherited,
             stab: None,
             depr: None,
@@ -245,7 +246,7 @@ pub struct Macro {
 
 pub struct ExternCrate {
     pub name: Name,
-    pub cnum: ast::CrateNum,
+    pub cnum: CrateNum,
     pub path: Option<String>,
     pub vis: hir::Visibility,
     pub attrs: hir::HirVec<ast::Attribute>,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 65992798ab0..adcdc7aaab4 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,8 +18,7 @@
 use std::fmt;
 use std::iter::repeat;
 
-use rustc::middle::cstore::LOCAL_CRATE;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use syntax::abi::Abi;
 use rustc::hir;
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 8cc9bbb422a..03d772d1a6d 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -53,10 +53,9 @@ use std::sync::Arc;
 use externalfiles::ExternalHtml;
 
 use serialize::json::{ToJson, Json, as_json};
-use syntax::{abi, ast};
+use syntax::abi;
 use syntax::feature_gate::UnstableFeatures;
-use rustc::middle::cstore::LOCAL_CRATE;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc::session::config::get_unstable_features_setting;
@@ -246,10 +245,10 @@ pub struct Cache {
     pub implementors: FnvHashMap<DefId, Vec<Implementor>>,
 
     /// Cache of where external crate documentation can be found.
-    pub extern_locations: FnvHashMap<ast::CrateNum, (String, ExternalLocation)>,
+    pub extern_locations: FnvHashMap<CrateNum, (String, ExternalLocation)>,
 
     /// Cache of where documentation for primitives can be found.
-    pub primitive_locations: FnvHashMap<clean::PrimitiveType, ast::CrateNum>,
+    pub primitive_locations: FnvHashMap<clean::PrimitiveType, CrateNum>,
 
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 851cf95f996..4518945dd98 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cell::{RefCell, Cell};
+use std::cell::Cell;
 use std::env;
 use std::ffi::OsString;
 use std::io::prelude::*;
@@ -28,7 +28,6 @@ use rustc::session::{self, config};
 use rustc::session::config::{get_unstable_features_setting, OutputType,
                              OutputTypes, Externs};
 use rustc::session::search_paths::{SearchPaths, PathKind};
-use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_back::dynamic_lib::DynamicLibrary;
 use rustc_back::tempdir::TempDir;
 use rustc_driver::{driver, Compilation};
@@ -107,12 +106,14 @@ pub fn run(input: &str,
         map: &map,
         maybe_typed: core::NotTyped(&sess),
         input: input,
-        external_traits: RefCell::new(FnvHashMap()),
-        populated_crate_impls: RefCell::new(FnvHashSet()),
+        populated_all_crate_impls: Cell::new(false),
+        external_traits: Default::default(),
         deref_trait_did: Cell::new(None),
         deref_mut_trait_did: Cell::new(None),
         access_levels: Default::default(),
         renderinfo: Default::default(),
+        ty_substs: Default::default(),
+        lt_substs: Default::default(),
     };
 
     let mut v = RustdocVisitor::new(&ctx);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 16a6e994b5a..a29566f7a07 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -20,6 +20,7 @@ use syntax_pos::Span;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::def::Def;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::middle::privacy::AccessLevel;
 use rustc::util::nodemap::FnvHashSet;
 
@@ -339,7 +340,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 let cstore = &self.cx.sess().cstore;
                 om.extern_crates.push(ExternCrate {
                     cnum: cstore.extern_mod_stmt_cnum(item.id)
-                                .unwrap_or(ast::CrateNum::max_value()),
+                                .unwrap_or(LOCAL_CRATE),
                     name: name,
                     path: p.map(|x|x.to_string()),
                     vis: item.vis.clone(),
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 3af030706b7..285b47fe60a 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::middle::cstore::{CrateStore, ChildItem, DefLike};
+use rustc::middle::cstore::CrateStore;
 use rustc::middle::privacy::{AccessLevels, AccessLevel};
 use rustc::hir::def::Def;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty::Visibility;
-use syntax::ast;
 
 use std::cell::RefMut;
 
@@ -42,7 +41,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    pub fn visit_lib(&mut self, cnum: ast::CrateNum) {
+    pub fn visit_lib(&mut self, cnum: CrateNum) {
         let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
         self.update(did, Some(AccessLevel::Public));
         self.visit_mod(did);
@@ -65,45 +64,27 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    pub fn visit_mod(&mut self, did: DefId) {
-        for item in self.cstore.item_children(did) {
-            if let DefLike::DlDef(def) = item.def {
-                match def {
-                    Def::Mod(did) |
-                    Def::ForeignMod(did) |
-                    Def::Trait(did) |
-                    Def::Struct(did) |
-                    Def::Union(did) |
-                    Def::Enum(did) |
-                    Def::TyAlias(did) |
-                    Def::Fn(did) |
-                    Def::Method(did) |
-                    Def::Static(did, _) |
-                    Def::Const(did) => self.visit_item(did, item),
-                    _ => {}
-                }
-            }
+    pub fn visit_mod(&mut self, def_id: DefId) {
+        for item in self.cstore.item_children(def_id) {
+            self.visit_item(item.def_id);
         }
     }
 
-    fn visit_item(&mut self, did: DefId, item: ChildItem) {
-        let inherited_item_level = match item.def {
-            DefLike::DlImpl(..) | DefLike::DlField => unreachable!(),
-            DefLike::DlDef(def) => {
-                match def {
-                    Def::ForeignMod(..) => self.prev_level,
-                    _ => if item.vis == Visibility::Public { self.prev_level } else { None }
-                }
-            }
+    fn visit_item(&mut self, def_id: DefId) {
+        let vis = self.cstore.visibility(def_id);
+        let inherited_item_level = if vis == Visibility::Public {
+            self.prev_level
+        } else {
+            None
         };
 
-        let item_level = self.update(did, inherited_item_level);
+        let item_level = self.update(def_id, inherited_item_level);
 
-        if let DefLike::DlDef(Def::Mod(did)) = item.def {
+        if let Some(Def::Mod(_)) = self.cstore.describe_def(def_id) {
             let orig_level = self.prev_level;
 
             self.prev_level = item_level;
-            self.visit_mod(did);
+            self.visit_mod(def_id);
             self.prev_level = orig_level;
         }
     }
diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs
index 7b5092e8848..ba9bf2b86a6 100644
--- a/src/libserialize/collection_impls.rs
+++ b/src/libserialize/collection_impls.rs
@@ -134,7 +134,7 @@ impl<
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         let mut bits = 0;
         for item in self {
-            bits |= item.to_usize();
+            bits |= 1 << item.to_usize();
         }
         s.emit_usize(bits)
     }
@@ -148,7 +148,7 @@ impl<
         let mut set = EnumSet::new();
         for bit in 0..(mem::size_of::<usize>()*8) {
             if bits & (1 << bit) != 0 {
-                set.insert(CLike::from_usize(1 << bit));
+                set.insert(CLike::from_usize(bit));
             }
         }
         Ok(set)
diff --git a/src/librbml/leb128.rs b/src/libserialize/leb128.rs
index 0c5356c0222..0c5356c0222 100644
--- a/src/librbml/leb128.rs
+++ b/src/libserialize/leb128.rs
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 80cd47c85cc..7cb02e2412c 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -29,8 +29,10 @@ Core encoding and decoding interfaces.
 
 #![feature(box_syntax)]
 #![feature(collections)]
+#![feature(core_intrinsics)]
 #![feature(enumset)]
 #![feature(rustc_private)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unicode)]
 #![feature(question_mark)]
@@ -43,8 +45,10 @@ Core encoding and decoding interfaces.
 extern crate rustc_unicode;
 extern crate collections;
 
-pub use self::serialize::{Decoder, Encoder, Decodable, Encodable,
-                          DecoderHelpers, EncoderHelpers};
+pub use self::serialize::{Decoder, Encoder, Decodable, Encodable};
+
+pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder};
+pub use self::serialize::{UseSpecializedEncodable, UseSpecializedDecodable};
 
 mod serialize;
 mod collection_impls;
@@ -52,6 +56,9 @@ mod collection_impls;
 pub mod hex;
 pub mod json;
 
+pub mod opaque;
+pub mod leb128;
+
 mod rustc_serialize {
     pub use serialize::*;
 }
diff --git a/src/librbml/opaque.rs b/src/libserialize/opaque.rs
index 6dc7a72b1b1..e97834f63ce 100644
--- a/src/librbml/opaque.rs
+++ b/src/libserialize/opaque.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use Error as DecodeError;
-use writer::EncodeResult;
 use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
 use std::io::{self, Write};
 use serialize;
@@ -18,6 +16,8 @@ use serialize;
 // Encoder
 // -----------------------------------------------------------------------------
 
+pub type EncodeResult = io::Result<()>;
+
 pub struct Encoder<'a> {
     pub cursor: &'a mut io::Cursor<Vec<u8>>,
 }
@@ -124,141 +124,12 @@ impl<'a> serialize::Encoder for Encoder<'a> {
         let _ = self.cursor.write_all(v.as_bytes());
         Ok(())
     }
-
-    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
-        where F: FnOnce(&mut Self) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(&mut self,
-                            _v_name: &str,
-                            v_id: usize,
-                            _len: usize,
-                            f: F)
-                            -> EncodeResult
-        where F: FnOnce(&mut Self) -> EncodeResult
-    {
-        self.emit_usize(v_id)?;
-        f(self)
-    }
-
-    fn emit_enum_variant_arg<F>(&mut self, _: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_enum_struct_variant<F>(&mut self,
-                                   v_name: &str,
-                                   v_id: usize,
-                                   cnt: usize,
-                                   f: F)
-                                   -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_enum_variant(v_name, v_id, cnt, f)
-    }
-
-    fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_enum_variant_arg(idx, f)
-    }
-
-    fn emit_struct<F>(&mut self, _: &str, _len: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_struct_field<F>(&mut self, _name: &str, _: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_seq(len, f)
-    }
-
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_seq(len, f)
-    }
-
-    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_option<F>(&mut self, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_enum("Option", f)
-    }
-
-    fn emit_option_none(&mut self) -> EncodeResult {
-        self.emit_enum_variant("None", 0, 0, |_| Ok(()))
-    }
-
-    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_enum_variant("Some", 1, 1, f)
-    }
-
-    fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
-
-    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
-        where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
-    {
-        f(self)
-    }
 }
 
 impl<'a> Encoder<'a> {
     pub fn position(&self) -> usize {
         self.cursor.position() as usize
     }
-
-    pub fn from_rbml<'b: 'c, 'c>(rbml: &'c mut ::writer::Encoder<'b>) -> Encoder<'c> {
-        Encoder { cursor: rbml.writer }
-    }
 }
 
 // -----------------------------------------------------------------------------
@@ -305,7 +176,7 @@ macro_rules! read_sleb128 {
 
 
 impl<'a> serialize::Decoder for Decoder<'a> {
-    type Error = DecodeError;
+    type Error = String;
 
     fn read_nil(&mut self) -> Result<(), Self::Error> {
         Ok(())
@@ -382,138 +253,8 @@ impl<'a> serialize::Decoder for Decoder<'a> {
         Ok(s.to_string())
     }
 
-    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_enum_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
-        where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
-    {
-        let disr = self.read_usize()?;
-        f(self, disr)
-    }
-
-    fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
-        where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
-    {
-        let disr = self.read_usize()?;
-        f(self, disr)
-    }
-
-    fn read_enum_struct_variant_field<T, F>(&mut self,
-                                            _name: &str,
-                                            _idx: usize,
-                                            f: F)
-                                            -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_struct<T, F>(&mut self, _name: &str, _: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_struct_field<T, F>(&mut self, _name: &str, _idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        self.read_seq(move |d, len| {
-            if len == tuple_len {
-                f(d)
-            } else {
-                let err = format!("Invalid tuple length. Expected {}, found {}",
-                                  tuple_len,
-                                  len);
-                Err(DecodeError::Expected(err))
-            }
-        })
-    }
-
-    fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        self.read_seq_elt(idx, f)
-    }
-
-    fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        self.read_tuple(len, f)
-    }
-
-    fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        self.read_tuple_arg(idx, f)
-    }
-
-    fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
-        where F: FnMut(&mut Decoder<'a>, bool) -> Result<T, Self::Error>
-    {
-        self.read_enum("Option", move |this| {
-            this.read_enum_variant(&["None", "Some"], move |this, idx| {
-                match idx {
-                    0 => f(this, false),
-                    1 => f(this, true),
-                    _ => {
-                        let msg = format!("Invalid Option index: {}", idx);
-                        Err(DecodeError::Expected(msg))
-                    }
-                }
-            })
-        })
-    }
-
-    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
-    {
-        let len = self.read_usize()?;
-        f(self, len)
-    }
-
-    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
-    {
-        let len = self.read_usize()?;
-        f(self, len)
-    }
-
-    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
-    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Decoder<'a>) -> Result<T, Self::Error>
-    {
-        f(self)
-    }
-
     fn error(&mut self, err: &str) -> Self::Error {
-        DecodeError::ApplicationError(err.to_string())
+        err.to_string()
     }
 }
 
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index 8e271597dfc..6650a981884 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -14,6 +14,7 @@
 Core encoding and decoding interfaces.
 */
 
+use std::intrinsics;
 use std::path;
 use std::rc::Rc;
 use std::cell::{Cell, RefCell};
@@ -41,66 +42,99 @@ pub trait Encoder {
     fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
 
     // Compound types:
-    fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+    fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 
-    fn emit_enum_variant<F>(&mut self, v_name: &str,
+    fn emit_enum_variant<F>(&mut self, _v_name: &str,
                             v_id: usize,
-                            len: usize,
+                            _len: usize,
                             f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F)
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_usize(v_id)?;
+        f(self)
+    }
+    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F)
                                 -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 
     fn emit_enum_struct_variant<F>(&mut self, v_name: &str,
                                    v_id: usize,
                                    len: usize,
                                    f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_enum_variant(v_name, v_id, len, f)
+    }
     fn emit_enum_struct_variant_field<F>(&mut self,
-                                         f_name: &str,
+                                         _f_name: &str,
                                          f_idx: usize,
                                          f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_enum_variant_arg(f_idx, f)
+    }
 
-    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F)
+    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F)
                       -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F)
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+    fn emit_struct_field<F>(&mut self, _f_name: &str, _f_idx: usize, f: F)
                             -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+    fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 
-    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F)
+    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F)
                             -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_tuple(len, f)
+    }
     fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F)
                                 -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_tuple_arg(f_idx, f)
+    }
 
     // Specialized types:
     fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_option_none(&mut self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_enum("Option", f)
+    }
+    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
+        self.emit_enum_variant("None", 0, 0, |_| Ok(()))
+    }
     fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+
+        self.emit_enum_variant("Some", 1, 1, f)
+    }
 
     fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_usize(len)?;
+        f(self)
+    }
+    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 
     fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
-    fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error>
-        where F: FnOnce(&mut Self) -> Result<(), Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+    {
+        self.emit_usize(len)?;
+        f(self)
+    }
+    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+        where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
 }
 
 pub trait Decoder {
@@ -125,66 +159,101 @@ pub trait Decoder {
     fn read_str(&mut self) -> Result<String, Self::Error>;
 
     // Compound types:
-    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
-    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
+    fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F)
                                -> Result<T, Self::Error>
-        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>;
-    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F)
+        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
+    {
+        let disr = self.read_usize()?;
+        f(self, disr)
+    }
+    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F)
                                    -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
     fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F)
                                       -> Result<T, Self::Error>
-        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>;
+        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
+    {
+        self.read_enum_variant(names, f)
+    }
     fn read_enum_struct_variant_field<T, F>(&mut self,
-                                            &f_name: &str,
+                                            _f_name: &str,
                                             f_idx: usize,
                                             f: F)
                                             -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+    {
+        self.read_enum_variant_arg(f_idx, f)
+    }
 
-    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
+    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F)
                          -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
     fn read_struct_field<T, F>(&mut self,
-                               f_name: &str,
-                               f_idx: usize,
+                               _f_name: &str,
+                               _f_idx: usize,
                                f: F)
                                -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
-    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
-    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F)
+    fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error>
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+    fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F)
                             -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
-    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F)
+    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F)
                                -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+    {
+        self.read_tuple(len, f)
+    }
     fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F)
                                    -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+    {
+        self.read_tuple_arg(a_idx, f)
+    }
 
     // Specialized types:
-    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
-        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>;
+    fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
+        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>
+    {
+        self.read_enum("Option", move |this| {
+            this.read_enum_variant(&["None", "Some"], move |this, idx| {
+                match idx {
+                    0 => f(this, false),
+                    1 => f(this, true),
+                    _ => Err(this.error("read_option: expected 0 for None or 1 for Some")),
+                }
+            })
+        })
+    }
 
     fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;
-    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
+    {
+        let len = self.read_usize()?;
+        f(self, len)
+    }
+    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
     fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;
-    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
+        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
+    {
+        let len = self.read_usize()?;
+        f(self, len)
+    }
+    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F)
                               -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
-    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F)
                               -> Result<T, Self::Error>
-        where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
+        where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
 
     // Failure
     fn error(&mut self, err: &str) -> Self::Error;
@@ -593,45 +662,97 @@ impl<T:Decodable+Send+Sync> Decodable for Arc<T> {
 }
 
 // ___________________________________________________________________________
-// Helper routines
+// Specialization-based interface for multi-dispatch Encodable/Decodable.
 
-pub trait EncoderHelpers: Encoder {
-    fn emit_from_vec<T, F>(&mut self, v: &[T], f: F)
-                           -> Result<(), Self::Error>
-        where F: FnMut(&mut Self, &T) -> Result<(), Self::Error>;
+/// Implement this trait on your `{Encodable,Decodable}::Error` types
+/// to override the default panic behavior for missing specializations.
+pub trait SpecializationError {
+    /// Create an error for a missing method specialization.
+    /// Defaults to panicking with type, trait & method names.
+    /// `S` is the encoder/decoder state type,
+    /// `T` is the type being encoded/decoded, and
+    /// the arguments are the names of the trait
+    /// and method that should've been overriden.
+    fn not_found<S, T: ?Sized>(trait_name: &'static str,
+                               method_name: &'static str) -> Self;
 }
 
-impl<S:Encoder> EncoderHelpers for S {
-    fn emit_from_vec<T, F>(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where
-        F: FnMut(&mut S, &T) -> Result<(), S::Error>,
-    {
-        self.emit_seq(v.len(), |this| {
-            for (i, e) in v.iter().enumerate() {
-                this.emit_seq_elt(i, |this| {
-                    f(this, e)
-                })?;
-            }
-            Ok(())
-        })
+impl<E> SpecializationError for E {
+    default fn not_found<S, T: ?Sized>(trait_name: &'static str,
+                                       method_name: &'static str) -> E {
+        panic!("missing specializaiton: `<{} as {}<{}>>::{}` not overriden",
+               unsafe { intrinsics::type_name::<S>() },
+               trait_name,
+               unsafe { intrinsics::type_name::<T>() },
+               method_name);
     }
 }
 
-pub trait DecoderHelpers: Decoder {
-    fn read_to_vec<T, F>(&mut self, f: F)
-                         -> Result<Vec<T>, Self::Error> where
-        F: FnMut(&mut Self) -> Result<T, Self::Error>;
+/// Implement this trait on encoders, with `T` being the type
+/// you want to encode (employing `UseSpecializedEncodable`),
+/// using a strategy specific to the encoder.
+pub trait SpecializedEncoder<T: ?Sized + UseSpecializedEncodable>: Encoder {
+    /// Encode the value in a manner specific to this encoder state.
+    fn specialized_encode(&mut self, value: &T) -> Result<(), Self::Error>;
 }
 
-impl<D: Decoder> DecoderHelpers for D {
-    fn read_to_vec<T, F>(&mut self, mut f: F) -> Result<Vec<T>, D::Error> where F:
-        FnMut(&mut D) -> Result<T, D::Error>,
-    {
-        self.read_seq(|this, len| {
-            let mut v = Vec::with_capacity(len);
-            for i in 0..len {
-                v.push(this.read_seq_elt(i, |this| f(this))?);
-            }
-            Ok(v)
-        })
+impl<E: Encoder, T: ?Sized + UseSpecializedEncodable> SpecializedEncoder<T> for E {
+    default fn specialized_encode(&mut self, value: &T) -> Result<(), E::Error> {
+        value.default_encode(self)
+    }
+}
+
+/// Implement this trait on decoders, with `T` being the type
+/// you want to decode (employing `UseSpecializedDecodable`),
+/// using a strategy specific to the decoder.
+pub trait SpecializedDecoder<T: UseSpecializedDecodable>: Decoder {
+    /// Decode a value in a manner specific to this decoder state.
+    fn specialized_decode(&mut self) -> Result<T, Self::Error>;
+}
+
+impl<D: Decoder, T: UseSpecializedDecodable> SpecializedDecoder<T> for D {
+    default fn specialized_decode(&mut self) -> Result<T, D::Error> {
+        T::default_decode(self)
+    }
+}
+
+/// Implement this trait on your type to get an `Encodable`
+/// implementation which goes through `SpecializedEncoder`.
+pub trait UseSpecializedEncodable {
+    /// Defaults to returning an error (see `SpecializationError`).
+    fn default_encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
+        Err(E::Error::not_found::<E, Self>("SpecializedEncoder", "specialized_encode"))
+    }
+}
+
+impl<T: ?Sized + UseSpecializedEncodable> Encodable for T {
+    default fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+        E::specialized_encode(e, self)
+    }
+}
+
+/// Implement this trait on your type to get an `Decodable`
+/// implementation which goes through `SpecializedDecoder`.
+pub trait UseSpecializedDecodable: Sized {
+    /// Defaults to returning an error (see `SpecializationError`).
+    fn default_decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
+        Err(D::Error::not_found::<D, Self>("SpecializedDecoder", "specialized_decode"))
     }
 }
+
+impl<T: UseSpecializedDecodable> Decodable for T {
+    default fn decode<D: Decoder>(d: &mut D) -> Result<T, D::Error> {
+        D::specialized_decode(d)
+    }
+}
+
+// Can't avoid specialization for &T and Box<T> impls,
+// as proxy impls on them are blankets that conflict
+// with the Encodable and Decodable impls above,
+// which only have `default` on their methods
+// for this exact reason.
+// May be fixable in a simpler fashion via the
+// more complex lattice model for specialization.
+impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {}
+impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> {}
+impl<T: Decodable> UseSpecializedDecodable for Box<T> {}
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 40c8ba93bd5..c18b36161df 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -27,7 +27,9 @@ use tokenstream::{TokenTree};
 
 use std::fmt;
 use std::rc::Rc;
-use serialize::{Encodable, Decodable, Encoder, Decoder};
+use std::u32;
+
+use serialize::{self, Encodable, Decodable, Encoder, Decoder};
 
 /// A name is a part of an identifier, representing a string or gensym. It's
 /// the result of interning.
@@ -298,17 +300,53 @@ pub struct ParenthesizedParameterData {
     pub output: Option<P<Ty>>,
 }
 
-pub type CrateNum = u32;
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
+pub struct NodeId(u32);
+
+impl NodeId {
+    pub fn new(x: usize) -> NodeId {
+        assert!(x < (u32::MAX as usize));
+        NodeId(x as u32)
+    }
+
+    pub fn from_u32(x: u32) -> NodeId {
+        NodeId(x)
+    }
+
+    pub fn as_usize(&self) -> usize {
+        self.0 as usize
+    }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
+}
 
-pub type NodeId = u32;
+impl fmt::Display for NodeId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
+
+impl serialize::UseSpecializedEncodable for NodeId {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_u32(self.0)
+    }
+}
+
+impl serialize::UseSpecializedDecodable for NodeId {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<NodeId, D::Error> {
+        d.read_u32().map(NodeId)
+    }
+}
 
 /// Node id used to represent the root of the crate.
-pub const CRATE_NODE_ID: NodeId = 0;
+pub const CRATE_NODE_ID: NodeId = NodeId(0);
 
 /// When parsing and doing expansions, we initially give all AST nodes this AST
 /// node value. Then later, in the renumber pass, we renumber them to have
 /// small, positive ids.
-pub const DUMMY_NODE_ID: NodeId = !0;
+pub const DUMMY_NODE_ID: NodeId = NodeId(!0);
 
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 81ee96459fd..dc02c26039c 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -895,7 +895,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                         "packed" => Some(ReprPacked),
                         "simd" => Some(ReprSimd),
                         _ => match int_type_of_word(word) {
-                            Some(ity) => Some(ReprInt(item.span, ity)),
+                            Some(ity) => Some(ReprInt(ity)),
                             None => {
                                 // Not a word we recognize
                                 span_err!(diagnostic, item.span, E0552,
@@ -939,7 +939,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum ReprAttr {
     ReprAny,
-    ReprInt(Span, IntType),
+    ReprInt(IntType),
     ReprExtern,
     ReprPacked,
     ReprSimd,
@@ -949,7 +949,7 @@ impl ReprAttr {
     pub fn is_ffi_safe(&self) -> bool {
         match *self {
             ReprAny => false,
-            ReprInt(_sp, ity) => ity.is_ffi_safe(),
+            ReprInt(ity) => ity.is_ffi_safe(),
             ReprExtern => true,
             ReprPacked => false,
             ReprSimd => true,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 4e87d8ee9dd..db0183a8b3a 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -242,11 +242,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
                 let expansion = expansion.fold_with(&mut placeholder_expander);
-                placeholder_expander.add(mark, expansion);
+                placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
             }
         }
 
-        placeholder_expander.remove(0)
+        placeholder_expander.remove(ast::NodeId::from_u32(0))
     }
 
     fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
@@ -424,7 +424,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             expansion_kind: expansion_kind,
             expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
         });
-        placeholder(expansion_kind, mark.as_u32())
+        placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
     }
 
     fn collect_bang(
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 4a2c9aff2d2..118ceb17ab4 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -33,6 +33,7 @@
 #![feature(unicode)]
 #![feature(question_mark)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(specialization)]
 
 extern crate serialize;
 extern crate term;
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 339a6c477cc..e307925a6ed 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -780,17 +780,17 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
                 attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
                 attr::ReprExtern => "i32",
 
-                attr::ReprInt(_, attr::SignedInt(ast::IntTy::Is)) => "isize",
-                attr::ReprInt(_, attr::SignedInt(ast::IntTy::I8)) => "i8",
-                attr::ReprInt(_, attr::SignedInt(ast::IntTy::I16)) => "i16",
-                attr::ReprInt(_, attr::SignedInt(ast::IntTy::I32)) => "i32",
-                attr::ReprInt(_, attr::SignedInt(ast::IntTy::I64)) => "i64",
-
-                attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::Us)) => "usize",
-                attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U8)) => "u8",
-                attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U16)) => "u16",
-                attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U32)) => "u32",
-                attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U64)) => "u64",
+                attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
+                attr::ReprInt(attr::SignedInt(ast::IntTy::I8)) => "i8",
+                attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16",
+                attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32",
+                attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64",
+
+                attr::ReprInt(attr::UnsignedInt(ast::UintTy::Us)) => "usize",
+                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8",
+                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16",
+                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32",
+                attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64",
             }
         }
     }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index d835f8058fa..8c8b4173fe5 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -28,6 +28,7 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(question_mark)]
+#![feature(specialization)]
 
 use std::cell::{Cell, RefCell};
 use std::ops::{Add, Sub};
@@ -137,8 +138,8 @@ pub struct SpanLabel {
     pub label: Option<String>,
 }
 
-impl Encodable for Span {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+impl serialize::UseSpecializedEncodable for Span {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_struct("Span", 2, |s| {
             s.emit_struct_field("lo", 0, |s| {
                 self.lo.encode(s)
@@ -151,17 +152,11 @@ impl Encodable for Span {
     }
 }
 
-impl Decodable for Span {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
+impl serialize::UseSpecializedDecodable for Span {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
         d.read_struct("Span", 2, |d| {
-            let lo = d.read_struct_field("lo", 0, |d| {
-                BytePos::decode(d)
-            })?;
-
-            let hi = d.read_struct_field("hi", 1, |d| {
-                BytePos::decode(d)
-            })?;
-
+            let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
+            let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
             Ok(mk_sp(lo, hi))
         })
     }
diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock
index 3377fc43d8a..69e3eab22e9 100644
--- a/src/rustc/Cargo.lock
+++ b/src/rustc/Cargo.lock
@@ -51,14 +51,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rbml"
-version = "0.0.0"
-dependencies = [
- "log 0.0.0",
- "serialize 0.0.0",
-]
-
-[[package]]
 name = "rustc"
 version = "0.0.0"
 dependencies = [
@@ -67,7 +59,6 @@ dependencies = [
  "fmt_macros 0.0.0",
  "graphviz 0.0.0",
  "log 0.0.0",
- "rbml 0.0.0",
  "rustc_back 0.0.0",
  "rustc_bitflags 0.0.0",
  "rustc_const_math 0.0.0",
@@ -185,7 +176,6 @@ version = "0.0.0"
 dependencies = [
  "graphviz 0.0.0",
  "log 0.0.0",
- "rbml 0.0.0",
  "rustc 0.0.0",
  "rustc_data_structures 0.0.0",
  "serialize 0.0.0",
@@ -227,10 +217,8 @@ version = "0.0.0"
 dependencies = [
  "flate 0.0.0",
  "log 0.0.0",
- "rbml 0.0.0",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
- "rustc_bitflags 0.0.0",
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index b7725251220..ad466671cf7 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -31,6 +31,7 @@ impl<T> Trait for Struct<T> {
 fn main() {
     let s1 = Struct { _a: 0u32 };
 
+    //~ TRANS_ITEM drop-glue i8
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
     let _ = &s1 as &Trait;
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index 45ba441bc8b..cd4cc258f7a 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -57,6 +57,7 @@ fn main()
 {
     // simple case
     let bool_sized = &true;
+    //~ TRANS_ITEM drop-glue i8
     //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0]
     let _bool_unsized = bool_sized as &Trait;
 
diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs
index ee5e97cd9c2..0007eaae289 100644
--- a/src/test/codegen-units/partitioning/vtable-through-const.rs
+++ b/src/test/codegen-units/partitioning/vtable-through-const.rs
@@ -69,6 +69,7 @@ mod mod1 {
 
 //~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[External]
 fn main() {
+    //~ TRANS_ITEM drop-glue i8 @@ vtable_through_const[Internal]
 
     // Since Trait1::do_something() is instantiated via its default implementation,
     // it is considered a generic and is instantiated here only because it is
diff --git a/src/test/compile-fail/auxiliary/issue_19452_aux.rs b/src/test/compile-fail/auxiliary/issue_19452_aux.rs
new file mode 100644
index 00000000000..205566e4b1f
--- /dev/null
+++ b/src/test/compile-fail/auxiliary/issue_19452_aux.rs
@@ -0,0 +1,13 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub enum Homura {
+    Madoka { age: u32 }
+}
diff --git a/src/test/compile-fail/issue-19452.rs b/src/test/compile-fail/issue-19452.rs
index 15d5d2b80c3..34872b7c8c5 100644
--- a/src/test/compile-fail/issue-19452.rs
+++ b/src/test/compile-fail/issue-19452.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// aux-build:issue_19452_aux.rs
+extern crate issue_19452_aux;
+
 enum Homura {
     Madoka { age: u32 }
 }
@@ -16,4 +19,8 @@ fn main() {
     let homura = Homura::Madoka;
     //~^ ERROR uses it like a function
     //~| struct called like a function
+
+    let homura = issue_19452_aux::Homura::Madoka;
+    //~^ ERROR uses it like a function
+    //~| struct called like a function
 }
diff --git a/src/test/run-pass-fulldeps/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs
index 9da04f72355..914e3dd4932 100644
--- a/src/test/run-pass-fulldeps/issue-11881.rs
+++ b/src/test/run-pass-fulldeps/issue-11881.rs
@@ -11,7 +11,6 @@
 
 #![feature(rustc_private)]
 
-extern crate rbml;
 extern crate serialize;
 
 use std::io::Cursor;
@@ -21,8 +20,7 @@ use std::slice;
 
 use serialize::{Encodable, Encoder};
 use serialize::json;
-
-use rbml::writer;
+use serialize::opaque;
 
 #[derive(Encodable)]
 struct Foo {
@@ -36,15 +34,15 @@ struct Bar {
 
 enum WireProtocol {
     JSON,
-    RBML,
+    Opaque,
     // ...
 }
 
 fn encode_json<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
     write!(wr, "{}", json::as_json(val));
 }
-fn encode_rbml<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
-    let mut encoder = writer::Encoder::new(wr);
+fn encode_opaque<T: Encodable>(val: &T, wr: &mut Cursor<Vec<u8>>) {
+    let mut encoder = opaque::Encoder::new(wr);
     val.encode(&mut encoder);
 }
 
@@ -54,6 +52,6 @@ pub fn main() {
     let proto = WireProtocol::JSON;
     match proto {
         WireProtocol::JSON => encode_json(&target, &mut wr),
-        WireProtocol::RBML => encode_rbml(&target, &mut wr)
+        WireProtocol::Opaque => encode_opaque(&target, &mut wr)
     }
 }
diff --git a/src/test/run-pass/auxiliary/issue-17718-aux.rs b/src/test/run-pass/auxiliary/issue-17718-aux.rs
index 373fc042175..cf7fdd7f983 100644
--- a/src/test/run-pass/auxiliary/issue-17718-aux.rs
+++ b/src/test/run-pass/auxiliary/issue-17718-aux.rs
@@ -14,11 +14,10 @@ use std::sync::atomic;
 
 pub const C1: usize = 1;
 pub const C2: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-pub const C3: fn() = foo;
+pub const C3: fn() = { fn foo() {} foo };
 pub const C4: usize = C1 * C1 + C1 / C1;
 pub const C5: &'static usize = &C4;
 
 pub static S1: usize = 3;
 pub static S2: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
 
-fn foo() {}
diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs
index 36650368d57..54d5415a553 100644
--- a/src/test/run-pass/typeid-intrinsic.rs
+++ b/src/test/run-pass/typeid-intrinsic.rs
@@ -87,4 +87,8 @@ pub fn main() {
     assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator());
     assert!(other1::id_i32_iterator() != other1::id_u32_iterator());
     assert!(TypeId::of::<other1::I32Iterator>() != TypeId::of::<other1::U32Iterator>());
+
+    // Check fn pointer against collisions
+    assert!(TypeId::of::<fn(fn(A) -> A) -> A>() !=
+            TypeId::of::<fn(fn() -> A, A) -> A>());
 }