about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-11-14 11:00:02 -0500
committerNiko Matsakis <niko@alum.mit.edu>2016-11-17 13:44:22 -0500
commitb10b98169ff7350236e96f99ddb2f5d4cbef732b (patch)
tree3c8595d45c5552932e03c0b9c9b6bc02dd77d723
parentc17be9ea110a1158e6a1ad131941ec6965ce6ac9 (diff)
downloadrust-b10b98169ff7350236e96f99ddb2f5d4cbef732b.tar.gz
rust-b10b98169ff7350236e96f99ddb2f5d4cbef732b.zip
hash the contents of impl-item-ref by adding them to visitor
Also simplify some of the `ty::AssociatedItem` representation,
in particular by folding `has_value` into `hir::Defaultness`
-rw-r--r--src/librustc/hir/intravisit.rs39
-rw-r--r--src/librustc/hir/lowering.rs19
-rw-r--r--src/librustc/hir/mod.rs15
-rw-r--r--src/librustc/hir/print.rs5
-rw-r--r--src/librustc/traits/project.rs4
-rw-r--r--src/librustc/ty/mod.rs7
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs14
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_metadata/encoder.rs17
-rw-r--r--src/librustc_metadata/schema.rs19
-rw-r--r--src/librustc_save_analysis/lib.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/impl_wf_check.rs2
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs128
17 files changed, 234 insertions, 55 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 887b1febf65..4cfa889ec56 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -267,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>) {
@@ -740,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);
@@ -767,8 +777,13 @@ 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) {
-    visitor.visit_nested_impl_item(impl_item_ref.id);
-    visitor.visit_name(impl_item_ref.span, impl_item_ref.name);
+    // 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);
 }
 
 
@@ -941,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/lowering.rs b/src/librustc/hir/lowering.rs
index d1b57586ffd..05c4ae52180 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -699,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))
@@ -715,6 +715,8 @@ 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 {
@@ -723,7 +725,7 @@ impl<'a> LoweringContext<'a> {
             name: i.ident.name,
             span: i.span,
             vis: self.lower_visibility(&i.vis),
-            defaultness: self.lower_defaultness(i.defaultness),
+            defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
             kind: match i.node {
                 ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
                 ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
@@ -732,9 +734,9 @@ impl<'a> LoweringContext<'a> {
                 },
                 ImplItemKind::Macro(..) => unimplemented!(),
             },
-            // since `default impl` is not yet implemented, this is always true in impls
-            has_value: true,
         }
+
+        // [1] since `default impl` is not yet implemented, this is always true in impls
     }
 
     fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
@@ -1650,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/mod.rs b/src/librustc/hir/mod.rs
index 9dac6fac100..9f5ff6914b0 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1259,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,
+        }
     }
 }
 
@@ -1584,7 +1594,6 @@ pub struct ImplItemRef {
     pub span: Span,
     pub vis: Visibility,
     pub defaultness: Defaultness,
-    pub has_value: bool,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 5a381a189fc..807bbec3b58 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1036,8 +1036,9 @@ impl<'a> State<'a> {
         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/traits/project.rs b/src/librustc/traits/project.rs
index ac2f3ad9b89..ca7d2ac3c69 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -943,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                         // an error when we confirm the candidate
                         // (which will ultimately lead to `normalize_to_error`
                         // being invoked).
-                        node_item.item.has_value
+                        node_item.item.defaultness.has_value()
                     } else {
                         node_item.item.defaultness.is_default()
                     };
@@ -1304,7 +1304,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 9984dd42f56..f5c23401a4e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -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()
     }
 
@@ -2180,8 +2179,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             name: trait_item.name,
             kind: kind,
             vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
-            defaultness: hir::Defaultness::Default,
-            has_value: has_value,
+            defaultness: hir::Defaultness::Default { has_value: has_value },
             def_id: def_id,
             container: TraitContainer(parent_def_id),
             method_has_self_argument: has_self
@@ -2211,7 +2209,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             kind: kind,
             vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
             defaultness: impl_item_ref.defaultness,
-            has_value: true,
             def_id: def_id,
             container: ImplContainer(parent_def_id),
             method_has_self_argument: has_self
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 318cc83d9ad..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,
@@ -693,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_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index ba85544326f..6dbcfc8523d 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -834,7 +834,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
@@ -848,7 +847,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
@@ -861,7 +859,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 2d96eeb8f20..d1508d7e9b3 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -460,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 {
@@ -501,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
@@ -530,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 {
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index d7a5f7ad715..7553b2e05a7 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_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_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2197ecc10a1..d2939316219 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1110,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 {
@@ -1144,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 066b3d4be08..2c55e8fbfd2 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -204,7 +204,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/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 1572d04f68c..9f5b73d9b30 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -118,7 +118,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         .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.has_value
+            item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
         })
         .flat_map(|def_id| {
             ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
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/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) { }
+}
+