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