about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-03-22 17:51:19 +0800
committerkennytm <kennytm@gmail.com>2018-03-22 22:43:30 +0800
commitb7ee149c474ee1a9c458a80f67dbb3d783b64265 (patch)
tree163b760bc80a5977c9c93d0536bcd4b0a997f499
parentd67084215d0b0d534104fc2957e7ced3f4d922a9 (diff)
parentb418b7ba0f7393d789860f96a718a4fba2729271 (diff)
downloadrust-b7ee149c474ee1a9c458a80f67dbb3d783b64265.tar.gz
rust-b7ee149c474ee1a9c458a80f67dbb3d783b64265.zip
Rollup merge of #48939 - wesleywiser:incr_query_wf_checking, r=michaelwoerister
Querify WF-checking so it can be cached

r? @michaelwoerister
-rw-r--r--src/librustc/dep_graph/dep_node.rs3
-rw-r--r--src/librustc/ty/maps/mod.rs4
-rw-r--r--src/librustc/ty/maps/plumbing.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs15
-rw-r--r--src/librustc_typeck/check/wfcheck.rs1026
5 files changed, 545 insertions, 506 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 744e3a5eaab..1e2e4e5a69f 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -579,6 +579,9 @@ define_dep_nodes!( <'tcx>
     [] GetPanicStrategy(CrateNum),
     [] IsNoBuiltins(CrateNum),
     [] ImplDefaultness(DefId),
+    [] CheckItemWellFormed(DefId),
+    [] CheckTraitItemWellFormed(DefId),
+    [] CheckImplItemWellFormed(DefId),
     [] ReachableNonGenerics(CrateNum),
     [] NativeLibraries(CrateNum),
     [] PluginRegistrarFn(CrateNum),
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index b6b7361bb2f..6c3b4efb932 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -299,6 +299,10 @@ define_maps! { <'tcx>
 
     [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness,
 
+    [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (),
+    [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (),
+    [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (),
+
     // The DefIds of all non-generic functions and statics in the given crate
     // that can be reached from outside the crate.
     //
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index c5146790425..4170fa76797 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -871,6 +871,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); }
         DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); }
         DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); }
+        DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); }
+        DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); }
+        DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); }
         DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); }
         DepKind::NativeLibraries => { force!(native_libraries, krate!()); }
         DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4a685cfddb7..eb61aa94cd7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -718,6 +718,18 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum
     })?)
 }
 
+fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    wfcheck::check_item_well_formed(tcx, def_id);
+}
+
+fn check_trait_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    wfcheck::check_trait_item(tcx, def_id);
+}
+
+fn check_impl_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    wfcheck::check_impl_item(tcx, def_id);
+}
+
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         typeck_item_bodies,
@@ -725,6 +737,9 @@ pub fn provide(providers: &mut Providers) {
         has_typeck_tables,
         adt_destructor,
         used_trait_imports,
+        check_item_well_formed,
+        check_trait_item_well_formed,
+        check_impl_item_well_formed,
         ..*providers
     };
 }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b94af0a1e00..406ff9463a0 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -26,17 +26,11 @@ use errors::{DiagnosticBuilder, DiagnosticId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 
-pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    code: ObligationCauseCode<'tcx>,
-}
-
 /// Helper type of a temporary returned by .for_item(...).
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
 struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
-    code: ObligationCauseCode<'gcx>,
     id: ast::NodeId,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
@@ -45,585 +39,597 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
     fn with_fcx<F>(&'tcx mut self, f: F) where
         F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>,
-                          &mut CheckTypeWellFormedVisitor<'b, 'gcx>) -> Vec<Ty<'tcx>>
+                         TyCtxt<'b, 'gcx, 'gcx>) -> Vec<Ty<'tcx>>
     {
-        let code = self.code.clone();
         let id = self.id;
         let span = self.span;
         let param_env = self.param_env;
         self.inherited.enter(|inh| {
             let fcx = FnCtxt::new(&inh, param_env, id);
-            let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
-                tcx: fcx.tcx.global_tcx(),
-                code,
-            });
+            let wf_tys = f(&fcx, fcx.tcx.global_tcx());
             fcx.select_all_obligations_or_error();
             fcx.regionck_item(id, span, &wf_tys);
         });
     }
 }
 
-impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
-               -> CheckTypeWellFormedVisitor<'a, 'gcx> {
-        CheckTypeWellFormedVisitor {
-            tcx,
-            code: ObligationCauseCode::MiscObligation
-        }
-    }
-
-    /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
-    /// well-formed, meaning that they do not require any constraints not declared in the struct
-    /// definition itself. For example, this definition would be illegal:
-    ///
-    ///     struct Ref<'a, T> { x: &'a T }
-    ///
-    /// because the type did not declare that `T:'a`.
-    ///
-    /// We do this check as a pre-pass before checking fn bodies because if these constraints are
-    /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
-    /// the types first.
-    fn check_item_well_formed(&mut self, item: &hir::Item) {
-        let tcx = self.tcx;
-        debug!("check_item_well_formed(it.id={}, it.name={})",
-               item.id,
-               tcx.item_path_str(tcx.hir.local_def_id(item.id)));
-
-        match item.node {
-            // Right now we check that every default trait implementation
-            // has an implementation of itself. Basically, a case like:
-            //
-            // `impl Trait for T {}`
-            //
-            // has a requirement of `T: Trait` which was required for default
-            // method implementations. Although this could be improved now that
-            // there's a better infrastructure in place for this, it's being left
-            // for a follow-up work.
-            //
-            // Since there's such a requirement, we need to check *just* positive
-            // implementations, otherwise things like:
-            //
-            // impl !Send for T {}
-            //
-            // won't be allowed unless there's an *explicit* implementation of `Send`
-            // for `T`
-            hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
-                let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id))
-                                 .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
-                if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
-                    tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
-                }
-                if polarity == hir::ImplPolarity::Positive {
-                    self.check_impl(item, self_ty, trait_ref);
-                } else {
-                    // FIXME(#27579) what amount of WF checking do we need for neg impls?
-                    if trait_ref.is_some() && !is_auto {
-                        span_err!(tcx.sess, item.span, E0192,
-                                  "negative impls are only allowed for \
-                                   auto traits (e.g., `Send` and `Sync`)")
-                    }
-                }
-            }
-            hir::ItemFn(..) => {
-                self.check_item_fn(item);
-            }
-            hir::ItemStatic(..) => {
-                self.check_item_type(item);
+/// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
+/// well-formed, meaning that they do not require any constraints not declared in the struct
+/// definition itself. For example, this definition would be illegal:
+///
+///     struct Ref<'a, T> { x: &'a T }
+///
+/// because the type did not declare that `T:'a`.
+///
+/// We do this check as a pre-pass before checking fn bodies because if these constraints are
+/// not included it frequently leads to confusing errors in fn bodies. So it's better to check
+/// the types first.
+pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let item = tcx.hir.expect_item(node_id);
+
+    debug!("check_item_well_formed(it.id={}, it.name={})",
+            item.id,
+            tcx.item_path_str(def_id));
+
+    match item.node {
+        // Right now we check that every default trait implementation
+        // has an implementation of itself. Basically, a case like:
+        //
+        // `impl Trait for T {}`
+        //
+        // has a requirement of `T: Trait` which was required for default
+        // method implementations. Although this could be improved now that
+        // there's a better infrastructure in place for this, it's being left
+        // for a follow-up work.
+        //
+        // Since there's such a requirement, we need to check *just* positive
+        // implementations, otherwise things like:
+        //
+        // impl !Send for T {}
+        //
+        // won't be allowed unless there's an *explicit* implementation of `Send`
+        // for `T`
+        hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => {
+            let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id))
+                                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+            if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
+                tcx.sess.span_err(item.span, "impls of auto traits cannot be default");
             }
-            hir::ItemConst(..) => {
-                self.check_item_type(item);
+            if polarity == hir::ImplPolarity::Positive {
+                check_impl(tcx, item, self_ty, trait_ref);
+            } else {
+                // FIXME(#27579) what amount of WF checking do we need for neg impls?
+                if trait_ref.is_some() && !is_auto {
+                    span_err!(tcx.sess, item.span, E0192,
+                                "negative impls are only allowed for \
+                                auto traits (e.g., `Send` and `Sync`)")
+                }
             }
-            hir::ItemStruct(ref struct_def, ref ast_generics) => {
-                self.check_type_defn(item, false, |fcx| {
-                    vec![fcx.non_enum_variant(struct_def)]
-                });
+        }
+        hir::ItemFn(..) => {
+            check_item_fn(tcx, item);
+        }
+        hir::ItemStatic(..) => {
+            check_item_type(tcx, item);
+        }
+        hir::ItemConst(..) => {
+            check_item_type(tcx, item);
+        }
+        hir::ItemStruct(ref struct_def, ref ast_generics) => {
+            check_type_defn(tcx, item, false, |fcx| {
+                vec![fcx.non_enum_variant(struct_def)]
+            });
 
-                self.check_variances_for_type_defn(item, ast_generics);
-            }
-            hir::ItemUnion(ref struct_def, ref ast_generics) => {
-                self.check_type_defn(item, true, |fcx| {
-                    vec![fcx.non_enum_variant(struct_def)]
-                });
+            check_variances_for_type_defn(tcx, item, ast_generics);
+        }
+        hir::ItemUnion(ref struct_def, ref ast_generics) => {
+            check_type_defn(tcx, item, true, |fcx| {
+                vec![fcx.non_enum_variant(struct_def)]
+            });
 
-                self.check_variances_for_type_defn(item, ast_generics);
-            }
-            hir::ItemEnum(ref enum_def, ref ast_generics) => {
-                self.check_type_defn(item, true, |fcx| {
-                    fcx.enum_variants(enum_def)
-                });
+            check_variances_for_type_defn(tcx, item, ast_generics);
+        }
+        hir::ItemEnum(ref enum_def, ref ast_generics) => {
+            check_type_defn(tcx, item, true, |fcx| {
+                fcx.enum_variants(enum_def)
+            });
 
-                self.check_variances_for_type_defn(item, ast_generics);
-            }
-            hir::ItemTrait(..) => {
-                self.check_trait(item);
-            }
-            _ => {}
+            check_variances_for_type_defn(tcx, item, ast_generics);
         }
+        hir::ItemTrait(..) => {
+            check_trait(tcx, item);
+        }
+        _ => {}
     }
+}
 
-    fn check_associated_item(&mut self,
-                             item_id: ast::NodeId,
-                             span: Span,
-                             sig_if_method: Option<&hir::MethodSig>) {
-        let code = self.code.clone();
-        self.for_id(item_id, span).with_fcx(|fcx, this| {
-            let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
-
-            let (mut implied_bounds, self_ty) = match item.container {
-                ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
-                ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
-                                              fcx.tcx.type_of(def_id))
-            };
+pub fn check_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let trait_item = tcx.hir.expect_trait_item(node_id);
+
+    let method_sig = match trait_item.node {
+        hir::TraitItemKind::Method(ref sig, _) => Some(sig),
+        _ => None
+    };
+    check_associated_item(tcx, trait_item.id, trait_item.span, method_sig);
+}
+
+pub fn check_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let impl_item = tcx.hir.expect_impl_item(node_id);
+
+    let method_sig = match impl_item.node {
+        hir::ImplItemKind::Method(ref sig, _) => Some(sig),
+        _ => None
+    };
+    check_associated_item(tcx, impl_item.id, impl_item.span, method_sig);
+}
+
+fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            item_id: ast::NodeId,
+                            span: Span,
+                            sig_if_method: Option<&hir::MethodSig>) {
+    let code = ObligationCauseCode::MiscObligation;
+    for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+        let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
+
+        let (mut implied_bounds, self_ty) = match item.container {
+            ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()),
+            ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span),
+                                            fcx.tcx.type_of(def_id))
+        };
 
-            match item.kind {
-                ty::AssociatedKind::Const => {
+        match item.kind {
+            ty::AssociatedKind::Const => {
+                let ty = fcx.tcx.type_of(item.def_id);
+                let ty = fcx.normalize_associated_types_in(span, &ty);
+                fcx.register_wf_obligation(ty, span, code.clone());
+            }
+            ty::AssociatedKind::Method => {
+                reject_shadowing_type_parameters(fcx.tcx, item.def_id);
+                let sig = fcx.tcx.fn_sig(item.def_id);
+                let sig = fcx.normalize_associated_types_in(span, &sig);
+                check_fn_or_method(tcx, fcx, span, sig,
+                                        item.def_id, &mut implied_bounds);
+                let sig_if_method = sig_if_method.expect("bad signature for method");
+                check_method_receiver(fcx, sig_if_method, &item, self_ty);
+            }
+            ty::AssociatedKind::Type => {
+                if item.defaultness.has_value() {
                     let ty = fcx.tcx.type_of(item.def_id);
                     let ty = fcx.normalize_associated_types_in(span, &ty);
                     fcx.register_wf_obligation(ty, span, code.clone());
                 }
-                ty::AssociatedKind::Method => {
-                    reject_shadowing_type_parameters(fcx.tcx, item.def_id);
-                    let sig = fcx.tcx.fn_sig(item.def_id);
-                    let sig = fcx.normalize_associated_types_in(span, &sig);
-                    this.check_fn_or_method(fcx, span, sig,
-                                            item.def_id, &mut implied_bounds);
-                    let sig_if_method = sig_if_method.expect("bad signature for method");
-                    this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
-                }
-                ty::AssociatedKind::Type => {
-                    if item.defaultness.has_value() {
-                        let ty = fcx.tcx.type_of(item.def_id);
-                        let ty = fcx.normalize_associated_types_in(span, &ty);
-                        fcx.register_wf_obligation(ty, span, code.clone());
-                    }
-                }
             }
+        }
 
-            implied_bounds
-        })
-    }
-
-    fn for_item<'tcx>(&self, item: &hir::Item)
-                      -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
-        self.for_id(item.id, item.span)
-    }
+        implied_bounds
+    })
+}
 
-    fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
+fn for_item<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, item: &hir::Item)
                     -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
-        let def_id = self.tcx.hir.local_def_id(id);
-        CheckWfFcxBuilder {
-            inherited: Inherited::build(self.tcx, def_id),
-            code: self.code.clone(),
-            id,
-            span,
-            param_env: self.tcx.param_env(def_id),
-        }
+    for_id(tcx, item.id, item.span)
+}
+
+fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId, span: Span)
+                -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
+    let def_id = tcx.hir.local_def_id(id);
+    CheckWfFcxBuilder {
+        inherited: Inherited::build(tcx, def_id),
+        id,
+        span,
+        param_env: tcx.param_env(def_id),
     }
+}
 
-    /// In a type definition, we check that to ensure that the types of the fields are well-formed.
-    fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
-        where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec<AdtVariant<'tcx>>
-    {
-        self.for_item(item).with_fcx(|fcx, this| {
-            let variants = lookup_fields(fcx);
-            let def_id = fcx.tcx.hir.local_def_id(item.id);
-            let packed = fcx.tcx.adt_def(def_id).repr.packed();
-
-            for variant in &variants {
-                // For DST, or when drop needs to copy things around, all
-                // intermediate types must be sized.
-                let needs_drop_copy = || {
-                    packed && {
-                        let ty = variant.fields.last().unwrap().ty;
-                        let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(this.tcx)
-                            .unwrap_or_else(|| {
-                                span_bug!(item.span, "inference variables in {:?}", ty)
-                            });
-                        ty.needs_drop(this.tcx, this.tcx.param_env(def_id))
-                    }
-                };
-                let unsized_len = if
-                    all_sized ||
-                    variant.fields.is_empty() ||
-                    needs_drop_copy()
-                {
-                    0
-                } else {
-                    1
-                };
-                for field in &variant.fields[..variant.fields.len() - unsized_len] {
-                    fcx.register_bound(
-                        field.ty,
-                        fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
-                        traits::ObligationCause::new(field.span,
-                                                     fcx.body_id,
-                                                     traits::FieldSized(match item.node.adt_kind() {
-                                                        Some(i) => i,
-                                                        None => bug!(),
-                                                     })));
+/// In a type definition, we check that to ensure that the types of the fields are well-formed.
+fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                item: &hir::Item, all_sized: bool, mut lookup_fields: F)
+    where F: for<'fcx, 'gcx, 'tcx2> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx2>) -> Vec<AdtVariant<'tcx2>>
+{
+    for_item(tcx, item).with_fcx(|fcx, fcx_tcx| {
+        let variants = lookup_fields(fcx);
+        let def_id = fcx.tcx.hir.local_def_id(item.id);
+        let packed = fcx.tcx.adt_def(def_id).repr.packed();
+
+        for variant in &variants {
+            // For DST, or when drop needs to copy things around, all
+            // intermediate types must be sized.
+            let needs_drop_copy = || {
+                packed && {
+                    let ty = variant.fields.last().unwrap().ty;
+                    let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(fcx_tcx)
+                        .unwrap_or_else(|| {
+                            span_bug!(item.span, "inference variables in {:?}", ty)
+                        });
+                    ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id))
                 }
+            };
+            let unsized_len = if
+                all_sized ||
+                variant.fields.is_empty() ||
+                needs_drop_copy()
+            {
+                0
+            } else {
+                1
+            };
+            for field in &variant.fields[..variant.fields.len() - unsized_len] {
+                fcx.register_bound(
+                    field.ty,
+                    fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
+                    traits::ObligationCause::new(field.span,
+                                                    fcx.body_id,
+                                                    traits::FieldSized(match item.node.adt_kind() {
+                                                    Some(i) => i,
+                                                    None => bug!(),
+                                                    })));
+            }
 
-                // All field types must be well-formed.
-                for field in &variant.fields {
-                    fcx.register_wf_obligation(field.ty, field.span, this.code.clone())
-                }
+            // All field types must be well-formed.
+            for field in &variant.fields {
+                fcx.register_wf_obligation(field.ty, field.span,
+                    ObligationCauseCode::MiscObligation)
             }
+        }
 
-            self.check_where_clauses(fcx, item.span, def_id);
+        check_where_clauses(tcx, fcx, item.span, def_id);
 
-            vec![] // no implied bounds in a struct def'n
-        });
-    }
+        vec![] // no implied bounds in a struct def'n
+    });
+}
 
-    fn check_trait(&mut self, item: &hir::Item) {
-        let trait_def_id = self.tcx.hir.local_def_id(item.id);
-        self.for_item(item).with_fcx(|fcx, _| {
-            self.check_where_clauses(fcx, item.span, trait_def_id);
-            vec![]
-        });
-    }
+fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
+    let trait_def_id = tcx.hir.local_def_id(item.id);
+    for_item(tcx, item).with_fcx(|fcx, _| {
+        check_where_clauses(tcx, fcx, item.span, trait_def_id);
+        vec![]
+    });
+}
 
-    fn check_item_fn(&mut self, item: &hir::Item) {
-        self.for_item(item).with_fcx(|fcx, this| {
-            let def_id = fcx.tcx.hir.local_def_id(item.id);
-            let sig = fcx.tcx.fn_sig(def_id);
-            let sig = fcx.normalize_associated_types_in(item.span, &sig);
-            let mut implied_bounds = vec![];
-            this.check_fn_or_method(fcx, item.span, sig,
-                                    def_id, &mut implied_bounds);
-            implied_bounds
-        })
-    }
+fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
+    for_item(tcx, item).with_fcx(|fcx, tcx| {
+        let def_id = fcx.tcx.hir.local_def_id(item.id);
+        let sig = fcx.tcx.fn_sig(def_id);
+        let sig = fcx.normalize_associated_types_in(item.span, &sig);
+        let mut implied_bounds = vec![];
+        check_fn_or_method(tcx, fcx, item.span, sig,
+                                def_id, &mut implied_bounds);
+        implied_bounds
+    })
+}
 
-    fn check_item_type(&mut self,
-                       item: &hir::Item)
-    {
-        debug!("check_item_type: {:?}", item);
+fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    item: &hir::Item)
+{
+    debug!("check_item_type: {:?}", item);
 
-        self.for_item(item).with_fcx(|fcx, this| {
-            let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
-            let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
+    for_item(tcx, item).with_fcx(|fcx, _this| {
+        let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
+        let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
 
-            fcx.register_wf_obligation(item_ty, item.span, this.code.clone());
+        fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);
 
-            vec![] // no implied bounds in a const etc
-        });
-    }
+        vec![] // no implied bounds in a const etc
+    });
+}
 
-    fn check_impl(&mut self,
-                  item: &hir::Item,
-                  ast_self_ty: &hir::Ty,
-                  ast_trait_ref: &Option<hir::TraitRef>)
-    {
-        debug!("check_impl: {:?}", item);
-
-        self.for_item(item).with_fcx(|fcx, this| {
-            let item_def_id = fcx.tcx.hir.local_def_id(item.id);
-
-            match *ast_trait_ref {
-                Some(ref ast_trait_ref) => {
-                    let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
-                    let trait_ref =
-                        fcx.normalize_associated_types_in(
-                            ast_trait_ref.path.span, &trait_ref);
-                    let obligations =
-                        ty::wf::trait_obligations(fcx,
-                                                  fcx.param_env,
-                                                  fcx.body_id,
-                                                  &trait_ref,
-                                                  ast_trait_ref.path.span);
-                    for obligation in obligations {
-                        fcx.register_predicate(obligation);
-                    }
-                }
-                None => {
-                    let self_ty = fcx.tcx.type_of(item_def_id);
-                    let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
-                    fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
+fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                item: &hir::Item,
+                ast_self_ty: &hir::Ty,
+                ast_trait_ref: &Option<hir::TraitRef>)
+{
+    debug!("check_impl: {:?}", item);
+
+    for_item(tcx, item).with_fcx(|fcx, tcx| {
+        let item_def_id = fcx.tcx.hir.local_def_id(item.id);
+
+        match *ast_trait_ref {
+            Some(ref ast_trait_ref) => {
+                let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
+                let trait_ref =
+                    fcx.normalize_associated_types_in(
+                        ast_trait_ref.path.span, &trait_ref);
+                let obligations =
+                    ty::wf::trait_obligations(fcx,
+                                                fcx.param_env,
+                                                fcx.body_id,
+                                                &trait_ref,
+                                                ast_trait_ref.path.span);
+                for obligation in obligations {
+                    fcx.register_predicate(obligation);
                 }
             }
+            None => {
+                let self_ty = fcx.tcx.type_of(item_def_id);
+                let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
+                fcx.register_wf_obligation(self_ty, ast_self_ty.span,
+                    ObligationCauseCode::MiscObligation);
+            }
+        }
 
-            this.check_where_clauses(fcx, item.span, item_def_id);
+        check_where_clauses(tcx, fcx, item.span, item_def_id);
 
-            fcx.impl_implied_bounds(item_def_id, item.span)
-        });
-    }
+        fcx.impl_implied_bounds(item_def_id, item.span)
+    });
+}
 
-    /// Checks where clauses and inline bounds that are declared on def_id.
-    fn check_where_clauses<'fcx, 'tcx>(&mut self,
-                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                       span: Span,
-                                       def_id: DefId) {
-        use ty::subst::Subst;
-        use rustc::ty::TypeFoldable;
-
-        let mut predicates = fcx.tcx.predicates_of(def_id);
-        let mut substituted_predicates = Vec::new();
-
-        let generics = self.tcx.generics_of(def_id);
-        let is_our_default = |def: &ty::TypeParameterDef|
-                                def.has_default && def.index >= generics.parent_count() as u32;
-
-        // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
-        // For example this forbids the declaration:
-        // struct Foo<T = Vec<[u32]>> { .. }
-        // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
-        for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
-            let ty = fcx.tcx.type_of(d);
-            // ignore dependent defaults -- that is, where the default of one type
-            // parameter includes another (e.g., <T, U = T>). In those cases, we can't
-            // be sure if it will error or not as user might always specify the other.
-            if !ty.needs_subst() {
-                fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
-            }
+/// Checks where clauses and inline bounds that are declared on def_id.
+fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                    fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                    span: Span,
+                                    def_id: DefId) {
+    use ty::subst::Subst;
+    use rustc::ty::TypeFoldable;
+
+    let mut predicates = fcx.tcx.predicates_of(def_id);
+    let mut substituted_predicates = Vec::new();
+
+    let generics = tcx.generics_of(def_id);
+    let is_our_default = |def: &ty::TypeParameterDef|
+                            def.has_default && def.index >= generics.parent_count() as u32;
+
+    // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
+    // For example this forbids the declaration:
+    // struct Foo<T = Vec<[u32]>> { .. }
+    // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+    for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
+        let ty = fcx.tcx.type_of(d);
+        // ignore dependent defaults -- that is, where the default of one type
+        // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+        // be sure if it will error or not as user might always specify the other.
+        if !ty.needs_subst() {
+            fcx.register_wf_obligation(ty, fcx.tcx.def_span(d),
+                ObligationCauseCode::MiscObligation);
         }
+    }
 
-        // Check that trait predicates are WF when params are substituted by their defaults.
-        // We don't want to overly constrain the predicates that may be written but we want to
-        // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
-        // Therefore we check if a predicate which contains a single type param
-        // with a concrete default is WF with that default substituted.
-        // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
-        //
-        // First we build the defaulted substitution.
-        let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
-                // All regions are identity.
-                fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
-            }, |def, _| {
-                // If the param has a default,
-                if is_our_default(def) {
-                    let default_ty = fcx.tcx.type_of(def.def_id);
-                    // and it's not a dependent default
-                    if !default_ty.needs_subst() {
-                        // then substitute with the default.
-                        return default_ty;
-                    }
+    // Check that trait predicates are WF when params are substituted by their defaults.
+    // We don't want to overly constrain the predicates that may be written but we want to
+    // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
+    // Therefore we check if a predicate which contains a single type param
+    // with a concrete default is WF with that default substituted.
+    // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
+    //
+    // First we build the defaulted substitution.
+    let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
+            // All regions are identity.
+            fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
+        }, |def, _| {
+            // If the param has a default,
+            if is_our_default(def) {
+                let default_ty = fcx.tcx.type_of(def.def_id);
+                // and it's not a dependent default
+                if !default_ty.needs_subst() {
+                    // then substitute with the default.
+                    return default_ty;
                 }
-                // Mark unwanted params as err.
-                fcx.tcx.types.err
-            });
-        // Now we build the substituted predicates.
-        for &pred in predicates.predicates.iter() {
-            struct CountParams { params: FxHashSet<u32> }
-            impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
-                fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-                    match t.sty {
-                        ty::TyParam(p) => {
-                            self.params.insert(p.idx);
-                            t.super_visit_with(self)
-                        }
-                        _ => t.super_visit_with(self)
+            }
+            // Mark unwanted params as err.
+            fcx.tcx.types.err
+        });
+    // Now we build the substituted predicates.
+    for &pred in predicates.predicates.iter() {
+        struct CountParams { params: FxHashSet<u32> }
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                match t.sty {
+                    ty::TyParam(p) => {
+                        self.params.insert(p.idx);
+                        t.super_visit_with(self)
                     }
+                    _ => t.super_visit_with(self)
                 }
             }
-            let mut param_count = CountParams { params: FxHashSet() };
-            pred.visit_with(&mut param_count);
-            let substituted_pred = pred.subst(fcx.tcx, substs);
-            // Don't check non-defaulted params, dependent defaults or preds with multiple params.
-            if substituted_pred.references_error() || param_count.params.len() > 1 {
-                continue;
-            }
-            // Avoid duplication of predicates that contain no parameters, for example.
-            if !predicates.predicates.contains(&substituted_pred) {
-                substituted_predicates.push(substituted_pred);
-            }
         }
-
-        predicates.predicates.extend(substituted_predicates);
-        let predicates = predicates.instantiate_identity(fcx.tcx);
-        let predicates = fcx.normalize_associated_types_in(span, &predicates);
-
-        let obligations =
-            predicates.predicates
-                      .iter()
-                      .flat_map(|p| ty::wf::predicate_obligations(fcx,
-                                                                  fcx.param_env,
-                                                                  fcx.body_id,
-                                                                  p,
-                                                                  span));
-
-        for obligation in obligations {
-            fcx.register_predicate(obligation);
+        let mut param_count = CountParams { params: FxHashSet() };
+        pred.visit_with(&mut param_count);
+        let substituted_pred = pred.subst(fcx.tcx, substs);
+        // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+        if substituted_pred.references_error() || param_count.params.len() > 1 {
+            continue;
+        }
+        // Avoid duplication of predicates that contain no parameters, for example.
+        if !predicates.predicates.contains(&substituted_pred) {
+            substituted_predicates.push(substituted_pred);
         }
     }
 
-    fn check_fn_or_method<'fcx, 'tcx>(&mut self,
-                                      fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                      span: Span,
-                                      sig: ty::PolyFnSig<'tcx>,
-                                      def_id: DefId,
-                                      implied_bounds: &mut Vec<Ty<'tcx>>)
-    {
-        let sig = fcx.normalize_associated_types_in(span, &sig);
-        let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
-
-        for input_ty in sig.inputs() {
-            fcx.register_wf_obligation(&input_ty, span, self.code.clone());
-        }
-        implied_bounds.extend(sig.inputs());
+    predicates.predicates.extend(substituted_predicates);
+    let predicates = predicates.instantiate_identity(fcx.tcx);
+    let predicates = fcx.normalize_associated_types_in(span, &predicates);
+
+    let obligations =
+        predicates.predicates
+                    .iter()
+                    .flat_map(|p| ty::wf::predicate_obligations(fcx,
+                                                                fcx.param_env,
+                                                                fcx.body_id,
+                                                                p,
+                                                                span));
+
+    for obligation in obligations {
+        fcx.register_predicate(obligation);
+    }
+}
 
-        fcx.register_wf_obligation(sig.output(), span, self.code.clone());
+fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                    fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                    span: Span,
+                                    sig: ty::PolyFnSig<'tcx>,
+                                    def_id: DefId,
+                                    implied_bounds: &mut Vec<Ty<'tcx>>)
+{
+    let sig = fcx.normalize_associated_types_in(span, &sig);
+    let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
+
+    for input_ty in sig.inputs() {
+        fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation);
+    }
+    implied_bounds.extend(sig.inputs());
 
-        // FIXME(#25759) return types should not be implied bounds
-        implied_bounds.push(sig.output());
+    fcx.register_wf_obligation(sig.output(), span, ObligationCauseCode::MiscObligation);
 
-        self.check_where_clauses(fcx, span, def_id);
-    }
+    // FIXME(#25759) return types should not be implied bounds
+    implied_bounds.push(sig.output());
 
-    fn check_method_receiver<'fcx, 'tcx>(&mut self,
-                                         fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
-                                         method_sig: &hir::MethodSig,
-                                         method: &ty::AssociatedItem,
-                                         self_ty: Ty<'tcx>)
-    {
-        // check that the method has a valid receiver type, given the type `Self`
-        debug!("check_method_receiver({:?}, self_ty={:?})",
-               method, self_ty);
+    check_where_clauses(tcx, fcx, span, def_id);
+}
 
-        if !method.method_has_self_argument {
-            return;
-        }
+fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
+                                           method_sig: &hir::MethodSig,
+                                           method: &ty::AssociatedItem,
+                                           self_ty: Ty<'tcx>)
+{
+    // check that the method has a valid receiver type, given the type `Self`
+    debug!("check_method_receiver({:?}, self_ty={:?})",
+            method, self_ty);
+
+    if !method.method_has_self_argument {
+        return;
+    }
 
-        let span = method_sig.decl.inputs[0].span;
+    let span = method_sig.decl.inputs[0].span;
 
-        let sig = fcx.tcx.fn_sig(method.def_id);
-        let sig = fcx.normalize_associated_types_in(span, &sig);
-        let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig);
+    let sig = fcx.tcx.fn_sig(method.def_id);
+    let sig = fcx.normalize_associated_types_in(span, &sig);
+    let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig);
 
-        debug!("check_method_receiver: sig={:?}", sig);
+    debug!("check_method_receiver: sig={:?}", sig);
 
-        let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
-        let self_ty = fcx.tcx.liberate_late_bound_regions(
-            method.def_id,
-            &ty::Binder(self_ty)
-        );
+    let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
+    let self_ty = fcx.tcx.liberate_late_bound_regions(
+        method.def_id,
+        &ty::Binder(self_ty)
+    );
 
-        let self_arg_ty = sig.inputs()[0];
+    let self_arg_ty = sig.inputs()[0];
 
-        let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
-        let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
-        let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
-            method.def_id,
-            &ty::Binder(self_arg_ty)
-        );
+    let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
+    let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
+    let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
+        method.def_id,
+        &ty::Binder(self_arg_ty)
+    );
 
-        let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
+    let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
 
-        loop {
-            if let Some((potential_self_ty, _)) = autoderef.next() {
-                debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
-                    potential_self_ty, self_ty);
+    loop {
+        if let Some((potential_self_ty, _)) = autoderef.next() {
+            debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
+                potential_self_ty, self_ty);
 
-                if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
-                    autoderef.finalize();
-                    if let Some(mut err) = fcx.demand_eqtype_with_origin(
-                        &cause, self_ty, potential_self_ty) {
-                        err.emit();
-                    }
-                    break
+            if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
+                autoderef.finalize();
+                if let Some(mut err) = fcx.demand_eqtype_with_origin(
+                    &cause, self_ty, potential_self_ty) {
+                    err.emit();
                 }
-            } else {
-                fcx.tcx.sess.diagnostic().mut_span_err(
-                    span, &format!("invalid `self` type: {:?}", self_arg_ty))
-                .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
-                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-                .code(DiagnosticId::Error("E0307".into()))
-                .emit();
-                return
+                break
             }
+        } else {
+            fcx.tcx.sess.diagnostic().mut_span_err(
+                span, &format!("invalid `self` type: {:?}", self_arg_ty))
+            .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
+            .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+            .code(DiagnosticId::Error("E0307".into()))
+            .emit();
+            return
         }
+    }
 
-        let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
-        let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
-
-        if !fcx.tcx.features().arbitrary_self_types {
-            match self_kind {
-                ExplicitSelf::ByValue |
-                ExplicitSelf::ByReference(_, _) |
-                ExplicitSelf::ByBox => (),
-
-                ExplicitSelf::ByRawPointer(_) => {
-                    feature_gate::feature_err(
-                        &fcx.tcx.sess.parse_sess,
-                        "arbitrary_self_types",
-                        span,
-                        GateIssue::Language,
-                        "raw pointer `self` is unstable")
-                    .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-                    .emit();
-                }
+    let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
+    let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
+
+    if !fcx.tcx.features().arbitrary_self_types {
+        match self_kind {
+            ExplicitSelf::ByValue |
+            ExplicitSelf::ByReference(_, _) |
+            ExplicitSelf::ByBox => (),
+
+            ExplicitSelf::ByRawPointer(_) => {
+                feature_gate::feature_err(
+                    &fcx.tcx.sess.parse_sess,
+                    "arbitrary_self_types",
+                    span,
+                    GateIssue::Language,
+                    "raw pointer `self` is unstable")
+                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .emit();
+            }
 
-                ExplicitSelf::Other => {
-                    feature_gate::feature_err(
-                        &fcx.tcx.sess.parse_sess,
-                        "arbitrary_self_types",
-                        span,
-                        GateIssue::Language,"arbitrary `self` types are unstable")
-                    .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
-                    .emit();
-                }
+            ExplicitSelf::Other => {
+                feature_gate::feature_err(
+                    &fcx.tcx.sess.parse_sess,
+                    "arbitrary_self_types",
+                    span,
+                    GateIssue::Language,"arbitrary `self` types are unstable")
+                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .emit();
             }
         }
     }
+}
 
-    fn check_variances_for_type_defn(&self,
-                                     item: &hir::Item,
-                                     ast_generics: &hir::Generics)
-    {
-        let item_def_id = self.tcx.hir.local_def_id(item.id);
-        let ty = self.tcx.type_of(item_def_id);
-        if self.tcx.has_error_field(ty) {
-            return;
-        }
-
-        let ty_predicates = self.tcx.predicates_of(item_def_id);
-        assert_eq!(ty_predicates.parent, None);
-        let variances = self.tcx.variances_of(item_def_id);
+fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    item: &hir::Item,
+                                    ast_generics: &hir::Generics)
+{
+    let item_def_id = tcx.hir.local_def_id(item.id);
+    let ty = tcx.type_of(item_def_id);
+    if tcx.has_error_field(ty) {
+        return;
+    }
 
-        let mut constrained_parameters: FxHashSet<_> =
-            variances.iter().enumerate()
-                     .filter(|&(_, &variance)| variance != ty::Bivariant)
-                     .map(|(index, _)| Parameter(index as u32))
-                     .collect();
+    let ty_predicates = tcx.predicates_of(item_def_id);
+    assert_eq!(ty_predicates.parent, None);
+    let variances = tcx.variances_of(item_def_id);
 
-        identify_constrained_type_params(self.tcx,
-                                         ty_predicates.predicates.as_slice(),
-                                         None,
-                                         &mut constrained_parameters);
+    let mut constrained_parameters: FxHashSet<_> =
+        variances.iter().enumerate()
+                    .filter(|&(_, &variance)| variance != ty::Bivariant)
+                    .map(|(index, _)| Parameter(index as u32))
+                    .collect();
 
-        for (index, _) in variances.iter().enumerate() {
-            if constrained_parameters.contains(&Parameter(index as u32)) {
-                continue;
-            }
+    identify_constrained_type_params(tcx,
+                                        ty_predicates.predicates.as_slice(),
+                                        None,
+                                        &mut constrained_parameters);
 
-            let (span, name) = match ast_generics.params[index] {
-                hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
-                hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
-            };
-            self.report_bivariance(span, name);
+    for (index, _) in variances.iter().enumerate() {
+        if constrained_parameters.contains(&Parameter(index as u32)) {
+            continue;
         }
+
+        let (span, name) = match ast_generics.params[index] {
+            hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()),
+            hir::GenericParam::Type(ref tp) => (tp.span, tp.name),
+        };
+        report_bivariance(tcx, span, name);
     }
+}
 
-    fn report_bivariance(&self,
-                         span: Span,
-                         param_name: ast::Name)
-    {
-        let mut err = error_392(self.tcx, span, param_name);
-
-        let suggested_marker_id = self.tcx.lang_items().phantom_data();
-        match suggested_marker_id {
-            Some(def_id) => {
-                err.help(
-                    &format!("consider removing `{}` or using a marker such as `{}`",
-                             param_name,
-                             self.tcx.item_path_str(def_id)));
-            }
-            None => {
-                // no lang items, no help!
-            }
+fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        span: Span,
+                        param_name: ast::Name)
+{
+    let mut err = error_392(tcx, span, param_name);
+
+    let suggested_marker_id = tcx.lang_items().phantom_data();
+    match suggested_marker_id {
+        Some(def_id) => {
+            err.help(
+                &format!("consider removing `{}` or using a marker such as `{}`",
+                            param_name,
+                            tcx.item_path_str(def_id)));
+        }
+        None => {
+            // no lang items, no help!
         }
-        err.emit();
     }
+    err.emit();
 }
 
 fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
@@ -648,6 +654,19 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
     }
 }
 
+pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
+               -> CheckTypeWellFormedVisitor<'a, 'gcx> {
+        CheckTypeWellFormedVisitor {
+            tcx,
+        }
+    }
+}
+
 impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
         NestedVisitorMap::None
@@ -655,27 +674,22 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
 
     fn visit_item(&mut self, i: &hir::Item) {
         debug!("visit_item: {:?}", i);
-        self.check_item_well_formed(i);
+        let def_id = self.tcx.hir.local_def_id(i.id);
+        ty::maps::queries::check_item_well_formed::ensure(self.tcx, def_id);
         intravisit::walk_item(self, i);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
         debug!("visit_trait_item: {:?}", trait_item);
-        let method_sig = match trait_item.node {
-            hir::TraitItemKind::Method(ref sig, _) => Some(sig),
-            _ => None
-        };
-        self.check_associated_item(trait_item.id, trait_item.span, method_sig);
+        let def_id = self.tcx.hir.local_def_id(trait_item.id);
+        ty::maps::queries::check_trait_item_well_formed::ensure(self.tcx, def_id);
         intravisit::walk_trait_item(self, trait_item)
     }
 
     fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
         debug!("visit_impl_item: {:?}", impl_item);
-        let method_sig = match impl_item.node {
-            hir::ImplItemKind::Method(ref sig, _) => Some(sig),
-            _ => None
-        };
-        self.check_associated_item(impl_item.id, impl_item.span, method_sig);
+        let def_id = self.tcx.hir.local_def_id(impl_item.id);
+        ty::maps::queries::check_impl_item_well_formed::ensure(self.tcx, def_id);
         intravisit::walk_impl_item(self, impl_item)
     }
 }