about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/coherence/builtin.rs569
-rw-r--r--src/librustc_typeck/coherence/mod.rs46
2 files changed, 298 insertions, 317 deletions
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 6fde18dbf82..8a12eba7d5d 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -22,336 +22,329 @@ use rustc::ty::subst::Subst;
 use rustc::ty::util::CopyImplementationError;
 use rustc::infer;
 
+use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use rustc::hir::{self, ItemImpl};
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    populate_destructors(tcx);
-    check_implementations_of_copy(tcx);
-    check_implementations_of_coerce_unsized(tcx);
-}
+    if let Some(drop_trait) = tcx.lang_items.drop_trait() {
+        tcx.lookup_trait_def(drop_trait).for_each_impl(tcx, |impl_did| {
+            visit_implementation_of_drop(tcx, impl_did)
+        });
+    }
 
-fn populate_destructors<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let drop_trait = match tcx.lang_items.drop_trait() {
-        Some(id) => id,
-        None => return,
-    };
-    tcx.populate_implementations_for_trait_if_necessary(drop_trait);
-    let drop_trait = tcx.lookup_trait_def(drop_trait);
-
-    drop_trait.for_each_impl(tcx, |impl_did| {
-        let items = tcx.associated_item_def_ids(impl_did);
-        if items.is_empty() {
-            // We'll error out later. For now, just don't ICE.
-            return;
-        }
-        let method_def_id = items[0];
+    if let Some(copy_trait) = tcx.lang_items.copy_trait() {
+        tcx.lookup_trait_def(copy_trait).for_each_impl(tcx, |impl_did| {
+            visit_implementation_of_copy(tcx, impl_did)
+        });
+    }
 
-        let self_type = tcx.item_type(impl_did);
-        match self_type.sty {
-            ty::TyAdt(type_def, _) => {
-                type_def.set_destructor(method_def_id);
+    if let Some(coerce_unsized_trait) = tcx.lang_items.coerce_unsized_trait() {
+        let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
+            Ok(id) => id,
+            Err(err) => {
+                tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
             }
-            _ => {
-                // Destructors only work on nominal types.
-                if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
-                    match tcx.map.find(impl_node_id) {
-                        Some(hir_map::NodeItem(item)) => {
-                            let span = match item.node {
-                                ItemImpl(.., ref ty, _) => ty.span,
-                                _ => item.span,
-                            };
-                            struct_span_err!(tcx.sess,
-                                             span,
-                                             E0120,
-                                             "the Drop trait may only be implemented on \
-                                              structures")
-                                    .span_label(span,
-                                                &format!("implementing Drop requires a struct"))
-                                .emit();
-                        }
-                        _ => {
-                            bug!("didn't find impl in ast map");
-                        }
+        };
+
+        tcx.lookup_trait_def(coerce_unsized_trait).for_each_impl(tcx, |impl_did| {
+            visit_implementation_of_coerce_unsized(tcx, impl_did,
+                                                   unsize_trait, coerce_unsized_trait)
+        });
+    }
+}
+
+fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) {
+    let items = tcx.associated_item_def_ids(impl_did);
+    if items.is_empty() {
+        // We'll error out later. For now, just don't ICE.
+        return;
+    }
+    let method_def_id = items[0];
+
+    let self_type = tcx.item_type(impl_did);
+    match self_type.sty {
+        ty::TyAdt(type_def, _) => {
+            type_def.set_destructor(method_def_id);
+        }
+        _ => {
+            // Destructors only work on nominal types.
+            if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
+                match tcx.map.find(impl_node_id) {
+                    Some(hir_map::NodeItem(item)) => {
+                        let span = match item.node {
+                            ItemImpl(.., ref ty, _) => ty.span,
+                            _ => item.span,
+                        };
+                        struct_span_err!(tcx.sess,
+                                         span,
+                                         E0120,
+                                         "the Drop trait may only be implemented on \
+                                         structures")
+                            .span_label(span,
+                                        &format!("implementing Drop requires a struct"))
+                            .emit();
+                    }
+                    _ => {
+                        bug!("didn't find impl in ast map");
                     }
-                } else {
-                    bug!("found external impl of Drop trait on \
-                          something other than a struct");
                 }
+            } else {
+                bug!("found external impl of Drop trait on \
+                      something other than a struct");
             }
         }
-    });
+    }
 }
 
-fn check_implementations_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let copy_trait = match tcx.lang_items.copy_trait() {
-        Some(id) => id,
-        None => return,
+fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) {
+    debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
+
+    let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+        n
+    } else {
+        debug!("visit_implementation_of_copy(): impl not in this \
+                crate");
+        return;
     };
-    tcx.populate_implementations_for_trait_if_necessary(copy_trait);
-    let copy_trait = tcx.lookup_trait_def(copy_trait);
-
-    copy_trait.for_each_impl(tcx, |impl_did| {
-        debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
-
-        let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
-            n
-        } else {
-            debug!("check_implementations_of_copy(): impl not in this \
-                    crate");
-            return;
-        };
 
-        let self_type = tcx.item_type(impl_did);
-        debug!("check_implementations_of_copy: self_type={:?} (bound)",
-               self_type);
-
-        let span = tcx.map.span(impl_node_id);
-        let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-        let self_type = self_type.subst(tcx, &param_env.free_substs);
-        assert!(!self_type.has_escaping_regions());
-
-        debug!("check_implementations_of_copy: self_type={:?} (free)",
-               self_type);
-
-        match param_env.can_type_implement_copy(tcx, self_type, span) {
-            Ok(()) => {}
-            Err(CopyImplementationError::InfrigingField(name)) => {
-                struct_span_err!(tcx.sess,
-                                 span,
-                                 E0204,
-                                 "the trait `Copy` may not be implemented for this type")
-                    .span_label(span, &format!("field `{}` does not implement `Copy`", name))
-                    .emit()
-            }
-            Err(CopyImplementationError::InfrigingVariant(name)) => {
-                let item = tcx.map.expect_item(impl_node_id);
-                let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
-                    tr.path.span
-                } else {
-                    span
-                };
-
-                struct_span_err!(tcx.sess,
-                                 span,
-                                 E0205,
-                                 "the trait `Copy` may not be implemented for this type")
-                    .span_label(span,
-                                &format!("variant `{}` does not implement `Copy`", name))
-                    .emit()
-            }
-            Err(CopyImplementationError::NotAnAdt) => {
-                let item = tcx.map.expect_item(impl_node_id);
-                let span = if let ItemImpl(.., ref ty, _) = item.node {
-                    ty.span
-                } else {
-                    span
-                };
-
-                struct_span_err!(tcx.sess,
-                                 span,
-                                 E0206,
-                                 "the trait `Copy` may not be implemented for this type")
-                    .span_label(span, &format!("type is not a structure or enumeration"))
-                    .emit();
-            }
-            Err(CopyImplementationError::HasDestructor) => {
-                struct_span_err!(tcx.sess,
-                                 span,
-                                 E0184,
-                                 "the trait `Copy` may not be implemented for this type; the \
-                                  type has a destructor")
-                        .span_label(span, &format!("Copy not allowed on types with destructors"))
-                    .emit();
-            }
+    let self_type = tcx.item_type(impl_did);
+    debug!("visit_implementation_of_copy: self_type={:?} (bound)",
+           self_type);
+
+    let span = tcx.map.span(impl_node_id);
+    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+    let self_type = self_type.subst(tcx, &param_env.free_substs);
+    assert!(!self_type.has_escaping_regions());
+
+    debug!("visit_implementation_of_copy: self_type={:?} (free)",
+           self_type);
+
+    match param_env.can_type_implement_copy(tcx, self_type, span) {
+        Ok(()) => {}
+        Err(CopyImplementationError::InfrigingField(name)) => {
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0204,
+                             "the trait `Copy` may not be implemented for this type")
+                .span_label(span, &format!("field `{}` does not implement `Copy`", name))
+                .emit()
         }
-    });
-}
+        Err(CopyImplementationError::InfrigingVariant(name)) => {
+            let item = tcx.map.expect_item(impl_node_id);
+            let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
+                tr.path.span
+            } else {
+                span
+            };
 
-fn check_implementations_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
-        Some(id) => id,
-        None => return,
-    };
-    let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
-        Ok(id) => id,
-        Err(err) => {
-            tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0205,
+                             "the trait `Copy` may not be implemented for this type")
+                .span_label(span,
+                            &format!("variant `{}` does not implement `Copy`", name))
+                .emit()
         }
-    };
+        Err(CopyImplementationError::NotAnAdt) => {
+            let item = tcx.map.expect_item(impl_node_id);
+            let span = if let ItemImpl(.., ref ty, _) = item.node {
+                ty.span
+            } else {
+                span
+            };
 
-    let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0206,
+                             "the trait `Copy` may not be implemented for this type")
+                .span_label(span, &format!("type is not a structure or enumeration"))
+                .emit();
+        }
+        Err(CopyImplementationError::HasDestructor) => {
+            struct_span_err!(tcx.sess,
+                             span,
+                             E0184,
+                             "the trait `Copy` may not be implemented for this type; the \
+                              type has a destructor")
+                .span_label(span, &format!("Copy not allowed on types with destructors"))
+                .emit();
+        }
+    }
+}
 
-    trait_def.for_each_impl(tcx, |impl_did| {
-        debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
-               impl_did);
+fn visit_implementation_of_coerce_unsized<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId,
+    unsize_trait: DefId, coerce_unsized_trait: DefId)
+{
+    debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
+           impl_did);
+
+    let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+        n
+    } else {
+        debug!("visit_implementation_of_coerce_unsized(): impl not \
+                in this crate");
+        return;
+    };
 
-        let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
-            n
-        } else {
-            debug!("check_implementations_of_coerce_unsized(): impl not \
-                    in this crate");
-            return;
+    let source = tcx.item_type(impl_did);
+    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+    let target = trait_ref.substs.type_at(1);
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
+           source,
+           target);
+
+    let span = tcx.map.span(impl_node_id);
+    let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
+    let source = source.subst(tcx, &param_env.free_substs);
+    let target = target.subst(tcx, &param_env.free_substs);
+    assert!(!source.has_escaping_regions());
+
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
+           source,
+           target);
+
+    tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
+        let cause = ObligationCause::misc(span, impl_node_id);
+        let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+                           mt_b: ty::TypeAndMut<'tcx>,
+                           mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
+            if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
+                infcx.report_mismatched_types(&cause,
+                                              mk_ptr(mt_b.ty),
+                                              target,
+                                              ty::error::TypeError::Mutability)
+                         .emit();
+            }
+            (mt_a.ty, mt_b.ty, unsize_trait, None)
         };
+        let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
+            (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
 
-        let source = tcx.item_type(impl_did);
-        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
-        let target = trait_ref.substs.type_at(1);
-        debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
-               source,
-               target);
-
-        let span = tcx.map.span(impl_node_id);
-        let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
-        let source = source.subst(tcx, &param_env.free_substs);
-        let target = target.subst(tcx, &param_env.free_substs);
-        assert!(!source.has_escaping_regions());
-
-        debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
-               source,
-               target);
-
-        tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
-            let cause = ObligationCause::misc(span, impl_node_id);
-            let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
-                               mt_b: ty::TypeAndMut<'tcx>,
-                               mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
-                if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
-                    infcx.report_mismatched_types(&cause,
-                                                  mk_ptr(mt_b.ty),
-                                                  target,
-                                                  ty::error::TypeError::Mutability)
-                         .emit();
-                }
-                (mt_a.ty, mt_b.ty, unsize_trait, None)
-            };
-            let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
-                (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
+            (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
+                infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+            }
 
-                (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
-                    infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
-                    check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
-                }
+            (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
+            (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+            }
 
-                (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
-                (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
-                    check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+            (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
+                if def_a.is_struct() && def_b.is_struct() => {
+                if def_a != def_b {
+                    let source_path = tcx.item_path_str(def_a.did);
+                    let target_path = tcx.item_path_str(def_b.did);
+                    span_err!(tcx.sess,
+                              span,
+                              E0377,
+                              "the trait `CoerceUnsized` may only be implemented \
+                               for a coercion between structures with the same \
+                               definition; expected {}, found {}",
+                              source_path,
+                              target_path);
+                    return;
                 }
 
-                (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
-                    if def_a.is_struct() && def_b.is_struct() => {
-                    if def_a != def_b {
-                        let source_path = tcx.item_path_str(def_a.did);
-                        let target_path = tcx.item_path_str(def_b.did);
-                        span_err!(tcx.sess,
-                                  span,
-                                  E0377,
-                                  "the trait `CoerceUnsized` may only be implemented \
-                                   for a coercion between structures with the same \
-                                   definition; expected {}, found {}",
-                                  source_path,
-                                  target_path);
-                        return;
-                    }
+                let fields = &def_a.struct_variant().fields;
+                let diff_fields = fields.iter()
+                    .enumerate()
+                    .filter_map(|(i, f)| {
+                        let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
 
-                    let fields = &def_a.struct_variant().fields;
-                    let diff_fields = fields.iter()
-                        .enumerate()
-                        .filter_map(|(i, f)| {
-                            let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+                        if tcx.item_type(f.did).is_phantom_data() {
+                            // Ignore PhantomData fields
+                            return None;
+                        }
 
-                            if tcx.item_type(f.did).is_phantom_data() {
-                                // Ignore PhantomData fields
+                        // Ignore fields that aren't significantly changed
+                        if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
+                            if ok.obligations.is_empty() {
                                 return None;
                             }
+                        }
 
-                            // Ignore fields that aren't significantly changed
-                            if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
-                                if ok.obligations.is_empty() {
-                                    return None;
-                                }
-                            }
-
-                            // Collect up all fields that were significantly changed
-                            // i.e. those that contain T in coerce_unsized T -> U
-                            Some((i, a, b))
-                        })
-                        .collect::<Vec<_>>();
-
-                    if diff_fields.is_empty() {
-                        span_err!(tcx.sess,
-                                  span,
-                                  E0374,
-                                  "the trait `CoerceUnsized` may only be implemented \
-                                   for a coercion between structures with one field \
-                                   being coerced, none found");
-                        return;
-                    } else if diff_fields.len() > 1 {
-                        let item = tcx.map.expect_item(impl_node_id);
-                        let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
-                            t.path.span
-                        } else {
-                            tcx.map.span(impl_node_id)
-                        };
-
-                        let mut err = struct_span_err!(tcx.sess,
-                                                       span,
-                                                       E0375,
-                                                       "implementing the trait \
-                                                        `CoerceUnsized` requires multiple \
-                                                        coercions");
-                        err.note("`CoerceUnsized` may only be implemented for \
-                                  a coercion between structures with one field being coerced");
-                        err.note(&format!("currently, {} fields need coercions: {}",
-                                          diff_fields.len(),
-                                          diff_fields.iter()
-                                          .map(|&(i, a, b)| {
-                                              format!("{} ({} to {})", fields[i].name, a, b)
-                                          })
-                                          .collect::<Vec<_>>()
-                                          .join(", ")));
-                        err.span_label(span, &format!("requires multiple coercions"));
-                        err.emit();
-                        return;
-                    }
+                        // Collect up all fields that were significantly changed
+                        // i.e. those that contain T in coerce_unsized T -> U
+                        Some((i, a, b))
+                    })
+                    .collect::<Vec<_>>();
 
-                    let (i, a, b) = diff_fields[0];
-                    let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
-                    (a, b, coerce_unsized_trait, Some(kind))
-                }
-
-                _ => {
+                if diff_fields.is_empty() {
                     span_err!(tcx.sess,
                               span,
-                              E0376,
+                              E0374,
                               "the trait `CoerceUnsized` may only be implemented \
-                               for a coercion between structures");
+                               for a coercion between structures with one field \
+                               being coerced, none found");
+                    return;
+                } else if diff_fields.len() > 1 {
+                    let item = tcx.map.expect_item(impl_node_id);
+                    let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
+                        t.path.span
+                    } else {
+                        tcx.map.span(impl_node_id)
+                    };
+
+                    let mut err = struct_span_err!(tcx.sess,
+                                                   span,
+                                                   E0375,
+                                                   "implementing the trait \
+                                                    `CoerceUnsized` requires multiple \
+                                                    coercions");
+                    err.note("`CoerceUnsized` may only be implemented for \
+                              a coercion between structures with one field being coerced");
+                    err.note(&format!("currently, {} fields need coercions: {}",
+                                      diff_fields.len(),
+                                      diff_fields.iter()
+                                      .map(|&(i, a, b)| {
+                                          format!("{} ({} to {})", fields[i].name, a, b)
+                                      })
+                                      .collect::<Vec<_>>()
+                                      .join(", ")));
+                    err.span_label(span, &format!("requires multiple coercions"));
+                    err.emit();
                     return;
                 }
-            };
-
-            let mut fulfill_cx = traits::FulfillmentContext::new();
 
-            // Register an obligation for `A: Trait<B>`.
-            let cause = traits::ObligationCause::misc(span, impl_node_id);
-            let predicate =
-                tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
-            fulfill_cx.register_predicate_obligation(&infcx, predicate);
+                let (i, a, b) = diff_fields[0];
+                let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+                (a, b, coerce_unsized_trait, Some(kind))
+            }
 
-            // Check that all transitive obligations are satisfied.
-            if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
-                infcx.report_fulfillment_errors(&errors);
+            _ => {
+                span_err!(tcx.sess,
+                          span,
+                          E0376,
+                          "the trait `CoerceUnsized` may only be implemented \
+                           for a coercion between structures");
+                return;
             }
+        };
 
-            // Finally, resolve all regions.
-            let mut free_regions = FreeRegionMap::new();
-            free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
-                                                             .caller_bounds);
-            infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
+        let mut fulfill_cx = traits::FulfillmentContext::new();
 
-            if let Some(kind) = kind {
-                tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
-            }
-        });
+        // Register an obligation for `A: Trait<B>`.
+        let cause = traits::ObligationCause::misc(span, impl_node_id);
+        let predicate =
+            tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
+        fulfill_cx.register_predicate_obligation(&infcx, predicate);
+
+        // Check that all transitive obligations are satisfied.
+        if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(&errors);
+        }
+
+        // Finally, resolve all regions.
+        let mut free_regions = FreeRegionMap::new();
+        free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
+                                                         .caller_bounds);
+        infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
+
+        if let Some(kind) = kind {
+            tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+        }
     });
 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 3293818348a..316e6555b41 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -16,7 +16,6 @@
 // mappings. That mapping code resides here.
 
 use hir::def_id::DefId;
-use rustc::traits::Reveal;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
@@ -25,7 +24,6 @@ use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use rustc::ty::{TyProjection, TyAnon};
 use CrateCtxt;
-use rustc::infer::{InferCtxt};
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -37,16 +35,15 @@ mod orphan;
 mod overlap;
 mod unsafety;
 
-struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    crate_context: &'a CrateCtxt<'a, 'gcx>,
-    inference_context: InferCtxt<'a, 'gcx, 'tcx>,
+struct CoherenceChecker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
+struct CoherenceCheckVisitor<'a, 'tcx: 'a> {
+    cc: &'a CoherenceChecker<'a, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
             self.cc.check_implementation(item)
@@ -60,7 +57,7 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx,
     }
 }
 
-impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
     // Returns the def ID of the base type, if there is one.
     fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
         match ty.sty {
@@ -68,7 +65,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
 
             TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
 
-            TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
+            TyBox(_) => self.tcx.lang_items.owned_box(),
 
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
             TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
@@ -88,21 +85,21 @@ 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_item_likes_in_krate(
+        self.tcx.visit_all_item_likes_in_krate(
             DepNode::CoherenceCheckImpl,
             &mut CoherenceCheckVisitor { cc: self });
-        builtin::check(self.crate_context.tcx);
+        builtin::check(self.tcx);
     }
 
     fn check_implementation(&self, item: &Item) {
-        let tcx = self.crate_context.tcx;
+        let tcx = self.tcx;
         let impl_did = tcx.map.local_def_id(item.id);
         let self_type = tcx.item_type(impl_did);
 
         // If there are no traits, then this implementation must have a
         // base type.
 
-        if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
+        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
             debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
                    trait_ref,
                    item.name);
@@ -113,9 +110,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 return;
             }
 
-            enforce_trait_manually_implementable(self.crate_context.tcx,
-                                                 item.span,
-                                                 trait_ref.def_id);
+            enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
             self.add_trait_impl(trait_ref, impl_did);
         } else {
             // Skip inherent impls where the self type is an error
@@ -134,16 +129,15 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
     }
 
     fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
-        let tcx = self.crate_context.tcx;
-        tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
+        self.tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
     }
 
-    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
+    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
         debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
                impl_trait_ref,
                impl_def_id);
-        let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
-        trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
+        let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
+        trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
     }
 }
 
@@ -176,13 +170,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
 
 pub fn check_coherence(ccx: &CrateCtxt) {
     let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
-    ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
-        CoherenceChecker {
-                crate_context: ccx,
-                inference_context: infcx,
-            }
-            .check();
-    });
+    CoherenceChecker { tcx: ccx.tcx }.check();
     unsafety::check(ccx.tcx);
     orphan::check(ccx.tcx);
     overlap::check(ccx.tcx);