Skip to main content

rustc_mir_build/thir/pattern/
const_to_pat.rs

1use core::ops::ControlFlow;
2
3use rustc_abi::{FieldIdx, VariantIdx};
4use rustc_apfloat::Float;
5use rustc_attr_ir::find_attr;
6use rustc_attr_ir::lang_items::LangItem;
7use rustc_data_structures::fx::FxHashSet;
8use rustc_errors::{Diag, msg};
9use rustc_hir as hir;
10use rustc_index::Idx;
11use rustc_infer::infer::TyCtxtInferExt;
12use rustc_infer::traits::Obligation;
13use rustc_middle::mir::interpret::ErrorHandled;
14use rustc_middle::thir::{FieldPat, Pat, PatKind};
15use rustc_middle::ty::consts::ConstExt;
16use rustc_middle::ty::{
17    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, Unnormalized,
18};
19use rustc_span::def_id::DefId;
20use rustc_span::{DUMMY_SP, Span, span_bug};
21use rustc_trait_selection::error_reporting::traits::ambiguity::{
22    CandidateSource, compute_applicable_impls_for_diagnostics,
23};
24use rustc_trait_selection::traits::ObligationCause;
25use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
26use tracing::{debug, instrument, trace};
27
28use super::PatCtxt;
29use crate::diagnostics::{
30    ConstPatternDependsOnGenericParameter, CouldNotEvalConstPattern, InvalidPattern, NaNPattern,
31    PointerPattern, SuggestEq, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern,
32};
33
34impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> {
35    /// Converts a constant to a pattern (if possible).
36    /// This means aggregate values (like structs and enums) are converted
37    /// to a pattern that matches the value (as if you'd compared via structural equality).
38    ///
39    /// Only type system constants are supported, as we are using valtrees
40    /// as an intermediate step. Unfortunately those don't carry a type
41    /// so we have to carry one ourselves.
42    {}
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("const_to_pat",
                                "rustc_mir_build::thir::pattern::const_to_pat",
                                ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                                ::tracing_core::__macro_support::Option::Some(42u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("c")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("c");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("ty")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("ty");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("id")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("id");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("span")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("span");
                                                    NAME.as_str()
                                                }], ::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};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&c)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&id)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&span)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[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 mut convert = ConstToPat::new(self, id, span, c);
                        match c.kind() {
                            ty::ConstKind::Alias(_, alias_const) =>
                                convert.alias_to_pat(alias_const, ty),
                            ty::ConstKind::Value(value) =>
                                convert.valtree_to_pat(value),
                            _ =>
                                ::rustc_span::macros::bug_impl(Some(span),
                                    format_args!("Invalid `ConstKind` for `const_to_pat`: {0:?}",
                                        c), Location::caller()),
                        }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:42",
                        "rustc_mir_build::thir::pattern::const_to_pat",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                        ::tracing_core::__macro_support::Option::Some(42u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "debug", skip(self), ret)]
43    pub(super) fn const_to_pat(
44        &self,
45        c: ty::Const<'tcx>,
46        ty: Ty<'tcx>,
47        id: hir::HirId,
48        span: Span,
49    ) -> Box<Pat<'tcx>> {
50        let mut convert = ConstToPat::new(self, id, span, c);
51
52        match c.kind() {
53            ty::ConstKind::Alias(_, alias_const) => convert.alias_to_pat(alias_const, ty),
54            ty::ConstKind::Value(value) => convert.valtree_to_pat(value),
55            _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
56        }
57    }
58}
59
60struct ConstToPat<'tcx> {
61    tcx: TyCtxt<'tcx>,
62    typing_env: ty::TypingEnv<'tcx>,
63    span: Span,
64    id: hir::HirId,
65
66    c: ty::Const<'tcx>,
67}
68
69impl<'tcx> ConstToPat<'tcx> {
70    fn new(pat_ctxt: &PatCtxt<'tcx, '_>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
71        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:71",
                        "rustc_mir_build::thir::pattern::const_to_pat",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                        ::tracing_core::__macro_support::Option::Some(71u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("pat_ctxt.typeck_results.hir_owner")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("pat_ctxt.typeck_results.hir_owner");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&pat_ctxt.typeck_results.hir_owner)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};trace!(?pat_ctxt.typeck_results.hir_owner);
72        ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c }
73    }
74
75    fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
76        ty.is_structural_eq_shallow(self.tcx)
77    }
78
79    /// We errored. Signal that in the pattern, so that follow up errors can be silenced.
80    fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
81        if let ty::ConstKind::Alias(_, alias_const) = self.c.kind() {
82            if let ty::AliasConstKind::Projection { def_id }
83            | ty::AliasConstKind::InherentSelf { def_id }
84            | ty::AliasConstKind::InherentImpl { def_id } = alias_const.kind
85                && let Some(def_id) = def_id.as_local()
86            {
87                // Include the container item in the output.
88                err.span_context(self.tcx.def_span(self.tcx.local_parent(def_id)));
89            }
90            if let ty::AliasConstKind::Projection { def_id }
91            | ty::AliasConstKind::InherentSelf { def_id }
92            | ty::AliasConstKind::InherentImpl { def_id }
93            | ty::AliasConstKind::Free { def_id } = alias_const.kind
94            {
95                err.span_label(self.tcx.def_span(def_id), rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("constant defined here"))msg!("constant defined here"));
96            }
97        }
98        Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit_err()), extra: None })
99    }
100
101    fn alias_to_pat(&mut self, alias_const: ty::AliasConst<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
102        // It's not *technically* correct to be revealing opaque types here as borrowcheck has
103        // not run yet. However, CTFE itself uses `TypingMode::PostAnalysis` unconditionally even
104        // during typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
105        // As a result we always use a revealed env when resolving the instance to evaluate.
106        //
107        // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
108        // instead of having this logic here
109        let typing_env =
110            self.tcx.erase_and_anonymize_regions(self.typing_env).with_codegen_normalized(self.tcx);
111        let alias_const = self.tcx.erase_and_anonymize_regions(alias_const);
112
113        let mk_too_generic_err = || {
114            let mut err = self
115                .tcx
116                .dcx()
117                .create_err(ConstPatternDependsOnGenericParameter { span: self.span });
118            for arg in alias_const.args {
119                if let ty::GenericArgKind::Type(ty) = arg.kind()
120                    && let ty::Param(param_ty) = ty.kind()
121                {
122                    let def_id = self.tcx.hir_enclosing_body_owner(self.id);
123                    let generics = self.tcx.generics_of(def_id);
124                    let param = generics.type_param(*param_ty, self.tcx);
125                    let span = self.tcx.def_span(param.def_id);
126                    err.span_label(span, "constant depends on this generic parameter");
127                    if let Some(ident) = self.tcx.def_ident_span(def_id)
128                        && self.tcx.sess.source_map().is_multiline(ident.between(span))
129                    {
130                        // Display the `fn` name as well in the diagnostic, as the generic isn't
131                        // in the same line and it could be confusing otherwise.
132                        err.span_context(ident);
133                    }
134                }
135            }
136            return self.mk_err(err, ty);
137        };
138
139        // Under gca_const_items, `alias_const` might be a regular const declared in a trait, but
140        // is `impl`d as a directly represented const. We do not know whether it is here, so we must
141        // use type system normalization for all consts under gca_const_items.
142        //
143        // We probably want to always use type system normalization on stable too, but that would be
144        // a breaking change (in addition to needing significant improvements to diagnostics), so
145        // right now, we limit this to just gca_const_items.
146        //
147        // See: https://github.com/rust-lang/project-const-generics/issues/105
148        let const_value = if self.tcx.features().gca_const_items()
149            || alias_const.kind.is_direct_const(self.tcx)
150        {
151            let Ok(normalize) = self
152                .tcx
153                .try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c))
154            else {
155                let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
156                return self.mk_err(err, ty);
157            };
158
159            let ty::ConstKind::Value(value) = normalize.kind() else {
160                let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
161                return self.mk_err(err, ty);
162            };
163            value
164        } else {
165            // try to resolve e.g. associated constants to their definition on an impl, and then
166            // evaluate the const.
167            let valtree =
168                match self.tcx.const_eval_resolve_for_typeck(typing_env, alias_const, self.span) {
169                    Ok(Ok(c)) => c,
170                    Err(ErrorHandled::Reported(_, _)) => {
171                        // Let's tell the use where this failing const occurs.
172                        let mut err =
173                            self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
174                        // We've emitted an error on the original const, it would be redundant to complain
175                        // on its use as well.
176                        if let ty::ConstKind::Alias(_, alias_const) = self.c.kind()
177                            && let ty::AliasConstKind::Projection { .. }
178                            | ty::AliasConstKind::InherentSelf { .. }
179                            | ty::AliasConstKind::InherentImpl { .. }
180                            | ty::AliasConstKind::Free { .. } = alias_const.kind
181                        {
182                            err.downgrade_to_delayed_bug();
183                        }
184                        return self.mk_err(err, ty);
185                    }
186                    Err(ErrorHandled::TooGeneric(_)) => {
187                        return mk_too_generic_err();
188                    }
189                    Ok(Err(bad_ty)) => {
190                        // The pattern cannot be turned into a valtree.
191                        let e = match bad_ty.kind() {
192                            ty::Adt(def, ..) => {
193                                if !def.is_union() {
    ::core::panicking::panic("assertion failed: def.is_union()")
};assert!(def.is_union());
194                                self.tcx.dcx().create_err(UnionPattern { span: self.span })
195                            }
196                            ty::FnPtr(..) | ty::RawPtr(..) => {
197                                self.tcx.dcx().create_err(PointerPattern { span: self.span })
198                            }
199                            _ => self.tcx.dcx().create_err(InvalidPattern {
200                                span: self.span,
201                                non_sm_ty: bad_ty,
202                                prefix: bad_ty.prefix_string(self.tcx).to_string(),
203                            }),
204                        };
205                        return self.mk_err(e, ty);
206                    }
207                };
208
209            // Lower the valtree to a THIR pattern.
210            ty::Value { ty, valtree }
211        };
212        if const_value.ty.has_param() {
213            return mk_too_generic_err();
214        }
215        let mut thir_pat = self.valtree_to_pat(const_value);
216
217        if !thir_pat.references_error() {
218            // Always check for `PartialEq` if we had no other errors yet.
219            if !type_has_partial_eq_impl(self.tcx, typing_env, ty).has_impl {
220                let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty });
221                extend_type_not_partial_eq(self.tcx, typing_env, ty, &mut err);
222                return self.mk_err(err, ty);
223            }
224        }
225
226        // Mark the pattern to indicate that it is the result of lowering a named
227        // constant. This is used for diagnostics.
228        thir_pat.extra.get_or_insert_default().expanded_const = Some(alias_const.kind);
229        thir_pat
230    }
231
232    fn lower_field_values_to_fieldpats(
233        &self,
234        values: impl Iterator<Item = ty::Value<'tcx>>,
235    ) -> Vec<FieldPat<'tcx>> {
236        values
237            .enumerate()
238            .map(|(index, value)| FieldPat {
239                field: FieldIdx::new(index),
240                pattern: *self.valtree_to_pat(value),
241            })
242            .collect()
243    }
244
245    // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
246    {}
#[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("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                                    ::tracing_core::__macro_support::Option::Some(246u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("value")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("value");
                                                        NAME.as_str()
                                                    }], ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value)
                                                            as &dyn ::tracing::field::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 ty::Value { ty, valtree } = value;
            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 /rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:258",
                                                "rustc_mir_build::thir::pattern::const_to_pat",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                                                ::tracing_core::__macro_support::Option::Some(258u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                                                ::tracing_core::field::FieldSet::new(&["message",
                                                                {
                                                                    const NAME:
                                                                        ::tracing::__macro_support::FieldName<{
                                                                            ::tracing::__macro_support::FieldName::len("adt_def")
                                                                        }> =
                                                                        ::tracing::__macro_support::FieldName::new("adt_def");
                                                                    NAME.as_str()
                                                                },
                                                                {
                                                                    const NAME:
                                                                        ::tracing::__macro_support::FieldName<{
                                                                            ::tracing::__macro_support::FieldName::len("value.ty")
                                                                        }> =
                                                                        ::tracing::__macro_support::FieldName::new("value.ty");
                                                                    NAME.as_str()
                                                                }], ::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};
                                        __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("ADT type in pattern is not `type_marked_structural`")
                                                                    as &dyn ::tracing::field::Value)),
                                                        (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&adt_def)
                                                                    as &dyn ::tracing::field::Value)),
                                                        (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&value.ty)
                                                                    as &dyn ::tracing::field::Value))])
                                    });
                            } else { ; }
                        };
                        let PartialEqImplStatus {
                                is_derived,
                                possibly_inapplicable_structural_partial_eq,
                                non_blanket_impl,
                                possibly_inapplicable_derived_partial_eq,
                                has_impl, .. } =
                            type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
                        if possibly_inapplicable_derived_partial_eq && !has_impl {
                            let mut err =
                                self.tcx.dcx().create_err(TypeNotPartialEq {
                                        span: self.span,
                                        ty,
                                    });
                            extend_type_not_partial_eq(self.tcx, self.typing_env, ty,
                                &mut err);
                            return self.mk_err(err, ty);
                        }
                        let (manual_partialeq_impl_span,
                                manual_partialeq_impl_note) =
                            match (possibly_inapplicable_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 manual_partialeq_impl =
                            manual_partialeq_impl_note ||
                                manual_partialeq_impl_span.is_some();
                        let is_local = adt_def.did().is_local();
                        let ty_def_span = tcx.def_span(adt_def.did());
                        let suggestion =
                            if let Ok(name) =
                                        tcx.sess.source_map().span_to_snippet(self.span) &&
                                    (is_local || manual_partialeq_impl) {
                                let mut hir_id = self.id;
                                while let hir::Node::Pat(pat) = tcx.parent_hir_node(hir_id)
                                    {
                                    hir_id = pat.hir_id;
                                }
                                match tcx.parent_hir_node(hir_id) {
                                    hir::Node::Arm(hir::Arm { pat, guard: None, .. }) => {
                                        Some(SuggestEq::AddIf {
                                                if_span: pat.span.shrink_to_hi(),
                                                pat_span: self.span,
                                                name,
                                                ty,
                                                manual_partialeq_impl,
                                            })
                                    }
                                    hir::Node::Arm(hir::Arm { guard: Some(guard), .. }) => {
                                        Some(SuggestEq::AddToIf {
                                                span: guard.span.shrink_to_hi(),
                                                pat_span: self.span,
                                                name,
                                                ty,
                                                manual_partialeq_impl,
                                            })
                                    }
                                    hir::Node::Expr(hir::Expr {
                                        kind: hir::ExprKind::Let(let_expr), span, .. }) => {
                                        if let_expr.pat.span == self.span {
                                            Some(SuggestEq::ReplaceWithEq {
                                                    removal: span.until(self.span),
                                                    eq: self.span.between(let_expr.init.span),
                                                    ty,
                                                    manual_partialeq_impl,
                                                })
                                        } else if tcx.sess.edition().at_least_rust_2024() {
                                            Some(SuggestEq::AddToLetChain {
                                                    span: span.shrink_to_hi(),
                                                    pat_span: self.span,
                                                    name,
                                                    ty,
                                                    manual_partialeq_impl,
                                                })
                                        } else { None }
                                    }
                                    hir::Node::LetStmt(let_stmt) if
                                        let Some(init) = let_stmt.init &&
                                                    let Some(els) = let_stmt.els && init.span.ctxt().is_root()
                                            && els.span.ctxt().is_root() => {
                                        Some(SuggestEq::ReplaceLetElseWithIf {
                                                if_span: let_stmt.span.until(let_stmt.pat.span),
                                                eq: let_stmt.pat.span.between(init.span),
                                                else_span: init.span.between(els.span),
                                                ty,
                                                manual_partialeq_impl,
                                            })
                                    }
                                    _ => None,
                                }
                            } else { None };
                        let err =
                            TypeNotStructural {
                                span,
                                ty,
                                ty_def_span,
                                manual_partialeq_impl_span,
                                manual_partialeq_impl_note,
                                is_local,
                                suggestion,
                            };
                        return self.mk_err(tcx.dcx().create_err(err), ty);
                    }
                    ty::Adt(adt_def, args) if adt_def.is_enum() => {
                        let (&variant_index, fields) =
                            valtree.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.lower_field_values_to_fieldpats(fields.iter().map(|ct|
                                        ct.to_value())),
                        }
                    }
                    ty::Adt(def, _) => {
                        if !!def.is_union() {
                            ::core::panicking::panic("assertion failed: !def.is_union()")
                        };
                        PatKind::Leaf {
                            subpatterns: self.lower_field_values_to_fieldpats(valtree.to_branch().iter().map(|ct|
                                        ct.to_value())),
                        }
                    }
                    ty::Tuple(_) =>
                        PatKind::Leaf {
                            subpatterns: self.lower_field_values_to_fieldpats(valtree.to_branch().iter().map(|ct|
                                        ct.to_value())),
                        },
                    ty::Slice(_) =>
                        PatKind::Slice {
                            prefix: valtree.to_branch().iter().map(|val|
                                        *self.valtree_to_pat(val.to_value())).collect(),
                            slice: None,
                            suffix: Box::new([]),
                        },
                    ty::Array(_, _) =>
                        PatKind::Array {
                            prefix: valtree.to_branch().iter().map(|val|
                                        *self.valtree_to_pat(val.to_value())).collect(),
                            slice: None,
                            suffix: Box::new([]),
                        },
                    ty::Str => { PatKind::Constant { value } }
                    ty::Ref(_, pointee_ty, ..) => {
                        if pointee_ty.is_str() || pointee_ty.is_slice() ||
                                pointee_ty.is_sized(tcx, self.typing_env) {
                            PatKind::Deref {
                                pin: hir::Pinnedness::Not,
                                subpattern: self.valtree_to_pat(ty::Value {
                                        ty: *pointee_ty,
                                        valtree,
                                    }),
                            }
                        } else {
                            return self.mk_err(tcx.dcx().create_err(UnsizedPattern {
                                            span,
                                            non_sm_ty: *pointee_ty,
                                        }), ty);
                        }
                    }
                    ty::Float(flt) => {
                        let v = valtree.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::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_)
                        | ty::RawPtr(..) => {
                        PatKind::Constant { value }
                    }
                    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")]
247    fn valtree_to_pat(&self, value: ty::Value<'tcx>) -> Box<Pat<'tcx>> {
248        let span = self.span;
249        let tcx = self.tcx;
250        let ty::Value { ty, valtree } = value;
251
252        let kind = match ty.kind() {
253            // Extremely important check for all ADTs!
254            // Make sure they are eligible to be used in patterns (structural), and if not, emit an
255            // error.
256            ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
257                // This ADT cannot be used as a constant in patterns.
258                debug!(?adt_def, ?value.ty, "ADT type in pattern is not `type_marked_structural`");
259                let PartialEqImplStatus {
260                    is_derived,
261                    possibly_inapplicable_structural_partial_eq,
262                    non_blanket_impl,
263                    possibly_inapplicable_derived_partial_eq,
264                    has_impl,
265                    ..
266                } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
267
268                // If we have a derived PartialEq impl but it does not apply,
269                // then error about that instead, because `TypeNotStructural` gives advice that is
270                // relevant only when the problem is that `ty` does not derive `PartialEq`.
271                //
272                // Note that this is a duplicate of a check in `alias_to_pat()`,
273                // which we would run later if we weren’t emitting an error now.
274                if possibly_inapplicable_derived_partial_eq && !has_impl {
275                    let mut err =
276                        self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty });
277                    extend_type_not_partial_eq(self.tcx, self.typing_env, ty, &mut err);
278                    return self.mk_err(err, ty);
279                }
280
281                let (manual_partialeq_impl_span, manual_partialeq_impl_note) =
282                    match (possibly_inapplicable_structural_partial_eq, non_blanket_impl) {
283                        (true, _) => (None, false),
284                        (_, Some(def_id)) if def_id.is_local() && !is_derived => {
285                            (Some(tcx.def_span(def_id)), false)
286                        }
287                        _ => (None, true),
288                    };
289                let manual_partialeq_impl =
290                    manual_partialeq_impl_note || manual_partialeq_impl_span.is_some();
291                let is_local = adt_def.did().is_local();
292                let ty_def_span = tcx.def_span(adt_def.did());
293                let suggestion = if let Ok(name) = tcx.sess.source_map().span_to_snippet(self.span)
294                    && (is_local || manual_partialeq_impl)
295                {
296                    let mut hir_id = self.id;
297                    while let hir::Node::Pat(pat) = tcx.parent_hir_node(hir_id) {
298                        hir_id = pat.hir_id;
299                    }
300                    match tcx.parent_hir_node(hir_id) {
301                        hir::Node::Arm(hir::Arm { pat, guard: None, .. }) => {
302                            // Add an if condition to the match arm.
303                            Some(SuggestEq::AddIf {
304                                if_span: pat.span.shrink_to_hi(),
305                                pat_span: self.span,
306                                name,
307                                ty,
308                                manual_partialeq_impl,
309                            })
310                        }
311                        hir::Node::Arm(hir::Arm { guard: Some(guard), .. }) => {
312                            // Modify the the match arm if condition and add a check for equality.
313                            Some(SuggestEq::AddToIf {
314                                span: guard.span.shrink_to_hi(),
315                                pat_span: self.span,
316                                name,
317                                ty,
318                                manual_partialeq_impl,
319                            })
320                        }
321                        hir::Node::Expr(hir::Expr {
322                            kind: hir::ExprKind::Let(let_expr),
323                            span,
324                            ..
325                        }) => {
326                            if let_expr.pat.span == self.span {
327                                // `if let CONST = expr` -> `if CONST == expr`.
328                                Some(SuggestEq::ReplaceWithEq {
329                                    removal: span.until(self.span),
330                                    eq: self.span.between(let_expr.init.span),
331                                    ty,
332                                    manual_partialeq_impl,
333                                })
334                            } else if tcx.sess.edition().at_least_rust_2024() {
335                                // `if let Some(CONST) = expr` ->
336                                // `if let Some(binding) = expr && binding == CONST`.
337                                Some(SuggestEq::AddToLetChain {
338                                    span: span.shrink_to_hi(),
339                                    pat_span: self.span,
340                                    name,
341                                    ty,
342                                    manual_partialeq_impl,
343                                })
344                            } else {
345                                None
346                            }
347                        }
348                        hir::Node::LetStmt(let_stmt)
349                            if let Some(init) = let_stmt.init
350                                && let Some(els) = let_stmt.els
351                                && init.span.ctxt().is_root()
352                                && els.span.ctxt().is_root() =>
353                        {
354                            // `let PAT = expr else {` -> `if PAT == expr {`.
355                            Some(SuggestEq::ReplaceLetElseWithIf {
356                                if_span: let_stmt.span.until(let_stmt.pat.span),
357                                eq: let_stmt.pat.span.between(init.span),
358                                else_span: init.span.between(els.span),
359                                ty,
360                                manual_partialeq_impl,
361                            })
362                        }
363                        _ => None,
364                    }
365                } else {
366                    None
367                };
368                let err = TypeNotStructural {
369                    span,
370                    ty,
371                    ty_def_span,
372                    manual_partialeq_impl_span,
373                    manual_partialeq_impl_note,
374                    is_local,
375                    suggestion,
376                };
377                return self.mk_err(tcx.dcx().create_err(err), ty);
378            }
379            ty::Adt(adt_def, args) if adt_def.is_enum() => {
380                let (&variant_index, fields) = valtree.to_branch().split_first().unwrap();
381                let variant_index = VariantIdx::from_u32(variant_index.to_leaf().to_u32());
382                PatKind::Variant {
383                    adt_def: *adt_def,
384                    args,
385                    variant_index,
386                    subpatterns: self
387                        .lower_field_values_to_fieldpats(fields.iter().map(|ct| ct.to_value())),
388                }
389            }
390            ty::Adt(def, _) => {
391                assert!(!def.is_union()); // Valtree construction would never succeed for unions.
392                PatKind::Leaf {
393                    subpatterns: self.lower_field_values_to_fieldpats(
394                        valtree.to_branch().iter().map(|ct| ct.to_value()),
395                    ),
396                }
397            }
398            ty::Tuple(_) => PatKind::Leaf {
399                subpatterns: self.lower_field_values_to_fieldpats(
400                    valtree.to_branch().iter().map(|ct| ct.to_value()),
401                ),
402            },
403            ty::Slice(_) => PatKind::Slice {
404                prefix: valtree
405                    .to_branch()
406                    .iter()
407                    .map(|val| *self.valtree_to_pat(val.to_value()))
408                    .collect(),
409                slice: None,
410                suffix: Box::new([]),
411            },
412            ty::Array(_, _) => PatKind::Array {
413                prefix: valtree
414                    .to_branch()
415                    .iter()
416                    .map(|val| *self.valtree_to_pat(val.to_value()))
417                    .collect(),
418                slice: None,
419                suffix: Box::new([]),
420            },
421            ty::Str => {
422                // Constant/literal patterns of type `&str` are lowered to a
423                // `PatKind::Deref` wrapping a `PatKind::Constant` of type `str`.
424                // This pattern node is the `str` constant part.
425                //
426                // Under `feature(deref_patterns)`, string literal patterns can also
427                // have type `str` directly, without the `&`, in order to allow things
428                // like `deref!("...")` to work when the scrutinee is `String`.
429                PatKind::Constant { value }
430            }
431            ty::Ref(_, pointee_ty, ..) => {
432                if pointee_ty.is_str()
433                    || pointee_ty.is_slice()
434                    || pointee_ty.is_sized(tcx, self.typing_env)
435                {
436                    PatKind::Deref {
437                        // This node has type `ty::Ref`, so it's not a pin-deref.
438                        pin: hir::Pinnedness::Not,
439                        // Lower the valtree to a pattern as the pointee type.
440                        // This works because references have the same valtree
441                        // representation as their pointee.
442                        subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }),
443                    }
444                } else {
445                    return self.mk_err(
446                        tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }),
447                        ty,
448                    );
449                }
450            }
451            ty::Float(flt) => {
452                let v = valtree.to_leaf();
453                let is_nan = match flt {
454                    ty::FloatTy::F16 => v.to_f16().is_nan(),
455                    ty::FloatTy::F32 => v.to_f32().is_nan(),
456                    ty::FloatTy::F64 => v.to_f64().is_nan(),
457                    ty::FloatTy::F128 => v.to_f128().is_nan(),
458                };
459                if is_nan {
460                    // NaNs are not ever equal to anything so they make no sense as patterns.
461                    // Also see <https://github.com/rust-lang/rfcs/pull/3535>.
462                    return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty);
463                } else {
464                    PatKind::Constant { value }
465                }
466            }
467            ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
468                // The raw pointers we see here have been "vetted" by valtree construction to be
469                // just integers, so we simply allow them.
470                PatKind::Constant { value }
471            }
472            ty::FnPtr(..) => {
473                unreachable!(
474                    "Valtree construction would never succeed for FnPtr, so this is unreachable."
475                )
476            }
477            _ => {
478                let err = InvalidPattern {
479                    span,
480                    non_sm_ty: ty,
481                    prefix: ty.prefix_string(tcx).to_string(),
482                };
483                return self.mk_err(tcx.dcx().create_err(err), ty);
484            }
485        };
486
487        Box::new(Pat { span, ty, kind, extra: None })
488    }
489}
490
491/// Given a type with type parameters, visit every ADT looking for types that need to
492/// `#[derive(PartialEq)]` for it to be a structural type.
493fn extend_type_not_partial_eq<'tcx>(
494    tcx: TyCtxt<'tcx>,
495    typing_env: ty::TypingEnv<'tcx>,
496    ty: Ty<'tcx>,
497    err: &mut Diag<'_>,
498) {
499    /// Collect all types that need to be `StructuralPartialEq`.
500    struct UsedParamsNeedInstantiationVisitor<'tcx> {
501        tcx: TyCtxt<'tcx>,
502        typing_env: ty::TypingEnv<'tcx>,
503        /// The user has written `impl PartialEq for Ty` which means it's non-structural.
504        adts_with_manual_partialeq: FxHashSet<Span>,
505        /// The type has no `PartialEq` implementation, neither manual or derived.
506        adts_without_partialeq: FxHashSet<Span>,
507        /// The user has written `impl PartialEq for Ty` which means it's non-structural,
508        /// but we don't have a span to point at, so we'll just add them as a `note`.
509        manual: FxHashSet<Ty<'tcx>>,
510        /// The type has no `PartialEq` implementation, neither manual or derived, but
511        /// we don't have a span to point at, so we'll just add them as a `note`.
512        without: FxHashSet<Ty<'tcx>>,
513    }
514
515    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
516        type Result = ControlFlow<()>;
517        fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
518            match ty.kind() {
519                ty::Dynamic(..) => return ControlFlow::Break(()),
520                // Unsafe binders never implement `PartialEq`, so avoid walking into them
521                // which would require instantiating its binder with placeholders too.
522                ty::UnsafeBinder(..) => return ControlFlow::Break(()),
523                ty::FnPtr(..) => return ControlFlow::Continue(()),
524                ty::Adt(def, _args) => {
525                    let ty_def_id = def.did();
526                    let ty_def_span = self.tcx.def_span(ty_def_id);
527                    let PartialEqImplStatus {
528                        has_impl,
529                        is_derived,
530                        possibly_inapplicable_structural_partial_eq: structural_partial_eq,
531                        non_blanket_impl,
532                        possibly_inapplicable_derived_partial_eq: _,
533                    } = type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
534                    match (has_impl, is_derived, structural_partial_eq, non_blanket_impl) {
535                        (_, _, true, _) => {}
536                        (true, false, _, Some(def_id)) if def_id.is_local() => {
537                            self.adts_with_manual_partialeq.insert(self.tcx.def_span(def_id));
538                        }
539                        (true, false, _, _) if ty_def_id.is_local() => {
540                            self.adts_with_manual_partialeq.insert(ty_def_span);
541                        }
542                        (false, _, _, _) if ty_def_id.is_local() => {
543                            self.adts_without_partialeq.insert(ty_def_span);
544                        }
545                        (true, false, _, _) => {
546                            self.manual.insert(ty);
547                        }
548                        (false, _, _, _) => {
549                            self.without.insert(ty);
550                        }
551                        _ => {}
552                    };
553                    ty.super_visit_with(self)
554                }
555                _ => ty.super_visit_with(self),
556            }
557        }
558    }
559    let mut v = UsedParamsNeedInstantiationVisitor {
560        tcx,
561        typing_env,
562        adts_with_manual_partialeq: FxHashSet::default(),
563        adts_without_partialeq: FxHashSet::default(),
564        manual: FxHashSet::default(),
565        without: FxHashSet::default(),
566    };
567    if v.visit_ty(ty).is_break() {
568        return;
569    }
570    #[allow(rustc::potential_query_instability)] // Span labels will be sorted by the rendering
571    for span in v.adts_with_manual_partialeq {
572        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");
573    }
574    #[allow(rustc::potential_query_instability)] // Span labels will be sorted by the rendering
575    for span in v.adts_without_partialeq {
576        err.span_label(
577            span,
578            "must be annotated with `#[derive(PartialEq)]` to be usable in patterns",
579        );
580    }
581    #[allow(rustc::potential_query_instability)]
582    let mut manual: Vec<_> = v.manual.into_iter().map(|t| t.to_string()).collect();
583    manual.sort();
584    for ty in manual {
585        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!(
586            "`{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"
587        ));
588    }
589    #[allow(rustc::potential_query_instability)]
590    let mut without: Vec<_> = v.without.into_iter().map(|t| t.to_string()).collect();
591    without.sort();
592    for ty in without {
593        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!(
594            "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
595        ));
596    }
597}
598
599#[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_field5_finish(f,
            "PartialEqImplStatus", "has_impl", &self.has_impl, "is_derived",
            &self.is_derived, "non_blanket_impl", &self.non_blanket_impl,
            "possibly_inapplicable_structural_partial_eq",
            &self.possibly_inapplicable_structural_partial_eq,
            "possibly_inapplicable_derived_partial_eq",
            &&self.possibly_inapplicable_derived_partial_eq)
    }
}Debug)]
600struct PartialEqImplStatus {
601    /// There is a `PartialEq` impl that applies to the type.
602    has_impl: bool,
603
604    /// The `PartialEq` impl is `#[automatically_derived]`.
605    is_derived: bool,
606    /// The `DefId` of the same impl that `is_derived` refers to.
607    non_blanket_impl: Option<DefId>,
608
609    /// If true, there is a `StructuralPartialEq` implementation,
610    /// but its bounds might not be satisfied.
611    possibly_inapplicable_structural_partial_eq: bool,
612    /// If true, there is a derived `PartialEq` implementation for the type,
613    /// but its bounds might not be satisfied.
614    possibly_inapplicable_derived_partial_eq: bool,
615}
616
617{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::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("type_has_partial_eq_impl",
                                "rustc_mir_build::thir::pattern::const_to_pat",
                                ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                                ::tracing_core::__macro_support::Option::Some(617u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("typing_env")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("typing_env");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("ty")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("ty");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::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};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&typing_env)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[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: PartialEqImplStatus =
                            loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let (infcx, param_env) =
                            tcx.infer_ctxt().build_with_typing_env(typing_env);
                        let partial_eq_trait_id =
                            tcx.require_lang_item(LangItem::PartialEq, DUMMY_SP);
                        let structural_partial_eq_trait_id =
                            tcx.require_lang_item(LangItem::StructuralPeq, DUMMY_SP);
                        let has_impl =
                            {
                                let obligation =
                                    Obligation::new(tcx, ObligationCause::dummy(), param_env,
                                        ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]));
                                infcx.predicate_must_hold_modulo_regions(&obligation)
                            };
                        let possibly_inapplicable_derived_partial_eq =
                            {
                                let obligation =
                                    Obligation::new(tcx, ObligationCause::dummy(), param_env,
                                        ty::Binder::dummy(ty::TraitRef::new(tcx,
                                                partial_eq_trait_id, [ty, ty])));
                                compute_applicable_impls_for_diagnostics(&infcx,
                                            &obligation,
                                            true).iter().any(|candidate_source|
                                        {

                                            #[allow(non_exhaustive_omitted_patterns)]
                                            match candidate_source {
                                                &CandidateSource::DefId(def_id) if
                                                    {
                                                            {
                                                                'done:
                                                                    {
                                                                    for i in ::rustc_attr_ir::HasAttrs::get_attrs(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(AutomaticallyDerived) =>
                                                                                {
                                                                                break 'done Some(());
                                                                            }
                                                                            ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                                                {}
                                                                                #[deny(unreachable_patterns)]
                                                                                _ => {}
                                                                        }
                                                                    }
                                                                    None
                                                                }
                                                            }
                                                        }.is_some() => true,
                                                _ => false,
                                            }
                                        })
                            };
                        let possibly_inapplicable_structural_partial_eq =
                            {
                                let obligation =
                                    Obligation::new(tcx, ObligationCause::dummy(), param_env,
                                        ty::Binder::dummy(ty::TraitRef::new(tcx,
                                                structural_partial_eq_trait_id, [ty])));
                                compute_applicable_impls_for_diagnostics(&infcx,
                                            &obligation,
                                            true).iter().any(|candidate_source|
                                        #[allow(non_exhaustive_omitted_patterns)] match candidate_source
                                            {
                                            CandidateSource::DefId(_) => true,
                                            _ => false,
                                        })
                            };
                        let mut automatically_derived = false;
                        let mut impl_def_id = None;
                        for def_id in
                            tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) {
                            automatically_derived =
                                {
                                        {
                                            'done:
                                                {
                                                for i in ::rustc_attr_ir::HasAttrs::get_attrs(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(AutomaticallyDerived) =>
                                                            {
                                                            break 'done Some(());
                                                        }
                                                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                            {}
                                                            #[deny(unreachable_patterns)]
                                                            _ => {}
                                                    }
                                                }
                                                None
                                            }
                                        }
                                    }.is_some();
                            impl_def_id = Some(def_id);
                        }
                        PartialEqImplStatus {
                            has_impl,
                            is_derived: automatically_derived,
                            possibly_inapplicable_structural_partial_eq,
                            non_blanket_impl: impl_def_id,
                            possibly_inapplicable_derived_partial_eq,
                        }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs:617",
                        "rustc_mir_build::thir::pattern::const_to_pat",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/1d81eb4ad9cd207e3e638bd32b17ec4fce8412a6/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs"),
                        ::tracing_core::__macro_support::Option::Some(617u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::pattern::const_to_pat"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(tcx), ret)]
618fn type_has_partial_eq_impl<'tcx>(
619    tcx: TyCtxt<'tcx>,
620    typing_env: ty::TypingEnv<'tcx>,
621    ty: Ty<'tcx>,
622) -> PartialEqImplStatus {
623    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
624    // double-check there even *is* a semantic `PartialEq` to dispatch to.
625    //
626    // (If there isn't, then we can safely issue a hard
627    // error, because that's never worked, due to compiler
628    // using `PartialEq::eq` in this scenario in the past.)
629    let partial_eq_trait_id = tcx.require_lang_item(LangItem::PartialEq, DUMMY_SP);
630    let structural_partial_eq_trait_id = tcx.require_lang_item(LangItem::StructuralPeq, DUMMY_SP);
631
632    // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
633    // ignored. However that should be pretty much impossible since consts that do not depend on
634    // generics can only mention the `'static` lifetime, and how would one have a type that's
635    // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
636    // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
637    // can ensure that the type really implements `PartialEq`.
638    // We also do *not* require `const PartialEq`, not even in `const fn`. This violates the model
639    // that patterns can only do things that the code could also do without patterns, but it is
640    // needed for backwards compatibility. The actual pattern matching compares primitive values,
641    // `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code.
642    let has_impl = {
643        let obligation = Obligation::new(
644            tcx,
645            ObligationCause::dummy(),
646            param_env,
647            ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
648        );
649        infcx.predicate_must_hold_modulo_regions(&obligation)
650    };
651
652    // Determine whether there are is a derived `PartialEq` implementation, whether or not its
653    // bounds are met.
654    let possibly_inapplicable_derived_partial_eq = {
655        let obligation = Obligation::new(
656            tcx,
657            ObligationCause::dummy(),
658            param_env,
659            ty::Binder::dummy(ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty])),
660        );
661        compute_applicable_impls_for_diagnostics(&infcx, &obligation, true).iter().any(
662            |candidate_source| {
663                matches!(
664                    candidate_source,
665                    &CandidateSource::DefId(def_id)
666                    if find_attr!(tcx, def_id, AutomaticallyDerived)
667                )
668            },
669        )
670    };
671
672    let possibly_inapplicable_structural_partial_eq = {
673        let obligation = Obligation::new(
674            tcx,
675            ObligationCause::dummy(),
676            param_env,
677            ty::Binder::dummy(ty::TraitRef::new(tcx, structural_partial_eq_trait_id, [ty])),
678        );
679        compute_applicable_impls_for_diagnostics(&infcx, &obligation, true)
680            .iter()
681            .any(|candidate_source| matches!(candidate_source, CandidateSource::DefId(_)))
682    };
683
684    let mut automatically_derived = false;
685    let mut impl_def_id = None;
686    for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) {
687        automatically_derived = find_attr!(tcx, def_id, AutomaticallyDerived);
688        impl_def_id = Some(def_id);
689    }
690
691    PartialEqImplStatus {
692        has_impl,
693        is_derived: automatically_derived,
694        possibly_inapplicable_structural_partial_eq,
695        non_blanket_impl: impl_def_id,
696        possibly_inapplicable_derived_partial_eq,
697    }
698}