rustc_trait_selection/traits/
misc.rs1use rustc_ast::Mutability;
4use rustc_hir as hir;
5use rustc_hir::attrs::lang_items::LangItem;
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(tcx, param_env, self_type, adt, args, parent_cause, LangItem::Copy)
73 .map_err(CopyImplementationError::InfringingFields)?;
74
75 if let Some(did) = adt.destructor(tcx).map(|dtor| dtor.did) {
76 return Err(CopyImplementationError::HasDestructor(did));
77 }
78
79 if impl_safety.is_safe() && self_type.has_unsafe_fields() {
80 return Err(CopyImplementationError::HasUnsafeFields);
81 }
82
83 Ok(())
84}
85
86pub fn type_allowed_to_implement_const_param_ty<'tcx>(
93 tcx: TyCtxt<'tcx>,
94 param_env: ty::ParamEnv<'tcx>,
95 self_type: Ty<'tcx>,
96 parent_cause: ObligationCause<'tcx>,
97) -> Result<(), ConstParamTyImplementationError<'tcx>> {
98 let mut need_unstable_feature_bound = false;
99
100 let inner_tys: Vec<_> = match *self_type.kind() {
101 ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()),
106
107 ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not) => {
110 need_unstable_feature_bound = true;
111 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[inner_ty]))vec![inner_ty]
112 }
113 ty::Str => {
114 need_unstable_feature_bound = true;
115 ::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)]
116 }
117 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],
118
119 ty::Tuple(inner_tys) => inner_tys.into_iter().collect(),
121
122 ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => {
123 if !tcx.features().adt_const_params() {
124 for variant in adt.variants() {
125 if variant.is_field_list_non_exhaustive() {
126 let attr_span = match {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(variant.def_id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(hir::attrs::AttributeKind::NonExhaustive(span))
=> {
break 'done Some(*span);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}hir::find_attr!(tcx, variant.def_id, hir::attrs::AttributeKind::NonExhaustive(span) => *span)
127 {
128 Some(sp) => sp,
129 None => ::rustc_middle::util::bug::bug_fmt(format_args!("non_exhaustive variant missing NonExhaustive attribute"))bug!("non_exhaustive variant missing NonExhaustive attribute"),
130 };
131 return Err(ConstParamTyImplementationError::NonExhaustive(attr_span));
132 }
133 }
134 }
135
136 all_fields_implement_trait(
137 tcx,
138 param_env,
139 self_type,
140 adt,
141 args,
142 parent_cause.clone(),
143 LangItem::ConstParamTy,
144 )
145 .map_err(ConstParamTyImplementationError::InfrigingFields)?;
146
147 ::alloc::vec::Vec::new()vec![]
148 }
149
150 _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
151 };
152
153 let mut infringing_inner_tys = ::alloc::vec::Vec::new()vec![];
154 for inner_ty in inner_tys {
155 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
157 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
158
159 if need_unstable_feature_bound {
161 ocx.register_obligation(Obligation::new(
162 tcx,
163 parent_cause.clone(),
164 param_env,
165 ty::ClauseKind::UnstableFeature(sym::unsized_const_params),
166 ));
167
168 if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() {
169 return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired);
170 }
171 }
172
173 ocx.register_bound(
174 parent_cause.clone(),
175 param_env,
176 inner_ty,
177 tcx.require_lang_item(LangItem::ConstParamTy, parent_cause.span),
178 );
179
180 let errors = ocx.evaluate_obligations_error_on_ambiguity();
181 if let TraitErrors::HasErrors(errors) = errors {
182 infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors)));
183 continue;
184 }
185
186 let errors = infcx.resolve_regions(parent_cause.body_def_id, param_env, [self_type]);
188 if !errors.is_empty() {
189 infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
190 continue;
191 }
192 }
193
194 if !infringing_inner_tys.is_empty() {
195 return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(
196 infringing_inner_tys,
197 ));
198 }
199
200 Ok(())
201}
202
203pub fn all_fields_implement_trait<'tcx>(
205 tcx: TyCtxt<'tcx>,
206 param_env: ty::ParamEnv<'tcx>,
207 self_type: Ty<'tcx>,
208 adt: AdtDef<'tcx>,
209 args: ty::GenericArgsRef<'tcx>,
210 parent_cause: ObligationCause<'tcx>,
211 lang_item: LangItem,
212) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
213 let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span);
214
215 let mut infringing = Vec::new();
216 for variant in adt.variants() {
217 for field in &variant.fields {
218 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
220 let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
221
222 let unnormalized_ty = field.ty(tcx, args);
223 if unnormalized_ty.references_error() {
224 continue;
225 }
226
227 let field_span = tcx.def_span(field.did);
228 let field_ty_span = match tcx.hir_get_if_local(field.did) {
229 Some(hir::Node::Field(field_def)) => field_def.ty.span,
230 _ => field_span,
231 };
232
233 let normalization_cause = if field
239 .ty(tcx, traits::GenericArgs::identity_for_item(tcx, adt.did()))
240 .has_non_region_param()
241 {
242 parent_cause.clone()
243 } else {
244 ObligationCause::dummy_with_span(field_ty_span)
245 };
246 let ty: Ty<'_> = ocx.normalize(&normalization_cause, param_env, unnormalized_ty);
247 let normalization_errors = ocx.try_evaluate_obligations();
248
249 if !normalization_errors.no_errors() || ty.references_error() {
254 tcx.dcx().span_delayed_bug(
255 field_span,
256 ::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!(
257 "couldn't normalize struct field `{ty}` when checking {tr} implementation",
258 tr = tcx.def_path_str(trait_def_id)
259 ),
260 );
261 continue;
262 }
263
264 ocx.register_bound(
265 ObligationCause::dummy_with_span(field_ty_span),
266 param_env,
267 ty,
268 trait_def_id,
269 );
270 let errors = ocx.evaluate_obligations_error_on_ambiguity();
271 if let TraitErrors::HasErrors(errors) = errors {
272 infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors)));
273 }
274
275 let errors = infcx.resolve_regions(parent_cause.body_def_id, param_env, [self_type]);
277 if !errors.is_empty() {
278 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
279 }
280 }
281 }
282
283 if infringing.is_empty() { Ok(()) } else { Err(infringing) }
284}