1 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
3 use crate::traits::{self, ObligationCause};
5 use rustc_data_structures::fx::FxIndexSet;
7 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
8 use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
9 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
11 use super::outlives_bounds::InferCtxtExt;
13 pub enum CopyImplementationError<'tcx> {
14 InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
19 pub enum InfringingFieldsReason<'tcx> {
20 Fulfill(Vec<FulfillmentError<'tcx>>),
21 Regions(Vec<RegionResolutionError<'tcx>>),
24 /// Checks that the fields of the type (an ADT) all implement copy.
26 /// If fields don't implement copy, return an error containing a list of
27 /// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
28 pub fn type_allowed_to_implement_copy<'tcx>(
30 param_env: ty::ParamEnv<'tcx>,
32 parent_cause: ObligationCause<'tcx>,
33 ) -> Result<(), CopyImplementationError<'tcx>> {
34 let (adt, substs) = match self_type.kind() {
35 // These types used to have a builtin impl.
36 // Now libcore provides that impl.
44 | ty::Ref(_, _, hir::Mutability::Not)
45 | ty::Array(..) => return Ok(()),
47 ty::Adt(adt, substs) => (adt, substs),
49 _ => return Err(CopyImplementationError::NotAnAdt),
52 let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
54 let mut infringing = Vec::new();
55 for variant in adt.variants() {
56 for field in &variant.fields {
57 // Do this per-field to get better error messages.
58 let infcx = tcx.infer_ctxt().build();
59 let ocx = traits::ObligationCtxt::new(&infcx);
61 let unnormalized_ty = field.ty(tcx, substs);
62 if unnormalized_ty.references_error() {
66 let field_span = tcx.def_span(field.did);
67 let field_ty_span = match tcx.hir().get_if_local(field.did) {
68 Some(hir::Node::Field(field_def)) => field_def.ty.span,
72 // FIXME(compiler-errors): This gives us better spans for bad
73 // projection types like in issue-50480.
74 // If the ADT has substs, point to the cause we are given.
75 // If it does not, then this field probably doesn't normalize
76 // to begin with, and point to the bad field's span instead.
77 let normalization_cause = if field
78 .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
79 .has_non_region_param()
83 ObligationCause::dummy_with_span(field_ty_span)
85 let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
86 let normalization_errors = ocx.select_where_possible();
87 if !normalization_errors.is_empty() {
88 tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
93 ObligationCause::dummy_with_span(field_ty_span),
98 let errors = ocx.select_all_or_error();
99 if !errors.is_empty() {
100 infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
103 // Check regions assuming the self type of the impl is WF
104 let outlives_env = OutlivesEnvironment::with_bounds(
107 infcx.implied_bounds_tys(
109 parent_cause.body_id,
110 FxIndexSet::from_iter([self_type]),
113 infcx.process_registered_region_obligations(
114 outlives_env.region_bound_pairs(),
117 let errors = infcx.resolve_regions(&outlives_env);
118 if !errors.is_empty() {
119 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
124 if !infringing.is_empty() {
125 return Err(CopyImplementationError::InfrigingFields(infringing));
128 if adt.has_dtor(tcx) {
129 return Err(CopyImplementationError::HasDestructor);