//! 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_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::traits::error_reporting::InferCtxtExt; #[derive(Clone)] pub enum CopyImplementationError<'tcx> { InfrigingFields(Vec<&'tcx ty::FieldDef>), NotAnAdt, HasDestructor, } pub fn can_type_implement_copy( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { 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) => return Ok(()), ty::Adt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), }; 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() { continue; } let span = tcx.def_span(field.did); let cause = ObligationCause::dummy_with_span(span); let ctx = traits::FulfillmentContext::new(); match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { infringing.push(field); } } Err(errors) => { infcx.report_fulfillment_errors(&errors, None, false); } }; } } if !infringing.is_empty() { return Err(CopyImplementationError::InfrigingFields(infringing)); } if adt.has_dtor(tcx) { return Err(CopyImplementationError::HasDestructor); } Ok(()) }) }