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