1 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
3 use crate::infer::TyCtxtInferExt;
4 use crate::traits::{self, ObligationCause};
6 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
10 pub enum CopyImplementationError<'tcx> {
11 InfrigingFields(Vec<&'tcx ty::FieldDef>),
16 pub fn can_type_implement_copy(
18 param_env: ty::ParamEnv<'tcx>,
20 ) -> Result<(), CopyImplementationError<'tcx>> {
21 // FIXME: (@jroesch) float this code up
22 tcx.infer_ctxt().enter(|infcx| {
23 let (adt, substs) = match self_type.kind {
24 // These types used to have a builtin impl.
25 // Now libcore provides that impl.
33 | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
35 ty::Adt(adt, substs) => (adt, substs),
37 _ => return Err(CopyImplementationError::NotAnAdt),
40 let mut infringing = Vec::new();
41 for variant in &adt.variants {
42 for field in &variant.fields {
43 let ty = field.ty(tcx, substs);
44 if ty.references_error() {
47 let span = tcx.def_span(field.did);
48 let cause = ObligationCause { span, ..ObligationCause::dummy() };
49 let ctx = traits::FulfillmentContext::new();
50 match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
52 if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
53 infringing.push(field);
57 infcx.report_fulfillment_errors(&errors, None, false);
62 if !infringing.is_empty() {
63 return Err(CopyImplementationError::InfrigingFields(infringing));
65 if adt.has_dtor(tcx) {
66 return Err(CopyImplementationError::HasDestructor);