summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/misc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/misc.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs93
1 files changed, 70 insertions, 23 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index b6ded4ce5..a41a601f2 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -1,29 +1,36 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
-use crate::infer::InferCtxtExt as _;
use crate::traits::{self, ObligationCause};
+use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
+use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
-use crate::traits::error_reporting::TypeErrCtxtExt;
+use super::outlives_bounds::InferCtxtExt;
-#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
- InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
+ InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
NotAnAdt,
HasDestructor,
}
-pub fn can_type_implement_copy<'tcx>(
+pub enum InfringingFieldsReason<'tcx> {
+ Fulfill(Vec<FulfillmentError<'tcx>>),
+ Regions(Vec<RegionResolutionError<'tcx>>),
+}
+
+/// Checks that the fields of the type (an ADT) all implement copy.
+///
+/// If fields don't implement copy, return an error containing a list of
+/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
+pub fn type_allowed_to_implement_copy<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
parent_cause: ObligationCause<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
- // FIXME: (@jroesch) float this code up
- let infcx = tcx.infer_ctxt().build();
let (adt, substs) = match self_type.kind() {
// These types used to have a builtin impl.
// Now libcore provides that impl.
@@ -42,42 +49,82 @@ pub fn can_type_implement_copy<'tcx>(
_ => return Err(CopyImplementationError::NotAnAdt),
};
+ let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
+
let mut infringing = Vec::new();
for variant in adt.variants() {
for field in &variant.fields {
- let ty = field.ty(tcx, substs);
- if ty.references_error() {
+ // Do this per-field to get better error messages.
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = traits::ObligationCtxt::new(&infcx);
+
+ let unnormalized_ty = field.ty(tcx, substs);
+ if unnormalized_ty.references_error() {
continue;
}
- let span = tcx.def_span(field.did);
+
+ let field_span = tcx.def_span(field.did);
+ let field_ty_span = match tcx.hir().get_if_local(field.did) {
+ Some(hir::Node::Field(field_def)) => field_def.ty.span,
+ _ => field_span,
+ };
+
// FIXME(compiler-errors): This gives us better spans for bad
// projection types like in issue-50480.
// If the ADT has substs, point to the cause we are given.
// If it does not, then this field probably doesn't normalize
// to begin with, and point to the bad field's span instead.
- let cause = if field
+ let normalization_cause = if field
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
.has_non_region_param()
{
parent_cause.clone()
} else {
- ObligationCause::dummy_with_span(span)
- };
- match traits::fully_normalize(&infcx, cause, param_env, ty) {
- Ok(ty) => {
- if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
- infringing.push((field, ty));
- }
- }
- Err(errors) => {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- }
+ ObligationCause::dummy_with_span(field_ty_span)
};
+ let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
+ let normalization_errors = ocx.select_where_possible();
+ if !normalization_errors.is_empty() {
+ tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
+ continue;
+ }
+
+ ocx.register_bound(
+ ObligationCause::dummy_with_span(field_ty_span),
+ param_env,
+ ty,
+ copy_def_id,
+ );
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
+ }
+
+ // Check regions assuming the self type of the impl is WF
+ let outlives_env = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(&infcx),
+ infcx.implied_bounds_tys(
+ param_env,
+ parent_cause.body_id,
+ FxIndexSet::from_iter([self_type]),
+ ),
+ );
+ infcx.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ param_env,
+ );
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
+ }
}
}
+
if !infringing.is_empty() {
return Err(CopyImplementationError::InfrigingFields(infringing));
}
+
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}