about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/book/syntax-index.md2
-rw-r--r--src/doc/reference.md8
-rw-r--r--src/libpanic_abort/lib.rs2
-rw-r--r--src/librustc/cfg/construct.rs12
-rw-r--r--src/librustc/cfg/mod.rs4
-rw-r--r--src/librustc/dep_graph/dep_node.rs12
-rw-r--r--src/librustc/diagnostics.rs114
-rw-r--r--src/librustc/hir/intravisit.rs8
-rw-r--r--src/librustc/hir/lowering.rs13
-rw-r--r--src/librustc/hir/map/blocks.rs43
-rw-r--r--src/librustc/hir/map/collector.rs2
-rw-r--r--src/librustc/hir/mod.rs8
-rw-r--r--src/librustc/hir/print.rs34
-rw-r--r--src/librustc/lint/context.rs10
-rw-r--r--src/librustc/lint/mod.rs8
-rw-r--r--src/librustc/middle/cstore.rs14
-rw-r--r--src/librustc/middle/dataflow.rs8
-rw-r--r--src/librustc/middle/dead.rs13
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs10
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/liveness.rs93
-rw-r--r--src/librustc/middle/reachable.rs12
-rw-r--r--src/librustc/middle/region.rs13
-rw-r--r--src/librustc/middle/resolve_lifetime.rs10
-rw-r--r--src/librustc/middle/stability.rs20
-rw-r--r--src/librustc/traits/error_reporting.rs14
-rw-r--r--src/librustc/traits/mod.rs20
-rw-r--r--src/librustc/traits/object_safety.rs48
-rw-r--r--src/librustc/traits/project.rs26
-rw-r--r--src/librustc/traits/specialize/mod.rs3
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs142
-rw-r--r--src/librustc/traits/util.rs16
-rw-r--r--src/librustc/ty/context.rs22
-rw-r--r--src/librustc/ty/maps.rs8
-rw-r--r--src/librustc/ty/mod.rs396
-rw-r--r--src/librustc/util/ppaux.rs26
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs12
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs4
-rw-r--r--src/librustc_const_eval/eval.rs12
-rw-r--r--src/librustc_driver/lib.rs2
-rw-r--r--src/librustc_driver/pretty.rs11
-rw-r--r--src/librustc_lint/bad_style.rs6
-rw-r--r--src/librustc_lint/builtin.rs16
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_llvm/build.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs12
-rw-r--r--src/librustc_metadata/decoder.rs45
-rw-r--r--src/librustc_metadata/encoder.rs84
-rw-r--r--src/librustc_metadata/schema.rs10
-rw-r--r--src/librustc_mir/build/mod.rs22
-rw-r--r--src/librustc_mir/hair/cx/mod.rs22
-rw-r--r--src/librustc_mir/mir_map.rs2
-rw-r--r--src/librustc_passes/consts.rs8
-rw-r--r--src/librustc_passes/hir_stats.rs5
-rw-r--r--src/librustc_passes/loops.rs2
-rw-r--r--src/librustc_passes/rvalues.rs2
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/lib.rs69
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs26
-rw-r--r--src/librustc_save_analysis/lib.rs57
-rw-r--r--src/librustc_trans/collector.rs21
-rw-r--r--src/librustc_trans/mir/constant.rs9
-rw-r--r--src/librustc_typeck/astconv.rs234
-rw-r--r--src/librustc_typeck/check/_match.rs26
-rw-r--r--src/librustc_typeck/check/closure.rs4
-rw-r--r--src/librustc_typeck/check/compare_method.rs153
-rw-r--r--src/librustc_typeck/check/dropck.rs6
-rw-r--r--src/librustc_typeck/check/method/confirm.rs90
-rw-r--r--src/librustc_typeck/check/method/mod.rs142
-rw-r--r--src/librustc_typeck/check/method/probe.rs109
-rw-r--r--src/librustc_typeck/check/method/suggest.rs31
-rw-r--r--src/librustc_typeck/check/mod.rs670
-rw-r--r--src/librustc_typeck/check/op.rs5
-rw-r--r--src/librustc_typeck/check/regionck.rs14
-rw-r--r--src/librustc_typeck/check/upvar.rs19
-rw-r--r--src/librustc_typeck/check/wfcheck.rs115
-rw-r--r--src/librustc_typeck/check/writeback.rs4
-rw-r--r--src/librustc_typeck/coherence/mod.rs24
-rw-r--r--src/librustc_typeck/coherence/overlap.rs30
-rw-r--r--src/librustc_typeck/collect.rs237
-rw-r--r--src/librustdoc/clean/inline.rs51
-rw-r--r--src/librustdoc/clean/mod.rs224
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/ext/build.rs45
-rw-r--r--src/libsyntax/feature_gate.rs11
-rw-r--r--src/libsyntax/fold.rs2
-rw-r--r--src/libsyntax/parse/parser.rs19
-rw-r--r--src/libsyntax/print/pprust.rs22
-rw-r--r--src/libsyntax/util/node_count.rs4
-rw-r--r--src/libsyntax/visit.rs53
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs6
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs6
-rw-r--r--src/test/compile-fail/E0138.rs4
-rw-r--r--src/test/compile-fail/consider-removing-last-semi.rs4
-rw-r--r--src/test/compile-fail/diverging-fn-tail-35849.rs4
-rw-r--r--src/test/compile-fail/issue-11714.rs2
-rw-r--r--src/test/compile-fail/issue-13428.rs4
-rw-r--r--src/test/compile-fail/issue-22645.rs2
-rw-r--r--src/test/compile-fail/issue-22684.rs2
-rw-r--r--src/test/compile-fail/issue-29161.rs2
-rw-r--r--src/test/compile-fail/issue-32323.rs2
-rw-r--r--src/test/compile-fail/issue-5239-1.rs2
-rw-r--r--src/test/compile-fail/issue-6458-4.rs7
-rw-r--r--src/test/compile-fail/liveness-forgot-ret.rs3
-rw-r--r--src/test/compile-fail/liveness-issue-2163.rs2
-rw-r--r--src/test/compile-fail/liveness-missing-ret2.rs4
-rw-r--r--src/test/compile-fail/liveness-return-last-stmt-semi.rs8
-rw-r--r--src/test/compile-fail/main-wrong-type-2.rs1
-rw-r--r--src/test/compile-fail/on-unimplemented/on-trait.rs2
-rw-r--r--src/test/compile-fail/private-in-public-lint.rs4
-rw-r--r--src/test/compile-fail/required-lang-item.rs1
-rw-r--r--src/test/compile-fail/unreachable-in-call.rs2
-rw-r--r--src/test/compile-fail/where-clauses-unsatisfied.rs3
-rw-r--r--src/test/parse-fail/closure-return-syntax.rs3
-rw-r--r--src/test/pretty/issue-4264.pp124
-rw-r--r--src/test/pretty/stmt_expr_attributes.rs22
-rw-r--r--src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot4
148 files changed, 1827 insertions, 2524 deletions
diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md
index 1e05b01d30d..28403711cd7 100644
--- a/src/doc/book/syntax-index.md
+++ b/src/doc/book/syntax-index.md
@@ -94,6 +94,7 @@
 * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
 * `||` (`expr || expr`): logical or.
 * `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
+* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro].
 
 ## Other Syntax
 
@@ -210,6 +211,7 @@
 [Functions]: functions.html
 [Generics]: generics.html
 [Iterators]: iterators.html
+[`try!` macro]: error-handling.html#the-try-macro
 [Lifetimes]: lifetimes.html
 [Loops (`for`)]: loops.html#for
 [Loops (`loop`)]: loops.html#loop
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 7233dbc618a..0596e476d5f 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2863,8 +2863,8 @@ assert_eq!(x, y);
 
 ### Unary operator expressions
 
-Rust defines the following unary operators. They are all written as prefix operators,
-before the expression they apply to.
+Rust defines the following unary operators. With the exception of `?`, they are
+all written as prefix operators, before the expression they apply to.
 
 * `-`
   : Negation. Signed integer types and floating-point types support negation. It
@@ -2893,6 +2893,10 @@ before the expression they apply to.
     If the `&` or `&mut` operators are applied to an rvalue, a
     temporary value is created; the lifetime of this temporary value
     is defined by [syntactic rules](#temporary-lifetimes).
+* `?`
+  : Propagating errors if applied to `Err(_)` and unwrapping if
+    applied to `Ok(_)`. Only works on the `Result<T, E>` type,
+    and written in postfix notation.
 
 ### Binary operator expressions
 
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index b87160dd75d..853f81ceaa9 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
 // now hopefully.
 #[no_mangle]
 pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
-    return abort();
+    abort();
 
     #[cfg(unix)]
     unsafe fn abort() -> ! {
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index a2fc6e044e7..22c7d14be29 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -33,16 +33,16 @@ struct LoopScope {
 }
 
 pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           blk: &hir::Block) -> CFG {
+                           body: &hir::Expr) -> CFG {
     let mut graph = graph::Graph::new();
     let entry = graph.add_node(CFGNodeData::Entry);
 
     // `fn_exit` is target of return exprs, which lies somewhere
-    // outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
+    // outside input `body`. (Distinguishing `fn_exit` and `body_exit`
     // also resolves chicken-and-egg problem that arises if you try to
-    // have return exprs jump to `block_exit` during construction.)
+    // have return exprs jump to `body_exit` during construction.)
     let fn_exit = graph.add_node(CFGNodeData::Exit);
-    let block_exit;
+    let body_exit;
 
     let mut cfg_builder = CFGBuilder {
         graph: graph,
@@ -50,8 +50,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx: tcx,
         loop_scopes: Vec::new()
     };
-    block_exit = cfg_builder.block(blk, entry);
-    cfg_builder.add_contained_edge(block_exit, fn_exit);
+    body_exit = cfg_builder.expr(body, entry);
+    cfg_builder.add_contained_edge(body_exit, fn_exit);
     let CFGBuilder {graph, ..} = cfg_builder;
     CFG {graph: graph,
          entry: entry,
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index d06f51073df..43434b884c8 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge<CFGEdgeData>;
 
 impl CFG {
     pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         blk: &hir::Block) -> CFG {
-        construct::construct(tcx, blk)
+                         body: &hir::Expr) -> CFG {
+        construct::construct(tcx, body)
     }
 
     pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index e99ffa95ed6..351feaba034 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -103,11 +103,11 @@ pub enum DepNode<D: Clone + Debug> {
     // 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`).
-    ImplOrTraitItems(D),
+    AssociatedItems(D),
     ItemSignature(D),
     FieldTy(D),
     SizedConstraint(D),
-    ImplOrTraitItemDefIds(D),
+    AssociatedItemDefIds(D),
     InherentImpls(D),
 
     // The set of impls for a given trait. Ultimately, it would be
@@ -153,10 +153,10 @@ impl<D: Clone + Debug> DepNode<D> {
             TransCrateItem,
             TypeckItemType,
             TypeckItemBody,
-            ImplOrTraitItems,
+            AssociatedItems,
             ItemSignature,
             FieldTy,
-            ImplOrTraitItemDefIds,
+            AssociatedItemDefIds,
             InherentImpls,
             TraitImpls,
             ReprHints,
@@ -219,11 +219,11 @@ impl<D: Clone + Debug> DepNode<D> {
             RvalueCheck(ref d) => op(d).map(RvalueCheck),
             TransCrateItem(ref d) => op(d).map(TransCrateItem),
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
-            ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
+            AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
             FieldTy(ref d) => op(d).map(FieldTy),
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
-            ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds),
+            AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 465a09505e4..ec09877ae12 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -672,120 +672,6 @@ extern "C" {
 ```
 "##,
 
-E0269: r##"
-A returned value was expected but not all control paths return one.
-
-Erroneous code example:
-
-```compile_fail,E0269
-fn abracada_FAIL() -> String {
-    "this won't work".to_string();
-    // error: not all control paths return a value
-}
-```
-
-In the previous code, the function is supposed to return a `String`, however,
-the code returns nothing (because of the ';'). Another erroneous code would be:
-
-```compile_fail
-fn abracada_FAIL(b: bool) -> u32 {
-    if b {
-        0
-    } else {
-        "a" // It fails because an `u32` was expected and something else is
-            // returned.
-    }
-}
-```
-
-It is advisable to find out what the unhandled cases are and check for them,
-returning an appropriate value or panicking if necessary. Check if you need
-to remove a semicolon from the last expression, like in the first erroneous
-code example.
-"##,
-
-E0270: r##"
-Rust lets you define functions which are known to never return, i.e. are
-'diverging', by marking its return type as `!`.
-
-For example, the following functions never return:
-
-```no_run
-fn foo() -> ! {
-    loop {}
-}
-
-fn bar() -> ! {
-    foo() // foo() is diverging, so this will diverge too
-}
-
-fn baz() -> ! {
-    panic!(); // this macro internally expands to a call to a diverging function
-}
-```
-
-Such functions can be used in a place where a value is expected without
-returning a value of that type, for instance:
-
-```no_run
-fn foo() -> ! {
-    loop {}
-}
-
-let x = 3;
-
-let y = match x {
-    1 => 1,
-    2 => 4,
-    _ => foo() // diverging function called here
-};
-
-println!("{}", y)
-```
-
-If the third arm of the match block is reached, since `foo()` doesn't ever
-return control to the match block, it is fine to use it in a place where an
-integer was expected. The `match` block will never finish executing, and any
-point where `y` (like the print statement) is needed will not be reached.
-
-However, if we had a diverging function that actually does finish execution:
-
-```ignore
-fn foo() -> ! {
-    loop {break;}
-}
-```
-
-Then we would have an unknown value for `y` in the following code:
-
-```no_run
-fn foo() -> ! {
-    loop {}
-}
-
-let x = 3;
-
-let y = match x {
-    1 => 1,
-    2 => 4,
-    _ => foo()
-};
-
-println!("{}", y);
-```
-
-In the previous example, the print statement was never reached when the
-wildcard match arm was hit, so we were okay with `foo()` not returning an
-integer that we could set to `y`. But in this example, `foo()` actually does
-return control, so the print statement will be executed with an uninitialized
-value.
-
-Obviously we cannot have functions which are allowed to be used in such
-positions and yet can return control. So, if you are defining a function that
-returns `!`, make sure that there is no way for it to actually finish
-executing.
-"##,
-
 E0271: r##"
 This is because of a type mismatch between the associated type of some
 trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index b1771f52da2..9932e5fe686 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized {
     fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
         walk_where_predicate(self, predicate)
     }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) {
         walk_fn(self, fk, fd, b, s, id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem) {
@@ -635,13 +635,13 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
 pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
                                    function_kind: FnKind<'v>,
                                    function_declaration: &'v FnDecl,
-                                   function_body: &'v Block,
+                                   function_body: &'v Expr,
                                    _span: Span,
                                    id: NodeId) {
     visitor.visit_id(id);
     walk_fn_decl(visitor, function_declaration);
     walk_fn_kind(visitor, function_kind);
-    visitor.visit_block(function_body)
+    visitor.visit_expr(function_body)
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
@@ -925,7 +925,7 @@ impl<'v> Visitor<'v> for IdRangeComputingVisitor {
 /// Computes the id range for a single fn body, ignoring nested items.
 pub fn compute_id_range_for_fn_body(fk: FnKind,
                                     decl: &FnDecl,
-                                    body: &Block,
+                                    body: &Expr,
                                     sp: Span,
                                     id: NodeId)
                                     -> IdRange {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e1fec898e41..b985298e47c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemConst(self.lower_ty(t), self.lower_expr(e))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+                let body = self.lower_block(body);
                 hir::ItemFn(self.lower_fn_decl(decl),
                             self.lower_unsafety(unsafety),
                             self.lower_constness(constness),
                             abi,
                             self.lower_generics(generics),
-                            self.lower_block(body))
+                            self.expr_block(body, ThinVec::new()))
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> {
                     }
                     TraitItemKind::Method(ref sig, ref body) => {
                         hir::MethodTraitItem(this.lower_method_sig(sig),
-                                             body.as_ref().map(|x| this.lower_block(x)))
+                                             body.as_ref().map(|x| {
+                            let body = this.lower_block(x);
+                            this.expr_block(body, ThinVec::new())
+                        }))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
                         hir::TypeTraitItem(this.lower_bounds(bounds),
@@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> {
                         hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
+                        let body = this.lower_block(body);
                         hir::ImplItemKind::Method(this.lower_method_sig(sig),
-                                                  this.lower_block(body))
+                                                  this.expr_block(body, ThinVec::new()))
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> {
                     self.with_parent_def(e.id, |this| {
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         this.lower_block(body),
+                                         this.lower_expr(body),
                                          fn_decl_span)
                     })
                 }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 44872348856..325a90ea91e 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -21,11 +21,9 @@
 //! nested within a uniquely determined `FnLike`), and users can ask
 //! for the `Code` associated with a particular NodeId.
 
-pub use self::Code::*;
-
 use hir as ast;
 use hir::map::{self, Node};
-use hir::{Block, FnDecl};
+use hir::{Expr, FnDecl};
 use hir::intravisit::FnKind;
 use syntax::abi;
 use syntax::ast::{Attribute, Name, NodeId};
@@ -50,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
 /// Components shared by fn-like things (fn items, methods, closures).
 pub struct FnParts<'a> {
     pub decl: &'a FnDecl,
-    pub body: &'a Block,
+    pub body: &'a Expr,
     pub kind: FnKind<'a>,
     pub span: Span,
     pub id:   NodeId,
@@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr {
     }
 }
 
-/// Carries either an FnLikeNode or a Block, as these are the two
+/// Carries either an FnLikeNode or a Expr, as these are the two
 /// constructs that correspond to "code" (as in, something from which
 /// we can construct a control-flow graph).
 #[derive(Copy, Clone)]
 pub enum Code<'a> {
-    FnLikeCode(FnLikeNode<'a>),
-    BlockCode(&'a Block),
+    FnLike(FnLikeNode<'a>),
+    Expr(&'a Expr),
 }
 
 impl<'a> Code<'a> {
     pub fn id(&self) -> NodeId {
         match *self {
-            FnLikeCode(node) => node.id(),
-            BlockCode(block) => block.id,
+            Code::FnLike(node) => node.id(),
+            Code::Expr(block) => block.id,
         }
     }
 
-    /// Attempts to construct a Code from presumed FnLike or Block node input.
-    pub fn from_node(node: Node) -> Option<Code> {
-        if let map::NodeBlock(block) = node {
-            Some(BlockCode(block))
-        } else {
-            FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
+    /// Attempts to construct a Code from presumed FnLike or Expr node input.
+    pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
+        match map.get(id) {
+            map::NodeBlock(_) => {
+                //  Use the parent, hopefully an expression node.
+                Code::from_node(map, map.get_parent_node(id))
+            }
+            map::NodeExpr(expr) => Some(Code::Expr(expr)),
+            node => FnLikeNode::from_node(node).map(Code::FnLike)
         }
     }
 }
@@ -114,7 +115,7 @@ struct ItemFnParts<'a> {
     abi:      abi::Abi,
     vis:      &'a ast::Visibility,
     generics: &'a ast::Generics,
-    body:     &'a Block,
+    body:     &'a Expr,
     id:       NodeId,
     span:     Span,
     attrs:    &'a [Attribute],
@@ -124,14 +125,14 @@ struct ItemFnParts<'a> {
 /// for use when implementing FnLikeNode operations.
 struct ClosureParts<'a> {
     decl: &'a FnDecl,
-    body: &'a Block,
+    body: &'a Expr,
     id: NodeId,
     span: Span,
     attrs: &'a [Attribute],
 }
 
 impl<'a> ClosureParts<'a> {
-    fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+    fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
         ClosureParts {
             decl: d,
             body: b,
@@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> {
         }
     }
 
-    pub fn body(self) -> &'a Block {
+    pub fn body(self) -> &'a Expr {
         self.handle(|i: ItemFnParts<'a>|  &*i.body,
-                    |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _|  body,
+                    |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _|  body,
                     |c: ClosureParts<'a>| c.body)
     }
 
@@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
                   Name,
                   &'a ast::MethodSig,
                   Option<&'a ast::Visibility>,
-                  &'a ast::Block,
+                  &'a ast::Expr,
                   Span,
                   &'a [Attribute])
                   -> A,
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 3d9031a136e..e23a721da08 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: &'ast Block, s: Span, id: NodeId) {
+                b: &'ast Expr, s: Span, id: NodeId) {
         assert_eq!(self.parent_node, id);
         intravisit::walk_fn(self, fk, fd, b, s, id);
     }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index cbd3e39f870..6b5b8101a14 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -904,7 +904,7 @@ pub enum Expr_ {
     /// A closure (for example, `move |a, b, c| {a + b + c}`).
     ///
     /// The final span is the span of the argument block `|...|`
-    ExprClosure(CaptureClause, P<FnDecl>, P<Block>, Span),
+    ExprClosure(CaptureClause, P<FnDecl>, P<Expr>, Span),
     /// A block (`{ ... }`)
     ExprBlock(P<Block>),
 
@@ -1035,7 +1035,7 @@ pub enum TraitItem_ {
     /// must contain a value)
     ConstTraitItem(P<Ty>, Option<P<Expr>>),
     /// A method with an optional body
-    MethodTraitItem(MethodSig, Option<P<Block>>),
+    MethodTraitItem(MethodSig, Option<P<Expr>>),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
     TypeTraitItem(TyParamBounds, Option<P<Ty>>),
@@ -1060,7 +1060,7 @@ pub enum ImplItemKind {
     /// of the expression
     Const(P<Ty>, P<Expr>),
     /// A method implementation with the given signature and body
-    Method(MethodSig, P<Block>),
+    Method(MethodSig, P<Expr>),
     /// An associated type
     Type(P<Ty>),
 }
@@ -1501,7 +1501,7 @@ pub enum Item_ {
     /// A `const` item
     ItemConst(P<Ty>, P<Expr>),
     /// A function declaration
-    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
+    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Expr>),
     /// A module
     ItemMod(Mod),
     /// An external module
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 657c10bab12..2c4ffb853c1 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -713,7 +713,9 @@ impl<'a> State<'a> {
                               typarams,
                               &item.vis)?;
                 word(&mut self.s, " ")?;
-                self.print_block_with_attrs(&body, &item.attrs)?;
+                self.end()?; // need to close a box
+                self.end()?; // need to close a box
+                self.print_expr(&body)?;
             }
             hir::ItemMod(ref _mod) => {
                 self.head(&visibility_qualified(&item.vis, "mod"))?;
@@ -1002,7 +1004,9 @@ impl<'a> State<'a> {
                 self.print_method_sig(ti.name, sig, &hir::Inherited)?;
                 if let Some(ref body) = *body {
                     self.nbsp()?;
-                    self.print_block_with_attrs(body, &ti.attrs)?;
+                    self.end()?; // need to close a box
+                    self.end()?; // need to close a box
+                    self.print_expr(body)?;
                 } else {
                     word(&mut self.s, ";")?;
                 }
@@ -1034,7 +1038,9 @@ impl<'a> State<'a> {
                 self.head("")?;
                 self.print_method_sig(ii.name, sig, &ii.vis)?;
                 self.nbsp()?;
-                self.print_block_with_attrs(body, &ii.attrs)?;
+                self.end()?; // need to close a box
+                self.end()?; // need to close a box
+                self.print_expr(body)?;
             }
             hir::ImplItemKind::Type(ref ty) => {
                 self.print_associated_type(ii.name, None, Some(ty))?;
@@ -1402,26 +1408,10 @@ impl<'a> State<'a> {
                 self.print_fn_block_args(&decl)?;
                 space(&mut self.s)?;
 
-                let default_return = match decl.output {
-                    hir::DefaultReturn(..) => true,
-                    _ => false,
-                };
+                // this is a bare expression
+                self.print_expr(body)?;
+                self.end()?; // need to close a box
 
-                if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
-                    self.print_block_unclosed(&body)?;
-                } else {
-                    // we extract the block, so as not to create another set of boxes
-                    match body.expr.as_ref().unwrap().node {
-                        hir::ExprBlock(ref blk) => {
-                            self.print_block_unclosed(&blk)?;
-                        }
-                        _ => {
-                            // this is a bare expression
-                            self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?;
-                            self.end()?; // need to close a box
-                        }
-                    }
-                }
                 // a box will be closed by print_expr, but we didn't want an overall
                 // wrapper so we closed the corresponding opening. so create an
                 // empty box to satisfy the close.
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 9cc2337e3dd..f44f8286007 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -838,7 +838,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
-                body: &'v hir::Block, span: Span, id: ast::NodeId) {
+                body: &'v hir::Expr, span: Span, id: ast::NodeId) {
         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body, span, id);
         run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
@@ -994,10 +994,10 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> {
     }
 
     fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl,
-                body: &ast::Block, span: Span, id: ast::NodeId) {
-        run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
-        ast_visit::walk_fn(self, fk, decl, body, span);
-        run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id);
+                span: Span, id: ast::NodeId) {
+        run_lints!(self, check_fn, early_passes, fk, decl, span, id);
+        ast_visit::walk_fn(self, fk, decl, span);
+        run_lints!(self, check_fn_post, early_passes, fk, decl, span, id);
     }
 
     fn visit_variant_data(&mut self,
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 34e0ce7da14..6f7102229f8 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -151,9 +151,9 @@ pub trait LateLintPass: LintPass {
     fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { }
     fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { }
     fn check_fn(&mut self, _: &LateContext,
-        _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
+        _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { }
     fn check_fn_post(&mut self, _: &LateContext,
-        _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
+        _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { }
     fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
     fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { }
     fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
@@ -200,9 +200,9 @@ pub trait EarlyLintPass: LintPass {
     fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
     fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
     fn check_fn(&mut self, _: &EarlyContext,
-        _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
+        _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
     fn check_fn_post(&mut self, _: &EarlyContext,
-        _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
+        _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
     fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
     fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
     fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 59a5147ed1c..a1f226ab11d 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -147,7 +147,7 @@ pub trait CrateStore<'tcx> {
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>;
+    fn associated_item_def_ids(&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) -> hir::ImplPolarity;
@@ -157,8 +157,8 @@ pub trait CrateStore<'tcx> {
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
-    fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                              -> Option<ty::ImplOrTraitItem<'tcx>>;
+    fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> Option<ty::AssociatedItem>;
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool;
@@ -311,8 +311,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     }
 
     // impl info
-    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>
-        { bug!("impl_or_trait_items") }
+    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
+        { bug!("associated_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) -> hir::ImplPolarity { bug!("impl_polarity") }
@@ -323,8 +323,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
-    fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                              -> Option<ty::ImplOrTraitItem<'tcx>> { bug!("impl_or_trait_item") }
+    fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> Option<ty::AssociatedItem> { bug!("associated_item") }
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 7f3a58808c2..1ec3d0db8e0 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -498,7 +498,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
 
 impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
 //                                ^^^^^^^^^^^^^ only needed for pretty printing
-    pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) {
+    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
         //! Performs the data flow analysis.
 
         if self.bits_per_id == 0 {
@@ -524,17 +524,17 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
         debug!("Dataflow result for {}:", self.analysis_name);
         debug!("{}", {
             let mut v = Vec::new();
-            self.pretty_print_to(box &mut v, blk).unwrap();
+            self.pretty_print_to(box &mut v, body).unwrap();
             String::from_utf8(v).unwrap()
         });
     }
 
     fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
-                           blk: &hir::Block) -> io::Result<()> {
+                           body: &hir::Expr) -> io::Result<()> {
         let mut ps = pprust::rust_printer_annotated(wr, self, None);
         ps.cbox(pprust::indent_unit)?;
         ps.ibox(0)?;
-        ps.print_block(blk)?;
+        ps.print_expr(body)?;
         pp::eof(&mut ps.s)
     }
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 7fc698fdbeb..23fc5911259 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -471,11 +471,10 @@ 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_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[impl_did][..] {
+            for &impl_did in impl_list.iter() {
+                for &item_did in &self.tcx.associated_item_def_ids(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;
@@ -567,7 +566,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "method");
                 }
-                intravisit::walk_block(self, body)
+                intravisit::walk_expr(self, body)
             }
             hir::ImplItemKind::Type(..) => {}
         }
@@ -576,11 +575,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
     // Overwrite so that we don't warn the trait item itself.
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
         match trait_item.node {
-            hir::ConstTraitItem(_, Some(ref expr)) => {
-                intravisit::walk_expr(self, expr)
-            }
+            hir::ConstTraitItem(_, Some(ref body))|
             hir::MethodTraitItem(_, Some(ref body)) => {
-                intravisit::walk_block(self, body)
+                intravisit::walk_expr(self, body)
             }
             hir::ConstTraitItem(_, None) |
             hir::MethodTraitItem(_, None) |
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 8ca3c75eaa4..5634e2012c9 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -94,7 +94,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
     fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl,
-                block: &'v hir::Block, span: Span, id: ast::NodeId) {
+                block: &'v hir::Expr, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 0543d1303a5..231da576f2b 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -227,8 +227,8 @@ impl OverloadedCallType {
     }
 
     fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType {
-        let method = tcx.impl_or_trait_item(method_id);
-        OverloadedCallType::from_trait_id(tcx, method.container().id())
+        let method = tcx.associated_item(method_id);
+        OverloadedCallType::from_trait_id(tcx, method.container.id())
     }
 }
 
@@ -290,14 +290,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
     pub fn walk_fn(&mut self,
                    decl: &hir::FnDecl,
-                   body: &hir::Block) {
+                   body: &hir::Expr) {
         self.walk_arg_patterns(decl, body);
-        self.walk_block(body);
+        self.consume_expr(body);
     }
 
     fn walk_arg_patterns(&mut self,
                          decl: &hir::FnDecl,
-                         body: &hir::Block) {
+                         body: &hir::Expr) {
         for arg in &decl.inputs {
             let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
 
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 57503398cfe..7dbf9aa7414 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, id: ast::NodeId) {
+                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
         if let FnKind::Closure(..) = fk {
             span_bug!(s, "intrinsicck: closure outside of function")
         }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 46bea00cca3..a654d65bc67 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -123,10 +123,9 @@ use std::io::prelude::*;
 use std::io;
 use std::rc::Rc;
 use syntax::ast::{self, NodeId};
-use syntax::codemap::original_sp;
 use syntax::parse::token::keywords;
 use syntax::ptr::P;
-use syntax_pos::{BytePos, Span};
+use syntax_pos::Span;
 
 use hir::Expr;
 use hir;
@@ -187,7 +186,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, id: NodeId) {
+                b: &'v hir::Expr, s: Span, id: NodeId) {
         visit_fn(self, fk, fd, b, s, id);
     }
     fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); }
@@ -352,9 +351,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> {
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, n: NodeId) {
-        check_fn(self, fk, fd, b, s, n);
+    fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl,
+                _: &'v hir::Expr, _: Span, _: NodeId) {
+        // do not check contents of nested fns
     }
     fn visit_local(&mut self, l: &hir::Local) {
         check_local(self, l);
@@ -370,7 +369,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> {
 fn visit_fn(ir: &mut IrMaps,
             fk: FnKind,
             decl: &hir::FnDecl,
-            body: &hir::Block,
+            body: &hir::Expr,
             sp: Span,
             id: ast::NodeId) {
     debug!("visit_fn");
@@ -405,10 +404,10 @@ fn visit_fn(ir: &mut IrMaps,
 
     // compute liveness
     let mut lsets = Liveness::new(&mut fn_maps, specials);
-    let entry_ln = lsets.compute(decl, body);
+    let entry_ln = lsets.compute(body);
 
     // check for various error conditions
-    lsets.visit_block(body);
+    lsets.visit_expr(body);
     lsets.check_ret(id, sp, fk, entry_ln, body);
     lsets.warn_about_unused_args(decl, entry_ln);
 }
@@ -821,17 +820,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     // _______________________________________________________________________
 
-    fn compute(&mut self, decl: &hir::FnDecl, body: &hir::Block) -> LiveNode {
+    fn compute(&mut self, body: &hir::Expr) -> LiveNode {
         // if there is a `break` or `again` at the top level, then it's
         // effectively a return---this only occurs in `for` loops,
         // where the body is really a closure.
 
-        debug!("compute: using id for block, {}", block_to_string(body));
+        debug!("compute: using id for body, {}", expr_to_string(body));
 
         let exit_ln = self.s.exit_ln;
-        let entry_ln: LiveNode =
-            self.with_loop_nodes(body.id, exit_ln, exit_ln,
-              |this| this.propagate_through_fn_block(decl, body));
+        let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
+            // the fallthrough exit is only for those cases where we do not
+            // explicitly return:
+            let s = this.s;
+            this.init_from_succ(s.fallthrough_ln, s.exit_ln);
+            this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
+
+            this.propagate_through_expr(body, s.fallthrough_ln)
+        });
 
         // hack to skip the loop unless debug! is enabled:
         debug!("^^ liveness computation results for body {} (entry={:?})",
@@ -846,20 +851,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         entry_ln
     }
 
-    fn propagate_through_fn_block(&mut self, _: &hir::FnDecl, blk: &hir::Block)
-                                  -> LiveNode {
-        // the fallthrough exit is only for those cases where we do not
-        // explicitly return:
-        let s = self.s;
-        self.init_from_succ(s.fallthrough_ln, s.exit_ln);
-        if blk.expr.is_none() {
-            self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ)
-        }
-        self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
-
-        self.propagate_through_block(blk, s.fallthrough_ln)
-    }
-
     fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
                                -> LiveNode {
         let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
@@ -1448,15 +1439,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
     }
 }
 
-fn check_fn(_v: &Liveness,
-            _fk: FnKind,
-            _decl: &hir::FnDecl,
-            _body: &hir::Block,
-            _sp: Span,
-            _id: NodeId) {
-    // do not check contents of nested fns
-}
-
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn fn_ret(&self, id: NodeId) -> ty::Binder<Ty<'tcx>> {
         let fn_ty = self.ir.tcx.tables().node_id_to_type(id);
@@ -1472,7 +1454,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                  sp: Span,
                  _fk: FnKind,
                  entry_ln: LiveNode,
-                 body: &hir::Block)
+                 body: &hir::Expr)
     {
         // within the fn body, late-bound regions are liberated
         // and must outlive the *call-site* of the function.
@@ -1481,13 +1463,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.ir.tcx.region_maps.call_site_extent(id, body.id),
                 &self.fn_ret(id));
 
-        if fn_ret.is_never() {
-            // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }`
-            if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() {
-                span_err!(self.ir.tcx.sess, sp, E0270,
-                          "computation may converge in a function marked as diverging");
-            }
-        } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
+        if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
             let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
             let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
             let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
@@ -1498,32 +1474,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
             // for nil return types, it is ok to not return a value expl.
             if !is_nil {
-                let ends_with_stmt = match body.expr {
-                    None if !body.stmts.is_empty() =>
-                        match body.stmts.last().unwrap().node {
-                            hir::StmtSemi(ref e, _) => {
-                                self.ir.tcx.tables().expr_ty(&e) == fn_ret
-                            },
-                            _ => false
-                        },
-                    _ => false
-                };
-                let mut err = struct_span_err!(self.ir.tcx.sess,
-                                               sp,
-                                               E0269,
-                                               "not all control paths return a value");
-                if ends_with_stmt {
-                    let last_stmt = body.stmts.last().unwrap();
-                    let original_span = original_sp(self.ir.tcx.sess.codemap(),
-                                                    last_stmt.span, sp);
-                    let span_semicolon = Span {
-                        lo: original_span.hi - BytePos(1),
-                        hi: original_span.hi,
-                        expn_id: original_span.expn_id
-                    };
-                    err.span_help(span_semicolon, "consider removing this semicolon:");
-                }
-                err.emit();
+                span_bug!(sp, "not all control paths return a value");
             }
         }
     }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 9898ec7597d..7868e700f27 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -248,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         match *node {
             ast_map::NodeItem(item) => {
                 match item.node {
-                    hir::ItemFn(.., ref search_block) => {
+                    hir::ItemFn(.., ref body) => {
                         if item_might_be_inlined(&item) {
-                            intravisit::walk_block(self, &search_block)
+                            self.visit_expr(body);
                         }
                     }
 
@@ -278,11 +278,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::MethodTraitItem(_, None) => {
                         // Keep going, nothing to get exported
                     }
-                    hir::ConstTraitItem(_, Some(ref expr)) => {
-                        self.visit_expr(&expr);
-                    }
+                    hir::ConstTraitItem(_, Some(ref body)) |
                     hir::MethodTraitItem(_, Some(ref body)) => {
-                        intravisit::walk_block(self, body);
+                        self.visit_expr(body);
                     }
                     hir::TypeTraitItem(..) => {}
                 }
@@ -295,7 +293,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Method(ref sig, ref body) => {
                         let did = self.tcx.map.get_parent_did(search_item);
                         if method_might_be_inlined(self.tcx, sig, impl_item, did) {
-                            intravisit::walk_block(self, body)
+                            self.visit_expr(body)
                         }
                     }
                     hir::ImplItemKind::Type(_) => {}
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 8d51fda0cf2..34a6a547d94 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -490,12 +490,7 @@ impl RegionMaps {
         // if there's one. Static items, for instance, won't
         // have an enclosing scope, hence no scope will be
         // returned.
-        let expr_extent = self.node_extent(expr_id);
-        // For some reason, the expr's scope itself is skipped here.
-        let mut id = match scope_map[expr_extent.0 as usize].into_option() {
-            Some(i) => i,
-            _ => return None
-        };
+        let mut id = self.node_extent(expr_id);
 
         while let Some(p) = scope_map[id.0 as usize].into_option() {
             match code_extents[p.0 as usize] {
@@ -1086,7 +1081,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) {
 fn resolve_fn(visitor: &mut RegionResolutionVisitor,
               kind: FnKind,
               decl: &hir::FnDecl,
-              body: &hir::Block,
+              body: &hir::Expr,
               sp: Span,
               id: ast::NodeId) {
     debug!("region::resolve_fn(id={:?}, \
@@ -1128,7 +1123,7 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
         parent: fn_decl_scope,
         var_parent: fn_decl_scope
     };
-    visitor.visit_block(body);
+    visitor.visit_expr(body);
 
     // Restore context we had at the start.
     visitor.cx = outer_cx;
@@ -1191,7 +1186,7 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
-                b: &'v Block, s: Span, n: NodeId) {
+                b: &'v Expr, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
     }
     fn visit_arm(&mut self, a: &Arm) {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index e6d96073529..292d9592ceb 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -202,7 +202,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
+                b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
@@ -403,7 +403,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
 
 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
 // if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
     struct GatherLabels<'a> {
         sess: &'a Session,
         scope: Scope<'a>,
@@ -415,7 +415,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
         scope: ctxt.scope,
         labels_in_fn: &mut ctxt.labels_in_fn,
     };
-    gather.visit_block(b);
+    gather.visit_expr(b);
     return;
 
     impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
@@ -493,7 +493,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     fn add_scope_and_walk_fn<'b>(&mut self,
                                  fk: FnKind,
                                  fd: &hir::FnDecl,
-                                 fb: &'b hir::Block,
+                                 fb: &'b hir::Expr,
                                  _span: Span,
                                  fn_id: ast::NodeId) {
 
@@ -516,7 +516,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         extract_labels(self, fb);
 
         self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
-                  |_old_scope, this| this.visit_block(fb))
+                  |_old_scope, this| this.visit_expr(fb))
     }
 
     fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index f1755c82b8c..d79833998d6 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -529,14 +529,11 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // items.
         hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
             let trait_did = tcx.expect_def(t.ref_id).def_id();
-            let trait_items = tcx.trait_items(trait_did);
-
             for impl_item in impl_items {
-                let item = trait_items.iter().find(|item| {
-                    item.name() == impl_item.name
-                }).unwrap();
+                let item = tcx.associated_items(trait_did)
+                    .find(|item| item.name == impl_item.name).unwrap();
                 if warn_about_defns {
-                    maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
+                    maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb);
                 }
             }
         }
@@ -685,15 +682,8 @@ 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(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))
-        }
-    }
+    *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
+        || tcx.sess.cstore.is_staged_api(id.krate))
 }
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 3522c738c16..7e70fdb92e6 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -663,25 +663,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                          in the supertrait listing"
                 }
 
-                ObjectSafetyViolation::Method(method,
+                ObjectSafetyViolation::Method(name,
                                               MethodViolationCode::StaticMethod) => {
-                    buf = format!("method `{}` has no receiver",
-                                  method.name);
+                    buf = format!("method `{}` has no receiver", name);
                     &buf
                 }
 
-                ObjectSafetyViolation::Method(method,
+                ObjectSafetyViolation::Method(name,
                                               MethodViolationCode::ReferencesSelf) => {
                     buf = format!("method `{}` references the `Self` type \
                                        in its arguments or return type",
-                                  method.name);
+                                  name);
                     &buf
                 }
 
-                ObjectSafetyViolation::Method(method,
+                ObjectSafetyViolation::Method(name,
                                               MethodViolationCode::Generic) => {
-                    buf = format!("method `{}` has generic type parameters",
-                                  method.name);
+                    buf = format!("method `{}` has generic type parameters", name);
                     &buf
                 }
             };
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 017b34d914f..36405df6325 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -578,18 +578,14 @@ pub fn get_vtable_methods<'a, 'tcx>(
     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
-            }
-        });
+        let trait_methods = tcx.associated_items(trait_ref.def_id())
+            .filter(|item| item.kind == ty::AssociatedKind::Method);
 
         // 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);
+            let def_id = trait_method.def_id;
 
             // Some methods cannot be called on an object; skip those.
             if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
@@ -599,21 +595,21 @@ pub fn get_vtable_methods<'a, 'tcx>(
 
             // 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));
+            let substs = Substs::for_item(tcx, 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);
+            let predicates = tcx.lookup_predicates(def_id).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))
+            Some((def_id, substs))
         })
     })
 }
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 5f7b7151829..c783bd561bb 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -22,11 +22,10 @@ use super::elaborate_predicates;
 use hir::def_id::DefId;
 use traits;
 use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
-use std::rc::Rc;
 use syntax::ast;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub enum ObjectSafetyViolation<'tcx> {
+pub enum ObjectSafetyViolation {
     /// Self : Sized declared on the trait
     SizedSelf,
 
@@ -35,7 +34,7 @@ pub enum ObjectSafetyViolation<'tcx> {
     SupertraitSelf,
 
     /// Method has something illegal
-    Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
+    Method(ast::Name, MethodViolationCode),
 }
 
 /// Reasons a method might not be object-safe.
@@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// because `object_safety_violations` can't be used during
     /// type collection.
     pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
-                                            -> Vec<ObjectSafetyViolation<'tcx>>
+                                            -> Vec<ObjectSafetyViolation>
     {
         let mut violations = vec![];
 
@@ -93,7 +92,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn object_safety_violations(self, trait_def_id: DefId)
-                                    -> Vec<ObjectSafetyViolation<'tcx>>
+                                    -> Vec<ObjectSafetyViolation>
     {
         traits::supertrait_def_ids(self, trait_def_id)
             .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
@@ -101,21 +100,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn object_safety_violations_for_trait(self, trait_def_id: DefId)
-                                          -> Vec<ObjectSafetyViolation<'tcx>>
+                                          -> Vec<ObjectSafetyViolation>
     {
         // Check methods for violations.
-        let mut violations: Vec<_> =
-            self.trait_items(trait_def_id).iter()
+        let mut violations: Vec<_> = self.associated_items(trait_def_id)
+            .filter(|item| item.kind == ty::AssociatedKind::Method)
             .filter_map(|item| {
-                match *item {
-                    ty::MethodTraitItem(ref m) => {
-                        self.object_safety_violation_for_method(trait_def_id, &m)
-                            .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
-                    }
-                    _ => None,
-                }
-            })
-            .collect();
+                self.object_safety_violation_for_method(trait_def_id, &item)
+                    .map(|code| ObjectSafetyViolation::Method(item.name, code))
+            }).collect();
 
         // Check the trait itself.
         if self.trait_has_sized_self(trait_def_id) {
@@ -198,7 +191,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns `Some(_)` if this method makes the containing trait not object safe.
     fn object_safety_violation_for_method(self,
                                           trait_def_id: DefId,
-                                          method: &ty::Method<'gcx>)
+                                          method: &ty::AssociatedItem)
                                           -> Option<MethodViolationCode>
     {
         // Any method that has a `Self : Sized` requisite is otherwise
@@ -216,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// otherwise ensure that they cannot be used when `Self=Trait`.
     pub fn is_vtable_safe_method(self,
                                  trait_def_id: DefId,
-                                 method: &ty::Method<'gcx>)
+                                 method: &ty::AssociatedItem)
                                  -> bool
     {
         // Any method that has a `Self : Sized` requisite can't be called.
@@ -233,26 +226,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// `Self:Sized`.
     fn virtual_call_violation_for_method(self,
                                          trait_def_id: DefId,
-                                         method: &ty::Method<'tcx>)
+                                         method: &ty::AssociatedItem)
                                          -> Option<MethodViolationCode>
     {
         // The method's first parameter must be something that derefs (or
         // autorefs) to `&self`. For now, we only accept `self`, `&self`
         // and `Box<Self>`.
-        match method.explicit_self {
-            ty::ExplicitSelfCategory::Static => {
-                return Some(MethodViolationCode::StaticMethod);
-            }
-
-            ty::ExplicitSelfCategory::ByValue |
-            ty::ExplicitSelfCategory::ByReference(..) |
-            ty::ExplicitSelfCategory::ByBox => {
-            }
+        if !method.method_has_self_argument {
+            return Some(MethodViolationCode::StaticMethod);
         }
 
         // The `Self` type is erased, so it should not appear in list of
         // arguments or return type apart from the receiver.
-        let ref sig = method.fty.sig;
+        let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig();
         for &input_ty in &sig.0.inputs[1..] {
             if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
                 return Some(MethodViolationCode::ReferencesSelf);
@@ -263,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
 
         // We can't monomorphize things like `fn foo<A>(...)`.
-        if !method.generics.types.is_empty() {
+        if !self.lookup_generics(method.def_id).types.is_empty() {
             return Some(MethodViolationCode::Generic);
         }
 
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index ce882c48377..b1ab61b0975 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -33,8 +33,6 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder};
 use util::common::FN_OUTPUT_NAME;
 
-use std::rc::Rc;
-
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -945,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                         // an error when we confirm the candidate
                         // (which will ultimately lead to `normalize_to_error`
                         // being invoked).
-                        node_item.item.ty.is_some()
+                        node_item.item.has_value
                     } else {
                         node_item.item.defaultness.is_default()
                     };
@@ -1305,7 +1303,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
 
     match assoc_ty {
         Some(node_item) => {
-            let ty = node_item.item.ty.unwrap_or_else(|| {
+            let ty = if !node_item.item.has_value {
                 // This means that the impl is missing a definition for the
                 // associated type. This error will be reported by the type
                 // checker method `check_impl_items_against_trait`, so here we
@@ -1314,7 +1312,9 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
                        node_item.item.name,
                        obligation.predicate.trait_ref);
                 tcx.types.err
-            });
+            } else {
+                tcx.lookup_item_type(node_item.item.def_id).ty
+            };
             let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node);
             Progress {
                 ty: ty.subst(tcx, substs),
@@ -1339,27 +1339,25 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
     selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
     impl_def_id: DefId,
     assoc_ty_name: ast::Name)
-    -> Option<specialization_graph::NodeItem<Rc<ty::AssociatedType<'tcx>>>>
+    -> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
 {
     let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
 
     if selcx.projection_mode() == Reveal::ExactMatch {
         let impl_node = specialization_graph::Node::Impl(impl_def_id);
         for item in impl_node.items(selcx.tcx()) {
-            if let ty::TypeTraitItem(assoc_ty) = item {
-                if assoc_ty.name == assoc_ty_name {
-                    return Some(specialization_graph::NodeItem {
-                        node: specialization_graph::Node::Impl(impl_def_id),
-                        item: assoc_ty,
-                    });
-                }
+            if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
+                return Some(specialization_graph::NodeItem {
+                    node: specialization_graph::Node::Impl(impl_def_id),
+                    item: item,
+                });
             }
         }
         None
     } else {
         selcx.tcx().lookup_trait_def(trait_def_id)
             .ancestors(impl_def_id)
-            .type_defs(selcx.tcx(), assoc_ty_name)
+            .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
             .next()
     }
 }
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 4eef6944974..91c40a5cc85 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -120,7 +120,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     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() {
+    let ancestors = trait_def.ancestors(impl_data.impl_def_id);
+    match ancestors.defs(tcx, name, ty::AssociatedKind::Method).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);
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index c746145474c..5a6809f1fad 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -8,13 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
-
 use super::{OverlapError, specializes};
 
 use hir::def_id::DefId;
 use traits::{self, Reveal};
-use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable};
+use ty::{self, TyCtxt, TraitDef, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
 use syntax::ast::Name;
 use util::nodemap::{DefIdMap, FxHashMap};
@@ -285,12 +283,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> {
-        NodeItems {
-            tcx: tcx.global_tcx(),
-            items: tcx.impl_or_trait_items(self.def_id()),
-            idx: 0,
-        }
+    #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+    pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                 -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+        tcx.associated_items(self.def_id())
     }
 
     pub fn def_id(&self) -> DefId {
@@ -301,28 +297,6 @@ impl<'a, 'gcx, 'tcx> Node {
     }
 }
 
-/// An iterator over the items defined within a trait or impl.
-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>> {
-        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
-        }
-    }
-}
-
 pub struct Ancestors<'a, 'tcx: 'a> {
     trait_def: &'a TraitDef<'tcx>,
     current_source: Option<Node>,
@@ -358,104 +332,16 @@ impl<T> NodeItem<T> {
     }
 }
 
-pub struct TypeDefs<'a, 'tcx: 'a> {
-    // generally only invoked once or twice, so the box doesn't hurt
-    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>> + 'a>,
-}
-
-impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> {
-    type Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>;
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-}
-
-pub struct FnDefs<'a, 'tcx: 'a> {
-    // generally only invoked once or twice, so the box doesn't hurt
-    iter: Box<Iterator<Item = NodeItem<Rc<ty::Method<'tcx>>>> + 'a>,
-}
-
-impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> {
-    type Item = NodeItem<Rc<ty::Method<'tcx>>>;
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-}
-
-pub struct ConstDefs<'a, 'tcx: 'a> {
-    // generally only invoked once or twice, so the box doesn't hurt
-    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>> + 'a>,
-}
-
-impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> {
-    type Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>;
-    fn next(&mut self) -> Option<Self::Item> {
-        self.iter.next()
-    }
-}
-
 impl<'a, 'gcx, 'tcx> Ancestors<'a, 'tcx> {
-    /// Search the items from the given ancestors, returning each type definition
-    /// with the given name.
-    pub fn type_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> TypeDefs<'a, 'gcx> {
-        let iter = self.flat_map(move |node| {
-            node.items(tcx)
-                .filter_map(move |item| {
-                    if let ty::TypeTraitItem(assoc_ty) = item {
-                        if assoc_ty.name == name {
-                            return Some(NodeItem {
-                                node: node,
-                                item: assoc_ty,
-                            });
-                        }
-                    }
-                    None
-                })
-
-        });
-        TypeDefs { iter: Box::new(iter) }
-    }
-
-    /// Search the items from the given ancestors, returning each fn definition
-    /// with the given name.
-    pub fn fn_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> FnDefs<'a, 'gcx> {
-        let iter = self.flat_map(move |node| {
-            node.items(tcx)
-                .filter_map(move |item| {
-                    if let ty::MethodTraitItem(method) = item {
-                        if method.name == name {
-                            return Some(NodeItem {
-                                node: node,
-                                item: method,
-                            });
-                        }
-                    }
-                    None
-                })
-
-        });
-        FnDefs { iter: Box::new(iter) }
-    }
-
-    /// Search the items from the given ancestors, returning each const
-    /// definition with the given name.
-    pub fn const_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> ConstDefs<'a, 'gcx> {
-        let iter = self.flat_map(move |node| {
-            node.items(tcx)
-                .filter_map(move |item| {
-                    if let ty::ConstTraitItem(konst) = item {
-                        if konst.name == name {
-                            return Some(NodeItem {
-                                node: node,
-                                item: konst,
-                            });
-                        }
-                    }
-                    None
-                })
-
-        });
-        ConstDefs { iter: Box::new(iter) }
+    /// Search the items from the given ancestors, returning each definition
+    /// with the given name and the given kind.
+    #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+    pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name, kind: ty::AssociatedKind)
+                -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + 'a {
+        self.flat_map(move |node| {
+            node.items(tcx).filter(move |item| item.kind == kind && item.name == name)
+                           .map(move |item| NodeItem { node: node, item: item })
+        })
     }
 }
 
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 52830164d1d..9346bbd30f9 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -477,8 +477,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let mut entries = 0;
         // Count number of methods and add them to the total offset.
         // Skip over associated types and constants.
-        for trait_item in &self.trait_items(trait_ref.def_id())[..] {
-            if let ty::MethodTraitItem(_) = *trait_item {
+        for trait_item in self.associated_items(trait_ref.def_id()) {
+            if trait_item.kind == ty::AssociatedKind::Method {
                 entries += 1;
             }
         }
@@ -495,17 +495,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // add them to the total offset.
         // Skip over associated types and constants.
         let mut entries = object.vtable_base;
-        for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] {
-            if trait_item.def_id() == method_def_id {
+        for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
+            if trait_item.def_id == method_def_id {
                 // The item with the ID we were given really ought to be a method.
-                assert!(match *trait_item {
-                    ty::MethodTraitItem(_) => true,
-                    _ => false
-                });
-
+                assert_eq!(trait_item.kind, ty::AssociatedKind::Method);
                 return entries;
             }
-            if let ty::MethodTraitItem(_) = *trait_item {
+            if trait_item.kind == ty::AssociatedKind::Method {
                 entries += 1;
             }
         }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index b19f9351235..60a48ba580a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -403,14 +403,10 @@ pub struct GlobalCtxt<'tcx> {
     pub tables: RefCell<Tables<'tcx>>,
 
     /// Maps from a trait item to the trait item "descriptor"
-    pub impl_or_trait_items: RefCell<DepTrackingMap<maps::ImplOrTraitItems<'tcx>>>,
+    pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'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.
-    trait_items_cache: RefCell<DepTrackingMap<maps::TraitItems<'tcx>>>,
+    pub associated_item_def_ids: RefCell<DepTrackingMap<maps::AssociatedItemDefIds<'tcx>>>,
 
     pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
     pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
@@ -822,9 +818,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rcache: RefCell::new(FxHashMap()),
             tc_cache: RefCell::new(FxHashMap()),
-            impl_or_trait_items: 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())),
+            associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
@@ -1539,15 +1534,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
     }
 
-    pub fn trait_items(self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'gcx>>> {
-        self.trait_items_cache.memoize(trait_did, || {
-            let def_ids = self.impl_or_trait_items(trait_did);
-            Rc::new(def_ids.iter()
-                           .map(|&def_id| self.impl_or_trait_item(def_id))
-                           .collect())
-        })
-    }
-
     /// 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, || {
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index cad87081a93..43abb61e7fc 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -16,7 +16,7 @@ use ty::{self, Ty};
 use std::cell::RefCell;
 use std::marker::PhantomData;
 use std::rc::Rc;
-use syntax::{attr, ast};
+use syntax::attr;
 
 macro_rules! dep_map_ty {
     ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
@@ -32,18 +32,16 @@ macro_rules! dep_map_ty {
     }
 }
 
-dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> }
+dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem }
 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! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc<Vec<DefId>> }
+dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(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! { 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 }
 dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index fcf9b5ff273..1d260fd65fe 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -10,9 +10,8 @@
 
 pub use self::Variance::*;
 pub use self::DtorKind::*;
-pub use self::ImplOrTraitItemContainer::*;
+pub use self::AssociatedItemContainer::*;
 pub use self::BorrowKind::*;
-pub use self::ImplOrTraitItem::*;
 pub use self::IntVarValue::*;
 pub use self::LvaluePreference::*;
 pub use self::fold::TypeFoldable;
@@ -135,12 +134,12 @@ impl DtorKind {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum ImplOrTraitItemContainer {
+pub enum AssociatedItemContainer {
     TraitContainer(DefId),
     ImplContainer(DefId),
 }
 
-impl ImplOrTraitItemContainer {
+impl AssociatedItemContainer {
     pub fn id(&self) -> DefId {
         match *self {
             TraitContainer(id) => id,
@@ -183,58 +182,34 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
     }
 }
 
-#[derive(Clone)]
-pub enum ImplOrTraitItem<'tcx> {
-    ConstTraitItem(Rc<AssociatedConst<'tcx>>),
-    MethodTraitItem(Rc<Method<'tcx>>),
-    TypeTraitItem(Rc<AssociatedType<'tcx>>),
-}
-
-impl<'tcx> ImplOrTraitItem<'tcx> {
-    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.def_id),
-        }
-    }
-
-    pub fn def_id(&self) -> DefId {
-        match *self {
-            ConstTraitItem(ref associated_const) => associated_const.def_id,
-            MethodTraitItem(ref method) => method.def_id,
-            TypeTraitItem(ref associated_type) => associated_type.def_id,
-        }
-    }
-
-    pub fn name(&self) -> Name {
-        match *self {
-            ConstTraitItem(ref associated_const) => associated_const.name,
-            MethodTraitItem(ref method) => method.name,
-            TypeTraitItem(ref associated_type) => associated_type.name,
-        }
-    }
+#[derive(Copy, Clone, Debug)]
+pub struct AssociatedItem {
+    pub def_id: DefId,
+    pub name: Name,
+    pub kind: AssociatedKind,
+    pub vis: Visibility,
+    pub defaultness: hir::Defaultness,
+    pub has_value: bool,
+    pub container: AssociatedItemContainer,
 
-    pub fn vis(&self) -> Visibility {
-        match *self {
-            ConstTraitItem(ref associated_const) => associated_const.vis,
-            MethodTraitItem(ref method) => method.vis,
-            TypeTraitItem(ref associated_type) => associated_type.vis,
-        }
-    }
+    /// Whether this is a method with an explicit self
+    /// as its first argument, allowing method calls.
+    pub method_has_self_argument: bool,
+}
 
-    pub fn container(&self) -> ImplOrTraitItemContainer {
-        match *self {
-            ConstTraitItem(ref associated_const) => associated_const.container,
-            MethodTraitItem(ref method) => method.container,
-            TypeTraitItem(ref associated_type) => associated_type.container,
-        }
-    }
+#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
+pub enum AssociatedKind {
+    Const,
+    Method,
+    Type
+}
 
-    pub fn as_opt_method(&self) -> Option<Rc<Method<'tcx>>> {
-        match *self {
-            MethodTraitItem(ref m) => Some((*m).clone()),
-            _ => None,
+impl AssociatedItem {
+    pub fn def(&self) -> Def {
+        match self.kind {
+            AssociatedKind::Const => Def::AssociatedConst(self.def_id),
+            AssociatedKind::Method => Def::Method(self.def_id),
+            AssociatedKind::Type => Def::AssociatedTy(self.def_id),
         }
     }
 }
@@ -308,64 +283,6 @@ impl Visibility {
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct Method<'tcx> {
-    pub name: Name,
-    pub generics: &'tcx Generics<'tcx>,
-    pub predicates: GenericPredicates<'tcx>,
-    pub fty: &'tcx BareFnTy<'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 container_id(&self) -> DefId {
-        match self.container {
-            TraitContainer(id) => id,
-            ImplContainer(id) => id,
-        }
-    }
-}
-
-impl<'tcx> PartialEq for Method<'tcx> {
-    #[inline]
-    fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id }
-}
-
-impl<'tcx> Eq for Method<'tcx> {}
-
-impl<'tcx> Hash for Method<'tcx> {
-    #[inline]
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        self.def_id.hash(s)
-    }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct AssociatedConst<'tcx> {
-    pub name: Name,
-    pub ty: Ty<'tcx>,
-    pub vis: Visibility,
-    pub defaultness: hir::Defaultness,
-    pub def_id: DefId,
-    pub container: ImplOrTraitItemContainer,
-    pub has_value: bool
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct AssociatedType<'tcx> {
-    pub name: Name,
-    pub ty: Option<Ty<'tcx>>,
-    pub vis: Visibility,
-    pub defaultness: hir::Defaultness,
-    pub def_id: DefId,
-    pub container: ImplOrTraitItemContainer,
-}
-
 #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
 pub enum Variance {
     Covariant,      // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -1288,19 +1205,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                                                             tcx.region_maps.item_extent(id))
                     }
                     hir::ImplItemKind::Method(_, ref body) => {
-                        let method_def_id = tcx.map.local_def_id(id);
-                        match tcx.impl_or_trait_item(method_def_id) {
-                            MethodTraitItem(ref method_ty) => {
-                                tcx.construct_parameter_environment(
-                                    impl_item.span,
-                                    method_ty.def_id,
-                                    tcx.region_maps.call_site_extent(id, body.id))
-                            }
-                            _ => {
-                                bug!("ParameterEnvironment::for_item(): \
-                                      got non-method item from impl method?!")
-                            }
-                        }
+                        tcx.construct_parameter_environment(
+                            impl_item.span,
+                            tcx.map.local_def_id(id),
+                            tcx.region_maps.call_site_extent(id, body.id))
                     }
                 }
             }
@@ -1319,27 +1227,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // Use call-site for extent (unless this is a
                         // trait method with no default; then fallback
                         // to the method id).
-                        let method_def_id = tcx.map.local_def_id(id);
-                        match tcx.impl_or_trait_item(method_def_id) {
-                            MethodTraitItem(ref method_ty) => {
-                                let extent = if let Some(ref body) = *body {
-                                    // default impl: use call_site extent as free_id_outlive bound.
-                                    tcx.region_maps.call_site_extent(id, body.id)
-                                } else {
-                                    // no default impl: use item extent as free_id_outlive bound.
-                                    tcx.region_maps.item_extent(id)
-                                };
-                                tcx.construct_parameter_environment(
-                                    trait_item.span,
-                                    method_ty.def_id,
-                                    extent)
-                            }
-                            _ => {
-                                bug!("ParameterEnvironment::for_item(): \
-                                      got non-method item from provided \
-                                      method?!")
-                            }
-                        }
+                        let extent = if let Some(ref body) = *body {
+                            // default impl: use call_site extent as free_id_outlive bound.
+                            tcx.region_maps.call_site_extent(id, body.id)
+                        } else {
+                            // no default impl: use item extent as free_id_outlive bound.
+                            tcx.region_maps.item_extent(id)
+                        };
+                        tcx.construct_parameter_environment(
+                            trait_item.span,
+                            tcx.map.local_def_id(id),
+                            extent)
                     }
                 }
             }
@@ -2065,7 +1963,7 @@ impl LvaluePreference {
 }
 
 /// Helper for looking things up in the various maps that are populated during
-/// typeck::collect (e.g., `tcx.impl_or_trait_items`, `tcx.tcache`, etc).  All of
+/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc).  All of
 /// these share the pattern that if the id is local, it should have been loaded
 /// into the map by the `typeck::collect` phase.  If the def-id is external,
 /// then we have to go consult the crate loading code (and cache the result for
@@ -2204,13 +2102,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn provided_trait_methods(self, id: DefId) -> Vec<Rc<Method<'gcx>>> {
-        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
-            }
-        }).collect()
+    pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
+        self.associated_items(id)
+            .filter(|item| item.kind == AssociatedKind::Method && item.has_value)
+            .collect()
     }
 
     pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity {
@@ -2243,17 +2138,105 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn impl_or_trait_item(self, id: DefId) -> ImplOrTraitItem<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "impl_or_trait_items", id, &self.impl_or_trait_items,
-            || self.sess.cstore.impl_or_trait_item(self.global_tcx(), id)
-                   .expect("missing ImplOrTraitItem in metadata"))
+    pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
+        self.associated_items.memoize(def_id, || {
+            if !def_id.is_local() {
+                return self.sess.cstore.associated_item(self.global_tcx(), def_id)
+                           .expect("missing AssociatedItem in metadata");
+            }
+
+            let id = self.map.as_local_node_id(def_id).unwrap();
+            let parent_id = self.map.get_parent(id);
+            let parent_def_id = self.map.local_def_id(parent_id);
+            match self.map.get(id) {
+                ast_map::NodeTraitItem(trait_item) => {
+                    let (kind, has_self, has_value) = match trait_item.node {
+                        hir::MethodTraitItem(ref sig, ref body) => {
+                            (AssociatedKind::Method, sig.decl.get_self().is_some(),
+                             body.is_some())
+                        }
+                        hir::ConstTraitItem(_, ref value) => {
+                            (AssociatedKind::Const, false, value.is_some())
+                        }
+                        hir::TypeTraitItem(_, ref ty) => {
+                            (AssociatedKind::Type, false, ty.is_some())
+                        }
+                    };
+
+                    AssociatedItem {
+                        name: trait_item.name,
+                        kind: kind,
+                        vis: Visibility::from_hir(&hir::Inherited, id, self),
+                        defaultness: hir::Defaultness::Default,
+                        has_value: has_value,
+                        def_id: def_id,
+                        container: TraitContainer(parent_def_id),
+                        method_has_self_argument: has_self
+                    }
+                }
+                ast_map::NodeImplItem(impl_item) => {
+                    let (kind, has_self) = match impl_item.node {
+                        hir::ImplItemKind::Method(ref sig, _) => {
+                            (AssociatedKind::Method, sig.decl.get_self().is_some())
+                        }
+                        hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false),
+                        hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false)
+                    };
+
+                    // Trait impl items are always public.
+                    let public = hir::Public;
+                    let parent_item = self.map.expect_item(parent_id);
+                    let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node {
+                        &public
+                    } else {
+                        &impl_item.vis
+                    };
+
+                    AssociatedItem {
+                        name: impl_item.name,
+                        kind: kind,
+                        vis: Visibility::from_hir(vis, id, self),
+                        defaultness: impl_item.defaultness,
+                        has_value: true,
+                        def_id: def_id,
+                        container: ImplContainer(parent_def_id),
+                        method_has_self_argument: has_self
+                    }
+                }
+                item => bug!("associated_item: {:?} not an associated item", item)
+            }
+        })
     }
 
-    pub fn impl_or_trait_items(self, id: DefId) -> Rc<Vec<DefId>> {
-        lookup_locally_or_in_crate_store(
-            "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids,
-            || Rc::new(self.sess.cstore.impl_or_trait_items(id)))
+    pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
+        self.associated_item_def_ids.memoize(def_id, || {
+            if !def_id.is_local() {
+                return Rc::new(self.sess.cstore.associated_item_def_ids(def_id));
+            }
+
+            let id = self.map.as_local_node_id(def_id).unwrap();
+            let item = self.map.expect_item(id);
+            match item.node {
+                hir::ItemTrait(.., ref trait_items) => {
+                    Rc::new(trait_items.iter().map(|trait_item| {
+                        self.map.local_def_id(trait_item.id)
+                    }).collect())
+                }
+                hir::ItemImpl(.., ref impl_items) => {
+                    Rc::new(impl_items.iter().map(|impl_item| {
+                        self.map.local_def_id(impl_item.id)
+                    }).collect())
+                }
+                _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
+            }
+        })
+    }
+
+    #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+    pub fn associated_items(self, def_id: DefId)
+                            -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+        let def_ids = self.associated_item_def_ids(def_id);
+        (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i]))
     }
 
     /// Returns the trait-ref corresponding to a given impl, or None if it is
@@ -2539,31 +2522,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL)
     }
 
-    /// Load primitive inherent implementations if necessary
-    pub fn populate_implementations_for_primitive_if_necessary(self,
-                                                               primitive_def_id: DefId) {
-        if primitive_def_id.is_local() {
-            return
-        }
-
-        // The primitive is not local, hence we are reading this out
-        // of metadata.
-        let _ignore = self.dep_graph.in_ignore();
-
-        if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) {
-            return
-        }
-
-        debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}",
-               primitive_def_id);
-
-        let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id);
-
-        // Store the implementation info.
-        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);
-    }
-
     /// Populates the type context with all the inherent implementations for
     /// the given type if necessary.
     pub fn populate_inherent_implementations_for_type_if_necessary(self,
@@ -2584,11 +2542,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                type_id);
 
         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_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);
         self.populated_external_types.borrow_mut().insert(type_id);
@@ -2617,23 +2570,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
 
         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.
             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 {
-                // load impl items eagerly for convenience
-                // FIXME: we may want to load these lazily
-                self.impl_or_trait_item(impl_item_def_id);
-            }
-
-            // Store the implementation info.
-            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);
@@ -2679,17 +2620,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// ID of the impl that the method belongs to. Otherwise, return `None`.
     pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
         if def_id.krate != LOCAL_CRATE {
-            return self.sess.cstore.impl_or_trait_item(self.global_tcx(), def_id)
+            return self.sess.cstore.associated_item(self.global_tcx(), def_id)
                        .and_then(|item| {
-                match item.container() {
+                match item.container {
                     TraitContainer(_) => None,
                     ImplContainer(def_id) => Some(def_id),
                 }
             });
         }
-        match self.impl_or_trait_items.borrow().get(&def_id).cloned() {
+        match self.associated_items.borrow().get(&def_id).cloned() {
             Some(trait_item) => {
-                match trait_item.container() {
+                match trait_item.container {
                     TraitContainer(_) => None,
                     ImplContainer(def_id) => Some(def_id),
                 }
@@ -2705,9 +2646,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         if def_id.krate != LOCAL_CRATE {
             return self.sess.cstore.trait_of_item(def_id);
         }
-        match self.impl_or_trait_items.borrow().get(&def_id) {
-            Some(impl_or_trait_item) => {
-                match impl_or_trait_item.container() {
+        match self.associated_items.borrow().get(&def_id) {
+            Some(associated_item) => {
+                match associated_item.container {
                     TraitContainer(def_id) => Some(def_id),
                     ImplContainer(_) => None
                 }
@@ -2716,30 +2657,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// If the given def ID describes an item belonging to a trait, (either a
-    /// default method or an implementation of a trait method), return the ID of
-    /// the method inside trait definition (this means that if the given def ID
-    /// 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<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.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.def_id())
-                })
-            }
-        }
-    }
-
     /// Construct a parameter environment suitable for static contexts or other contexts where there
     /// are no free type/lifetime parameters in scope.
     pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
@@ -2856,15 +2773,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-/// The category of explicit self.
-#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
-pub enum ExplicitSelfCategory<'tcx> {
-    Static,
-    ByValue,
-    ByReference(&'tcx Region, hir::Mutability),
-    ByBox,
-}
-
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn with_freevars<T, F>(self, fid: NodeId, f: F) -> T where
         F: FnOnce(&[hir::Freevar]) -> T,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 31304fb7b49..01b44ced8e0 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -670,18 +670,6 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ImplOrTraitItem(")?;
-        match *self {
-            ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i),
-            ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i),
-            ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i),
-        }?;
-        write!(f, ")")
-    }
-}
-
 impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "fn")?;
@@ -995,20 +983,6 @@ impl fmt::Display for ty::InferTy {
     }
 }
 
-impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str(match *self {
-            ty::ExplicitSelfCategory::Static => "static",
-            ty::ExplicitSelfCategory::ByValue => "self",
-            ty::ExplicitSelfCategory::ByReference(_, hir::MutMutable) => {
-                "&mut self"
-            }
-            ty::ExplicitSelfCategory::ByReference(_, hir::MutImmutable) => "&self",
-            ty::ExplicitSelfCategory::ByBox => "Box<self>",
-        })
-    }
-}
-
 impl fmt::Display for ty::ParamTy {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.name)
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index b2032e6a1bf..5ed628d7dca 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -190,7 +190,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      all_loans: &[Loan<'tcx>],
                                      fn_id: ast::NodeId,
                                      decl: &hir::FnDecl,
-                                     body: &hir::Block) {
+                                     body: &hir::Expr) {
     debug!("check_loans(body id={})", body.id);
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 763c012a8f8..8f2afa7f808 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -42,7 +42,7 @@ mod move_error;
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     fn_id: NodeId,
                                     decl: &hir::FnDecl,
-                                    body: &hir::Block)
+                                    body: &hir::Expr)
                                     -> (Vec<Loan<'tcx>>,
                                         move_data::MoveData<'tcx>) {
     let mut glcx = GatherLoanCtxt {
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index cea9170da9f..836832de5b9 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -58,7 +58,7 @@ pub struct MoveDataParamEnv<'tcx> {
 pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
                     fk: FnKind,
                     _decl: &hir::FnDecl,
-                    body: &hir::Block,
+                    body: &hir::Expr,
                     _sp: Span,
                     id: ast::NodeId,
                     attributes: &[ast::Attribute]) {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 2f74ea3e475..fb842f70a54 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -47,9 +47,7 @@ use syntax_pos::{MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
 use rustc::hir;
-use rustc::hir::{FnDecl, Block};
-use rustc::hir::intravisit;
-use rustc::hir::intravisit::{Visitor, FnKind};
+use rustc::hir::intravisit::{self, Visitor, FnKind};
 
 pub mod check_loans;
 
@@ -65,8 +63,8 @@ pub struct LoanDataFlowOperator;
 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
 
 impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
-                b: &'v Block, s: Span, id: ast::NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
+                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(..) |
             FnKind::Method(..) => {
@@ -159,7 +157,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
 fn borrowck_fn(this: &mut BorrowckCtxt,
                fk: FnKind,
                decl: &hir::FnDecl,
-               body: &hir::Block,
+               body: &hir::Expr,
                sp: Span,
                id: ast::NodeId,
                attributes: &[ast::Attribute]) {
@@ -200,7 +198,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                           fk: FnKind,
                                           decl: &hir::FnDecl,
                                           cfg: &cfg::CFG,
-                                          body: &hir::Block,
+                                          body: &hir::Expr,
                                           sp: Span,
                                           id: ast::NodeId)
                                           -> AnalysisData<'a, 'tcx>
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index afc4ccef0cc..32bda5e1162 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
                cfg: &cfg::CFG,
                id_range: IdRange,
                decl: &hir::FnDecl,
-               body: &hir::Block)
+               body: &hir::Expr)
                -> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_moves =
             DataFlowContext::new(tcx,
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 615aca90db8..e0e8a215919 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -65,7 +65,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, id: ast::NodeId) {
+                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
         if let FnKind::Closure(..) = fk {
             span_bug!(s, "check_match: closure outside of function")
         }
@@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, s: Span, n: ast::NodeId) {
+                b: &'v hir::Expr, s: Span, n: ast::NodeId) {
         intravisit::walk_fn(self, fk, fd, b, s, n);
 
         for input in &fd.inputs {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 57a5400ecad..5f0c94744a1 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -857,11 +857,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               callee => signal!(e, CallOn(callee)),
           };
           let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
-              (fn_like.decl(), &fn_like.body().expr)
+              (fn_like.decl(), fn_like.body())
           } else {
               signal!(e, NonConstPath)
           };
-          let result = result.as_ref().expect("const fn has no result expression");
           assert_eq!(decl.inputs.len(), args.len());
 
           let mut call_args = DefIdMap();
@@ -1091,13 +1090,8 @@ 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) => {
-                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);
+                let ac = tcx.associated_items(impl_data.impl_def_id)
+                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name);
                 match ac {
                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
                     None => match ti.node {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 6551bad3bc9..7e60c40220f 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -455,8 +455,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
             1 => panic!("make_input should have provided valid inputs"),
             _ => early_error(sopts.error_format, "multiple input filenames provided"),
         }
-
-        None
     }
 
     fn late_callback(&mut self,
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index b4ab9da92e9..ecbf28c1082 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -701,8 +701,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
                                        mut out: W)
                                        -> io::Result<()> {
     let cfg = match code {
-        blocks::BlockCode(block) => cfg::CFG::new(tcx, &block),
-        blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()),
+        blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
+        blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()),
     };
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
     let lcfg = LabelledCFG {
@@ -717,12 +717,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
             let r = dot::render(&lcfg, &mut out);
             return expand_err_details(r);
         }
-        blocks::BlockCode(_) => {
+        blocks::Code::Expr(_) => {
             tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \
                           fn-like node id.");
             return Ok(());
         }
-        blocks::FnLikeCode(fn_like) => {
+        blocks::Code::FnLike(fn_like) => {
             let (bccx, analysis_data) =
                 borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg);
 
@@ -990,8 +990,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                     tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
                 });
 
-                let code = blocks::Code::from_node(node);
-                match code {
+                match blocks::Code::from_node(&tcx.map, nodeid) {
                     Some(code) => {
                         let variants = gather_flowgraph_variants(tcx.sess);
 
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index fea3de59520..6320a923d69 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -29,10 +29,10 @@ pub enum MethodLateContext {
 
 pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
     let def_id = cx.tcx.map.local_def_id(id);
-    match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
+    match cx.tcx.associated_items.borrow().get(&def_id) {
         None => span_bug!(span, "missing method descriptor?!"),
         Some(item) => {
-            match item.container() {
+            match item.container {
                 ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
                 ty::ImplContainer(cid) => {
                     match cx.tcx.impl_trait_ref(cid) {
@@ -250,7 +250,7 @@ impl LateLintPass for NonSnakeCase {
                 cx: &LateContext,
                 fk: FnKind,
                 _: &hir::FnDecl,
-                _: &hir::Block,
+                _: &hir::Expr,
                 span: Span,
                 id: ast::NodeId) {
         match fk {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 28dc71fd59b..c19b3c40f65 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -222,7 +222,7 @@ impl LateLintPass for UnsafeCode {
                 cx: &LateContext,
                 fk: FnKind,
                 _: &hir::FnDecl,
-                _: &hir::Block,
+                _: &hir::Expr,
                 span: Span,
                 _: ast::NodeId) {
         match fk {
@@ -812,13 +812,13 @@ impl LateLintPass for UnconditionalRecursion {
                 cx: &LateContext,
                 fn_kind: FnKind,
                 _: &hir::FnDecl,
-                blk: &hir::Block,
+                blk: &hir::Expr,
                 sp: Span,
                 id: ast::NodeId) {
         let method = match fn_kind {
             FnKind::ItemFn(..) => None,
             FnKind::Method(..) => {
-                cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
+                Some(cx.tcx.associated_item(cx.tcx.map.local_def_id(id)))
             }
             // closures can't recur, so they don't matter.
             FnKind::Closure(_) => return,
@@ -937,7 +937,7 @@ impl LateLintPass for UnconditionalRecursion {
 
         // Check if the expression `id` performs a call to `method`.
         fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                method: &ty::Method,
+                                                method: &ty::AssociatedItem,
                                                 id: ast::NodeId)
                                                 -> bool {
             use rustc::ty::adjustment::*;
@@ -986,14 +986,14 @@ impl LateLintPass for UnconditionalRecursion {
         // Check if the method call to the method with the ID `callee_id`
         // and instantiated with `callee_substs` refers to method `method`.
         fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                  method: &ty::Method,
+                                                  method: &ty::AssociatedItem,
                                                   callee_id: DefId,
                                                   callee_substs: &Substs<'tcx>,
                                                   expr_id: ast::NodeId)
                                                   -> bool {
-            let callee_item = tcx.impl_or_trait_item(callee_id);
+            let callee_item = tcx.associated_item(callee_id);
 
-            match callee_item.container() {
+            match callee_item.container {
                 // This is an inherent method, so the `def_id` refers
                 // directly to the method definition.
                 ty::ImplContainer(_) => callee_id == method.def_id,
@@ -1034,7 +1034,7 @@ impl LateLintPass for UnconditionalRecursion {
                                 let container = ty::ImplContainer(vtable_impl.impl_def_id);
                                 // It matches if it comes from the same impl,
                                 // and has the same method name.
-                                container == method.container && callee_item.name() == method.name
+                                container == method.container && callee_item.name == method.name
                             }
 
                             // There's no way to know if this call is
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index d3fd638d6b5..0668d362037 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -99,7 +99,7 @@ impl LateLintPass for UnusedMut {
                 cx: &LateContext,
                 _: FnKind,
                 decl: &hir::FnDecl,
-                _: &hir::Block,
+                _: &hir::Expr,
                 _: Span,
                 _: ast::NodeId) {
         for a in &decl.inputs {
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 4d3a4d09dce..8656bb8bf00 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -136,7 +136,7 @@ fn main() {
     let mut parts = version_output.split('.');
     if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::<u32>().ok()),
                                          parts.next().and_then(|s| s.parse::<u32>().ok())) {
-        if major > 3 || (major == 3 && minor >= 8) {
+        if major > 3 || (major == 3 && minor >= 9) {
             cmd.arg("--link-static");
         }
     }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index a618c98ff77..18ce514c9c4 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -144,7 +144,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         result
     }
 
-    fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId> {
+    fn associated_item_def_ids(&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)
@@ -182,11 +182,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         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>>
+    fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> Option<ty::AssociatedItem>
     {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx)
+        self.get_crate_data(def.krate).get_associated_item(def.index)
     }
 
     fn is_const_fn(&self, did: DefId) -> bool
@@ -427,9 +427,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                 // the logic to do that already exists in `middle`. In order to
                 // reuse that code, it needs to be able to look up the traits for
                 // inlined items.
-                let ty_trait_item = tcx.impl_or_trait_item(def_id).clone();
+                let ty_trait_item = tcx.associated_item(def_id).clone();
                 let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
-                tcx.impl_or_trait_items.borrow_mut()
+                tcx.associated_items.borrow_mut()
                    .insert(trait_item_def_id, ty_trait_item);
             }
             Some(&InlinedItem::ImplItem(_, ref impl_item)) => {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 630b0774424..7973cd880fe 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -36,7 +36,6 @@ use std::borrow::Cow;
 use std::cell::Ref;
 use std::io;
 use std::mem;
-use std::rc::Rc;
 use std::str;
 use std::u32;
 
@@ -792,10 +791,7 @@ impl<'a, 'tcx> CrateMetadata {
         self.entry(id).mir.map(|mir| mir.decode((self, tcx)))
     }
 
-    pub fn get_impl_or_trait_item(&self,
-                                  id: DefIndex,
-                                  tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                  -> Option<ty::ImplOrTraitItem<'tcx>> {
+    pub fn get_associated_item(&self, id: DefIndex) -> Option<ty::AssociatedItem> {
         let item = self.entry(id);
         let parent_and_name = || {
             let def_key = item.def_key.decode(self);
@@ -806,52 +802,43 @@ impl<'a, 'tcx> CrateMetadata {
         Some(match item.kind {
             EntryKind::AssociatedConst(container) => {
                 let (parent, name) = parent_and_name();
-                ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+                ty::AssociatedItem {
                     name: name,
-                    ty: item.ty.unwrap().decode((self, tcx)),
+                    kind: ty::AssociatedKind::Const,
                     vis: item.visibility,
                     defaultness: container.defaultness(),
+                    has_value: container.has_value(),
                     def_id: self.local_def_id(id),
                     container: container.with_def_id(parent),
-                    has_value: container.has_body(),
-                }))
+                    method_has_self_argument: false
+                }
             }
             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 {
+                ty::AssociatedItem {
                     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)),
+                    kind: ty::AssociatedKind::Method,
                     vis: item.visibility,
                     defaultness: data.container.defaultness(),
-                    has_body: data.container.has_body(),
+                    has_value: data.container.has_value(),
                     def_id: self.local_def_id(id),
                     container: data.container.with_def_id(parent),
-                }))
+                    method_has_self_argument: data.has_self
+                }
             }
             EntryKind::AssociatedType(container) => {
                 let (parent, name) = parent_and_name();
-                ty::TypeTraitItem(Rc::new(ty::AssociatedType {
+                ty::AssociatedItem {
                     name: name,
-                    ty: item.ty.map(|ty| ty.decode((self, tcx))),
+                    kind: ty::AssociatedKind::Type,
                     vis: item.visibility,
                     defaultness: container.defaultness(),
+                    has_value: container.has_value(),
                     def_id: self.local_def_id(id),
                     container: container.with_def_id(parent),
-                }))
+                    method_has_self_argument: false
+                }
             }
             _ => return None,
         })
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index fb4fb507296..2379e744c49 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -457,19 +457,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         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);
+        let trait_item = tcx.associated_item(def_id);
 
-        let container = |has_body| if has_body {
+        let container = if trait_item.has_value {
             AssociatedContainer::TraitWithDefault
         } else {
             AssociatedContainer::TraitRequired
         };
 
-        let kind = match trait_item {
-            ty::ConstTraitItem(ref associated_const) => {
-                EntryKind::AssociatedConst(container(associated_const.has_value))
-            }
-            ty::MethodTraitItem(ref method_ty) => {
+        let kind = match trait_item.kind {
+            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Method => {
                 let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
                     FnData {
                         constness: hir::Constness::NotConst,
@@ -478,30 +476,35 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 } else {
                     bug!()
                 };
-                let data = MethodData {
+                EntryKind::Method(self.lazy(&MethodData {
                     fn_data: fn_data,
-                    container: container(method_ty.has_body),
-                    explicit_self: self.lazy(&method_ty.explicit_self),
-                };
-                EntryKind::Method(self.lazy(&data))
+                    container: container,
+                    has_self: trait_item.method_has_self_argument,
+                }))
             }
-            ty::TypeTraitItem(_) => EntryKind::AssociatedType(container(false)),
+            ty::AssociatedKind::Type => EntryKind::AssociatedType(container),
         };
 
         Entry {
             kind: kind,
-            visibility: trait_item.vis().simplify(),
+            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)),
-                ty::TypeTraitItem(ref associated_type) => {
-                    associated_type.ty.map(|ty| self.lazy(&ty))
+            ty: match trait_item.kind {
+                ty::AssociatedKind::Const |
+                ty::AssociatedKind::Method => {
+                    Some(self.encode_item_type(def_id))
+                }
+                ty::AssociatedKind::Type => {
+                    if trait_item.has_value {
+                        Some(self.encode_item_type(def_id))
+                    } else {
+                        None
+                    }
                 }
             },
             inherent_impls: LazySeq::empty(),
@@ -509,8 +512,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             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();
+            ast: if trait_item.kind == ty::AssociatedKind::Const {
+                let trait_def_id = trait_item.container.id();
                 Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
             } else {
                 None
@@ -522,17 +525,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     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 impl_item = self.tcx.associated_item(def_id);
+        let impl_def_id = impl_item.container.id();
 
-        let container = match ast_item.defaultness {
+        let container = match impl_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_ty) => {
+        let kind = match impl_item.kind {
+            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Method => {
                 let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
                     FnData {
                         constness: sig.constness,
@@ -541,17 +544,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 } else {
                     bug!()
                 };
-                let data = MethodData {
+                EntryKind::Method(self.lazy(&MethodData {
                     fn_data: fn_data,
                     container: container,
-                    explicit_self: self.lazy(&method_ty.explicit_self),
-                };
-                EntryKind::Method(self.lazy(&data))
+                    has_self: impl_item.method_has_self_argument,
+                }))
             }
-            ty::TypeTraitItem(_) => EntryKind::AssociatedType(container),
+            ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
         };
 
-        let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item {
+        let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const {
             (true, true)
         } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
             let generics = self.tcx.lookup_generics(def_id);
@@ -565,20 +567,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         Entry {
             kind: kind,
-            visibility: impl_item.vis().simplify(),
+            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)),
-                ty::TypeTraitItem(ref associated_type) => {
-                    associated_type.ty.map(|ty| self.lazy(&ty))
-                }
-            },
+            ty: Some(self.encode_item_type(def_id)),
             inherent_impls: LazySeq::empty(),
             variances: LazySeq::empty(),
             generics: Some(self.encode_generics(def_id)),
@@ -758,7 +754,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
                 hir::ItemImpl(..) |
                 hir::ItemTrait(..) => {
-                    self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| {
+                    self.lazy_seq(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| {
                         assert!(def_id.is_local());
                         def_id.index
                     }))
@@ -880,14 +876,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
                 self.encode_fields(def_id);
             }
             hir::ItemImpl(..) => {
-                for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] {
                     self.record(trait_item_def_id,
                                 EncodeContext::encode_info_for_impl_item,
                                 trait_item_def_id);
                 }
             }
             hir::ItemTrait(..) => {
-                for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] {
                     self.record(item_def_id,
                                 EncodeContext::encode_info_for_trait_item,
                                 item_def_id);
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 3d1bd77d8bc..ff2a7645710 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -245,7 +245,7 @@ pub enum EntryKind<'tcx> {
     Trait(Lazy<TraitData<'tcx>>),
     Impl(Lazy<ImplData<'tcx>>),
     DefaultImpl(Lazy<ImplData<'tcx>>),
-    Method(Lazy<MethodData<'tcx>>),
+    Method(Lazy<MethodData>),
     AssociatedType(AssociatedContainer),
     AssociatedConst(AssociatedContainer),
 }
@@ -300,7 +300,7 @@ pub enum AssociatedContainer {
 }
 
 impl AssociatedContainer {
-    pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer {
+    pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer {
         match *self {
             AssociatedContainer::TraitRequired |
             AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id),
@@ -310,7 +310,7 @@ impl AssociatedContainer {
         }
     }
 
-    pub fn has_body(&self) -> bool {
+    pub fn has_value(&self) -> bool {
         match *self {
             AssociatedContainer::TraitRequired => false,
 
@@ -332,10 +332,10 @@ impl AssociatedContainer {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct MethodData<'tcx> {
+pub struct MethodData {
     pub fn_data: FnData,
     pub container: AssociatedContainer,
-    pub explicit_self: Lazy<ty::ExplicitSelfCategory<'tcx>>,
+    pub has_self: bool,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index b37dd8dd0a9..902798ec980 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -156,7 +156,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        fn_id: ast::NodeId,
                                        arguments: A,
                                        return_ty: Ty<'gcx>,
-                                       ast_block: &'gcx hir::Block)
+                                       ast_body: &'gcx hir::Expr)
                                        -> (Mir<'tcx>, ScopeAuxiliaryVec)
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
@@ -166,7 +166,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let span = tcx.map.span(fn_id);
     let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
 
-    let body_id = ast_block.id;
+    let body_id = ast_body.id;
     let call_site_extent =
         tcx.region_maps.lookup_code_extent(
             CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
@@ -176,7 +176,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
         unpack!(block = builder.in_scope(arg_extent, block, |builder| {
-            builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block)
+            builder.args_and_body(block, &arguments, arg_extent, ast_body)
         }));
         // Attribute epilogue to function's closing brace
         let fn_end = Span { lo: span.hi, ..span };
@@ -310,10 +310,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn args_and_body(&mut self,
                      mut block: BasicBlock,
-                     return_ty: Ty<'tcx>,
                      arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
                      argument_extent: CodeExtent,
-                     ast_block: &'gcx hir::Block)
+                     ast_body: &'gcx hir::Expr)
                      -> BlockAnd<()>
     {
         // Allocate locals for the function arguments
@@ -342,12 +341,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             if let Some(pattern) = pattern {
                 let pattern = Pattern::from_hir(self.hir.tcx(), pattern);
-                scope = self.declare_bindings(scope, ast_block.span, &pattern);
+                scope = self.declare_bindings(scope, ast_body.span, &pattern);
                 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
             }
 
             // Make sure we drop (parts of) the argument even when not matched on.
-            self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
+            self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span),
                                argument_extent, &lvalue, ty);
 
         }
@@ -357,13 +356,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.visibility_scope = visibility_scope;
         }
 
-        // FIXME(#32959): temporary hack for the issue at hand
-        let return_is_unit = return_ty.is_nil();
-        // start the first basic block and translate the body
-        unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER),
-                return_is_unit, block, ast_block));
-
-        block.unit()
+        let body = self.hir.mirror(ast_body);
+        self.into(&Lvalue::Local(RETURN_POINTER), block, body)
     }
 
     fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 678db1e544c..ecc2d8fe050 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -147,20 +147,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                         -> (Ty<'tcx>, Literal<'tcx>) {
         let method_name = token::intern(method_name);
         let substs = self.tcx.mk_substs_trait(self_ty, params);
-        for trait_item in self.tcx.trait_items(trait_def_id).iter() {
-            match *trait_item {
-                ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
-                    if method.name == method_name {
-                        let method_ty = self.tcx.lookup_item_type(method.def_id);
-                        let method_ty = method_ty.ty.subst(self.tcx, substs);
-                        return (method_ty, Literal::Item {
-                            def_id: method.def_id,
-                            substs: substs,
-                        });
-                    }
-                }
-                ty::ImplOrTraitItem::ConstTraitItem(..) |
-                ty::ImplOrTraitItem::TypeTraitItem(..) => {}
+        for item in self.tcx.associated_items(trait_def_id) {
+            if item.kind == ty::AssociatedKind::Method && item.name == method_name {
+                let method_ty = self.tcx.lookup_item_type(item.def_id);
+                let method_ty = method_ty.ty.subst(self.tcx, substs);
+                return (method_ty, Literal::Item {
+                    def_id: item.def_id,
+                    substs: substs,
+                });
             }
         }
 
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 0ffc59fe6bf..af2f9adfc9a 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'tcx>,
                 decl: &'tcx hir::FnDecl,
-                body: &'tcx hir::Block,
+                body: &'tcx hir::Expr,
                 span: Span,
                 id: ast::NodeId) {
         // fetch the fully liberated fn signature (that is, all bound
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index f23539e88f7..02a0b3ab28d 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -134,7 +134,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn fn_like(&mut self,
                fk: FnKind,
                fd: &hir::FnDecl,
-               b: &hir::Block,
+               b: &hir::Expr,
                s: Span,
                fn_id: ast::NodeId)
                -> ConstQualif {
@@ -265,7 +265,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'v>,
                 fd: &'v hir::FnDecl,
-                b: &'v hir::Block,
+                b: &'v hir::Expr,
                 s: Span,
                 fn_id: ast::NodeId) {
         self.fn_like(fk, fd, b, s, fn_id);
@@ -542,7 +542,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                     v.handle_const_fn_call(e, did, node_ty)
                 }
                 Some(Def::Method(did)) => {
-                    match v.tcx.impl_or_trait_item(did).container() {
+                    match v.tcx.associated_item(did).container {
                         ty::ImplContainer(_) => {
                             v.handle_const_fn_call(e, did, node_ty)
                         }
@@ -557,7 +557,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         }
         hir::ExprMethodCall(..) => {
             let method = v.tcx.tables().method_map[&method_call];
-            let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
+            let is_const = match v.tcx.associated_item(method.def_id).container {
                 ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
                 ty::TraitContainer(_) => false
             };
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 84cf85e2fc4..417987d9664 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -164,7 +164,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_fn(&mut self,
                 fk: hir_visit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
-                b: &'v hir::Block,
+                b: &'v hir::Expr,
                 s: Span,
                 id: NodeId) {
         self.record("FnDecl", Id::None, fd);
@@ -295,11 +295,10 @@ impl<'v> ast_visit::Visitor for StatCollector<'v> {
     fn visit_fn(&mut self,
                 fk: ast_visit::FnKind,
                 fd: &ast::FnDecl,
-                b: &ast::Block,
                 s: Span,
                 _: NodeId) {
         self.record("FnDecl", Id::None, fd);
-        ast_visit::walk_fn(self, fk, fd, b, s)
+        ast_visit::walk_fn(self, fk, fd, s)
     }
 
     fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index e942707acd5..e58cd893819 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -54,7 +54,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
                 self.with_context(Loop, |v| v.visit_block(&b));
             }
             hir::ExprClosure(.., ref b, _) => {
-                self.with_context(Closure, |v| v.visit_block(&b));
+                self.with_context(Closure, |v| v.visit_expr(&b));
             }
             hir::ExprBreak(_) => self.require_loop("break", e.span),
             hir::ExprAgain(_) => self.require_loop("continue", e.span),
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index c3ef5a72a29..d55ce4c3563 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -35,7 +35,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
-                b: &'v hir::Block,
+                b: &'v hir::Expr,
                 s: Span,
                 fn_id: ast::NodeId) {
         // FIXME (@jroesch) change this to be an inference context
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index cbe2cd2628d..dc7399e2289 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -399,7 +399,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
 
     // Checks that a method is in scope.
     fn check_method(&mut self, span: Span, method_def_id: DefId) {
-        match self.tcx.impl_or_trait_item(method_def_id).container() {
+        match self.tcx.associated_item(method_def_id).container {
             // Trait methods are always all public. The only controlling factor
             // is whether the trait itself is accessible or not.
             ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 1e998a2a4d5..cb8dd7250b4 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -456,7 +456,7 @@ impl<'b> Resolver<'b> {
                 self.define(parent, name, TypeNS, (module, DUMMY_SP, vis));
 
                 // If this is a trait, add all the trait item names to the trait info.
-                let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id);
+                let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id);
                 for trait_item_def_id in trait_item_def_ids {
                     let trait_item_name = self.session.cstore.def_key(trait_item_def_id)
                                               .disambiguated_data.data.get_opt_name()
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0c7c1a55a61..664efc27fbb 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -596,7 +596,6 @@ impl<'a> Visitor for Resolver<'a> {
     fn visit_fn(&mut self,
                 function_kind: FnKind,
                 declaration: &FnDecl,
-                block: &Block,
                 _: Span,
                 node_id: NodeId) {
         let rib_kind = match function_kind {
@@ -604,13 +603,45 @@ impl<'a> Visitor for Resolver<'a> {
                 self.visit_generics(generics);
                 ItemRibKind
             }
-            FnKind::Method(_, sig, _) => {
+            FnKind::Method(_, sig, _, _) => {
                 self.visit_generics(&sig.generics);
                 MethodRibKind(!sig.decl.has_self())
             }
-            FnKind::Closure => ClosureRibKind(node_id),
+            FnKind::Closure(_) => ClosureRibKind(node_id),
         };
-        self.resolve_function(rib_kind, declaration, block);
+
+        // Create a value rib for the function.
+        self.value_ribs.push(Rib::new(rib_kind));
+
+        // Create a label rib for the function.
+        self.label_ribs.push(Rib::new(rib_kind));
+
+        // Add each argument to the rib.
+        let mut bindings_list = FxHashMap();
+        for argument in &declaration.inputs {
+            self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
+
+            self.visit_ty(&argument.ty);
+
+            debug!("(resolving function) recorded argument");
+        }
+        visit::walk_fn_ret_ty(self, &declaration.output);
+
+        // Resolve the function body.
+        match function_kind {
+            FnKind::ItemFn(.., body) |
+            FnKind::Method(.., body) => {
+                self.visit_block(body);
+            }
+            FnKind::Closure(body) => {
+                self.visit_expr(body);
+            }
+        };
+
+        debug!("(resolving function) leaving function");
+
+        self.label_ribs.pop();
+        self.value_ribs.pop();
     }
 }
 
@@ -1856,36 +1887,6 @@ impl<'a> Resolver<'a> {
         self.value_ribs.pop();
     }
 
-    fn resolve_function(&mut self,
-                        rib_kind: RibKind<'a>,
-                        declaration: &FnDecl,
-                        block: &Block) {
-        // Create a value rib for the function.
-        self.value_ribs.push(Rib::new(rib_kind));
-
-        // Create a label rib for the function.
-        self.label_ribs.push(Rib::new(rib_kind));
-
-        // Add each argument to the rib.
-        let mut bindings_list = FxHashMap();
-        for argument in &declaration.inputs {
-            self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
-
-            self.visit_ty(&argument.ty);
-
-            debug!("(resolving function) recorded argument");
-        }
-        visit::walk_fn_ret_ty(self, &declaration.output);
-
-        // Resolve the function body.
-        self.visit_block(block);
-
-        debug!("(resolving function) leaving function");
-
-        self.label_ribs.pop();
-        self.value_ribs.pop();
-    }
-
     fn resolve_trait_reference(&mut self,
                                id: NodeId,
                                trait_path: &Path,
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index db4788c3cea..36c6a676013 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -32,7 +32,7 @@ use rustc::hir::def::Def;
 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};
+use rustc::ty::{self, TyCtxt, AssociatedItemContainer};
 
 use std::collections::HashSet;
 use std::collections::hash_map::DefaultHasher;
@@ -402,19 +402,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             // with the right name.
             if !self.span.filter_generated(Some(method_data.span), span) {
                 let container =
-                    self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container();
+                    self.tcx.associated_item(self.tcx.map.local_def_id(id)).container;
                 let mut trait_id;
                 let mut decl_id = None;
                 match container {
-                    ImplOrTraitItemContainer::ImplContainer(id) => {
+                    AssociatedItemContainer::ImplContainer(id) => {
                         trait_id = self.tcx.trait_id_of_impl(id);
 
                         match trait_id {
                             Some(id) => {
-                                for item in &**self.tcx.trait_items(id) {
-                                    if let &ImplOrTraitItem::MethodTraitItem(ref m) = item {
-                                        if m.name == name {
-                                            decl_id = Some(m.def_id);
+                                for item in self.tcx.associated_items(id) {
+                                    if item.kind == ty::AssociatedKind::Method {
+                                        if item.name == name {
+                                            decl_id = Some(item.def_id);
                                             break;
                                         }
                                     }
@@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                             }
                         }
                     }
-                    ImplOrTraitItemContainer::TraitContainer(id) => {
+                    AssociatedItemContainer::TraitContainer(id) => {
                         trait_id = Some(id);
                     }
                 }
@@ -916,11 +916,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         // Modules or types in the path prefix.
         match self.tcx.expect_def(id) {
             Def::Method(did) => {
-                let ti = self.tcx.impl_or_trait_item(did);
-                if let ty::MethodTraitItem(m) = ti {
-                    if m.explicit_self == ty::ExplicitSelfCategory::Static {
-                        self.write_sub_path_trait_truncated(path);
-                    }
+                let ti = self.tcx.associated_item(did);
+                if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
+                    self.write_sub_path_trait_truncated(path);
                 }
             }
             Def::Fn(..) |
@@ -1414,7 +1412,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 }
 
                 // walk the body
-                self.nest(ex.id, |v| v.visit_block(&body));
+                self.nest(ex.id, |v| v.visit_expr(body));
             }
             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
             ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index e1b67d211a3..fded34d2c85 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -313,7 +313,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                            name: ast::Name, span: Span) -> Option<FunctionData> {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let (qualname, parent_scope, vis, docs) =
+        let (qualname, parent_scope, decl_id, vis, docs) =
           match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
             Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
                 Some(NodeItem(item)) => {
@@ -323,12 +323,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                             result.push_str(&rustc::hir::print::ty_to_string(&ty));
 
                             let trait_id = self.tcx.trait_id_of_impl(impl_id);
+                            let mut decl_id = None;
                             if let Some(def_id) = trait_id {
                                 result.push_str(" as ");
                                 result.push_str(&self.tcx.item_path_str(def_id));
+                                self.tcx.associated_items(def_id)
+                                    .find(|item| item.name == name)
+                                    .map(|item| decl_id = Some(item.def_id));
                             }
                             result.push_str(">");
-                            (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs))
+
+                            (result, trait_id, decl_id,
+                             From::from(&item.vis),
+                             docs_for_attrs(&item.attrs))
                         }
                         _ => {
                             span_bug!(span,
@@ -351,7 +358,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     match self.tcx.map.get_if_local(def_id) {
                         Some(NodeItem(item)) => {
                             (format!("::{}", self.tcx.item_path_str(def_id)),
-                             Some(def_id),
+                             Some(def_id), None,
                              From::from(&item.vis),
                              docs_for_attrs(&item.attrs))
                         }
@@ -373,15 +380,6 @@ 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_def_id| {
-            if new_def_id != def_id {
-                Some(new_def_id)
-            } else {
-                None
-            }
-        });
-
         let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
         filter!(self.span_utils, sub_span, span, None);
         Some(FunctionData {
@@ -473,7 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             ast::ExprKind::MethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
                 let method_id = self.tcx.tables().method_map[&method_call].def_id;
-                let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() {
+                let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
                     ty::ImplContainer(_) => (Some(method_id), None),
                     ty::TraitContainer(_) => (None, Some(method_id)),
                 };
@@ -535,21 +533,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
                 filter!(self.span_utils, sub_span, path.span, None);
                 let def_id = if decl_id.is_local() {
-                    let ti = self.tcx.impl_or_trait_item(decl_id);
-                    match ti.container() {
-                        ty::TraitContainer(def_id) => {
-                            self.tcx
-                                .trait_items(def_id)
-                                .iter()
-                                .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr))
-                                .map(|mr| mr.def_id())
-                        }
-                        ty::ImplContainer(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())
-                        }
-                    }
+                    let ti = self.tcx.associated_item(decl_id);
+                    self.tcx.associated_items(ti.container.id())
+                        .find(|item| item.name == ti.name && item.has_value)
+                        .map(|item| item.def_id)
                 } else {
                     None
                 };
@@ -582,20 +569,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
-        let def_id = mr.def_id();
-        if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
-            let trait_item = self.tcx.map.expect_trait_item(node_id);
-            if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
-                true
-            } else {
-                false
-            }
-        } else {
-            false
-        }
-    }
-
     pub fn get_field_ref_data(&self,
                               field_ref: &ast::Field,
                               variant: ty::VariantDef,
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 548554af972..2c0ba36f3b4 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -844,17 +844,12 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
            param_substs);
 
     if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) {
-        match scx.tcx().impl_or_trait_item(fn_def_id) {
-            ty::MethodTraitItem(ref method) => {
-                debug!(" => trait method, attempting to find impl");
-                do_static_trait_method_dispatch(scx,
-                                                method,
-                                                trait_def_id,
-                                                fn_substs,
-                                                param_substs)
-            }
-            _ => bug!()
-        }
+        debug!(" => trait method, attempting to find impl");
+        do_static_trait_method_dispatch(scx,
+                                        &scx.tcx().associated_item(fn_def_id),
+                                        trait_def_id,
+                                        fn_substs,
+                                        param_substs)
     } else {
         debug!(" => regular function");
         // The function is not part of an impl or trait, no dispatching
@@ -866,7 +861,7 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 // Given a trait-method and substitution information, find out the actual
 // implementation of the trait method.
 fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                             trait_method: &ty::Method,
+                                             trait_method: &ty::AssociatedItem,
                                              trait_id: DefId,
                                              callee_substs: &'tcx Substs<'tcx>,
                                              param_substs: &'tcx Substs<'tcx>)
@@ -1187,7 +1182,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
                         continue;
                     }
 
-                    if !method.generics.types.is_empty() {
+                    if !tcx.lookup_generics(method.def_id).types.is_empty() {
                         continue;
                     }
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 3d0d8897609..b8d346b11c1 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -248,13 +248,8 @@ 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);
-                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);
+                let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id)
+                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 if let Some(ac) = ac {
                     instance = Instance::new(ac.def_id, vtable_impl.substs);
                 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 57936f8a4b3..513b4860d5e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -107,11 +107,6 @@ pub trait AstConv<'gcx, 'tcx> {
     fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
                                  -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
 
-    /// Returns true if the trait with id `trait_def_id` defines an
-    /// associated type with the name `name`.
-    fn trait_defines_associated_type_named(&self, trait_def_id: DefId, name: ast::Name)
-                                           -> bool;
-
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
     /// within a fn body.
@@ -831,6 +826,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                         Some(self_ty))
     }
 
+    fn trait_defines_associated_type_named(&self,
+                                           trait_def_id: DefId,
+                                           assoc_name: ast::Name)
+                                           -> bool
+    {
+        self.tcx().associated_items(trait_def_id).any(|item| {
+            item.kind == ty::AssociatedKind::Type && item.name == assoc_name
+        })
+    }
+
     fn ast_type_binding_to_poly_projection_predicate(
         &self,
         path_id: ast::NodeId,
@@ -1144,20 +1149,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let mut associated_types = FxHashSet::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)));
-            }
+            associated_types.extend(tcx.associated_items(tr.def_id())
+                .filter(|item| item.kind == ty::AssociatedKind::Type)
+                .map(|item| (tr.def_id(), item.name)));
         }
 
         for projection_bound in &projection_bounds {
@@ -1260,14 +1254,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         if bounds.len() > 1 {
             let spans = bounds.iter().map(|b| {
-                self.tcx().impl_or_trait_items(b.def_id()).iter()
-                .find(|&&def_id| {
-                    match self.tcx().impl_or_trait_item(def_id) {
-                        ty::TypeTraitItem(ref item) => item.name.as_str() == assoc_name,
-                        _ => false
-                    }
+                self.tcx().associated_items(b.def_id()).find(|item| {
+                    item.kind == ty::AssociatedKind::Type && item.name.as_str() == assoc_name
                 })
-                .and_then(|&def_id| self.tcx().map.as_local_node_id(def_id))
+                .and_then(|item| self.tcx().map.as_local_node_id(item.def_id))
                 .and_then(|node_id| self.tcx().map.opt_span(node_id))
             });
 
@@ -1383,25 +1373,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let trait_did = bound.0.def_id;
         let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
 
-        let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) {
-            // `ty::trait_items` used below requires information generated
-            // by type collection, which may be in progress at this point.
-            match tcx.map.expect_item(trait_id).node {
-                hir::ItemTrait(.., ref trait_items) => {
-                    let item = trait_items.iter()
-                                          .find(|i| i.name == assoc_name)
-                                          .expect("missing associated type");
-                    tcx.map.local_def_id(item.id)
-                }
-                _ => bug!()
-            }
-        } else {
-            let trait_items = tcx.trait_items(trait_did);
-            let item = trait_items.iter().find(|i| i.name() == assoc_name);
-            item.expect("missing associated type").def_id()
-        };
-
-        (ty, Def::AssociatedTy(item_did))
+        let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name);
+        (ty, Def::AssociatedTy(item.expect("missing associated type").def_id))
     }
 
     fn qpath_to_ty(&self,
@@ -1694,13 +1667,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyBareFn(ref bf) => {
                 require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
                 let anon_scope = rscope.anon_type_scope();
-                let (bare_fn_ty, _) =
-                    self.ty_of_method_or_bare_fn(bf.unsafety,
-                                                 bf.abi,
-                                                 None,
-                                                 &bf.decl,
-                                                 anon_scope,
-                                                 anon_scope);
+                let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety,
+                                                              bf.abi,
+                                                              None,
+                                                              &bf.decl,
+                                                              anon_scope,
+                                                              anon_scope);
 
                 // Find any late-bound regions declared in return type that do
                 // not appear in the arguments. These are not wellformed.
@@ -1842,7 +1814,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         sig: &hir::MethodSig,
                         untransformed_self_ty: Ty<'tcx>,
                         anon_scope: Option<AnonTypeScope>)
-                        -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) {
+                        -> &'tcx ty::BareFnTy<'tcx> {
         self.ty_of_method_or_bare_fn(sig.unsafety,
                                      sig.abi,
                                      Some(untransformed_self_ty),
@@ -1857,7 +1829,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                          decl: &hir::FnDecl,
                          anon_scope: Option<AnonTypeScope>)
                          -> &'tcx ty::BareFnTy<'tcx> {
-        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0
+        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
     }
 
     fn ty_of_method_or_bare_fn(&self,
@@ -1867,7 +1839,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                decl: &hir::FnDecl,
                                arg_anon_scope: Option<AnonTypeScope>,
                                ret_anon_scope: Option<AnonTypeScope>)
-                               -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>)
+                               -> &'tcx ty::BareFnTy<'tcx>
     {
         debug!("ty_of_method_or_bare_fn");
 
@@ -1880,13 +1852,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // lifetime elision, we can determine it in two ways. First (determined
         // here), if self is by-reference, then the implied output region is the
         // region of the self parameter.
-        let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) {
+        let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
             (Some(untransformed_self_ty), Some(explicit_self)) => {
                 let self_type = self.determine_self_type(&rb, untransformed_self_ty,
                                                          &explicit_self);
-                (Some(self_type.0), self_type.1)
+                (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
             }
-            _ => (None, ty::ExplicitSelfCategory::Static),
+            _ => (None, None),
         };
 
         // HACK(eddyb) replace the fake self type in the AST with the actual type.
@@ -1901,8 +1873,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // Second, if there was exactly one lifetime (either a substitution or a
         // reference) in the arguments, then any anonymous regions in the output
         // have that lifetime.
-        let implied_output_region = match explicit_self_category {
-            ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region),
+        let implied_output_region = match explicit_self {
+            Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
             _ => {
                 // `pat_to_string` is expensive and
                 // `find_implied_output_region` only needs its result when
@@ -1928,7 +1900,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys);
         debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty);
 
-        (self.tcx().mk_bare_fn(ty::BareFnTy {
+        self.tcx().mk_bare_fn(ty::BareFnTy {
             unsafety: unsafety,
             abi: abi,
             sig: ty::Binder(ty::FnSig {
@@ -1936,95 +1908,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 output: output_ty,
                 variadic: decl.variadic
             }),
-        }), explicit_self_category)
+        })
     }
 
     fn determine_self_type<'a>(&self,
                                rscope: &RegionScope,
                                untransformed_self_ty: Ty<'tcx>,
                                explicit_self: &hir::ExplicitSelf)
-                               -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>)
+                               -> Ty<'tcx>
     {
-        return match explicit_self.node {
-            SelfKind::Value(..) => {
-                (untransformed_self_ty, ty::ExplicitSelfCategory::ByValue)
-            }
+        match explicit_self.node {
+            SelfKind::Value(..) => untransformed_self_ty,
             SelfKind::Region(ref lifetime, mutability) => {
                 let region =
                     self.opt_ast_region_to_region(
                                              rscope,
                                              explicit_self.span,
                                              lifetime);
-                (self.tcx().mk_ref(region,
+                self.tcx().mk_ref(region,
                     ty::TypeAndMut {
                         ty: untransformed_self_ty,
                         mutbl: mutability
-                    }),
-                 ty::ExplicitSelfCategory::ByReference(region, mutability))
-            }
-            SelfKind::Explicit(ref ast_type, _) => {
-                let explicit_type = self.ast_ty_to_ty(rscope, &ast_type);
-
-                // We wish to (for now) categorize an explicit self
-                // declaration like `self: SomeType` into either `self`,
-                // `&self`, `&mut self`, or `Box<self>`. We do this here
-                // by some simple pattern matching. A more precise check
-                // is done later in `check_method_self_type()`.
-                //
-                // Examples:
-                //
-                // ```
-                // impl Foo for &T {
-                //     // Legal declarations:
-                //     fn method1(self: &&T); // ExplicitSelfCategory::ByReference
-                //     fn method2(self: &T); // ExplicitSelfCategory::ByValue
-                //     fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox
-                //
-                //     // Invalid cases will be caught later by `check_method_self_type`:
-                //     fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference
-                // }
-                // ```
-                //
-                // To do the check we just count the number of "modifiers"
-                // on each type and compare them. If they are the same or
-                // the impl has more, we call it "by value". Otherwise, we
-                // look at the outermost modifier on the method decl and
-                // call it by-ref, by-box as appropriate. For method1, for
-                // example, the impl type has one modifier, but the method
-                // type has two, so we end up with
-                // ExplicitSelfCategory::ByReference.
-
-                let impl_modifiers = count_modifiers(untransformed_self_ty);
-                let method_modifiers = count_modifiers(explicit_type);
-
-                debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \
-                       explicit_type={:?} \
-                       modifiers=({},{})",
-                       untransformed_self_ty,
-                       explicit_type,
-                       impl_modifiers,
-                       method_modifiers);
-
-                let category = if impl_modifiers >= method_modifiers {
-                    ty::ExplicitSelfCategory::ByValue
-                } else {
-                    match explicit_type.sty {
-                        ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl),
-                        ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox,
-                        _ => ty::ExplicitSelfCategory::ByValue,
-                    }
-                };
-
-                (explicit_type, category)
-            }
-        };
-
-        fn count_modifiers(ty: Ty) -> usize {
-            match ty.sty {
-                ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
-                ty::TyBox(t) => count_modifiers(t) + 1,
-                _ => 0,
+                    })
             }
+            SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
         }
     }
 
@@ -2334,3 +2241,64 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
         vec
     }
 }
+
+pub enum ExplicitSelf<'tcx> {
+    ByValue,
+    ByReference(&'tcx ty::Region, hir::Mutability),
+    ByBox
+}
+
+impl<'tcx> ExplicitSelf<'tcx> {
+    /// We wish to (for now) categorize an explicit self
+    /// declaration like `self: SomeType` into either `self`,
+    /// `&self`, `&mut self`, or `Box<self>`. We do this here
+    /// by some simple pattern matching. A more precise check
+    /// is done later in `check_method_self_type()`.
+    ///
+    /// Examples:
+    ///
+    /// ```
+    /// impl Foo for &T {
+    ///     // Legal declarations:
+    ///     fn method1(self: &&T); // ExplicitSelf::ByReference
+    ///     fn method2(self: &T); // ExplicitSelf::ByValue
+    ///     fn method3(self: Box<&T>); // ExplicitSelf::ByBox
+    ///
+    ///     // Invalid cases will be caught later by `check_method_self_type`:
+    ///     fn method_err1(self: &mut T); // ExplicitSelf::ByReference
+    /// }
+    /// ```
+    ///
+    /// To do the check we just count the number of "modifiers"
+    /// on each type and compare them. If they are the same or
+    /// the impl has more, we call it "by value". Otherwise, we
+    /// look at the outermost modifier on the method decl and
+    /// call it by-ref, by-box as appropriate. For method1, for
+    /// example, the impl type has one modifier, but the method
+    /// type has two, so we end up with
+    /// ExplicitSelf::ByReference.
+    pub fn determine(untransformed_self_ty: Ty<'tcx>,
+                     self_arg_ty: Ty<'tcx>)
+                     -> ExplicitSelf<'tcx> {
+        fn count_modifiers(ty: Ty) -> usize {
+            match ty.sty {
+                ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
+                ty::TyBox(t) => count_modifiers(t) + 1,
+                _ => 0,
+            }
+        }
+
+        let impl_modifiers = count_modifiers(untransformed_self_ty);
+        let method_modifiers = count_modifiers(self_arg_ty);
+
+        if impl_modifiers >= method_modifiers {
+            ExplicitSelf::ByValue
+        } else {
+            match self_arg_ty.sty {
+                ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl),
+                ty::TyBox(_) => ExplicitSelf::ByBox,
+                _ => ExplicitSelf::ByValue,
+            }
+        }
+    }
+}
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 15b29573ac4..ca630624cdb 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
-use check::{FnCtxt, Expectation};
+use check::{FnCtxt, Expectation, Diverges};
 use util::nodemap::FxHashMap;
 
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
         true
     }
-}
 
-impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn check_match(&self,
                        expr: &'gcx hir::Expr,
                        discrim: &'gcx hir::Expr,
@@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             discrim_ty = self.next_ty_var();
             self.check_expr_has_type(discrim, discrim_ty);
         };
+        let discrim_diverges = self.diverges.get();
+        self.diverges.set(Diverges::Maybe);
 
         // Typecheck the patterns first, so that we get types for all the
         // bindings.
-        for arm in arms {
+        let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| {
+            let mut all_pats_diverge = Diverges::WarnedAlways;
             for p in &arm.pats {
+                self.diverges.set(Diverges::Maybe);
                 self.check_pat(&p, discrim_ty);
+                all_pats_diverge &= self.diverges.get();
             }
-        }
+            all_pats_diverge
+        }).collect();
 
         // Now typecheck the blocks.
         //
@@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // type in that case)
         let expected = expected.adjust_for_branches(self);
         let mut result_ty = self.next_diverging_ty_var();
+        let mut all_arms_diverge = Diverges::WarnedAlways;
         let coerce_first = match expected {
             // We don't coerce to `()` so that if the match expression is a
             // statement it's branches can have any consistent type. That allows
@@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ => result_ty
         };
 
-        for (i, arm) in arms.iter().enumerate() {
+        for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
             if let Some(ref e) = arm.guard {
+                self.diverges.set(pats_diverge);
                 self.check_expr_has_type(e, tcx.types.bool);
             }
+
+            self.diverges.set(pats_diverge);
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
+            all_arms_diverge &= self.diverges.get();
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
         }
 
+        // We won't diverge unless the discriminant or all arms diverge.
+        self.diverges.set(discrim_diverges | all_arms_diverge);
+
         result_ty
     }
-}
 
-impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_pat_struct(&self,
                         pat: &'gcx hir::Pat,
                         path: &hir::Path,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index d478f1092bd..af834f3f84d 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &hir::Expr,
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
-                              body: &'gcx hir::Block,
+                              body: &'gcx hir::Expr,
                               expected: Expectation<'tcx>)
                               -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
@@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      expr: &hir::Expr,
                      opt_kind: Option<ty::ClosureKind>,
                      decl: &'gcx hir::FnDecl,
-                     body: &'gcx hir::Block,
+                     body: &'gcx hir::Expr,
                      expected_sig: Option<ty::FnSig<'tcx>>)
                      -> Ty<'tcx> {
         let expr_def_id = self.tcx.map.local_def_id(expr.id);
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2cb719675ac..ffde940b3f4 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::hir;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::middle::free_region::FreeRegionMap;
 use rustc::ty;
@@ -23,6 +24,7 @@ use syntax_pos::Span;
 use CrateCtxt;
 use super::assoc;
 use super::{Inherited, FnCtxt};
+use astconv::ExplicitSelf;
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -36,11 +38,11 @@ use super::{Inherited, FnCtxt};
 /// - impl_trait_ref: the TraitRef corresponding to the trait implementation
 
 pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     impl_m: &ty::Method<'tcx>,
+                                     impl_m: &ty::AssociatedItem,
                                      impl_m_span: Span,
                                      impl_m_body_id: ast::NodeId,
-                                     trait_m: &ty::Method<'tcx>,
-                                     impl_trait_ref: &ty::TraitRef<'tcx>,
+                                     trait_m: &ty::AssociatedItem,
+                                     impl_trait_ref: ty::TraitRef<'tcx>,
                                      trait_item_span: Option<Span>,
                                      old_broken_mode: bool) {
     debug!("compare_impl_method(impl_trait_ref={:?})",
@@ -49,7 +51,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     if let Err(ErrorReported) = compare_self_type(ccx,
                                                   impl_m,
                                                   impl_m_span,
-                                                  trait_m) {
+                                                  trait_m,
+                                                  impl_trait_ref) {
         return;
     }
 
@@ -81,16 +84,16 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 }
 
 fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                          impl_m: &ty::Method<'tcx>,
+                                          impl_m: &ty::AssociatedItem,
                                           impl_m_span: Span,
                                           impl_m_body_id: ast::NodeId,
-                                          trait_m: &ty::Method<'tcx>,
-                                          impl_trait_ref: &ty::TraitRef<'tcx>,
+                                          trait_m: &ty::AssociatedItem,
+                                          impl_trait_ref: ty::TraitRef<'tcx>,
                                           old_broken_mode: bool)
                                           -> Result<(), ErrorReported> {
     let tcx = ccx.tcx;
 
-    let trait_to_impl_substs = &impl_trait_ref.substs;
+    let trait_to_impl_substs = impl_trait_ref.substs;
 
     // This code is best explained by example. Consider a trait:
     //
@@ -165,18 +168,23 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     // Create mapping from trait to skolemized.
     let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
-                                                               impl_m.container_id(),
+                                                               impl_m.container.id(),
                                                                trait_to_impl_substs.subst(tcx,
                                                                           impl_to_skol_substs));
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
            trait_to_skol_substs);
 
+    let impl_m_generics = tcx.lookup_generics(impl_m.def_id);
+    let trait_m_generics = tcx.lookup_generics(trait_m.def_id);
+    let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id);
+    let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id);
+
     // Check region bounds.
     check_region_bounds_on_impl_method(ccx,
                                        impl_m_span,
                                        impl_m,
-                                       &trait_m.generics,
-                                       &impl_m.generics,
+                                       &trait_m_generics,
+                                       &impl_m_generics,
                                        trait_to_skol_substs,
                                        impl_to_skol_substs)?;
 
@@ -185,7 +193,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // environment. We can't just use `impl_env.caller_bounds`,
     // however, because we want to replace all late-bound regions with
     // region variables.
-    let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
+    let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap());
     let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
 
     debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
@@ -198,7 +206,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // We then register the obligations from the impl_m and check to see
     // if all constraints hold.
     hybrid_preds.predicates
-                .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+                .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
 
     // Construct trait parameter environment and then shift it into the skolemized viewpoint.
     // The key step here is to update the caller_bounds's predicates to be
@@ -219,7 +227,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         let mut selcx = traits::SelectionContext::new(&infcx);
 
-        let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs);
+        let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs);
         let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
                                                        infer::HigherRankedType,
                                                        &ty::Binder(impl_m_own_bounds.predicates));
@@ -260,10 +268,19 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let tcx = infcx.tcx;
         let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
 
+        let m_fty = |method: &ty::AssociatedItem| {
+            match tcx.lookup_item_type(method.def_id).ty.sty {
+                ty::TyFnDef(_, _, f) => f,
+                _ => bug!()
+            }
+        };
+        let impl_m_fty = m_fty(impl_m);
+        let trait_m_fty = m_fty(trait_m);
+
         let (impl_sig, _) =
             infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
                                                             infer::HigherRankedType,
-                                                            &impl_m.fty.sig);
+                                                            &impl_m_fty.sig);
         let impl_sig =
             impl_sig.subst(tcx, impl_to_skol_substs);
         let impl_sig =
@@ -273,15 +290,15 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_body_id,
                                                  &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: impl_m.fty.unsafety,
-            abi: impl_m.fty.abi,
+            unsafety: impl_m_fty.unsafety,
+            abi: impl_m_fty.abi,
             sig: ty::Binder(impl_sig.clone()),
         }));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
         let trait_sig = tcx.liberate_late_bound_regions(
             infcx.parameter_environment.free_id_outlive,
-            &trait_m.fty.sig);
+            &trait_m_fty.sig);
         let trait_sig =
             trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
@@ -291,8 +308,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_body_id,
                                                  &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: trait_m.fty.unsafety,
-            abi: trait_m.fty.abi,
+            unsafety: trait_m_fty.unsafety,
+            abi: trait_m_fty.abi,
             sig: ty::Binder(trait_sig.clone()),
         }));
 
@@ -367,7 +384,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                 span: Span,
-                                                impl_m: &ty::Method<'tcx>,
+                                                impl_m: &ty::AssociatedItem,
                                                 trait_generics: &ty::Generics<'tcx>,
                                                 impl_generics: &ty::Generics<'tcx>,
                                                 trait_to_skol_substs: &Substs<'tcx>,
@@ -413,9 +430,9 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
                                                      terr: &TypeError,
                                                      origin: TypeOrigin,
-                                                     impl_m: &ty::Method,
+                                                     impl_m: &ty::AssociatedItem,
                                                      impl_sig: ty::FnSig<'tcx>,
-                                                     trait_m: &ty::Method,
+                                                     trait_m: &ty::AssociatedItem,
                                                      trait_sig: ty::FnSig<'tcx>)
                                                      -> (Span, Option<Span>) {
     let tcx = infcx.tcx;
@@ -505,9 +522,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
 }
 
 fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                               impl_m: &ty::Method<'tcx>,
+                               impl_m: &ty::AssociatedItem,
                                impl_m_span: Span,
-                               trait_m: &ty::Method<'tcx>)
+                               trait_m: &ty::AssociatedItem,
+                               impl_trait_ref: ty::TraitRef<'tcx>)
                                -> Result<(), ErrorReported>
 {
     let tcx = ccx.tcx;
@@ -518,58 +536,75 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // that the error messages you get out of this code are a bit more
     // inscrutable, particularly for cases where one method has no
     // self.
-    match (&trait_m.explicit_self, &impl_m.explicit_self) {
-        (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
-        (&ty::ExplicitSelfCategory::Static, _) => {
+
+    let self_string = |method: &ty::AssociatedItem| {
+        let untransformed_self_ty = match method.container {
+            ty::ImplContainer(_) => impl_trait_ref.self_ty(),
+            ty::TraitContainer(_) => tcx.mk_self_type()
+        };
+        let method_ty = tcx.lookup_item_type(method.def_id).ty;
+        let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder();
+        match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) {
+            ExplicitSelf::ByValue => "self".to_string(),
+            ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
+            ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(),
+            _ => format!("self: {}", self_arg_ty)
+        }
+    };
+
+    match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) {
+        (false, false) | (true, true) => {}
+
+        (false, true) => {
+            let self_descr = self_string(impl_m);
             let mut err = struct_span_err!(tcx.sess,
                                            impl_m_span,
                                            E0185,
                                            "method `{}` has a `{}` declaration in the impl, but \
                                             not in the trait",
                                            trait_m.name,
-                                           impl_m.explicit_self);
-            err.span_label(impl_m_span,
-                           &format!("`{}` used in impl", impl_m.explicit_self));
+                                           self_descr);
+            err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr));
             if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span,
-                               &format!("trait declared without `{}`", impl_m.explicit_self));
+                err.span_label(span, &format!("trait declared without `{}`", self_descr));
             }
             err.emit();
             return Err(ErrorReported);
         }
-        (_, &ty::ExplicitSelfCategory::Static) => {
+
+        (true, false) => {
+            let self_descr = self_string(trait_m);
             let mut err = struct_span_err!(tcx.sess,
                                            impl_m_span,
                                            E0186,
                                            "method `{}` has a `{}` declaration in the trait, but \
                                             not in the impl",
                                            trait_m.name,
-                                           trait_m.explicit_self);
+                                           self_descr);
             err.span_label(impl_m_span,
-                           &format!("expected `{}` in impl", trait_m.explicit_self));
+                           &format!("expected `{}` in impl", self_descr));
             if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
+                err.span_label(span, &format!("`{}` used in trait", self_descr));
             }
             err.emit();
             return Err(ErrorReported);
         }
-        _ => {
-            // Let the type checker catch other errors below
-        }
     }
 
     Ok(())
 }
 
 fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                        impl_m: &ty::Method<'tcx>,
+                                        impl_m: &ty::AssociatedItem,
                                         impl_m_span: Span,
-                                        trait_m: &ty::Method<'tcx>,
+                                        trait_m: &ty::AssociatedItem,
                                         trait_item_span: Option<Span>)
                                         -> Result<(), ErrorReported> {
     let tcx = ccx.tcx;
-    let num_impl_m_type_params = impl_m.generics.types.len();
-    let num_trait_m_type_params = trait_m.generics.types.len();
+    let impl_m_generics = tcx.lookup_generics(impl_m.def_id);
+    let trait_m_generics = tcx.lookup_generics(trait_m.def_id);
+    let num_impl_m_type_params = impl_m_generics.types.len();
+    let num_trait_m_type_params = trait_m_generics.types.len();
     if num_impl_m_type_params != num_trait_m_type_params {
         let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
         let span = match tcx.map.expect_impl_item(impl_m_node_id).node {
@@ -630,15 +665,23 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 }
 
 fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                impl_m: &ty::Method<'tcx>,
+                                                impl_m: &ty::AssociatedItem,
                                                 impl_m_span: Span,
-                                                trait_m: &ty::Method<'tcx>,
+                                                trait_m: &ty::AssociatedItem,
                                                 trait_item_span: Option<Span>)
                                                 -> Result<(), ErrorReported> {
     let tcx = ccx.tcx;
-    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
-        let trait_number_args = trait_m.fty.sig.0.inputs.len();
-        let impl_number_args = impl_m.fty.sig.0.inputs.len();
+    let m_fty = |method: &ty::AssociatedItem| {
+        match tcx.lookup_item_type(method.def_id).ty.sty {
+            ty::TyFnDef(_, _, f) => f,
+            _ => bug!()
+        }
+    };
+    let impl_m_fty = m_fty(impl_m);
+    let trait_m_fty = m_fty(trait_m);
+    if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() {
+        let trait_number_args = trait_m_fty.sig.0.inputs.len();
+        let impl_number_args = impl_m_fty.sig.0.inputs.len();
         let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
         let trait_span = if let Some(trait_id) = trait_m_node_id {
             match tcx.map.expect_trait_item(trait_id).node {
@@ -708,10 +751,10 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 }
 
 pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                    impl_c: &ty::AssociatedConst<'tcx>,
+                                    impl_c: &ty::AssociatedItem,
                                     impl_c_span: Span,
-                                    trait_c: &ty::AssociatedConst<'tcx>,
-                                    impl_trait_ref: &ty::TraitRef<'tcx>) {
+                                    trait_c: &ty::AssociatedItem,
+                                    impl_trait_ref: ty::TraitRef<'tcx>) {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     let tcx = ccx.tcx;
@@ -723,7 +766,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // because we shouldn't really have to deal with lifetimes or
         // predicates. In fact some of this should probably be put into
         // shared functions because of DRY violations...
-        let trait_to_impl_substs = &impl_trait_ref.substs;
+        let trait_to_impl_substs = impl_trait_ref.substs;
 
         // Create a parameter environment that represents the implementation's
         // method.
@@ -742,8 +785,8 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                trait_to_skol_substs);
 
         // Compute skolemized form of impl and trait const tys.
-        let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
-        let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs);
+        let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs);
+        let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs);
         let mut origin = TypeOrigin::Misc(impl_c_span);
 
         let err = infcx.commit_if_ok(|_| {
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index d28eb85ebb4..a06b3e70881 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -553,9 +553,9 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             // attributes attached to the impl's generics.
             let dtor_method = adt_def.destructor()
                 .expect("dtorck type without destructor impossible");
-            let method = tcx.impl_or_trait_item(dtor_method);
-            let impl_id: DefId = method.container().id();
-            let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs);
+            let method = tcx.associated_item(dtor_method);
+            let impl_def_id = method.container.id();
+            let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
             return DropckKind::RevisedSelf(revised_ty);
         }
         ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index f88bb355d12..3894a7a2097 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -37,16 +37,6 @@ impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> {
     }
 }
 
-struct InstantiatedMethodSig<'tcx> {
-    /// Function signature of the method being invoked. The 0th
-    /// argument is the receiver.
-    method_sig: ty::FnSig<'tcx>,
-
-    /// Generic bounds on the method's parameters which must be added
-    /// as pending obligations.
-    method_predicates: ty::InstantiatedPredicates<'tcx>,
-}
-
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn confirm_method(&self,
                           span: Span,
@@ -98,31 +88,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         debug!("all_substs={:?}", all_substs);
 
         // Create the final signature for the method, replacing late-bound regions.
-        let InstantiatedMethodSig { method_sig, method_predicates } =
-            self.instantiate_method_sig(&pick, all_substs);
-        let method_self_ty = method_sig.inputs[0];
+        let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
 
         // Unify the (adjusted) self type with what the method expects.
-        self.unify_receivers(self_ty, method_self_ty);
-
-        // Create the method type
-        let def_id = pick.item.def_id();
-        let method_ty = pick.item.as_opt_method().unwrap();
-        let fty = self.tcx.mk_fn_def(def_id,
-                                     all_substs,
-                                     self.tcx.mk_bare_fn(ty::BareFnTy {
-                                         sig: ty::Binder(method_sig),
-                                         unsafety: method_ty.fty.unsafety,
-                                         abi: method_ty.fty.abi.clone(),
-                                     }));
+        self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder());
 
         // Add any trait/regions obligations specified on the method's type parameters.
-        self.add_obligations(fty, all_substs, &method_predicates);
+        self.add_obligations(method_ty, all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
         let callee = ty::MethodCallee {
-            def_id: def_id,
-            ty: fty,
+            def_id: pick.item.def_id,
+            ty: method_ty,
             substs: all_substs,
         };
 
@@ -193,7 +170,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                              -> &'tcx Substs<'tcx> {
         match pick.kind {
             probe::InherentImplPick => {
-                let impl_def_id = pick.item.container().id();
+                let impl_def_id = pick.item.container.id();
                 assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(),
                         "impl {:?} is not an inherent impl",
                         impl_def_id);
@@ -201,7 +178,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             }
 
             probe::ObjectPick => {
-                let trait_def_id = pick.item.container().id();
+                let trait_def_id = pick.item.container.id();
                 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
                     // The object data has no entry for the Self
                     // Type. For the purposes of this method call, we
@@ -244,7 +221,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             }
 
             probe::TraitPick => {
-                let trait_def_id = pick.item.container().id();
+                let trait_def_id = pick.item.container.id();
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
                 // consisting entirely of type variables. Later on in
@@ -299,8 +276,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // If they were not explicitly supplied, just construct fresh
         // variables.
         let num_supplied_types = supplied_method_types.len();
-        let method = pick.item.as_opt_method().unwrap();
-        let num_method_types = method.generics.types.len();
+        let method_generics = self.tcx.lookup_generics(pick.item.def_id);
+        let num_method_types = method_generics.types.len();
 
         if num_supplied_types > 0 && num_supplied_types != num_method_types {
             if num_method_types == 0 {
@@ -332,18 +309,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // parameters from the type and those from the method.
         //
         // FIXME -- permit users to manually specify lifetimes
-        let supplied_start = substs.params().len() + method.generics.regions.len();
-        Substs::for_item(self.tcx,
-                         method.def_id,
-                         |def, _| {
+        let supplied_start = substs.params().len() + method_generics.regions.len();
+        Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
             let i = def.index as usize;
             if i < substs.params().len() {
                 substs.region_at(i)
             } else {
                 self.region_var_for_def(self.span, def)
             }
-        },
-                         |def, cur_substs| {
+        }, |def, cur_substs| {
             let i = def.index as usize;
             if i < substs.params().len() {
                 substs.type_at(i)
@@ -376,7 +350,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     fn instantiate_method_sig(&mut self,
                               pick: &probe::Pick<'tcx>,
                               all_substs: &'tcx Substs<'tcx>)
-                              -> InstantiatedMethodSig<'tcx> {
+                              -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) {
         debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
                pick,
                all_substs);
@@ -384,36 +358,40 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // Instantiate the bounds on the method with the
         // type/early-bound-regions substitutions performed. There can
         // be no late-bound regions appearing here.
-        let method_predicates = pick.item
-            .as_opt_method()
-            .unwrap()
-            .predicates
-            .instantiate(self.tcx, all_substs);
-        let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates);
+        let def_id = pick.item.def_id;
+        let method_predicates = self.tcx.lookup_predicates(def_id)
+                                    .instantiate(self.tcx, all_substs);
+        let method_predicates = self.normalize_associated_types_in(self.span,
+                                                                   &method_predicates);
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
+        let fty = match self.tcx.lookup_item_type(def_id).ty.sty {
+            ty::TyFnDef(_, _, f) => f,
+            _ => bug!()
+        };
+
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
         //
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item
-            .as_opt_method()
-            .unwrap()
-            .fty
-            .sig);
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
         let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}", method_sig);
 
-        InstantiatedMethodSig {
-            method_sig: method_sig,
-            method_predicates: method_predicates,
-        }
+        let method_ty = self.tcx.mk_fn_def(def_id, all_substs,
+                                           self.tcx.mk_bare_fn(ty::BareFnTy {
+            sig: ty::Binder(method_sig),
+            unsafety: fty.unsafety,
+            abi: fty.abi,
+        }));
+
+        (method_ty, method_predicates)
     }
 
     fn add_obligations(&mut self,
@@ -587,7 +565,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
-        match pick.item.container() {
+        match pick.item.container {
             ty::TraitContainer(trait_def_id) => {
                 callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id)
             }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 2df562f9ade..579a54fb531 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -228,14 +228,13 @@ 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.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);
+        let method_item = self.associated_item(trait_def_id, m_name).unwrap();
+        let def_id = method_item.def_id;
+        let generics = tcx.lookup_generics(def_id);
+        assert_eq!(generics.types.len(), 0);
+        assert_eq!(generics.regions.len(), 0);
 
-        debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
-               method_item,
-               method_ty);
+        debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
 
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
@@ -243,22 +242,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let fn_sig =
-            self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig)
-                .0;
+        let original_method_ty = tcx.lookup_item_type(def_id).ty;
+        let fty = match original_method_ty.sty {
+            ty::TyFnDef(_, _, f) => f,
+            _ => bug!()
+        };
+        let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
+                                                                    infer::FnCall,
+                                                                    &fty.sig).0;
         let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
         let transformed_self_ty = fn_sig.inputs[0];
-        let def_id = method_item.def_id();
-        let fty = tcx.mk_fn_def(def_id,
-                                trait_ref.substs,
-                                tcx.mk_bare_fn(ty::BareFnTy {
-                                    sig: ty::Binder(fn_sig),
-                                    unsafety: method_ty.fty.unsafety,
-                                    abi: method_ty.fty.abi.clone(),
-                                }));
-
-        debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
-               fty,
+        let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
+                                      tcx.mk_bare_fn(ty::BareFnTy {
+            sig: ty::Binder(fn_sig),
+            unsafety: fty.unsafety,
+            abi: fty.abi
+        }));
+
+        debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
+               method_ty,
                obligation);
 
         // Register obligations for the parameters.  This will include the
@@ -269,13 +271,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         //
         // Note that as the method comes from a trait, it should not have
         // any late-bound regions appearing in its bounds.
-        let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
+        let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs);
         assert!(!method_bounds.has_escaping_regions());
         self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id),
                                             &method_bounds);
 
         // Also register an obligation for the method type being well-formed.
-        self.register_wf_obligation(fty, span, traits::MiscObligation);
+        self.register_wf_obligation(method_ty, span, traits::MiscObligation);
 
         // FIXME(#18653) -- Try to resolve obligations, giving us more
         // typing information, which can sometimes be needed to avoid
@@ -283,61 +285,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.select_obligations_where_possible();
 
         // Insert any adjustments needed (always an autoref of some mutability).
-        match self_expr {
-            None => {}
-
-            Some(self_expr) => {
-                debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
-                       (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
-                       self_expr.id,
-                       autoderefs,
-                       unsize,
-                       method_ty.explicit_self);
-
-                let autoref = match method_ty.explicit_self {
-                    ty::ExplicitSelfCategory::ByValue => {
-                        // Trait method is fn(self), no transformation needed.
-                        assert!(!unsize);
-                        None
-                    }
-
-                    ty::ExplicitSelfCategory::ByReference(..) => {
-                        // Trait method is fn(&self) or fn(&mut self), need an
-                        // autoref. Pull the region etc out of the type of first argument.
-                        match transformed_self_ty.sty {
-                            ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
-                                Some(AutoBorrow::Ref(region, mutbl))
-                            }
-
-                            _ => {
-                                span_bug!(span,
-                                          "trait method is &self but first arg is: {}",
-                                          transformed_self_ty);
-                            }
-                        }
-                    }
-
-                    _ => {
-                        span_bug!(span,
-                                  "unexpected explicit self type in operator method: {:?}",
-                                  method_ty.explicit_self);
-                    }
-                };
-
-                self.write_adjustment(self_expr.id, Adjustment {
-                    kind: Adjust::DerefRef {
-                        autoderefs: autoderefs,
-                        autoref: autoref,
-                        unsize: unsize
-                    },
-                    target: transformed_self_ty
-                });
-            }
+        if let Some(self_expr) = self_expr {
+            debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
+                    (self-id={}, autoderefs={}, unsize={}, fty={:?})",
+                    self_expr.id, autoderefs, unsize, original_method_ty);
+
+            let original_sig = original_method_ty.fn_sig();
+            let autoref = match (&original_sig.input(0).skip_binder().sty,
+                                 &transformed_self_ty.sty) {
+                (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => {
+                    // Trait method is fn(&self) or fn(&mut self), need an
+                    // autoref. Pull the region etc out of the type of first argument.
+                    Some(AutoBorrow::Ref(region, mutbl))
+                }
+                _ => {
+                    // Trait method is fn(self), no transformation needed.
+                    assert!(!unsize);
+                    None
+                }
+            };
+
+            self.write_adjustment(self_expr.id, Adjustment {
+                kind: Adjust::DerefRef {
+                    autoderefs: autoderefs,
+                    autoref: autoref,
+                    unsize: unsize
+                },
+                target: transformed_self_ty
+            });
         }
 
         let callee = ty::MethodCallee {
             def_id: def_id,
-            ty: fty,
+            ty: method_ty,
             substs: trait_ref.substs,
         };
 
@@ -361,7 +341,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let def = pick.item.def();
         if let probe::InherentImplPick = pick.kind {
-            if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
+            if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
                 let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
                 self.tcx.sess.span_err(span, &msg);
             }
@@ -371,14 +351,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '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>> {
-        self.tcx
-            .impl_or_trait_items(def_id)
-            .iter()
-            .map(|&did| self.tcx.impl_or_trait_item(did))
-            .find(|m| m.name() == item_name)
+    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name)
+                           -> Option<ty::AssociatedItem> {
+        self.tcx.associated_items(def_id).find(|item| item.name == item_name)
     }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 54b1b6c6807..7068b2dea72 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -72,7 +72,7 @@ struct CandidateStep<'tcx> {
 #[derive(Debug)]
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
-    item: ty::ImplOrTraitItem<'tcx>,
+    item: ty::AssociatedItem,
     kind: CandidateKind<'tcx>,
     import_id: Option<ast::NodeId>,
 }
@@ -95,7 +95,7 @@ enum CandidateKind<'tcx> {
 
 #[derive(Debug)]
 pub struct Pick<'tcx> {
-    pub item: ty::ImplOrTraitItem<'tcx>,
+    pub item: ty::AssociatedItem,
     pub kind: PickKind<'tcx>,
     pub import_id: Option<ast::NodeId>,
 
@@ -384,8 +384,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option<DefId>) {
         if let Some(impl_def_id) = lang_def_id {
-            self.tcx.populate_implementations_for_primitive_if_necessary(impl_def_id);
-
             self.assemble_inherent_impl_probe(impl_def_id);
         }
     }
@@ -409,7 +407,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
 
-        let item = match self.impl_or_trait_item(impl_def_id) {
+        let item = match self.associated_item(impl_def_id) {
             Some(m) => m,
             None => {
                 return;
@@ -421,7 +419,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             return self.record_static_candidate(ImplSource(impl_def_id));
         }
 
-        if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
+        if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
             self.private_candidate = Some(item.def());
             return;
         }
@@ -512,17 +510,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
             let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
 
-            if let Some(ref m) = item.as_opt_method() {
-                debug!("found match: trait_ref={:?} substs={:?} m={:?}",
-                       trait_ref,
-                       trait_ref.substs,
-                       m);
-                assert_eq!(m.generics.parent_types as usize,
-                           trait_ref.substs.types().count());
-                assert_eq!(m.generics.parent_regions as usize,
-                           trait_ref.substs.regions().count());
-            }
-
             // Because this trait derives from a where-clause, it
             // should not contain any inference variables or other
             // artifacts. This means it is safe to put into the
@@ -544,13 +531,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     fn elaborate_bounds<F>(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F)
         where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>,
                                ty::PolyTraitRef<'tcx>,
-                               ty::ImplOrTraitItem<'tcx>)
+                               ty::AssociatedItem)
     {
         debug!("elaborate_bounds(bounds={:?})", bounds);
 
         let tcx = self.tcx;
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) {
+            let item = match self.associated_item(bound_trait_ref.def_id()) {
                 Some(v) => v,
                 None => {
                     continue;
@@ -601,9 +588,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                trait_def_id);
 
         // Check whether `trait_def_id` defines a method with suitable name:
-        let trait_items = self.tcx.trait_items(trait_def_id);
-        let maybe_item = trait_items.iter()
-            .find(|item| item.name() == self.item_name);
+        let maybe_item = self.tcx.associated_items(trait_def_id)
+                             .find(|item| item.name == self.item_name);
         let item = match maybe_item {
             Some(i) => i,
             None => {
@@ -612,7 +598,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         };
 
         // Check whether `trait_def_id` defines a method with suitable name:
-        if !self.has_applicable_self(item) {
+        if !self.has_applicable_self(&item) {
             debug!("method has inapplicable self");
             self.record_static_candidate(TraitSource(trait_def_id));
             return Ok(());
@@ -631,7 +617,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_extension_candidates_for_trait_impls(&mut self,
                                                      trait_def_id: DefId,
-                                                     item: ty::ImplOrTraitItem<'tcx>) {
+                                                     item: ty::AssociatedItem) {
         let trait_def = self.tcx.lookup_trait_def(trait_def_id);
 
         // FIXME(arielb1): can we use for_each_relevant_impl here?
@@ -700,7 +686,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_closure_candidates(&mut self,
                                    trait_def_id: DefId,
-                                   item: ty::ImplOrTraitItem<'tcx>)
+                                   item: ty::AssociatedItem)
                                    -> Result<(), MethodError<'tcx>> {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
         let tcx = self.tcx;
@@ -765,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_projection_candidates(&mut self,
                                       trait_def_id: DefId,
-                                      item: ty::ImplOrTraitItem<'tcx>) {
+                                      item: ty::AssociatedItem) {
         debug!("assemble_projection_candidates(\
                trait_def_id={:?}, \
                item={:?})",
@@ -820,7 +806,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     fn assemble_where_clause_candidates(&mut self,
                                         trait_def_id: DefId,
-                                        item: ty::ImplOrTraitItem<'tcx>) {
+                                        item: ty::AssociatedItem) {
         debug!("assemble_where_clause_candidates(trait_def_id={:?})",
                trait_def_id);
 
@@ -865,7 +851,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         self.assemble_extension_candidates_for_all_traits()?;
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.item.container().id()],
+            Some(Ok(p)) => vec![p.item.container.id()],
             Some(Err(MethodError::Ambiguity(v))) => {
                 v.into_iter()
                     .map(|source| {
@@ -1065,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             // don't have enough information to fully evaluate).
             let (impl_def_id, substs, ref_obligations) = match probe.kind {
                 InherentImplCandidate(ref substs, ref ref_obligations) => {
-                    (probe.item.container().id(), substs, ref_obligations)
+                    (probe.item.container.id(), substs, ref_obligations)
                 }
 
                 ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => {
@@ -1128,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     /// use, so it's ok to just commit to "using the method from the trait Foo".
     fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option<Pick<'tcx>> {
         // Do all probes correspond to the same trait?
-        let container = probes[0].item.container();
+        let container = probes[0].item.container;
         match container {
             ty::TraitContainer(_) => {}
             ty::ImplContainer(_) => return None,
         }
-        if probes[1..].iter().any(|p| p.item.container() != container) {
+        if probes[1..].iter().any(|p| p.item.container != container) {
             return None;
         }
 
@@ -1150,19 +1136,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
     ///////////////////////////////////////////////////////////////////////////
     // MISCELLANY
-    fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
+    fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool {
         // "fast track" -- check for usage of sugar
-        match *item {
-            ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
-                match method.explicit_self {
-                    ty::ExplicitSelfCategory::Static => self.mode == Mode::Path,
-                    ty::ExplicitSelfCategory::ByValue |
-                    ty::ExplicitSelfCategory::ByReference(..) |
-                    ty::ExplicitSelfCategory::ByBox => true,
-                }
-            }
-            ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
-            _ => false,
+        match self.mode {
+            Mode::MethodCall => item.method_has_self_argument,
+            Mode::Path => true
         }
         // FIXME -- check for types that deref to `Self`,
         // like `Rc<Self>` and so on.
@@ -1177,24 +1155,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn xform_self_ty(&self,
-                     item: &ty::ImplOrTraitItem<'tcx>,
+                     item: &ty::AssociatedItem,
                      impl_ty: Ty<'tcx>,
                      substs: &Substs<'tcx>)
                      -> Ty<'tcx> {
-        match item.as_opt_method() {
-            Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs),
-            None => impl_ty,
+        if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall {
+            self.xform_method_self_ty(item.def_id, impl_ty, substs)
+        } else {
+            impl_ty
         }
     }
 
     fn xform_method_self_ty(&self,
-                            method: &Rc<ty::Method<'tcx>>,
+                            method: DefId,
                             impl_ty: Ty<'tcx>,
                             substs: &Substs<'tcx>)
                             -> Ty<'tcx> {
+        let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0);
         debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
                impl_ty,
-               method.fty.sig.0.inputs.get(0),
+               self_ty,
                substs);
 
         assert!(!substs.has_escaping_regions());
@@ -1204,26 +1184,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         // are given do not include type/lifetime parameters for the
         // method yet. So create fresh variables here for those too,
         // if there are any.
-        assert_eq!(substs.types().count(),
-                   method.generics.parent_types as usize);
-        assert_eq!(substs.regions().count(),
-                   method.generics.parent_regions as usize);
-
-        if self.mode == Mode::Path {
-            return impl_ty;
-        }
+        let generics = self.tcx.lookup_generics(method);
+        assert_eq!(substs.types().count(), generics.parent_types as usize);
+        assert_eq!(substs.regions().count(), generics.parent_regions as usize);
 
         // Erase any late-bound regions from the method and substitute
         // in the values from the substitution.
-        let xform_self_ty = method.fty.sig.input(0);
-        let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty);
+        let xform_self_ty = self.erase_late_bound_regions(&self_ty);
 
-        if method.generics.types.is_empty() && method.generics.regions.is_empty() {
+        if generics.types.is_empty() && generics.regions.is_empty() {
             xform_self_ty.subst(self.tcx, substs)
         } else {
-            let substs = Substs::for_item(self.tcx,
-                                          method.def_id,
-                                          |def, _| {
+            let substs = Substs::for_item(self.tcx, method, |def, _| {
                 let i = def.index as usize;
                 if i < substs.params().len() {
                     substs.region_at(i)
@@ -1232,8 +1204,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     // `impl_self_ty()` for an explanation.
                     self.tcx.mk_region(ty::ReErased)
                 }
-            },
-                                          |def, cur_substs| {
+            }, |def, cur_substs| {
                 let i = def.index as usize;
                 if i < substs.params().len() {
                     substs.type_at(i)
@@ -1283,8 +1254,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, '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_or_trait_item(def_id, self.item_name)
+    fn associated_item(&self, def_id: DefId) -> Option<ty::AssociatedItem> {
+        self.fcx.associated_item(def_id, self.item_name)
     }
 }
 
@@ -1317,11 +1288,11 @@ impl<'tcx> Candidate<'tcx> {
 
     fn to_source(&self) -> CandidateSource {
         match self.kind {
-            InherentImplCandidate(..) => ImplSource(self.item.container().id()),
+            InherentImplCandidate(..) => ImplSource(self.item.container.id()),
             ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
             ObjectCandidate |
             TraitCandidate |
-            WhereClauseCandidate(_) => TraitSource(self.item.container().id()),
+            WhereClauseCandidate(_) => TraitSource(self.item.container.id()),
         }
     }
 }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 98d3957db70..0cb8cf2a588 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -89,20 +89,17 @@ 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_or_trait_item(impl_did, item_name)
+                        let item = self.associated_item(impl_did, item_name)
                             .or_else(|| {
-                                self.impl_or_trait_item(self.tcx
-                                                            .impl_trait_ref(impl_did)
-                                                            .unwrap()
-                                                            .def_id,
-
-                                                        item_name)
-                            })
-                            .unwrap();
-                        let note_span = self.tcx
-                            .map
-                            .span_if_local(item.def_id())
-                            .or_else(|| self.tcx.map.span_if_local(impl_did));
+                                self.associated_item(
+                                    self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
+
+                                    item_name
+                                )
+                            }).unwrap();
+                        let note_span = self.tcx.map.span_if_local(item.def_id).or_else(|| {
+                            self.tcx.map.span_if_local(impl_did)
+                        });
 
                         let impl_ty = self.impl_self_ty(span, impl_did).ty;
 
@@ -127,8 +124,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        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);
+                        let item = self.associated_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 `{}`",
@@ -334,8 +331,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // this isn't perfect (that is, there are cases when
                 // implementing a trait would be legal but is rejected
                 // here).
-                (type_is_local || info.def_id.is_local()) &&
-                self.impl_or_trait_item(info.def_id, item_name).is_some()
+                (type_is_local || info.def_id.is_local())
+                    && self.associated_item(info.def_id, item_name).is_some()
             })
             .collect::<Vec<_>>();
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f7e05f4777e..08242cff112 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -106,17 +106,18 @@ use util::common::{block_query, ErrorReported, indenter, loop_query};
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
 use std::cell::{Cell, Ref, RefCell};
+use std::cmp;
 use std::mem::replace;
-use std::ops::Deref;
+use std::ops::{self, Deref};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::codemap::{self, Spanned};
+use syntax::codemap::{self, original_sp, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::parse::token::{self, InternedString, keywords};
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{self, Span};
+use syntax_pos::{self, BytePos, Span};
 
 use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::{self, PatKind};
@@ -351,6 +352,59 @@ impl UnsafetyState {
     }
 }
 
+/// Whether a node ever exits normally or not.
+/// Tracked semi-automatically (through type variables
+/// marked as diverging), with some manual adjustments
+/// for control-flow primitives (approximating a CFG).
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+enum Diverges {
+    /// Potentially unknown, some cases converge,
+    /// others require a CFG to determine them.
+    Maybe,
+
+    /// Definitely known to diverge and therefore
+    /// not reach the next sibling or its parent.
+    Always,
+
+    /// Same as `Always` but with a reachability
+    /// warning already emitted
+    WarnedAlways
+}
+
+// Convenience impls for combinig `Diverges`.
+
+impl ops::BitAnd for Diverges {
+    type Output = Self;
+    fn bitand(self, other: Self) -> Self {
+        cmp::min(self, other)
+    }
+}
+
+impl ops::BitOr for Diverges {
+    type Output = Self;
+    fn bitor(self, other: Self) -> Self {
+        cmp::max(self, other)
+    }
+}
+
+impl ops::BitAndAssign for Diverges {
+    fn bitand_assign(&mut self, other: Self) {
+        *self = *self & other;
+    }
+}
+
+impl ops::BitOrAssign for Diverges {
+    fn bitor_assign(&mut self, other: Self) {
+        *self = *self | other;
+    }
+}
+
+impl Diverges {
+    fn always(self) -> bool {
+        self >= Diverges::Always
+    }
+}
+
 #[derive(Clone)]
 pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
@@ -371,6 +425,12 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     ps: RefCell<UnsafetyState>,
 
+    /// Whether the last checked node can ever exit.
+    diverges: Cell<Diverges>,
+
+    /// Whether any child nodes have any type errors.
+    has_errors: Cell<bool>,
+
     inh: &'a Inherited<'a, 'gcx, 'tcx>,
 }
 
@@ -534,7 +594,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
 
 fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            decl: &'tcx hir::FnDecl,
-                           body: &'tcx hir::Block,
+                           body: &'tcx hir::Expr,
                            fn_id: ast::NodeId,
                            span: Span) {
     let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
@@ -558,7 +618,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
 
         fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze_fn(body);
+        fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
         fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
@@ -654,7 +714,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
 
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
-                _: &'gcx hir::Block, _: Span, _: ast::NodeId) { }
+                _: &'gcx hir::Expr, _: Span, _: ast::NodeId) { }
 }
 
 /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@@ -669,7 +729,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                             fn_sig: &ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
-                            body: &'gcx hir::Block)
+                            body: &'gcx hir::Expr)
                             -> FnCtxt<'a, 'gcx, 'tcx>
 {
     let mut fn_sig = fn_sig.clone();
@@ -709,18 +769,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
             fcx.write_ty(input.id, arg_ty);
         }
 
-        visit.visit_block(body);
+        visit.visit_expr(body);
     }
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
 
-    // FIXME(aburka) do we need this special case? and should it be is_uninhabited?
-    let expected = if fcx.ret_ty.is_never() {
-        NoExpectation
-    } else {
-        ExpectHasType(fcx.ret_ty)
-    };
-    fcx.check_block_with_expected(body, expected);
+    fcx.check_expr_coercable_to_type(body, fcx.ret_ty);
 
     fcx
 }
@@ -760,7 +814,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
               check_impl_items_against_trait(ccx,
                                              it.span,
                                              impl_def_id,
-                                             &impl_trait_ref,
+                                             impl_trait_ref,
                                              impl_items);
               let trait_def_id = impl_trait_ref.def_id;
               check_on_unimplemented(ccx, trait_def_id, it);
@@ -942,21 +996,13 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let ancestors = trait_def.ancestors(impl_id);
 
-    let parent = match impl_item.node {
-        hir::ImplItemKind::Const(..) => {
-            ancestors.const_defs(tcx, impl_item.name).skip(1).next()
-                .map(|node_item| node_item.map(|parent| parent.defaultness))
-        }
-        hir::ImplItemKind::Method(..) => {
-            ancestors.fn_defs(tcx, impl_item.name).skip(1).next()
-                .map(|node_item| node_item.map(|parent| parent.defaultness))
-
-        }
-        hir::ImplItemKind::Type(_) => {
-            ancestors.type_defs(tcx, impl_item.name).skip(1).next()
-                .map(|node_item| node_item.map(|parent| parent.defaultness))
-        }
+    let kind = match impl_item.node {
+        hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const,
+        hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method,
+        hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type
     };
+    let parent = ancestors.defs(tcx, impl_item.name, kind).skip(1).next()
+        .map(|node_item| node_item.map(|parent| parent.defaultness));
 
     if let Some(parent) = parent {
         if parent.item.is_final() {
@@ -969,7 +1015,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                             impl_span: Span,
                                             impl_id: DefId,
-                                            impl_trait_ref: &ty::TraitRef<'tcx>,
+                                            impl_trait_ref: ty::TraitRef<'tcx>,
                                             impl_items: &[hir::ImplItem]) {
     // If the trait reference itself is erroneous (so the compilation is going
     // to fail), skip checking the items here -- the `impl_item` table in `tcx`
@@ -979,72 +1025,61 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // Locate trait definition and items
     let tcx = ccx.tcx;
     let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
-    let trait_items = tcx.trait_items(impl_trait_ref.def_id);
     let mut overridden_associated_type = None;
 
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
     for impl_item in impl_items {
-        let ty_impl_item = tcx.impl_or_trait_item(tcx.map.local_def_id(impl_item.id));
-        let ty_trait_item = trait_items.iter()
-            .find(|ac| ac.name() == ty_impl_item.name());
+        let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id));
+        let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id)
+            .find(|ac| ac.name == ty_impl_item.name);
 
         // Check that impl definition matches trait definition
         if let Some(ty_trait_item) = ty_trait_item {
             match impl_item.node {
                 hir::ImplItemKind::Const(..) => {
-                    let impl_const = match ty_impl_item {
-                        ty::ConstTraitItem(ref cti) => cti,
-                        _ => span_bug!(impl_item.span, "non-const impl-item for const")
-                    };
-
                     // Find associated const definition.
-                    if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item {
+                    if ty_trait_item.kind == ty::AssociatedKind::Const {
                         compare_const_impl(ccx,
-                                           &impl_const,
+                                           &ty_impl_item,
                                            impl_item.span,
-                                           trait_const,
-                                           &impl_trait_ref);
+                                           &ty_trait_item,
+                                           impl_trait_ref);
                     } else {
                          let mut err = struct_span_err!(tcx.sess, impl_item.span, E0323,
                                   "item `{}` is an associated const, \
                                   which doesn't match its trait `{:?}`",
-                                  impl_const.name,
+                                  ty_impl_item.name,
                                   impl_trait_ref);
                          err.span_label(impl_item.span, &format!("does not match trait"));
                          // We can only get the spans from local trait definition
                          // Same for E0324 and E0325
-                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
+                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) {
                             err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
                     }
                 }
                 hir::ImplItemKind::Method(_, ref body) => {
-                    let impl_method = match ty_impl_item {
-                        ty::MethodTraitItem(ref mti) => mti,
-                        _ => span_bug!(impl_item.span, "non-method impl-item for method")
-                    };
-
-                    let trait_span = tcx.map.span_if_local(ty_trait_item.def_id());
-                    if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item {
+                    let trait_span = tcx.map.span_if_local(ty_trait_item.def_id);
+                    if ty_trait_item.kind == ty::AssociatedKind::Method {
                         let err_count = tcx.sess.err_count();
                         compare_impl_method(ccx,
-                                            &impl_method,
+                                            &ty_impl_item,
                                             impl_item.span,
                                             body.id,
-                                            &trait_method,
-                                            &impl_trait_ref,
+                                            &ty_trait_item,
+                                            impl_trait_ref,
                                             trait_span,
                                             true); // start with old-broken-mode
                         if err_count == tcx.sess.err_count() {
                             // old broken mode did not report an error. Try with the new mode.
                             compare_impl_method(ccx,
-                                                &impl_method,
+                                                &ty_impl_item,
                                                 impl_item.span,
                                                 body.id,
-                                                &trait_method,
-                                                &impl_trait_ref,
+                                                &ty_trait_item,
+                                                impl_trait_ref,
                                                 trait_span,
                                                 false); // use the new mode
                         }
@@ -1052,33 +1087,28 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324,
                                   "item `{}` is an associated method, \
                                   which doesn't match its trait `{:?}`",
-                                  impl_method.name,
+                                  ty_impl_item.name,
                                   impl_trait_ref);
                          err.span_label(impl_item.span, &format!("does not match trait"));
-                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
+                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) {
                             err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
                     }
                 }
                 hir::ImplItemKind::Type(_) => {
-                    let impl_type = match ty_impl_item {
-                        ty::TypeTraitItem(ref tti) => tti,
-                        _ => span_bug!(impl_item.span, "non-type impl-item for type")
-                    };
-
-                    if let &ty::TypeTraitItem(ref at) = ty_trait_item {
-                        if let Some(_) = at.ty {
+                    if ty_trait_item.kind == ty::AssociatedKind::Type {
+                        if ty_trait_item.has_value {
                             overridden_associated_type = Some(impl_item);
                         }
                     } else {
                         let mut err = struct_span_err!(tcx.sess, impl_item.span, E0325,
                                   "item `{}` is an associated type, \
                                   which doesn't match its trait `{:?}`",
-                                  impl_type.name,
+                                  ty_impl_item.name,
                                   impl_trait_ref);
                          err.span_label(impl_item.span, &format!("does not match trait"));
-                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
+                         if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) {
                             err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
@@ -1091,70 +1121,55 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 
     // Check for missing items from trait
-    let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id);
     let mut missing_items = Vec::new();
     let mut invalidated_items = Vec::new();
     let associated_type_overridden = overridden_associated_type.is_some();
-    for trait_item in trait_items.iter() {
-        let is_implemented;
-        let is_provided;
-
-        match *trait_item {
-            ty::ConstTraitItem(ref associated_const) => {
-                is_provided = associated_const.has_value;
-                is_implemented = impl_items.iter().any(|ii| {
-                    match ii.node {
-                        hir::ImplItemKind::Const(..) => {
-                            ii.name == associated_const.name
-                        }
-                        _ => false,
-                    }
-                });
-            }
-            ty::MethodTraitItem(ref trait_method) => {
-                is_provided = provided_methods.iter().any(|m| m.name == trait_method.name);
-                is_implemented = trait_def.ancestors(impl_id)
-                    .fn_defs(tcx, trait_method.name)
-                    .next()
-                    .map(|node_item| !node_item.node.is_from_trait())
-                    .unwrap_or(false);
-            }
-            ty::TypeTraitItem(ref trait_assoc_ty) => {
-                is_provided = trait_assoc_ty.ty.is_some();
-                is_implemented = trait_def.ancestors(impl_id)
-                    .type_defs(tcx, trait_assoc_ty.name)
-                    .next()
-                    .map(|node_item| !node_item.node.is_from_trait())
-                    .unwrap_or(false);
-            }
-        }
+    for trait_item in tcx.associated_items(impl_trait_ref.def_id) {
+        let is_implemented = trait_def.ancestors(impl_id)
+            .defs(tcx, trait_item.name, trait_item.kind)
+            .next()
+            .map(|node_item| !node_item.node.is_from_trait())
+            .unwrap_or(false);
 
         if !is_implemented {
-            if !is_provided {
+            if !trait_item.has_value {
                 missing_items.push(trait_item);
             } else if associated_type_overridden {
-                invalidated_items.push(trait_item.name());
+                invalidated_items.push(trait_item.name);
             }
         }
     }
 
+    let signature = |item: &ty::AssociatedItem| {
+        match item.kind {
+            ty::AssociatedKind::Method => {
+                format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0)
+            }
+            ty::AssociatedKind::Type => format!("type {};", item.name.to_string()),
+            ty::AssociatedKind::Const => {
+                format!("const {}: {:?};", item.name.to_string(),
+                        tcx.lookup_item_type(item.def_id).ty)
+            }
+        }
+    };
+
     if !missing_items.is_empty() {
         let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
             "not all trait items implemented, missing: `{}`",
             missing_items.iter()
-                  .map(|trait_item| trait_item.name().to_string())
+                  .map(|trait_item| trait_item.name.to_string())
                   .collect::<Vec<_>>().join("`, `"));
         err.span_label(impl_span, &format!("missing `{}` in implementation",
                 missing_items.iter()
-                    .map(|trait_item| trait_item.name().to_string())
+                    .map(|trait_item| trait_item.name.to_string())
                     .collect::<Vec<_>>().join("`, `")));
         for trait_item in missing_items {
-            if let Some(span) = tcx.map.span_if_local(trait_item.def_id()) {
-                err.span_label(span, &format!("`{}` from trait", trait_item.name()));
+            if let Some(span) = tcx.map.span_if_local(trait_item.def_id) {
+                err.span_label(span, &format!("`{}` from trait", trait_item.name));
             } else {
                 err.note(&format!("`{}` from trait: `{}`",
-                                  trait_item.name(),
-                                  signature(trait_item)));
+                                  trait_item.name,
+                                  signature(&trait_item)));
             }
         }
         err.emit();
@@ -1172,14 +1187,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn signature<'a, 'tcx>(item: &ty::ImplOrTraitItem) -> String {
-    match *item {
-        ty::MethodTraitItem(ref item) => format!("{}", item.fty.sig.0),
-        ty::TypeTraitItem(ref item) => format!("type {};", item.name.to_string()),
-        ty::ConstTraitItem(ref item) => format!("const {}: {:?};", item.name.to_string(), item.ty),
-    }
-}
-
 /// Checks a constant with a given type.
 fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                                    expr: &'tcx hir::Expr,
@@ -1198,7 +1205,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         fcx.check_expr_coercable_to_type(expr, expected_type);
 
         fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze_const(expr);
+        fcx.closure_analyze(expr);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
         fcx.select_all_obligations_or_error();
@@ -1385,19 +1392,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         Ok(r)
     }
 
-    fn trait_defines_associated_type_named(&self,
-                                           trait_def_id: DefId,
-                                           assoc_name: ast::Name)
-                                           -> bool
-    {
-        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> {
         self.next_ty_var()
     }
@@ -1497,6 +1491,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ret_ty: rty,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
                                                      ast::CRATE_NODE_ID)),
+            diverges: Cell::new(Diverges::Maybe),
+            has_errors: Cell::new(false),
             inh: inh,
         }
     }
@@ -1513,6 +1509,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx.sess.err_count() - self.err_count_on_creation
     }
 
+    /// Produce warning on the given node, if the current point in the
+    /// function is unreachable, and there hasn't been another warning.
+    fn warn_if_unreachable(&self, id: ast::NodeId, span: Span, kind: &str) {
+        if self.diverges.get() == Diverges::Always {
+            self.diverges.set(Diverges::WarnedAlways);
+
+            self.tcx.sess.add_lint(lint::builtin::UNREACHABLE_CODE,
+                                   id, span,
+                                   format!("unreachable {}", kind));
+        }
+    }
+
     /// Resolves type variables in `ty` if possible. Unlike the infcx
     /// version (resolve_type_vars_if_possible), this version will
     /// also select obligations if it seems useful, in an effort
@@ -1583,6 +1591,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
+
+        if ty.references_error() {
+            self.has_errors.set(true);
+        }
+
+        // FIXME(canndrew): This is_never should probably be an is_uninhabited
+        if ty.is_never() || self.type_var_diverges(ty) {
+            self.diverges.set(self.diverges.get() | Diverges::Always);
+        }
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1643,12 +1660,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     /// As `instantiate_type_scheme`, but for the bounds found in a
     /// generic type scheme.
-    fn instantiate_bounds(&self,
-                          span: Span,
-                          substs: &Substs<'tcx>,
-                          bounds: &ty::GenericPredicates<'tcx>)
-                          -> ty::InstantiatedPredicates<'tcx>
-    {
+    fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>)
+                          -> ty::InstantiatedPredicates<'tcx> {
+        let bounds = self.tcx.lookup_predicates(def_id);
         let result = bounds.instantiate(self.tcx, substs);
         let result = self.normalize_associated_types_in(span, &result.predicates);
         debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}",
@@ -2518,21 +2532,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Check the arguments.
         // We do this in a pretty awful way: first we typecheck any arguments
-        // that are not anonymous functions, then we typecheck the anonymous
-        // functions. This is so that we have more information about the types
-        // of arguments when we typecheck the functions. This isn't really the
-        // right way to do this.
-        let xs = [false, true];
-        let mut any_diverges = false; // has any of the arguments diverged?
-        let mut warned = false; // have we already warned about unreachable code?
-        for check_blocks in &xs {
-            let check_blocks = *check_blocks;
-            debug!("check_blocks={}", check_blocks);
+        // that are not closures, then we typecheck the closures. This is so
+        // that we have more information about the types of arguments when we
+        // typecheck the functions. This isn't really the right way to do this.
+        for &check_closures in &[false, true] {
+            debug!("check_closures={}", check_closures);
 
             // More awful hacks: before we check argument types, try to do
             // an "opportunistic" vtable resolution of any trait bounds on
             // the call. This helps coercions.
-            if check_blocks {
+            if check_closures {
                 self.select_obligations_where_possible();
             }
 
@@ -2547,61 +2556,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 supplied_arg_count
             };
             for (i, arg) in args.iter().take(t).enumerate() {
-                if any_diverges && !warned {
-                    self.tcx
-                        .sess
-                        .add_lint(lint::builtin::UNREACHABLE_CODE,
-                                  arg.id,
-                                  arg.span,
-                                  "unreachable expression".to_string());
-                    warned = true;
+                // Warn only for the first loop (the "no closures" one).
+                // Closure arguments themselves can't be diverging, but
+                // a previous argument can, e.g. `foo(panic!(), || {})`.
+                if !check_closures {
+                    self.warn_if_unreachable(arg.id, arg.span, "expression");
                 }
-                let is_block = match arg.node {
+
+                let is_closure = match arg.node {
                     hir::ExprClosure(..) => true,
                     _ => false
                 };
 
-                if is_block == check_blocks {
-                    debug!("checking the argument");
-                    let formal_ty = formal_tys[i];
+                if is_closure != check_closures {
+                    continue;
+                }
 
-                    // The special-cased logic below has three functions:
-                    // 1. Provide as good of an expected type as possible.
-                    let expected = expected_arg_tys.get(i).map(|&ty| {
-                        Expectation::rvalue_hint(self, ty)
-                    });
+                debug!("checking the argument");
+                let formal_ty = formal_tys[i];
 
-                    let checked_ty = self.check_expr_with_expectation(&arg,
-                                            expected.unwrap_or(ExpectHasType(formal_ty)));
-                    // 2. Coerce to the most detailed type that could be coerced
-                    //    to, which is `expected_ty` if `rvalue_hint` returns an
-                    //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                    let coerce_ty = expected.and_then(|e| e.only_has_type(self));
-                    self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
-
-                    // 3. Relate the expected type and the formal one,
-                    //    if the expected type was used for the coercion.
-                    coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
-                }
+                // The special-cased logic below has three functions:
+                // 1. Provide as good of an expected type as possible.
+                let expected = expected_arg_tys.get(i).map(|&ty| {
+                    Expectation::rvalue_hint(self, ty)
+                });
 
-                if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
-                    // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                    any_diverges = any_diverges ||
-                                   self.type_var_diverges(arg_ty) ||
-                                   arg_ty.is_never();
-                }
+                let checked_ty = self.check_expr_with_expectation(&arg,
+                                        expected.unwrap_or(ExpectHasType(formal_ty)));
+                // 2. Coerce to the most detailed type that could be coerced
+                //    to, which is `expected_ty` if `rvalue_hint` returns an
+                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                let coerce_ty = expected.and_then(|e| e.only_has_type(self));
+                self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
+
+                // 3. Relate the expected type and the formal one,
+                //    if the expected type was used for the coercion.
+                coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty));
             }
-            if any_diverges && !warned {
-                let parent = self.tcx.map.get_parent_node(args[0].id);
-                self.tcx
-                    .sess
-                    .add_lint(lint::builtin::UNREACHABLE_CODE,
-                              parent,
-                              sp,
-                              "unreachable call".to_string());
-                warned = true;
-            }
-
         }
 
         // We also need to make sure we at least write the ty of the other
@@ -2852,18 +2843,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
         let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
+        let cond_diverges = self.diverges.get();
+        self.diverges.set(Diverges::Maybe);
 
         let expected = expected.adjust_for_branches(self);
         let then_ty = self.check_block_with_expected(then_blk, expected);
+        let then_diverges = self.diverges.get();
+        self.diverges.set(Diverges::Maybe);
 
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
             let else_ty = self.check_expr_with_expectation(else_expr, expected);
-            let origin = TypeOrigin::IfExpression(sp);
+            let else_diverges = self.diverges.get();
 
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
+            let origin = TypeOrigin::IfExpression(sp);
             let result = if let Some(ref then) = then_blk.expr {
                 let res = self.try_find_coercion_lub(origin, || Some(&**then),
                                                      then_ty, else_expr, else_ty);
@@ -2889,8 +2885,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         })
                 })
             };
+
+            // We won't diverge unless both branches do (or the condition does).
+            self.diverges.set(cond_diverges | then_diverges & else_diverges);
+
             (origin, then_ty, else_ty, result)
         } else {
+            // If the condition is false we can't diverge.
+            self.diverges.set(cond_diverges);
+
             let origin = TypeOrigin::IfExpressionWithNoElse(sp);
             (origin, unit, then_ty,
              self.eq_types(true, origin, unit, then_ty)
@@ -3279,8 +3282,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((variant, did, substs)) = variant {
             // Check bounds on type arguments used in the path.
-            let type_predicates = self.tcx.lookup_predicates(did);
-            let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
+            let bounds = self.instantiate_bounds(path.span, did, substs);
             let cause = traits::ObligationCause::new(path.span, self.body_id,
                                                      traits::ItemObligation(did));
             self.add_obligations_for_parameters(cause, &bounds);
@@ -3352,10 +3354,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                    lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
+
+        // Warn for expressions after diverging siblings.
+        self.warn_if_unreachable(expr.id, expr.span, "expression");
+
+        // Hide the outer diverging and has_errors flags.
+        let old_diverges = self.diverges.get();
+        let old_has_errors = self.has_errors.get();
+        self.diverges.set(Diverges::Maybe);
+        self.has_errors.set(false);
+
         let ty = self.check_expr_kind(expr, expected, lvalue_pref);
 
+        // Warn for non-block expressions with diverging children.
+        match expr.node {
+            hir::ExprBlock(_) |
+            hir::ExprLoop(..) | hir::ExprWhile(..) |
+            hir::ExprIf(..) | hir::ExprMatch(..) => {}
+
+            _ => self.warn_if_unreachable(expr.id, expr.span, "expression")
+        }
+
+        // Record the type, which applies it effects.
+        // We need to do this after the warning above, so that
+        // we don't warn for the diverging expression itself.
         self.write_ty(expr.id, ty);
 
+        // Combine the diverging and has_error flags.
+        self.diverges.set(self.diverges.get() | old_diverges);
+        self.has_errors.set(self.has_errors.get() | old_has_errors);
+
         debug!("type of expr({}) {} is...", expr.id,
                pprust::expr_to_string(expr));
         debug!("... {:?}, expected is {:?}",
@@ -3580,22 +3608,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                  expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
-            let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
+            self.check_expr_has_type(&cond, tcx.types.bool);
+            let cond_diverging = self.diverges.get();
             self.check_block_no_value(&body);
-            let body_ty = self.node_ty(body.id);
-            if cond_ty.references_error() || body_ty.references_error() {
+
+            // We may never reach the body so it diverging means nothing.
+            self.diverges.set(cond_diverging);
+
+            if self.has_errors.get() {
                 tcx.types.err
-            }
-            else {
+            } else {
                 tcx.mk_nil()
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
-            if !may_break(tcx, expr.id, &body) {
-                tcx.types.never
-            } else {
+            if may_break(tcx, expr.id, &body) {
+                // No way to know whether it's diverging because
+                // of a `break` or an outer `break` or `return.
+                self.diverges.set(Diverges::Maybe);
+
                 tcx.mk_nil()
+            } else {
+                tcx.types.never
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
@@ -3928,55 +3963,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
-        let node_id;
-        let mut saw_bot = false;
-        let mut saw_err = false;
+        // Don't do all the complex logic below for DeclItem.
         match stmt.node {
-          hir::StmtDecl(ref decl, id) => {
-            node_id = id;
-            match decl.node {
-              hir::DeclLocal(ref l) => {
-                  self.check_decl_local(&l);
-                  let l_t = self.node_ty(l.id);
-                  saw_bot = saw_bot || self.type_var_diverges(l_t);
-                  saw_err = saw_err || l_t.references_error();
-              }
-              hir::DeclItem(_) => {/* ignore for now */ }
+            hir::StmtDecl(ref decl, id) => {
+                match decl.node {
+                    hir::DeclLocal(_) => {}
+                    hir::DeclItem(_) => {
+                        self.write_nil(id);
+                        return;
+                    }
+                }
             }
-          }
-          hir::StmtExpr(ref expr, id) => {
-            node_id = id;
-            // Check with expected type of ()
-            let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            saw_bot = saw_bot || self.type_var_diverges(ty);
-            saw_err = saw_err || ty.references_error();
-          }
-          hir::StmtSemi(ref expr, id) => {
-            node_id = id;
-            let ty = self.check_expr(&expr);
-            saw_bot |= self.type_var_diverges(ty);
-            saw_err |= ty.references_error();
-          }
-        }
-        if saw_bot {
-            self.write_ty(node_id, self.next_diverging_ty_var());
+            hir::StmtExpr(..) | hir::StmtSemi(..) => {}
         }
-        else if saw_err {
+
+        self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement");
+
+        // Hide the outer diverging and has_errors flags.
+        let old_diverges = self.diverges.get();
+        let old_has_errors = self.has_errors.get();
+        self.diverges.set(Diverges::Maybe);
+        self.has_errors.set(false);
+
+        let node_id = match stmt.node {
+            hir::StmtDecl(ref decl, id) => {
+                match decl.node {
+                    hir::DeclLocal(ref l) => {
+                        self.check_decl_local(&l);
+                    }
+                    hir::DeclItem(_) => {/* ignore for now */ }
+                }
+                id
+            }
+            hir::StmtExpr(ref expr, id) => {
+                // Check with expected type of ()
+                self.check_expr_has_type(&expr, self.tcx.mk_nil());
+                id
+            }
+            hir::StmtSemi(ref expr, id) => {
+                self.check_expr(&expr);
+                id
+            }
+        };
+
+        if self.has_errors.get() {
             self.write_error(node_id);
-        }
-        else {
+        } else if self.diverges.get().always() {
+            self.write_ty(node_id, self.next_diverging_ty_var());
+        } else {
             self.write_nil(node_id);
         }
+
+        // Combine the diverging and has_error flags.
+        self.diverges.set(self.diverges.get() | old_diverges);
+        self.has_errors.set(self.has_errors.get() | old_has_errors);
     }
 
     pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
-        let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
-        if blkty.references_error() {
-            self.write_error(blk.id);
-        } else {
-            let nilty = self.tcx.mk_nil();
-            self.demand_suptype(blk.span, nilty, blkty);
-        }
+        let unit = self.tcx.mk_nil();
+        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+        self.demand_suptype(blk.span, unit, ty);
     }
 
     fn check_block_with_expected(&self,
@@ -3988,72 +4034,81 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             replace(&mut *fcx_ps, unsafety_state)
         };
 
-        let mut warned = false;
-        let mut any_diverges = false;
-        let mut any_err = false;
         for s in &blk.stmts {
             self.check_stmt(s);
-            let s_id = s.node.id();
-            let s_ty = self.node_ty(s_id);
-            if any_diverges && !warned && match s.node {
-                hir::StmtDecl(ref decl, _) => {
-                    match decl.node {
-                        hir::DeclLocal(_) => true,
-                        _ => false,
+        }
+
+        let mut ty = match blk.expr {
+            Some(ref e) => self.check_expr_with_expectation(e, expected),
+            None => self.tcx.mk_nil()
+        };
+
+        if self.diverges.get().always() {
+            if let ExpectHasType(ety) = expected {
+                // Avoid forcing a type (only `!` for now) in unreachable code.
+                // FIXME(aburka) do we need this special case? and should it be is_uninhabited?
+                if !ety.is_never() {
+                    if let Some(ref e) = blk.expr {
+                        // Coerce the tail expression to the right type.
+                        self.demand_coerce(e, ty, ety);
                     }
                 }
-                hir::StmtExpr(..) | hir::StmtSemi(..) => true,
-            } {
-                self.tcx
-                    .sess
-                    .add_lint(lint::builtin::UNREACHABLE_CODE,
-                              s_id,
-                              s.span,
-                              "unreachable statement".to_string());
-                warned = true;
             }
-            // FIXME(canndrew): This is_never should probably be an is_uninhabited
-            any_diverges = any_diverges ||
-                           self.type_var_diverges(s_ty) ||
-                           s_ty.is_never();
-            any_err = any_err || s_ty.references_error();
-        }
-        let ty = match blk.expr {
-            None => if any_err {
-                self.tcx.types.err
-            } else if any_diverges {
-                self.next_diverging_ty_var()
+
+            ty = self.next_diverging_ty_var();
+        } else if let ExpectHasType(ety) = expected {
+            if let Some(ref e) = blk.expr {
+                // Coerce the tail expression to the right type.
+                self.demand_coerce(e, ty, ety);
             } else {
-                self.tcx.mk_nil()
-            },
-            Some(ref e) => {
-                if any_diverges && !warned {
-                    self.tcx
-                        .sess
-                        .add_lint(lint::builtin::UNREACHABLE_CODE,
-                                  e.id,
-                                  e.span,
-                                  "unreachable expression".to_string());
-                }
-                let ety = match expected {
-                    ExpectHasType(ety) => {
-                        self.check_expr_coercable_to_type(&e, ety);
-                        ety
-                    }
-                    _ => {
-                        self.check_expr_with_expectation(&e, expected)
-                    }
-                };
+                // We're not diverging and there's an expected type, which,
+                // in case it's not `()`, could result in an error higher-up.
+                // We have a chance to error here early and be more helpful.
+                let origin = TypeOrigin::Misc(blk.span);
+                let trace = TypeTrace::types(origin, false, ty, ety);
+                match self.sub_types(false, origin, ty, ety) {
+                    Ok(InferOk { obligations, .. }) => {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                    },
+                    Err(err) => {
+                        let mut err = self.report_and_explain_type_error(trace, &err);
+
+                        // Be helpful when the user wrote `{... expr;}` and
+                        // taking the `;` off is enough to fix the error.
+                        let mut extra_semi = None;
+                        if let Some(stmt) = blk.stmts.last() {
+                            if let hir::StmtSemi(ref e, _) = stmt.node {
+                                if self.can_sub_types(self.node_ty(e.id), ety).is_ok() {
+                                    extra_semi = Some(stmt);
+                                }
+                            }
+                        }
+                        if let Some(last_stmt) = extra_semi {
+                            let original_span = original_sp(self.tcx.sess.codemap(),
+                                                            last_stmt.span, blk.span);
+                            let span_semi = Span {
+                                lo: original_span.hi - BytePos(1),
+                                hi: original_span.hi,
+                                expn_id: original_span.expn_id
+                            };
+                            err.span_help(span_semi, "consider removing this semicolon:");
+                        }
 
-                if any_err {
-                    self.tcx.types.err
-                } else if any_diverges {
-                    self.next_diverging_ty_var()
-                } else {
-                    ety
+                        err.emit();
+                    }
                 }
             }
-        };
+
+            // We already applied the type (and potentially errored),
+            // use the expected type to avoid further errors out.
+            ty = ety;
+        }
+
+        if self.has_errors.get() || ty.references_error() {
+            ty = self.tcx.types.err
+        }
+
         self.write_ty(blk.id, ty);
 
         *self.ps.borrow_mut() = prev;
@@ -4149,7 +4204,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Case 3. Reference to a method or associated const.
             Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
-                let container = self.tcx.impl_or_trait_item(def_id).container();
+                let container = self.tcx.associated_item(def_id).container;
                 match container {
                     ty::TraitContainer(trait_did) => {
                         callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
@@ -4290,13 +4345,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // The things we are substituting into the type should not contain
         // escaping late-bound regions, and nor should the base type scheme.
         let scheme = self.tcx.lookup_item_type(def.def_id());
-        let type_predicates = self.tcx.lookup_predicates(def.def_id());
         assert!(!substs.has_escaping_regions());
         assert!(!scheme.ty.has_escaping_regions());
 
         // Add all the obligations that are required, substituting and
         // normalized appropriately.
-        let bounds = self.instantiate_bounds(span, &substs, &type_predicates);
+        let bounds = self.instantiate_bounds(span, def.def_id(), &substs);
         self.add_obligations_for_parameters(
             traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())),
             &bounds);
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 411bd7e7b5c..8b4975b7e3a 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -75,8 +75,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
+                let lhs_diverges = self.diverges.get();
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
                 self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
+
+                // Depending on the LHS' value, the RHS can never execute.
+                self.diverges.set(lhs_diverges);
+
                 tcx.mk_bool()
             }
             _ => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 6f6538254c4..d4e5e9a5bb3 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -142,13 +142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn regionck_fn(&self,
                        fn_id: ast::NodeId,
                        decl: &hir::FnDecl,
-                       blk: &hir::Block) {
+                       body: &hir::Expr) {
         debug!("regionck_fn(id={})", fn_id);
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id));
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id));
 
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id));
+            rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id));
         }
 
         rcx.free_region_map.relate_free_regions_from_predicates(
@@ -268,7 +268,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn visit_fn_body(&mut self,
                      id: ast::NodeId, // the id of the fn itself
                      fn_decl: &hir::FnDecl,
-                     body: &hir::Block,
+                     body: &hir::Expr,
                      span: Span)
     {
         // When we enter a function, we can derive
@@ -305,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         self.relate_free_regions(&fn_sig_tys[..], body.id, span);
         self.link_fn_args(self.tcx.region_maps.node_extent(body.id),
                           &fn_decl.inputs[..]);
-        self.visit_block(body);
+        self.visit_expr(body);
         self.visit_region_obligations(body.id);
 
         let call_site_scope = self.call_site_scope.unwrap();
@@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
     // regions, until regionck, as described in #3238.
 
     fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Block, span: Span, id: ast::NodeId) {
+                b: &'v hir::Expr, span: Span, id: ast::NodeId) {
         self.visit_fn_body(id, fd, b, span)
     }
 
@@ -825,7 +825,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn check_expr_fn_block(&mut self,
                            expr: &hir::Expr,
-                           body: &hir::Block) {
+                           body: &hir::Expr) {
         let repeating_scope = self.set_repeating_scope(body.id);
         intravisit::walk_expr(self, expr);
         self.set_repeating_scope(repeating_scope);
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index aa221c33b5d..2fea86cb212 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -57,18 +57,7 @@ use rustc::util::nodemap::NodeMap;
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn closure_analyze_fn(&self, body: &hir::Block) {
-        let mut seed = SeedBorrowKind::new(self);
-        seed.visit_block(body);
-
-        let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
-        adjust.visit_block(body);
-
-        // it's our job to process these.
-        assert!(self.deferred_call_resolutions.borrow().is_empty());
-    }
-
-    pub fn closure_analyze_const(&self, body: &hir::Expr) {
+    pub fn closure_analyze(&self, body: &hir::Expr) {
         let mut seed = SeedBorrowKind::new(self);
         seed.visit_expr(body);
 
@@ -110,7 +99,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
     fn check_closure(&mut self,
                      expr: &hir::Expr,
                      capture_clause: hir::CaptureClause,
-                     _body: &hir::Block)
+                     _body: &hir::Expr)
     {
         let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
         if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
@@ -164,7 +153,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                        id: ast::NodeId,
                        span: Span,
                        decl: &hir::FnDecl,
-                       body: &hir::Block) {
+                       body: &hir::Expr) {
         /*!
          * Analysis starting point.
          */
@@ -497,7 +486,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
     fn visit_fn(&mut self,
                 fn_kind: intravisit::FnKind<'v>,
                 decl: &'v hir::FnDecl,
-                body: &'v hir::Block,
+                body: &'v hir::Expr,
                 span: Span,
                 id: ast::NodeId)
     {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 741f327ac99..4136f543ccc 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use astconv::ExplicitSelf;
 use check::FnCtxt;
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
+
 use hir::def_id::DefId;
 use middle::region::{CodeExtent};
 use rustc::infer::TypeOrigin;
@@ -156,8 +158,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
-            hir::ItemTrait(.., ref items) => {
-                self.check_trait(item, items);
+            hir::ItemTrait(..) => {
+                self.check_trait(item);
             }
             _ => {}
         }
@@ -172,32 +174,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let free_substs = &fcx.parameter_environment.free_substs;
             let free_id_outlive = fcx.parameter_environment.free_id_outlive;
 
-            let item = fcx.tcx.impl_or_trait_item(fcx.tcx.map.local_def_id(item_id));
+            let item = fcx.tcx.associated_item(fcx.tcx.map.local_def_id(item_id));
 
-            let (mut implied_bounds, self_ty) = match item.container() {
+            let (mut implied_bounds, self_ty) = match item.container {
                 ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
                 ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
                                               fcx.tcx.lookup_item_type(def_id).ty)
             };
 
-            match item {
-                ty::ConstTraitItem(assoc_const) => {
-                    let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty);
+            match item.kind {
+                ty::AssociatedKind::Const => {
+                    let ty = fcx.tcx.lookup_item_type(item.def_id).ty;
+                    let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
                     fcx.register_wf_obligation(ty, span, code.clone());
                 }
-                ty::MethodTraitItem(method) => {
-                    reject_shadowing_type_parameters(fcx.tcx, span, &method.generics);
-                    let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
-                    let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
-                    this.check_fn_or_method(fcx, span, &method_ty, &predicates,
+                ty::AssociatedKind::Method => {
+                    reject_shadowing_type_parameters(fcx.tcx, span, item.def_id);
+                    let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty;
+                    let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
+                    let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
+                    let fty = match method_ty.sty {
+                        ty::TyFnDef(_, _, f) => f,
+                        _ => bug!()
+                    };
+                    this.check_fn_or_method(fcx, span, fty, &predicates,
                                             free_id_outlive, &mut implied_bounds);
                     let sig_if_method = sig_if_method.expect("bad signature for method");
-                    this.check_method_receiver(fcx, sig_if_method, &method,
+                    this.check_method_receiver(fcx, sig_if_method, &item,
                                                free_id_outlive, self_ty);
                 }
-                ty::TypeTraitItem(assoc_type) => {
-                    if let Some(ref ty) = assoc_type.ty {
-                        let ty = fcx.instantiate_type_scheme(span, free_substs, ty);
+                ty::AssociatedKind::Type => {
+                    if item.has_value {
+                        let ty = fcx.tcx.lookup_item_type(item.def_id).ty;
+                        let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
                         fcx.register_wf_obligation(ty, span, code.clone());
                     }
                 }
@@ -248,19 +257,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             }
 
             let free_substs = &fcx.parameter_environment.free_substs;
-            let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id));
-            let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
+            let def_id = fcx.tcx.map.local_def_id(item.id);
+            let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
             this.check_where_clauses(fcx, item.span, &predicates);
 
             vec![] // no implied bounds in a struct def'n
         });
     }
 
-    fn check_auto_trait(&mut self,
-                        trait_def_id: DefId,
-                        items: &[hir::TraitItem],
-                        span: Span)
-    {
+    fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) {
         // We want to ensure:
         //
         // 1) that there are no items contained within
@@ -302,7 +307,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         // extraneous predicates created by things like
         // an associated type inside the trait.
         let mut err = None;
-        if !items.is_empty() {
+        if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() {
             error_380(self.ccx, span);
         } else if has_ty_params {
             err = Some(struct_span_err!(self.tcx().sess, span, E0567,
@@ -326,20 +331,16 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         }
     }
 
-    fn check_trait(&mut self,
-                   item: &hir::Item,
-                   items: &[hir::TraitItem])
-    {
+    fn check_trait(&mut self, item: &hir::Item) {
         let trait_def_id = self.tcx().map.local_def_id(item.id);
 
         if self.tcx().trait_has_default_impl(trait_def_id) {
-            self.check_auto_trait(trait_def_id, items, item.span);
+            self.check_auto_trait(trait_def_id, item.span);
         }
 
         self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
-            let predicates = fcx.tcx.lookup_predicates(trait_def_id);
-            let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
+            let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs);
             this.check_where_clauses(fcx, item.span, &predicates);
             vec![]
         });
@@ -347,11 +348,12 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
     fn check_item_fn(&mut self,
                      item: &hir::Item,
-                     body: &hir::Block)
+                     body: &hir::Expr)
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
-            let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id));
+            let def_id = fcx.tcx.map.local_def_id(item.id);
+            let type_scheme = fcx.tcx.lookup_item_type(def_id);
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
             let bare_fn_ty = match item_ty.sty {
                 ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
@@ -360,8 +362,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 }
             };
 
-            let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id));
-            let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
+            let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
 
             let mut implied_bounds = vec![];
             let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body.id);
@@ -422,8 +423,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 }
             }
 
-            let predicates = fcx.tcx.lookup_predicates(item_def_id);
-            let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
+            let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs);
             this.check_where_clauses(fcx, item.span, &predicates);
 
             fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span)
@@ -476,35 +476,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     fn check_method_receiver<'fcx, 'tcx>(&mut self,
                                          fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                          method_sig: &hir::MethodSig,
-                                         method: &ty::Method<'tcx>,
+                                         method: &ty::AssociatedItem,
                                          free_id_outlive: CodeExtent,
                                          self_ty: ty::Ty<'tcx>)
     {
         // check that the type of the method's receiver matches the
         // method's first parameter.
-        debug!("check_method_receiver({:?},cat={:?},self_ty={:?})",
-               method.name, method.explicit_self, self_ty);
+        debug!("check_method_receiver({:?}, self_ty={:?})",
+               method, self_ty);
 
-        let rcvr_ty = match method.explicit_self {
-            ty::ExplicitSelfCategory::Static => return,
-            ty::ExplicitSelfCategory::ByValue => self_ty,
-            ty::ExplicitSelfCategory::ByReference(region, mutability) => {
-                fcx.tcx.mk_ref(region, ty::TypeAndMut {
-                    ty: self_ty,
-                    mutbl: mutability
-                })
-            }
-            ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty)
-        };
+        if !method.method_has_self_argument {
+            return;
+        }
 
         let span = method_sig.decl.inputs[0].pat.span;
 
         let free_substs = &fcx.parameter_environment.free_substs;
-        let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+        let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty;
+        let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig());
 
         debug!("check_method_receiver: sig={:?}", sig);
 
+        let self_arg_ty = sig.inputs[0];
+        let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
+            ExplicitSelf::ByValue => self_ty,
+            ExplicitSelf::ByReference(region, mutbl) => {
+                fcx.tcx.mk_ref(region, ty::TypeAndMut {
+                    ty: self_ty,
+                    mutbl: mutbl
+                })
+            }
+            ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
+        };
         let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
         let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive,
                                                           &ty::Binder(rcvr_ty));
@@ -512,7 +516,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
         let origin = TypeOrigin::MethodReceiver(span);
-        fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]);
+        fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty);
     }
 
     fn check_variances_for_type_defn(&self,
@@ -578,7 +582,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     }
 }
 
-fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) {
+fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) {
+    let generics = tcx.lookup_generics(def_id);
     let parent = tcx.lookup_generics(generics.parent.unwrap());
     let impl_params: FxHashMap<_, _> = parent.types
                                        .iter()
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 5ef3e869960..9f3214a0d81 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -49,11 +49,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn resolve_type_vars_in_fn(&self,
                                    decl: &hir::FnDecl,
-                                   blk: &hir::Block,
+                                   body: &hir::Expr,
                                    item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_block(blk);
+        wbcx.visit_expr(body);
         for arg in &decl.inputs {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
             wbcx.visit_pat(&arg.pat);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 4a4dea5b514..90541539c1e 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -38,8 +38,6 @@ use rustc::hir::intravisit;
 use rustc::hir::{Item, ItemImpl};
 use rustc::hir;
 
-use std::rc::Rc;
-
 mod orphan;
 mod overlap;
 mod unsafety;
@@ -113,8 +111,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         // If there are no traits, then this implementation must have a
         // base type.
 
-        let impl_items = self.create_impl_from_item(item);
-
         if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
             debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
                    trait_ref,
@@ -144,8 +140,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 self.add_inherent_impl(base_def_id, impl_did);
             }
         }
-
-        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) {
@@ -161,20 +155,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
     }
 
-    // Converts an implementation in the AST to a vector of items.
-    fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
-        match item.node {
-            ItemImpl(.., ref impl_items) => {
-                impl_items.iter()
-                    .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id))
-                    .collect()
-            }
-            _ => {
-                span_bug!(item.span, "can't convert a non-impl to an impl");
-            }
-        }
-    }
-
     // Destructors
     //
 
@@ -187,10 +167,8 @@ 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_or_trait_item_def_ids.borrow();
-
         drop_trait.for_each_impl(tcx, |impl_did| {
-            let items = impl_items.get(&impl_did).unwrap();
+            let items = tcx.associated_item_def_ids(impl_did);
             if items.is_empty() {
                 // We'll error out later. For now, just don't ICE.
                 return;
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 1bf140c21a5..b5aba512a66 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -48,25 +48,23 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
             Value,
         }
 
-        fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        def_id: DefId)
-                                        -> (ast::Name, Namespace) {
-            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 name_and_namespace = |def_id| {
+            let item = self.tcx.associated_item(def_id);
+            (item.name, match item.kind {
+                ty::AssociatedKind::Type => Namespace::Type,
+                ty::AssociatedKind::Const |
+                ty::AssociatedKind::Method => Namespace::Value,
+            })
+        };
 
-        let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
+        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
+        let impl_items2 = self.tcx.associated_item_def_ids(impl2);
 
-        for &item1 in &impl_items[&impl1][..] {
-            let (name, namespace) = name_and_namespace(self.tcx, item1);
+        for &item1 in &impl_items1[..] {
+            let (name, namespace) = name_and_namespace(item1);
 
-            for &item2 in &impl_items[&impl2][..] {
-                if (name, namespace) == name_and_namespace(self.tcx, item2) {
+            for &item2 in &impl_items2[..] {
+                if (name, namespace) == name_and_namespace(item2) {
                     let msg = format!("duplicate definitions with name `{}`", name);
                     let node_id = self.tcx.map.as_local_node_id(item1).unwrap();
                     self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5c51877ae74..d92a9848510 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -66,7 +66,7 @@ use middle::const_val::ConstVal;
 use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err};
 use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
+use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
 use rustc::ty::util::IntTypeExt;
 use rscope::*;
@@ -79,7 +79,6 @@ use rustc_const_math::ConstInt;
 
 use std::cell::RefCell;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
-use std::rc::Rc;
 
 use syntax::{abi, ast, attr};
 use syntax::parse::token::keywords;
@@ -351,24 +350,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         })
     }
 
-    fn trait_defines_associated_type_named(&self,
-                                           trait_def_id: DefId,
-                                           assoc_name: ast::Name)
-                                           -> bool
-    {
-        if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) {
-            trait_associated_type_names(self.tcx(), trait_id)
-                .any(|name| name == assoc_name)
-        } else {
-            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 get_free_substs(&self) -> Option<&Substs<'tcx>> {
         None
     }
@@ -557,60 +538,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                            container: ImplOrTraitItemContainer,
-                            name: ast::Name,
-                            id: ast::NodeId,
-                            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);
-    let ty_generics = generics_of_def_id(ccx, def_id);
-
-    let ty_generic_predicates =
-        ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
-
-    let (fty, explicit_self_category) = {
-        let anon_scope = match container {
-            ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
-            TraitContainer(_) => None
-        };
-        AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                              sig, untransformed_rcvr_ty, anon_scope)
-    };
-
-    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);
-    let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty);
-    debug!("method {} (id {}) has type {:?}",
-            name, id, fty);
-    ccx.tcx.tcache.borrow_mut().insert(def_id, fty);
-    write_ty_to_tcx(ccx, id, fty);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone());
-
-    debug!("writing method type: def_id={:?} mty={:?}",
-            def_id, ty_method);
-
-    ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id,
-        ty::MethodTraitItem(Rc::new(ty_method)));
-}
-
 fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            struct_generics: &'tcx ty::Generics<'tcx>,
                            struct_predicates: &ty::GenericPredicates<'tcx>,
@@ -631,62 +558,65 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                            struct_predicates.clone());
 }
 
+fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                            container: AssociatedItemContainer,
+                            id: ast::NodeId,
+                            sig: &hir::MethodSig,
+                            untransformed_rcvr_ty: Ty<'tcx>,
+                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
+    let def_id = ccx.tcx.map.local_def_id(id);
+    let ty_generics = generics_of_def_id(ccx, def_id);
+
+    let ty_generic_predicates =
+        ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
+
+    let anon_scope = match container {
+        ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
+        TraitContainer(_) => None
+    };
+    let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
+                                    sig, untransformed_rcvr_ty, anon_scope);
+
+    let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
+                                ccx.tcx.map.span(id), def_id);
+    let fty = ccx.tcx.mk_fn_def(def_id, substs, fty);
+    ccx.tcx.tcache.borrow_mut().insert(def_id, fty);
+    write_ty_to_tcx(ccx, id, fty);
+    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates);
+}
+
 fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                      container: ImplOrTraitItemContainer,
-                                      name: ast::Name,
+                                      container: AssociatedItemContainer,
                                       id: ast::NodeId,
-                                      vis: &hir::Visibility,
-                                      defaultness: hir::Defaultness,
-                                      ty: ty::Ty<'tcx>,
-                                      has_value: bool)
+                                      ty: ty::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 def_id = ccx.tcx.map.local_def_id(id);
+    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
+    ccx.tcx.tcache.borrow_mut().insert(def_id, ty);
 
     write_ty_to_tcx(ccx, id, ty);
-
-    let associated_const = Rc::new(ty::AssociatedConst {
-        name: name,
-        vis: ty::Visibility::from_hir(vis, id, ccx.tcx),
-        defaultness: defaultness,
-        def_id: ccx.tcx.map.local_def_id(id),
-        container: container,
-        ty: ty,
-        has_value: has_value
-    });
-    ccx.tcx.impl_or_trait_items.borrow_mut()
-       .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const));
 }
 
 fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     container: ImplOrTraitItemContainer,
-                                     name: ast::Name,
+                                     container: AssociatedItemContainer,
                                      id: ast::NodeId,
-                                     vis: &hir::Visibility,
-                                     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 def_id = ccx.tcx.map.local_def_id(id);
+    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
 
-    let associated_type = Rc::new(ty::AssociatedType {
-        name: name,
-        vis: ty::Visibility::from_hir(vis, id, ccx.tcx),
-        defaultness: defaultness,
-        ty: ty,
-        def_id: ccx.tcx.map.local_def_id(id),
-        container: container
-    });
-    ccx.tcx.impl_or_trait_items.borrow_mut()
-       .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type));
+    if let Some(ty) = ty {
+        ccx.tcx.tcache.borrow_mut().insert(def_id, ty);
+        write_ty_to_tcx(ccx, id, ty);
+    }
 }
 
 fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
@@ -820,14 +750,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                                generics: ty_generics,
                                                ty: ty,
                                            });
-                    // Trait-associated constants are always public.
-                    let public = &hir::Public;
-                    let visibility = if opt_trait_ref.is_some() { public } else { &impl_item.vis };
                     convert_associated_const(ccx, ImplContainer(def_id),
-                                             impl_item.name, impl_item.id,
-                                             visibility,
-                                             impl_item.defaultness,
-                                             ty, true /* has_value */);
+                                             impl_item.id, ty);
                 }
             }
 
@@ -844,21 +768,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
 
-                    convert_associated_type(ccx, ImplContainer(def_id),
-                                            impl_item.name, impl_item.id, &impl_item.vis,
-                                            impl_item.defaultness, Some(typ));
+                    convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ));
                 }
             }
 
             for impl_item in impl_items {
                 if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
-                    // Trait methods are always public.
-                    let public = &hir::Public;
-                    let method_vis = if opt_trait_ref.is_some() { public } else { &impl_item.vis };
-
                     convert_method(ccx, ImplContainer(def_id),
-                                   impl_item.name, impl_item.id, method_vis,
-                                   sig, impl_item.defaultness, true, selfty,
+                                   impl_item.id, sig, selfty,
                                    &ty_predicates);
                 }
             }
@@ -880,7 +797,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             // Convert all the associated constants.
             for trait_item in trait_items {
-                if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node {
+                if let hir::ConstTraitItem(ref ty, _) = trait_item.node {
                     let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
                     let ty_generics = generics_of_def_id(ccx, const_def_id);
                     let ty = ccx.icx(&trait_predicates)
@@ -890,14 +807,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                                generics: ty_generics,
                                                ty: ty,
                                            });
-                    convert_associated_const(ccx,
-                                             container,
-                                             trait_item.name,
-                                             trait_item.id,
-                                             &hir::Public,
-                                             hir::Defaultness::Default,
-                                             ty,
-                                             default.is_some())
+                    convert_associated_const(ccx, container, trait_item.id, ty)
                 }
             }
 
@@ -911,39 +821,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                         |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
                     });
 
-                    convert_associated_type(ccx,
-                                            container,
-                                            trait_item.name,
-                                            trait_item.id,
-                                            &hir::Public,
-                                            hir::Defaultness::Default,
-                                            typ);
+                    convert_associated_type(ccx, container, trait_item.id, typ);
                 }
             }
 
             // Convert all the methods
             for trait_item in trait_items {
-                if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node {
+                if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
                     convert_method(ccx,
                                    container,
-                                   trait_item.name,
                                    trait_item.id,
-                                   &hir::Inherited,
                                    sig,
-                                   hir::Defaultness::Default,
-                                   body.is_some(),
                                    tcx.mk_self_type(),
                                    &trait_predicates);
-
                 }
             }
-
-            // Add an entry mapping
-            let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
-                ccx.tcx.map.local_def_id(trait_item.id)
-            }).collect());
-            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, _) => {
@@ -1308,28 +1200,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     tcx.intern_trait_def(trait_def)
 }
 
-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 tcx.map.get(trait_node_id) {
-        hir_map::NodeItem(item) => item,
-        _ => bug!("trait_node_id {} is not an item", trait_node_id)
-    };
-
-    let trait_items = match item.node {
-        hir::ItemTrait(.., ref trait_items) => trait_items,
-        _ => bug!("trait_node_id {} is not a trait", trait_node_id)
-    };
-
-    trait_items.iter().filter_map(|trait_item| {
-        match trait_item.node {
-            hir::TypeTraitItem(..) => Some(trait_item.name),
-            _ => None,
-        }
-    })
-}
-
 fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) {
     let tcx = ccx.tcx;
     let trait_def = trait_def_of_item(ccx, it);
@@ -2209,13 +2079,14 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
 
     let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter()
-        .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id)))
-        .filter_map(|item| match item {
-            ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
-            ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
+        .map(|item|  ccx.tcx.map.local_def_id(item.id))
+        .filter(|&def_id| {
+            let item = ccx.tcx.associated_item(def_id);
+            item.kind == ty::AssociatedKind::Type && item.has_value
         })
-        .flat_map(|ty| ctp::parameters_for(&ty, true))
-        .collect();
+        .flat_map(|def_id| {
+            ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true)
+        }).collect();
 
     for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter()
         .zip(&ast_generics.lifetimes)
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 1885b4276cc..a2955169cbb 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -163,7 +163,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
 pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       did: DefId) -> clean::Trait {
     let def = tcx.lookup_trait_def(did);
-    let trait_items = tcx.trait_items(did).clean(cx);
+    let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect();
     let predicates = tcx.lookup_predicates(did);
     let generics = (def.generics, &predicates).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
@@ -307,7 +307,6 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,
 
     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);
         }
     }
@@ -367,21 +366,18 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
     }
 
     let predicates = tcx.lookup_predicates(did);
-    let trait_items = tcx.sess.cstore.impl_or_trait_items(did)
-            .iter()
-            .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);
-                let default = if assoc_const.has_value {
+    let trait_items = tcx.associated_items(did).filter_map(|item| {
+        match item.kind {
+            ty::AssociatedKind::Const => {
+                let type_scheme = tcx.lookup_item_type(item.def_id);
+                let default = if item.has_value {
                     Some(pprust::expr_to_string(
-                        lookup_const_by_id(tcx, did, None).unwrap().0))
+                        lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
                 } else {
                     None
                 };
                 Some(clean::Item {
-                    name: Some(assoc_const.name.clean(cx)),
+                    name: Some(item.name.clean(cx)),
                     inner: clean::AssociatedConstItem(
                         type_scheme.ty.clean(cx),
                         default,
@@ -389,21 +385,21 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                     source: clean::Span::empty(),
                     attrs: vec![],
                     visibility: None,
-                    stability: tcx.lookup_stability(did).clean(cx),
-                    deprecation: tcx.lookup_deprecation(did).clean(cx),
-                    def_id: did
+                    stability: tcx.lookup_stability(item.def_id).clean(cx),
+                    deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
+                    def_id: item.def_id
                 })
             }
-            ty::MethodTraitItem(method) => {
-                if method.vis != ty::Visibility::Public && associated_trait.is_none() {
+            ty::AssociatedKind::Method => {
+                if item.vis != ty::Visibility::Public && associated_trait.is_none() {
                     return None
                 }
-                let mut item = method.clean(cx);
-                item.inner = match item.inner.clone() {
+                let mut cleaned = item.clean(cx);
+                cleaned.inner = match cleaned.inner.clone() {
                     clean::TyMethodItem(clean::TyMethod {
                         unsafety, decl, generics, abi
                     }) => {
-                        let constness = if tcx.sess.cstore.is_const_fn(did) {
+                        let constness = if tcx.sess.cstore.is_const_fn(item.def_id) {
                             hir::Constness::Const
                         } else {
                             hir::Constness::NotConst
@@ -419,12 +415,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                     }
                     _ => panic!("not a tymethod"),
                 };
-                Some(item)
+                Some(cleaned)
             }
-            ty::TypeTraitItem(ref assoc_ty) => {
-                let did = assoc_ty.def_id;
+            ty::AssociatedKind::Type => {
                 let typedef = clean::Typedef {
-                    type_: assoc_ty.ty.unwrap().clean(cx),
+                    type_: tcx.lookup_item_type(item.def_id).ty.clean(cx),
                     generics: clean::Generics {
                         lifetimes: vec![],
                         type_params: vec![],
@@ -432,14 +427,14 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                     }
                 };
                 Some(clean::Item {
-                    name: Some(assoc_ty.name.clean(cx)),
+                    name: Some(item.name.clean(cx)),
                     inner: clean::TypedefItem(typedef, true),
                     source: clean::Span::empty(),
                     attrs: vec![],
                     visibility: None,
-                    stability: tcx.lookup_stability(did).clean(cx),
-                    deprecation: tcx.lookup_deprecation(did).clean(cx),
-                    def_id: did
+                    stability: tcx.lookup_stability(item.def_id).clean(cx),
+                    deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
+                    def_id: item.def_id
                 })
             }
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index df13e384d96..9e29d191946 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1338,48 +1338,117 @@ impl Clean<Item> for hir::ImplItem {
     }
 }
 
-impl<'tcx> Clean<Item> for ty::Method<'tcx> {
+impl<'tcx> Clean<Item> for ty::AssociatedItem {
     fn clean(&self, cx: &DocContext) -> Item {
-        let generics = (self.generics, &self.predicates).clean(cx);
-        let mut decl = (self.def_id, &self.fty.sig).clean(cx);
-        match self.explicit_self {
-            ty::ExplicitSelfCategory::ByValue => {
-                decl.inputs.values[0].type_ = Infer;
+        let inner = match self.kind {
+            ty::AssociatedKind::Const => {
+                let ty = cx.tcx().lookup_item_type(self.def_id).ty;
+                AssociatedConstItem(ty.clean(cx), None)
             }
-            ty::ExplicitSelfCategory::ByReference(..) => {
-                match decl.inputs.values[0].type_ {
-                    BorrowedRef{ref mut type_, ..} => **type_ = Infer,
-                    _ => unreachable!(),
+            ty::AssociatedKind::Method => {
+                let generics = (cx.tcx().lookup_generics(self.def_id),
+                                &cx.tcx().lookup_predicates(self.def_id)).clean(cx);
+                let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty {
+                    ty::TyFnDef(_, _, f) => f,
+                    _ => unreachable!()
+                };
+                let mut decl = (self.def_id, &fty.sig).clean(cx);
+
+                if self.method_has_self_argument {
+                    let self_ty = match self.container {
+                        ty::ImplContainer(def_id) => {
+                            cx.tcx().lookup_item_type(def_id).ty
+                        }
+                        ty::TraitContainer(_) => cx.tcx().mk_self_type()
+                    };
+                    let self_arg_ty = *fty.sig.input(0).skip_binder();
+                    if self_arg_ty == self_ty {
+                        decl.inputs.values[0].type_ = Infer;
+                    } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
+                        if mt.ty == self_ty {
+                            match decl.inputs.values[0].type_ {
+                                BorrowedRef{ref mut type_, ..} => **type_ = Infer,
+                                _ => unreachable!(),
+                            }
+                        }
+                    }
+                }
+                let provided = match self.container {
+                    ty::ImplContainer(_) => false,
+                    ty::TraitContainer(_) => self.has_value
+                };
+                if provided {
+                    MethodItem(Method {
+                        unsafety: fty.unsafety,
+                        generics: generics,
+                        decl: decl,
+                        abi: fty.abi,
+
+                        // trait methods canot (currently, at least) be const
+                        constness: hir::Constness::NotConst,
+                    })
+                } else {
+                    TyMethodItem(TyMethod {
+                        unsafety: fty.unsafety,
+                        generics: generics,
+                        decl: decl,
+                        abi: fty.abi,
+                    })
                 }
             }
-            _ => {}
-        }
-        let provided = match self.container {
-            ty::ImplContainer(..) => false,
-            ty::TraitContainer(did) => {
-                cx.tcx().provided_trait_methods(did).iter().any(|m| {
-                    m.def_id == self.def_id
-                })
+            ty::AssociatedKind::Type => {
+                let my_name = self.name.clean(cx);
+
+                let mut bounds = if let ty::TraitContainer(did) = self.container {
+                    // When loading a cross-crate associated type, the bounds for this type
+                    // are actually located on the trait/impl itself, so we need to load
+                    // all of the generics from there and then look for bounds that are
+                    // applied to this associated type in question.
+                    let def = cx.tcx().lookup_trait_def(did);
+                    let predicates = cx.tcx().lookup_predicates(did);
+                    let generics = (def.generics, &predicates).clean(cx);
+                    generics.where_predicates.iter().filter_map(|pred| {
+                        let (name, self_type, trait_, bounds) = match *pred {
+                            WherePredicate::BoundPredicate {
+                                ty: QPath { ref name, ref self_type, ref trait_ },
+                                ref bounds
+                            } => (name, self_type, trait_, bounds),
+                            _ => return None,
+                        };
+                        if *name != my_name { return None }
+                        match **trait_ {
+                            ResolvedPath { did, .. } if did == self.container.id() => {}
+                            _ => return None,
+                        }
+                        match **self_type {
+                            Generic(ref s) if *s == "Self" => {}
+                            _ => return None,
+                        }
+                        Some(bounds)
+                    }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
+                } else {
+                    vec![]
+                };
+
+                // Our Sized/?Sized bound didn't get handled when creating the generics
+                // because we didn't actually get our whole set of bounds until just now
+                // (some of them may have come from the trait). If we do have a sized
+                // bound, we remove it, and if we don't then we add the `?Sized` bound
+                // at the end.
+                match bounds.iter().position(|b| b.is_sized_bound(cx)) {
+                    Some(i) => { bounds.remove(i); }
+                    None => bounds.push(TyParamBound::maybe_sized(cx)),
+                }
+
+                let ty = if self.has_value {
+                    Some(cx.tcx().lookup_item_type(self.def_id).ty)
+                } else {
+                    None
+                };
+
+                AssociatedTypeItem(bounds, ty.clean(cx))
             }
         };
-        let inner = if provided {
-            MethodItem(Method {
-                unsafety: self.fty.unsafety,
-                generics: generics,
-                decl: decl,
-                abi: self.fty.abi,
-
-                // trait methods canot (currently, at least) be const
-                constness: hir::Constness::NotConst,
-            })
-        } else {
-            TyMethodItem(TyMethod {
-                unsafety: self.fty.unsafety,
-                generics: generics,
-                decl: decl,
-                abi: self.fty.abi,
-            })
-        };
 
         Item {
             name: Some(self.name.clean(cx)),
@@ -1394,16 +1463,6 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
     }
 }
 
-impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Item {
-        match *self {
-            ty::ConstTraitItem(ref cti) => cti.clean(cx),
-            ty::MethodTraitItem(ref mti) => mti.clean(cx),
-            ty::TypeTraitItem(ref tti) => tti.clean(cx),
-        }
-    }
-}
-
 /// A trait reference, which may have higher ranked lifetimes.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct PolyTrait {
@@ -2884,79 +2943,6 @@ impl Clean<Deprecation> for attr::Deprecation {
     }
 }
 
-impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Item {
-        Item {
-            source: DUMMY_SP.clean(cx),
-            name: Some(self.name.clean(cx)),
-            attrs: Vec::new(),
-            inner: AssociatedConstItem(self.ty.clean(cx), None),
-            visibility: None,
-            def_id: self.def_id,
-            stability: None,
-            deprecation: None,
-        }
-    }
-}
-
-impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Item {
-        let my_name = self.name.clean(cx);
-
-        let mut bounds = if let ty::TraitContainer(did) = self.container {
-            // When loading a cross-crate associated type, the bounds for this type
-            // are actually located on the trait/impl itself, so we need to load
-            // all of the generics from there and then look for bounds that are
-            // applied to this associated type in question.
-            let def = cx.tcx().lookup_trait_def(did);
-            let predicates = cx.tcx().lookup_predicates(did);
-            let generics = (def.generics, &predicates).clean(cx);
-            generics.where_predicates.iter().filter_map(|pred| {
-                let (name, self_type, trait_, bounds) = match *pred {
-                    WherePredicate::BoundPredicate {
-                        ty: QPath { ref name, ref self_type, ref trait_ },
-                        ref bounds
-                    } => (name, self_type, trait_, bounds),
-                    _ => return None,
-                };
-                if *name != my_name { return None }
-                match **trait_ {
-                    ResolvedPath { did, .. } if did == self.container.id() => {}
-                    _ => return None,
-                }
-                match **self_type {
-                    Generic(ref s) if *s == "Self" => {}
-                    _ => return None,
-                }
-                Some(bounds)
-            }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
-        } else {
-            vec![]
-        };
-
-        // Our Sized/?Sized bound didn't get handled when creating the generics
-        // because we didn't actually get our whole set of bounds until just now
-        // (some of them may have come from the trait). If we do have a sized
-        // bound, we remove it, and if we don't then we add the `?Sized` bound
-        // at the end.
-        match bounds.iter().position(|b| b.is_sized_bound(cx)) {
-            Some(i) => { bounds.remove(i); }
-            None => bounds.push(TyParamBound::maybe_sized(cx)),
-        }
-
-        Item {
-            source: DUMMY_SP.clean(cx),
-            name: Some(self.name.clean(cx)),
-            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
-            inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
-            visibility: self.vis.clean(cx),
-            def_id: self.def_id,
-            stability: cx.tcx().lookup_stability(self.def_id).clean(cx),
-            deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx),
-        }
-    }
-}
-
 fn lang_struct(cx: &DocContext, did: Option<DefId>,
                t: ty::Ty, name: &str,
                fallback: fn(Box<Type>) -> Type) -> Type {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 9751ad6aa43..f5cd089e923 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1017,10 +1017,10 @@ pub enum ExprKind {
     Loop(P<Block>, Option<SpannedIdent>),
     /// A `match` block.
     Match(P<Expr>, Vec<Arm>),
-    /// A closure (for example, `move |a, b, c| {a + b + c}`)
+    /// A closure (for example, `move |a, b, c| a + b + c`)
     ///
     /// The final span is the span of the argument block `|...|`
-    Closure(CaptureBy, P<FnDecl>, P<Block>, Span),
+    Closure(CaptureBy, P<FnDecl>, P<Expr>, Span),
     /// A block (`{ ... }`)
     Block(P<Block>),
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 37bd83be7b4..c3e28cbb006 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -198,17 +198,13 @@ pub trait AstBuilder {
     fn lambda_fn_decl(&self,
                       span: Span,
                       fn_decl: P<ast::FnDecl>,
-                      blk: P<ast::Block>,
+                      body: P<ast::Expr>,
                       fn_decl_span: Span)
                       -> P<ast::Expr>;
 
-    fn lambda(&self, span: Span, ids: Vec<ast::Ident>, blk: P<ast::Block>) -> P<ast::Expr>;
-    fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr>;
-    fn lambda1(&self, span: Span, blk: P<ast::Block>, ident: ast::Ident) -> P<ast::Expr>;
-
-    fn lambda_expr(&self, span: Span, ids: Vec<ast::Ident> , blk: P<ast::Expr>) -> P<ast::Expr>;
-    fn lambda_expr_0(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Expr>;
-    fn lambda_expr_1(&self, span: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr>;
+    fn lambda(&self, span: Span, ids: Vec<ast::Ident>, body: P<ast::Expr>) -> P<ast::Expr>;
+    fn lambda0(&self, span: Span, body: P<ast::Expr>) -> P<ast::Expr>;
+    fn lambda1(&self, span: Span, body: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr>;
 
     fn lambda_stmts(&self, span: Span, ids: Vec<ast::Ident>,
                     blk: Vec<ast::Stmt>) -> P<ast::Expr>;
@@ -940,19 +936,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn lambda_fn_decl(&self,
                       span: Span,
                       fn_decl: P<ast::FnDecl>,
-                      blk: P<ast::Block>,
+                      body: P<ast::Expr>,
                       fn_decl_span: Span) // span of the `|...|` part
                       -> P<ast::Expr> {
         self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
                                                fn_decl,
-                                               blk,
+                                               body,
                                                fn_decl_span))
     }
 
     fn lambda(&self,
               span: Span,
               ids: Vec<ast::Ident>,
-              blk: P<ast::Block>)
+              body: P<ast::Expr>)
               -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
@@ -962,26 +958,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         // part of the lambda, but it probably (maybe?) corresponds to
         // the entire lambda body. Probably we should extend the API
         // here, but that's not entirely clear.
-        self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, blk, span))
-    }
-
-    fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
-        self.lambda(span, Vec::new(), blk)
+        self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, body, span))
     }
 
-    fn lambda1(&self, span: Span, blk: P<ast::Block>, ident: ast::Ident) -> P<ast::Expr> {
-        self.lambda(span, vec![ident], blk)
+    fn lambda0(&self, span: Span, body: P<ast::Expr>) -> P<ast::Expr> {
+        self.lambda(span, Vec::new(), body)
     }
 
-    fn lambda_expr(&self, span: Span, ids: Vec<ast::Ident>,
-                   expr: P<ast::Expr>) -> P<ast::Expr> {
-        self.lambda(span, ids, self.block_expr(expr))
-    }
-    fn lambda_expr_0(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
-        self.lambda0(span, self.block_expr(expr))
-    }
-    fn lambda_expr_1(&self, span: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> {
-        self.lambda1(span, self.block_expr(expr), ident)
+    fn lambda1(&self, span: Span, body: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> {
+        self.lambda(span, vec![ident], body)
     }
 
     fn lambda_stmts(&self,
@@ -989,14 +974,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                     ids: Vec<ast::Ident>,
                     stmts: Vec<ast::Stmt>)
                     -> P<ast::Expr> {
-        self.lambda(span, ids, self.block(span, stmts))
+        self.lambda(span, ids, self.expr_block(self.block(span, stmts)))
     }
     fn lambda_stmts_0(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Expr> {
-        self.lambda0(span, self.block(span, stmts))
+        self.lambda0(span, self.expr_block(self.block(span, stmts)))
     }
     fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
                       ident: ast::Ident) -> P<ast::Expr> {
-        self.lambda1(span, self.block(span, stmts), ident)
+        self.lambda1(span, self.expr_block(self.block(span, stmts)), ident)
     }
 
     fn arg(&self, span: Span, ident: ast::Ident, ty: P<ast::Ty>) -> ast::Arg {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index a6493872338..9116b392f17 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -354,7 +354,7 @@ declare_features! (
     // Allows `#[deprecated]` attribute
     (accepted, deprecated, "1.9.0", Some(29935)),
     // `expr?`
-    (accepted, question_mark, "1.14.0", Some(31436)),
+    (accepted, question_mark, "1.13.0", Some(31436)),
     // Allows `..` in tuple (struct) patterns
     (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
 );
@@ -1228,12 +1228,11 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
     fn visit_fn(&mut self,
                 fn_kind: FnKind,
                 fn_decl: &ast::FnDecl,
-                block: &ast::Block,
                 span: Span,
                 _node_id: NodeId) {
         // check for const fn declarations
         match fn_kind {
-            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => {
+            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
             }
             _ => {
@@ -1245,13 +1244,13 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
         }
 
         match fn_kind {
-            FnKind::ItemFn(_, _, _, _, abi, _) |
-            FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
+            FnKind::ItemFn(_, _, _, _, abi, _, _) |
+            FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
                 self.check_abi(abi, span);
             }
             _ => {}
         }
-        visit::walk_fn(self, fn_kind, fn_decl, block, span);
+        visit::walk_fn(self, fn_kind, fn_decl, span);
     }
 
     fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1deeaf42231..2e62f23578d 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1201,7 +1201,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
             ExprKind::Closure(capture_clause, decl, body, span) => {
                 ExprKind::Closure(capture_clause,
                                   folder.fold_fn_decl(decl),
-                                  folder.fold_block(body),
+                                  folder.fold_expr(body),
                                   folder.new_span(span))
             }
             ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b670a738473..7d15334ff9f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3162,25 +3162,12 @@ impl<'a> Parser<'a> {
         let decl = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_span.hi;
         let body = match decl.output {
-            FunctionRetTy::Default(_) => {
-                // If no explicit return type is given, parse any
-                // expr and wrap it up in a dummy block:
-                let body_expr = self.parse_expr()?;
-                P(ast::Block {
-                    id: ast::DUMMY_NODE_ID,
-                    span: body_expr.span,
-                    stmts: vec![Stmt {
-                        span: body_expr.span,
-                        node: StmtKind::Expr(body_expr),
-                        id: ast::DUMMY_NODE_ID,
-                    }],
-                    rules: BlockCheckMode::Default,
-                })
-            }
+            FunctionRetTy::Default(_) => self.parse_expr()?,
             _ => {
                 // If an explicit return type is given, require a
                 // block to appear (RFC 968).
-                self.parse_block()?
+                let body_lo = self.span.lo;
+                self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())?
             }
         };
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7352792a8a2..203c19285ac 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2128,26 +2128,8 @@ impl<'a> State<'a> {
 
                 try!(self.print_fn_block_args(&decl));
                 try!(space(&mut self.s));
-
-                let default_return = match decl.output {
-                    ast::FunctionRetTy::Default(..) => true,
-                    _ => false
-                };
-
-                match body.stmts.last().map(|stmt| &stmt.node) {
-                    Some(&ast::StmtKind::Expr(ref i_expr)) if default_return &&
-                                                              body.stmts.len() == 1 => {
-                        // we extract the block, so as not to create another set of boxes
-                        if let ast::ExprKind::Block(ref blk) = i_expr.node {
-                            try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs));
-                        } else {
-                            // this is a bare expression
-                            try!(self.print_expr(&i_expr));
-                            try!(self.end()); // need to close a box
-                        }
-                    }
-                    _ => try!(self.print_block_unclosed(&body)),
-                }
+                try!(self.print_expr(body));
+                try!(self.end()); // need to close a box
 
                 // a box will be closed by print_expr, but we didn't want an overall
                 // wrapper so we closed the corresponding opening. so create an
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index 14244bbdddf..a1f07381db7 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -75,9 +75,9 @@ impl Visitor for NodeCounter {
         self.count += 1;
         walk_generics(self, g)
     }
-    fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) {
         self.count += 1;
-        walk_fn(self, fk, fd, b, s)
+        walk_fn(self, fk, fd, s)
     }
     fn visit_trait_item(&mut self, ti: &TraitItem) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 7fb3e5c6bee..7c1ff617ab6 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -31,13 +31,13 @@ use codemap::Spanned;
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
     /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility),
+    ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block),
 
     /// fn foo(&self)
-    Method(Ident, &'a MethodSig, Option<&'a Visibility>),
+    Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block),
 
-    /// |x, y| {}
-    Closure,
+    /// |x, y| body
+    Closure(&'a Expr),
 }
 
 /// Each method of the Visitor trait is a hook to be potentially
@@ -68,8 +68,8 @@ pub trait Visitor: Sized {
     fn visit_expr_post(&mut self, _ex: &Expr) { }
     fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) }
     fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) }
-    fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) {
-        walk_fn(self, fk, fd, b, s)
+    fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) {
+        walk_fn(self, fk, fd, s)
     }
     fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) }
     fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) }
@@ -246,9 +246,8 @@ pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
         }
         ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
             visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety,
-                                            constness, abi, &item.vis),
+                                            constness, abi, &item.vis, body),
                              declaration,
-                             body,
                              item.span,
                              item.id)
         }
@@ -519,26 +518,27 @@ pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, function_declaration: &FnDecl)
     visitor.visit_fn_ret_ty(&function_declaration.output)
 }
 
-pub fn walk_fn_kind<V: Visitor>(visitor: &mut V, function_kind: FnKind) {
-    match function_kind {
-        FnKind::ItemFn(_, generics, _, _, _, _) => {
+pub fn walk_fn<V>(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Span)
+    where V: Visitor,
+{
+    match kind {
+        FnKind::ItemFn(_, generics, _, _, _, _, body) => {
             visitor.visit_generics(generics);
+            walk_fn_decl(visitor, declaration);
+            visitor.visit_block(body);
         }
-        FnKind::Method(_, ref sig, _) => {
+        FnKind::Method(_, ref sig, _, body) => {
             visitor.visit_generics(&sig.generics);
+            walk_fn_decl(visitor, declaration);
+            visitor.visit_block(body);
+        }
+        FnKind::Closure(body) => {
+            walk_fn_decl(visitor, declaration);
+            visitor.visit_expr(body);
         }
-        FnKind::Closure => {}
     }
 }
 
-pub fn walk_fn<V>(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span)
-    where V: Visitor,
-{
-    walk_fn_kind(visitor, kind);
-    walk_fn_decl(visitor, declaration);
-    visitor.visit_block(body)
-}
-
 pub fn walk_trait_item<V: Visitor>(visitor: &mut V, trait_item: &TraitItem) {
     visitor.visit_ident(trait_item.span, trait_item.ident);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
@@ -552,8 +552,8 @@ pub fn walk_trait_item<V: Visitor>(visitor: &mut V, trait_item: &TraitItem) {
             walk_fn_decl(visitor, &sig.decl);
         }
         TraitItemKind::Method(ref sig, Some(ref body)) => {
-            visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl,
-                             body, trait_item.span, trait_item.id);
+            visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body),
+                             &sig.decl, trait_item.span, trait_item.id);
         }
         TraitItemKind::Type(ref bounds, ref default) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
@@ -575,8 +575,8 @@ pub fn walk_impl_item<V: Visitor>(visitor: &mut V, impl_item: &ImplItem) {
             visitor.visit_expr(expr);
         }
         ImplItemKind::Method(ref sig, ref body) => {
-            visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)), &sig.decl,
-                             body, impl_item.span, impl_item.id);
+            visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body),
+                             &sig.decl, impl_item.span, impl_item.id);
         }
         ImplItemKind::Type(ref ty) => {
             visitor.visit_ty(ty);
@@ -711,9 +711,8 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expression: &Expr) {
             walk_list!(visitor, visit_arm, arms);
         }
         ExprKind::Closure(_, ref function_declaration, ref body, _decl_span) => {
-            visitor.visit_fn(FnKind::Closure,
+            visitor.visit_fn(FnKind::Closure(body),
                              function_declaration,
-                             body,
                              expression.span,
                              expression.id)
         }
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index 10db56d46f6..dc1f7b4e620 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -133,7 +133,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
                                 cx.ident_of("read_struct"),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()),
                                      cx.expr_usize(trait_span, nfields),
-                                     cx.lambda_expr_1(trait_span, result, blkarg)])
+                                     cx.lambda1(trait_span, result, blkarg)])
         }
         StaticEnum(_, ref fields) => {
             let variant = cx.ident_of("i");
@@ -165,7 +165,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
             let result =
                 cx.expr_ok(trait_span,
                            cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms));
-            let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result);
+            let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
             let variant_vec = cx.expr_vec(trait_span, variants);
             let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
             let result = cx.expr_method_call(trait_span,
@@ -176,7 +176,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
                                 decoder,
                                 cx.ident_of("read_enum"),
                                 vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()),
-                                     cx.lambda_expr_1(trait_span, result, blkarg)])
+                                     cx.lambda1(trait_span, result, blkarg)])
         }
         _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
     };
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index 640296d7f06..ebbddc6e480 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -197,7 +197,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
                 };
                 let self_ref = cx.expr_addr_of(span, self_.clone());
                 let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
-                let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                let lambda = cx.lambda1(span, enc, blkarg);
                 let call = cx.expr_method_call(span,
                                                blkencoder.clone(),
                                                emit_struct_field,
@@ -246,7 +246,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
                     let self_ref = cx.expr_addr_of(span, self_.clone());
                     let enc =
                         cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
-                    let lambda = cx.lambda_expr_1(span, enc, blkarg);
+                    let lambda = cx.lambda1(span, enc, blkarg);
                     let call = cx.expr_method_call(span,
                                                    blkencoder.clone(),
                                                    emit_variant_arg,
@@ -273,7 +273,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
                                                 cx.expr_usize(trait_span, idx),
                                                 cx.expr_usize(trait_span, fields.len()),
                                                 blk]);
-            let blk = cx.lambda_expr_1(trait_span, call, blkarg);
+            let blk = cx.lambda1(trait_span, call, blkarg);
             let ret = cx.expr_method_call(trait_span,
                                           encoder,
                                           cx.ident_of("emit_enum"),
diff --git a/src/test/compile-fail/E0138.rs b/src/test/compile-fail/E0138.rs
index d4630d7c2ef..11d90658ab2 100644
--- a/src/test/compile-fail/E0138.rs
+++ b/src/test/compile-fail/E0138.rs
@@ -11,10 +11,10 @@
 #![feature(start)]
 
 #[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize {}
+fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
 //~^ NOTE previous `start` function here
 
 #[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {}
+fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
 //~^ ERROR E0138
 //~| NOTE multiple `start` functions
diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs
index 2e110cb3d0b..530a0e41562 100644
--- a/src/test/compile-fail/consider-removing-last-semi.rs
+++ b/src/test/compile-fail/consider-removing-last-semi.rs
@@ -8,12 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn f() -> String {  //~ ERROR E0269
+fn f() -> String {  //~ ERROR mismatched types
     0u8;
     "bla".to_string();  //~ HELP consider removing this semicolon
 }
 
-fn g() -> String {  //~ ERROR E0269
+fn g() -> String {  //~ ERROR mismatched types
     "this won't work".to_string();
     "removeme".to_string(); //~ HELP consider removing this semicolon
 }
diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs
index 6dc447b4dc8..3a27c084133 100644
--- a/src/test/compile-fail/diverging-fn-tail-35849.rs
+++ b/src/test/compile-fail/diverging-fn-tail-35849.rs
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn _converge() -> ! { //~ ERROR computation may converge
-    42
+fn _converge() -> ! {
+    42 //~ ERROR mismatched types
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs
index 998576097a0..192f78e41cb 100644
--- a/src/test/compile-fail/issue-11714.rs
+++ b/src/test/compile-fail/issue-11714.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn blah() -> i32 { //~ ERROR not all control paths return a value
+fn blah() -> i32 { //~ ERROR mismatched types
     1
 
     ; //~ HELP consider removing this semicolon:
diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs
index c771970650d..9406199afc2 100644
--- a/src/test/compile-fail/issue-13428.rs
+++ b/src/test/compile-fail/issue-13428.rs
@@ -10,7 +10,7 @@
 
 // Regression test for #13428
 
-fn foo() -> String {  //~ ERROR not all control paths return a value
+fn foo() -> String {  //~ ERROR mismatched types
     format!("Hello {}",
             "world")
     // Put the trailing semicolon on its own line to test that the
@@ -18,7 +18,7 @@ fn foo() -> String {  //~ ERROR not all control paths return a value
     ;   //~ HELP consider removing this semicolon
 }
 
-fn bar() -> String {  //~ ERROR not all control paths return a value
+fn bar() -> String {  //~ ERROR mismatched types
     "foobar".to_string()
     ;   //~ HELP consider removing this semicolon
 }
diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs
index 402b9a04496..81f66e3e2cf 100644
--- a/src/test/compile-fail/issue-22645.rs
+++ b/src/test/compile-fail/issue-22645.rs
@@ -17,7 +17,7 @@ struct Bob;
 
 impl<RHS: Scalar> Add <RHS> for Bob {
   type Output = Bob;
-  fn add(self, rhs : RHS) -> Bob {}
+  fn add(self, rhs : RHS) -> Bob { Bob }
 }
 
 fn main() {
diff --git a/src/test/compile-fail/issue-22684.rs b/src/test/compile-fail/issue-22684.rs
index b7ffbefba6a..a791758ad17 100644
--- a/src/test/compile-fail/issue-22684.rs
+++ b/src/test/compile-fail/issue-22684.rs
@@ -15,7 +15,7 @@ mod foo {
     }
 
     pub trait Baz {
-        fn bar(&self) -> bool {}
+        fn bar(&self) -> bool { true }
     }
     impl Baz for Foo {}
 }
diff --git a/src/test/compile-fail/issue-29161.rs b/src/test/compile-fail/issue-29161.rs
index bc09f61a754..97ba222fe45 100644
--- a/src/test/compile-fail/issue-29161.rs
+++ b/src/test/compile-fail/issue-29161.rs
@@ -13,7 +13,7 @@ mod a {
 
     impl Default for A {
         pub fn default() -> A { //~ ERROR unnecessary visibility qualifier
-            A;
+            A
         }
     }
 }
diff --git a/src/test/compile-fail/issue-32323.rs b/src/test/compile-fail/issue-32323.rs
index e3461e52e1c..e5cb8130327 100644
--- a/src/test/compile-fail/issue-32323.rs
+++ b/src/test/compile-fail/issue-32323.rs
@@ -13,6 +13,6 @@ pub trait Tr<'a> {
 }
 
 pub fn f<'a, T: Tr<'a>>() -> <T as Tr<'a>>::Out {}
-//~^ ERROR not all control paths return a value
+//~^ ERROR mismatched types
 
 pub fn main() {}
diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs
index 06e3c9a207b..a77b27150d7 100644
--- a/src/test/compile-fail/issue-5239-1.rs
+++ b/src/test/compile-fail/issue-5239-1.rs
@@ -11,7 +11,7 @@
 // Regression test for issue #5239
 
 fn main() {
-    let x = |ref x: isize| -> isize { x += 1; };
+    let x = |ref x: isize| { x += 1; };
     //~^ ERROR E0368
     //~| NOTE cannot use `+=` on type `&isize`
 }
diff --git a/src/test/compile-fail/issue-6458-4.rs b/src/test/compile-fail/issue-6458-4.rs
index c3f3a718ad0..a078cdea4ac 100644
--- a/src/test/compile-fail/issue-6458-4.rs
+++ b/src/test/compile-fail/issue-6458-4.rs
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn foo(b: bool) -> Result<bool,String> {
-    Err("bar".to_string());
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
-    //~| NOTE cannot infer type for `_`
-    //~| NOTE type annotations or generic parameter binding
+fn foo(b: bool) -> Result<bool,String> { //~ ERROR mismatched types
+    Err("bar".to_string()); //~ HELP consider removing this semicolon
 }
 
 fn main() {
diff --git a/src/test/compile-fail/liveness-forgot-ret.rs b/src/test/compile-fail/liveness-forgot-ret.rs
index e08515e40af..1ee4be08a1c 100644
--- a/src/test/compile-fail/liveness-forgot-ret.rs
+++ b/src/test/compile-fail/liveness-forgot-ret.rs
@@ -8,10 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: not all control paths return a value
-
 fn god_exists(a: isize) -> bool { return god_exists(a); }
 
 fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
+//~^ ERROR mismatched types
 
 fn main() { f(12); }
diff --git a/src/test/compile-fail/liveness-issue-2163.rs b/src/test/compile-fail/liveness-issue-2163.rs
index 7c94e33b47b..69bceec8c32 100644
--- a/src/test/compile-fail/liveness-issue-2163.rs
+++ b/src/test/compile-fail/liveness-issue-2163.rs
@@ -13,6 +13,6 @@ use std::vec::Vec;
 fn main() {
     let a: Vec<isize> = Vec::new();
     a.iter().all(|_| -> bool {
-        //~^ ERROR not all control paths return a value
+        //~^ ERROR mismatched types
     });
 }
diff --git a/src/test/compile-fail/liveness-missing-ret2.rs b/src/test/compile-fail/liveness-missing-ret2.rs
index b53bb6159e8..a35eb1af4f3 100644
--- a/src/test/compile-fail/liveness-missing-ret2.rs
+++ b/src/test/compile-fail/liveness-missing-ret2.rs
@@ -8,9 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: not all control paths return a value
-
-fn f() -> isize {
+fn f() -> isize { //~ ERROR mismatched types
     // Make sure typestate doesn't interpret this match expression as
     // the function result
    match true { true => { } _ => {} };
diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs
index 03733cc2eb5..ada91c38d48 100644
--- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs
+++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs
@@ -11,16 +11,16 @@
 // regression test for #8005
 
 macro_rules! test { () => { fn foo() -> i32 { 1; } } }
-                                           //~^ ERROR not all control paths return a value
+                                           //~^ ERROR mismatched types
                                            //~| HELP consider removing this semicolon
 
-fn no_return() -> i32 {} //~ ERROR  not all control paths return a value
+fn no_return() -> i32 {} //~ ERROR mismatched types
 
-fn bar(x: u32) -> u32 { //~ ERROR  not all control paths return a value
+fn bar(x: u32) -> u32 { //~ ERROR mismatched types
     x * 2; //~ HELP consider removing this semicolon
 }
 
-fn baz(x: u64) -> u32 { //~ ERROR  not all control paths return a value
+fn baz(x: u64) -> u32 { //~ ERROR mismatched types
     x * 2;
 }
 
diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs
index 7434a6c960b..2878cbc7fc1 100644
--- a/src/test/compile-fail/main-wrong-type-2.rs
+++ b/src/test/compile-fail/main-wrong-type-2.rs
@@ -10,4 +10,5 @@
 
 fn main() -> char {
 //~^ ERROR: main function has wrong type
+    ' '
 }
diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs
index 3a789f3faeb..0f4b0919b65 100644
--- a/src/test/compile-fail/on-unimplemented/on-trait.rs
+++ b/src/test/compile-fail/on-unimplemented/on-trait.rs
@@ -16,7 +16,7 @@ trait Foo<Bar, Baz, Quux>
 {}
 
 fn foobar<U: Clone, T: Foo<u8, U, u32>>() -> T {
-
+    panic!()
 }
 
 #[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"]
diff --git a/src/test/compile-fail/private-in-public-lint.rs b/src/test/compile-fail/private-in-public-lint.rs
index 8e23bfcfb10..4796548112d 100644
--- a/src/test/compile-fail/private-in-public-lint.rs
+++ b/src/test/compile-fail/private-in-public-lint.rs
@@ -13,7 +13,7 @@ mod m1 {
     struct Priv;
 
     impl Pub {
-        pub fn f() -> Priv {} //~ ERROR private type in public interface
+        pub fn f() -> Priv {Priv} //~ ERROR private type in public interface
     }
 }
 
@@ -24,7 +24,7 @@ mod m2 {
     struct Priv;
 
     impl Pub {
-        pub fn f() -> Priv {} //~ ERROR private type in public interface
+        pub fn f() -> Priv {Priv} //~ ERROR private type in public interface
     }
 }
 
diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs
index 1aa22a1676e..ce40702b3dc 100644
--- a/src/test/compile-fail/required-lang-item.rs
+++ b/src/test/compile-fail/required-lang-item.rs
@@ -11,6 +11,7 @@
 #![feature(lang_items, no_core)]
 #![no_core]
 
+#[lang="copy"] pub trait Copy { }
 #[lang="sized"] pub trait Sized { }
 
 // error-pattern:requires `start` lang_item
diff --git a/src/test/compile-fail/unreachable-in-call.rs b/src/test/compile-fail/unreachable-in-call.rs
index 5a3257d54db..72462468432 100644
--- a/src/test/compile-fail/unreachable-in-call.rs
+++ b/src/test/compile-fail/unreachable-in-call.rs
@@ -24,7 +24,7 @@ fn diverge_first() {
          get_u8()); //~ ERROR unreachable expression
 }
 fn diverge_second() {
-    call( //~ ERROR unreachable call
+    call( //~ ERROR unreachable expression
         get_u8(),
         diverge());
 }
diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs
index 278a8db4e1a..ffc39008c4e 100644
--- a/src/test/compile-fail/where-clauses-unsatisfied.rs
+++ b/src/test/compile-fail/where-clauses-unsatisfied.rs
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn equal<T>(_: &T, _: &T) -> bool where T : Eq {
-}
+fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b }
 
 struct Struct;
 
diff --git a/src/test/parse-fail/closure-return-syntax.rs b/src/test/parse-fail/closure-return-syntax.rs
index da6245597f8..1da67359180 100644
--- a/src/test/parse-fail/closure-return-syntax.rs
+++ b/src/test/parse-fail/closure-return-syntax.rs
@@ -12,5 +12,6 @@
 // unless it uses braces.
 
 fn main() {
-    let x = || -> i32 22; //~ ERROR expected `{`, found `22`
+    let x = || -> i32 22;
+    //~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22`
 }
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 40ff4852e38..24b0f90d08e 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -18,18 +18,18 @@ extern crate std as std;
 
 // #4264 fixed-length vector types
 
-pub fn foo(_: [i32; (3 as usize)]) { }
+pub fn foo(_: [i32; (3 as usize)]) ({ } as ())
 
-pub fn bar() {
-    const FOO: usize = ((5 as usize) - (4 as usize) as usize);
-    let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
+pub fn bar() ({
+                  const FOO: usize = ((5 as usize) - (4 as usize) as usize);
+                  let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
 
-    let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
+                  let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
 
-    let _ =
-        (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3])
-             as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as
-            *const [i32; 3]);
+                  let _ =
+                      (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3])
+                            as &[i32; 3]) as *const _ as *const [i32; 3]) as
+                          *const [i32; (3 as usize)] as *const [i32; 3]);
 
 
 
@@ -38,58 +38,66 @@ pub fn bar() {
 
 
 
-    (($crate::fmt::format as
-         fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1
-                                                                                     as
-                                                                                     fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({
-                                                                                                                                                                                                 static __STATIC_FMTSTR:
-                                                                                                                                                                                                        &'static [&'static str]
-                                                                                                                                                                                                        =
-                                                                                                                                                                                                     (&([("test"
-                                                                                                                                                                                                             as
-                                                                                                                                                                                                             &'static str)]
-                                                                                                                                                                                                           as
-                                                                                                                                                                                                           [&'static str; 1])
-                                                                                                                                                                                                         as
-                                                                                                                                                                                                         &'static [&'static str; 1]);
-                                                                                                                                                                                                 (__STATIC_FMTSTR
-                                                                                                                                                                                                     as
-                                                                                                                                                                                                     &'static [&'static str])
-                                                                                                                                                                                             }
-                                                                                                                                                                                                as
-                                                                                                                                                                                                &[&str]),
-                                                                                                                                                                                            (&(match (()
-                                                                                                                                                                                                         as
-                                                                                                                                                                                                         ())
-                                                                                                                                                                                                   {
-                                                                                                                                                                                                   ()
-                                                                                                                                                                                                   =>
-                                                                                                                                                                                                   ([]
-                                                                                                                                                                                                       as
-                                                                                                                                                                                                       [std::fmt::ArgumentV1<'_>; 0]),
-                                                                                                                                                                                               }
-                                                                                                                                                                                                  as
-                                                                                                                                                                                                  [std::fmt::ArgumentV1<'_>; 0])
-                                                                                                                                                                                                as
-                                                                                                                                                                                                &[std::fmt::ArgumentV1<'_>; 0]))
-                                                                                    as
-                                                                                    std::fmt::Arguments<'_>))
-        as std::string::String);
-}
+
+                  (($crate::fmt::format as
+                       fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1
+                                                                                                   as
+                                                                                                   fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({
+                                                                                                                                                                                                               static __STATIC_FMTSTR:
+                                                                                                                                                                                                                      &'static [&'static str]
+                                                                                                                                                                                                                      =
+                                                                                                                                                                                                                   (&([("test"
+                                                                                                                                                                                                                           as
+                                                                                                                                                                                                                           &'static str)]
+                                                                                                                                                                                                                         as
+                                                                                                                                                                                                                         [&'static str; 1])
+                                                                                                                                                                                                                       as
+                                                                                                                                                                                                                       &'static [&'static str; 1]);
+                                                                                                                                                                                                               (__STATIC_FMTSTR
+                                                                                                                                                                                                                   as
+                                                                                                                                                                                                                   &'static [&'static str])
+                                                                                                                                                                                                           }
+                                                                                                                                                                                                              as
+                                                                                                                                                                                                              &[&str]),
+                                                                                                                                                                                                          (&(match (()
+                                                                                                                                                                                                                       as
+                                                                                                                                                                                                                       ())
+                                                                                                                                                                                                                 {
+                                                                                                                                                                                                                 ()
+                                                                                                                                                                                                                 =>
+                                                                                                                                                                                                                 ([]
+                                                                                                                                                                                                                     as
+                                                                                                                                                                                                                     [std::fmt::ArgumentV1<'_>; 0]),
+                                                                                                                                                                                                             }
+                                                                                                                                                                                                                as
+                                                                                                                                                                                                                [std::fmt::ArgumentV1<'_>; 0])
+                                                                                                                                                                                                              as
+                                                                                                                                                                                                              &[std::fmt::ArgumentV1<'_>; 0]))
+                                                                                                  as
+                                                                                                  std::fmt::Arguments<'_>))
+                      as std::string::String);
+              } as ())
 pub type Foo = [i32; (3 as usize)];
 pub struct Bar {
     pub x: [i32; (3 as usize)],
 }
 pub struct TupleBar([i32; (4 as usize)]);
 pub enum Baz { BazVariant([i32; (5 as usize)]), }
-pub fn id<T>(x: T) -> T { (x as T) }
-pub fn use_id() {
-    let _ =
-        ((id::<[i32; (3 as usize)]> as
-             fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
-                                                          (2 as i32),
-                                                          (3 as i32)] as
-                                                            [i32; 3])) as
-            [i32; 3]);
-}
-fn main() { }
+pub fn id<T>(x: T) -> T ({ (x as T) } as T)
+pub fn use_id() ({
+                     let _ =
+                         ((id::<[i32; (3 as usize)]> as
+                              fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1
+                                                                               as
+                                                                               i32),
+                                                                           (2
+                                                                               as
+                                                                               i32),
+                                                                           (3
+                                                                               as
+                                                                               i32)]
+                                                                             as
+                                                                             [i32; 3]))
+                             as [i32; 3]);
+                 } as ())
+fn main() ({ } as ())
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index e52932cd7be..1c443020d2e 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -198,14 +198,20 @@ fn _11() {
                 };
     let _ = #[attr] || #[attr] ();
     let _ = #[attr] move || #[attr] ();
-    let _ = #[attr] || {
-        #![attr]
-        #[attr]
-        () };
-    let _ = #[attr] move || {
-        #![attr]
-        #[attr]
-        () };
+    let _ =
+        #[attr] ||
+                    {
+                        #![attr]
+                        #[attr]
+                        ()
+                    };
+    let _ =
+        #[attr] move ||
+                    {
+                        #![attr]
+                        #[attr]
+                        ()
+                    };
     let _ =
         #[attr] {
                     #![attr]
diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot
index f699771ef24..8ea8370ab23 100644
--- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot
@@ -2,6 +2,8 @@ digraph block {
     N0[label="entry"];
     N1[label="exit"];
     N2[label="block { }"];
+    N3[label="expr { }"];
     N0 -> N2;
-    N2 -> N1;
+    N2 -> N3;
+    N3 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
index d924890b311..5982fbea769 100644
--- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
@@ -4,8 +4,10 @@ digraph block {
     N2[label="expr 1"];
     N3[label="stmt 1;"];
     N4[label="block { 1; }"];
+    N5[label="expr { 1; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
-    N4 -> N1;
+    N4 -> N5;
+    N5 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
index 1f4a58ba0a3..1639785bd68 100644
--- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
@@ -4,8 +4,10 @@ digraph block {
     N2[label="local _x"];
     N3[label="stmt let _x: isize;"];
     N4[label="block { let _x: isize; }"];
+    N5[label="expr { let _x: isize; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
-    N4 -> N1;
+    N4 -> N5;
+    N5 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
index 8b650076185..b0ae00d8167 100644
--- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
@@ -6,10 +6,12 @@ digraph block {
     N4[label="expr 3 + 4"];
     N5[label="stmt 3 + 4;"];
     N6[label="block { 3 + 4; }"];
+    N7[label="expr { 3 + 4; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
-    N6 -> N1;
+    N6 -> N7;
+    N7 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
index fde6cc29005..41ace15a4c6 100644
--- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
@@ -5,9 +5,11 @@ digraph block {
     N3[label="local _x"];
     N4[label="stmt let _x = 4;"];
     N5[label="block { let _x = 4; }"];
+    N6[label="expr { let _x = 4; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
-    N5 -> N1;
+    N5 -> N6;
+    N6 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
index efd56cd0c75..72b8ae71751 100644
--- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
@@ -9,6 +9,7 @@ digraph block {
     N7[label="pat (_x, _y)"];
     N8[label="stmt let (_x, _y) = (5, 55);"];
     N9[label="block { let (_x, _y) = (5, 55); }"];
+    N10[label="expr { let (_x, _y) = (5, 55); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -17,5 +18,6 @@ digraph block {
     N6 -> N7;
     N7 -> N8;
     N8 -> N9;
-    N9 -> N1;
+    N9 -> N10;
+    N10 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
index 54e9d89d3fb..acba71ef625 100644
--- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
@@ -7,11 +7,13 @@ digraph block {
     N5[label="pat S6 { val: _x }"];
     N6[label="stmt let S6 { val: _x } = S6{val: 6,};"];
     N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"];
+    N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
     N5 -> N6;
     N6 -> N7;
-    N7 -> N1;
+    N7 -> N8;
+    N8 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
index c60cd1cfd27..251e2b39f14 100644
--- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
@@ -17,6 +17,7 @@ digraph block {
     N15[label="expr x + y"];
     N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"];
     N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"];
+    N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -33,5 +34,6 @@ digraph block {
     N15 -> N7;
     N7 -> N16;
     N16 -> N17;
-    N17 -> N1;
+    N17 -> N18;
+    N18 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
index da0120b7bdc..e2779c9414a 100644
--- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
@@ -16,6 +16,7 @@ digraph block {
     N14[label="block { _y = 888; }"];
     N15[label="expr if x > 88 { _y = 888; }"];
     N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"];
+    N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -32,5 +33,6 @@ digraph block {
     N9 -> N15;
     N14 -> N15;
     N15 -> N16;
-    N16 -> N1;
+    N16 -> N17;
+    N17 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
index c98d1b0bed5..536abde91e8 100644
--- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
@@ -24,6 +24,7 @@ digraph block {
     N22[label="expr { _y = 94 + 95; }"];
     N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"];
     N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"];
+    N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -48,5 +49,6 @@ digraph block {
     N14 -> N23;
     N22 -> N23;
     N23 -> N24;
-    N24 -> N1;
+    N24 -> N25;
+    N25 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
index 516c39ef560..a3b531b1e2f 100644
--- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
@@ -15,6 +15,7 @@ digraph block {
     N13[label="stmt x -= 1;"];
     N14[label="block { x -= 1; }"];
     N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"];
+    N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -30,5 +31,6 @@ digraph block {
     N13 -> N14;
     N14 -> N5;
     N9 -> N15;
-    N15 -> N1;
+    N15 -> N16;
+    N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
index 9b66fd581cb..70034d299ba 100644
--- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
@@ -15,6 +15,7 @@ digraph block {
     N13[label="expr \"unreachable\""];
     N14[label="stmt \"unreachable\";"];
     N15[label="block { let mut _x = 11; loop  { _x -= 1; } \"unreachable\"; }"];
+    N16[label="expr { let mut _x = 11; loop  { _x -= 1; } \"unreachable\"; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -29,5 +30,6 @@ digraph block {
     N12 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N1;
+    N15 -> N16;
+    N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
index 071af6faf6f..245afc43504 100644
--- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
@@ -22,6 +22,7 @@ digraph block {
     N20[label="expr if x == 2 { break ; \"unreachable\"; }"];
     N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
     N22[label="block { let mut x = 12; loop  { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"];
+    N23[label="expr { let mut x = 12; loop  { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -44,5 +45,6 @@ digraph block {
     N20 -> N21;
     N21 -> N5;
     N6 -> N22;
-    N22 -> N1;
+    N22 -> N23;
+    N23 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
index fb7d2ad97bd..0f268bd0f2a 100644
--- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
@@ -24,6 +24,7 @@ digraph block {
     N22[label="expr _y"];
     N23[label="expr _y = v + 1"];
     N24[label="block {\l    let x = E13::E13b(13);\l    let _y;\l    match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"];
+    N25[label="expr {\l    let x = E13::E13b(13);\l    let _y;\l    match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -48,5 +49,6 @@ digraph block {
     N22 -> N23;
     N23 -> N10;
     N10 -> N24;
-    N24 -> N1;
+    N24 -> N25;
+    N25 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
index 66250aa441e..719a6cf2619 100644
--- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
@@ -15,6 +15,7 @@ digraph block {
     N13[label="block { return; \"unreachable\"; }"];
     N14[label="expr if x > 1 { return; \"unreachable\"; }"];
     N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"];
+    N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -30,5 +31,6 @@ digraph block {
     N7 -> N14;
     N13 -> N14;
     N14 -> N15;
-    N15 -> N1;
+    N15 -> N16;
+    N16 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
index 4c94630f4e1..d8cbd8411e2 100644
--- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
@@ -49,6 +49,7 @@ digraph block {
     N47[label="stmt x -= 5;"];
     N48[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\"; }\l            if y >= 2 { break ; \"unreachable\"; }\l            y -= 3;\l        }\l    y -= 4;\l    x -= 5;\l}\l"];
     N49[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\"; }\l                    if y >= 2 { break ; \"unreachable\"; }\l                    y -= 3;\l                }\l            y -= 4;\l            x -= 5;\l        }\l}\l"];
+    N50[label="expr {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\"; }\l                    if y >= 2 { break ; \"unreachable\"; }\l                    y -= 3;\l                }\l            y -= 4;\l            x -= 5;\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -99,5 +100,6 @@ digraph block {
     N47 -> N48;
     N48 -> N8;
     N9 -> N49;
-    N49 -> N1;
+    N49 -> N50;
+    N50 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
index d7d027cefb5..b11881247fb 100644
--- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
@@ -52,6 +52,7 @@ digraph block {
     N50[label="expr \"unreachable\""];
     N51[label="stmt \"unreachable\";"];
     N52[label="block {\l    let mut x = 16;\l    let mut y = 16;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\"; }\l                    if y >= 1 { break ; \"unreachable\"; }\l                    y -= 1;\l                }\l            y -= 1;\l            x -= 1;\l        }\l    \"unreachable\";\l}\l"];
+    N53[label="expr {\l    let mut x = 16;\l    let mut y = 16;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\"; }\l                    if y >= 1 { break ; \"unreachable\"; }\l                    y -= 1;\l                }\l            y -= 1;\l            x -= 1;\l        }\l    \"unreachable\";\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -105,5 +106,6 @@ digraph block {
     N49 -> N50;
     N50 -> N51;
     N51 -> N52;
-    N52 -> N1;
+    N52 -> N53;
+    N53 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
index f87b70a71ca..705eece7755 100644
--- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
@@ -8,6 +8,7 @@ digraph block {
     N6[label="local _v"];
     N7[label="stmt let _v = [1, 7, 17];"];
     N8[label="block { let _v = [1, 7, 17]; }"];
+    N9[label="expr { let _v = [1, 7, 17]; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -15,5 +16,6 @@ digraph block {
     N5 -> N6;
     N6 -> N7;
     N7 -> N8;
-    N8 -> N1;
+    N8 -> N9;
+    N9 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
index 8ea42561332..c1d6e3023fb 100644
--- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
@@ -9,6 +9,7 @@ digraph block {
     N7[label="expr inner(inner(18))"];
     N8[label="stmt inner(inner(18));"];
     N9[label="block { inner(inner(18)); }"];
+    N10[label="expr { inner(inner(18)); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -17,5 +18,6 @@ digraph block {
     N6 -> N7;
     N7 -> N8;
     N8 -> N9;
-    N9 -> N1;
+    N9 -> N10;
+    N10 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
index bc0ca08d422..d2f9f41f647 100644
--- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
@@ -12,6 +12,7 @@ digraph block {
     N10[label="expr s.inner().inner()"];
     N11[label="stmt s.inner().inner();"];
     N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"];
+    N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -23,5 +24,6 @@ digraph block {
     N9 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N1;
+    N12 -> N13;
+    N13 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
index 21e84fb858b..120eab4dac9 100644
--- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
@@ -12,6 +12,7 @@ digraph block {
     N10[label="expr v[20]"];
     N11[label="stmt v[20];"];
     N12[label="block { let v = [2, 0, 20]; v[20]; }"];
+    N13[label="expr { let v = [2, 0, 20]; v[20]; }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -23,5 +24,6 @@ digraph block {
     N9 -> N10;
     N10 -> N11;
     N11 -> N12;
-    N12 -> N1;
+    N12 -> N13;
+    N13 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
index 796bf4910c9..370dcdd8554 100644
--- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
@@ -47,6 +47,7 @@ digraph block {
     N45[label="stmt \"unreachable\";"];
     N46[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\"; }\l            if y >= 2 { return; \"unreachable\"; }\l            y -= 3;\l            x -= 5;\l        }\l    \"unreachable\";\l}\l"];
     N47[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    y -= 3;\l                    x -= 5;\l                }\l            \"unreachable\";\l        }\l}\l"];
+    N48[label="expr {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    y -= 3;\l                    x -= 5;\l                }\l            \"unreachable\";\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -95,5 +96,6 @@ digraph block {
     N45 -> N46;
     N46 -> N8;
     N9 -> N47;
-    N47 -> N1;
+    N47 -> N48;
+    N48 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
index 9e8049f0741..9d3bc22831a 100644
--- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
@@ -50,6 +50,7 @@ digraph block {
     N48[label="expr \"unreachable\""];
     N49[label="stmt \"unreachable\";"];
     N50[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    x -= 1;\l                    y -= 3;\l                }\l            \"unreachable\";\l        }\l    \"unreachable\";\l}\l"];
+    N51[label="expr {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    x -= 1;\l                    y -= 3;\l                }\l            \"unreachable\";\l        }\l    \"unreachable\";\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -101,5 +102,6 @@ digraph block {
     N47 -> N48;
     N48 -> N49;
     N49 -> N50;
-    N50 -> N1;
+    N50 -> N51;
+    N51 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
index b3f285049c5..f152977438c 100644
--- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
@@ -52,6 +52,7 @@ digraph block {
     N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"];
     N51[label="block {\l    x -= 1;\l    while y > 0 {\l        y -= 1;\l        while z > 0 { z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
     N52[label="block {\l    let mut x = 23;\l    let mut y = 23;\l    let mut z = 23;\l    while x > 0 {\l        x -= 1;\l        while y > 0 {\l            y -= 1;\l            while z > 0 { z -= 1; }\l            if x > 10 { return; \"unreachable\"; }\l        }\l    }\l}\l"];
+    N53[label="expr {\l    let mut x = 23;\l    let mut y = 23;\l    let mut z = 23;\l    while x > 0 {\l        x -= 1;\l        while y > 0 {\l            y -= 1;\l            while z > 0 { z -= 1; }\l            if x > 10 { return; \"unreachable\"; }\l        }\l    }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -107,5 +108,6 @@ digraph block {
     N24 -> N51;
     N51 -> N11;
     N15 -> N52;
-    N52 -> N1;
+    N52 -> N53;
+    N53 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
index 43b3295bf3b..e40dd014f0a 100644
--- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
@@ -76,6 +76,7 @@ digraph block {
     N74[label="block {\l    if y == 0 { break ; \"unreachable\"; }\l    y -= 1;\l    loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l    if x > 10 { return; \"unreachable\"; }\l}\l"];
     N75[label="block {\l    if x == 0 { break ; \"unreachable\"; }\l    x -= 1;\l    loop  {\l        if y == 0 { break ; \"unreachable\"; }\l        y -= 1;\l        loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
     N76[label="block {\l    let mut x = 24;\l    let mut y = 24;\l    let mut z = 24;\l    loop  {\l        if x == 0 { break ; \"unreachable\"; }\l        x -= 1;\l        loop  {\l            if y == 0 { break ; \"unreachable\"; }\l            y -= 1;\l            loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l            if x > 10 { return; \"unreachable\"; }\l        }\l    }\l}\l"];
+    N77[label="expr {\l    let mut x = 24;\l    let mut y = 24;\l    let mut z = 24;\l    loop  {\l        if x == 0 { break ; \"unreachable\"; }\l        x -= 1;\l        loop  {\l            if y == 0 { break ; \"unreachable\"; }\l            y -= 1;\l            loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l            if x > 10 { return; \"unreachable\"; }\l        }\l    }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -155,5 +156,6 @@ digraph block {
     N29 -> N75;
     N75 -> N11;
     N12 -> N76;
-    N76 -> N1;
+    N76 -> N77;
+    N77 -> N1;
 }
diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
index 50fdffb781d..1e2df1ab5e7 100644
--- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
@@ -76,6 +76,7 @@ digraph block {
     N74[label="block {\l    if y == 0 { break ; \"unreachable\"; }\l    y -= 1;\l    \'a: loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l    if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"];
     N75[label="block {\l    if x == 0 { break ; \"unreachable\"; }\l    x -= 1;\l    \'a:\l        loop  {\l            if y == 0 { break ; \"unreachable\"; }\l            y -= 1;\l            \'a: loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l            if x > 10 { continue \'a ; \"unreachable\"; }\l        }\l}\l"];
     N76[label="block {\l    let mut x = 25;\l    let mut y = 25;\l    let mut z = 25;\l    \'a:\l        loop  {\l            if x == 0 { break ; \"unreachable\"; }\l            x -= 1;\l            \'a:\l                loop  {\l                    if y == 0 { break ; \"unreachable\"; }\l                    y -= 1;\l                    \'a: loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l                    if x > 10 { continue \'a ; \"unreachable\"; }\l                }\l        }\l}\l"];
+    N77[label="expr {\l    let mut x = 25;\l    let mut y = 25;\l    let mut z = 25;\l    \'a:\l        loop  {\l            if x == 0 { break ; \"unreachable\"; }\l            x -= 1;\l            \'a:\l                loop  {\l                    if y == 0 { break ; \"unreachable\"; }\l                    y -= 1;\l                    \'a: loop  { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l                    if x > 10 { continue \'a ; \"unreachable\"; }\l                }\l        }\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
@@ -155,5 +156,6 @@ digraph block {
     N29 -> N75;
     N75 -> N11;
     N12 -> N76;
-    N76 -> N1;
+    N76 -> N77;
+    N77 -> N1;
 }