Skip to main content

rustc_hir_analysis/coherence/
builtin.rs

1//! Check properties that are required by built-in traits and set
2//! up data structures required by type-checking/codegen.
3
4use std::collections::BTreeMap;
5
6use rustc_data_structures::fx::FxHashSet;
7use rustc_errors::{ErrorGuaranteed, MultiSpan};
8use rustc_hir as hir;
9use rustc_hir::ItemKind;
10use rustc_hir::def_id::{DefId, LocalDefId};
11use rustc_hir::lang_items::LangItem;
12use rustc_infer::infer::{self, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
13use rustc_infer::traits::Obligation;
14use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
15use rustc_middle::ty::print::PrintTraitRefExt as _;
16use rustc_middle::ty::relate::solver_relating::RelateExt;
17use rustc_middle::ty::{
18    self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, suggest_constraining_type_params,
19};
20use rustc_span::{DUMMY_SP, Span, sym};
21use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
22use rustc_trait_selection::traits::misc::{
23    ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
24    type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
25};
26use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCause, ObligationCtxt};
27use tracing::debug;
28
29use crate::diagnostics;
30
31pub(super) fn check_trait<'tcx>(
32    tcx: TyCtxt<'tcx>,
33    trait_def_id: DefId,
34    impl_def_id: LocalDefId,
35    impl_header: ty::ImplTraitHeader<'tcx>,
36) -> Result<(), ErrorGuaranteed> {
37    let checker = Checker { tcx, impl_def_id, impl_header };
38    match tcx.as_lang_item(trait_def_id) {
39        Some(LangItem::Drop) => visit_implementation_of_drop(&checker),
40        Some(LangItem::AsyncDrop) => visit_implementation_of_drop(&checker),
41        Some(LangItem::Copy) => visit_implementation_of_copy(&checker),
42        Some(LangItem::Unpin) => visit_implementation_of_unpin(&checker),
43        Some(LangItem::ConstParamTy) => visit_implementation_of_const_param_ty(&checker),
44        Some(LangItem::CoerceUnsized) => visit_implementation_of_coerce_unsized(&checker),
45        Some(LangItem::Reborrow) => visit_implementation_of_reborrow(&checker),
46        Some(LangItem::CoerceShared) => visit_implementation_of_coerce_shared(&checker),
47        Some(LangItem::DispatchFromDyn) => visit_implementation_of_dispatch_from_dyn(&checker),
48        Some(LangItem::CoercePointeeValidated) => {
49            visit_implementation_of_coerce_pointee_validity(&checker)
50        }
51        _ => Ok(()),
52    }
53}
54
55struct Checker<'tcx> {
56    tcx: TyCtxt<'tcx>,
57    impl_def_id: LocalDefId,
58    impl_header: ty::ImplTraitHeader<'tcx>,
59}
60
61fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
62    let tcx = checker.tcx;
63    let impl_did = checker.impl_def_id;
64    // Destructors only work on local ADT types.
65    match checker.impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty().kind() {
66        ty::Adt(def, _) if def.did().is_local() => return Ok(()),
67        ty::Error(_) => return Ok(()),
68        _ => {}
69    }
70
71    let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
72
73    Err(tcx.dcx().emit_err(diagnostics::DropImplOnWrongItem {
74        span: impl_.self_ty.span,
75        trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id),
76    }))
77}
78
79fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
80    let tcx = checker.tcx;
81    let impl_header = checker.impl_header;
82    let impl_did = checker.impl_def_id;
83    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:83",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(83u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_copy: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
84
85    let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
86    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:86",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(86u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_copy: self_type={0:?} (bound)",
                                                    self_type) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
87
88    let param_env = tcx.param_env(impl_did);
89    if !!self_type.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_type.has_escaping_bound_vars()")
};assert!(!self_type.has_escaping_bound_vars());
90
91    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:91",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(91u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_copy: self_type={0:?} (free)",
                                                    self_type) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
92
93    if let ty::ImplPolarity::Negative = impl_header.polarity {
94        return Ok(());
95    }
96
97    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
98    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
99        Ok(()) => Ok(()),
100        Err(CopyImplementationError::InfringingFields(fields)) => {
101            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
102            Err(infringing_fields_error(
103                tcx,
104                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
105                LangItem::Copy,
106                impl_did,
107                span,
108            ))
109        }
110        Err(CopyImplementationError::NotAnAdt) => {
111            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
112            Err(tcx.dcx().emit_err(diagnostics::CopyImplOnNonAdt { span }))
113        }
114        Err(CopyImplementationError::HasDestructor(did)) => {
115            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
116            let impl_ = tcx.def_span(did);
117            Err(tcx.dcx().emit_err(diagnostics::CopyImplOnTypeWithDtor { span, impl_ }))
118        }
119        Err(CopyImplementationError::HasUnsafeFields) => {
120            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
121            Err(tcx
122                .dcx()
123                .span_delayed_bug(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot implement `Copy` for `{0}`",
                self_type))
    })format!("cannot implement `Copy` for `{}`", self_type)))
124        }
125    }
126}
127
128fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
129    let tcx = checker.tcx;
130    let impl_header = checker.impl_header;
131    let impl_did = checker.impl_def_id;
132    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:132",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(132u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_unpin: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_unpin: impl_did={:?}", impl_did);
133
134    let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
135    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:135",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(135u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_unpin: self_type={0:?}",
                                                    self_type) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_unpin: self_type={:?}", self_type);
136
137    let span = tcx.def_span(impl_did);
138
139    if tcx.features().pin_ergonomics() {
140        match self_type.kind() {
141            // Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project
142            // `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).
143            // If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
144            // which cannot carry safety properties), then `&mut U` could be obtained from
145            // `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
146            // `Pin<&mut U>` for `U: !Unpin`.
147            ty::Adt(adt, _) if adt.is_pin_project() => {
148                return Err(tcx.dcx().emit_err(crate::diagnostics::ImplUnpinForPinProjectedType {
149                    span,
150                    adt_span: tcx.def_span(adt.did()),
151                    adt_name: tcx.item_name(adt.did()),
152                }));
153            }
154            ty::Adt(_, _) => {}
155            _ => {
156                return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));
157            }
158        };
159    }
160    Ok(())
161}
162
163fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
164    let tcx = checker.tcx;
165    let header = checker.impl_header;
166    let impl_did = checker.impl_def_id;
167    let self_type = header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
168    if !!self_type.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !self_type.has_escaping_bound_vars()")
};assert!(!self_type.has_escaping_bound_vars());
169
170    let param_env = tcx.param_env(impl_did);
171
172    if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
173        return Ok(());
174    }
175
176    if tcx.features().const_param_ty_unchecked() {
177        return Ok(());
178    }
179
180    if !tcx.features().adt_const_params() {
181        match *self_type.kind() {
182            ty::Adt(adt, _) if adt.is_struct() => {
183                let struct_vis = tcx.visibility(adt.did());
184                for variant in adt.variants() {
185                    for field in &variant.fields {
186                        if struct_vis.greater_than(field.vis, tcx) {
187                            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
188                            return Err(tcx
189                                .dcx()
190                                .emit_err(diagnostics::ConstParamTyFieldVisMismatch { span }));
191                        }
192                    }
193                }
194            }
195
196            _ => {}
197        }
198    }
199
200    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
201    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
202        Ok(()) => Ok(()),
203        Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
204            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
205            Err(infringing_fields_error(
206                tcx,
207                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
208                LangItem::ConstParamTy,
209                impl_did,
210                span,
211            ))
212        }
213        Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
214            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
215            Err(tcx.dcx().emit_err(diagnostics::ConstParamTyImplOnNonAdt { span }))
216        }
217        Err(ConstParamTyImplementationError::NonExhaustive(attr_span)) => {
218            let defn_span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
219            Err(tcx
220                .dcx()
221                .emit_err(diagnostics::ConstParamTyImplOnNonExhaustive { defn_span, attr_span }))
222        }
223        Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
224            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
225            Err(infringing_fields_error(
226                tcx,
227                infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
228                LangItem::ConstParamTy,
229                impl_did,
230                span,
231            ))
232        }
233        Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
234            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
235            Err(tcx.dcx().emit_err(diagnostics::ConstParamTyImplOnUnsized { span }))
236        }
237    }
238}
239
240fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
241    let tcx = checker.tcx;
242    let impl_did = checker.impl_def_id;
243    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:243",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(243u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_coerce_unsized: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
244
245    // Just compute this for the side-effects, in particular reporting
246    // errors; other parts of the code may demand it for the info of
247    // course.
248    tcx.ensure_result().coerce_unsized_info(impl_did)
249}
250
251fn visit_implementation_of_reborrow(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
252    let tcx = checker.tcx;
253    let impl_did = checker.impl_def_id;
254    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:254",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(254u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_reborrow: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_reborrow: impl_did={:?}", impl_did);
255
256    // Just compute this for the side-effects, in particular reporting
257    // errors; other parts of the code may demand it for the info of
258    // course.
259    reborrow_info(tcx, impl_did)
260}
261
262fn visit_implementation_of_coerce_shared(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
263    let tcx = checker.tcx;
264    let impl_did = checker.impl_def_id;
265    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:265",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(265u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_coerce_shared: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_coerce_shared: impl_did={:?}", impl_did);
266
267    // Just compute this for the side-effects, in particular reporting
268    // errors; other parts of the code may demand it for the info of
269    // course.
270    coerce_shared_info(tcx, impl_did)
271}
272
273fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
274    span.ctxt()
275        .outer_expn_data()
276        .macro_def_id
277        .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
278}
279
280fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
281    let tcx = checker.tcx;
282    let impl_did = checker.impl_def_id;
283    let trait_ref = checker.impl_header.trait_ref.instantiate_identity().skip_norm_wip();
284    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:284",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(284u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_dispatch_from_dyn: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
285
286    let span = tcx.def_span(impl_did);
287    let trait_name = "DispatchFromDyn";
288
289    let source = trait_ref.self_ty();
290    let target = {
291        if !tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn) {
    ::core::panicking::panic("assertion failed: tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn)")
};assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
292
293        trait_ref.args.type_at(1)
294    };
295
296    // Check `CoercePointee` impl is WF -- if not, then there's no reason to report
297    // redundant errors for `DispatchFromDyn`. This is best effort, though.
298    let mut res = Ok(());
299    tcx.for_each_relevant_impl(
300        tcx.require_lang_item(LangItem::CoerceUnsized, span),
301        source,
302        |impl_def_id| {
303            res = res.and(tcx.ensure_result().coerce_unsized_info(impl_def_id));
304        },
305    );
306    res?;
307
308    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:308",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(308u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_dispatch_from_dyn: {0:?} -> {1:?}",
                                                    source, target) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
309
310    let param_env = tcx.param_env(impl_did);
311
312    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
313    let cause = ObligationCause::misc(span, impl_did);
314
315    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
316    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
317    // that are effectively repr(transparent) newtypes around types that already hav a
318    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some
319    // of them support an allocator, but we ensure that for the cases where the type implements this
320    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
321    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
322    // even if they do not carry that attribute.
323    match (source.kind(), target.kind()) {
324        (&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
325            if pat_a != pat_b {
326                return Err(tcx.dcx().emit_err(diagnostics::CoerceSamePatKind {
327                    span,
328                    trait_name,
329                    pat_a: pat_a.to_string(),
330                    pat_b: pat_b.to_string(),
331                }));
332            }
333            Ok(())
334        }
335
336        (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
337            if r_a == *r_b && mutbl_a == *mutbl_b =>
338        {
339            Ok(())
340        }
341        (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
342        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
343            if def_a.is_struct() && def_b.is_struct() =>
344        {
345            if def_a != def_b {
346                let source_path = tcx.def_path_str(def_a.did());
347                let target_path = tcx.def_path_str(def_b.did());
348                return Err(tcx.dcx().emit_err(diagnostics::CoerceSameStruct {
349                    span,
350                    trait_name,
351                    note: true,
352                    source_path,
353                    target_path,
354                }));
355            }
356
357            if def_a.repr().c() || def_a.repr().packed() {
358                return Err(tcx.dcx().emit_err(diagnostics::DispatchFromDynRepr { span }));
359            }
360
361            let fields = &def_a.non_enum_variant().fields;
362
363            let mut res = Ok(());
364            let coerced_fields = fields
365                .iter_enumerated()
366                .filter_map(|(i, field)| {
367                    // Ignore PhantomData fields
368                    let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
369                    if tcx
370                        .try_normalize_erasing_regions(
371                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
372                            unnormalized_ty,
373                        )
374                        .unwrap_or(unnormalized_ty.skip_norm_wip())
375                        .is_phantom_data()
376                    {
377                        return None;
378                    }
379
380                    let ty_a = field.ty(tcx, args_a).skip_norm_wip();
381                    let ty_b = field.ty(tcx, args_b).skip_norm_wip();
382
383                    // FIXME: We could do normalization here, but is it really worth it?
384                    if ty_a == ty_b {
385                        // Allow 1-ZSTs that don't mention type params.
386                        //
387                        // Allowing type params here would allow us to possibly transmute
388                        // between ZSTs, which may be used to create library unsoundness.
389                        if let Ok(layout) =
390                            tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
391                            && layout.is_1zst()
392                            && !ty_a.has_non_region_param()
393                        {
394                            // ignore 1-ZST fields
395                            return None;
396                        }
397
398                        res = Err(tcx.dcx().emit_err(diagnostics::DispatchFromDynZST {
399                            span,
400                            name: field.ident(tcx),
401                            ty: ty_a,
402                        }));
403
404                        None
405                    } else {
406                        Some((i, ty_a, ty_b, tcx.def_span(field.did)))
407                    }
408                })
409                .collect::<Vec<_>>();
410            res?;
411
412            if coerced_fields.is_empty() {
413                return Err(tcx.dcx().emit_err(diagnostics::CoerceNoField {
414                    span,
415                    trait_name,
416                    note: true,
417                }));
418            } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
419                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
420                ocx.register_obligation(Obligation::new(
421                    tcx,
422                    cause.clone(),
423                    param_env,
424                    ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
425                ));
426                let errors = ocx.evaluate_obligations_error_on_ambiguity();
427                if !errors.is_empty() {
428                    if is_from_coerce_pointee_derive(tcx, span) {
429                        return Err(tcx.dcx().emit_err(diagnostics::CoerceFieldValidity {
430                            span,
431                            trait_name,
432                            ty: trait_ref.self_ty(),
433                            field_span,
434                            field_ty: ty_a,
435                        }));
436                    } else {
437                        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
438                    }
439                }
440
441                // Finally, resolve all regions.
442                ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
443
444                Ok(())
445            } else {
446                return Err(tcx.dcx().emit_err(diagnostics::CoerceMulti {
447                    span,
448                    trait_name,
449                    number: coerced_fields.len(),
450                    fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
451                }));
452            }
453        }
454        _ => Err(tcx.dcx().emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name })),
455    }
456}
457
458pub(crate) fn reborrow_info<'tcx>(
459    tcx: TyCtxt<'tcx>,
460    impl_did: LocalDefId,
461) -> Result<(), ErrorGuaranteed> {
462    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:462",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(462u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("compute_reborrow_info(impl_did={0:?})",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("compute_reborrow_info(impl_did={:?})", impl_did);
463    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
464    let span = tcx.def_span(impl_did);
465    let trait_name = "Reborrow";
466
467    let reborrow_trait = tcx.require_lang_item(LangItem::Reborrow, span);
468
469    let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();
470    let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();
471
472    if trait_impl_lifetime_params_count(tcx, impl_did) != 1 {
473        return Err(tcx
474            .dcx()
475            .emit_err(diagnostics::CoerceSharedNotSingleLifetimeParam { span, trait_name }));
476    }
477
478    {
    match (&trait_ref.def_id, &reborrow_trait) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(trait_ref.def_id, reborrow_trait);
479    let param_env = tcx.param_env(impl_did);
480    if !!source.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
481
482    let (def, args) = match source.kind() {
483        &ty::Adt(def, args) if def.is_struct() => (def, args),
484        _ => {
485            // Note: reusing error here as it takes trait_name as argument.
486            return Err(tcx
487                .dcx()
488                .emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name }));
489        }
490    };
491
492    let lifetimes_count = generic_lifetime_params_count(args);
493    let data_fields = collect_struct_data_fields(tcx, def, args);
494
495    if lifetimes_count != 1 {
496        let item = tcx.hir_expect_item(impl_did);
497        let _span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = &item.kind {
498            of_trait.trait_ref.path.span
499        } else {
500            tcx.def_span(impl_did)
501        };
502
503        return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMulti { span, trait_name }));
504    }
505
506    if data_fields.is_empty() {
507        return Ok(());
508    }
509
510    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
511    // We've found some data fields. They must all be either be Copy or Reborrow.
512    for (field, span) in data_fields {
513        let field = ocx
514            .deeply_normalize(&traits::ObligationCause::misc(span, impl_did), param_env, field)
515            .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
516        if assert_field_type_is_reborrow(
517            tcx,
518            &infcx,
519            reborrow_trait,
520            impl_did,
521            param_env,
522            field,
523            span,
524        )
525        .is_ok()
526        {
527            // Field implements Reborrow, check remaining fields.
528            continue;
529        }
530
531        // Field does not implement Reborrow: it must be Copy.
532        assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field, span)?;
533    }
534
535    Ok(())
536}
537
538fn assert_field_type_is_reborrow<'tcx>(
539    tcx: TyCtxt<'tcx>,
540    infcx: &InferCtxt<'tcx>,
541    reborrow_trait: DefId,
542    impl_did: LocalDefId,
543    param_env: ty::ParamEnv<'tcx>,
544    ty: Ty<'tcx>,
545    span: Span,
546) -> Result<(), Vec<FulfillmentError<'tcx>>> {
547    if ty.ref_mutability() == Some(ty::Mutability::Mut) {
548        // Mutable references are Reborrow but not really.
549        return Ok(());
550    }
551    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
552    let cause = traits::ObligationCause::misc(span, impl_did);
553    let obligation =
554        Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, reborrow_trait, [ty]));
555    ocx.register_obligation(obligation);
556    let errors = ocx.evaluate_obligations_error_on_ambiguity();
557
558    if !errors.is_empty() { Err(errors) } else { Ok(()) }
559}
560
561pub(crate) fn coerce_shared_info<'tcx>(
562    tcx: TyCtxt<'tcx>,
563    impl_did: LocalDefId,
564) -> Result<(), ErrorGuaranteed> {
565    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:565",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(565u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("compute_coerce_shared_info(impl_did={0:?})",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("compute_coerce_shared_info(impl_did={:?})", impl_did);
566    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
567    let span = tcx.def_span(impl_did);
568    let trait_name = "CoerceShared";
569
570    let coerce_shared_trait = tcx.require_lang_item(LangItem::CoerceShared, span);
571
572    let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();
573    let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();
574
575    if trait_impl_lifetime_params_count(tcx, impl_did) != 1 {
576        return Err(tcx
577            .dcx()
578            .emit_err(diagnostics::CoerceSharedNotSingleLifetimeParam { span, trait_name }));
579    }
580
581    {
    match (&trait_ref.def_id, &coerce_shared_trait) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(trait_ref.def_id, coerce_shared_trait);
582    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
583    let param_env = tcx.param_env(impl_did);
584    let (source, target) = ocx
585        .deeply_normalize(
586            &traits::ObligationCause::misc(span, impl_did),
587            param_env,
588            Unnormalized::new_wip((source, trait_ref.args.type_at(1))),
589        )
590        .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
591
592    if !!source.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
593
594    let data = match (source.kind(), target.kind()) {
595        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
596            if def_a.is_struct() && def_b.is_struct() =>
597        {
598            // Check that both A and B have exactly one lifetime argument, and that they have the
599            // same number of data fields that is not more than 1. The eventual intention is to
600            // support multiple lifetime arguments (with the reborrowed lifetimes inferred from
601            // usage one way or another) and multiple data fields with B allowed to leave out fields
602            // from A. The current state is just the simplest choice.
603            let a_lifetimes_count = generic_lifetime_params_count(args_a);
604            let a_data_fields = collect_struct_data_fields(tcx, def_a, args_a);
605            let b_lifetimes_count = generic_lifetime_params_count(args_b);
606            let b_data_fields = collect_struct_data_fields(tcx, def_b, args_b);
607
608            if a_lifetimes_count != 1
609                || b_lifetimes_count != 1
610                || a_data_fields.len() > 1
611                || b_data_fields.len() > 1
612                || a_data_fields.len() != b_data_fields.len()
613            {
614                let item = tcx.hir_expect_item(impl_did);
615                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
616                    &item.kind
617                {
618                    of_trait.trait_ref.path.span
619                } else {
620                    tcx.def_span(impl_did)
621                };
622
623                return Err(tcx
624                    .dcx()
625                    .emit_err(diagnostics::CoerceSharedMulti { span, trait_name }));
626            }
627
628            if a_data_fields.len() == 1 {
629                // We found one data field for both: we'll attempt to perform CoerceShared between
630                // them below.
631                let (a, span_a) = a_data_fields[0];
632                let (b, span_b) = b_data_fields[0];
633                let a = ocx
634                    .deeply_normalize(
635                        &traits::ObligationCause::misc(span_a, impl_did),
636                        param_env,
637                        a,
638                    )
639                    .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
640                let b = ocx
641                    .deeply_normalize(
642                        &traits::ObligationCause::misc(span_b, impl_did),
643                        param_env,
644                        b,
645                    )
646                    .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
647
648                Some((a, b, coerce_shared_trait, span_a, span_b))
649            } else {
650                // We found no data fields in either: this is a reborrowable marker type being
651                // coerced into a shared marker. That is fine too.
652                None
653            }
654        }
655
656        _ => {
657            // Note: reusing CoerceUnsizedNonStruct error as it takes trait_name as argument.
658            return Err(tcx
659                .dcx()
660                .emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name }));
661        }
662    };
663
664    // We've proven that we have two types with one lifetime each and 0 or 1 data fields each.
665    if let Some((source, target, trait_def_id, source_field_span, _target_field_span)) = data {
666        // struct Source(SourceData);
667        // struct Target(TargetData);
668        //
669        // 1 data field each; they must be the same type and Copy, or relate to one another using
670        // CoerceShared.
671        //
672        // FIXME(reborrow): we should do the relating inside `probe` so the region constraint
673        // doesn't affect later result in case that this relating fails.
674        // We should resolve regions if the relating succeeds.
675        // Besides, the regions of `Ref`s are not checked here so `&'a mut T -> &'static T` is
676        // allowed.
677        if source.ref_mutability() == Some(ty::Mutability::Mut)
678            && target.ref_mutability() == Some(ty::Mutability::Not)
679            && infcx
680                .relate(
681                    param_env,
682                    source.peel_refs(),
683                    ty::Variance::Invariant,
684                    target.peel_refs(),
685                    source_field_span,
686                )
687                .is_ok()
688        {
689            // &mut T implements CoerceShared to &T, except not really.
690            return Ok(());
691        }
692
693        // FIXME(reborrow): we should do the relating inside `probe` so the region constraint
694        // doesn't affect later result in case that this relating fails.
695        if infcx
696            .relate(param_env, source, ty::Variance::Invariant, target, source_field_span)
697            .is_err()
698        {
699            // The two data fields don't agree on a common type; this means
700            // that they must be `A: CoerceShared<B>`. Register an obligation
701            // for that.
702            let cause = traits::ObligationCause::misc(span, impl_did);
703            let obligation = Obligation::new(
704                tcx,
705                cause,
706                param_env,
707                ty::TraitRef::new(tcx, trait_def_id, [source, target]),
708            );
709            ocx.register_obligation(obligation);
710            let errors = ocx.evaluate_obligations_error_on_ambiguity();
711
712            if !errors.is_empty() {
713                return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
714            }
715            // Finally, resolve all regions.
716            ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
717        } else {
718            // Types match: check that it is Copy.
719            //
720            // FIXME(reborrow): We should resolve regions here.
721            assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, source, source_field_span)?;
722        }
723    }
724
725    Ok(())
726}
727
728fn trait_impl_lifetime_params_count(tcx: TyCtxt<'_>, did: LocalDefId) -> usize {
729    tcx.generics_of(did)
730        .own_params
731        .iter()
732        .filter(|p| #[allow(non_exhaustive_omitted_patterns)] match p.kind {
    ty::GenericParamDefKind::Lifetime => true,
    _ => false,
}matches!(p.kind, ty::GenericParamDefKind::Lifetime))
733        .count()
734}
735
736fn generic_lifetime_params_count(args: &[ty::GenericArg<'_>]) -> usize {
737    args.iter().filter(|arg| arg.as_region().is_some()).count()
738}
739
740fn collect_struct_data_fields<'tcx>(
741    tcx: TyCtxt<'tcx>,
742    def: ty::AdtDef<'tcx>,
743    args: ty::GenericArgsRef<'tcx>,
744) -> Vec<(Unnormalized<'tcx, Ty<'tcx>>, Span)> {
745    def.non_enum_variant()
746        .fields
747        .iter()
748        .filter_map(|f| {
749            // Ignore PhantomData fields
750            let ty = f.ty(tcx, args);
751            // FIXME(#155345): alias might be normalized to PhantomData.
752            // We probably should normalize here instead.
753            if ty.skip_norm_wip().is_phantom_data() {
754                return None;
755            }
756            Some((ty, tcx.def_span(f.did)))
757        })
758        .collect()
759}
760
761fn assert_field_type_is_copy<'tcx>(
762    tcx: TyCtxt<'tcx>,
763    infcx: &InferCtxt<'tcx>,
764    impl_did: LocalDefId,
765    param_env: ty::ParamEnv<'tcx>,
766    ty: Ty<'tcx>,
767    span: Span,
768) -> Result<(), ErrorGuaranteed> {
769    let copy_trait = tcx.require_lang_item(LangItem::Copy, span);
770    let ocx = ObligationCtxt::new_with_diagnostics(infcx);
771    let cause = traits::ObligationCause::misc(span, impl_did);
772    let obligation =
773        Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, copy_trait, [ty]));
774    ocx.register_obligation(obligation);
775    let errors = ocx.evaluate_obligations_error_on_ambiguity();
776
777    if !errors.is_empty() {
778        Err(infcx.err_ctxt().report_fulfillment_errors(errors))
779    } else {
780        Ok(())
781    }
782}
783
784pub(crate) fn coerce_unsized_info<'tcx>(
785    tcx: TyCtxt<'tcx>,
786    impl_did: LocalDefId,
787) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
788    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:788",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(788u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("compute_coerce_unsized_info(impl_did={0:?})",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
789    let span = tcx.def_span(impl_did);
790    let trait_name = "CoerceUnsized";
791
792    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
793    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
794
795    let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();
796    let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();
797
798    {
    match (&trait_ref.def_id, &coerce_unsized_trait) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(trait_ref.def_id, coerce_unsized_trait);
799    let target = trait_ref.args.type_at(1);
800    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:800",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(800u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_coerce_unsized: {0:?} -> {1:?} (bound)",
                                                    source, target) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
801
802    let param_env = tcx.param_env(impl_did);
803    if !!source.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
804
805    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:805",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(805u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_coerce_unsized: {0:?} -> {1:?} (free)",
                                                    source, target) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
806
807    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
808    let cause = ObligationCause::misc(span, impl_did);
809    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
810                       mt_b: ty::TypeAndMut<'tcx>,
811                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
812        if mt_a.mutbl < mt_b.mutbl {
813            infcx
814                .err_ctxt()
815                .report_mismatched_types(
816                    &cause,
817                    param_env,
818                    mk_ptr(mt_b.ty),
819                    target,
820                    ty::error::TypeError::Mutability,
821                )
822                .emit();
823        }
824        (mt_a.ty, mt_b.ty, unsize_trait, None, span)
825    };
826    let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
827        (&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
828            if pat_a != pat_b {
829                return Err(tcx.dcx().emit_err(diagnostics::CoerceSamePatKind {
830                    span,
831                    trait_name,
832                    pat_a: pat_a.to_string(),
833                    pat_b: pat_b.to_string(),
834                }));
835            }
836            (ty_a, ty_b, coerce_unsized_trait, None, span)
837        }
838
839        (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
840            infcx.sub_regions(
841                SubregionOrigin::RelateObjectBound(span),
842                r_b,
843                r_a,
844                ty::VisibleForLeakCheck::Yes,
845            );
846            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
847            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
848            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
849        }
850
851        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
852        | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
853            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
854            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
855            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
856        }
857
858        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
859            if def_a.is_struct() && def_b.is_struct() =>
860        {
861            if def_a != def_b {
862                let source_path = tcx.def_path_str(def_a.did());
863                let target_path = tcx.def_path_str(def_b.did());
864                return Err(tcx.dcx().emit_err(diagnostics::CoerceSameStruct {
865                    span,
866                    trait_name,
867                    note: true,
868                    source_path,
869                    target_path,
870                }));
871            }
872
873            // Here we are considering a case of converting
874            // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
875            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
876            //
877            //     struct Foo<T, U> {
878            //         extra: T,
879            //         ptr: *mut U,
880            //     }
881            //
882            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
883            // to `Foo<T, [i32]>`. That impl would look like:
884            //
885            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
886            //
887            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
888            // when this coercion occurs, we would be changing the
889            // field `ptr` from a thin pointer of type `*mut [i32;
890            // 3]` to a wide pointer of type `*mut [i32]` (with
891            // extra data `3`). **The purpose of this check is to
892            // make sure that we know how to do this conversion.**
893            //
894            // To check if this impl is legal, we would walk down
895            // the fields of `Foo` and consider their types with
896            // both generic parameters. We are looking to find that
897            // exactly one (non-phantom) field has changed its
898            // type, which we will expect to be the pointer that
899            // is becoming fat (we could probably generalize this
900            // to multiple thin pointers of the same type becoming
901            // fat, but we don't). In this case:
902            //
903            // - `extra` has type `T` before and type `T` after
904            // - `ptr` has type `*mut U` before and type `*mut V` after
905            //
906            // Since just one field changed, we would then check
907            // that `*mut U: CoerceUnsized<*mut V>` is implemented
908            // (in other words, that we know how to do this
909            // conversion). This will work out because `U:
910            // Unsize<V>`, and we have a builtin rule that `*mut
911            // U` can be coerced to `*mut V` if `U: Unsize<V>`.
912            let fields = &def_a.non_enum_variant().fields;
913            let diff_fields = fields
914                .iter_enumerated()
915                .filter_map(|(i, f)| {
916                    let (a, b) =
917                        (f.ty(tcx, args_a).skip_norm_wip(), f.ty(tcx, args_b).skip_norm_wip());
918
919                    // Ignore PhantomData fields
920                    let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
921                    if tcx
922                        .try_normalize_erasing_regions(
923                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
924                            unnormalized_ty,
925                        )
926                        .unwrap_or(unnormalized_ty.skip_norm_wip())
927                        .is_phantom_data()
928                    {
929                        return None;
930                    }
931
932                    // Ignore fields that aren't changed; it may
933                    // be that we could get away with subtyping or
934                    // something more accepting, but we use
935                    // equality because we want to be able to
936                    // perform this check without computing
937                    // variance or constraining opaque types' hidden types.
938                    // (This is because we may have to evaluate constraint
939                    // expressions in the course of execution.)
940                    // See e.g., #41936.
941                    if a == b {
942                        return None;
943                    }
944
945                    // Collect up all fields that were significantly changed
946                    // i.e., those that contain T in coerce_unsized T -> U
947                    Some((i, a, b, tcx.def_span(f.did)))
948                })
949                .collect::<Vec<_>>();
950
951            if diff_fields.is_empty() {
952                return Err(tcx.dcx().emit_err(diagnostics::CoerceNoField {
953                    span,
954                    trait_name,
955                    note: true,
956                }));
957            } else if diff_fields.len() > 1 {
958                let item = tcx.hir_expect_item(impl_did);
959                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
960                    &item.kind
961                {
962                    of_trait.trait_ref.path.span
963                } else {
964                    tcx.def_span(impl_did)
965                };
966
967                return Err(tcx.dcx().emit_err(diagnostics::CoerceMulti {
968                    span,
969                    trait_name,
970                    number: diff_fields.len(),
971                    fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
972                }));
973            }
974
975            let (i, a, b, field_span) = diff_fields[0];
976            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
977            (a, b, coerce_unsized_trait, Some(kind), field_span)
978        }
979
980        _ => {
981            return Err(tcx
982                .dcx()
983                .emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name }));
984        }
985    };
986
987    // Register an obligation for `A: Trait<B>`.
988    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
989    let cause = traits::ObligationCause::misc(span, impl_did);
990    let obligation = Obligation::new(
991        tcx,
992        cause,
993        param_env,
994        ty::TraitRef::new(tcx, trait_def_id, [source, target]),
995    );
996    ocx.register_obligation(obligation);
997    let errors = ocx.evaluate_obligations_error_on_ambiguity();
998
999    if !errors.is_empty() {
1000        if is_from_coerce_pointee_derive(tcx, span) {
1001            return Err(tcx.dcx().emit_err(diagnostics::CoerceFieldValidity {
1002                span,
1003                trait_name,
1004                ty: trait_ref.self_ty(),
1005                field_span,
1006                field_ty: source,
1007            }));
1008        } else {
1009            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
1010        }
1011    }
1012
1013    // Finally, resolve all regions.
1014    ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
1015
1016    Ok(CoerceUnsizedInfo { custom_kind: kind })
1017}
1018
1019fn infringing_fields_error<'tcx>(
1020    tcx: TyCtxt<'tcx>,
1021    infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
1022    lang_item: LangItem,
1023    impl_did: LocalDefId,
1024    impl_span: Span,
1025) -> ErrorGuaranteed {
1026    let trait_did = tcx.require_lang_item(lang_item, impl_span);
1027
1028    let trait_name = tcx.def_path_str(trait_did);
1029
1030    // We'll try to suggest constraining type parameters to fulfill the requirements of
1031    // their `Copy` implementation.
1032    let mut errors: BTreeMap<_, Vec<_>> = Default::default();
1033    let mut bounds = ::alloc::vec::Vec::new()vec![];
1034
1035    let mut seen_tys = FxHashSet::default();
1036
1037    let mut label_spans = Vec::new();
1038
1039    for (span, ty, reason) in infringing_tys {
1040        // Only report an error once per type.
1041        if !seen_tys.insert(ty) {
1042            continue;
1043        }
1044
1045        label_spans.push(span);
1046
1047        match reason {
1048            InfringingFieldsReason::Fulfill(fulfillment_errors) => {
1049                for error in fulfillment_errors {
1050                    let error_predicate = error.obligation.predicate;
1051                    // Only note if it's not the root obligation, otherwise it's trivial and
1052                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
1053
1054                    // FIXME: This error could be more descriptive, especially if the error_predicate
1055                    // contains a foreign type or if it's a deeply nested type...
1056                    if error_predicate != error.root_obligation.predicate {
1057                        errors
1058                            .entry((ty.to_string(), error_predicate.to_string()))
1059                            .or_default()
1060                            .push(error.obligation.cause.span);
1061                    }
1062                    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
1063                        trait_ref,
1064                        polarity: ty::PredicatePolarity::Positive,
1065                        ..
1066                    })) = error_predicate.kind().skip_binder()
1067                    {
1068                        let ty = trait_ref.self_ty();
1069                        if let ty::Param(_) = ty.kind() {
1070                            bounds.push((
1071                                ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("{0}", ty)) })format!("{ty}"),
1072                                trait_ref.print_trait_sugared().to_string(),
1073                                Some(trait_ref.def_id),
1074                            ));
1075                        }
1076                    }
1077                }
1078            }
1079            InfringingFieldsReason::Regions(region_errors) => {
1080                for error in region_errors {
1081                    let ty = ty.to_string();
1082                    match error {
1083                        RegionResolutionError::ConcreteFailure(origin, a, b) => {
1084                            let predicate = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", b, a))
    })format!("{b}: {a}");
1085                            errors
1086                                .entry((ty.clone(), predicate.clone()))
1087                                .or_default()
1088                                .push(origin.span());
1089                            if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
1090                                && ebr.is_named()
1091                            {
1092                                bounds.push((b.to_string(), a.to_string(), None));
1093                            }
1094                        }
1095                        RegionResolutionError::GenericBoundFailure(origin, a, b) => {
1096                            let predicate = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", a, b))
    })format!("{a}: {b}");
1097                            errors
1098                                .entry((ty.clone(), predicate.clone()))
1099                                .or_default()
1100                                .push(origin.span());
1101                            if let infer::region_constraints::GenericKind::Param(_) = a {
1102                                bounds.push((a.to_string(), b.to_string(), None));
1103                            }
1104                        }
1105                        _ => continue,
1106                    }
1107                }
1108            }
1109        }
1110    }
1111    let mut notes = Vec::new();
1112    for ((ty, error_predicate), spans) in errors {
1113        let span: MultiSpan = spans.into();
1114        notes.push(diagnostics::ImplForTyRequires {
1115            span,
1116            error_predicate,
1117            trait_name: trait_name.clone(),
1118            ty,
1119        });
1120    }
1121
1122    let mut err = tcx.dcx().create_err(diagnostics::TraitCannotImplForTy {
1123        span: impl_span,
1124        trait_name,
1125        label_spans,
1126        notes,
1127    });
1128
1129    suggest_constraining_type_params(
1130        tcx,
1131        tcx.hir_get_generics(impl_did).expect("impls always have generics"),
1132        &mut err,
1133        bounds
1134            .iter()
1135            .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
1136        None,
1137    );
1138
1139    err.emit()
1140}
1141
1142fn visit_implementation_of_coerce_pointee_validity(
1143    checker: &Checker<'_>,
1144) -> Result<(), ErrorGuaranteed> {
1145    let tcx = checker.tcx;
1146    let self_ty =
1147        tcx.impl_trait_ref(checker.impl_def_id).instantiate_identity().skip_norm_wip().self_ty();
1148    let span = tcx.def_span(checker.impl_def_id);
1149    if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
1150        return Err(tcx.dcx().emit_err(diagnostics::CoercePointeeNoUserValidityAssertion { span }));
1151    }
1152    let ty::Adt(def, _args) = self_ty.kind() else {
1153        return Err(tcx.dcx().emit_err(diagnostics::CoercePointeeNotConcreteType { span }));
1154    };
1155    let did = def.did();
1156    // Now get a more precise span of the `struct`.
1157    let span = tcx.def_span(did);
1158    if !def.is_struct() {
1159        return Err(tcx
1160            .dcx()
1161            .emit_err(diagnostics::CoercePointeeNotStruct { span, kind: def.descr().into() }));
1162    }
1163    if !def.repr().transparent() {
1164        return Err(tcx.dcx().emit_err(diagnostics::CoercePointeeNotTransparent { span }));
1165    }
1166    if def.all_fields().next().is_none() {
1167        return Err(tcx.dcx().emit_err(diagnostics::CoercePointeeNoField { span }));
1168    }
1169    Ok(())
1170}