rustc_trait_selection/traits/
misc.rs1use hir::LangItem;
4use rustc_ast::Mutability;
5use rustc_hir as hir;
6use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
7use rustc_middle::bug;
8use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized};
9use rustc_span::{Span, sym};
10
11use crate::regions::InferCtxtRegionExt;
12use crate::traits::{self, FulfillmentError, Obligation, ObligationCause};
13
14pub enum CopyImplementationError<'tcx> {
15 InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
16 NotAnAdt,
17 HasDestructor(hir::def_id::DefId),
18 HasUnsafeFields,
19}
20
21pub enum ConstParamTyImplementationError<'tcx> {
22 UnsizedConstParamsFeatureRequired,
23 InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
24 InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
25 NotAnAdtOrBuiltinAllowed,
26 NonExhaustive(Span),
27}
28
29pub enum InfringingFieldsReason<'tcx> {
30 Fulfill(Vec<FulfillmentError<'tcx>>),
31 Regions(Vec<RegionResolutionError<'tcx>>),
32}
33
34pub fn type_allowed_to_implement_copy<'tcx>(
46 tcx: TyCtxt<'tcx>,
47 param_env: ty::ParamEnv<'tcx>,
48 self_type: Ty<'tcx>,
49 parent_cause: ObligationCause<'tcx>,
50 impl_safety: hir::Safety,
51) -> Result<(), CopyImplementationError<'tcx>> {
52 let (adt, args) = match self_type.kind() {
53 ty::Uint(_)
56 | ty::Int(_)
57 | ty::Bool
58 | ty::Float(_)
59 | ty::Char
60 | ty::RawPtr(..)
61 | ty::Never
62 | ty::Ref(_, _, hir::Mutability::Not)
63 | ty::Array(..) => return Ok(()),
64
65 &ty::Adt(adt, args) => (adt, args),
66
67 _ => return Err(CopyImplementationError::NotAnAdt),
68 };
69
70 all_fields_implement_trait(
71 tcx,
72 param_env,
73 self_type,
74 adt,
75 args,
76 parent_cause,
77 hir::LangItem::Copy,
78 )
79 .map_err(CopyImplementationError::InfringingFields)?;
80
81 if let Some(did) = adt.destructor(tcx).map(|dtor| dtor.did) {
82 return Err(CopyImplementationError::HasDestructor(did));
83 }
84
85 if impl_safety.is_safe() && self_type.has_unsafe_fields() {
86 return Err(CopyImplementationError::HasUnsafeFields);
87 }
88
89 Ok(())
90}
91
92pub fn type_allowed_to_implement_const_param_ty<'tcx>(
99 tcx: TyCtxt<'tcx>,
100 param_env: ty::ParamEnv<'tcx>,
101 self_type: Ty<'tcx>,
102 parent_cause: ObligationCause<'tcx>,
103) -> Result<(), ConstParamTyImplementationError<'tcx>> {
104 let mut need_unstable_feature_bound = false;
105
106 let inner_tys: Vec<_> = match *self_type.kind() {
107 ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
112
113 ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not) => {
116 need_unstable_feature_bound = true;
117 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[inner_ty]))vec![inner_ty]
118 }
119 ty::Str => {
120 need_unstable_feature_bound = true;
121 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Ty::new_slice(tcx, tcx.types.u8)]))vec![Ty::new_slice(tcx, tcx.types.u8)]
122 }
123 ty::Array(inner_ty, _) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[inner_ty]))vec![inner_ty],
124
125 ty::Tuple(inner_tys) => inner_tys.into_iter().collect(),
127
128 ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => {
129 if !tcx.features().adt_const_params() {
130 for variant in adt.variants() {
131 if variant.is_field_list_non_exhaustive() {
132 let attr_span = match {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(variant.def_id, &tcx)
{
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(hir::attrs::AttributeKind::NonExhaustive(span))
=> {
break 'done Some(*span);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}hir::find_attr!(tcx, variant.def_id, hir::attrs::AttributeKind::NonExhaustive(span) => *span)
133 {
134 Some(sp) => sp,
135 None => ::rustc_middle::util::bug::bug_fmt(format_args!("non_exhaustive variant missing NonExhaustive attribute"))bug!("non_exhaustive variant missing NonExhaustive attribute"),
136 };
137 return Err(ConstParamTyImplementationError::NonExhaustive(attr_span));
138 }
139 }
140 }
141
142 all_fields_implement_trait(
143 tcx,
144 param_env,
145 self_type,
146 adt,
147 args,
148 parent_cause.clone(),
149 LangItem::ConstParamTy,
150 )
151 .map_err(ConstParamTyImplementationError::InfrigingFields)?;
152
153 ::alloc::vec::Vec::new()vec![]
154 }
155
156 _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
157 };
158
159 let mut infringing_inner_tys = ::alloc::vec::Vec::new()vec![];
160 for inner_ty in inner_tys {
161 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
163 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
164
165 if need_unstable_feature_bound {
167 ocx.register_obligation(Obligation::new(
168 tcx,
169 parent_cause.clone(),
170 param_env,
171 ty::ClauseKind::UnstableFeature(sym::unsized_const_params),
172 ));
173
174 if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
175 return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired);
176 }
177 }
178
179 ocx.register_bound(
180 parent_cause.clone(),
181 param_env,
182 inner_ty,
183 tcx.require_lang_item(LangItem::ConstParamTy, parent_cause.span),
184 );
185
186 let errors = ocx.evaluate_obligations_error_on_ambiguity();
187 if !errors.is_empty() {
188 infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors)));
189 continue;
190 }
191
192 let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]);
194 if !errors.is_empty() {
195 infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
196 continue;
197 }
198 }
199
200 if !infringing_inner_tys.is_empty() {
201 return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(
202 infringing_inner_tys,
203 ));
204 }
205
206 Ok(())
207}
208
209pub fn all_fields_implement_trait<'tcx>(
211 tcx: TyCtxt<'tcx>,
212 param_env: ty::ParamEnv<'tcx>,
213 self_type: Ty<'tcx>,
214 adt: AdtDef<'tcx>,
215 args: ty::GenericArgsRef<'tcx>,
216 parent_cause: ObligationCause<'tcx>,
217 lang_item: LangItem,
218) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
219 let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span);
220
221 let mut infringing = Vec::new();
222 for variant in adt.variants() {
223 for field in &variant.fields {
224 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
226 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
227
228 let unnormalized_ty = field.ty(tcx, args);
229 if unnormalized_ty.references_error() {
230 continue;
231 }
232
233 let field_span = tcx.def_span(field.did);
234 let field_ty_span = match tcx.hir_get_if_local(field.did) {
235 Some(hir::Node::Field(field_def)) => field_def.ty.span,
236 _ => field_span,
237 };
238
239 let normalization_cause = if field
245 .ty(tcx, traits::GenericArgs::identity_for_item(tcx, adt.did()))
246 .has_non_region_param()
247 {
248 parent_cause.clone()
249 } else {
250 ObligationCause::dummy_with_span(field_ty_span)
251 };
252 let ty = ocx.normalize(
253 &normalization_cause,
254 param_env,
255 Unnormalized::new_wip(unnormalized_ty),
256 );
257 let normalization_errors = ocx.try_evaluate_obligations();
258
259 if !normalization_errors.is_empty() || ty.references_error() {
264 tcx.dcx().span_delayed_bug(field_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("couldn\'t normalize struct field `{1}` when checking {0} implementation",
tcx.def_path_str(trait_def_id), unnormalized_ty))
})format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
265 continue;
266 }
267
268 ocx.register_bound(
269 ObligationCause::dummy_with_span(field_ty_span),
270 param_env,
271 ty,
272 trait_def_id,
273 );
274 let errors = ocx.evaluate_obligations_error_on_ambiguity();
275 if !errors.is_empty() {
276 infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
277 }
278
279 let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]);
281 if !errors.is_empty() {
282 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
283 }
284 }
285 }
286
287 if infringing.is_empty() { Ok(()) } else { Err(infringing) }
288}