1 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
3 use crate::infer::InferCtxtExt as _;
4 use crate::traits::{self, ObligationCause};
7 use rustc_infer::infer::TyCtxtInferExt;
8 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
10 use crate::traits::error_reporting::TypeErrCtxtExt;
13 pub enum CopyImplementationError<'tcx> {
14 InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
19 pub fn can_type_implement_copy<'tcx>(
21 param_env: ty::ParamEnv<'tcx>,
23 parent_cause: ObligationCause<'tcx>,
24 ) -> Result<(), CopyImplementationError<'tcx>> {
25 // FIXME: (@jroesch) float this code up
26 let infcx = tcx.infer_ctxt().build();
27 let (adt, substs) = match self_type.kind() {
28 // These types used to have a builtin impl.
29 // Now libcore provides that impl.
37 | ty::Ref(_, _, hir::Mutability::Not)
38 | ty::Array(..) => return Ok(()),
40 ty::Adt(adt, substs) => (adt, substs),
42 _ => return Err(CopyImplementationError::NotAnAdt),
45 let mut infringing = Vec::new();
46 for variant in adt.variants() {
47 for field in &variant.fields {
48 let ty = field.ty(tcx, substs);
49 if ty.references_error() {
52 let span = tcx.def_span(field.did);
53 // FIXME(compiler-errors): This gives us better spans for bad
54 // projection types like in issue-50480.
55 // If the ADT has substs, point to the cause we are given.
56 // If it does not, then this field probably doesn't normalize
57 // to begin with, and point to the bad field's span instead.
59 .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
60 .has_non_region_param()
64 ObligationCause::dummy_with_span(span)
66 match traits::fully_normalize(&infcx, cause, param_env, ty) {
68 if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
69 infringing.push((field, ty));
73 infcx.err_ctxt().report_fulfillment_errors(&errors, None);
78 if !infringing.is_empty() {
79 return Err(CopyImplementationError::InfrigingFields(infringing));
81 if adt.has_dtor(tcx) {
82 return Err(CopyImplementationError::HasDestructor);