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