]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/misc.rs
Rollup merge of #107424 - bpeel:clone-into-from-share-code, r=scottmcm
[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::traits::{self, ObligationCause};
4
5 use rustc_data_structures::fx::FxIndexSet;
6 use rustc_hir as hir;
7 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
8 use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
9 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
10
11 use super::outlives_bounds::InferCtxtExt;
12
13 pub enum CopyImplementationError<'tcx> {
14     InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
15     NotAnAdt,
16     HasDestructor,
17 }
18
19 pub enum InfringingFieldsReason<'tcx> {
20     Fulfill(Vec<FulfillmentError<'tcx>>),
21     Regions(Vec<RegionResolutionError<'tcx>>),
22 }
23
24 /// Checks that the fields of the type (an ADT) all implement copy.
25 ///
26 /// If fields don't implement copy, return an error containing a list of
27 /// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
28 pub fn type_allowed_to_implement_copy<'tcx>(
29     tcx: TyCtxt<'tcx>,
30     param_env: ty::ParamEnv<'tcx>,
31     self_type: Ty<'tcx>,
32     parent_cause: ObligationCause<'tcx>,
33 ) -> Result<(), CopyImplementationError<'tcx>> {
34     let (adt, substs) = match self_type.kind() {
35         // These types used to have a builtin impl.
36         // Now libcore provides that impl.
37         ty::Uint(_)
38         | ty::Int(_)
39         | ty::Bool
40         | ty::Float(_)
41         | ty::Char
42         | ty::RawPtr(..)
43         | ty::Never
44         | ty::Ref(_, _, hir::Mutability::Not)
45         | ty::Array(..) => return Ok(()),
46
47         ty::Adt(adt, substs) => (adt, substs),
48
49         _ => return Err(CopyImplementationError::NotAnAdt),
50     };
51
52     let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
53
54     let mut infringing = Vec::new();
55     for variant in adt.variants() {
56         for field in &variant.fields {
57             // Do this per-field to get better error messages.
58             let infcx = tcx.infer_ctxt().build();
59             let ocx = traits::ObligationCtxt::new(&infcx);
60
61             let unnormalized_ty = field.ty(tcx, substs);
62             if unnormalized_ty.references_error() {
63                 continue;
64             }
65
66             let field_span = tcx.def_span(field.did);
67             let field_ty_span = match tcx.hir().get_if_local(field.did) {
68                 Some(hir::Node::Field(field_def)) => field_def.ty.span,
69                 _ => field_span,
70             };
71
72             // FIXME(compiler-errors): This gives us better spans for bad
73             // projection types like in issue-50480.
74             // If the ADT has substs, point to the cause we are given.
75             // If it does not, then this field probably doesn't normalize
76             // to begin with, and point to the bad field's span instead.
77             let normalization_cause = if field
78                 .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
79                 .has_non_region_param()
80             {
81                 parent_cause.clone()
82             } else {
83                 ObligationCause::dummy_with_span(field_ty_span)
84             };
85             let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
86             let normalization_errors = ocx.select_where_possible();
87             if !normalization_errors.is_empty() {
88                 tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
89                 continue;
90             }
91
92             ocx.register_bound(
93                 ObligationCause::dummy_with_span(field_ty_span),
94                 param_env,
95                 ty,
96                 copy_def_id,
97             );
98             let errors = ocx.select_all_or_error();
99             if !errors.is_empty() {
100                 infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
101             }
102
103             // Check regions assuming the self type of the impl is WF
104             let outlives_env = OutlivesEnvironment::with_bounds(
105                 param_env,
106                 Some(&infcx),
107                 infcx.implied_bounds_tys(
108                     param_env,
109                     parent_cause.body_id,
110                     FxIndexSet::from_iter([self_type]),
111                 ),
112             );
113             infcx.process_registered_region_obligations(
114                 outlives_env.region_bound_pairs(),
115                 param_env,
116             );
117             let errors = infcx.resolve_regions(&outlives_env);
118             if !errors.is_empty() {
119                 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
120             }
121         }
122     }
123
124     if !infringing.is_empty() {
125         return Err(CopyImplementationError::InfrigingFields(infringing));
126     }
127
128     if adt.has_dtor(tcx) {
129         return Err(CopyImplementationError::HasDestructor);
130     }
131
132     Ok(())
133 }