diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/misc.rs')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/misc.rs | 74 | 
1 files changed, 74 insertions, 0 deletions
| diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs new file mode 100644 index 00000000000..61567aeb57c --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -0,0 +1,74 @@ +//! 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(()) + }) +} | 
