]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/traits/misc.rs
Auto merge of #67953 - cjgillot:split_infer, r=Zoxc
[rust.git] / src / librustc_infer / traits / misc.rs
1 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
2
3 use crate::infer::TyCtxtInferExt;
4 use crate::traits::{self, ObligationCause};
5
6 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
7 use rustc_hir as hir;
8
9 #[derive(Clone)]
10 pub enum CopyImplementationError<'tcx> {
11     InfrigingFields(Vec<&'tcx ty::FieldDef>),
12     NotAnAdt,
13     HasDestructor,
14 }
15
16 pub fn can_type_implement_copy(
17     tcx: TyCtxt<'tcx>,
18     param_env: ty::ParamEnv<'tcx>,
19     self_type: Ty<'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.
26             ty::Uint(_)
27             | ty::Int(_)
28             | ty::Bool
29             | ty::Float(_)
30             | ty::Char
31             | ty::RawPtr(..)
32             | ty::Never
33             | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
34
35             ty::Adt(adt, substs) => (adt, substs),
36
37             _ => return Err(CopyImplementationError::NotAnAdt),
38         };
39
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() {
45                     continue;
46                 }
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) {
51                     Ok(ty) => {
52                         if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
53                             infringing.push(field);
54                         }
55                     }
56                     Err(errors) => {
57                         infcx.report_fulfillment_errors(&errors, None, false);
58                     }
59                 };
60             }
61         }
62         if !infringing.is_empty() {
63             return Err(CopyImplementationError::InfrigingFields(infringing));
64         }
65         if adt.has_dtor(tcx) {
66             return Err(CopyImplementationError::HasDestructor);
67         }
68
69         Ok(())
70     })
71 }