]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_typeck/coherence/builtin.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / src / librustc_typeck / coherence / builtin.rs
index 9305eff1436520e7b3ee0bebf1c2e21c4e105198..8c6161a62647346b780450776524de5e5228a51d 100644 (file)
-// 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.
-
 //! Check properties that are required by built-in traits and set
-//! up data structures required by type-checking/translation.
-
-use rustc::middle::free_region::FreeRegionMap;
-use rustc::middle::region::RegionMaps;
-use rustc::middle::lang_items::UnsizeTraitLangItem;
-
-use rustc::traits::{self, ObligationCause};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::TypeFoldable;
-use rustc::ty::adjustment::CoerceUnsizedInfo;
-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_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
+//! up data structures required by type-checking/codegen.
+
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::lang_items::{
+    CoerceUnsizedTraitLangItem, DispatchFromDynTraitLangItem, UnsizeTraitLangItem,
+};
+use rustc_hir::ItemKind;
+use rustc_infer::infer;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
+use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
+use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_trait_selection::traits::predicate_for_trait_def;
+use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+
+pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
+    let lang_items = tcx.lang_items();
     Checker { tcx, trait_def_id }
-        .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
-        .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
-        .check(tcx.lang_items.coerce_unsized_trait(),
-               visit_implementation_of_coerce_unsized);
+        .check(lang_items.drop_trait(), visit_implementation_of_drop)
+        .check(lang_items.copy_trait(), visit_implementation_of_copy)
+        .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
+        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
 }
 
-struct Checker<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    trait_def_id: DefId
+struct Checker<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
 }
 
-impl<'a, 'tcx> Checker<'a, 'tcx> {
+impl<'tcx> Checker<'tcx> {
     fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
-        where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
+    where
+        F: FnMut(TyCtxt<'tcx>, LocalDefId),
     {
         if Some(self.trait_def_id) == trait_def_id {
-            for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
-                let impl_def_id = self.tcx.hir.local_def_id(impl_id);
-                f(self.tcx, self.trait_def_id, impl_def_id);
+            for &impl_id in self.tcx.hir().trait_impls(self.trait_def_id) {
+                let impl_def_id = self.tcx.hir().local_def_id(impl_id);
+                f(self.tcx, impl_def_id);
             }
         }
         self
     }
 }
 
-fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                          _drop_did: DefId,
-                                          impl_did: DefId) {
-    match tcx.type_of(impl_did).sty {
-        ty::TyAdt(..) => {}
-        _ => {
-            // Destructors only work on nominal types.
-            if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
-                match tcx.hir.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, "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");
-            }
-        }
+fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+    // Destructors only work on nominal types.
+    if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind {
+        return;
     }
+
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did);
+    let sp = match tcx.hir().expect_item(impl_hir_id).kind {
+        ItemKind::Impl { self_ty, .. } => self_ty.span,
+        _ => bug!("expected Drop impl item"),
+    };
+
+    struct_span_err!(
+        tcx.sess,
+        sp,
+        E0120,
+        "the `Drop` trait may only be implemented for structs, enums, and unions",
+    )
+    .span_label(sp, "must be a struct, enum, or union")
+    .emit();
 }
 
-fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                          _copy_did: DefId,
-                                          impl_did: DefId) {
+fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
 
-    let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) {
-        n
-    } else {
-        debug!("visit_implementation_of_copy(): impl not in this \
-                crate");
-        return;
-    };
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did);
 
     let self_type = tcx.type_of(impl_did);
-    debug!("visit_implementation_of_copy: self_type={:?} (bound)",
-           self_type);
+    debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
 
-    let span = tcx.hir.span(impl_node_id);
+    let span = tcx.hir().span(impl_hir_id);
     let param_env = tcx.param_env(impl_did);
-    assert!(!self_type.has_escaping_regions());
+    assert!(!self_type.has_escaping_bound_vars());
 
-    debug!("visit_implementation_of_copy: self_type={:?} (free)",
-           self_type);
+    debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
-    match param_env.can_type_implement_copy(tcx, self_type, span) {
+    match can_type_implement_copy(tcx, param_env, self_type) {
         Ok(()) => {}
-        Err(CopyImplementationError::InfrigingField(field)) => {
-            let item = tcx.hir.expect_item(impl_node_id);
-            let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
+        Err(CopyImplementationError::InfrigingFields(fields)) => {
+            let item = tcx.hir().expect_item(impl_hir_id);
+            let span = if let ItemKind::Impl { of_trait: Some(ref tr), .. } = item.kind {
                 tr.path.span
             } else {
                 span
             };
 
-            struct_span_err!(tcx.sess,
-                             span,
-                             E0204,
-                             "the trait `Copy` may not be implemented for this type")
-                .span_label(
-                    tcx.def_span(field.did),
-                    "this field does not implement `Copy`")
-                .emit()
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0204,
+                "the trait `Copy` may not be implemented for this type"
+            );
+            for span in fields.iter().map(|f| tcx.def_span(f.did)) {
+                err.span_label(span, "this field does not implement `Copy`");
+            }
+            err.emit()
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            let item = tcx.hir.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, "type is not a structure or enumeration")
-                .emit();
+            let item = tcx.hir().expect_item(impl_hir_id);
+            let span =
+                if let ItemKind::Impl { self_ty, .. } = item.kind { self_ty.span } else { span };
+
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0206,
+                "the trait `Copy` may not be implemented for this type"
+            )
+            .span_label(span, "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, "Copy not allowed on types with destructors")
-                .emit();
+            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, "Copy not allowed on types with destructors")
+            .emit();
         }
     }
 }
 
-fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                    _: DefId,
-                                                    impl_did: DefId) {
-    debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
-           impl_did);
+fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+    debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
 
     // Just compute this for the side-effects, in particular reporting
     // errors; other parts of the code may demand it for the info of
     // course.
-    if impl_did.is_local() {
-        let span = tcx.def_span(impl_did);
-        tcx.at(span).coerce_unsized_info(impl_did);
-    }
+    let span = tcx.def_span(impl_did);
+    tcx.at(span).coerce_unsized_info(impl_did);
 }
 
-pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     impl_did: DefId)
-                                     -> CoerceUnsizedInfo {
-    debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-    let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap();
+fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+    debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
 
-    let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
-        Ok(id) => id,
-        Err(err) => {
-            tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
-        }
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did);
+    let span = tcx.hir().span(impl_hir_id);
+
+    let dispatch_from_dyn_trait = tcx.require_lang_item(DispatchFromDynTraitLangItem, Some(span));
+
+    let source = tcx.type_of(impl_did);
+    assert!(!source.has_escaping_bound_vars());
+    let target = {
+        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+        assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
+
+        trait_ref.substs.type_at(1)
     };
 
+    debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
+
+    let param_env = tcx.param_env(impl_did);
+
+    let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
+
+    tcx.infer_ctxt().enter(|infcx| {
+        let cause = ObligationCause::misc(span, impl_hir_id);
+
+        use ty::TyKind::*;
+        match (&source.kind, &target.kind) {
+            (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
+                if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {}
+            (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
+            (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
+                if def_a.is_struct() && def_b.is_struct() =>
+            {
+                if def_a != def_b {
+                    let source_path = tcx.def_path_str(def_a.did);
+                    let target_path = tcx.def_path_str(def_b.did);
+
+                    create_err(&format!(
+                        "the trait `DispatchFromDyn` may only be implemented \
+                                for a coercion between structures with the same \
+                                definition; expected `{}`, found `{}`",
+                        source_path, target_path,
+                    ))
+                    .emit();
+
+                    return;
+                }
+
+                if def_a.repr.c() || def_a.repr.packed() {
+                    create_err(
+                        "structs implementing `DispatchFromDyn` may not have \
+                             `#[repr(packed)]` or `#[repr(C)]`",
+                    )
+                    .emit();
+                }
+
+                let fields = &def_a.non_enum_variant().fields;
+
+                let coerced_fields = fields
+                    .iter()
+                    .filter_map(|field| {
+                        let ty_a = field.ty(tcx, substs_a);
+                        let ty_b = field.ty(tcx, substs_b);
+
+                        if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
+                            if layout.is_zst() && layout.align.abi.bytes() == 1 {
+                                // ignore ZST fields with alignment of 1 byte
+                                return None;
+                            }
+                        }
+
+                        if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+                            if ok.obligations.is_empty() {
+                                create_err(
+                                    "the trait `DispatchFromDyn` may only be implemented \
+                                     for structs containing the field being coerced, \
+                                     ZST fields with 1 byte alignment, and nothing else",
+                                )
+                                .note(&format!(
+                                    "extra field `{}` of type `{}` is not allowed",
+                                    field.ident, ty_a,
+                                ))
+                                .emit();
+
+                                return None;
+                            }
+                        }
+
+                        Some(field)
+                    })
+                    .collect::<Vec<_>>();
+
+                if coerced_fields.is_empty() {
+                    create_err(
+                        "the trait `DispatchFromDyn` may only be implemented \
+                            for a coercion between structures with a single field \
+                            being coerced, none found",
+                    )
+                    .emit();
+                } else if coerced_fields.len() > 1 {
+                    create_err(
+                        "implementing the `DispatchFromDyn` trait requires multiple coercions",
+                    )
+                    .note(
+                        "the trait `DispatchFromDyn` may only be implemented \
+                                for a coercion between structures with a single field \
+                                being coerced",
+                    )
+                    .note(&format!(
+                        "currently, {} fields need coercions: {}",
+                        coerced_fields.len(),
+                        coerced_fields
+                            .iter()
+                            .map(|field| {
+                                format!(
+                                    "`{}` (`{}` to `{}`)",
+                                    field.ident,
+                                    field.ty(tcx, substs_a),
+                                    field.ty(tcx, substs_b),
+                                )
+                            })
+                            .collect::<Vec<_>>()
+                            .join(", ")
+                    ))
+                    .emit();
+                } else {
+                    let mut fulfill_cx = TraitEngine::new(infcx.tcx);
+
+                    for field in coerced_fields {
+                        let predicate = predicate_for_trait_def(
+                            tcx,
+                            param_env,
+                            cause.clone(),
+                            dispatch_from_dyn_trait,
+                            0,
+                            field.ty(tcx, substs_a),
+                            &[field.ty(tcx, substs_b).into()],
+                        );
+
+                        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, None, false);
+                    }
+
+                    // Finally, resolve all regions.
+                    let outlives_env = OutlivesEnvironment::new(param_env);
+                    infcx.resolve_regions_and_report_errors(
+                        impl_did.to_def_id(),
+                        &outlives_env,
+                        RegionckMode::default(),
+                    );
+                }
+            }
+            _ => {
+                create_err(
+                    "the trait `DispatchFromDyn` may only be implemented \
+                        for a coercion between structures",
+                )
+                .emit();
+            }
+        }
+    })
+}
+
+pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+    debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
+
     // this provider should only get invoked for local def-ids
-    let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| {
-        bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
+    let impl_hir_id = tcx.hir().as_local_hir_id(impl_did.expect_local());
+    let span = tcx.hir().span(impl_hir_id);
+
+    let coerce_unsized_trait = tcx.require_lang_item(CoerceUnsizedTraitLangItem, Some(span));
+
+    let unsize_trait = tcx.lang_items().require(UnsizeTraitLangItem).unwrap_or_else(|err| {
+        tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
     });
 
     let source = tcx.type_of(impl_did);
     let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.substs.type_at(1);
-    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
-           source,
-           target);
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
 
-    let span = tcx.hir.span(impl_node_id);
     let param_env = tcx.param_env(impl_did);
-    assert!(!source.has_escaping_regions());
+    assert!(!source.has_escaping_bound_vars());
 
     let err_info = CoerceUnsizedInfo { custom_kind: None };
 
-    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
-           source,
-           target);
+    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
     tcx.infer_ctxt().enter(|infcx| {
-        let cause = ObligationCause::misc(span, impl_node_id);
+        let cause = ObligationCause::misc(span, impl_hir_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)
+                           mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
+            if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+                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::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
+        let (source, target, trait_def_id, kind) = match (&source.kind, &target.kind) {
+            (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
                 infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+                let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+                let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
                 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)) => {
+            (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
+                let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+            }
+
+            (&ty::RawPtr(mt_a), &ty::RawPtr(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() => {
+            (&ty::Adt(def_a, substs_a), &ty::Adt(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 \
+                    let source_path = tcx.def_path_str(def_a.did);
+                    let target_path = tcx.def_path_str(def_b.did);
+                    struct_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);
+                               definition; expected `{}`, found `{}`",
+                        source_path,
+                        target_path
+                    )
+                    .emit();
                     return err_info;
                 }
 
@@ -276,7 +418,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // exactly one (non-phantom) field has changed its
                 // type, which we will expect to be the pointer that
                 // is becoming fat (we could probably generalize this
-                // to mutiple thin pointers of the same type becoming
+                // to multiple thin pointers of the same type becoming
                 // fat, but we don't). In this case:
                 //
                 // - `extra` has type `T` before and type `T` after
@@ -288,8 +430,9 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // conversion). This will work out because `U:
                 // Unsize<V>`, and we have a builtin rule that `*mut
                 // U` can be coerced to `*mut V` if `U: Unsize<V>`.
-                let fields = &def_a.struct_variant().fields;
-                let diff_fields = fields.iter()
+                let fields = &def_a.non_enum_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));
@@ -307,7 +450,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         // variance where possible. (This is because
                         // we may have to evaluate constraint
                         // expressions in the course of execution.)
-                        // See e.g. #41936.
+                        // See e.g., #41936.
                         if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
                             if ok.obligations.is_empty() {
                                 return None;
@@ -315,45 +458,55 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         }
 
                         // Collect up all fields that were significantly changed
-                        // i.e. those that contain T in coerce_unsized T -> U
+                        // 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 \
+                    struct_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");
+                               being coerced, none found"
+                    )
+                    .emit();
                     return err_info;
                 } else if diff_fields.len() > 1 {
-                    let item = tcx.hir.expect_item(impl_node_id);
-                    let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
+                    let item = tcx.hir().expect_item(impl_hir_id);
+                    let span = if let ItemKind::Impl { of_trait: Some(ref t), .. } = item.kind {
                         t.path.span
                     } else {
-                        tcx.hir.span(impl_node_id)
+                        tcx.hir().span(impl_hir_id)
                     };
 
-                    let mut err = struct_span_err!(tcx.sess,
-                                                   span,
-                                                   E0375,
-                                                   "implementing the trait \
+                    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, "requires multiple coercions");
-                    err.emit();
+                                                    coercions"
+                    )
+                    .note(
+                        "`CoerceUnsized` may only be implemented for \
+                              a coercion between structures with one field being coerced",
+                    )
+                    .note(&format!(
+                        "currently, {} fields need coercions: {}",
+                        diff_fields.len(),
+                        diff_fields
+                            .iter()
+                            .map(|&(i, a, b)| {
+                                format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b)
+                            })
+                            .collect::<Vec<_>>()
+                            .join(", ")
+                    ))
+                    .span_label(span, "requires multiple coercions")
+                    .emit();
                     return err_info;
                 }
 
@@ -363,40 +516,42 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
 
             _ => {
-                span_err!(tcx.sess,
-                          span,
-                          E0376,
-                          "the trait `CoerceUnsized` may only be implemented \
-                           for a coercion between structures");
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0376,
+                    "the trait `CoerceUnsized` may only be implemented \
+                           for a coercion between structures"
+                )
+                .emit();
                 return err_info;
             }
         };
 
-        let mut fulfill_cx = traits::FulfillmentContext::new();
+        let mut fulfill_cx = TraitEngine::new(infcx.tcx);
 
         // Register an obligation for `A: Trait<B>`.
-        let cause = traits::ObligationCause::misc(span, impl_node_id);
-        let predicate = tcx.predicate_for_trait_def(param_env,
-                                                    cause,
-                                                    trait_def_id,
-                                                    0,
-                                                    source,
-                                                    &[target]);
+        let cause = traits::ObligationCause::misc(span, impl_hir_id);
+        let predicate = predicate_for_trait_def(
+            tcx,
+            param_env,
+            cause,
+            trait_def_id,
+            0,
+            source,
+            &[target.into()],
+        );
         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, None);
+            infcx.report_fulfillment_errors(&errors, None, false);
         }
 
         // Finally, resolve all regions.
-        let region_maps = RegionMaps::new();
-        let mut free_regions = FreeRegionMap::new();
-        free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
-        infcx.resolve_regions_and_report_errors(impl_did, &region_maps, &free_regions);
+        let outlives_env = OutlivesEnvironment::new(param_env);
+        infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default());
 
-        CoerceUnsizedInfo {
-            custom_kind: kind
-        }
+        CoerceUnsizedInfo { custom_kind: kind }
     })
 }