1use core::ops::ControlFlow;
2
3use rustc_abi::{FieldIdx, VariantIdx};
4use rustc_apfloat::Float;
5use rustc_data_structures::fx::FxHashSet;
6use rustc_errors::Diag;
7use rustc_hir as hir;
8use rustc_hir::attrs::AttributeKind;
9use rustc_hir::find_attr;
10use rustc_index::Idx;
11use rustc_infer::infer::TyCtxtInferExt;
12use rustc_infer::traits::Obligation;
13use rustc_middle::mir::interpret::ErrorHandled;
14use rustc_middle::span_bug;
15use rustc_middle::thir::{FieldPat, Pat, PatKind};
16use rustc_middle::ty::{
17 self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree,
18};
19use rustc_span::def_id::DefId;
20use rustc_span::{DUMMY_SP, Span};
21use rustc_trait_selection::traits::ObligationCause;
22use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
23use tracing::{debug, instrument, trace};
24
25use super::PatCtxt;
26use crate::errors::{
27 ConstPatternDependsOnGenericParameter, CouldNotEvalConstPattern, InvalidPattern, NaNPattern,
28 PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern,
29};
30
31impl<'tcx> PatCtxt<'tcx> {
32 x;#[instrument(level = "debug", skip(self), ret)]
40 pub(super) fn const_to_pat(
41 &self,
42 c: ty::Const<'tcx>,
43 ty: Ty<'tcx>,
44 id: hir::HirId,
45 span: Span,
46 ) -> Box<Pat<'tcx>> {
47 let mut convert = ConstToPat::new(self, id, span, c);
48
49 match c.kind() {
50 ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
51 ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty),
52 _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
53 }
54 }
55}
56
57struct ConstToPat<'tcx> {
58 tcx: TyCtxt<'tcx>,
59 typing_env: ty::TypingEnv<'tcx>,
60 span: Span,
61 id: hir::HirId,
62
63 c: ty::Const<'tcx>,
64}
65
66impl<'tcx> ConstToPat<'tcx> {
67 fn new(pat_ctxt: &PatCtxt<'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
68 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:68",
"rustc_mir_build::thir::pattern::const_to_pat",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
::tracing_core::__macro_support::Option::Some(68u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
::tracing_core::field::FieldSet::new(&["pat_ctxt.typeck_results.hir_owner"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&pat_ctxt.typeck_results.hir_owner)
as &dyn Value))])
});
} else { ; }
};trace!(?pat_ctxt.typeck_results.hir_owner);
69 ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c }
70 }
71
72 fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
73 ty.is_structural_eq_shallow(self.tcx)
74 }
75
76 fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
78 if let ty::ConstKind::Unevaluated(uv) = self.c.kind() {
79 let def_kind = self.tcx.def_kind(uv.def);
80 if let hir::def::DefKind::AssocConst = def_kind
81 && let Some(def_id) = uv.def.as_local()
82 {
83 err.span_label(self.tcx.def_span(self.tcx.local_parent(def_id)), "");
85 }
86 if let hir::def::DefKind::Const | hir::def::DefKind::AssocConst = def_kind {
87 err.span_label(
88 self.tcx.def_span(uv.def),
89 crate::fluent_generated::mir_build_const_defined_here,
90 );
91 }
92 }
93 Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()), extra: None })
94 }
95
96 fn unevaluated_to_pat(
97 &mut self,
98 uv: ty::UnevaluatedConst<'tcx>,
99 ty: Ty<'tcx>,
100 ) -> Box<Pat<'tcx>> {
101 let typing_env = self
109 .tcx
110 .erase_and_anonymize_regions(self.typing_env)
111 .with_post_analysis_normalized(self.tcx);
112 let uv = self.tcx.erase_and_anonymize_regions(uv);
113
114 let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) {
117 Ok(Ok(c)) => c,
118 Err(ErrorHandled::Reported(_, _)) => {
119 let mut err =
121 self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
122 if let ty::ConstKind::Unevaluated(uv) = self.c.kind()
125 && let hir::def::DefKind::Const | hir::def::DefKind::AssocConst =
126 self.tcx.def_kind(uv.def)
127 {
128 err.downgrade_to_delayed_bug();
129 }
130 return self.mk_err(err, ty);
131 }
132 Err(ErrorHandled::TooGeneric(_)) => {
133 let mut e = self
134 .tcx
135 .dcx()
136 .create_err(ConstPatternDependsOnGenericParameter { span: self.span });
137 for arg in uv.args {
138 if let ty::GenericArgKind::Type(ty) = arg.kind()
139 && let ty::Param(param_ty) = ty.kind()
140 {
141 let def_id = self.tcx.hir_enclosing_body_owner(self.id);
142 let generics = self.tcx.generics_of(def_id);
143 let param = generics.type_param(*param_ty, self.tcx);
144 let span = self.tcx.def_span(param.def_id);
145 e.span_label(span, "constant depends on this generic parameter");
146 if let Some(ident) = self.tcx.def_ident_span(def_id)
147 && self.tcx.sess.source_map().is_multiline(ident.between(span))
148 {
149 e.span_label(ident, "");
152 }
153 }
154 }
155 return self.mk_err(e, ty);
156 }
157 Ok(Err(bad_ty)) => {
158 let e = match bad_ty.kind() {
160 ty::Adt(def, ..) => {
161 if !def.is_union() {
::core::panicking::panic("assertion failed: def.is_union()")
};assert!(def.is_union());
162 self.tcx.dcx().create_err(UnionPattern { span: self.span })
163 }
164 ty::FnPtr(..) | ty::RawPtr(..) => {
165 self.tcx.dcx().create_err(PointerPattern { span: self.span })
166 }
167 _ => self.tcx.dcx().create_err(InvalidPattern {
168 span: self.span,
169 non_sm_ty: bad_ty,
170 prefix: bad_ty.prefix_string(self.tcx).to_string(),
171 }),
172 };
173 return self.mk_err(e, ty);
174 }
175 };
176
177 let mut thir_pat = self.valtree_to_pat(valtree, ty);
179
180 if !thir_pat.references_error() {
181 if !type_has_partial_eq_impl(self.tcx, typing_env, ty).has_impl {
183 let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty });
184 extend_type_not_partial_eq(self.tcx, typing_env, ty, &mut err);
185 return self.mk_err(err, ty);
186 }
187 }
188
189 thir_pat.extra.get_or_insert_default().expanded_const = Some(uv.def);
192 thir_pat
193 }
194
195 fn field_pats(
196 &self,
197 vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
198 ) -> Vec<FieldPat<'tcx>> {
199 vals.enumerate()
200 .map(|(idx, (val, ty))| {
201 let field = FieldIdx::new(idx);
202 let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
204 FieldPat { field, pattern: *self.valtree_to_pat(val, ty) }
205 })
206 .collect()
207 }
208
209 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("valtree_to_pat",
"rustc_mir_build::thir::pattern::const_to_pat",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
::tracing_core::__macro_support::Option::Some(211u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
::tracing_core::field::FieldSet::new(&["cv", "ty"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cv)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Box<Pat<'tcx>> = loop {};
return __tracing_attr_fake_return;
}
{
let span = self.span;
let tcx = self.tcx;
let kind =
match ty.kind() {
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:219",
"rustc_mir_build::thir::pattern::const_to_pat",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
::tracing_core::__macro_support::Option::Some(219u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("adt_def {0:?} has !type_marked_structural for cv.ty: {1:?}",
adt_def, ty) as &dyn Value))])
});
} else { ; }
};
let PartialEqImplStatus {
is_derived, structural_partial_eq, non_blanket_impl, .. } =
type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
let (manual_partialeq_impl_span,
manual_partialeq_impl_note) =
match (structural_partial_eq, non_blanket_impl) {
(true, _) => (None, false),
(_, Some(def_id)) if def_id.is_local() && !is_derived => {
(Some(tcx.def_span(def_id)), false)
}
_ => (None, true),
};
let ty_def_span = tcx.def_span(adt_def.did());
let err =
TypeNotStructural {
span,
ty,
ty_def_span,
manual_partialeq_impl_span,
manual_partialeq_impl_note,
};
return self.mk_err(tcx.dcx().create_err(err), ty);
}
ty::Adt(adt_def, args) if adt_def.is_enum() => {
let (&variant_index, fields) =
cv.to_branch().split_first().unwrap();
let variant_index =
VariantIdx::from_u32(variant_index.to_leaf().to_u32());
PatKind::Variant {
adt_def: *adt_def,
args,
variant_index,
subpatterns: self.field_pats(fields.iter().map(|ct|
ct.to_value().valtree).zip(adt_def.variants()[variant_index].fields.iter().map(|field|
field.ty(tcx, args)))),
}
}
ty::Adt(def, args) => {
if !!def.is_union() {
::core::panicking::panic("assertion failed: !def.is_union()")
};
PatKind::Leaf {
subpatterns: self.field_pats(cv.to_branch().iter().map(|ct|
ct.to_value().valtree).zip(def.non_enum_variant().fields.iter().map(|field|
field.ty(tcx, args)))),
}
}
ty::Tuple(fields) =>
PatKind::Leaf {
subpatterns: self.field_pats(cv.to_branch().iter().map(|ct|
ct.to_value().valtree).zip(fields.iter())),
},
ty::Slice(elem_ty) =>
PatKind::Slice {
prefix: cv.to_branch().iter().map(|val|
*self.valtree_to_pat(val.to_value().valtree,
*elem_ty)).collect(),
slice: None,
suffix: Box::new([]),
},
ty::Array(elem_ty, _) =>
PatKind::Array {
prefix: cv.to_branch().iter().map(|val|
*self.valtree_to_pat(val.to_value().valtree,
*elem_ty)).collect(),
slice: None,
suffix: Box::new([]),
},
ty::Str => {
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
}
ty::Ref(_, pointee_ty, ..) => {
if pointee_ty.is_str() || pointee_ty.is_slice() ||
pointee_ty.is_sized(tcx, self.typing_env) {
PatKind::Deref {
subpattern: self.valtree_to_pat(cv, *pointee_ty),
}
} else {
return self.mk_err(tcx.dcx().create_err(UnsizedPattern {
span,
non_sm_ty: *pointee_ty,
}), ty);
}
}
ty::Float(flt) => {
let v = cv.to_leaf();
let is_nan =
match flt {
ty::FloatTy::F16 => v.to_f16().is_nan(),
ty::FloatTy::F32 => v.to_f32().is_nan(),
ty::FloatTy::F64 => v.to_f64().is_nan(),
ty::FloatTy::F128 => v.to_f128().is_nan(),
};
if is_nan {
return self.mk_err(tcx.dcx().create_err(NaNPattern {
span,
}), ty);
} else {
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
}
}
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_)
| ty::RawPtr(..) => {
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
}
ty::FnPtr(..) => {
{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Valtree construction would never succeed for FnPtr, so this is unreachable.")));
}
}
_ => {
let err =
InvalidPattern {
span,
non_sm_ty: ty,
prefix: ty.prefix_string(tcx).to_string(),
};
return self.mk_err(tcx.dcx().create_err(err), ty);
}
};
Box::new(Pat { span, ty, kind, extra: None })
}
}
}#[instrument(skip(self), level = "debug")]
212 fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
213 let span = self.span;
214 let tcx = self.tcx;
215 let kind = match ty.kind() {
216 ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
217 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
220 let PartialEqImplStatus {
221 is_derived, structural_partial_eq, non_blanket_impl, ..
222 } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
223 let (manual_partialeq_impl_span, manual_partialeq_impl_note) =
224 match (structural_partial_eq, non_blanket_impl) {
225 (true, _) => (None, false),
226 (_, Some(def_id)) if def_id.is_local() && !is_derived => {
227 (Some(tcx.def_span(def_id)), false)
228 }
229 _ => (None, true),
230 };
231 let ty_def_span = tcx.def_span(adt_def.did());
232 let err = TypeNotStructural {
233 span,
234 ty,
235 ty_def_span,
236 manual_partialeq_impl_span,
237 manual_partialeq_impl_note,
238 };
239 return self.mk_err(tcx.dcx().create_err(err), ty);
240 }
241 ty::Adt(adt_def, args) if adt_def.is_enum() => {
242 let (&variant_index, fields) = cv.to_branch().split_first().unwrap();
243 let variant_index = VariantIdx::from_u32(variant_index.to_leaf().to_u32());
244 PatKind::Variant {
245 adt_def: *adt_def,
246 args,
247 variant_index,
248 subpatterns: self.field_pats(
249 fields.iter().map(|ct| ct.to_value().valtree).zip(
250 adt_def.variants()[variant_index]
251 .fields
252 .iter()
253 .map(|field| field.ty(tcx, args)),
254 ),
255 ),
256 }
257 }
258 ty::Adt(def, args) => {
259 assert!(!def.is_union()); PatKind::Leaf {
261 subpatterns: self.field_pats(
262 cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(
263 def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)),
264 ),
265 ),
266 }
267 }
268 ty::Tuple(fields) => PatKind::Leaf {
269 subpatterns: self.field_pats(
270 cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(fields.iter()),
271 ),
272 },
273 ty::Slice(elem_ty) => PatKind::Slice {
274 prefix: cv
275 .to_branch()
276 .iter()
277 .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty))
278 .collect(),
279 slice: None,
280 suffix: Box::new([]),
281 },
282 ty::Array(elem_ty, _) => PatKind::Array {
283 prefix: cv
284 .to_branch()
285 .iter()
286 .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty))
287 .collect(),
288 slice: None,
289 suffix: Box::new([]),
290 },
291 ty::Str => {
292 PatKind::Constant { value: ty::Value { ty, valtree: cv } }
300 }
301 ty::Ref(_, pointee_ty, ..) => {
302 if pointee_ty.is_str()
303 || pointee_ty.is_slice()
304 || pointee_ty.is_sized(tcx, self.typing_env)
305 {
306 PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) }
308 } else {
309 return self.mk_err(
310 tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }),
311 ty,
312 );
313 }
314 }
315 ty::Float(flt) => {
316 let v = cv.to_leaf();
317 let is_nan = match flt {
318 ty::FloatTy::F16 => v.to_f16().is_nan(),
319 ty::FloatTy::F32 => v.to_f32().is_nan(),
320 ty::FloatTy::F64 => v.to_f64().is_nan(),
321 ty::FloatTy::F128 => v.to_f128().is_nan(),
322 };
323 if is_nan {
324 return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty);
327 } else {
328 PatKind::Constant { value: ty::Value { ty, valtree: cv } }
329 }
330 }
331 ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
332 PatKind::Constant { value: ty::Value { ty, valtree: cv } }
335 }
336 ty::FnPtr(..) => {
337 unreachable!(
338 "Valtree construction would never succeed for FnPtr, so this is unreachable."
339 )
340 }
341 _ => {
342 let err = InvalidPattern {
343 span,
344 non_sm_ty: ty,
345 prefix: ty.prefix_string(tcx).to_string(),
346 };
347 return self.mk_err(tcx.dcx().create_err(err), ty);
348 }
349 };
350
351 Box::new(Pat { span, ty, kind, extra: None })
352 }
353}
354
355fn extend_type_not_partial_eq<'tcx>(
358 tcx: TyCtxt<'tcx>,
359 typing_env: ty::TypingEnv<'tcx>,
360 ty: Ty<'tcx>,
361 err: &mut Diag<'_>,
362) {
363 struct UsedParamsNeedInstantiationVisitor<'tcx> {
365 tcx: TyCtxt<'tcx>,
366 typing_env: ty::TypingEnv<'tcx>,
367 adts_with_manual_partialeq: FxHashSet<Span>,
369 adts_without_partialeq: FxHashSet<Span>,
371 manual: FxHashSet<Ty<'tcx>>,
374 without: FxHashSet<Ty<'tcx>>,
377 }
378
379 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
380 type Result = ControlFlow<()>;
381 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
382 match ty.kind() {
383 ty::Dynamic(..) => return ControlFlow::Break(()),
384 ty::UnsafeBinder(..) => return ControlFlow::Break(()),
387 ty::FnPtr(..) => return ControlFlow::Continue(()),
388 ty::Adt(def, _args) => {
389 let ty_def_id = def.did();
390 let ty_def_span = self.tcx.def_span(ty_def_id);
391 let PartialEqImplStatus {
392 has_impl,
393 is_derived,
394 structural_partial_eq,
395 non_blanket_impl,
396 } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
397 match (has_impl, is_derived, structural_partial_eq, non_blanket_impl) {
398 (_, _, true, _) => {}
399 (true, false, _, Some(def_id)) if def_id.is_local() => {
400 self.adts_with_manual_partialeq.insert(self.tcx.def_span(def_id));
401 }
402 (true, false, _, _) if ty_def_id.is_local() => {
403 self.adts_with_manual_partialeq.insert(ty_def_span);
404 }
405 (false, _, _, _) if ty_def_id.is_local() => {
406 self.adts_without_partialeq.insert(ty_def_span);
407 }
408 (true, false, _, _) => {
409 self.manual.insert(ty);
410 }
411 (false, _, _, _) => {
412 self.without.insert(ty);
413 }
414 _ => {}
415 };
416 ty.super_visit_with(self)
417 }
418 _ => ty.super_visit_with(self),
419 }
420 }
421 }
422 let mut v = UsedParamsNeedInstantiationVisitor {
423 tcx,
424 typing_env,
425 adts_with_manual_partialeq: FxHashSet::default(),
426 adts_without_partialeq: FxHashSet::default(),
427 manual: FxHashSet::default(),
428 without: FxHashSet::default(),
429 };
430 if v.visit_ty(ty).is_break() {
431 return;
432 }
433 #[allow(rustc::potential_query_instability)] for span in v.adts_with_manual_partialeq {
435 err.span_note(span, "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details");
436 }
437 #[allow(rustc::potential_query_instability)] for span in v.adts_without_partialeq {
439 err.span_label(
440 span,
441 "must be annotated with `#[derive(PartialEq)]` to be usable in patterns",
442 );
443 }
444 #[allow(rustc::potential_query_instability)]
445 let mut manual: Vec<_> = v.manual.into_iter().map(|t| t.to_string()).collect();
446 manual.sort();
447 for ty in manual {
448 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details",
ty))
})format!(
449 "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details"
450 ));
451 }
452 #[allow(rustc::potential_query_instability)]
453 let mut without: Vec<_> = v.without.into_iter().map(|t| t.to_string()).collect();
454 without.sort();
455 for ty in without {
456 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns",
ty))
})format!(
457 "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
458 ));
459 }
460}
461
462#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PartialEqImplStatus {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f,
"PartialEqImplStatus", "has_impl", &self.has_impl, "is_derived",
&self.is_derived, "structural_partial_eq",
&self.structural_partial_eq, "non_blanket_impl",
&&self.non_blanket_impl)
}
}Debug)]
463struct PartialEqImplStatus {
464 has_impl: bool,
465 is_derived: bool,
466 structural_partial_eq: bool,
467 non_blanket_impl: Option<DefId>,
468}
469
470x;#[instrument(level = "trace", skip(tcx), ret)]
471fn type_has_partial_eq_impl<'tcx>(
472 tcx: TyCtxt<'tcx>,
473 typing_env: ty::TypingEnv<'tcx>,
474 ty: Ty<'tcx>,
475) -> PartialEqImplStatus {
476 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
477 let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP);
483 let structural_partial_eq_trait_id =
484 tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP);
485
486 let partial_eq_obligation = Obligation::new(
487 tcx,
488 ObligationCause::dummy(),
489 param_env,
490 ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
491 );
492
493 let mut automatically_derived = false;
494 let mut structural_peq = false;
495 let mut impl_def_id = None;
496 for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) {
497 automatically_derived =
498 find_attr!(tcx.get_all_attrs(def_id), AttributeKind::AutomaticallyDerived(..));
499 impl_def_id = Some(def_id);
500 }
501 for _ in tcx.non_blanket_impls_for_ty(structural_partial_eq_trait_id, ty) {
502 structural_peq = true;
503 }
504 PartialEqImplStatus {
515 has_impl: infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation),
516 is_derived: automatically_derived,
517 structural_partial_eq: structural_peq,
518 non_blanket_impl: impl_def_id,
519 }
520}