1//! Check properties that are required by built-in traits and set2//! up data structures required by type-checking/codegen.34use std::collections::BTreeMap;56use 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, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};13use rustc_infer::traits::{Obligation, PredicateObligations};14use rustc_middle::ty::adjustment::CoerceUnsizedInfo;15use rustc_middle::ty::print::PrintTraitRefExt as _;16use rustc_middle::ty::relate::solver_relating::RelateExt;17use rustc_middle::ty::{18 self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, 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, FulfillmentError, ObligationCause, ObligationCtxt};27use tracing::debug;2829use crate::errors;3031pub(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.unpin_trait(), visit_implementation_of_unpin)?;43 checker.check(lang_items.const_param_ty_trait(), |checker| {44 visit_implementation_of_const_param_ty(checker)45 })?;46 checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;47 checker.check(lang_items.reborrow(), visit_implementation_of_reborrow)?;48 checker.check(lang_items.coerce_shared(), visit_implementation_of_coerce_shared)?;49 checker50 .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}5758struct Checker<'tcx> {59 tcx: TyCtxt<'tcx>,60 trait_def_id: DefId,61 impl_def_id: LocalDefId,62 impl_header: ty::ImplTraitHeader<'tcx>,63}6465impl<'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}7475fn 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().skip_norm_wip().self_ty().kind() {80 ty::Adt(def, _) if def.did().is_local() => return Ok(()),81 ty::Error(_) => return Ok(()),82 _ => {}83 }8485 let impl_ = tcx.hir_expect_item(impl_did).expect_impl();8687 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}9293fn 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);9899 let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();100 debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);101102 let param_env = tcx.param_env(impl_did);103 assert!(!self_type.has_escaping_bound_vars());104105 debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);106107 if let ty::ImplPolarity::Negative = impl_header.polarity {108 return Ok(());109 }110111 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(did)) => {129 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;130 let impl_ = tcx.def_span(did);131 Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span, impl_ }))132 }133 Err(CopyImplementationError::HasUnsafeFields) => {134 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;135 Err(tcx136 .dcx()137 .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))138 }139 }140}141142fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {143 let tcx = checker.tcx;144 let impl_header = checker.impl_header;145 let impl_did = checker.impl_def_id;146 debug!("visit_implementation_of_unpin: impl_did={:?}", impl_did);147148 let self_type = impl_header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();149 debug!("visit_implementation_of_unpin: self_type={:?}", self_type);150151 let span = tcx.def_span(impl_did);152153 if tcx.features().pin_ergonomics() {154 match self_type.kind() {155 // Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project156 // `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).157 // If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,158 // which cannot carry safety properties), then `&mut U` could be obtained from159 // `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of160 // `Pin<&mut U>` for `U: !Unpin`.161 ty::Adt(adt, _) if adt.is_pin_project() => {162 return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {163 span,164 adt_span: tcx.def_span(adt.did()),165 adt_name: tcx.item_name(adt.did()),166 }));167 }168 ty::Adt(_, _) => {}169 _ => {170 return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));171 }172 };173 }174 Ok(())175}176177fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {178 let tcx = checker.tcx;179 let header = checker.impl_header;180 let impl_did = checker.impl_def_id;181 let self_type = header.trait_ref.instantiate_identity().skip_norm_wip().self_ty();182 assert!(!self_type.has_escaping_bound_vars());183184 let param_env = tcx.param_env(impl_did);185186 if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {187 return Ok(());188 }189190 if tcx.features().const_param_ty_unchecked() {191 return Ok(());192 }193194 if !tcx.features().adt_const_params() {195 match *self_type.kind() {196 ty::Adt(adt, _) if adt.is_struct() => {197 let struct_vis = tcx.visibility(adt.did());198 for variant in adt.variants() {199 for field in &variant.fields {200 if struct_vis.greater_than(field.vis, tcx) {201 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;202 return Err(tcx203 .dcx()204 .emit_err(errors::ConstParamTyFieldVisMismatch { span }));205 }206 }207 }208 }209210 _ => {}211 }212 }213214 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);215 match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {216 Ok(()) => Ok(()),217 Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {218 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;219 Err(infringing_fields_error(220 tcx,221 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),222 LangItem::ConstParamTy,223 impl_did,224 span,225 ))226 }227 Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {228 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;229 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))230 }231 Err(ConstParamTyImplementationError::NonExhaustive(attr_span)) => {232 let defn_span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;233 Err(tcx234 .dcx()235 .emit_err(errors::ConstParamTyImplOnNonExhaustive { defn_span, attr_span }))236 }237 Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {238 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;239 Err(infringing_fields_error(240 tcx,241 infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),242 LangItem::ConstParamTy,243 impl_did,244 span,245 ))246 }247 Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {248 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;249 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))250 }251 }252}253254fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {255 let tcx = checker.tcx;256 let impl_did = checker.impl_def_id;257 debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);258259 // Just compute this for the side-effects, in particular reporting260 // errors; other parts of the code may demand it for the info of261 // course.262 tcx.ensure_result().coerce_unsized_info(impl_did)263}264265fn visit_implementation_of_reborrow(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {266 let tcx = checker.tcx;267 let impl_did = checker.impl_def_id;268 debug!("visit_implementation_of_reborrow: impl_did={:?}", impl_did);269270 // Just compute this for the side-effects, in particular reporting271 // errors; other parts of the code may demand it for the info of272 // course.273 reborrow_info(tcx, impl_did)274}275276fn visit_implementation_of_coerce_shared(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {277 let tcx = checker.tcx;278 let impl_did = checker.impl_def_id;279 debug!("visit_implementation_of_coerce_shared: impl_did={:?}", impl_did);280281 // Just compute this for the side-effects, in particular reporting282 // errors; other parts of the code may demand it for the info of283 // course.284 coerce_shared_info(tcx, impl_did)285}286287fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {288 span.ctxt()289 .outer_expn_data()290 .macro_def_id291 .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))292}293294fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {295 let tcx = checker.tcx;296 let impl_did = checker.impl_def_id;297 let trait_ref = checker.impl_header.trait_ref.instantiate_identity().skip_norm_wip();298 debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);299300 let span = tcx.def_span(impl_did);301 let trait_name = "DispatchFromDyn";302303 let source = trait_ref.self_ty();304 let target = {305 assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));306307 trait_ref.args.type_at(1)308 };309310 // Check `CoercePointee` impl is WF -- if not, then there's no reason to report311 // redundant errors for `DispatchFromDyn`. This is best effort, though.312 let mut res = Ok(());313 tcx.for_each_relevant_impl(314 tcx.require_lang_item(LangItem::CoerceUnsized, span),315 source,316 |impl_def_id| {317 res = res.and(tcx.ensure_result().coerce_unsized_info(impl_def_id));318 },319 );320 res?;321322 debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);323324 let param_env = tcx.param_env(impl_did);325326 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());327 let cause = ObligationCause::misc(span, impl_did);328329 // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw330 // pointers. This is enforced here: we only allow impls for references, raw pointers, and things331 // that are effectively repr(transparent) newtypes around types that already hav a332 // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some333 // of them support an allocator, but we ensure that for the cases where the type implements this334 // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else335 // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)336 // even if they do not carry that attribute.337 match (source.kind(), target.kind()) {338 (&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {339 if pat_a != pat_b {340 return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {341 span,342 trait_name,343 pat_a: pat_a.to_string(),344 pat_b: pat_b.to_string(),345 }));346 }347 Ok(())348 }349350 (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))351 if r_a == *r_b && mutbl_a == *mutbl_b =>352 {353 Ok(())354 }355 (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),356 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))357 if def_a.is_struct() && def_b.is_struct() =>358 {359 if def_a != def_b {360 let source_path = tcx.def_path_str(def_a.did());361 let target_path = tcx.def_path_str(def_b.did());362 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {363 span,364 trait_name,365 note: true,366 source_path,367 target_path,368 }));369 }370371 if def_a.repr().c() || def_a.repr().packed() {372 return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));373 }374375 let fields = &def_a.non_enum_variant().fields;376377 let mut res = Ok(());378 let coerced_fields = fields379 .iter_enumerated()380 .filter_map(|(i, field)| {381 // Ignore PhantomData fields382 let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();383 if tcx384 .try_normalize_erasing_regions(385 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),386 unnormalized_ty,387 )388 .unwrap_or(unnormalized_ty.skip_norm_wip())389 .is_phantom_data()390 {391 return None;392 }393394 let ty_a = field.ty(tcx, args_a);395 let ty_b = field.ty(tcx, args_b);396397 // FIXME: We could do normalization here, but is it really worth it?398 if ty_a == ty_b {399 // Allow 1-ZSTs that don't mention type params.400 //401 // Allowing type params here would allow us to possibly transmute402 // between ZSTs, which may be used to create library unsoundness.403 if let Ok(layout) =404 tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))405 && layout.is_1zst()406 && !ty_a.has_non_region_param()407 {408 // ignore 1-ZST fields409 return None;410 }411412 res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {413 span,414 name: field.ident(tcx),415 ty: ty_a,416 }));417418 None419 } else {420 Some((i, ty_a, ty_b, tcx.def_span(field.did)))421 }422 })423 .collect::<Vec<_>>();424 res?;425426 if coerced_fields.is_empty() {427 return Err(tcx.dcx().emit_err(errors::CoerceNoField {428 span,429 trait_name,430 note: true,431 }));432 } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {433 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);434 ocx.register_obligation(Obligation::new(435 tcx,436 cause.clone(),437 param_env,438 ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),439 ));440 let errors = ocx.evaluate_obligations_error_on_ambiguity();441 if !errors.is_empty() {442 if is_from_coerce_pointee_derive(tcx, span) {443 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {444 span,445 trait_name,446 ty: trait_ref.self_ty(),447 field_span,448 field_ty: ty_a,449 }));450 } else {451 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));452 }453 }454455 // Finally, resolve all regions.456 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;457458 Ok(())459 } else {460 return Err(tcx.dcx().emit_err(errors::CoerceMulti {461 span,462 trait_name,463 number: coerced_fields.len(),464 fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),465 }));466 }467 }468 _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),469 }470}471472fn structurally_normalize_ty<'tcx>(473 tcx: TyCtxt<'tcx>,474 infcx: &InferCtxt<'tcx>,475 impl_did: LocalDefId,476 span: Span,477 ty: Unnormalized<'tcx, Ty<'tcx>>,478) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {479 let ocx = ObligationCtxt::new(infcx);480 let Ok(normalized_ty) = ocx.structurally_normalize_ty(481 &traits::ObligationCause::misc(span, impl_did),482 tcx.param_env(impl_did),483 ty,484 ) else {485 // We shouldn't have errors here in the old solver, except for486 // evaluate/fulfill mismatches, but that's not a reason for an ICE.487 return None;488 };489 let errors = ocx.try_evaluate_obligations();490 if !errors.is_empty() {491 if infcx.next_trait_solver() {492 unreachable!();493 }494 // We shouldn't have errors here in the old solver, except for495 // evaluate/fulfill mismatches, but that's not a reason for an ICE.496 debug!(?errors, "encountered errors while fulfilling");497 return None;498 }499500 Some((normalized_ty, ocx.into_pending_obligations()))501}502503pub(crate) fn reborrow_info<'tcx>(504 tcx: TyCtxt<'tcx>,505 impl_did: LocalDefId,506) -> Result<(), ErrorGuaranteed> {507 debug!("compute_reborrow_info(impl_did={:?})", impl_did);508 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());509 let span = tcx.def_span(impl_did);510 let trait_name = "Reborrow";511512 let reborrow_trait = tcx.require_lang_item(LangItem::Reborrow, span);513514 let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();515 let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();516517 if trait_impl_lifetime_params_count(tcx, impl_did) != 1 {518 return Err(tcx519 .dcx()520 .emit_err(errors::CoerceSharedNotSingleLifetimeParam { span, trait_name }));521 }522523 assert_eq!(trait_ref.def_id, reborrow_trait);524 let param_env = tcx.param_env(impl_did);525 assert!(!source.has_escaping_bound_vars());526527 let (def, args) = match source.kind() {528 &ty::Adt(def, args) if def.is_struct() => (def, args),529 _ => {530 // Note: reusing error here as it takes trait_name as argument.531 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));532 }533 };534535 let lifetimes_count = generic_lifetime_params_count(args);536 let data_fields = collect_struct_data_fields(tcx, def, args);537538 if lifetimes_count != 1 {539 let item = tcx.hir_expect_item(impl_did);540 let _span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = &item.kind {541 of_trait.trait_ref.path.span542 } else {543 tcx.def_span(impl_did)544 };545546 return Err(tcx.dcx().emit_err(errors::CoerceSharedMulti { span, trait_name }));547 }548549 if data_fields.is_empty() {550 return Ok(());551 }552553 // We've found some data fields. They must all be either be Copy or Reborrow.554 for (field, span) in data_fields {555 if assert_field_type_is_reborrow(556 tcx,557 &infcx,558 reborrow_trait,559 impl_did,560 param_env,561 field,562 span,563 )564 .is_ok()565 {566 // Field implements Reborrow.567 return Ok(());568 }569570 // Field does not implement Reborrow: it must be Copy.571 assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field, span)?;572 }573574 Ok(())575}576577fn assert_field_type_is_reborrow<'tcx>(578 tcx: TyCtxt<'tcx>,579 infcx: &InferCtxt<'tcx>,580 reborrow_trait: DefId,581 impl_did: LocalDefId,582 param_env: ty::ParamEnv<'tcx>,583 ty: Ty<'tcx>,584 span: Span,585) -> Result<(), Vec<FulfillmentError<'tcx>>> {586 if ty.ref_mutability() == Some(ty::Mutability::Mut) {587 // Mutable references are Reborrow but not really.588 return Ok(());589 }590 let ocx = ObligationCtxt::new_with_diagnostics(infcx);591 let cause = traits::ObligationCause::misc(span, impl_did);592 let obligation =593 Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, reborrow_trait, [ty]));594 ocx.register_obligation(obligation);595 let errors = ocx.evaluate_obligations_error_on_ambiguity();596597 if !errors.is_empty() { Err(errors) } else { Ok(()) }598}599600pub(crate) fn coerce_shared_info<'tcx>(601 tcx: TyCtxt<'tcx>,602 impl_did: LocalDefId,603) -> Result<(), ErrorGuaranteed> {604 debug!("compute_coerce_shared_info(impl_did={:?})", impl_did);605 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());606 let span = tcx.def_span(impl_did);607 let trait_name = "CoerceShared";608609 let coerce_shared_trait = tcx.require_lang_item(LangItem::CoerceShared, span);610611 let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();612 let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();613614 if trait_impl_lifetime_params_count(tcx, impl_did) != 1 {615 return Err(tcx616 .dcx()617 .emit_err(errors::CoerceSharedNotSingleLifetimeParam { span, trait_name }));618 }619620 assert_eq!(trait_ref.def_id, coerce_shared_trait);621 let Some((target, _obligations)) = structurally_normalize_ty(622 tcx,623 &infcx,624 impl_did,625 span,626 Unnormalized::new_wip(trait_ref.args.type_at(1)),627 ) else {628 todo!("something went wrong with structurally_normalize_ty");629 };630631 let param_env = tcx.param_env(impl_did);632 assert!(!source.has_escaping_bound_vars());633634 let data = match (source.kind(), target.kind()) {635 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))636 if def_a.is_struct() && def_b.is_struct() =>637 {638 // Check that both A and B have exactly one lifetime argument, and that they have the639 // same number of data fields that is not more than 1. The eventual intention is to640 // support multiple lifetime arguments (with the reborrowed lifetimes inferred from641 // usage one way or another) and multiple data fields with B allowed to leave out fields642 // from A. The current state is just the simplest choice.643 let a_lifetimes_count = generic_lifetime_params_count(args_a);644 let a_data_fields = collect_struct_data_fields(tcx, def_a, args_a);645 let b_lifetimes_count = generic_lifetime_params_count(args_b);646 let b_data_fields = collect_struct_data_fields(tcx, def_b, args_b);647648 if a_lifetimes_count != 1649 || b_lifetimes_count != 1650 || a_data_fields.len() > 1651 || b_data_fields.len() > 1652 || a_data_fields.len() != b_data_fields.len()653 {654 let item = tcx.hir_expect_item(impl_did);655 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =656 &item.kind657 {658 of_trait.trait_ref.path.span659 } else {660 tcx.def_span(impl_did)661 };662663 return Err(tcx.dcx().emit_err(errors::CoerceSharedMulti { span, trait_name }));664 }665666 if a_data_fields.len() == 1 {667 // We found one data field for both: we'll attempt to perform CoerceShared between668 // them below.669 let (a, span_a) = a_data_fields[0];670 let (b, span_b) = b_data_fields[0];671672 Some((a, b, coerce_shared_trait, span_a, span_b))673 } else {674 // We found no data fields in either: this is a reborrowable marker type being675 // coerced into a shared marker. That is fine too.676 None677 }678 }679680 _ => {681 // Note: reusing CoerceUnsizedNonStruct error as it takes trait_name as argument.682 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));683 }684 };685686 // We've proven that we have two types with one lifetime each and 0 or 1 data fields each.687 if let Some((source, target, trait_def_id, source_field_span, _target_field_span)) = data {688 // struct Source(SourceData);689 // struct Target(TargetData);690 //691 // 1 data field each; they must be the same type and Copy, or relate to one another using692 // CoerceShared.693 if source.ref_mutability() == Some(ty::Mutability::Mut)694 && target.ref_mutability() == Some(ty::Mutability::Not)695 && infcx696 .eq_structurally_relating_aliases(697 param_env,698 source.peel_refs(),699 target.peel_refs(),700 source_field_span,701 )702 .is_ok()703 {704 // &mut T implements CoerceShared to &T, except not really.705 return Ok(());706 }707 if infcx708 .eq_structurally_relating_aliases(param_env, source, target, source_field_span)709 .is_err()710 {711 // The two data fields don't agree on a common type; this means712 // that they must be `A: CoerceShared<B>`. Register an obligation713 // for that.714 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);715 let cause = traits::ObligationCause::misc(span, impl_did);716 let obligation = Obligation::new(717 tcx,718 cause,719 param_env,720 ty::TraitRef::new(tcx, trait_def_id, [source, target]),721 );722 ocx.register_obligation(obligation);723 let errors = ocx.evaluate_obligations_error_on_ambiguity();724725 if !errors.is_empty() {726 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));727 }728 // Finally, resolve all regions.729 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;730 } else {731 // Types match: check that it is Copy.732 assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, source, source_field_span)?;733 }734 }735736 Ok(())737}738739fn trait_impl_lifetime_params_count(tcx: TyCtxt<'_>, did: LocalDefId) -> usize {740 tcx.generics_of(did)741 .own_params742 .iter()743 .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))744 .count()745}746747fn generic_lifetime_params_count(args: &[ty::GenericArg<'_>]) -> usize {748 args.iter().filter(|arg| arg.as_region().is_some()).count()749}750751fn collect_struct_data_fields<'tcx>(752 tcx: TyCtxt<'tcx>,753 def: ty::AdtDef<'tcx>,754 args: ty::GenericArgsRef<'tcx>,755) -> Vec<(Ty<'tcx>, Span)> {756 def.non_enum_variant()757 .fields758 .iter()759 .filter_map(|f| {760 // Ignore PhantomData fields761 let ty = f.ty(tcx, args);762 if ty.is_phantom_data() {763 return None;764 }765 Some((ty, tcx.def_span(f.did)))766 })767 .collect()768}769770fn assert_field_type_is_copy<'tcx>(771 tcx: TyCtxt<'tcx>,772 infcx: &InferCtxt<'tcx>,773 impl_did: LocalDefId,774 param_env: ty::ParamEnv<'tcx>,775 ty: Ty<'tcx>,776 span: Span,777) -> Result<(), ErrorGuaranteed> {778 let copy_trait = tcx.require_lang_item(LangItem::Copy, span);779 let ocx = ObligationCtxt::new_with_diagnostics(infcx);780 let cause = traits::ObligationCause::misc(span, impl_did);781 let obligation =782 Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, copy_trait, [ty]));783 ocx.register_obligation(obligation);784 let errors = ocx.evaluate_obligations_error_on_ambiguity();785786 if !errors.is_empty() {787 Err(infcx.err_ctxt().report_fulfillment_errors(errors))788 } else {789 Ok(())790 }791}792793pub(crate) fn coerce_unsized_info<'tcx>(794 tcx: TyCtxt<'tcx>,795 impl_did: LocalDefId,796) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {797 debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);798 let span = tcx.def_span(impl_did);799 let trait_name = "CoerceUnsized";800801 let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);802 let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);803804 let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();805 let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();806807 assert_eq!(trait_ref.def_id, coerce_unsized_trait);808 let target = trait_ref.args.type_at(1);809 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);810811 let param_env = tcx.param_env(impl_did);812 assert!(!source.has_escaping_bound_vars());813814 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);815816 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());817 let cause = ObligationCause::misc(span, impl_did);818 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,819 mt_b: ty::TypeAndMut<'tcx>,820 mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {821 if mt_a.mutbl < mt_b.mutbl {822 infcx823 .err_ctxt()824 .report_mismatched_types(825 &cause,826 param_env,827 mk_ptr(mt_b.ty),828 target,829 ty::error::TypeError::Mutability,830 )831 .emit();832 }833 (mt_a.ty, mt_b.ty, unsize_trait, None, span)834 };835 let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {836 (&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {837 if pat_a != pat_b {838 return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {839 span,840 trait_name,841 pat_a: pat_a.to_string(),842 pat_b: pat_b.to_string(),843 }));844 }845 (ty_a, ty_b, coerce_unsized_trait, None, span)846 }847848 (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {849 infcx.sub_regions(850 SubregionOrigin::RelateObjectBound(span),851 r_b,852 r_a,853 ty::VisibleForLeakCheck::Yes,854 );855 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };856 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };857 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))858 }859860 (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))861 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {862 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };863 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };864 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))865 }866867 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))868 if def_a.is_struct() && def_b.is_struct() =>869 {870 if def_a != def_b {871 let source_path = tcx.def_path_str(def_a.did());872 let target_path = tcx.def_path_str(def_b.did());873 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {874 span,875 trait_name,876 note: true,877 source_path,878 target_path,879 }));880 }881882 // Here we are considering a case of converting883 // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,884 // which acts like a pointer to `U`, but carries along some extra data of type `T`:885 //886 // struct Foo<T, U> {887 // extra: T,888 // ptr: *mut U,889 // }890 //891 // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized892 // to `Foo<T, [i32]>`. That impl would look like:893 //894 // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}895 //896 // Here `U = [i32; 3]` and `V = [i32]`. At runtime,897 // when this coercion occurs, we would be changing the898 // field `ptr` from a thin pointer of type `*mut [i32;899 // 3]` to a wide pointer of type `*mut [i32]` (with900 // extra data `3`). **The purpose of this check is to901 // make sure that we know how to do this conversion.**902 //903 // To check if this impl is legal, we would walk down904 // the fields of `Foo` and consider their types with905 // both generic parameters. We are looking to find that906 // exactly one (non-phantom) field has changed its907 // type, which we will expect to be the pointer that908 // is becoming fat (we could probably generalize this909 // to multiple thin pointers of the same type becoming910 // fat, but we don't). In this case:911 //912 // - `extra` has type `T` before and type `T` after913 // - `ptr` has type `*mut U` before and type `*mut V` after914 //915 // Since just one field changed, we would then check916 // that `*mut U: CoerceUnsized<*mut V>` is implemented917 // (in other words, that we know how to do this918 // conversion). This will work out because `U:919 // Unsize<V>`, and we have a builtin rule that `*mut920 // U` can be coerced to `*mut V` if `U: Unsize<V>`.921 let fields = &def_a.non_enum_variant().fields;922 let diff_fields = fields923 .iter_enumerated()924 .filter_map(|(i, f)| {925 let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));926927 // Ignore PhantomData fields928 let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();929 if tcx930 .try_normalize_erasing_regions(931 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),932 unnormalized_ty,933 )934 .unwrap_or(unnormalized_ty.skip_norm_wip())935 .is_phantom_data()936 {937 return None;938 }939940 // Ignore fields that aren't changed; it may941 // be that we could get away with subtyping or942 // something more accepting, but we use943 // equality because we want to be able to944 // perform this check without computing945 // variance or constraining opaque types' hidden types.946 // (This is because we may have to evaluate constraint947 // expressions in the course of execution.)948 // See e.g., #41936.949 if a == b {950 return None;951 }952953 // Collect up all fields that were significantly changed954 // i.e., those that contain T in coerce_unsized T -> U955 Some((i, a, b, tcx.def_span(f.did)))956 })957 .collect::<Vec<_>>();958959 if diff_fields.is_empty() {960 return Err(tcx.dcx().emit_err(errors::CoerceNoField {961 span,962 trait_name,963 note: true,964 }));965 } else if diff_fields.len() > 1 {966 let item = tcx.hir_expect_item(impl_did);967 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =968 &item.kind969 {970 of_trait.trait_ref.path.span971 } else {972 tcx.def_span(impl_did)973 };974975 return Err(tcx.dcx().emit_err(errors::CoerceMulti {976 span,977 trait_name,978 number: diff_fields.len(),979 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),980 }));981 }982983 let (i, a, b, field_span) = diff_fields[0];984 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);985 (a, b, coerce_unsized_trait, Some(kind), field_span)986 }987988 _ => {989 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));990 }991 };992993 // Register an obligation for `A: Trait<B>`.994 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);995 let cause = traits::ObligationCause::misc(span, impl_did);996 let obligation = Obligation::new(997 tcx,998 cause,999 param_env,1000 ty::TraitRef::new(tcx, trait_def_id, [source, target]),1001 );1002 ocx.register_obligation(obligation);1003 let errors = ocx.evaluate_obligations_error_on_ambiguity();10041005 if !errors.is_empty() {1006 if is_from_coerce_pointee_derive(tcx, span) {1007 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {1008 span,1009 trait_name,1010 ty: trait_ref.self_ty(),1011 field_span,1012 field_ty: source,1013 }));1014 } else {1015 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));1016 }1017 }10181019 // Finally, resolve all regions.1020 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;10211022 Ok(CoerceUnsizedInfo { custom_kind: kind })1023}10241025fn infringing_fields_error<'tcx>(1026 tcx: TyCtxt<'tcx>,1027 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,1028 lang_item: LangItem,1029 impl_did: LocalDefId,1030 impl_span: Span,1031) -> ErrorGuaranteed {1032 let trait_did = tcx.require_lang_item(lang_item, impl_span);10331034 let trait_name = tcx.def_path_str(trait_did);10351036 // We'll try to suggest constraining type parameters to fulfill the requirements of1037 // their `Copy` implementation.1038 let mut errors: BTreeMap<_, Vec<_>> = Default::default();1039 let mut bounds = vec![];10401041 let mut seen_tys = FxHashSet::default();10421043 let mut label_spans = Vec::new();10441045 for (span, ty, reason) in infringing_tys {1046 // Only report an error once per type.1047 if !seen_tys.insert(ty) {1048 continue;1049 }10501051 label_spans.push(span);10521053 match reason {1054 InfringingFieldsReason::Fulfill(fulfillment_errors) => {1055 for error in fulfillment_errors {1056 let error_predicate = error.obligation.predicate;1057 // Only note if it's not the root obligation, otherwise it's trivial and1058 // should be self-explanatory (i.e. a field literally doesn't implement Copy).10591060 // FIXME: This error could be more descriptive, especially if the error_predicate1061 // contains a foreign type or if it's a deeply nested type...1062 if error_predicate != error.root_obligation.predicate {1063 errors1064 .entry((ty.to_string(), error_predicate.to_string()))1065 .or_default()1066 .push(error.obligation.cause.span);1067 }1068 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {1069 trait_ref,1070 polarity: ty::PredicatePolarity::Positive,1071 ..1072 })) = error_predicate.kind().skip_binder()1073 {1074 let ty = trait_ref.self_ty();1075 if let ty::Param(_) = ty.kind() {1076 bounds.push((1077 format!("{ty}"),1078 trait_ref.print_trait_sugared().to_string(),1079 Some(trait_ref.def_id),1080 ));1081 }1082 }1083 }1084 }1085 InfringingFieldsReason::Regions(region_errors) => {1086 for error in region_errors {1087 let ty = ty.to_string();1088 match error {1089 RegionResolutionError::ConcreteFailure(origin, a, b) => {1090 let predicate = format!("{b}: {a}");1091 errors1092 .entry((ty.clone(), predicate.clone()))1093 .or_default()1094 .push(origin.span());1095 if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()1096 && ebr.is_named()1097 {1098 bounds.push((b.to_string(), a.to_string(), None));1099 }1100 }1101 RegionResolutionError::GenericBoundFailure(origin, a, b) => {1102 let predicate = format!("{a}: {b}");1103 errors1104 .entry((ty.clone(), predicate.clone()))1105 .or_default()1106 .push(origin.span());1107 if let infer::region_constraints::GenericKind::Param(_) = a {1108 bounds.push((a.to_string(), b.to_string(), None));1109 }1110 }1111 _ => continue,1112 }1113 }1114 }1115 }1116 }1117 let mut notes = Vec::new();1118 for ((ty, error_predicate), spans) in errors {1119 let span: MultiSpan = spans.into();1120 notes.push(errors::ImplForTyRequires {1121 span,1122 error_predicate,1123 trait_name: trait_name.clone(),1124 ty,1125 });1126 }11271128 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {1129 span: impl_span,1130 trait_name,1131 label_spans,1132 notes,1133 });11341135 suggest_constraining_type_params(1136 tcx,1137 tcx.hir_get_generics(impl_did).expect("impls always have generics"),1138 &mut err,1139 bounds1140 .iter()1141 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),1142 None,1143 );11441145 err.emit()1146}11471148fn visit_implementation_of_coerce_pointee_validity(1149 checker: &Checker<'_>,1150) -> Result<(), ErrorGuaranteed> {1151 let tcx = checker.tcx;1152 let self_ty =1153 tcx.impl_trait_ref(checker.impl_def_id).instantiate_identity().skip_norm_wip().self_ty();1154 let span = tcx.def_span(checker.impl_def_id);1155 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {1156 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));1157 }1158 let ty::Adt(def, _args) = self_ty.kind() else {1159 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));1160 };1161 let did = def.did();1162 // Now get a more precise span of the `struct`.1163 let span = tcx.def_span(did);1164 if !def.is_struct() {1165 return Err(tcx1166 .dcx()1167 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));1168 }1169 if !def.repr().transparent() {1170 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));1171 }1172 if def.all_fields().next().is_none() {1173 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));1174 }1175 Ok(())1176}