about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src/coherence/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/coherence/builtin.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs645
1 files changed, 314 insertions, 331 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 2cc389498af..b6c91d425df 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -108,43 +108,42 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 // why this field does not implement Copy. This is useful because sometimes
                 // it is not immediately clear why Copy is not implemented for a field, since
                 // all we point at is the field itself.
-                tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-                    for error in traits::fully_solve_bound(
-                        &infcx,
-                        traits::ObligationCause::dummy_with_span(field_ty_span),
-                        param_env,
-                        ty,
-                        tcx.lang_items().copy_trait().unwrap(),
-                    ) {
-                        let error_predicate = error.obligation.predicate;
-                        // Only note if it's not the root obligation, otherwise it's trivial and
-                        // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
-                        // FIXME: This error could be more descriptive, especially if the error_predicate
-                        // contains a foreign type or if it's a deeply nested type...
-                        if error_predicate != error.root_obligation.predicate {
-                            errors
-                                .entry((ty.to_string(), error_predicate.to_string()))
-                                .or_default()
-                                .push(error.obligation.cause.span);
-                        }
-                        if let ty::PredicateKind::Trait(ty::TraitPredicate {
-                            trait_ref,
-                            polarity: ty::ImplPolarity::Positive,
-                            ..
-                        }) = error_predicate.kind().skip_binder()
-                        {
-                            let ty = trait_ref.self_ty();
-                            if let ty::Param(_) = ty.kind() {
-                                bounds.push((
-                                    format!("{ty}"),
-                                    trait_ref.print_only_trait_path().to_string(),
-                                    Some(trait_ref.def_id),
-                                ));
-                            }
+                let infcx = tcx.infer_ctxt().ignoring_regions().build();
+                for error in traits::fully_solve_bound(
+                    &infcx,
+                    traits::ObligationCause::dummy_with_span(field_ty_span),
+                    param_env,
+                    ty,
+                    tcx.lang_items().copy_trait().unwrap(),
+                ) {
+                    let error_predicate = error.obligation.predicate;
+                    // Only note if it's not the root obligation, otherwise it's trivial and
+                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+                    // FIXME: This error could be more descriptive, especially if the error_predicate
+                    // contains a foreign type or if it's a deeply nested type...
+                    if error_predicate != error.root_obligation.predicate {
+                        errors
+                            .entry((ty.to_string(), error_predicate.to_string()))
+                            .or_default()
+                            .push(error.obligation.cause.span);
+                    }
+                    if let ty::PredicateKind::Trait(ty::TraitPredicate {
+                        trait_ref,
+                        polarity: ty::ImplPolarity::Positive,
+                        ..
+                    }) = error_predicate.kind().skip_binder()
+                    {
+                        let ty = trait_ref.self_ty();
+                        if let ty::Param(_) = ty.kind() {
+                            bounds.push((
+                                format!("{ty}"),
+                                trait_ref.print_only_trait_path().to_string(),
+                                Some(trait_ref.def_id),
+                            ));
                         }
                     }
-                });
+                }
             }
             for ((ty, error_predicate), spans) in errors {
                 let span: MultiSpan = spans.into();
@@ -205,91 +204,89 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, 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 rustc_type_ir::sty::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();
+    let infcx = tcx.infer_ctxt().build();
+    let cause = ObligationCause::misc(span, impl_hir_id);
+
+    use rustc_type_ir::sty::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;
-                }
+                return;
+            }
 
-                if def_a.repr().c() || def_a.repr().packed() {
-                    create_err(
-                        "structs implementing `DispatchFromDyn` may not have \
-                             `#[repr(packed)]` or `#[repr(C)]`",
-                    )
-                    .emit();
-                }
+            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 fields = &def_a.non_enum_variant().fields;
 
-                let coerced_fields = fields
-                    .iter()
-                    .filter(|field| {
-                        let ty_a = field.ty(tcx, substs_a);
-                        let ty_b = field.ty(tcx, substs_b);
+            let coerced_fields = fields
+                .iter()
+                .filter(|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 false;
-                            }
+                    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 false;
                         }
+                    }
 
-                        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.name, ty_a,
-                                ))
-                                .emit();
-
-                                return false;
-                            }
+                    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.name, ty_a,
+                            ))
+                            .emit();
+
+                            return false;
                         }
+                    }
 
-                        return true;
-                    })
-                    .collect::<Vec<_>>();
+                    return true;
+                })
+                .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",
-                    )
+            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",
+                            for a coercion between structures with a single field \
+                            being coerced",
                     )
                     .note(&format!(
                         "currently, {} fields need coercions: {}",
@@ -308,39 +305,38 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                             .join(", ")
                     ))
                     .emit();
-                } else {
-                    let errors = traits::fully_solve_obligations(
-                        &infcx,
-                        coerced_fields.into_iter().map(|field| {
-                            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()],
-                            )
-                        }),
-                    );
-                    if !errors.is_empty() {
-                        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
-                    }
-
-                    // Finally, resolve all regions.
-                    let outlives_env = OutlivesEnvironment::new(param_env);
-                    infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+            } else {
+                let errors = traits::fully_solve_obligations(
+                    &infcx,
+                    coerced_fields.into_iter().map(|field| {
+                        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()],
+                        )
+                    }),
+                );
+                if !errors.is_empty() {
+                    infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
                 }
-            }
-            _ => {
-                create_err(
-                    "the trait `DispatchFromDyn` may only be implemented \
-                        for a coercion between structures",
-                )
-                .emit();
+
+                // Finally, resolve all regions.
+                let outlives_env = OutlivesEnvironment::new(param_env);
+                infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
             }
         }
-    })
+        _ => {
+            create_err(
+                "the trait `DispatchFromDyn` may only be implemented \
+                    for a coercion between structures",
+            )
+            .emit();
+        }
+    }
 }
 
 pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
@@ -369,221 +365,208 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
-    tcx.infer_ctxt().enter(|infcx| {
-        let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-        let cause = ObligationCause::misc(span, impl_hir_id);
-        let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
-                           mt_b: ty::TypeAndMut<'tcx>,
-                           mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
-            if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
-                infcx
-                    .err_ctxt()
-                    .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.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))
-            }
+    let infcx = tcx.infer_ctxt().build();
+    let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+    let cause = ObligationCause::misc(span, impl_hir_id);
+    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+                       mt_b: ty::TypeAndMut<'tcx>,
+                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
+        if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+            infcx
+                .err_ctxt()
+                .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.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::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::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::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
-                check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+        (&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.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
+                )
+                .emit();
+                return err_info;
             }
 
-            (&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.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
-                    )
-                    .emit();
-                    return err_info;
-                }
+            // Here we are considering a case of converting
+            // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
+            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
+            //
+            //     struct Foo<T, U> {
+            //         extra: T,
+            //         ptr: *mut U,
+            //     }
+            //
+            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
+            // to `Foo<T, [i32]>`. That impl would look like:
+            //
+            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
+            //
+            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
+            // when this coercion occurs, we would be changing the
+            // field `ptr` from a thin pointer of type `*mut [i32;
+            // 3]` to a fat pointer of type `*mut [i32]` (with
+            // extra data `3`).  **The purpose of this check is to
+            // make sure that we know how to do this conversion.**
+            //
+            // To check if this impl is legal, we would walk down
+            // the fields of `Foo` and consider their types with
+            // both substitutes. We are looking to find that
+            // 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 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
+            // - `ptr` has type `*mut U` before and type `*mut V` after
+            //
+            // Since just one field changed, we would then check
+            // that `*mut U: CoerceUnsized<*mut V>` is implemented
+            // (in other words, that we know how to do this
+            // 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.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));
+
+                    if tcx.type_of(f.did).is_phantom_data() {
+                        // Ignore PhantomData fields
+                        return None;
+                    }
 
-                // Here we are considering a case of converting
-                // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
-                // which acts like a pointer to `U`, but carries along some extra data of type `T`:
-                //
-                //     struct Foo<T, U> {
-                //         extra: T,
-                //         ptr: *mut U,
-                //     }
-                //
-                // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
-                // to `Foo<T, [i32]>`. That impl would look like:
-                //
-                //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
-                //
-                // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
-                // when this coercion occurs, we would be changing the
-                // field `ptr` from a thin pointer of type `*mut [i32;
-                // 3]` to a fat pointer of type `*mut [i32]` (with
-                // extra data `3`).  **The purpose of this check is to
-                // make sure that we know how to do this conversion.**
-                //
-                // To check if this impl is legal, we would walk down
-                // the fields of `Foo` and consider their types with
-                // both substitutes. We are looking to find that
-                // 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 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
-                // - `ptr` has type `*mut U` before and type `*mut V` after
-                //
-                // Since just one field changed, we would then check
-                // that `*mut U: CoerceUnsized<*mut V>` is implemented
-                // (in other words, that we know how to do this
-                // 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.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));
-
-                        if tcx.type_of(f.did).is_phantom_data() {
-                            // Ignore PhantomData fields
+                    // Ignore fields that aren't changed; it may
+                    // be that we could get away with subtyping or
+                    // something more accepting, but we use
+                    // equality because we want to be able to
+                    // perform this check without computing
+                    // variance where possible. (This is because
+                    // we may have to evaluate constraint
+                    // expressions in the course of execution.)
+                    // See e.g., #41936.
+                    if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
+                        if ok.obligations.is_empty() {
                             return None;
                         }
+                    }
 
-                        // Ignore fields that aren't changed; it may
-                        // be that we could get away with subtyping or
-                        // something more accepting, but we use
-                        // equality because we want to be able to
-                        // perform this check without computing
-                        // variance where possible. (This is because
-                        // we may have to evaluate constraint
-                        // expressions in the course of execution.)
-                        // See e.g., #41936.
-                        if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
-                            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<_>>();
 
-                        // 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() {
-                    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"
-                    )
-                    .emit();
-                    return err_info;
-                } else if diff_fields.len() > 1 {
-                    let item = tcx.hir().expect_item(impl_did);
-                    let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
-                        item.kind
-                    {
+            if diff_fields.is_empty() {
+                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"
+                )
+                .emit();
+                return err_info;
+            } else if diff_fields.len() > 1 {
+                let item = tcx.hir().expect_item(impl_did);
+                let span =
+                    if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
                         t.path.span
                     } else {
                         tcx.def_span(impl_did)
                     };
 
-                    struct_span_err!(
-                        tcx.sess,
-                        span,
-                        E0375,
-                        "implementing the trait \
-                                                    `CoerceUnsized` requires multiple \
-                                                    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].name, a, b)
-                            })
-                            .collect::<Vec<_>>()
-                            .join(", ")
-                    ))
-                    .span_label(span, "requires multiple coercions")
-                    .emit();
-                    return err_info;
-                }
-
-                let (i, a, b) = diff_fields[0];
-                let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
-                (a, b, coerce_unsized_trait, Some(kind))
-            }
-
-            _ => {
                 struct_span_err!(
                     tcx.sess,
                     span,
-                    E0376,
-                    "the trait `CoerceUnsized` may only be implemented \
-                           for a coercion between structures"
+                    E0375,
+                    "implementing the trait \
+                                                `CoerceUnsized` requires multiple \
+                                                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].name, a, b) })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                ))
+                .span_label(span, "requires multiple coercions")
                 .emit();
                 return err_info;
             }
-        };
-
-        // Register an obligation for `A: Trait<B>`.
-        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()],
-        );
-        let errors = traits::fully_solve_obligation(&infcx, predicate);
-        if !errors.is_empty() {
-            infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+
+            let (i, a, b) = diff_fields[0];
+            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+            (a, b, coerce_unsized_trait, Some(kind))
         }
 
-        // Finally, resolve all regions.
-        let outlives_env = OutlivesEnvironment::new(param_env);
-        infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+        _ => {
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0376,
+                "the trait `CoerceUnsized` may only be implemented \
+                       for a coercion between structures"
+            )
+            .emit();
+            return err_info;
+        }
+    };
+
+    // Register an obligation for `A: Trait<B>`.
+    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()]);
+    let errors = traits::fully_solve_obligation(&infcx, predicate);
+    if !errors.is_empty() {
+        infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+    }
+
+    // Finally, resolve all regions.
+    let outlives_env = OutlivesEnvironment::new(param_env);
+    infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
 
-        CoerceUnsizedInfo { custom_kind: kind }
-    })
+    CoerceUnsizedInfo { custom_kind: kind }
 }