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