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