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, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
13use rustc_infer::traits::Obligation;
14use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
15use rustc_middle::ty::print::PrintTraitRefExt as _;
16use rustc_middle::ty::{
17    self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
18};
19use rustc_span::{DUMMY_SP, Span, sym};
20use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
21use rustc_trait_selection::traits::misc::{
22    ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
23    type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
24};
25use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
26use tracing::debug;
27
28use crate::errors;
29
30pub(super) fn check_trait<'tcx>(
31    tcx: TyCtxt<'tcx>,
32    trait_def_id: DefId,
33    impl_def_id: LocalDefId,
34    impl_header: ty::ImplTraitHeader<'tcx>,
35) -> Result<(), ErrorGuaranteed> {
36    let lang_items = tcx.lang_items();
37    let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
38    checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
39    checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?;
40    checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
41    checker.check(lang_items.unpin_trait(), visit_implementation_of_unpin)?;
42    checker.check(lang_items.const_param_ty_trait(), |checker| {
43        visit_implementation_of_const_param_ty(checker)
44    })?;
45    checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
46    checker
47        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
48    checker.check(
49        lang_items.coerce_pointee_validated_trait(),
50        visit_implementation_of_coerce_pointee_validity,
51    )?;
52    Ok(())
53}
54
55struct Checker<'tcx> {
56    tcx: TyCtxt<'tcx>,
57    trait_def_id: DefId,
58    impl_def_id: LocalDefId,
59    impl_header: ty::ImplTraitHeader<'tcx>,
60}
61
62impl<'tcx> Checker<'tcx> {
63    fn check(
64        &self,
65        trait_def_id: Option<DefId>,
66        f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>,
67    ) -> Result<(), ErrorGuaranteed> {
68        if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) }
69    }
70}
71
72fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
73    let tcx = checker.tcx;
74    let impl_did = checker.impl_def_id;
75    // Destructors only work on local ADT types.
76    match checker.impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty().kind() {
77        ty::Adt(def, _) if def.did().is_local() => return Ok(()),
78        ty::Error(_) => return Ok(()),
79        _ => {}
80    }
81
82    let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
83
84    Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem {
85        span: impl_.self_ty.span,
86        trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id),
87    }))
88}
89
90fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
91    let tcx = checker.tcx;
92    let impl_header = checker.impl_header;
93    let impl_did = checker.impl_def_id;
94    {
    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:94",
                        "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(94u32),
                        ::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);
95
96    let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
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: self_type={0:?} (bound)",
                                                    self_type) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
98
99    let param_env = tcx.param_env(impl_did);
100    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());
101
102    {
    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:102",
                        "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(102u32),
                        ::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);
103
104    if let ty::ImplPolarity::Negative = impl_header.polarity {
105        return Ok(());
106    }
107
108    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
109    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
110        Ok(()) => Ok(()),
111        Err(CopyImplementationError::InfringingFields(fields)) => {
112            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
113            Err(infringing_fields_error(
114                tcx,
115                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
116                LangItem::Copy,
117                impl_did,
118                span,
119            ))
120        }
121        Err(CopyImplementationError::NotAnAdt) => {
122            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
123            Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
124        }
125        Err(CopyImplementationError::HasDestructor(did)) => {
126            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
127            let impl_ = tcx.def_span(did);
128            Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span, impl_ }))
129        }
130        Err(CopyImplementationError::HasUnsafeFields) => {
131            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
132            Err(tcx
133                .dcx()
134                .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)))
135        }
136    }
137}
138
139fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
140    let tcx = checker.tcx;
141    let impl_header = checker.impl_header;
142    let impl_did = checker.impl_def_id;
143    {
    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:143",
                        "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(143u32),
                        ::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);
144
145    let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
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: self_type={0:?}",
                                                    self_type) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_unpin: self_type={:?}", self_type);
147
148    let span = tcx.def_span(impl_did);
149
150    if tcx.features().pin_ergonomics() {
151        match self_type.kind() {
152            // Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project
153            // `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).
154            // If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
155            // which cannot carry safety properties), then `&mut U` could be obtained from
156            // `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
157            // `Pin<&mut U>` for `U: !Unpin`.
158            ty::Adt(adt, _) if adt.is_pin_project() => {
159                return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
160                    span,
161                    adt_span: tcx.def_span(adt.did()),
162                    adt_name: tcx.item_name(adt.did()),
163                }));
164            }
165            ty::Adt(_, _) => {}
166            _ => {
167                return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));
168            }
169        };
170    }
171    Ok(())
172}
173
174fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
175    let tcx = checker.tcx;
176    let header = checker.impl_header;
177    let impl_did = checker.impl_def_id;
178    let self_type = header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();
179    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());
180
181    let param_env = tcx.param_env(impl_did);
182
183    if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
184        return Ok(());
185    }
186
187    if tcx.features().const_param_ty_unchecked() {
188        return Ok(());
189    }
190
191    if !tcx.features().adt_const_params() {
192        match *self_type.kind() {
193            ty::Adt(adt, _) if adt.is_struct() => {
194                let struct_vis = tcx.visibility(adt.did());
195                for variant in adt.variants() {
196                    for field in &variant.fields {
197                        if struct_vis.greater_than(field.vis, tcx) {
198                            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
199                            return Err(tcx
200                                .dcx()
201                                .emit_err(errors::ConstParamTyFieldVisMismatch { span }));
202                        }
203                    }
204                }
205            }
206
207            _ => {}
208        }
209    }
210
211    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
212    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
213        Ok(()) => Ok(()),
214        Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
215            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
216            Err(infringing_fields_error(
217                tcx,
218                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
219                LangItem::ConstParamTy,
220                impl_did,
221                span,
222            ))
223        }
224        Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
225            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
226            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
227        }
228        Err(ConstParamTyImplementationError::NonExhaustive(attr_span)) => {
229            let defn_span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
230            Err(tcx
231                .dcx()
232                .emit_err(errors::ConstParamTyImplOnNonExhaustive { defn_span, attr_span }))
233        }
234        Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
235            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
236            Err(infringing_fields_error(
237                tcx,
238                infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
239                LangItem::ConstParamTy,
240                impl_did,
241                span,
242            ))
243        }
244        Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
245            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
246            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
247        }
248    }
249}
250
251fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
252    let tcx = checker.tcx;
253    let impl_did = checker.impl_def_id;
254    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_analysis/src/coherence/builtin.rs:254",
                        "rustc_hir_analysis::coherence::builtin",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin.rs"),
                        ::tracing_core::__macro_support::Option::Some(254u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("visit_implementation_of_coerce_unsized: impl_did={0:?}",
                                                    impl_did) as &dyn Value))])
            });
    } else { ; }
};debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
255
256    // Just compute this for the side-effects, in particular reporting
257    // errors; other parts of the code may demand it for the info of
258    // course.
259    tcx.ensure_result().coerce_unsized_info(impl_did)
260}
261
262fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
263    span.ctxt()
264        .outer_expn_data()
265        .macro_def_id
266        .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
267}
268
269fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
270    let tcx = checker.tcx;
271    let impl_did = checker.impl_def_id;
272    let trait_ref = checker.impl_header.trait_ref.instantiate_identity().skip_norm_wip();
273    {
    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:273",
                        "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(273u32),
                        ::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);
274
275    let span = tcx.def_span(impl_did);
276    let trait_name = "DispatchFromDyn";
277
278    let source = trait_ref.self_ty();
279    let target = {
280        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));
281
282        trait_ref.args.type_at(1)
283    };
284
285    // Check `CoercePointee` impl is WF -- if not, then there's no reason to report
286    // redundant errors for `DispatchFromDyn`. This is best effort, though.
287    let mut res = Ok(());
288    tcx.for_each_relevant_impl(
289        tcx.require_lang_item(LangItem::CoerceUnsized, span),
290        source,
291        |impl_def_id| {
292            res = res.and(tcx.ensure_result().coerce_unsized_info(impl_def_id));
293        },
294    );
295    res?;
296
297    {
    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:297",
                        "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(297u32),
                        ::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);
298
299    let param_env = tcx.param_env(impl_did);
300
301    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
302    let cause = ObligationCause::misc(span, impl_did);
303
304    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
305    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
306    // that are effectively repr(transparent) newtypes around types that already hav a
307    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some
308    // of them support an allocator, but we ensure that for the cases where the type implements this
309    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
310    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
311    // even if they do not carry that attribute.
312    match (source.kind(), target.kind()) {
313        (&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
314            if pat_a != pat_b {
315                return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
316                    span,
317                    trait_name,
318                    pat_a: pat_a.to_string(),
319                    pat_b: pat_b.to_string(),
320                }));
321            }
322            Ok(())
323        }
324
325        (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
326            if r_a == *r_b && mutbl_a == *mutbl_b =>
327        {
328            Ok(())
329        }
330        (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
331        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
332            if def_a.is_struct() && def_b.is_struct() =>
333        {
334            if def_a != def_b {
335                let source_path = tcx.def_path_str(def_a.did());
336                let target_path = tcx.def_path_str(def_b.did());
337                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
338                    span,
339                    trait_name,
340                    note: true,
341                    source_path,
342                    target_path,
343                }));
344            }
345
346            if def_a.repr().c() || def_a.repr().packed() {
347                return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
348            }
349
350            let fields = &def_a.non_enum_variant().fields;
351
352            let mut res = Ok(());
353            let coerced_fields = fields
354                .iter_enumerated()
355                .filter_map(|(i, field)| {
356                    // Ignore PhantomData fields
357                    let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
358                    if tcx
359                        .try_normalize_erasing_regions(
360                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
361                            unnormalized_ty,
362                        )
363                        .unwrap_or(unnormalized_ty.skip_norm_wip())
364                        .is_phantom_data()
365                    {
366                        return None;
367                    }
368
369                    let ty_a = field.ty(tcx, args_a);
370                    let ty_b = field.ty(tcx, args_b);
371
372                    // FIXME: We could do normalization here, but is it really worth it?
373                    if ty_a == ty_b {
374                        // Allow 1-ZSTs that don't mention type params.
375                        //
376                        // Allowing type params here would allow us to possibly transmute
377                        // between ZSTs, which may be used to create library unsoundness.
378                        if let Ok(layout) =
379                            tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
380                            && layout.is_1zst()
381                            && !ty_a.has_non_region_param()
382                        {
383                            // ignore 1-ZST fields
384                            return None;
385                        }
386
387                        res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
388                            span,
389                            name: field.ident(tcx),
390                            ty: ty_a,
391                        }));
392
393                        None
394                    } else {
395                        Some((i, ty_a, ty_b, tcx.def_span(field.did)))
396                    }
397                })
398                .collect::<Vec<_>>();
399            res?;
400
401            if coerced_fields.is_empty() {
402                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
403                    span,
404                    trait_name,
405                    note: true,
406                }));
407            } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
408                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
409                ocx.register_obligation(Obligation::new(
410                    tcx,
411                    cause.clone(),
412                    param_env,
413                    ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
414                ));
415                let errors = ocx.evaluate_obligations_error_on_ambiguity();
416                if !errors.is_empty() {
417                    if is_from_coerce_pointee_derive(tcx, span) {
418                        return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
419                            span,
420                            trait_name,
421                            ty: trait_ref.self_ty(),
422                            field_span,
423                            field_ty: ty_a,
424                        }));
425                    } else {
426                        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
427                    }
428                }
429
430                // Finally, resolve all regions.
431                ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
432
433                Ok(())
434            } else {
435                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
436                    span,
437                    trait_name,
438                    number: coerced_fields.len(),
439                    fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
440                }));
441            }
442        }
443        _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
444    }
445}
446
447pub(crate) fn coerce_unsized_info<'tcx>(
448    tcx: TyCtxt<'tcx>,
449    impl_did: LocalDefId,
450) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
451    {
    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:451",
                        "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(451u32),
                        ::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);
452    let span = tcx.def_span(impl_did);
453    let trait_name = "CoerceUnsized";
454
455    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
456    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
457
458    let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();
459    let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();
460
461    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);
462    let target = trait_ref.args.type_at(1);
463    {
    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:463",
                        "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(463u32),
                        ::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);
464
465    let param_env = tcx.param_env(impl_did);
466    if !!source.has_escaping_bound_vars() {
    ::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
467
468    {
    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:468",
                        "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(468u32),
                        ::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);
469
470    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
471    let cause = ObligationCause::misc(span, impl_did);
472    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
473                       mt_b: ty::TypeAndMut<'tcx>,
474                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
475        if mt_a.mutbl < mt_b.mutbl {
476            infcx
477                .err_ctxt()
478                .report_mismatched_types(
479                    &cause,
480                    param_env,
481                    mk_ptr(mt_b.ty),
482                    target,
483                    ty::error::TypeError::Mutability,
484                )
485                .emit();
486        }
487        (mt_a.ty, mt_b.ty, unsize_trait, None, span)
488    };
489    let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
490        (&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
491            if pat_a != pat_b {
492                return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
493                    span,
494                    trait_name,
495                    pat_a: pat_a.to_string(),
496                    pat_b: pat_b.to_string(),
497                }));
498            }
499            (ty_a, ty_b, coerce_unsized_trait, None, span)
500        }
501
502        (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
503            infcx.sub_regions(
504                SubregionOrigin::RelateObjectBound(span),
505                r_b,
506                r_a,
507                ty::VisibleForLeakCheck::Yes,
508            );
509            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
510            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
511            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
512        }
513
514        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
515        | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
516            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
517            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
518            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
519        }
520
521        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
522            if def_a.is_struct() && def_b.is_struct() =>
523        {
524            if def_a != def_b {
525                let source_path = tcx.def_path_str(def_a.did());
526                let target_path = tcx.def_path_str(def_b.did());
527                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
528                    span,
529                    trait_name,
530                    note: true,
531                    source_path,
532                    target_path,
533                }));
534            }
535
536            // Here we are considering a case of converting
537            // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
538            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
539            //
540            //     struct Foo<T, U> {
541            //         extra: T,
542            //         ptr: *mut U,
543            //     }
544            //
545            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
546            // to `Foo<T, [i32]>`. That impl would look like:
547            //
548            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
549            //
550            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
551            // when this coercion occurs, we would be changing the
552            // field `ptr` from a thin pointer of type `*mut [i32;
553            // 3]` to a wide pointer of type `*mut [i32]` (with
554            // extra data `3`). **The purpose of this check is to
555            // make sure that we know how to do this conversion.**
556            //
557            // To check if this impl is legal, we would walk down
558            // the fields of `Foo` and consider their types with
559            // both generic parameters. We are looking to find that
560            // exactly one (non-phantom) field has changed its
561            // type, which we will expect to be the pointer that
562            // is becoming fat (we could probably generalize this
563            // to multiple thin pointers of the same type becoming
564            // fat, but we don't). In this case:
565            //
566            // - `extra` has type `T` before and type `T` after
567            // - `ptr` has type `*mut U` before and type `*mut V` after
568            //
569            // Since just one field changed, we would then check
570            // that `*mut U: CoerceUnsized<*mut V>` is implemented
571            // (in other words, that we know how to do this
572            // conversion). This will work out because `U:
573            // Unsize<V>`, and we have a builtin rule that `*mut
574            // U` can be coerced to `*mut V` if `U: Unsize<V>`.
575            let fields = &def_a.non_enum_variant().fields;
576            let diff_fields = fields
577                .iter_enumerated()
578                .filter_map(|(i, f)| {
579                    let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
580
581                    // Ignore PhantomData fields
582                    let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
583                    if tcx
584                        .try_normalize_erasing_regions(
585                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
586                            unnormalized_ty,
587                        )
588                        .unwrap_or(unnormalized_ty.skip_norm_wip())
589                        .is_phantom_data()
590                    {
591                        return None;
592                    }
593
594                    // Ignore fields that aren't changed; it may
595                    // be that we could get away with subtyping or
596                    // something more accepting, but we use
597                    // equality because we want to be able to
598                    // perform this check without computing
599                    // variance or constraining opaque types' hidden types.
600                    // (This is because we may have to evaluate constraint
601                    // expressions in the course of execution.)
602                    // See e.g., #41936.
603                    if a == b {
604                        return None;
605                    }
606
607                    // Collect up all fields that were significantly changed
608                    // i.e., those that contain T in coerce_unsized T -> U
609                    Some((i, a, b, tcx.def_span(f.did)))
610                })
611                .collect::<Vec<_>>();
612
613            if diff_fields.is_empty() {
614                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
615                    span,
616                    trait_name,
617                    note: true,
618                }));
619            } else if diff_fields.len() > 1 {
620                let item = tcx.hir_expect_item(impl_did);
621                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
622                    &item.kind
623                {
624                    of_trait.trait_ref.path.span
625                } else {
626                    tcx.def_span(impl_did)
627                };
628
629                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
630                    span,
631                    trait_name,
632                    number: diff_fields.len(),
633                    fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
634                }));
635            }
636
637            let (i, a, b, field_span) = diff_fields[0];
638            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
639            (a, b, coerce_unsized_trait, Some(kind), field_span)
640        }
641
642        _ => {
643            return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
644        }
645    };
646
647    // Register an obligation for `A: Trait<B>`.
648    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
649    let cause = traits::ObligationCause::misc(span, impl_did);
650    let obligation = Obligation::new(
651        tcx,
652        cause,
653        param_env,
654        ty::TraitRef::new(tcx, trait_def_id, [source, target]),
655    );
656    ocx.register_obligation(obligation);
657    let errors = ocx.evaluate_obligations_error_on_ambiguity();
658
659    if !errors.is_empty() {
660        if is_from_coerce_pointee_derive(tcx, span) {
661            return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
662                span,
663                trait_name,
664                ty: trait_ref.self_ty(),
665                field_span,
666                field_ty: source,
667            }));
668        } else {
669            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
670        }
671    }
672
673    // Finally, resolve all regions.
674    ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
675
676    Ok(CoerceUnsizedInfo { custom_kind: kind })
677}
678
679fn infringing_fields_error<'tcx>(
680    tcx: TyCtxt<'tcx>,
681    infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
682    lang_item: LangItem,
683    impl_did: LocalDefId,
684    impl_span: Span,
685) -> ErrorGuaranteed {
686    let trait_did = tcx.require_lang_item(lang_item, impl_span);
687
688    let trait_name = tcx.def_path_str(trait_did);
689
690    // We'll try to suggest constraining type parameters to fulfill the requirements of
691    // their `Copy` implementation.
692    let mut errors: BTreeMap<_, Vec<_>> = Default::default();
693    let mut bounds = ::alloc::vec::Vec::new()vec![];
694
695    let mut seen_tys = FxHashSet::default();
696
697    let mut label_spans = Vec::new();
698
699    for (span, ty, reason) in infringing_tys {
700        // Only report an error once per type.
701        if !seen_tys.insert(ty) {
702            continue;
703        }
704
705        label_spans.push(span);
706
707        match reason {
708            InfringingFieldsReason::Fulfill(fulfillment_errors) => {
709                for error in fulfillment_errors {
710                    let error_predicate = error.obligation.predicate;
711                    // Only note if it's not the root obligation, otherwise it's trivial and
712                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
713
714                    // FIXME: This error could be more descriptive, especially if the error_predicate
715                    // contains a foreign type or if it's a deeply nested type...
716                    if error_predicate != error.root_obligation.predicate {
717                        errors
718                            .entry((ty.to_string(), error_predicate.to_string()))
719                            .or_default()
720                            .push(error.obligation.cause.span);
721                    }
722                    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
723                        trait_ref,
724                        polarity: ty::PredicatePolarity::Positive,
725                        ..
726                    })) = error_predicate.kind().skip_binder()
727                    {
728                        let ty = trait_ref.self_ty();
729                        if let ty::Param(_) = ty.kind() {
730                            bounds.push((
731                                ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("{0}", ty)) })format!("{ty}"),
732                                trait_ref.print_trait_sugared().to_string(),
733                                Some(trait_ref.def_id),
734                            ));
735                        }
736                    }
737                }
738            }
739            InfringingFieldsReason::Regions(region_errors) => {
740                for error in region_errors {
741                    let ty = ty.to_string();
742                    match error {
743                        RegionResolutionError::ConcreteFailure(origin, a, b) => {
744                            let predicate = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", b, a))
    })format!("{b}: {a}");
745                            errors
746                                .entry((ty.clone(), predicate.clone()))
747                                .or_default()
748                                .push(origin.span());
749                            if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
750                                && ebr.is_named()
751                            {
752                                bounds.push((b.to_string(), a.to_string(), None));
753                            }
754                        }
755                        RegionResolutionError::GenericBoundFailure(origin, a, b) => {
756                            let predicate = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", a, b))
    })format!("{a}: {b}");
757                            errors
758                                .entry((ty.clone(), predicate.clone()))
759                                .or_default()
760                                .push(origin.span());
761                            if let infer::region_constraints::GenericKind::Param(_) = a {
762                                bounds.push((a.to_string(), b.to_string(), None));
763                            }
764                        }
765                        _ => continue,
766                    }
767                }
768            }
769        }
770    }
771    let mut notes = Vec::new();
772    for ((ty, error_predicate), spans) in errors {
773        let span: MultiSpan = spans.into();
774        notes.push(errors::ImplForTyRequires {
775            span,
776            error_predicate,
777            trait_name: trait_name.clone(),
778            ty,
779        });
780    }
781
782    let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
783        span: impl_span,
784        trait_name,
785        label_spans,
786        notes,
787    });
788
789    suggest_constraining_type_params(
790        tcx,
791        tcx.hir_get_generics(impl_did).expect("impls always have generics"),
792        &mut err,
793        bounds
794            .iter()
795            .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
796        None,
797    );
798
799    err.emit()
800}
801
802fn visit_implementation_of_coerce_pointee_validity(
803    checker: &Checker<'_>,
804) -> Result<(), ErrorGuaranteed> {
805    let tcx = checker.tcx;
806    let self_ty =
807        tcx.impl_trait_ref(checker.impl_def_id).instantiate_identity().skip_norm_wip().self_ty();
808    let span = tcx.def_span(checker.impl_def_id);
809    if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
810        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
811    }
812    let ty::Adt(def, _args) = self_ty.kind() else {
813        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
814    };
815    let did = def.did();
816    // Now get a more precise span of the `struct`.
817    let span = tcx.def_span(did);
818    if !def.is_struct() {
819        return Err(tcx
820            .dcx()
821            .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
822    }
823    if !def.repr().transparent() {
824        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
825    }
826    if def.all_fields().next().is_none() {
827        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
828    }
829    Ok(())
830}