]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | //! Miscellaneous type-system utilities that are too small to deserve their own modules. |
2 | ||
ba9703b0 | 3 | use crate::infer::InferCtxtExt as _; |
74b04a01 XL |
4 | use crate::traits::{self, ObligationCause}; |
5 | ||
74b04a01 | 6 | use rustc_hir as hir; |
ba9703b0 | 7 | use rustc_infer::infer::TyCtxtInferExt; |
064997fb | 8 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; |
ba9703b0 | 9 | |
2b03887a | 10 | use crate::traits::error_reporting::TypeErrCtxtExt; |
74b04a01 XL |
11 | |
12 | #[derive(Clone)] | |
13 | pub enum CopyImplementationError<'tcx> { | |
5e7ed085 | 14 | InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>), |
74b04a01 XL |
15 | NotAnAdt, |
16 | HasDestructor, | |
17 | } | |
18 | ||
a2a8927a | 19 | pub fn can_type_implement_copy<'tcx>( |
74b04a01 XL |
20 | tcx: TyCtxt<'tcx>, |
21 | param_env: ty::ParamEnv<'tcx>, | |
22 | self_type: Ty<'tcx>, | |
923072b8 | 23 | parent_cause: ObligationCause<'tcx>, |
74b04a01 XL |
24 | ) -> Result<(), CopyImplementationError<'tcx>> { |
25 | // FIXME: (@jroesch) float this code up | |
2b03887a FG |
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. | |
30 | ty::Uint(_) | |
31 | | ty::Int(_) | |
32 | | ty::Bool | |
33 | | ty::Float(_) | |
34 | | ty::Char | |
35 | | ty::RawPtr(..) | |
36 | | ty::Never | |
37 | | ty::Ref(_, _, hir::Mutability::Not) | |
38 | | ty::Array(..) => return Ok(()), | |
74b04a01 | 39 | |
2b03887a | 40 | ty::Adt(adt, substs) => (adt, substs), |
74b04a01 | 41 | |
2b03887a FG |
42 | _ => return Err(CopyImplementationError::NotAnAdt), |
43 | }; | |
74b04a01 | 44 | |
2b03887a FG |
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() { | |
50 | continue; | |
74b04a01 | 51 | } |
2b03887a FG |
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. | |
58 | let cause = if field | |
59 | .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did())) | |
60 | .has_non_region_param() | |
61 | { | |
62 | parent_cause.clone() | |
63 | } else { | |
64 | ObligationCause::dummy_with_span(span) | |
65 | }; | |
66 | match traits::fully_normalize(&infcx, cause, param_env, ty) { | |
67 | Ok(ty) => { | |
68 | if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { | |
69 | infringing.push((field, ty)); | |
70 | } | |
71 | } | |
72 | Err(errors) => { | |
73 | infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); | |
74 | } | |
75 | }; | |
74b04a01 | 76 | } |
2b03887a FG |
77 | } |
78 | if !infringing.is_empty() { | |
79 | return Err(CopyImplementationError::InfrigingFields(infringing)); | |
80 | } | |
81 | if adt.has_dtor(tcx) { | |
82 | return Err(CopyImplementationError::HasDestructor); | |
83 | } | |
74b04a01 | 84 | |
2b03887a | 85 | Ok(()) |
74b04a01 | 86 | } |