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