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