about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/dep_graph/visit.rs28
-rw-r--r--src/librustc/hir/def.rs2
-rw-r--r--src/librustc/hir/intravisit.rs124
-rw-r--r--src/librustc/hir/itemlikevisit.rs84
-rw-r--r--src/librustc/hir/lowering.rs51
-rw-r--r--src/librustc/hir/map/collector.rs9
-rw-r--r--src/librustc/hir/map/mod.rs15
-rw-r--r--src/librustc/hir/mod.rs62
-rw-r--r--src/librustc/hir/print.rs17
-rw-r--r--src/librustc/lint/context.rs61
-rw-r--r--src/librustc/middle/dead.rs46
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/entry.rs12
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/lang_items.rs10
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/reachable.rs15
-rw-r--r--src/librustc/middle/region.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs70
-rw-r--r--src/librustc/middle/stability.rs47
-rw-r--r--src/librustc/middle/weak_lang_items.rs2
-rw-r--r--src/librustc/traits/project.rs9
-rw-r--r--src/librustc/ty/mod.rs180
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs3
-rw-r--r--src/librustc_driver/derive_registrar.rs10
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs10
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs11
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs18
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs16
-rw-r--r--src/librustc_incremental/persist/fs.rs13
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_metadata/encoder.rs28
-rw-r--r--src/librustc_metadata/schema.rs19
-rw-r--r--src/librustc_mir/mir_map.rs4
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs8
-rw-r--r--src/librustc_passes/consts.rs14
-rw-r--r--src/librustc_passes/hir_stats.rs8
-rw-r--r--src/librustc_passes/loops.rs8
-rw-r--r--src/librustc_passes/rvalues.rs6
-rw-r--r--src/librustc_passes/static_recursion.rs3
-rw-r--r--src/librustc_plugin/build.rs9
-rw-r--r--src/librustc_privacy/lib.rs138
-rw-r--r--src/librustc_save_analysis/lib.rs2
-rw-r--r--src/librustc_trans/callee.rs9
-rw-r--r--src/librustc_trans/collector.rs25
-rw-r--r--src/librustc_trans/symbol_names_test.rs3
-rw-r--r--src/librustc_typeck/Cargo.toml1
-rw-r--r--src/librustc_typeck/check/method/suggest.rs9
-rw-r--r--src/librustc_typeck/check/mod.rs33
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/check_unused.rs9
-rw-r--r--src/librustc_typeck/coherence/mod.rs12
-rw-r--r--src/librustc_typeck/coherence/orphan.rs10
-rw-r--r--src/librustc_typeck/coherence/overlap.rs9
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs11
-rw-r--r--src/librustc_typeck/collect.rs240
-rw-r--r--src/librustc_typeck/constrained_type_params.rs12
-rw-r--r--src/librustc_typeck/impl_wf_check.rs203
-rw-r--r--src/librustc_typeck/lib.rs7
-rw-r--r--src/librustc_typeck/variance/constraints.rs11
-rw-r--r--src/librustc_typeck/variance/terms.rs9
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/visit_ast.rs7
-rw-r--r--src/test/compile-fail/dep-graph-type-alias.rs3
-rw-r--r--src/test/compile-fail/issue-3214.rs1
-rw-r--r--src/test/incremental/change_private_impl_method/struct_point.rs11
-rw-r--r--src/test/incremental/change_private_impl_method_cc/struct_point.rs24
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs128
-rw-r--r--src/test/incremental/hashes/trait_impls.rs404
73 files changed, 1765 insertions, 630 deletions
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 9c00e95c17e..e365cea6d0e 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -25,5 +25,5 @@ pub use self::dep_node::WorkProductId;
 pub use self::graph::DepGraph;
 pub use self::graph::WorkProduct;
 pub use self::query::DepGraphQuery;
-pub use self::visit::visit_all_items_in_krate;
+pub use self::visit::visit_all_item_likes_in_krate;
 pub use self::raii::DepTask;
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index d085c24036c..600732fc6f7 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -10,22 +10,21 @@
 
 use hir;
 use hir::def_id::DefId;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use ty::TyCtxt;
 
 use super::dep_node::DepNode;
 
-
 /// Visit all the items in the krate in some order. When visiting a
 /// particular item, first create a dep-node by calling `dep_node_fn`
 /// and push that onto the dep-graph stack of tasks, and also create a
 /// read edge from the corresponding AST node. This is used in
 /// compiler passes to automatically record the item that they are
 /// working on.
-pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                mut dep_node_fn: F,
-                                                visitor: &mut V)
-    where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                                     mut dep_node_fn: F,
+                                                     visitor: &mut V)
+    where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
 {
     struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
         tcx: TyCtxt<'visit, 'tcx, 'tcx>,
@@ -33,8 +32,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         visitor: &'visit mut V
     }
 
-    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
-        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+    impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
     {
         fn visit_item(&mut self, i: &'tcx hir::Item) {
             let item_def_id = self.tcx.map.local_def_id(i.id);
@@ -46,6 +45,17 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             self.visitor.visit_item(i);
             debug!("Ended task {:?}", task_id);
         }
+
+        fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
+            let impl_item_def_id = self.tcx.map.local_def_id(i.id);
+            let task_id = (self.dep_node_fn)(impl_item_def_id);
+            let _task = self.tcx.dep_graph.in_task(task_id.clone());
+            debug!("Started task {:?}", task_id);
+            assert!(!self.tcx.map.is_inlined_def_id(impl_item_def_id));
+            self.tcx.dep_graph.read(DepNode::Hir(impl_item_def_id));
+            self.visitor.visit_impl_item(i);
+            debug!("Ended task {:?}", task_id);
+        }
     }
 
     let krate = tcx.dep_graph.with_ignore(|| tcx.map.krate());
@@ -54,5 +64,5 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         dep_node_fn: &mut dep_node_fn,
         visitor: visitor
     };
-    krate.visit_all_items(&mut tracking_visitor)
+    krate.visit_all_item_likes(&mut tracking_visitor)
 }
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 044e36e5c9c..feefc43f401 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -106,7 +106,7 @@ pub type DefMap = NodeMap<PathResolution>;
 // within.
 pub type ExportMap = NodeMap<Vec<Export>>;
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Export {
     pub name: ast::Name, // The name of the target.
     pub def: Def, // The definition of the target.
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 9932e5fe686..4cfa889ec56 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -8,7 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! HIR walker. Each overridden visit method has full control over what
+//! HIR walker for walking the contents of nodes.
+//!
+//! **For an overview of the visitor strategy, see the docs on the
+//! `super::itemlikevisit::ItemLikeVisitor` trait.**
+//!
+//! If you have decided to use this visitor, here are some general
+//! notes on how to do it:
+//!
+//! Each overridden visit method has full control over what
 //! happens with its node, it can do its own traversal of the node's children,
 //! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
 //! deeper traversal by doing nothing.
@@ -30,6 +38,8 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
+use hir::map::Map;
+use super::itemlikevisit::DeepVisitor;
 
 use std::cmp;
 use std::u32;
@@ -76,22 +86,70 @@ pub trait Visitor<'v> : Sized {
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
 
-    /// Invoked when a nested item is encountered. By default, does
-    /// nothing. If you want a deep walk, you need to override to
-    /// fetch the item contents. But most of the time, it is easier
-    /// (and better) to invoke `Crate::visit_all_items`, which visits
-    /// all items in the crate in some order (but doesn't respect
-    /// nesting).
+    /// The default versions of the `visit_nested_XXX` routines invoke
+    /// this method to get a map to use; if they get back `None`, they
+    /// just skip nested things. Otherwise, they will lookup the
+    /// nested item-like things in the map and visit it. So the best
+    /// way to implement a nested visitor is to override this method
+    /// to return a `Map`; one advantage of this is that if we add
+    /// more types of nested things in the future, they will
+    /// automatically work.
+    ///
+    /// **If for some reason you want the nested behavior, but don't
+    /// have a `Map` are your disposal:** then you should override the
+    /// `visit_nested_XXX` methods, and override this method to
+    /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
+    /// added in the future, we will see the panic in your code and
+    /// fix it appropriately.
+    fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
+        None
+    }
+
+    /// Invoked when a nested item is encountered. By default does
+    /// nothing unless you override `nested_visit_map` to return
+    /// `Some(_)`, in which case it will walk the item. **You probably
+    /// don't want to override this method** -- instead, override
+    /// `nested_visit_map` or use the "shallow" or "deep" visit
+    /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
+    /// reason to override this method is if you want a nested pattern
+    /// but cannot supply a `Map`; see `nested_visit_map` for advice.
     #[allow(unused_variables)]
     fn visit_nested_item(&mut self, id: ItemId) {
+        let opt_item = self.nested_visit_map()
+                           .map(|map| map.expect_item(id.id));
+        if let Some(item) = opt_item {
+            self.visit_item(item);
+        }
     }
 
-    /// Visit the top-level item and (optionally) nested items. See
+    /// Like `visit_nested_item()`, but for impl items. See
+    /// `visit_nested_item()` for advice on when to override this
+    /// method.
+    #[allow(unused_variables)]
+    fn visit_nested_impl_item(&mut self, id: ImplItemId) {
+        let opt_item = self.nested_visit_map()
+                           .map(|map| map.impl_item(id));
+        if let Some(item) = opt_item {
+            self.visit_impl_item(item);
+        }
+    }
+
+    /// Visit the top-level item and (optionally) nested items / impl items. See
     /// `visit_nested_item` for details.
     fn visit_item(&mut self, i: &'v Item) {
         walk_item(self, i)
     }
 
+    /// When invoking `visit_all_item_likes()`, you need to supply an
+    /// item-like visitor.  This method converts a "intra-visit"
+    /// visitor into an item-like visitor that walks the entire tree.
+    /// If you use this, you probably don't want to process the
+    /// contents of nested item-like things, since the outer loop will
+    /// visit them as well.
+    fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> {
+        DeepVisitor::new(self)
+    }
+
     ///////////////////////////////////////////////////////////////////////////
 
     fn visit_id(&mut self, _node_id: NodeId) {
@@ -147,6 +205,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_impl_item(&mut self, ii: &'v ImplItem) {
         walk_impl_item(self, ii)
     }
+    fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) {
+        walk_impl_item_ref(self, ii)
+    }
     fn visit_trait_ref(&mut self, t: &'v TraitRef) {
         walk_trait_ref(self, t)
     }
@@ -206,6 +267,12 @@ pub trait Visitor<'v> : Sized {
     fn visit_vis(&mut self, vis: &'v Visibility) {
         walk_vis(self, vis)
     }
+    fn visit_associated_item_kind(&mut self, kind: &'v AssociatedItemKind) {
+        walk_associated_item_kind(self, kind);
+    }
+    fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
+        walk_defaultness(self, defaultness);
+    }
 }
 
 pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
@@ -341,12 +408,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_trait_ref(trait_ref)
         }
-        ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
+        ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_refs) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(type_parameters);
             walk_list!(visitor, visit_trait_ref, opt_trait_reference);
             visitor.visit_ty(typ);
-            walk_list!(visitor, visit_impl_item, impl_items);
+            for impl_item_ref in impl_item_refs {
+                visitor.visit_impl_item_ref(impl_item_ref);
+            }
         }
         ItemStruct(ref struct_definition, ref generics) |
         ItemUnion(ref struct_definition, ref generics) => {
@@ -677,10 +746,14 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
 }
 
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
-    visitor.visit_vis(&impl_item.vis);
-    visitor.visit_name(impl_item.span, impl_item.name);
-    walk_list!(visitor, visit_attribute, &impl_item.attrs);
-    match impl_item.node {
+    // NB: Deliberately force a compilation error if/when new fields are added.
+    let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
+
+    visitor.visit_name(span, name);
+    visitor.visit_vis(vis);
+    visitor.visit_defaultness(defaultness);
+    walk_list!(visitor, visit_attribute, attrs);
+    match *node {
         ImplItemKind::Const(ref ty, ref expr) => {
             visitor.visit_id(impl_item.id);
             visitor.visit_ty(ty);
@@ -703,6 +776,17 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     }
 }
 
+pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
+    // NB: Deliberately force a compilation error if/when new fields are added.
+    let ImplItemRef { id, name, ref kind, span, ref vis, ref defaultness } = *impl_item_ref;
+    visitor.visit_nested_impl_item(id);
+    visitor.visit_name(span, name);
+    visitor.visit_associated_item_kind(kind);
+    visitor.visit_vis(vis);
+    visitor.visit_defaultness(defaultness);
+}
+
+
 pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
     visitor.visit_id(struct_definition.id());
     walk_list!(visitor, visit_struct_field, struct_definition.fields());
@@ -872,6 +956,18 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
     }
 }
 
+pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssociatedItemKind) {
+    // No visitable content here: this fn exists so you can call it if
+    // the right thing to do, should content be added in the future,
+    // would be to walk it.
+}
+
+pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) {
+    // No visitable content here: this fn exists so you can call it if
+    // the right thing to do, should content be added in the future,
+    // would be to walk it.
+}
+
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
 pub struct IdRange {
     pub min: NodeId,
diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs
new file mode 100644
index 00000000000..1e373441e9e
--- /dev/null
+++ b/src/librustc/hir/itemlikevisit.rs
@@ -0,0 +1,84 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{Item, ImplItem};
+use super::intravisit::Visitor;
+
+/// The "item-like visitor" visitor defines only the top-level methods
+/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
+/// this trait is the right one to implement will depend on the
+/// overall pattern you need. Here are the three available patterns,
+/// in roughly the order of desirability:
+///
+/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
+///    - Example: find all items with a `#[foo]` attribute on them.
+///    - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`.
+///    - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
+///    - Pro: Integrates well into dependency tracking.
+///    - Con: Don't get information about nesting
+///    - Con: Don't have methods for specific bits of HIR, like "on
+///      every expr, do this".
+/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
+///    an item, but don't care about how item-like things are nested
+///    within one another.
+///    - Example: Examine each expression to look for its type and do some check or other.
+///    - How: Implement `intravisit::Visitor` and use
+///      `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within
+///      your `intravisit::Visitor` impl, implement methods like
+///      `visit_expr()`; don't forget to invoke
+///      `intravisit::walk_visit_expr()` to keep walking the subparts.
+///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+///    - Pro: Integrates well into dependency tracking.
+///    - Con: Don't get information about nesting between items
+/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
+///    item-like things.
+///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
+///      impl into scope while visiting the impl-items, and then back out again.
+///    - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods
+///      as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
+///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+///    - Pro: Preserves nesting information
+///    - Con: Does not integrate well into dependency tracking.
+///
+/// Note: the methods of `ItemLikeVisitor` intentionally have no
+/// defaults, so that as we expand the list of item-like things, we
+/// revisit the various visitors to see if they need to change. This
+/// is harder to do with `intravisit::Visitor`, so when you add a new
+/// `visit_nested_foo()` method, it is recommended that you search for
+/// existing `fn visit_nested` methods to see where changes are
+/// needed.
+pub trait ItemLikeVisitor<'hir> {
+    fn visit_item(&mut self, item: &'hir Item);
+    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
+}
+
+pub struct DeepVisitor<'v, V: 'v> {
+    visitor: &'v mut V,
+}
+
+impl<'v, 'hir, V> DeepVisitor<'v, V>
+    where V: Visitor<'hir> + 'v
+{
+    pub fn new(base: &'v mut V) -> Self {
+        DeepVisitor { visitor: base }
+    }
+}
+
+impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
+    where V: Visitor<'hir>
+{
+    fn visit_item(&mut self, item: &'hir Item) {
+        self.visitor.visit_item(item);
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
+        self.visitor.visit_impl_item(impl_item);
+    }
+}
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b985298e47c..05c4ae52180 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -105,6 +105,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_crate(&mut self, c: &Crate) -> hir::Crate {
         struct ItemLowerer<'lcx, 'interner: 'lcx> {
             items: BTreeMap<NodeId, hir::Item>,
+            impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
             lctx: &'lcx mut LoweringContext<'interner>,
         }
 
@@ -113,12 +114,20 @@ impl<'a> LoweringContext<'a> {
                 self.items.insert(item.id, self.lctx.lower_item(item));
                 visit::walk_item(self, item);
             }
+
+            fn visit_impl_item(&mut self, item: &ImplItem) {
+                let id = self.lctx.lower_impl_item_ref(item).id;
+                self.impl_items.insert(id, self.lctx.lower_impl_item(item));
+                visit::walk_impl_item(self, item);
+            }
         }
 
-        let items = {
-            let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: self };
+        let (items, impl_items) = {
+            let mut item_lowerer = ItemLowerer { items: BTreeMap::new(),
+                                                 impl_items: BTreeMap::new(),
+                                                 lctx: self };
             visit::walk_crate(&mut item_lowerer, c);
-            item_lowerer.items
+            (item_lowerer.items, item_lowerer.impl_items)
         };
 
         hir::Crate {
@@ -127,6 +136,7 @@ impl<'a> LoweringContext<'a> {
             span: c.span,
             exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(),
             items: items,
+            impl_items: impl_items,
         }
     }
 
@@ -631,7 +641,7 @@ impl<'a> LoweringContext<'a> {
             }
             ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
                 let new_impl_items = impl_items.iter()
-                                               .map(|item| self.lower_impl_item(item))
+                                               .map(|item| self.lower_impl_item_ref(item))
                                                .collect();
                 let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
                 hir::ItemImpl(self.lower_unsafety(unsafety),
@@ -689,7 +699,7 @@ impl<'a> LoweringContext<'a> {
                 name: i.ident.name,
                 attrs: this.lower_attrs(&i.attrs),
                 vis: this.lower_visibility(&i.vis),
-                defaultness: this.lower_defaultness(i.defaultness),
+                defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
                         hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
@@ -705,6 +715,28 @@ impl<'a> LoweringContext<'a> {
                 span: i.span,
             }
         })
+
+        // [1] since `default impl` is not yet implemented, this is always true in impls
+    }
+
+    fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
+        hir::ImplItemRef {
+            id: hir::ImplItemId { node_id: i.id },
+            name: i.ident.name,
+            span: i.span,
+            vis: self.lower_visibility(&i.vis),
+            defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
+            kind: match i.node {
+                ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
+                ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
+                ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
+                    has_self: sig.decl.get_self().is_some(),
+                },
+                ImplItemKind::Macro(..) => unimplemented!(),
+            },
+        }
+
+        // [1] since `default impl` is not yet implemented, this is always true in impls
     }
 
     fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
@@ -1620,10 +1652,13 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_defaultness(&mut self, d: Defaultness) -> hir::Defaultness {
+    fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness {
         match d {
-            Defaultness::Default => hir::Defaultness::Default,
-            Defaultness::Final => hir::Defaultness::Final,
+            Defaultness::Default => hir::Defaultness::Default { has_value: has_value },
+            Defaultness::Final => {
+                assert!(has_value);
+                hir::Defaultness::Final
+            }
         }
     }
 
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 04fcf7e8450..51a378a0833 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     /// Because we want to track parent items and so forth, enable
     /// deep walking so that we walk nested items in the context of
     /// their outer items.
+
+    fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> {
+        panic!("visit_nested_xxx must be manually implemented in this visitor")
+    }
+
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
         if !self.ignore_nested_items {
@@ -99,6 +104,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         }
     }
 
+    fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+        self.visit_impl_item(self.krate.impl_item(item_id))
+    }
+
     fn visit_item(&mut self, i: &'ast Item) {
         debug!("visit_item: {:?}", i);
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 39114ec4238..06cfc8aee8c 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -254,9 +254,14 @@ impl<'ast> Map<'ast> {
                         return DepNode::Hir(def_id);
                     }
 
+                    EntryImplItem(..) => {
+                        let def_id = self.local_def_id(id);
+                        assert!(!self.is_inlined_def_id(def_id));
+                        return DepNode::Hir(def_id);
+                    }
+
                     EntryForeignItem(p, _) |
                     EntryTraitItem(p, _) |
-                    EntryImplItem(p, _) |
                     EntryVariant(p, _) |
                     EntryExpr(p, _) |
                     EntryStmt(p, _) |
@@ -378,6 +383,14 @@ impl<'ast> Map<'ast> {
         self.forest.krate()
     }
 
+    pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
+        self.read(id.node_id);
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.impl_item(id)
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 6b5b8101a14..9f5ff6914b0 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -68,6 +68,7 @@ pub mod check_attr;
 pub mod def;
 pub mod def_id;
 pub mod intravisit;
+pub mod itemlikevisit;
 pub mod lowering;
 pub mod map;
 pub mod pat_util;
@@ -423,6 +424,8 @@ pub struct Crate {
     // detected, which in turn can make compile-fail tests yield
     // slightly different results.
     pub items: BTreeMap<NodeId, Item>,
+
+    pub impl_items: BTreeMap<ImplItemId, ImplItem>,
 }
 
 impl Crate {
@@ -430,6 +433,10 @@ impl Crate {
         &self.items[&id]
     }
 
+    pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
+        &self.impl_items[&id]
+    }
+
     /// Visits all items in the crate in some determinstic (but
     /// unspecified) order. If you just need to process every item,
     /// but don't care about nesting, this method is the best choice.
@@ -438,12 +445,16 @@ impl Crate {
     /// follows lexical scoping rules -- then you want a different
     /// approach. You should override `visit_nested_item` in your
     /// visitor and then call `intravisit::walk_crate` instead.
-    pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V)
-        where V: intravisit::Visitor<'hir>
+    pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V)
+        where V: itemlikevisit::ItemLikeVisitor<'hir>
     {
         for (_, item) in &self.items {
             visitor.visit_item(item);
         }
+
+        for (_, impl_item) in &self.impl_items {
+            visitor.visit_impl_item(impl_item);
+        }
     }
 }
 
@@ -1041,6 +1052,14 @@ pub enum TraitItem_ {
     TypeTraitItem(TyParamBounds, Option<P<Ty>>),
 }
 
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ImplItemId {
+    pub node_id: NodeId,
+}
+
 /// Represents anything within an `impl` block
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct ImplItem {
@@ -1240,17 +1259,27 @@ pub enum Constness {
 
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Defaultness {
-    Default,
+    Default { has_value: bool },
     Final,
 }
 
 impl Defaultness {
+    pub fn has_value(&self) -> bool {
+        match *self {
+            Defaultness::Default { has_value, .. } => has_value,
+            Defaultness::Final => true,
+        }
+    }
+
     pub fn is_final(&self) -> bool {
         *self == Defaultness::Final
     }
 
     pub fn is_default(&self) -> bool {
-        *self == Defaultness::Default
+        match *self {
+            Defaultness::Default { .. } => true,
+            _ => false,
+        }
     }
 }
 
@@ -1527,7 +1556,7 @@ pub enum Item_ {
              Generics,
              Option<TraitRef>, // (optional) trait this impl implements
              P<Ty>, // self
-             HirVec<ImplItem>),
+             HirVec<ImplItemRef>),
 }
 
 impl Item_ {
@@ -1551,6 +1580,29 @@ impl Item_ {
     }
 }
 
+/// A reference from an impl to one of its associated items. This
+/// contains the item's id, naturally, but also the item's name and
+/// some other high-level details (like whether it is an associated
+/// type or method, and whether it is public). This allows other
+/// passes to find the impl they want without loading the id (which
+/// means fewer edges in the incremental compilation graph).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ImplItemRef {
+    pub id: ImplItemId,
+    pub name: Name,
+    pub kind: AssociatedItemKind,
+    pub span: Span,
+    pub vis: Visibility,
+    pub defaultness: Defaultness,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum AssociatedItemKind {
+    Const,
+    Method { has_self: bool },
+    Type,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct ForeignItem {
     pub name: Name,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 2c4ffb853c1..807bbec3b58 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -809,7 +809,7 @@ impl<'a> State<'a> {
                 self.bopen()?;
                 self.print_inner_attributes(&item.attrs)?;
                 for impl_item in impl_items {
-                    self.print_impl_item(impl_item)?;
+                    self.print_impl_item_ref(impl_item)?;
                 }
                 self.bclose(item.span)?;
             }
@@ -1020,14 +1020,25 @@ impl<'a> State<'a> {
         self.ann.post(self, NodeSubItem(ti.id))
     }
 
+    pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
+        if let Some(krate) = self.krate {
+            // skip nested items if krate context was not provided
+            let item = &krate.impl_item(item_ref.id);
+            self.print_impl_item(item)
+        } else {
+            Ok(())
+        }
+    }
+
     pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
         self.ann.pre(self, NodeSubItem(ii.id))?;
         self.hardbreak_if_not_bol()?;
         self.maybe_print_comment(ii.span.lo)?;
         self.print_outer_attributes(&ii.attrs)?;
 
-        if let hir::Defaultness::Default = ii.defaultness {
-            self.word_nbsp("default")?;
+        match ii.defaultness {
+            hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
+            hir::Defaultness::Final => (),
         }
 
         match ii.node {
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 50c58105740..a490b58964a 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -792,16 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> {
     }
 }
 
-impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
+impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, it: &hir::Item) {
+    fn visit_item(&mut self, it: &'tcx hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_item, late_passes, it);
             cx.visit_ids(|v| v.visit_item(it));
@@ -810,7 +809,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         })
     }
 
-    fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_foreign_item, late_passes, it);
             hir_visit::walk_foreign_item(cx, it);
@@ -818,19 +817,19 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         })
     }
 
-    fn visit_pat(&mut self, p: &hir::Pat) {
+    fn visit_pat(&mut self, p: &'tcx hir::Pat) {
         run_lints!(self, check_pat, late_passes, p);
         hir_visit::walk_pat(self, p);
     }
 
-    fn visit_expr(&mut self, e: &hir::Expr) {
+    fn visit_expr(&mut self, e: &'tcx hir::Expr) {
         self.with_lint_attrs(&e.attrs, |cx| {
             run_lints!(cx, check_expr, late_passes, e);
             hir_visit::walk_expr(cx, e);
         })
     }
 
-    fn visit_stmt(&mut self, s: &hir::Stmt) {
+    fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
         // statement attributes are actually just attributes on one of
         // - item
         // - local
@@ -840,17 +839,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         hir_visit::walk_stmt(self, s);
     }
 
-    fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
-                body: &'v hir::Expr, span: Span, id: ast::NodeId) {
+    fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
+                body: &'tcx 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);
     }
 
     fn visit_variant_data(&mut self,
-                        s: &hir::VariantData,
+                        s: &'tcx hir::VariantData,
                         name: ast::Name,
-                        g: &hir::Generics,
+                        g: &'tcx hir::Generics,
                         item_id: ast::NodeId,
                         _: Span) {
         run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
@@ -858,14 +857,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
     }
 
-    fn visit_struct_field(&mut self, s: &hir::StructField) {
+    fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
         self.with_lint_attrs(&s.attrs, |cx| {
             run_lints!(cx, check_struct_field, late_passes, s);
             hir_visit::walk_struct_field(cx, s);
         })
     }
 
-    fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
+    fn visit_variant(&mut self,
+                     v: &'tcx hir::Variant,
+                     g: &'tcx hir::Generics,
+                     item_id: ast::NodeId) {
         self.with_lint_attrs(&v.node.attrs, |cx| {
             run_lints!(cx, check_variant, late_passes, v, g);
             hir_visit::walk_variant(cx, v, g, item_id);
@@ -873,7 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         })
     }
 
-    fn visit_ty(&mut self, t: &hir::Ty) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         run_lints!(self, check_ty, late_passes, t);
         hir_visit::walk_ty(self, t);
     }
@@ -882,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         run_lints!(self, check_name, late_passes, sp, name);
     }
 
-    fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
+    fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
         run_lints!(self, check_mod, late_passes, m, s, n);
         hir_visit::walk_mod(self, m, n);
         run_lints!(self, check_mod_post, late_passes, m, s, n);
     }
 
-    fn visit_local(&mut self, l: &hir::Local) {
+    fn visit_local(&mut self, l: &'tcx hir::Local) {
         self.with_lint_attrs(&l.attrs, |cx| {
             run_lints!(cx, check_local, late_passes, l);
             hir_visit::walk_local(cx, l);
         })
     }
 
-    fn visit_block(&mut self, b: &hir::Block) {
+    fn visit_block(&mut self, b: &'tcx hir::Block) {
         run_lints!(self, check_block, late_passes, b);
         hir_visit::walk_block(self, b);
         run_lints!(self, check_block_post, late_passes, b);
     }
 
-    fn visit_arm(&mut self, a: &hir::Arm) {
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) {
         run_lints!(self, check_arm, late_passes, a);
         hir_visit::walk_arm(self, a);
     }
 
-    fn visit_decl(&mut self, d: &hir::Decl) {
+    fn visit_decl(&mut self, d: &'tcx hir::Decl) {
         run_lints!(self, check_decl, late_passes, d);
         hir_visit::walk_decl(self, d);
     }
 
-    fn visit_expr_post(&mut self, e: &hir::Expr) {
+    fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
         run_lints!(self, check_expr_post, late_passes, e);
     }
 
-    fn visit_generics(&mut self, g: &hir::Generics) {
+    fn visit_generics(&mut self, g: &'tcx hir::Generics) {
         run_lints!(self, check_generics, late_passes, g);
         hir_visit::walk_generics(self, g);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         self.with_lint_attrs(&trait_item.attrs, |cx| {
             run_lints!(cx, check_trait_item, late_passes, trait_item);
             cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
@@ -929,7 +931,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         });
     }
 
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.with_lint_attrs(&impl_item.attrs, |cx| {
             run_lints!(cx, check_impl_item, late_passes, impl_item);
             cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
@@ -938,20 +940,20 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
         });
     }
 
-    fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
+    fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
         run_lints!(self, check_lifetime, late_passes, lt);
     }
 
-    fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
+    fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
         run_lints!(self, check_lifetime_def, late_passes, lt);
     }
 
-    fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
+    fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
         run_lints!(self, check_path, late_passes, p, id);
         hir_visit::walk_path(self, p);
     }
 
-    fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+    fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
         run_lints!(self, check_path_list_item, late_passes, item);
         hir_visit::walk_path_list_item(self, prefix, item);
     }
@@ -1116,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
 
 // Output any lints that were previously added to the session.
 impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
-
     fn visit_id(&mut self, id: ast::NodeId) {
         if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
             debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 94667b398b0..99139881375 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -16,6 +16,7 @@ use dep_graph::DepNode;
 use hir::map as ast_map;
 use hir::{self, pat_util, PatKind};
 use hir::intravisit::{self, Visitor};
+use hir::itemlikevisit::ItemLikeVisitor;
 
 use middle::privacy;
 use ty::{self, TyCtxt};
@@ -329,11 +330,12 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
 //   or
 //   2) We are not sure to be live or not
 //     * Implementation of a trait method
-struct LifeSeeder {
-    worklist: Vec<ast::NodeId>
+struct LifeSeeder<'k> {
+    worklist: Vec<ast::NodeId>,
+    krate: &'k hir::Crate,
 }
 
-impl<'v> Visitor<'v> for LifeSeeder {
+impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
     fn visit_item(&mut self, item: &hir::Item) {
         let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs);
         if allow_dead_code {
@@ -357,17 +359,22 @@ impl<'v> Visitor<'v> for LifeSeeder {
                     }
                 }
             }
-            hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => {
-                for impl_item in impl_items {
+            hir::ItemImpl(.., ref opt_trait, _, ref impl_item_refs) => {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.krate.impl_item(impl_item_ref.id);
                     if opt_trait.is_some() ||
                             has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
-                        self.worklist.push(impl_item.id);
+                        self.worklist.push(impl_item_ref.id.node_id);
                     }
                 }
             }
             _ => ()
         }
     }
+
+    fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
+        // ignore: we are handling this in `visit_item` above
+    }
 }
 
 fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -386,9 +393,10 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Seed implemented trait items
     let mut life_seeder = LifeSeeder {
-        worklist: worklist
+        worklist: worklist,
+        krate: krate,
     };
-    krate.visit_all_items(&mut life_seeder);
+    krate.visit_all_item_likes(&mut life_seeder);
 
     return life_seeder.worklist;
 }
@@ -503,17 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
     /// Walk nested items in place so that we don't report dead-code
     /// on inner functions when the outer function is already getting
     /// an error. We could do this also by checking the parents, but
     /// this is how the code is setup and it seems harmless enough.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         if self.should_warn_about_item(item) {
             self.warn_dead_code(
                 item.id,
@@ -527,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) {
+    fn visit_variant(&mut self,
+                     variant: &'tcx hir::Variant,
+                     g: &'tcx hir::Generics,
+                     id: ast::NodeId) {
         if self.should_warn_about_variant(&variant.node) {
             self.warn_dead_code(variant.node.data.id(), variant.span,
                                 variant.node.name, "variant");
@@ -536,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
         if !self.symbol_is_live(fi.id, None) {
             self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
         }
         intravisit::walk_foreign_item(self, fi);
     }
 
-    fn visit_struct_field(&mut self, field: &hir::StructField) {
+    fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
         if self.should_warn_about_field(&field) {
             self.warn_dead_code(field.id, field.span,
                                 field.name, "field");
@@ -552,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
         intravisit::walk_struct_field(self, field);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
             hir::ImplItemKind::Const(_, ref expr) => {
                 if !self.symbol_is_live(impl_item.id, None) {
@@ -573,7 +583,7 @@ 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) {
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
             hir::ConstTraitItem(_, Some(ref body))|
             hir::MethodTraitItem(_, Some(ref body)) => {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 5634e2012c9..25fe407271b 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -235,5 +235,5 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         unsafe_context: UnsafeContext::new(SafeContext),
     };
 
-    tcx.map.krate().visit_all_items(&mut visitor);
+    tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 11bde922f47..9dd54457a34 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -17,8 +17,8 @@ use syntax::ast::NodeId;
 use syntax::attr;
 use syntax::entry::EntryPointType;
 use syntax_pos::Span;
-use hir::{Item, ItemFn};
-use hir::intravisit::Visitor;
+use hir::{Item, ItemFn, ImplItem};
+use hir::itemlikevisit::ItemLikeVisitor;
 
 struct EntryContext<'a, 'tcx: 'a> {
     session: &'a Session,
@@ -39,13 +39,17 @@ struct EntryContext<'a, 'tcx: 'a> {
     non_main_fns: Vec<(NodeId, Span)> ,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx Item) {
         let def_id = self.map.local_def_id(item.id);
         let def_key = self.map.def_key(def_id);
         let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
         find_item(item, self, at_root);
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
+        // entry fn is never an impl item
+    }
 }
 
 pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
@@ -74,7 +78,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
         non_main_fns: Vec::new(),
     };
 
-    ast_map.krate().visit_all_items(&mut ctxt);
+    ast_map.krate().visit_all_item_likes(&mut ctxt);
 
     configure_main(&mut ctxt);
 }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 0f9748a16f4..cf08b59312d 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -26,7 +26,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut visitor = ItemVisitor {
         tcx: tcx
     };
-    tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor);
+    tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor());
 }
 
 struct ItemVisitor<'a, 'tcx: 'a> {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 3e7de79246b..9b4b1396669 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -31,7 +31,7 @@ use util::nodemap::FxHashMap;
 
 use syntax::ast;
 use syntax::parse::token::InternedString;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use hir;
 
 // The actual lang items defined come at the end of this file in one handy table.
@@ -149,7 +149,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> {
     item_refs: FxHashMap<&'static str, usize>,
 }
 
-impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
+impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let Some(value) = extract(&item.attrs) {
             let item_index = self.item_refs.get(&value[..]).cloned();
@@ -164,6 +164,10 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+        // at present, lang items are always items, not impl items
+    }
 }
 
 impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
@@ -219,7 +223,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
     }
 
     pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
-        krate.visit_all_items(self);
+        krate.visit_all_item_likes(self);
     }
 
     pub fn collect_external_language_items(&mut self) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f472205b732..d381188d56b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -196,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::Liveness);
-    tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx));
+    tcx.map.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 7868e700f27..ac614494355 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -29,6 +29,7 @@ use syntax::ast;
 use syntax::attr;
 use hir;
 use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use hir::intravisit;
 
 // Returns true if the given set of generics implies that the item it's
@@ -324,17 +325,21 @@ struct CollectPrivateImplItemsVisitor<'a> {
     worklist: &'a mut Vec<ast::NodeId>,
 }
 
-impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
+impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> {
     fn visit_item(&mut self, item: &hir::Item) {
         // We need only trait impls here, not inherent impls, and only non-exported ones
-        if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node {
+        if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node {
             if !self.access_levels.is_reachable(item.id) {
-                for impl_item in impl_items {
-                    self.worklist.push(impl_item.id);
+                for impl_item_ref in impl_item_refs {
+                    self.worklist.push(impl_item_ref.id.node_id);
                 }
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+        // processed in visit_item above
+    }
 }
 
 pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -364,7 +369,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             access_levels: access_levels,
             worklist: &mut reachable_context.worklist,
         };
-        tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
+        tcx.map.krate().visit_all_item_likes(&mut collect_private_impl_items);
     }
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 34a6a547d94..5f9a6b283c6 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -1235,7 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
             },
             terminating_scopes: NodeSet()
         };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
     }
     return maps;
 }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 292d9592ceb..f682dfbf1be 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -119,7 +119,7 @@ pub fn krate(sess: &Session,
         late_bound: NodeMap(),
     };
     sess.track_errors(|| {
-        krate.visit_all_items(&mut LifetimeContext {
+        intravisit::walk_crate(&mut LifetimeContext {
             sess: sess,
             hir_map: hir_map,
             map: &mut map,
@@ -127,14 +127,21 @@ pub fn krate(sess: &Session,
             def_map: def_map,
             trait_ref_hack: false,
             labels_in_fn: vec![],
-        });
+        }, krate);
     })?;
     Ok(map)
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item) {
-        assert!(self.labels_in_fn.is_empty());
+impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
+    // Override the nested functions -- lifetimes follow lexical scope,
+    // so it's convenient to walk the tree in lexical order.
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.hir_map)
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        // Save labels for nested items.
+        let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
 
         // Items always introduce a new root scope
         self.with(RootScope, |_, this| {
@@ -175,10 +182,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         });
 
         // Done traversing the item; remove any labels it created
-        self.labels_in_fn.truncate(0);
+        self.labels_in_fn = saved_labels_in_fn;
     }
 
-    fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
         // Items save/restore the set of labels. This way inner items
         // can freely reuse names, be they loop labels or lifetimes.
         let saved = replace(&mut self.labels_in_fn, vec![]);
@@ -201,8 +208,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         replace(&mut self.labels_in_fn, saved);
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
+                b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
@@ -227,7 +234,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn visit_ty(&mut self, ty: &hir::Ty) {
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         match ty.node {
             hir::TyBareFn(ref c) => {
                 self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
@@ -257,7 +264,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         // We reset the labels on every trait item, so that different
         // methods in an impl can reuse label names.
         let saved = replace(&mut self.labels_in_fn, vec![]);
@@ -274,7 +281,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         replace(&mut self.labels_in_fn, saved);
     }
 
-    fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
+    fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         if lifetime_ref.name == keywords::StaticLifetime.name() {
             self.insert_lifetime(lifetime_ref, DefStaticRegion);
             return;
@@ -282,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         self.resolve_lifetime_ref(lifetime_ref);
     }
 
-    fn visit_generics(&mut self, generics: &hir::Generics) {
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
         for ty_param in generics.ty_params.iter() {
             walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
             if let Some(ref ty) = ty_param.default {
@@ -331,8 +338,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_poly_trait_ref(&mut self,
-                            trait_ref: &hir::PolyTraitRef,
-                            _modifier: &hir::TraitBoundModifier) {
+                            trait_ref: &'tcx hir::PolyTraitRef,
+                            _modifier: &'tcx hir::TraitBoundModifier) {
         debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
 
         if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
@@ -490,13 +497,12 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
-    fn add_scope_and_walk_fn<'b>(&mut self,
-                                 fk: FnKind,
-                                 fd: &hir::FnDecl,
-                                 fb: &'b hir::Expr,
-                                 _span: Span,
-                                 fn_id: ast::NodeId) {
-
+    fn add_scope_and_walk_fn(&mut self,
+                             fk: FnKind<'tcx>,
+                             fd: &'tcx hir::FnDecl,
+                             fb: &'tcx hir::Expr,
+                             _span: Span,
+                             fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 intravisit::walk_fn_decl(self, fd);
@@ -519,8 +525,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                   |_old_scope, this| this.visit_expr(fb))
     }
 
+    // FIXME(#37666) this works around a limitation in the region inferencer
+    fn hack<F>(&mut self, f: F) where
+        F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
+    {
+        f(self)
+    }
+
     fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
-        F: FnOnce(Scope, &mut LifetimeContext),
+        F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
         let mut this = LifetimeContext {
@@ -557,10 +570,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     /// ordering is not important there.
     fn visit_early_late<F>(&mut self,
                            fn_id: ast::NodeId,
-                           decl: &hir::FnDecl,
-                           generics: &hir::Generics,
+                           decl: &'tcx hir::FnDecl,
+                           generics: &'tcx hir::Generics,
                            walk: F) where
-        F: FnOnce(&mut LifetimeContext),
+        F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
     {
         let fn_def_id = self.hir_map.local_def_id(fn_id);
         insert_late_bound_lifetimes(self.map,
@@ -590,11 +603,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }
 
-        let this = self;
-        this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| {
+        self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| {
             this.with(LateScope(&late, this.scope), move |_, this| {
                 this.check_lifetime_defs(old_scope, &generics.lifetimes);
-                walk(this);
+                this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
             });
         });
     }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index d79833998d6..7e4efc7ddca 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
     // stability. The stability is recorded in the index and used as the parent.
     fn annotate<F>(&mut self, id: NodeId, attrs: &[Attribute],
                    item_sp: Span, kind: AnnotationKind, visit_children: F)
-        where F: FnOnce(&mut Annotator)
+        where F: FnOnce(&mut Self)
     {
         if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
             debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
@@ -234,16 +234,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, i: &Item) {
+    fn visit_item(&mut self, i: &'tcx Item) {
         let orig_in_trait_impl = self.in_trait_impl;
         let mut kind = AnnotationKind::Required;
         match i.node {
@@ -272,13 +271,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
         self.in_trait_impl = orig_in_trait_impl;
     }
 
-    fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
         self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
             intravisit::walk_trait_item(v, ti);
         });
     }
 
-    fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
         let kind = if self.in_trait_impl {
             AnnotationKind::Prohibited
         } else {
@@ -289,25 +288,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
         });
     }
 
-    fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
+    fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
         self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
             intravisit::walk_variant(v, var, g, item_id);
         })
     }
 
-    fn visit_struct_field(&mut self, s: &StructField) {
+    fn visit_struct_field(&mut self, s: &'tcx StructField) {
         self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| {
             intravisit::walk_struct_field(v, s);
         });
     }
 
-    fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
         self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
             intravisit::walk_foreign_item(v, i);
         });
     }
 
-    fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
+    fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
         if md.imported_from.is_none() {
             self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
         }
@@ -444,16 +443,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
     }
 }
 
-impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         // When compiling with --test we don't enforce stability on the
         // compiler-generated test module, demarcated with `DUMMY_SP` plus the
         // name `__test`
@@ -464,31 +462,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
         intravisit::walk_item(self, item);
     }
 
-    fn visit_expr(&mut self, ex: &hir::Expr) {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         check_expr(self.tcx, ex,
                    &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
         intravisit::walk_expr(self, ex);
     }
 
-    fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
+    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
         check_path(self.tcx, path, id,
                    &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
         intravisit::walk_path(self, path)
     }
 
-    fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+    fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
         check_path_list_item(self.tcx, item,
                    &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
         intravisit::walk_path_list_item(self, prefix, item)
     }
 
-    fn visit_pat(&mut self, pat: &hir::Pat) {
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
         check_pat(self.tcx, pat,
                   &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
         intravisit::walk_pat(self, pat)
     }
 
-    fn visit_block(&mut self, b: &hir::Block) {
+    fn visit_block(&mut self, b: &'tcx hir::Block) {
         let old_skip_count = self.in_skip_block;
         match b.rules {
             hir::BlockCheckMode::PushUnstableBlock => {
@@ -527,9 +525,10 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // For implementations of traits, check the stability of each item
         // individually as it's possible to have a stable trait with unstable
         // items.
-        hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
+        hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => {
             let trait_did = tcx.expect_def(t.ref_id).def_id();
-            for impl_item in impl_items {
+            for impl_item_ref in impl_item_refs {
+                let impl_item = tcx.map.impl_item(impl_item_ref.id);
                 let item = tcx.associated_items(trait_did)
                     .find(|item| item.name == impl_item.name).unwrap();
                 if warn_about_defns {
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 2c08e17f8f1..12d32bf31b1 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate,
 
     {
         let mut cx = Context { sess: sess, items: items };
-        krate.visit_all_items(&mut cx);
+        krate.visit_all_item_likes(&mut cx.as_deep_visitor());
     }
     verify(sess, items);
 }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 986e4192f88..a2d45fa2714 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -940,7 +940,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.has_value
+                        node_item.item.defaultness.has_value()
                     } else {
                         node_item.item.defaultness.is_default()
                     };
@@ -1004,8 +1004,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                     // types, which appear not to unify -- so the
                     // overlap check succeeds, when it should
                     // fail.
-                    bug!("Tried to project an inherited associated type during \
-                          coherence checking, which is currently not supported.");
+                    span_bug!(obligation.cause.span,
+                              "Tried to project an inherited associated type during \
+                               coherence checking, which is currently not supported.");
                 };
                 candidate_set.vec.extend(new_candidate);
             }
@@ -1295,7 +1296,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
 
     match assoc_ty {
         Some(node_item) => {
-            let ty = if !node_item.item.has_value {
+            let ty = if !node_item.item.defaultness.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
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1de54f49a55..f5c23401a4e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -50,7 +50,7 @@ use syntax_pos::{DUMMY_SP, Span};
 use rustc_const_math::ConstInt;
 
 use hir;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BuiltinBound, BuiltinBounds};
@@ -189,7 +189,6 @@ pub struct AssociatedItem {
     pub kind: AssociatedKind,
     pub vis: Visibility,
     pub defaultness: hir::Defaultness,
-    pub has_value: bool,
     pub container: AssociatedItemContainer,
 
     /// Whether this is a method with an explicit self
@@ -2072,7 +2071,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
         self.associated_items(id)
-            .filter(|item| item.kind == AssociatedKind::Method && item.has_value)
+            .filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value())
             .collect()
     }
 
@@ -2113,69 +2112,109 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                            .expect("missing AssociatedItem in metadata");
             }
 
+            // When the user asks for a given associated item, we
+            // always go ahead and convert all the associated items in
+            // the container. Note that we are also careful only to
+            // ever register a read on the *container* of the assoc
+            // item, not the assoc item itself. This prevents changes
+            // in the details of an item (for example, the type to
+            // which an associated type is bound) from contaminating
+            // those tasks that just need to scan the names of items
+            // and so forth.
+
             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
+            let parent_item = self.map.expect_item(parent_id);
+            match parent_item.node {
+                hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => {
+                    for impl_item_ref in impl_item_refs {
+                        let assoc_item =
+                            self.associated_item_from_impl_item_ref(parent_def_id,
+                                                                    impl_trait_ref.is_some(),
+                                                                    impl_item_ref);
+                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
                     }
                 }
-                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
+
+                hir::ItemTrait(.., ref trait_items) => {
+                    for trait_item in trait_items {
+                        let assoc_item =
+                            self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
+                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
                     }
                 }
-                item => bug!("associated_item: {:?} not an associated item", item)
+
+                ref r => {
+                    panic!("unexpected container of associated items: {:?}", r)
+                }
             }
+
+            // memoize wants us to return something, so return
+            // the one we generated for this def-id
+            *self.associated_items.borrow().get(&def_id).unwrap()
         })
     }
 
+    fn associated_item_from_trait_item_ref(self,
+                                           parent_def_id: DefId,
+                                           trait_item: &hir::TraitItem)
+                                           -> AssociatedItem {
+        let def_id = self.map.local_def_id(trait_item.id);
+
+        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, trait_item.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
+        }
+    }
+
+    fn associated_item_from_impl_item_ref(self,
+                                          parent_def_id: DefId,
+                                          from_trait_impl: bool,
+                                          impl_item_ref: &hir::ImplItemRef)
+                                          -> AssociatedItem {
+        let def_id = self.map.local_def_id(impl_item_ref.id.node_id);
+        let (kind, has_self) = match impl_item_ref.kind {
+            hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
+            hir::AssociatedItemKind::Method { has_self } => {
+                (ty::AssociatedKind::Method, has_self)
+            }
+            hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
+        };
+
+        // Trait impl items are always public.
+        let public = hir::Public;
+        let vis = if from_trait_impl { &public } else { &impl_item_ref.vis };
+
+        ty::AssociatedItem {
+            name: impl_item_ref.name,
+            kind: kind,
+            vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
+            defaultness: impl_item_ref.defaultness,
+            def_id: def_id,
+            container: ImplContainer(parent_def_id),
+            method_has_self_argument: has_self
+        }
+    }
+
     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() {
@@ -2184,19 +2223,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
             let id = self.map.as_local_node_id(def_id).unwrap();
             let item = self.map.expect_item(id);
-            match item.node {
+            let vec: Vec<_> = 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())
+                    trait_items.iter()
+                               .map(|trait_item| trait_item.id)
+                               .map(|id| self.map.local_def_id(id))
+                               .collect()
                 }
-                hir::ItemImpl(.., ref impl_items) => {
-                    Rc::new(impl_items.iter().map(|impl_item| {
-                        self.map.local_def_id(impl_item.id)
-                    }).collect())
+                hir::ItemImpl(.., ref impl_item_refs) => {
+                    impl_item_refs.iter()
+                                  .map(|impl_item_ref| impl_item_ref.id)
+                                  .map(|id| self.map.local_def_id(id.node_id))
+                                  .collect()
                 }
                 _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
-            }
+            };
+            Rc::new(vec)
         })
     }
 
@@ -2695,12 +2737,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
     }
 
-    pub fn visit_all_items_in_krate<V,F>(self,
-                                         dep_node_fn: F,
-                                         visitor: &mut V)
-        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'gcx>
+    pub fn visit_all_item_likes_in_krate<V,F>(self,
+                                              dep_node_fn: F,
+                                              visitor: &mut V)
+        where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'gcx>
     {
-        dep_graph::visit_all_items_in_krate(self.global_tcx(), dep_node_fn, visitor);
+        dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
     }
 
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 23765608792..5e54e333bb9 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -110,7 +110,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         }
     };
 
-    tcx.visit_all_items_in_krate(DepNode::BorrowCheck, &mut bccx);
+    tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor());
 
     if tcx.sess.borrowck_stats() {
         println!("--- borrowck stats ---");
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index e0e8a215919..f63a27e0d75 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -78,7 +78,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx });
+    tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck,
+                                      &mut OuterVisitor { tcx: tcx }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs
index ea7621e16e7..4db620b2bec 100644
--- a/src/librustc_driver/derive_registrar.rs
+++ b/src/librustc_driver/derive_registrar.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::dep_graph::DepNode;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map::Map;
 use rustc::hir;
 use syntax::ast;
@@ -20,7 +20,7 @@ pub fn find(hir_map: &Map) -> Option<ast::NodeId> {
     let krate = hir_map.krate();
 
     let mut finder = Finder { registrar: None };
-    krate.visit_all_items(&mut finder);
+    krate.visit_all_item_likes(&mut finder);
     finder.registrar
 }
 
@@ -28,10 +28,14 @@ struct Finder {
     registrar: Option<ast::NodeId>,
 }
 
-impl<'v> Visitor<'v> for Finder {
+impl<'v> ItemLikeVisitor<'v> for Finder {
     fn visit_item(&mut self, item: &hir::Item) {
         if attr::contains_name(&item.attrs, "rustc_derive_registrar") {
             self.registrar = Some(item.id);
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
+
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 37477da755c..998cbae2cce 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -51,7 +51,7 @@ use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use graphviz::IntoCow;
 use std::env;
 use std::fs::File;
@@ -81,7 +81,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
                                           if_this_changed: vec![],
                                           then_this_would_need: vec![] };
         visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs);
-        tcx.map.krate().visit_all_items(&mut visitor);
+        tcx.map.krate().visit_all_item_likes(&mut visitor);
         (visitor.if_this_changed, visitor.then_this_would_need)
     };
 
@@ -167,10 +167,14 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.process_attrs(item.id, &item.attrs);
     }
+
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+        self.process_attrs(impl_item.id, &impl_item.attrs);
+    }
 }
 
 fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index 58a21529974..c08519090d2 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -34,6 +34,7 @@ use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit as visit;
+use rustc::hir::intravisit::Visitor;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
@@ -107,7 +108,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
     record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
         visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX),
                                  |v| visit::walk_crate(v, krate));
-        krate.visit_all_items(&mut visitor);
+        // FIXME(#37713) if foreign items were item likes, could use ItemLikeVisitor
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
     });
 
     tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
@@ -199,12 +201,17 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
 }
 
 
-impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.calculate_node_id(item.id, |v| v.visit_item(item));
         visit::walk_item(self, item);
     }
 
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
+        visit::walk_impl_item(self, impl_item);
+    }
+
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
         self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
         visit::walk_foreign_item(self, item);
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 0b0dd596784..fa2eff817ea 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -199,6 +199,8 @@ enum SawAbiComponent<'a> {
     SawExpr(SawExprComponent<'a>),
     SawStmt,
     SawVis,
+    SawAssociatedItemKind(hir::AssociatedItemKind),
+    SawDefaultness(hir::Defaultness),
     SawWherePredicate,
     SawTyParamBound,
     SawPolyTraitRef,
@@ -499,10 +501,6 @@ macro_rules! hash_span {
 }
 
 impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn visit_nested_item(&mut self, _: ItemId) {
-        // Each item is hashed independently; ignore nested items.
-    }
-
     fn visit_variant_data(&mut self,
                           s: &'tcx VariantData,
                           name: Name,
@@ -697,6 +695,18 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         visit::walk_vis(self, v)
     }
 
+    fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) {
+        debug!("visit_associated_item_kind: st={:?}", self.st);
+        SawAssociatedItemKind(*kind).hash(self.st);
+        visit::walk_associated_item_kind(self, kind);
+    }
+
+    fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) {
+        debug!("visit_associated_item_kind: st={:?}", self.st);
+        SawDefaultness(*defaultness).hash(self.st);
+        visit::walk_defaultness(self, defaultness);
+    }
+
     fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) {
         debug!("visit_where_predicate: st={:?}", self.st);
         SawWherePredicate.hash(self.st);
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 69b9be12de4..0cd1c88fb87 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -45,7 +45,7 @@ use super::load::DirtyNodes;
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use syntax::ast::{self, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use syntax::parse::token::InternedString;
@@ -74,7 +74,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let query = tcx.dep_graph.query();
     debug!("query-nodes: {:?}", query.nodes());
     let krate = tcx.map.krate();
-    krate.visit_all_items(&mut DirtyCleanVisitor {
+    krate.visit_all_item_likes(&mut DirtyCleanVisitor {
         tcx: tcx,
         query: &query,
         dirty_inputs: dirty_inputs,
@@ -169,7 +169,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
         for attr in self.tcx.get_attrs(def_id).iter() {
@@ -184,6 +184,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -195,7 +198,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     tcx.dep_graph.with_ignore(||{
         let krate = tcx.map.krate();
-        krate.visit_all_items(&mut DirtyCleanMetadataVisitor {
+        krate.visit_all_item_likes(&mut DirtyCleanMetadataVisitor {
             tcx: tcx,
             prev_metadata_hashes: prev_metadata_hashes,
             current_metadata_hashes: current_metadata_hashes,
@@ -209,7 +212,7 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
     current_metadata_hashes: &'m FxHashMap<DefId, Fingerprint>,
 }
 
-impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
+impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
 
@@ -225,6 +228,9 @@ impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 223200957cb..2572a9c1d78 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -201,6 +201,19 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
     debug!("crate-dir: {}", crate_dir.display());
     try!(create_dir(tcx.sess, &crate_dir, "crate"));
 
+    // Hack: canonicalize the path *after creating the directory*
+    // because, on windows, long paths can cause problems;
+    // canonicalization inserts this weird prefix that makes windows
+    // tolerate long paths.
+    let crate_dir = match crate_dir.canonicalize() {
+        Ok(v) => v,
+        Err(err) => {
+            tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
+                                  crate_dir.display(), err));
+            return Err(());
+        }
+    };
+
     let mut source_directories_already_tried = FxHashSet();
 
     loop {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f6b6c89b7cc..51ffb1ebc8e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -387,7 +387,7 @@ impl LateLintPass for MissingDoc {
                 "a trait"
             }
             hir::ItemTy(..) => "a type alias",
-            hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
+            hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
                 let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
@@ -395,8 +395,8 @@ impl LateLintPass for MissingDoc {
                     match cx.tcx.map.find(node_id) {
                         Some(hir_map::NodeItem(item)) => {
                             if item.vis == hir::Visibility::Inherited {
-                                for itm in impl_items {
-                                    self.private_traits.insert(itm.id);
+                                for impl_item_ref in impl_item_refs {
+                                    self.private_traits.insert(impl_item_ref.id.node_id);
                                 }
                             }
                         }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 79c90a04b37..3af9d291ae5 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -850,7 +850,6 @@ impl<'a, 'tcx> CrateMetadata {
                     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),
                     method_has_self_argument: false
@@ -864,7 +863,6 @@ impl<'a, 'tcx> CrateMetadata {
                     kind: ty::AssociatedKind::Method,
                     vis: item.visibility,
                     defaultness: data.container.defaultness(),
-                    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
@@ -877,7 +875,6 @@ impl<'a, 'tcx> CrateMetadata {
                     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
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 823c50e1e5f..3ab542442a1 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -38,6 +38,7 @@ use syntax;
 use syntax_pos;
 
 use rustc::hir::{self, PatKind};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit::Visitor;
 use rustc::hir::intravisit;
 
@@ -459,10 +460,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let ast_item = tcx.map.expect_trait_item(node_id);
         let trait_item = tcx.associated_item(def_id);
 
-        let container = if trait_item.has_value {
-            AssociatedContainer::TraitWithDefault
-        } else {
-            AssociatedContainer::TraitRequired
+        let container = match trait_item.defaultness {
+            hir::Defaultness::Default { has_value: true } =>
+                AssociatedContainer::TraitWithDefault,
+            hir::Defaultness::Default { has_value: false } =>
+                AssociatedContainer::TraitRequired,
+            hir::Defaultness::Final =>
+                span_bug!(ast_item.span, "traits cannot have final items"),
         };
 
         let kind = match trait_item.kind {
@@ -500,7 +504,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     Some(self.encode_item_type(def_id))
                 }
                 ty::AssociatedKind::Type => {
-                    if trait_item.has_value {
+                    if trait_item.defaultness.has_value() {
                         Some(self.encode_item_type(def_id))
                     } else {
                         None
@@ -529,8 +533,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let impl_def_id = impl_item.container.id();
 
         let container = match impl_item.defaultness {
-            hir::Defaultness::Default => AssociatedContainer::ImplDefault,
+            hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
             hir::Defaultness::Final => AssociatedContainer::ImplFinal,
+            hir::Defaultness::Default { has_value: false } =>
+                span_bug!(ast_item.span, "impl items always have values (currently)"),
         };
 
         let kind = match impl_item.kind {
@@ -1074,7 +1080,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                      EncodeContext::encode_info_for_mod,
                      FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
         let mut visitor = EncodeVisitor { index: index };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
         for macro_def in &krate.exported_macros {
             visitor.visit_macro_def(macro_def);
         }
@@ -1159,7 +1165,7 @@ struct ImplVisitor<'a, 'tcx: 'a> {
     impls: FxHashMap<DefId, Vec<DefIndex>>,
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let hir::ItemImpl(..) = item.node {
             let impl_id = self.tcx.map.local_def_id(item.id);
@@ -1171,6 +1177,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
+        // handled in `visit_item` above
+    }
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
@@ -1180,7 +1190,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             tcx: self.tcx,
             impls: FxHashMap(),
         };
-        self.tcx.map.krate().visit_all_items(&mut visitor);
+        self.tcx.map.krate().visit_all_item_likes(&mut visitor);
 
         let all_impls: Vec<_> = visitor.impls
             .into_iter()
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 5292a4a7c37..32c8c5e2ee8 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -310,21 +310,16 @@ impl AssociatedContainer {
         }
     }
 
-    pub fn has_value(&self) -> bool {
-        match *self {
-            AssociatedContainer::TraitRequired => false,
-
-            AssociatedContainer::TraitWithDefault |
-            AssociatedContainer::ImplDefault |
-            AssociatedContainer::ImplFinal => true,
-        }
-    }
-
     pub fn defaultness(&self) -> hir::Defaultness {
         match *self {
-            AssociatedContainer::TraitRequired |
+            AssociatedContainer::TraitRequired => hir::Defaultness::Default {
+                has_value: false,
+            },
+
             AssociatedContainer::TraitWithDefault |
-            AssociatedContainer::ImplDefault => hir::Defaultness::Default,
+            AssociatedContainer::ImplDefault => hir::Defaultness::Default {
+                has_value: true,
+            },
 
             AssociatedContainer::ImplFinal => hir::Defaultness::Final,
         }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 4a50585efe3..992c0e9b5fc 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -38,9 +38,9 @@ use syntax_pos::Span;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir {
+    tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir {
         tcx: tcx
-    });
+    }.as_deep_visitor());
 }
 
 /// A pass to lift all the types and substitutions in a Mir
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index b33a7060e37..4ff2beb3fdb 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -277,8 +277,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                             .and_then(|impl_node_id| self.tcx.map.find(impl_node_id))
                             .map(|node| {
                                 if let hir_map::NodeItem(item) = node {
-                                    if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node {
-                                        span = methods.first().map(|method| method.span);
+                                    if let hir::ItemImpl(.., ref impl_item_refs) = item.node {
+                                        span = impl_item_refs.first()
+                                                             .map(|iiref| {
+                                                                 self.tcx.map.impl_item(iiref.id)
+                                                                             .span
+                                                             });
                                     }
                                 }
                             });
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 02a0b3ab28d..5df8accd8ce 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -644,13 +644,13 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::CheckConst,
-                                 &mut CheckCrateVisitor {
-                                     tcx: tcx,
-                                     mode: Mode::Var,
-                                     qualif: ConstQualif::NOT_CONST,
-                                     rvalue_borrows: NodeMap(),
-                                 });
+    tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
+                                      &mut CheckCrateVisitor {
+                                          tcx: tcx,
+                                          mode: Mode::Var,
+                                          qualif: ConstQualif::NOT_CONST,
+                                          rvalue_borrows: NodeMap(),
+                                      }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 417987d9664..3bdaf276b40 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -106,12 +106,20 @@ impl<'k> StatCollector<'k> {
 }
 
 impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
+        panic!("visit_nested_xxx must be manually implemented in this visitor")
+    }
 
     fn visit_nested_item(&mut self, id: hir::ItemId) {
         let nested_item = self.krate.unwrap().item(id.id);
         self.visit_item(nested_item)
     }
 
+    fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
+        let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
+        self.visit_impl_item(nested_impl_item)
+    }
+
     fn visit_item(&mut self, i: &'v hir::Item) {
         self.record("Item", Id::Node(i.id), i);
         hir_visit::walk_item(self, i)
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index e58cd893819..724100e0223 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -33,10 +33,10 @@ struct CheckLoopVisitor<'a> {
 pub fn check_crate(sess: &Session, map: &Map) {
     let _task = map.dep_graph.in_task(DepNode::CheckLoops);
     let krate = map.krate();
-    krate.visit_all_items(&mut CheckLoopVisitor {
+    krate.visit_all_item_likes(&mut CheckLoopVisitor {
         sess: sess,
         cx: Normal,
-    });
+    }.as_deep_visitor());
 }
 
 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
@@ -44,6 +44,10 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
         self.with_context(Normal, |v| intravisit::walk_item(v, i));
     }
 
+    fn visit_impl_item(&mut self, i: &hir::ImplItem) {
+        self.with_context(Normal, |v| intravisit::walk_impl_item(v, i));
+    }
+
     fn visit_expr(&mut self, e: &hir::Expr) {
         match e.node {
             hir::ExprWhile(ref e, ref b, _) => {
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index d55ce4c3563..7386be2528c 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -18,20 +18,20 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment};
 use rustc::traits::Reveal;
 
 use rustc::hir;
-use rustc::hir::intravisit;
+use rustc::hir::intravisit::{self, Visitor};
 use syntax::ast;
 use syntax_pos::Span;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut rvcx = RvalueContext { tcx: tcx };
-    tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
+    tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
 }
 
 struct RvalueContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index 0e0f8a84567..5f76f865c4a 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -100,7 +100,8 @@ pub fn check_crate<'ast>(sess: &Session,
         discriminant_map: RefCell::new(NodeMap()),
     };
     sess.track_errors(|| {
-        ast_map.krate().visit_all_items(&mut visitor);
+        // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+        ast_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
     })
 }
 
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
index ff3038c3d11..75046f6aeb8 100644
--- a/src/librustc_plugin/build.rs
+++ b/src/librustc_plugin/build.rs
@@ -16,14 +16,14 @@ use errors;
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::Map;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
 
 struct RegistrarFinder {
     registrars: Vec<(ast::NodeId, Span)> ,
 }
 
-impl<'v> Visitor<'v> for RegistrarFinder {
+impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
     fn visit_item(&mut self, item: &hir::Item) {
         if let hir::ItemFn(..) = item.node {
             if attr::contains_name(&item.attrs,
@@ -32,6 +32,9 @@ impl<'v> Visitor<'v> for RegistrarFinder {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 /// Find the function marked with `#[plugin_registrar]`, if any.
@@ -42,7 +45,7 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler,
     let krate = hir_map.krate();
 
     let mut finder = RegistrarFinder { registrars: Vec::new() };
-    krate.visit_all_items(&mut finder);
+    krate.visit_all_item_likes(&mut finder);
 
     match finder.registrars.len() {
         0 => None,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index dc7399e2289..b116408269e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -31,6 +31,7 @@ use rustc::hir::{self, PatKind};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
@@ -115,15 +116,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         let inherited_item_level = match item.node {
             // Impls inherit level from their types and traits
             hir::ItemImpl(.., None, ref ty, _) => {
@@ -158,15 +158,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ItemImpl(.., None, _, ref impl_items) => {
-                for impl_item in impl_items {
+            hir::ItemImpl(.., None, _, ref impl_item_refs) => {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                     if impl_item.vis == hir::Public {
                         self.update(impl_item.id, item_level);
                     }
                 }
             }
-            hir::ItemImpl(.., Some(_), _, ref impl_items) => {
-                for impl_item in impl_items {
+            hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                     self.update(impl_item.id, item_level);
                 }
             }
@@ -249,11 +251,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             // The interface is empty
             hir::ItemDefaultImpl(..) => {}
             // Visit everything except for private impl items
-            hir::ItemImpl(.., ref generics, None, _, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => {
                 if item_level.is_some() {
                     self.reach().visit_generics(generics);
-                    for impl_item in impl_items {
-                        if self.get(impl_item.id).is_some() {
+                    for impl_item_ref in impl_item_refs {
+                        if self.get(impl_item_ref.id.node_id).is_some() {
+                            let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                             self.reach().visit_impl_item(impl_item);
                         }
                     }
@@ -269,7 +272,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
         self.prev_level = orig_level;
     }
 
-    fn visit_block(&mut self, b: &'v hir::Block) {
+    fn visit_block(&mut self, b: &'tcx hir::Block) {
         let orig_level = replace(&mut self.prev_level, None);
 
         // Blocks can have public items, for example impls, but they always
@@ -280,7 +283,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
         self.prev_level = orig_level;
     }
 
-    fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
+    fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: ast::NodeId) {
         // This code is here instead of in visit_item so that the
         // crate module gets processed as well.
         if self.prev_level.is_some() {
@@ -296,14 +299,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
         intravisit::walk_mod(self, m, id);
     }
 
-    fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
+    fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
         self.update(md.id, Some(AccessLevel::Public));
     }
 }
 
 impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     // Make the type hidden under a type alias reachable
-    fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
+    fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) {
         if let hir::ItemTy(ref ty, ref generics) = item.node {
             // See `fn is_public_type_alias` for details
             self.visit_ty(ty);
@@ -317,8 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     }
 }
 
-impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
-    fn visit_ty(&mut self, ty: &hir::Ty) {
+impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
+    fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
+        // when we visit an impl, its methods and items are part of its "interface"
+        let impl_item = self.ev.tcx.map.impl_item(item_id);
+        self.visit_impl_item(impl_item)
+    }
+
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         if let hir::TyPath(_, ref path) = ty.node {
             let def = self.ev.tcx.expect_def(ty.id);
             match def {
@@ -350,7 +359,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
         intravisit::walk_ty(self, ty);
     }
 
-    fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
+    fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
         let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
         if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
             let item = self.ev.tcx.map.expect_item(node_id);
@@ -412,21 +421,20 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         let orig_curitem = replace(&mut self.curitem, item.id);
         intravisit::walk_item(self, item);
         self.curitem = orig_curitem;
     }
 
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
@@ -486,7 +494,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
-    fn visit_pat(&mut self, pattern: &hir::Pat) {
+    fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
         // Foreign functions do not have their patterns mapped in the def_map,
         // and there's nothing really relevant there anyway, so don't bother
         // checking privacy. If you can name the type then you can pass it to an
@@ -522,7 +530,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
         intravisit::walk_pat(self, pattern);
     }
 
-    fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
         self.in_foreign = true;
         intravisit::walk_foreign_item(self, fi);
         self.in_foreign = false;
@@ -616,15 +624,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a
     fn visit_expr(&mut self, _: &hir::Expr) {}
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn visit_nested_item(&mut self, item: hir::ItemId) {
-        let tcx = self.tcx;
-        self.visit_item(tcx.map.expect_item(item.id))
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
+        Some(&self.tcx.map)
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             // contents of a private mod can be reexported, so we need
             // to check internals.
@@ -649,7 +656,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
             // (i.e. we could just return here to not check them at
             // all, or some worse estimation of whether an impl is
             // publicly visible).
-            hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => {
+            hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => {
                 // `impl [... for] Private` is never visible.
                 let self_contains_private;
                 // impl [... for] Public<...>, but not `impl [... for]
@@ -694,16 +701,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
                 // are private (because `T` won't be visible externally).
                 let trait_or_some_public_method =
                     trait_ref.is_some() ||
-                    impl_items.iter()
-                              .any(|impl_item| {
-                                  match impl_item.node {
-                                      hir::ImplItemKind::Const(..) |
-                                      hir::ImplItemKind::Method(..) => {
-                                          self.access_levels.is_reachable(impl_item.id)
-                                      }
-                                      hir::ImplItemKind::Type(_) => false,
-                                  }
-                              });
+                    impl_item_refs.iter()
+                                 .any(|impl_item_ref| {
+                                     let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
+                                     match impl_item.node {
+                                         hir::ImplItemKind::Const(..) |
+                                         hir::ImplItemKind::Method(..) => {
+                                             self.access_levels.is_reachable(impl_item.id)
+                                         }
+                                         hir::ImplItemKind::Type(_) => false,
+                                     }
+                                 });
 
                 if !self_contains_private &&
                         not_private_trait &&
@@ -713,12 +721,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
 
                     match *trait_ref {
                         None => {
-                            for impl_item in impl_items {
+                            for impl_item_ref in impl_item_refs {
                                 // This is where we choose whether to walk down
                                 // further into the impl to check its items. We
                                 // should only walk into public items so that we
                                 // don't erroneously report errors for private
                                 // types in private items.
+                                let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                                 match impl_item.node {
                                     hir::ImplItemKind::Const(..) |
                                     hir::ImplItemKind::Method(..)
@@ -750,7 +759,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
                             intravisit::walk_path(self, &tr.path);
 
                             // Those in 3. are warned with this call.
-                            for impl_item in impl_items {
+                            for impl_item_ref in impl_item_refs {
+                                let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                                 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
                                     self.visit_ty(ty);
                                 }
@@ -761,7 +771,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
                     // impl Public<Private> { ... }. Any public static
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
-                    for impl_item in impl_items {
+                    for impl_item_ref in impl_item_refs {
+                        let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                         match impl_item.node {
                             hir::ImplItemKind::Const(..) => {
                                 if self.item_is_public(&impl_item.id, &impl_item.vis) {
@@ -805,7 +816,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
         intravisit::walk_item(self, item);
     }
 
-    fn visit_generics(&mut self, generics: &hir::Generics) {
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
         for ty_param in generics.ty_params.iter() {
             for bound in ty_param.bounds.iter() {
                 self.check_ty_param_bound(bound)
@@ -826,13 +837,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
         }
     }
 
-    fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
         if self.access_levels.is_reachable(item.id) {
             intravisit::walk_foreign_item(self, item)
         }
     }
 
-    fn visit_ty(&mut self, t: &hir::Ty) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         if let hir::TyPath(..) = t.node {
             if self.path_is_private_type(t.id) {
                 self.old_error_set.insert(t.id);
@@ -841,7 +852,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
         intravisit::walk_ty(self, t)
     }
 
-    fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
+    fn visit_variant(&mut self,
+                     v: &'tcx hir::Variant,
+                     g: &'tcx hir::Generics,
+                     item_id: ast::NodeId) {
         if self.access_levels.is_reachable(v.node.data.id()) {
             self.in_variant = true;
             intravisit::walk_variant(self, v, g, item_id);
@@ -849,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
         }
     }
 
-    fn visit_struct_field(&mut self, s: &hir::StructField) {
+    fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
         if s.vis == hir::Public || self.in_variant {
             intravisit::walk_struct_field(self, s);
         }
@@ -859,8 +873,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
     // expression/block context can't possibly contain exported things.
     // (Making them no-ops stops us from traversing the whole AST without
     // having to be super careful about our `walk_...` calls above.)
-    fn visit_block(&mut self, _: &hir::Block) {}
-    fn visit_expr(&mut self, _: &hir::Expr) {}
+    fn visit_block(&mut self, _: &'tcx hir::Block) {}
+    fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1039,7 +1053,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let min = |vis1: ty::Visibility, vis2| {
             if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 }
@@ -1085,12 +1099,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             hir::ItemDefaultImpl(..) => {}
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity
-            hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, ref ty, ref impl_item_refs) => {
                 let ty_vis = self.ty_visibility(ty);
                 check.required_visibility = ty_vis;
                 check.visit_generics(generics);
 
-                for impl_item in impl_items {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                     let impl_item_vis =
                         ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx);
                     check.required_visibility = min(impl_item_vis, ty_vis);
@@ -1099,16 +1114,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             }
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity
-            hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_item_refs) => {
                 let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref));
                 check.required_visibility = vis;
                 check.visit_generics(generics);
-                for impl_item in impl_items {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
                     check.visit_impl_item(impl_item);
                 }
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
+        // handled in `visit_item` above
+    }
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1161,7 +1181,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             tcx: tcx,
             old_error_set: &visitor.old_error_set,
         };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor);
     }
 
     visitor.access_levels
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 4fb11509a1c..778f0184141 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -536,7 +536,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 let def_id = if decl_id.is_local() {
                     let ti = self.tcx.associated_item(decl_id);
                     self.tcx.associated_items(ti.container.id())
-                        .find(|item| item.name == ti.name && item.has_value)
+                        .find(|item| item.name == ti.name && item.defaultness.has_value())
                         .map(|item| item.def_id)
                 } else {
                     None
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index faf65f3f98b..df56e27128c 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -600,13 +600,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // reference. It also occurs when testing libcore and in some
     // other weird situations. Annoying.
 
-    let fn_ptr_ty = match fn_ty.sty {
-        ty::TyFnDef(.., fty) => {
-            // Create a fn pointer with the substituted signature.
-            tcx.mk_fn_ptr(fty)
-        }
-        _ => bug!("expected fn item type, found {}", fn_ty)
-    };
+    // Create a fn pointer with the substituted signature.
+    let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 0fc6436e63c..5902b0b1ce0 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -189,7 +189,7 @@
 //! regardless of whether it is actually needed or not.
 
 use rustc::hir;
-use rustc::hir::intravisit as hir_visit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
@@ -306,10 +306,9 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             scx: scx,
             mode: mode,
             output: &mut roots,
-            enclosing_item: None,
         };
 
-        scx.tcx().map.krate().visit_all_items(&mut visitor);
+        scx.tcx().map.krate().visit_all_item_likes(&mut visitor);
     }
 
     roots
@@ -1030,14 +1029,10 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> {
     scx: &'b SharedCrateContext<'a, 'tcx>,
     mode: TransItemCollectionMode,
     output: &'b mut Vec<TransItem<'tcx>>,
-    enclosing_item: Option<&'tcx hir::Item>,
 }
 
-impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
+impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
     fn visit_item(&mut self, item: &'v hir::Item) {
-        let old_enclosing_item = self.enclosing_item;
-        self.enclosing_item = Some(item);
-
         match item.node {
             hir::ItemExternCrate(..) |
             hir::ItemUse(..)         |
@@ -1094,9 +1089,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 }
             }
         }
-
-        hir_visit::walk_item(self, item);
-        self.enclosing_item = old_enclosing_item;
     }
 
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
@@ -1131,8 +1123,6 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
             }
             _ => { /* Nothing to do here */ }
         }
-
-        hir_visit::walk_impl_item(self, ii)
     }
 }
 
@@ -1145,7 +1135,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
                       _,
                       ref generics,
                       ..,
-                      ref items) => {
+                      ref impl_item_refs) => {
             if generics.is_type_parameterized() {
                 return
             }
@@ -1157,9 +1147,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
 
             if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
                 let callee_substs = tcx.erase_regions(&trait_ref.substs);
-                let overridden_methods: FxHashSet<_> = items.iter()
-                                                            .map(|item| item.name)
-                                                            .collect();
+                let overridden_methods: FxHashSet<_> =
+                    impl_item_refs.iter()
+                                  .map(|iiref| iiref.name)
+                                  .collect();
                 for method in tcx.provided_trait_methods(trait_ref.def_id) {
                     if overridden_methods.contains(&method.name) {
                         continue;
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index 25c30151ad4..aa23a181722 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -35,7 +35,8 @@ pub fn report_symbol_names(scx: &SharedCrateContext) {
 
     let _ignore = tcx.dep_graph.in_ignore();
     let mut visitor = SymbolNamesTest { scx: scx };
-    tcx.map.krate().visit_all_items(&mut visitor);
+    // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+    tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
 
 struct SymbolNamesTest<'a, 'tcx:'a> {
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 720423371a8..f08d26373e5 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -18,6 +18,7 @@ rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
+rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index d15795730a8..4ae15740cf2 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -439,7 +439,7 @@ impl Ord for TraitInfo {
 /// Retrieve all traits in this crate and any dependent crates.
 pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
     if ccx.all_traits.borrow().is_none() {
-        use rustc::hir::intravisit;
+        use rustc::hir::itemlikevisit;
 
         let mut traits = vec![];
 
@@ -450,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
             map: &'a hir_map::Map<'tcx>,
             traits: &'a mut AllTraitsVec,
         }
-        impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> {
+        impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
             fn visit_item(&mut self, i: &'v hir::Item) {
                 match i.node {
                     hir::ItemTrait(..) => {
@@ -460,8 +460,11 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
                     _ => {}
                 }
             }
+
+            fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+            }
         }
-        ccx.tcx.map.krate().visit_all_items(&mut Visitor {
+        ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor {
             map: &ccx.tcx.map,
             traits: &mut traits,
         });
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8e9dfe54f01..f08178e49fb 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -121,6 +121,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{self, BytePos, Span};
 
 use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
 use rustc_back::slice;
@@ -525,30 +526,35 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_body(self.ccx, i);
     }
+
+    fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
+        // done as part of `visit_item` above
+    }
 }
 
 pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
-        ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
     })
 }
 
 pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = CheckItemTypesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
+                                              &mut visit.as_deep_visitor());
     })
 }
 
 pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = CheckItemBodiesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemBody, &mut visit);
 
         // Process deferred obligations, now that all functions
         // bodies have been fully inferred.
@@ -809,7 +815,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                             it.id);
       }
       hir::ItemFn(..) => {} // entirely within check_item_body
-      hir::ItemImpl(.., ref impl_items) => {
+      hir::ItemImpl(.., ref impl_item_refs) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) {
@@ -817,7 +823,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                                              it.span,
                                              impl_def_id,
                                              impl_trait_ref,
-                                             impl_items);
+                                             impl_item_refs);
               let trait_def_id = impl_trait_ref.def_id;
               check_on_unimplemented(ccx, trait_def_id, it);
           }
@@ -879,10 +885,11 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemFn(ref decl, .., ref body) => {
         check_bare_fn(ccx, &decl, &body, it.id, it.span);
       }
-      hir::ItemImpl(.., ref impl_items) => {
+      hir::ItemImpl(.., ref impl_item_refs) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
 
-        for impl_item in impl_items {
+        for impl_item_ref in impl_item_refs {
+            let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
             match impl_item.node {
                 hir::ImplItemKind::Const(_, ref expr) => {
                     check_const(ccx, &expr, impl_item.id)
@@ -1019,7 +1026,7 @@ 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_items: &[hir::ImplItem]) {
+                                            impl_item_refs: &[hir::ImplItemRef]) {
     // 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`
     // isn't populated for such impls.
@@ -1030,9 +1037,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
     let mut overridden_associated_type = None;
 
+    let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.map.impl_item(iiref.id));
+
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
-    for impl_item in impl_items {
+    for impl_item in impl_items() {
         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);
@@ -1101,7 +1110,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 }
                 hir::ImplItemKind::Type(_) => {
                     if ty_trait_item.kind == ty::AssociatedKind::Type {
-                        if ty_trait_item.has_value {
+                        if ty_trait_item.defaultness.has_value() {
                             overridden_associated_type = Some(impl_item);
                         }
                     } else {
@@ -1135,7 +1144,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             .unwrap_or(false);
 
         if !is_implemented {
-            if !trait_item.has_value {
+            if !trait_item.defaultness.has_value() {
                 missing_items.push(trait_item);
             } else if associated_type_overridden {
                 invalidated_items.push(trait_item.name);
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 41bea187416..1ad81660f83 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -203,7 +203,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                                                free_id_outlive, self_ty);
                 }
                 ty::AssociatedKind::Type => {
-                    if item.has_value {
+                    if item.defaultness.has_value() {
                         let ty = fcx.tcx.item_type(item.def_id);
                         let ty = fcx.instantiate_type_scheme(span, free_substs, &ty);
                         fcx.register_wf_obligation(ty, span, code.clone());
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 7e41a672bf3..b4a10c52270 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -16,7 +16,7 @@ use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 struct UnusedTraitImportVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -40,7 +40,7 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if item.vis == hir::Public || item.span == DUMMY_SP {
             return;
@@ -58,10 +58,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
             }
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck);
     let mut visitor = UnusedTraitImportVisitor { tcx: tcx };
-    tcx.map.krate().visit_all_items(&mut visitor);
+    tcx.map.krate().visit_all_item_likes(&mut visitor);
 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 7c860bc5aec..2663739e36b 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -34,7 +34,7 @@ use rustc::infer::{self, InferCtxt};
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{Item, ItemImpl};
 use rustc::hir;
 
@@ -51,12 +51,15 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
             self.cc.check_implementation(item)
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
@@ -87,8 +90,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
-                                                        &mut CoherenceCheckVisitor { cc: self });
+        self.crate_context.tcx.visit_all_item_likes_in_krate(
+            DepNode::CoherenceCheckImpl,
+            &mut CoherenceCheckVisitor { cc: self });
 
         // Populate the table of destructors. It might seem a bit strange to
         // do this here, but it's actually the most convenient place, since
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 371c182030e..a507077bef7 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -17,12 +17,12 @@ use rustc::ty::{self, TyCtxt};
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut orphan = OrphanChecker { tcx: tcx };
-    tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
 }
 
 struct OrphanChecker<'cx, 'tcx: 'cx> {
@@ -380,8 +380,12 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         self.check_item(item);
     }
+
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index df3a79f09bd..e5be7f63067 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt, TypeFoldable};
 use syntax::ast;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use util::nodemap::DefIdMap;
 use lint;
 
@@ -30,7 +30,7 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
-    tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
 }
 
 struct OverlapChecker<'cx, 'tcx: 'cx> {
@@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemEnum(..) |
@@ -205,4 +205,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
             _ => {}
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index cca6c884306..6d5de8f2506 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -12,12 +12,12 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc::ty::TyCtxt;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, Unsafety};
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut orphan = UnsafetyChecker { tcx: tcx };
-    tcx.map.krate().visit_all_items(&mut orphan);
+    let mut unsafety = UnsafetyChecker { tcx: tcx };
+    tcx.map.krate().visit_all_item_likes(&mut unsafety);
 }
 
 struct UnsafetyChecker<'cx, 'tcx: 'cx> {
@@ -94,7 +94,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemDefaultImpl(unsafety, _) => {
@@ -106,4 +106,7 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
             _ => {}
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 816243b3eab..535b6bcdcba 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -77,13 +77,13 @@ use CrateCtxt;
 use rustc_const_math::ConstInt;
 
 use std::cell::RefCell;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax::{abi, ast, attr};
 use syntax::parse::token::{self, keywords};
 use syntax_pos::Span;
 
-use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
+use rustc::hir::{self, map as hir_map, print as pprust};
+use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 
@@ -92,7 +92,7 @@ use rustc::hir::def_id::DefId;
 
 pub fn collect_item_types(ccx: &CrateCtxt) {
     let mut visitor = CollectItemTypesVisitor { ccx: ccx };
-    ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor);
+    ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -128,7 +128,7 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         convert_item(self.ccx, item);
         intravisit::walk_item(self, item);
@@ -148,6 +148,11 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx>
         }
         intravisit::walk_ty(self, ty);
     }
+
+    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+        convert_impl_item(self.ccx, impl_item);
+        intravisit::walk_impl_item(self, impl_item);
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -726,7 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                       ref generics,
                       ref opt_trait_ref,
                       ref selfty,
-                      ref impl_items) => {
+                      _) => {
             // Create generics from the generics specified in the impl head.
             debug!("convert: ast_generics={:?}", generics);
             let def_id = ccx.tcx.map.local_def_id(it.id);
@@ -747,73 +752,16 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             });
             tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
 
-            enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id);
-            tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
-
-
-            // Convert all the associated consts.
-            // Also, check if there are any duplicate associated items
-            let mut seen_type_items = FxHashMap();
-            let mut seen_value_items = FxHashMap();
-
-            for impl_item in impl_items {
-                let seen_items = match impl_item.node {
-                    hir::ImplItemKind::Type(_) => &mut seen_type_items,
-                    _                    => &mut seen_value_items,
-                };
-                match seen_items.entry(impl_item.name) {
-                    Occupied(entry) => {
-                        let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
-                                                       "duplicate definitions with name `{}`:",
-                                                       impl_item.name);
-                        err.span_label(*entry.get(),
-                                   &format!("previous definition of `{}` here",
-                                        impl_item.name));
-                        err.span_label(impl_item.span, &format!("duplicate definition"));
-                        err.emit();
-                    }
-                    Vacant(entry) => {
-                        entry.insert(impl_item.span);
-                    }
-                }
-
-                if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node {
-                    let const_def_id = ccx.tcx.map.local_def_id(impl_item.id);
-                    generics_of_def_id(ccx, const_def_id);
-                    let ty = ccx.icx(&ty_predicates)
-                                .to_ty(&ExplicitRscope, &ty);
-                    tcx.item_types.borrow_mut().insert(const_def_id, ty);
-                    convert_associated_const(ccx, ImplContainer(def_id),
-                                             impl_item.id, ty);
-                }
-            }
-
-            // Convert all the associated types.
-            for impl_item in impl_items {
-                if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
-                    let type_def_id = ccx.tcx.map.local_def_id(impl_item.id);
-                    generics_of_def_id(ccx, type_def_id);
-
-                    if opt_trait_ref.is_none() {
-                        span_err!(tcx.sess, impl_item.span, E0202,
-                                  "associated types are not allowed in inherent impls");
-                    }
-
-                    let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
-
-                    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 {
-                    convert_method(ccx, ImplContainer(def_id),
-                                   impl_item.id, sig, selfty,
-                                   &ty_predicates);
-                }
-            }
+            // Subtle: before we store the predicates into the tcx, we
+            // sort them so that predicates like `T: Foo<Item=U>` come
+            // before uses of `U`.  This avoids false ambiguity errors
+            // in trait checking. See `setup_constraining_predicates`
+            // for details.
+            ctp::setup_constraining_predicates(&mut ty_predicates.predicates,
+                                               trait_ref,
+                                               &mut ctp::parameters_for_impl(selfty, trait_ref));
 
-            enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items);
+            tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
         },
         hir::ItemTrait(.., ref trait_items) => {
             let trait_def = trait_def_of_item(ccx, it);
@@ -899,6 +847,49 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
     }
 }
 
+fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
+    let tcx = ccx.tcx;
+
+    // we can lookup details about the impl because items are visited
+    // before impl-items
+    let impl_def_id = tcx.map.get_parent_did(impl_item.id);
+    let impl_predicates = tcx.item_predicates(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+    let impl_self_ty = tcx.item_type(impl_def_id);
+
+    match impl_item.node {
+        hir::ImplItemKind::Const(ref ty, _) => {
+            let const_def_id = ccx.tcx.map.local_def_id(impl_item.id);
+            generics_of_def_id(ccx, const_def_id);
+            let ty = ccx.icx(&impl_predicates)
+                        .to_ty(&ExplicitRscope, &ty);
+            tcx.item_types.borrow_mut().insert(const_def_id, ty);
+            convert_associated_const(ccx, ImplContainer(impl_def_id),
+                                     impl_item.id, ty);
+        }
+
+        hir::ImplItemKind::Type(ref ty) => {
+            let type_def_id = ccx.tcx.map.local_def_id(impl_item.id);
+            generics_of_def_id(ccx, type_def_id);
+
+            if impl_trait_ref.is_none() {
+                span_err!(tcx.sess, impl_item.span, E0202,
+                          "associated types are not allowed in inherent impls");
+            }
+
+            let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty);
+
+            convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
+        }
+
+        hir::ImplItemKind::Method(ref sig, _) => {
+            convert_method(ccx, ImplContainer(impl_def_id),
+                           impl_item.id, sig, impl_self_ty,
+                           &impl_predicates);
+        }
+    }
+}
+
 fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                   ctor_id: ast::NodeId,
                                   variant: ty::VariantDef<'tcx>,
@@ -2067,110 +2058,3 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                      |def, _| tcx.mk_region(def.to_early_bound_region()),
                      |def, _| tcx.mk_param_from_def(def))
 }
-
-/// Checks that all the type parameters on an impl
-fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                 generics: &hir::Generics,
-                                                 impl_predicates: &mut ty::GenericPredicates<'tcx>,
-                                                 impl_def_id: DefId)
-{
-    let impl_ty = ccx.tcx.item_type(impl_def_id);
-    let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
-
-    // The trait reference is an input, so find all type parameters
-    // reachable from there, to start (if this is an inherent impl,
-    // then just examine the self type).
-    let mut input_parameters: FxHashSet<_> =
-        ctp::parameters_for(&impl_ty, false).into_iter().collect();
-    if let Some(ref trait_ref) = impl_trait_ref {
-        input_parameters.extend(ctp::parameters_for(trait_ref, false));
-    }
-
-    ctp::setup_constraining_predicates(&mut impl_predicates.predicates,
-                                       impl_trait_ref,
-                                       &mut input_parameters);
-
-    let ty_generics = generics_of_def_id(ccx, impl_def_id);
-    for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) {
-        let param_ty = ty::ParamTy::for_def(ty_param);
-        if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
-            report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
-        }
-    }
-}
-
-fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                    ast_generics: &hir::Generics,
-                                                    impl_def_id: DefId,
-                                                    impl_items: &[hir::ImplItem])
-{
-    // Every lifetime used in an associated type must be constrained.
-    let impl_ty = ccx.tcx.item_type(impl_def_id);
-    let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
-    let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
-
-    let mut input_parameters: FxHashSet<_> =
-        ctp::parameters_for(&impl_ty, false).into_iter().collect();
-    if let Some(ref trait_ref) = impl_trait_ref {
-        input_parameters.extend(ctp::parameters_for(trait_ref, false));
-    }
-    ctp::identify_constrained_type_params(
-        &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
-
-    let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter()
-        .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(|def_id| {
-            ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
-        }).collect();
-
-    for (ty_lifetime, lifetime) in ccx.tcx.item_generics(impl_def_id).regions.iter()
-        .zip(&ast_generics.lifetimes)
-    {
-        let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
-
-        if
-            lifetimes_in_associated_types.contains(&param) && // (*)
-            !input_parameters.contains(&param)
-        {
-            report_unused_parameter(ccx, lifetime.lifetime.span,
-                                    "lifetime", &lifetime.lifetime.name.to_string());
-        }
-    }
-
-    // (*) This is a horrible concession to reality. I think it'd be
-    // better to just ban unconstrianed lifetimes outright, but in
-    // practice people do non-hygenic macros like:
-    //
-    // ```
-    // macro_rules! __impl_slice_eq1 {
-    //     ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
-    //         impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
-    //            ....
-    //         }
-    //     }
-    // }
-    // ```
-    //
-    // In a concession to backwards compatbility, we continue to
-    // permit those, so long as the lifetimes aren't used in
-    // associated types. I believe this is sound, because lifetimes
-    // used elsewhere are not projected back out.
-}
-
-fn report_unused_parameter(ccx: &CrateCtxt,
-                           span: Span,
-                           kind: &str,
-                           name: &str)
-{
-    struct_span_err!(
-        ccx.tcx.sess, span, E0207,
-        "the {} parameter `{}` is not constrained by the \
-        impl trait, self type, or predicates",
-        kind, name)
-        .span_label(span, &format!("unconstrained {} parameter", kind))
-        .emit();
-}
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index 7918537a6c0..22be4491273 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -23,6 +23,18 @@ impl From<ty::EarlyBoundRegion> for Parameter {
     fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) }
 }
 
+/// Return the set of parameters constrained by the impl header.
+pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>,
+                                 impl_trait_ref: Option<ty::TraitRef<'tcx>>)
+                                 -> FxHashSet<Parameter>
+{
+    let vec = match impl_trait_ref {
+        Some(tr) => parameters_for(&tr, false),
+        None => parameters_for(&impl_self_ty, false),
+    };
+    vec.into_iter().collect()
+}
+
 /// If `include_projections` is false, returns the list of parameters that are
 /// constrained by `t` - i.e. the value of each parameter in the list is
 /// uniquely determined by `t` (see RFC 447). If it is true, return the list
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
new file mode 100644
index 00000000000..9f5b73d9b30
--- /dev/null
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -0,0 +1,203 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This pass enforces various "well-formedness constraints" on impls.
+//! Logically, it is part of wfcheck -- but we do it early so that we
+//! can stop compilation afterwards, since part of the trait matching
+//! infrastructure gets very grumpy if these conditions don't hold. In
+//! particular, if there are type parameters that are not part of the
+//! impl, then coherence will report strange inference ambiguity
+//! errors; if impls have duplicate items, we get misleading
+//! specialization errors. These things can (and probably should) be
+//! fixed, but for the moment it's easier to do these checks early.
+
+use constrained_type_params as ctp;
+use rustc::dep_graph::DepNode;
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir::def_id::DefId;
+use rustc::ty;
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use std::collections::hash_map::Entry::{Occupied, Vacant};
+
+use syntax_pos::Span;
+
+use CrateCtxt;
+
+/// Checks that all the type/lifetime parameters on an impl also
+/// appear in the trait ref or self-type (or are constrained by a
+/// where-clause). These rules are needed to ensure that, given a
+/// trait ref like `<T as Trait<U>>`, we can derive the values of all
+/// parameters on the impl (which is needed to make specialization
+/// possible).
+///
+/// However, in the case of lifetimes, we only enforce these rules if
+/// the lifetime parameter is used in an associated type.  This is a
+/// concession to backwards compatibility; see comment at the end of
+/// the fn for details.
+///
+/// Example:
+///
+/// ```
+/// impl<T> Trait<Foo> for Bar { ... }
+///      ^ T does not appear in `Foo` or `Bar`, error!
+///
+/// impl<T> Trait<Foo<T>> for Bar { ... }
+///      ^ T appears in `Foo<T>`, ok.
+///
+/// impl<T> Trait<Foo> for Bar where Bar: Iterator<Item=T> { ... }
+///      ^ T is bound to `<Bar as Iterator>::Item`, ok.
+///
+/// impl<'a> Trait<Foo> for Bar { }
+///      ^ 'a is unused, but for back-compat we allow it
+///
+/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
+///      ^ 'a is unused and appears in assoc type, error
+/// ```
+pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) {
+    // We will tag this as part of the WF check -- logically, it is,
+    // but it's one that we must perform earlier than the rest of
+    // WfCheck.
+    ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx });
+}
+
+struct ImplWfCheck<'a, 'tcx: 'a> {
+    ccx: &'a CrateCtxt<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        match item.node {
+            hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
+                let impl_def_id = self.ccx.tcx.map.local_def_id(item.id);
+                enforce_impl_params_are_constrained(self.ccx,
+                                                    generics,
+                                                    impl_def_id,
+                                                    impl_item_refs);
+                enforce_impl_items_are_distinct(self.ccx, impl_item_refs);
+            }
+            _ => { }
+        }
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
+}
+
+fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                                 impl_hir_generics: &hir::Generics,
+                                                 impl_def_id: DefId,
+                                                 impl_item_refs: &[hir::ImplItemRef])
+{
+    // Every lifetime used in an associated type must be constrained.
+    let impl_self_ty = ccx.tcx.item_type(impl_def_id);
+    let impl_generics = ccx.tcx.item_generics(impl_def_id);
+    let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
+    let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
+
+    let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
+    ctp::identify_constrained_type_params(
+        &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
+
+    // Disallow ANY unconstrained type parameters.
+    for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
+        let param_ty = ty::ParamTy::for_def(ty_param);
+        if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
+            report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
+        }
+    }
+
+    // Disallow unconstrained lifetimes, but only if they appear in assoc types.
+    let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
+        .map(|item_ref|  ccx.tcx.map.local_def_id(item_ref.id.node_id))
+        .filter(|&def_id| {
+            let item = ccx.tcx.associated_item(def_id);
+            item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
+        })
+        .flat_map(|def_id| {
+            ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
+        }).collect();
+    for (ty_lifetime, lifetime) in impl_generics.regions.iter()
+        .zip(&impl_hir_generics.lifetimes)
+    {
+        let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
+
+        if
+            lifetimes_in_associated_types.contains(&param) && // (*)
+            !input_parameters.contains(&param)
+        {
+            report_unused_parameter(ccx, lifetime.lifetime.span,
+                                    "lifetime", &lifetime.lifetime.name.to_string());
+        }
+    }
+
+    // (*) This is a horrible concession to reality. I think it'd be
+    // better to just ban unconstrianed lifetimes outright, but in
+    // practice people do non-hygenic macros like:
+    //
+    // ```
+    // macro_rules! __impl_slice_eq1 {
+    //     ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
+    //         impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+    //            ....
+    //         }
+    //     }
+    // }
+    // ```
+    //
+    // In a concession to backwards compatbility, we continue to
+    // permit those, so long as the lifetimes aren't used in
+    // associated types. I believe this is sound, because lifetimes
+    // used elsewhere are not projected back out.
+}
+
+fn report_unused_parameter(ccx: &CrateCtxt,
+                           span: Span,
+                           kind: &str,
+                           name: &str)
+{
+    struct_span_err!(
+        ccx.tcx.sess, span, E0207,
+        "the {} parameter `{}` is not constrained by the \
+        impl trait, self type, or predicates",
+        kind, name)
+        .span_label(span, &format!("unconstrained {} parameter", kind))
+        .emit();
+}
+
+/// Enforce that we do not have two items in an impl with the same name.
+fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                             impl_item_refs: &[hir::ImplItemRef])
+{
+    let tcx = ccx.tcx;
+    let mut seen_type_items = FxHashMap();
+    let mut seen_value_items = FxHashMap();
+    for impl_item_ref in impl_item_refs {
+        let impl_item = tcx.map.impl_item(impl_item_ref.id);
+        let seen_items = match impl_item.node {
+            hir::ImplItemKind::Type(_) => &mut seen_type_items,
+            _                    => &mut seen_value_items,
+        };
+        match seen_items.entry(impl_item.name) {
+            Occupied(entry) => {
+                let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
+                                               "duplicate definitions with name `{}`:",
+                                               impl_item.name);
+                err.span_label(*entry.get(),
+                               &format!("previous definition of `{}` here",
+                                        impl_item.name));
+                err.span_label(impl_item.span, &format!("duplicate definition"));
+                err.emit();
+            }
+            Vacant(entry) => {
+                entry.insert(impl_item.span);
+            }
+        }
+    }
+}
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 76f8254cb0f..a1ee6979116 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -95,6 +95,7 @@ extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_back;
 extern crate rustc_const_math;
 extern crate rustc_const_eval;
+extern crate rustc_data_structures;
 extern crate rustc_errors as errors;
 
 pub use rustc::dep_graph;
@@ -130,6 +131,7 @@ mod rscope;
 mod astconv;
 pub mod collect;
 mod constrained_type_params;
+mod impl_wf_check;
 pub mod coherence;
 pub mod variance;
 
@@ -334,6 +336,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
          variance::infer_variance(tcx));
 
     tcx.sess.track_errors(|| {
+        time(time_passes, "impl wf inference", ||
+             impl_wf_check::impl_wf_check(&ccx));
+    })?;
+
+    tcx.sess.track_errors(|| {
       time(time_passes, "coherence checking", ||
           coherence::check_coherence(&ccx));
     })?;
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 10fca644ec1..8a0c1c68322 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -22,7 +22,7 @@ use rustc::ty::maps::ItemVariances;
 use rustc::hir::map as hir_map;
 use syntax::ast;
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 use super::terms::*;
 use super::terms::VarianceTerm::*;
@@ -65,13 +65,13 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
-                                 &mut constraint_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
+                                      &mut constraint_cx);
 
     constraint_cx
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let tcx = self.terms_cx.tcx;
         let did = tcx.map.local_def_id(item.id);
@@ -115,6 +115,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
             hir::ItemDefaultImpl(..) => {}
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
 
 /// Is `param_id` a lifetime according to `map`?
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index f6732f36e35..0a3238480d9 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -27,7 +27,7 @@ use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use util::nodemap::NodeMap;
 
 use self::VarianceTerm::*;
@@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
 
     terms_cx
 }
@@ -227,7 +227,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         debug!("add_inferreds for item {}",
                self.tcx.map.node_to_string(item.id));
@@ -257,4 +257,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
             hir::ItemTy(..) => {}
         }
     }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
 }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e8367bca2ef..185f897c1ba 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -364,7 +364,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
     let trait_items = tcx.associated_items(did).filter_map(|item| {
         match item.kind {
             ty::AssociatedKind::Const => {
-                let default = if item.has_value {
+                let default = if item.defaultness.has_value() {
                     Some(pprust::expr_to_string(
                         lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
                 } else {
@@ -407,7 +407,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                             abi: abi
                         })
                     }
-                    _ => panic!("not a tymethod"),
+                    ref r => panic!("not a tymethod: {:?}", r),
                 };
                 Some(cleaned)
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4d70c64634f..a141d0e4788 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1373,9 +1373,10 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                         }
                     }
                 }
+
                 let provided = match self.container {
                     ty::ImplContainer(_) => false,
-                    ty::TraitContainer(_) => self.has_value
+                    ty::TraitContainer(_) => self.defaultness.has_value()
                 };
                 if provided {
                     MethodItem(Method {
@@ -1440,7 +1441,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                     None => bounds.push(TyParamBound::maybe_sized(cx)),
                 }
 
-                let ty = if self.has_value {
+                let ty = if self.defaultness.has_value() {
                     Some(cx.tcx().item_type(self.def_id))
                 } else {
                     None
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index d9155e10e17..939fd6ccfc8 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -502,17 +502,20 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.traits.push(t);
             },
 
-            hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref items) => {
+            hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => {
                 // Don't duplicate impls when inlining, we'll pick them up
                 // regardless of where they're located.
                 if !self.inlining {
+                    let items = item_ids.iter()
+                                        .map(|ii| self.cx.map.impl_item(ii.id).clone())
+                                        .collect();
                     let i = Impl {
                         unsafety: unsafety,
                         polarity: polarity,
                         generics: gen.clone(),
                         trait_: tr.clone(),
                         for_: ty.clone(),
-                        items: items.clone(),
+                        items: items,
                         attrs: item.attrs.clone(),
                         id: item.id,
                         whence: item.span,
diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs
index 80cc9e71c7a..2e33f11c04b 100644
--- a/src/test/compile-fail/dep-graph-type-alias.rs
+++ b/src/test/compile-fail/dep-graph-type-alias.rs
@@ -42,8 +42,9 @@ trait Trait {
 
 struct SomeType;
 
-#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
 impl SomeType {
+    #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
     fn method(&self, _: TypeAlias) {}
 }
 
diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs
index d3b932fbc53..010cfb54c1a 100644
--- a/src/test/compile-fail/issue-3214.rs
+++ b/src/test/compile-fail/issue-3214.rs
@@ -15,7 +15,6 @@ fn foo<T>() {
 
     impl<T> Drop for foo<T> {
         //~^ ERROR wrong number of type arguments
-        //~^^ ERROR the type parameter `T` is not constrained
         fn drop(&mut self) {}
     }
 }
diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs
index 8fa34bde170..46e5a88eef9 100644
--- a/src/test/incremental/change_private_impl_method/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method/struct_point.rs
@@ -20,9 +20,8 @@
 
 #![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
 
-// FIXME(#37121) -- the following two modules *should* be reused but are not
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
@@ -60,8 +59,7 @@ mod point {
 mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    // FIXME(#37121) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl {
 mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    // FIXME(#37121) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
index d8e5fbadad8..bb7f7025c59 100644
--- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
@@ -19,12 +19,13 @@
 #![feature(stmt_expr_attributes)]
 #![allow(dead_code)]
 
-// FIXME(#37333) -- the following modules *should* be reused but are not
+#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
+
+// FIXME(#37720) these two should be reused, but data gets entangled across crates
 #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
 #![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")]
 
 extern crate point;
 
@@ -32,7 +33,7 @@ extern crate point;
 mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
+    // FIXME(#37720) data gets entangled across crates
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
@@ -44,9 +45,9 @@ mod fn_calls_methods_in_same_impl {
 mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
+    // FIXME(#37720) data gets entangled across crates
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
-    pub fn check() {
+    pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
     }
@@ -56,8 +57,7 @@ mod fn_calls_methods_in_another_impl {
 mod fn_make_struct {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -67,8 +67,7 @@ mod fn_make_struct {
 mod fn_read_field {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -78,8 +77,7 @@ mod fn_read_field {
 mod fn_write_field {
     use point::Point;
 
-    // FIXME(#37333) -- we should not need to typeck this again
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
new file mode 100644
index 00000000000..f7a390e8745
--- /dev/null
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -0,0 +1,128 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for let expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+struct Foo;
+
+// Change Method Name -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_name2() { }
+}
+
+// Change Method Body -----------------------------------------------------------
+//
+// This should affect the method itself, but not the impl.
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_body() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_body() {
+        println!("Hello, world!");
+    }
+}
+
+// Change Method Privacy -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_privacy() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_privacy() { }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_selfness() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_selfness(&self) { }
+}
+
+// Change Method Selfmutness -----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+    pub fn method_selfmutness(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    pub fn method_selfmutness(&mut self) { }
+}
+
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
new file mode 100644
index 00000000000..500aaf52324
--- /dev/null
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -0,0 +1,404 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for let expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(specialization)]
+#![crate_type="rlib"]
+
+struct Foo;
+
+// Change Method Name -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodNameTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodNameTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub trait ChangeMethodNameTrait {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name2();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodNameTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name2() { }
+}
+
+// Change Method Body -----------------------------------------------------------
+//
+// This should affect the method itself, but not the trait.
+
+pub trait ChangeMethodBodyTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodBodyTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodBodyTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name() {
+        ()
+    }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodSelfnessTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodSelfnessTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeMethodSelfnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodSelfnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self) {
+        ()
+    }
+}
+
+// Change Method Selfness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait RemoveMethodSelfnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl RemoveMethodSelfnessTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait RemoveMethodSelfnessTrait {
+    fn method_name();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveMethodSelfnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name() {
+        ()
+    }
+}
+
+// Change Method Selfmutness -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeMethodSelfmutnessTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl ChangeMethodSelfmutnessTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeMethodSelfmutnessTrait {
+    fn method_name(&mut self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeMethodSelfmutnessTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&mut self) {
+        ()
+    }
+}
+
+// Change item kind -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeItemKindTrait {
+    fn name();
+}
+
+#[cfg(cfail1)]
+impl ChangeItemKindTrait for Foo {
+    fn name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeItemKindTrait {
+    type name;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeItemKindTrait for Foo {
+    type name = ();
+}
+
+// Remove item -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait RemoveItemTrait {
+    type TypeName;
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl RemoveItemTrait for Foo {
+    type TypeName = ();
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+pub trait RemoveItemTrait {
+    type TypeName;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveItemTrait for Foo {
+    type TypeName = ();
+}
+
+// Add item -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait AddItemTrait {
+    type TypeName;
+}
+
+#[cfg(cfail1)]
+impl AddItemTrait for Foo {
+    type TypeName = ();
+}
+
+#[cfg(not(cfail1))]
+pub trait AddItemTrait {
+    type TypeName;
+    fn method_name();
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddItemTrait for Foo {
+    type TypeName = ();
+    fn method_name() { }
+}
+
+// Change has-value -----------------------------------------------------------
+
+#[cfg(cfail1)]
+pub trait ChangeHasValueTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl ChangeHasValueTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub trait ChangeHasValueTrait {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeHasValueTrait for Foo {
+    fn method_name() { }
+}
+
+// Add default
+
+pub trait AddDefaultTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl AddDefaultTrait for Foo {
+    fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddDefaultTrait for Foo {
+    default fn method_name() { }
+}
+
+// Remove default
+
+pub trait RemoveDefaultTrait {
+    fn method_name();
+}
+
+#[cfg(cfail1)]
+impl RemoveDefaultTrait for Foo {
+    default fn method_name() { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl RemoveDefaultTrait for Foo {
+    fn method_name() { }
+}
+
+// Add arguments
+
+#[cfg(cfail1)]
+pub trait AddArgumentTrait {
+    fn method_name(&self);
+}
+
+#[cfg(cfail1)]
+impl AddArgumentTrait for Foo {
+    fn method_name(&self) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait AddArgumentTrait {
+    fn method_name(&self, x: u32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl AddArgumentTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self, _x: u32) { }
+}
+
+// Change argument type
+
+#[cfg(cfail1)]
+pub trait ChangeArgumentTypeTrait {
+    fn method_name(&self, x: u32);
+}
+
+#[cfg(cfail1)]
+impl ChangeArgumentTypeTrait for Foo {
+    fn method_name(&self, _x: u32) { }
+}
+
+#[cfg(not(cfail1))]
+pub trait ChangeArgumentTypeTrait {
+    fn method_name(&self, x: char);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl ChangeArgumentTypeTrait for Foo {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn method_name(&self, _x: char) { }
+}
+