1use std::assert_matches::assert_matches;
5use std::collections::BTreeMap;
6
7use rustc_data_structures::fx::FxHashSet;
8use rustc_errors::{ErrorGuaranteed, MultiSpan};
9use rustc_hir as hir;
10use rustc_hir::ItemKind;
11use rustc_hir::def_id::{DefId, LocalDefId};
12use rustc_hir::lang_items::LangItem;
13use rustc_infer::infer::{self, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
14use rustc_infer::traits::Obligation;
15use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
16use rustc_middle::ty::print::PrintTraitRefExt as _;
17use rustc_middle::ty::{
18 self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
19};
20use rustc_span::{DUMMY_SP, Span, sym};
21use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
22use rustc_trait_selection::traits::misc::{
23 ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
24 type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
25};
26use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
27use tracing::debug;
28
29use crate::errors;
30
31pub(super) fn check_trait<'tcx>(
32 tcx: TyCtxt<'tcx>,
33 trait_def_id: DefId,
34 impl_def_id: LocalDefId,
35 impl_header: ty::ImplTraitHeader<'tcx>,
36) -> Result<(), ErrorGuaranteed> {
37 let lang_items = tcx.lang_items();
38 let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
39 checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
40 checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
41 checker.check(lang_items.const_param_ty_trait(), |checker| {
42 visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
43 })?;
44 checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
45 visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
46 })?;
47 checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
48 checker
49 .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
50 checker.check(
51 lang_items.coerce_pointee_validated_trait(),
52 visit_implementation_of_coerce_pointee_validity,
53 )?;
54 Ok(())
55}
56
57struct Checker<'tcx> {
58 tcx: TyCtxt<'tcx>,
59 trait_def_id: DefId,
60 impl_def_id: LocalDefId,
61 impl_header: ty::ImplTraitHeader<'tcx>,
62}
63
64impl<'tcx> Checker<'tcx> {
65 fn check(
66 &self,
67 trait_def_id: Option<DefId>,
68 f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>,
69 ) -> Result<(), ErrorGuaranteed> {
70 if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) }
71 }
72}
73
74fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
75 let tcx = checker.tcx;
76 let impl_did = checker.impl_def_id;
77 match checker.impl_header.trait_ref.instantiate_identity().self_ty().kind() {
79 ty::Adt(def, _) if def.did().is_local() => return Ok(()),
80 ty::Error(_) => return Ok(()),
81 _ => {}
82 }
83
84 let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
85
86 Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
87}
88
89fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
90 let tcx = checker.tcx;
91 let impl_header = checker.impl_header;
92 let impl_did = checker.impl_def_id;
93 debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
94
95 let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
96 debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
97
98 let param_env = tcx.param_env(impl_did);
99 assert!(!self_type.has_escaping_bound_vars());
100
101 debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
102
103 if let ty::ImplPolarity::Negative = impl_header.polarity {
104 return Ok(());
105 }
106
107 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
108 match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
109 Ok(()) => Ok(()),
110 Err(CopyImplementationError::InfringingFields(fields)) => {
111 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
112 Err(infringing_fields_error(
113 tcx,
114 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
115 LangItem::Copy,
116 impl_did,
117 span,
118 ))
119 }
120 Err(CopyImplementationError::NotAnAdt) => {
121 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
122 Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
123 }
124 Err(CopyImplementationError::HasDestructor) => {
125 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
126 Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
127 }
128 Err(CopyImplementationError::HasUnsafeFields) => {
129 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
130 Err(tcx
131 .dcx()
132 .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
133 }
134 }
135}
136
137fn visit_implementation_of_const_param_ty(
138 checker: &Checker<'_>,
139 kind: LangItem,
140) -> Result<(), ErrorGuaranteed> {
141 assert_matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy);
142
143 let tcx = checker.tcx;
144 let header = checker.impl_header;
145 let impl_did = checker.impl_def_id;
146 let self_type = header.trait_ref.instantiate_identity().self_ty();
147 assert!(!self_type.has_escaping_bound_vars());
148
149 let param_env = tcx.param_env(impl_did);
150
151 if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
152 return Ok(());
153 }
154
155 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
156 match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
157 Ok(()) => Ok(()),
158 Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
159 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
160 Err(infringing_fields_error(
161 tcx,
162 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
163 LangItem::ConstParamTy,
164 impl_did,
165 span,
166 ))
167 }
168 Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
169 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
170 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
171 }
172 Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
173 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
174 Err(infringing_fields_error(
175 tcx,
176 infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
177 LangItem::ConstParamTy,
178 impl_did,
179 span,
180 ))
181 }
182 Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
183 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
184 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
185 }
186 }
187}
188
189fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
190 let tcx = checker.tcx;
191 let impl_did = checker.impl_def_id;
192 debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
193
194 tcx.ensure_ok().coerce_unsized_info(impl_did)
198}
199
200fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
201 span.ctxt()
202 .outer_expn_data()
203 .macro_def_id
204 .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
205}
206
207fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
208 let tcx = checker.tcx;
209 let impl_did = checker.impl_def_id;
210 let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
211 debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
212
213 let span = tcx.def_span(impl_did);
214 let trait_name = "DispatchFromDyn";
215
216 let source = trait_ref.self_ty();
217 let target = {
218 assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
219
220 trait_ref.args.type_at(1)
221 };
222
223 let mut res = Ok(());
226 tcx.for_each_relevant_impl(
227 tcx.require_lang_item(LangItem::CoerceUnsized, span),
228 source,
229 |impl_def_id| {
230 res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
231 },
232 );
233 res?;
234
235 debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
236
237 let param_env = tcx.param_env(impl_did);
238
239 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
240 let cause = ObligationCause::misc(span, impl_did);
241
242 match (source.kind(), target.kind()) {
251 (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
252 if r_a == *r_b && mutbl_a == *mutbl_b =>
253 {
254 Ok(())
255 }
256 (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
257 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
258 if def_a.is_struct() && def_b.is_struct() =>
259 {
260 if def_a != def_b {
261 let source_path = tcx.def_path_str(def_a.did());
262 let target_path = tcx.def_path_str(def_b.did());
263 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
264 span,
265 trait_name,
266 note: true,
267 source_path,
268 target_path,
269 }));
270 }
271
272 if def_a.repr().c() || def_a.repr().packed() {
273 return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
274 }
275
276 let fields = &def_a.non_enum_variant().fields;
277
278 let mut res = Ok(());
279 let coerced_fields = fields
280 .iter_enumerated()
281 .filter_map(|(i, field)| {
282 let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
284 if tcx
285 .try_normalize_erasing_regions(
286 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
287 unnormalized_ty,
288 )
289 .unwrap_or(unnormalized_ty)
290 .is_phantom_data()
291 {
292 return None;
293 }
294
295 let ty_a = field.ty(tcx, args_a);
296 let ty_b = field.ty(tcx, args_b);
297
298 if ty_a == ty_b {
300 if let Ok(layout) =
305 tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
306 && layout.is_1zst()
307 && !ty_a.has_non_region_param()
308 {
309 return None;
311 }
312
313 res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
314 span,
315 name: field.ident(tcx),
316 ty: ty_a,
317 }));
318
319 None
320 } else {
321 Some((i, ty_a, ty_b, tcx.def_span(field.did)))
322 }
323 })
324 .collect::<Vec<_>>();
325 res?;
326
327 if coerced_fields.is_empty() {
328 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
329 span,
330 trait_name,
331 note: true,
332 }));
333 } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
334 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
335 ocx.register_obligation(Obligation::new(
336 tcx,
337 cause.clone(),
338 param_env,
339 ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
340 ));
341 let errors = ocx.select_all_or_error();
342 if !errors.is_empty() {
343 if is_from_coerce_pointee_derive(tcx, span) {
344 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
345 span,
346 trait_name,
347 ty: trait_ref.self_ty(),
348 field_span,
349 field_ty: ty_a,
350 }));
351 } else {
352 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
353 }
354 }
355
356 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
358
359 Ok(())
360 } else {
361 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
362 span,
363 trait_name,
364 number: coerced_fields.len(),
365 fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
366 }));
367 }
368 }
369 _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
370 }
371}
372
373pub(crate) fn coerce_unsized_info<'tcx>(
374 tcx: TyCtxt<'tcx>,
375 impl_did: LocalDefId,
376) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
377 debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
378 let span = tcx.def_span(impl_did);
379 let trait_name = "CoerceUnsized";
380
381 let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
382 let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
383
384 let source = tcx.type_of(impl_did).instantiate_identity();
385 let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
386
387 assert_eq!(trait_ref.def_id, coerce_unsized_trait);
388 let target = trait_ref.args.type_at(1);
389 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
390
391 let param_env = tcx.param_env(impl_did);
392 assert!(!source.has_escaping_bound_vars());
393
394 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
395
396 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
397 let cause = ObligationCause::misc(span, impl_did);
398 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
399 mt_b: ty::TypeAndMut<'tcx>,
400 mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
401 if mt_a.mutbl < mt_b.mutbl {
402 infcx
403 .err_ctxt()
404 .report_mismatched_types(
405 &cause,
406 param_env,
407 mk_ptr(mt_b.ty),
408 target,
409 ty::error::TypeError::Mutability,
410 )
411 .emit();
412 }
413 (mt_a.ty, mt_b.ty, unsize_trait, None, span)
414 };
415 let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
416 (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
417 infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
418 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
419 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
420 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
421 }
422
423 (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
424 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
425 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
426 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
427 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
428 }
429
430 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
431 if def_a.is_struct() && def_b.is_struct() =>
432 {
433 if def_a != def_b {
434 let source_path = tcx.def_path_str(def_a.did());
435 let target_path = tcx.def_path_str(def_b.did());
436 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
437 span,
438 trait_name,
439 note: true,
440 source_path,
441 target_path,
442 }));
443 }
444
445 let fields = &def_a.non_enum_variant().fields;
485 let diff_fields = fields
486 .iter_enumerated()
487 .filter_map(|(i, f)| {
488 let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
489
490 let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
492 if tcx
493 .try_normalize_erasing_regions(
494 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
495 unnormalized_ty,
496 )
497 .unwrap_or(unnormalized_ty)
498 .is_phantom_data()
499 {
500 return None;
501 }
502
503 if a == b {
513 return None;
514 }
515
516 Some((i, a, b, tcx.def_span(f.did)))
519 })
520 .collect::<Vec<_>>();
521
522 if diff_fields.is_empty() {
523 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
524 span,
525 trait_name,
526 note: true,
527 }));
528 } else if diff_fields.len() > 1 {
529 let item = tcx.hir_expect_item(impl_did);
530 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
531 t.path.span
532 } else {
533 tcx.def_span(impl_did)
534 };
535
536 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
537 span,
538 trait_name,
539 number: diff_fields.len(),
540 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
541 }));
542 }
543
544 let (i, a, b, field_span) = diff_fields[0];
545 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
546 (a, b, coerce_unsized_trait, Some(kind), field_span)
547 }
548
549 _ => {
550 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
551 }
552 };
553
554 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
556 let cause = traits::ObligationCause::misc(span, impl_did);
557 let obligation = Obligation::new(
558 tcx,
559 cause,
560 param_env,
561 ty::TraitRef::new(tcx, trait_def_id, [source, target]),
562 );
563 ocx.register_obligation(obligation);
564 let errors = ocx.select_all_or_error();
565
566 if !errors.is_empty() {
567 if is_from_coerce_pointee_derive(tcx, span) {
568 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
569 span,
570 trait_name,
571 ty: trait_ref.self_ty(),
572 field_span,
573 field_ty: source,
574 }));
575 } else {
576 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
577 }
578 }
579
580 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
582
583 Ok(CoerceUnsizedInfo { custom_kind: kind })
584}
585
586fn infringing_fields_error<'tcx>(
587 tcx: TyCtxt<'tcx>,
588 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
589 lang_item: LangItem,
590 impl_did: LocalDefId,
591 impl_span: Span,
592) -> ErrorGuaranteed {
593 let trait_did = tcx.require_lang_item(lang_item, impl_span);
594
595 let trait_name = tcx.def_path_str(trait_did);
596
597 let mut errors: BTreeMap<_, Vec<_>> = Default::default();
600 let mut bounds = vec![];
601
602 let mut seen_tys = FxHashSet::default();
603
604 let mut label_spans = Vec::new();
605
606 for (span, ty, reason) in infringing_tys {
607 if !seen_tys.insert(ty) {
609 continue;
610 }
611
612 label_spans.push(span);
613
614 match reason {
615 InfringingFieldsReason::Fulfill(fulfillment_errors) => {
616 for error in fulfillment_errors {
617 let error_predicate = error.obligation.predicate;
618 if error_predicate != error.root_obligation.predicate {
624 errors
625 .entry((ty.to_string(), error_predicate.to_string()))
626 .or_default()
627 .push(error.obligation.cause.span);
628 }
629 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
630 trait_ref,
631 polarity: ty::PredicatePolarity::Positive,
632 ..
633 })) = error_predicate.kind().skip_binder()
634 {
635 let ty = trait_ref.self_ty();
636 if let ty::Param(_) = ty.kind() {
637 bounds.push((
638 format!("{ty}"),
639 trait_ref.print_trait_sugared().to_string(),
640 Some(trait_ref.def_id),
641 ));
642 }
643 }
644 }
645 }
646 InfringingFieldsReason::Regions(region_errors) => {
647 for error in region_errors {
648 let ty = ty.to_string();
649 match error {
650 RegionResolutionError::ConcreteFailure(origin, a, b) => {
651 let predicate = format!("{b}: {a}");
652 errors
653 .entry((ty.clone(), predicate.clone()))
654 .or_default()
655 .push(origin.span());
656 if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
657 && ebr.is_named()
658 {
659 bounds.push((b.to_string(), a.to_string(), None));
660 }
661 }
662 RegionResolutionError::GenericBoundFailure(origin, a, b) => {
663 let predicate = format!("{a}: {b}");
664 errors
665 .entry((ty.clone(), predicate.clone()))
666 .or_default()
667 .push(origin.span());
668 if let infer::region_constraints::GenericKind::Param(_) = a {
669 bounds.push((a.to_string(), b.to_string(), None));
670 }
671 }
672 _ => continue,
673 }
674 }
675 }
676 }
677 }
678 let mut notes = Vec::new();
679 for ((ty, error_predicate), spans) in errors {
680 let span: MultiSpan = spans.into();
681 notes.push(errors::ImplForTyRequires {
682 span,
683 error_predicate,
684 trait_name: trait_name.clone(),
685 ty,
686 });
687 }
688
689 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
690 span: impl_span,
691 trait_name,
692 label_spans,
693 notes,
694 });
695
696 suggest_constraining_type_params(
697 tcx,
698 tcx.hir_get_generics(impl_did).expect("impls always have generics"),
699 &mut err,
700 bounds
701 .iter()
702 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
703 None,
704 );
705
706 err.emit()
707}
708
709fn visit_implementation_of_coerce_pointee_validity(
710 checker: &Checker<'_>,
711) -> Result<(), ErrorGuaranteed> {
712 let tcx = checker.tcx;
713 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
714 let span = tcx.def_span(checker.impl_def_id);
715 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
716 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
717 }
718 let ty::Adt(def, _args) = self_ty.kind() else {
719 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
720 };
721 let did = def.did();
722 let span = tcx.def_span(did);
724 if !def.is_struct() {
725 return Err(tcx
726 .dcx()
727 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
728 }
729 if !def.repr().transparent() {
730 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
731 }
732 if def.all_fields().next().is_none() {
733 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
734 }
735 Ok(())
736}