2020-01-05 23:43:45 +01:00
|
|
|
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
|
|
|
|
|
|
|
|
|
|
use crate::traits::{self, ObligationCause};
|
|
|
|
|
|
|
|
|
|
use rustc_hir as hir;
|
2022-11-30 20:41:02 +00:00
|
|
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
2020-02-22 11:44:18 +01:00
|
|
|
use rustc_infer::infer::TyCtxtInferExt;
|
2022-06-17 13:15:00 +01:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
|
2020-02-22 11:44:18 +01:00
|
|
|
|
2022-09-09 15:08:06 -05:00
|
|
|
use crate::traits::error_reporting::TypeErrCtxtExt;
|
2020-01-05 23:43:45 +01:00
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub enum CopyImplementationError<'tcx> {
|
2022-02-21 21:26:37 -08:00
|
|
|
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
|
2020-01-05 23:43:45 +01:00
|
|
|
NotAnAdt,
|
|
|
|
|
HasDestructor,
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 20:41:02 +00:00
|
|
|
/// 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>(
|
2020-01-05 23:43:45 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
|
self_type: Ty<'tcx>,
|
2022-06-03 19:17:12 -07:00
|
|
|
parent_cause: ObligationCause<'tcx>,
|
2020-01-05 23:43:45 +01:00
|
|
|
) -> Result<(), CopyImplementationError<'tcx>> {
|
2022-09-19 22:03:59 -05:00
|
|
|
let (adt, substs) = match self_type.kind() {
|
|
|
|
|
// These types used to have a builtin impl.
|
|
|
|
|
// Now libcore provides that impl.
|
|
|
|
|
ty::Uint(_)
|
|
|
|
|
| ty::Int(_)
|
|
|
|
|
| ty::Bool
|
|
|
|
|
| ty::Float(_)
|
|
|
|
|
| ty::Char
|
|
|
|
|
| ty::RawPtr(..)
|
|
|
|
|
| ty::Never
|
|
|
|
|
| ty::Ref(_, _, hir::Mutability::Not)
|
|
|
|
|
| ty::Array(..) => return Ok(()),
|
2020-01-05 23:43:45 +01:00
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
ty::Adt(adt, substs) => (adt, substs),
|
2020-01-05 23:43:45 +01:00
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
_ => return Err(CopyImplementationError::NotAnAdt),
|
|
|
|
|
};
|
2020-01-05 23:43:45 +01:00
|
|
|
|
2022-11-30 20:41:02 +00:00
|
|
|
let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
|
2022-09-19 22:03:59 -05:00
|
|
|
let mut infringing = Vec::new();
|
|
|
|
|
for variant in adt.variants() {
|
|
|
|
|
for field in &variant.fields {
|
2022-11-30 20:41:02 +00:00
|
|
|
// Do this per-field to get better error messages.
|
|
|
|
|
let infcx = tcx.infer_ctxt().build();
|
|
|
|
|
let ocx = traits::ObligationCtxt::new(&infcx);
|
|
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
let ty = field.ty(tcx, substs);
|
|
|
|
|
if ty.references_error() {
|
|
|
|
|
continue;
|
2020-01-05 23:43:45 +01:00
|
|
|
}
|
2022-09-19 22:03:59 -05:00
|
|
|
let span = tcx.def_span(field.did);
|
|
|
|
|
// 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
|
|
|
|
|
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
|
|
|
|
|
.has_non_region_param()
|
|
|
|
|
{
|
|
|
|
|
parent_cause.clone()
|
|
|
|
|
} else {
|
|
|
|
|
ObligationCause::dummy_with_span(span)
|
|
|
|
|
};
|
2022-11-30 20:41:02 +00:00
|
|
|
|
|
|
|
|
let ty = ocx.normalize(&cause, param_env, ty);
|
|
|
|
|
let normalization_errors = ocx.select_where_possible();
|
|
|
|
|
if !normalization_errors.is_empty() {
|
|
|
|
|
// Don't report this as a field that doesn't implement Copy,
|
|
|
|
|
// but instead just implement this as a field that isn't WF.
|
|
|
|
|
infcx.err_ctxt().report_fulfillment_errors(&normalization_errors, None);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ocx.register_bound(cause, param_env, ty, copy_def_id);
|
|
|
|
|
if !ocx.select_all_or_error().is_empty() {
|
|
|
|
|
infringing.push((field, ty));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
|
|
|
|
infcx.process_registered_region_obligations(
|
|
|
|
|
outlives_env.region_bound_pairs(),
|
|
|
|
|
param_env,
|
|
|
|
|
);
|
|
|
|
|
if !infcx.resolve_regions(&outlives_env).is_empty() {
|
|
|
|
|
infringing.push((field, ty));
|
|
|
|
|
}
|
2020-01-05 23:43:45 +01:00
|
|
|
}
|
2022-09-19 22:03:59 -05:00
|
|
|
}
|
2022-11-30 20:41:02 +00:00
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
if !infringing.is_empty() {
|
|
|
|
|
return Err(CopyImplementationError::InfrigingFields(infringing));
|
|
|
|
|
}
|
2022-11-30 20:41:02 +00:00
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
if adt.has_dtor(tcx) {
|
|
|
|
|
return Err(CopyImplementationError::HasDestructor);
|
|
|
|
|
}
|
2020-01-05 23:43:45 +01:00
|
|
|
|
2022-09-19 22:03:59 -05:00
|
|
|
Ok(())
|
2020-01-05 23:43:45 +01:00
|
|
|
}
|