]>
Commit | Line | Data |
---|---|---|
1 | //! Miscellaneous type-system utilities that are too small to deserve their own modules. | |
2 | ||
3 | use crate::infer::InferCtxtExt as _; | |
4 | use crate::traits::{self, ObligationCause}; | |
5 | ||
6 | use rustc_hir as hir; | |
7 | use rustc_infer::infer::TyCtxtInferExt; | |
8 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; | |
9 | ||
10 | use crate::traits::error_reporting::InferCtxtExt; | |
11 | ||
12 | #[derive(Clone)] | |
13 | pub enum CopyImplementationError<'tcx> { | |
14 | InfrigingFields(Vec<&'tcx ty::FieldDef>), | |
15 | NotAnAdt, | |
16 | HasDestructor, | |
17 | } | |
18 | ||
19 | pub fn can_type_implement_copy( | |
20 | tcx: TyCtxt<'tcx>, | |
21 | param_env: ty::ParamEnv<'tcx>, | |
22 | self_type: Ty<'tcx>, | |
23 | ) -> Result<(), CopyImplementationError<'tcx>> { | |
24 | // FIXME: (@jroesch) float this code up | |
25 | tcx.infer_ctxt().enter(|infcx| { | |
26 | let (adt, substs) = match self_type.kind { | |
27 | // These types used to have a builtin impl. | |
28 | // Now libcore provides that impl. | |
29 | ty::Uint(_) | |
30 | | ty::Int(_) | |
31 | | ty::Bool | |
32 | | ty::Float(_) | |
33 | | ty::Char | |
34 | | ty::RawPtr(..) | |
35 | | ty::Never | |
36 | | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), | |
37 | ||
38 | ty::Adt(adt, substs) => (adt, substs), | |
39 | ||
40 | _ => return Err(CopyImplementationError::NotAnAdt), | |
41 | }; | |
42 | ||
43 | let mut infringing = Vec::new(); | |
44 | for variant in &adt.variants { | |
45 | for field in &variant.fields { | |
46 | let ty = field.ty(tcx, substs); | |
47 | if ty.references_error() { | |
48 | continue; | |
49 | } | |
50 | let span = tcx.def_span(field.did); | |
51 | let cause = ObligationCause::dummy_with_span(span); | |
52 | let ctx = traits::FulfillmentContext::new(); | |
53 | match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { | |
54 | Ok(ty) => { | |
55 | if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { | |
56 | infringing.push(field); | |
57 | } | |
58 | } | |
59 | Err(errors) => { | |
60 | infcx.report_fulfillment_errors(&errors, None, false); | |
61 | } | |
62 | }; | |
63 | } | |
64 | } | |
65 | if !infringing.is_empty() { | |
66 | return Err(CopyImplementationError::InfrigingFields(infringing)); | |
67 | } | |
68 | if adt.has_dtor(tcx) { | |
69 | return Err(CopyImplementationError::HasDestructor); | |
70 | } | |
71 | ||
72 | Ok(()) | |
73 | }) | |
74 | } |