]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/misc.rs
Auto merge of #102025 - chenyukang:fix-102002, r=jyn514
[rust.git] / compiler / rustc_trait_selection / src / traits / misc.rs
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, TypeVisitable};
9
10 use crate::traits::error_reporting::InferCtxtExt;
11
12 #[derive(Clone)]
13 pub enum CopyImplementationError<'tcx> {
14     InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
15     NotAnAdt,
16     HasDestructor,
17 }
18
19 pub fn can_type_implement_copy<'tcx>(
20     tcx: TyCtxt<'tcx>,
21     param_env: ty::ParamEnv<'tcx>,
22     self_type: Ty<'tcx>,
23     parent_cause: ObligationCause<'tcx>,
24 ) -> Result<(), CopyImplementationError<'tcx>> {
25     // FIXME: (@jroesch) float this code up
26     tcx.infer_ctxt().enter(|infcx| {
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(()),
39
40             ty::Adt(adt, substs) => (adt, substs),
41
42             _ => return Err(CopyImplementationError::NotAnAdt),
43         };
44
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;
51                 }
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.report_fulfillment_errors(&errors, None, false);
74                     }
75                 };
76             }
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         }
84
85         Ok(())
86     })
87 }