]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/misc.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / misc.rs
CommitLineData
74b04a01
XL
1//! Miscellaneous type-system utilities that are too small to deserve their own modules.
2
9ffffee4 3use crate::traits::{self, ObligationCause, ObligationCtxt};
74b04a01 4
49aad941 5use hir::LangItem;
9c376795 6use rustc_data_structures::fx::FxIndexSet;
74b04a01 7use rustc_hir as hir;
9ffffee4 8use rustc_infer::infer::canonical::Canonical;
9c376795 9use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
9ffffee4 10use rustc_infer::traits::query::NoSolution;
9c376795 11use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
4b012472 12use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt};
9ffffee4 13use rustc_span::DUMMY_SP;
ba9703b0 14
9c376795 15use super::outlives_bounds::InferCtxtExt;
74b04a01 16
74b04a01 17pub enum CopyImplementationError<'tcx> {
49aad941 18 InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
74b04a01
XL
19 NotAnAdt,
20 HasDestructor,
21}
22
49aad941
FG
23pub enum ConstParamTyImplementationError<'tcx> {
24 InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
25 NotAnAdtOrBuiltinAllowed,
26}
27
9c376795
FG
28pub enum InfringingFieldsReason<'tcx> {
29 Fulfill(Vec<FulfillmentError<'tcx>>),
30 Regions(Vec<RegionResolutionError<'tcx>>),
31}
32
33/// Checks that the fields of the type (an ADT) all implement copy.
34///
35/// If fields don't implement copy, return an error containing a list of
49aad941
FG
36/// those violating fields.
37///
38/// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
39/// a reference or an array returns `Err(NotAnAdt)`.
9c376795 40pub fn type_allowed_to_implement_copy<'tcx>(
74b04a01
XL
41 tcx: TyCtxt<'tcx>,
42 param_env: ty::ParamEnv<'tcx>,
43 self_type: Ty<'tcx>,
923072b8 44 parent_cause: ObligationCause<'tcx>,
74b04a01 45) -> Result<(), CopyImplementationError<'tcx>> {
add651ee 46 let (adt, args) = match self_type.kind() {
2b03887a
FG
47 // These types used to have a builtin impl.
48 // Now libcore provides that impl.
49 ty::Uint(_)
50 | ty::Int(_)
51 | ty::Bool
52 | ty::Float(_)
53 | ty::Char
54 | ty::RawPtr(..)
55 | ty::Never
56 | ty::Ref(_, _, hir::Mutability::Not)
57 | ty::Array(..) => return Ok(()),
74b04a01 58
add651ee 59 &ty::Adt(adt, args) => (adt, args),
74b04a01 60
2b03887a
FG
61 _ => return Err(CopyImplementationError::NotAnAdt),
62 };
74b04a01 63
49aad941
FG
64 all_fields_implement_trait(
65 tcx,
66 param_env,
67 self_type,
68 adt,
add651ee 69 args,
49aad941
FG
70 parent_cause,
71 hir::LangItem::Copy,
72 )
73 .map_err(CopyImplementationError::InfringingFields)?;
74
75 if adt.has_dtor(tcx) {
76 return Err(CopyImplementationError::HasDestructor);
77 }
78
79 Ok(())
80}
81
82/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
83///
84/// If fields don't implement `ConstParamTy`, return an error containing a list of
85/// those violating fields.
86///
87/// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`.
88pub fn type_allowed_to_implement_const_param_ty<'tcx>(
89 tcx: TyCtxt<'tcx>,
90 param_env: ty::ParamEnv<'tcx>,
91 self_type: Ty<'tcx>,
92 parent_cause: ObligationCause<'tcx>,
93) -> Result<(), ConstParamTyImplementationError<'tcx>> {
add651ee 94 let (adt, args) = match self_type.kind() {
49aad941
FG
95 // `core` provides these impls.
96 ty::Uint(_)
97 | ty::Int(_)
98 | ty::Bool
99 | ty::Char
100 | ty::Str
101 | ty::Array(..)
102 | ty::Slice(_)
fe692bf9
FG
103 | ty::Ref(.., hir::Mutability::Not)
104 | ty::Tuple(_) => return Ok(()),
49aad941 105
add651ee 106 &ty::Adt(adt, args) => (adt, args),
49aad941
FG
107
108 _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
109 };
110
111 all_fields_implement_trait(
112 tcx,
113 param_env,
114 self_type,
115 adt,
add651ee 116 args,
49aad941
FG
117 parent_cause,
118 hir::LangItem::ConstParamTy,
119 )
120 .map_err(ConstParamTyImplementationError::InfrigingFields)?;
121
122 Ok(())
123}
124
125/// Check that all fields of a given `adt` implement `lang_item` trait.
126pub fn all_fields_implement_trait<'tcx>(
127 tcx: TyCtxt<'tcx>,
128 param_env: ty::ParamEnv<'tcx>,
129 self_type: Ty<'tcx>,
130 adt: AdtDef<'tcx>,
add651ee 131 args: &'tcx List<GenericArg<'tcx>>,
49aad941
FG
132 parent_cause: ObligationCause<'tcx>,
133 lang_item: LangItem,
134) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
135 let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span));
9c376795 136
2b03887a
FG
137 let mut infringing = Vec::new();
138 for variant in adt.variants() {
139 for field in &variant.fields {
9c376795
FG
140 // Do this per-field to get better error messages.
141 let infcx = tcx.infer_ctxt().build();
142 let ocx = traits::ObligationCtxt::new(&infcx);
143
add651ee 144 let unnormalized_ty = field.ty(tcx, args);
9c376795 145 if unnormalized_ty.references_error() {
2b03887a 146 continue;
74b04a01 147 }
9c376795
FG
148
149 let field_span = tcx.def_span(field.did);
150 let field_ty_span = match tcx.hir().get_if_local(field.did) {
151 Some(hir::Node::Field(field_def)) => field_def.ty.span,
152 _ => field_span,
153 };
154
2b03887a
FG
155 // FIXME(compiler-errors): This gives us better spans for bad
156 // projection types like in issue-50480.
add651ee 157 // If the ADT has args, point to the cause we are given.
2b03887a
FG
158 // If it does not, then this field probably doesn't normalize
159 // to begin with, and point to the bad field's span instead.
9c376795 160 let normalization_cause = if field
add651ee 161 .ty(tcx, traits::GenericArgs::identity_for_item(tcx, adt.did()))
2b03887a
FG
162 .has_non_region_param()
163 {
164 parent_cause.clone()
165 } else {
9c376795 166 ObligationCause::dummy_with_span(field_ty_span)
2b03887a 167 };
9c376795
FG
168 let ty = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
169 let normalization_errors = ocx.select_where_possible();
353b0b11
FG
170
171 // NOTE: The post-normalization type may also reference errors,
172 // such as when we project to a missing type or we have a mismatch
173 // between expected and found const-generic types. Don't report an
174 // additional copy error here, since it's not typically useful.
175 if !normalization_errors.is_empty() || ty.references_error() {
4b012472 176 tcx.sess.span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
9c376795
FG
177 continue;
178 }
179
180 ocx.register_bound(
181 ObligationCause::dummy_with_span(field_ty_span),
182 param_env,
183 ty,
49aad941 184 trait_def_id,
9c376795
FG
185 );
186 let errors = ocx.select_all_or_error();
187 if !errors.is_empty() {
188 infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
189 }
190
191 // Check regions assuming the self type of the impl is WF
192 let outlives_env = OutlivesEnvironment::with_bounds(
193 param_env,
9c376795
FG
194 infcx.implied_bounds_tys(
195 param_env,
196 parent_cause.body_id,
197 FxIndexSet::from_iter([self_type]),
198 ),
199 );
9c376795
FG
200 let errors = infcx.resolve_regions(&outlives_env);
201 if !errors.is_empty() {
202 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
203 }
74b04a01 204 }
2b03887a 205 }
9c376795 206
49aad941 207 if infringing.is_empty() { Ok(()) } else { Err(infringing) }
74b04a01 208}
9ffffee4
FG
209
210pub fn check_tys_might_be_eq<'tcx>(
211 tcx: TyCtxt<'tcx>,
4b012472 212 canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>,
9ffffee4 213) -> Result<(), NoSolution> {
4b012472
FG
214 let (infcx, key, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
215 let (param_env, (ty_a, ty_b)) = key.into_parts();
9ffffee4
FG
216 let ocx = ObligationCtxt::new(&infcx);
217
218 let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b);
219 // use `select_where_possible` instead of `select_all_or_error` so that
220 // we don't get errors from obligations being ambiguous.
221 let errors = ocx.select_where_possible();
222
223 if errors.len() > 0 || result.is_err() { Err(NoSolution) } else { Ok(()) }
224}