Skip to main content

flux_middle/
lib.rs

1//! This crate contains common type definitions that are used by other crates.
2#![feature(
3    associated_type_defaults,
4    closure_track_caller,
5    map_try_insert,
6    min_specialization,
7    never_type,
8    rustc_private,
9    unwrap_infallible
10)]
11
12extern crate rustc_abi;
13extern crate rustc_ast;
14extern crate rustc_data_structures;
15extern crate rustc_errors;
16extern crate rustc_hir;
17extern crate rustc_index;
18extern crate rustc_macros;
19extern crate rustc_middle;
20extern crate rustc_serialize;
21extern crate rustc_span;
22extern crate rustc_type_ir;
23
24extern crate self as flux_middle;
25
26pub mod big_int;
27mod builtin_assoc_refts;
28pub mod call_graph;
29pub mod cstore;
30pub mod def_id;
31pub mod fhir;
32pub mod global_env;
33pub mod metrics;
34pub mod pretty;
35pub mod queries;
36pub mod rty;
37mod sort_of;
38
39use std::sync::LazyLock;
40
41use flux_arc_interner::List;
42pub use flux_rustc_bridge::def_id_to_string;
43use flux_rustc_bridge::{
44    mir::{LocalDecls, PlaceElem},
45    ty::{self, GenericArgsExt},
46};
47use flux_syntax::surface::{self, NodeId};
48use global_env::GlobalEnv;
49use liquid_fixpoint::ThyFunc;
50use queries::QueryResult;
51use rty::VariantIdx;
52use rustc_abi::FieldIdx;
53use rustc_data_structures::{
54    fx::FxIndexMap,
55    unord::{UnordMap, UnordSet},
56};
57use rustc_hir::OwnerId;
58use rustc_macros::{Decodable, Encodable, extension};
59use rustc_middle::ty::TyCtxt;
60use rustc_span::{
61    Span, Symbol,
62    def_id::{DefId, LocalDefId},
63    symbol::Ident,
64};
65
66#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Encodable, Decodable)]
67pub enum PanicSpec {
68    WillNotPanic,
69    MightPanic(PanicReason),
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
73pub enum PanicReason {
74    Transitive,
75    UnresolvedCall(DefId),
76    DynamicDispatch,
77    SynthesizedPanic,
78    NotInCallGraph,
79    NoMIRAvailable,
80}
81
82pub struct TheoryFunc {
83    pub name: Symbol,
84    pub sort: rty::PolyFuncSort,
85    pub itf: liquid_fixpoint::ThyFunc,
86}
87
88pub static THEORY_FUNCS: LazyLock<UnordMap<liquid_fixpoint::ThyFunc, TheoryFunc>> =
89    LazyLock::new(|| {
90        use rty::{BvSize, Sort::*};
91        liquid_fixpoint::ThyFunc::ALL
92            .into_iter()
93            .filter_map(|func| {
94                let func = TheoryFunc {
95                    name: Symbol::intern(name_of_thy_func(func)?),
96                    itf: func,
97                    sort: sort_of_thy_func(func)?,
98                };
99                Some(func)
100            })
101            .chain([
102                // we can't express these as function types so we add special case
103                TheoryFunc {
104                    name: Symbol::intern("bv_zero_extend_32_to_64"),
105                    itf: liquid_fixpoint::ThyFunc::BvZeroExtend(32),
106                    sort: rty::PolyFuncSort::new(
107                        List::empty(),
108                        rty::FuncSort::new(
109                            vec![BitVec(BvSize::Fixed(32))],
110                            BitVec(BvSize::Fixed(64)),
111                        ),
112                    ),
113                },
114                TheoryFunc {
115                    name: Symbol::intern("bv_sign_extend_32_to_64"),
116                    itf: liquid_fixpoint::ThyFunc::BvSignExtend(32),
117                    sort: rty::PolyFuncSort::new(
118                        List::empty(),
119                        rty::FuncSort::new(
120                            vec![BitVec(BvSize::Fixed(32))],
121                            BitVec(BvSize::Fixed(64)),
122                        ),
123                    ),
124                },
125            ])
126            .map(|func| (func.itf, func))
127            .collect()
128    });
129
130pub fn name_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<&'static str> {
131    let name = match func {
132        ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
133        ThyFunc::StrLen => "str_len",
134        ThyFunc::StrConcat => "str_concat",
135        ThyFunc::StrPrefixOf => "str_prefix_of",
136        ThyFunc::StrSuffixOf => "str_suffix_of",
137        ThyFunc::StrContains => "str_contains",
138        ThyFunc::IntToBv8 => "bv_int_to_bv8",
139        ThyFunc::Bv8ToInt => "bv_bv8_to_int",
140        ThyFunc::IntToBv32 => "bv_int_to_bv32",
141        ThyFunc::Bv32ToInt => "bv_bv32_to_int",
142        ThyFunc::IntToBv64 => "bv_int_to_bv64",
143        ThyFunc::Bv64ToInt => "bv_bv64_to_int",
144        ThyFunc::IntToBv128 => "bv_int_to_bv128",
145        ThyFunc::Bv128ToInt => "bv_bv128_to_int",
146        ThyFunc::BvUge => "bv_uge",
147        ThyFunc::BvSge => "bv_sge",
148        ThyFunc::BvUdiv => "bv_udiv",
149        ThyFunc::BvSdiv => "bv_sdiv",
150        ThyFunc::BvSrem => "bv_srem",
151        ThyFunc::BvUrem => "bv_urem",
152        ThyFunc::BvLshr => "bv_lshr",
153        ThyFunc::BvAshr => "bv_ashr",
154        ThyFunc::BvAnd => "bv_and",
155        ThyFunc::BvOr => "bv_or",
156        ThyFunc::BvXor => "bv_xor",
157        ThyFunc::BvNot => "bv_not",
158        ThyFunc::BvAdd => "bv_add",
159        ThyFunc::BvNeg => "bv_neg",
160        ThyFunc::BvSub => "bv_sub",
161        ThyFunc::BvMul => "bv_mul",
162        ThyFunc::BvShl => "bv_shl",
163        ThyFunc::BvUle => "bv_ule",
164        ThyFunc::BvSle => "bv_sle",
165        ThyFunc::BvUgt => "bv_ugt",
166        ThyFunc::BvSgt => "bv_sgt",
167        ThyFunc::BvUlt => "bv_ult",
168        ThyFunc::BvSlt => "bv_slt",
169        ThyFunc::SetEmpty => "set_empty",
170        ThyFunc::SetSng => "set_singleton",
171        ThyFunc::SetCup => "set_union",
172        ThyFunc::SetCap => "set_intersection",
173        ThyFunc::SetDif => "set_difference",
174        ThyFunc::SetSub => "set_subset",
175        ThyFunc::SetMem => "set_is_in",
176        ThyFunc::MapDefault => "map_default",
177        ThyFunc::MapSelect => "map_select",
178        ThyFunc::MapStore => "map_store",
179    };
180    Some(name)
181}
182
183fn sort_of_thy_func(func: liquid_fixpoint::ThyFunc) -> Option<rty::PolyFuncSort> {
184    use rty::{
185        BvSize, ParamSort,
186        Sort::{self, *},
187        SortCtor::*,
188        SortParamKind,
189    };
190    let param0 = ParamSort::from_u32(0);
191    let param1 = ParamSort::from_u32(1);
192    let bv_param0 = BvSize::Param(ParamSort::from_u32(0));
193
194    let sort = match func {
195        ThyFunc::BvZeroExtend(_) | ThyFunc::BvSignExtend(_) => return None,
196        ThyFunc::StrLen => {
197            // str -> int
198            rty::PolyFuncSort::new(List::empty(), rty::FuncSort::new(vec![rty::Sort::Str], Int))
199        }
200        ThyFunc::StrConcat => {
201            // (str, str) -> str
202            rty::PolyFuncSort::new(
203                List::empty(),
204                rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], rty::Sort::Str),
205            )
206        }
207        ThyFunc::StrPrefixOf | ThyFunc::StrSuffixOf | ThyFunc::StrContains => {
208            // (str, str) -> bool
209            rty::PolyFuncSort::new(
210                List::empty(),
211                rty::FuncSort::new(vec![rty::Sort::Str, rty::Sort::Str], Bool),
212            )
213        }
214        ThyFunc::IntToBv8 => {
215            // int -> BitVec<8>
216            rty::PolyFuncSort::new(
217                List::empty(),
218                rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(8))),
219            )
220        }
221        ThyFunc::Bv8ToInt => {
222            // BitVec<8> -> int
223            rty::PolyFuncSort::new(
224                List::empty(),
225                rty::FuncSort::new(vec![BitVec(BvSize::Fixed(8))], Int),
226            )
227        }
228        ThyFunc::IntToBv32 => {
229            // int -> BitVec<32>
230            rty::PolyFuncSort::new(
231                List::empty(),
232                rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(32))),
233            )
234        }
235        ThyFunc::Bv32ToInt => {
236            // BitVec<32> -> int
237            rty::PolyFuncSort::new(
238                List::empty(),
239                rty::FuncSort::new(vec![BitVec(BvSize::Fixed(32))], Int),
240            )
241        }
242        ThyFunc::IntToBv64 => {
243            // int -> BitVec<64>
244            rty::PolyFuncSort::new(
245                List::empty(),
246                rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(64))),
247            )
248        }
249        ThyFunc::Bv64ToInt => {
250            // BitVec<64> -> int
251            rty::PolyFuncSort::new(
252                List::empty(),
253                rty::FuncSort::new(vec![BitVec(BvSize::Fixed(64))], Int),
254            )
255        }
256        ThyFunc::IntToBv128 => {
257            // int -> BitVec<128>
258            rty::PolyFuncSort::new(
259                List::empty(),
260                rty::FuncSort::new(vec![rty::Sort::Int], BitVec(BvSize::Fixed(128))),
261            )
262        }
263        ThyFunc::Bv128ToInt => {
264            // BitVec<128> -> int
265            rty::PolyFuncSort::new(
266                List::empty(),
267                rty::FuncSort::new(vec![BitVec(BvSize::Fixed(128))], Int),
268            )
269        }
270        ThyFunc::BvUdiv
271        | ThyFunc::BvSdiv
272        | ThyFunc::BvSrem
273        | ThyFunc::BvUrem
274        | ThyFunc::BvLshr
275        | ThyFunc::BvAshr
276        | ThyFunc::BvAnd
277        | ThyFunc::BvOr
278        | ThyFunc::BvXor
279        | ThyFunc::BvAdd
280        | ThyFunc::BvSub
281        | ThyFunc::BvMul
282        | ThyFunc::BvShl => {
283            // ∀s. (BitVec<s>, BitVec<s>) -> BitVec<s>
284            rty::PolyFuncSort::new(
285                List::singleton(SortParamKind::BvSize),
286                rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], BitVec(bv_param0)),
287            )
288        }
289        ThyFunc::BvNot | ThyFunc::BvNeg => {
290            // ∀s. BitVec<s> -> BitVec<s>
291            rty::PolyFuncSort::new(
292                List::singleton(SortParamKind::BvSize),
293                rty::FuncSort::new(vec![BitVec(bv_param0)], BitVec(bv_param0)),
294            )
295        }
296        ThyFunc::BvUgt
297        | ThyFunc::BvSgt
298        | ThyFunc::BvUlt
299        | ThyFunc::BvSlt
300        | ThyFunc::BvSle
301        | ThyFunc::BvUge
302        | ThyFunc::BvSge
303        | ThyFunc::BvUle => {
304            // ∀s. (BitVec<s>, BitVec<s>) -> bool
305            rty::PolyFuncSort::new(
306                List::singleton(SortParamKind::BvSize),
307                rty::FuncSort::new(vec![BitVec(bv_param0), BitVec(bv_param0)], Bool),
308            )
309        }
310        ThyFunc::SetEmpty => {
311            // ∀s. int -> Set<S> why does this take an int?
312            rty::PolyFuncSort::new(
313                List::singleton(SortParamKind::Sort),
314                rty::FuncSort::new(vec![Int], Sort::app(Set, List::singleton(Var(param0)))),
315            )
316        }
317        ThyFunc::SetSng => {
318            // ∀s. s -> Set<S>
319            rty::PolyFuncSort::new(
320                List::singleton(SortParamKind::Sort),
321                rty::FuncSort::new(vec![Var(param0)], Sort::app(Set, List::singleton(Var(param0)))),
322            )
323        }
324        ThyFunc::SetCup | ThyFunc::SetCap | ThyFunc::SetDif => {
325            // ∀s. (Set<S>, Set<S>) -> Set<S>
326            rty::PolyFuncSort::new(
327                List::singleton(SortParamKind::Sort),
328                rty::FuncSort::new(
329                    vec![
330                        Sort::app(Set, List::singleton(Var(param0))),
331                        Sort::app(Set, List::singleton(Var(param0))),
332                    ],
333                    Sort::app(Set, List::singleton(Var(param0))),
334                ),
335            )
336        }
337        ThyFunc::SetMem => {
338            // ∀s. (s, Set<S>) -> bool
339            rty::PolyFuncSort::new(
340                List::singleton(SortParamKind::Sort),
341                rty::FuncSort::new(
342                    vec![Var(param0), Sort::app(Set, List::singleton(Var(param0)))],
343                    Bool,
344                ),
345            )
346        }
347        ThyFunc::SetSub => {
348            // ∀s. (Set<s>, Set<s>) -> bool
349            rty::PolyFuncSort::new(
350                List::singleton(SortParamKind::Sort),
351                rty::FuncSort::new(
352                    vec![
353                        Sort::app(Set, List::singleton(Var(param0))),
354                        Sort::app(Set, List::singleton(Var(param0))),
355                    ],
356                    Bool,
357                ),
358            )
359        }
360
361        ThyFunc::MapDefault => {
362            // ∀k,v. v -> Map<k,v>
363            rty::PolyFuncSort::new(
364                List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
365                rty::FuncSort::new(
366                    vec![Var(param1)],
367                    Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
368                ),
369            )
370        }
371        ThyFunc::MapSelect => {
372            // ∀k,v. (Map<k,v>, k) -> v
373            rty::PolyFuncSort::new(
374                List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
375                rty::FuncSort::new(
376                    vec![Sort::app(Map, List::from_arr([Var(param0), Var(param1)])), Var(param0)],
377                    Var(param1),
378                ),
379            )
380        }
381        ThyFunc::MapStore => {
382            // ∀k,v. (Map<k,v>, k, v) -> Map<k, v>
383            rty::PolyFuncSort::new(
384                List::from_arr([SortParamKind::Sort, SortParamKind::Sort]),
385                rty::FuncSort::new(
386                    vec![
387                        Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
388                        Var(param0),
389                        Var(param1),
390                    ],
391                    Sort::app(Map, List::from_arr([Var(param0), Var(param1)])),
392                ),
393            )
394        }
395    };
396    Some(sort)
397}
398
399#[derive(Default)]
400pub struct Specs {
401    items: UnordMap<OwnerId, surface::Item>,
402    trait_items: UnordMap<OwnerId, surface::TraitItemFn>,
403    impl_items: UnordMap<OwnerId, surface::ImplItemFn>,
404    pub flux_items_by_parent: FxIndexMap<OwnerId, Vec<surface::FluxItem>>,
405    /// Maps function DefIds to their #[sig(...)] attribute spans (if they have one)
406    spec_attr_spans: UnordMap<DefId, Span>,
407    /// Set of dummy items generated by the extern spec macro we must completely ignore. This is
408    /// not the same as [ignored items] because, for ignored items, we still need to return errors
409    /// for queries and handle them gracefully in order to report them at the use it.
410    ///
411    /// If an item is in this set, all its descendants are also consider dummy (but they may not be
412    /// in the set).
413    ///
414    /// [ignored items]: Specs::ignores
415    dummy_extern: UnordSet<LocalDefId>,
416    extern_id_to_local_id: UnordMap<DefId, LocalDefId>,
417    local_id_to_extern_id: UnordMap<LocalDefId, DefId>,
418}
419
420impl Specs {
421    pub fn insert_extern_spec_id_mapping(
422        &mut self,
423        local_id: LocalDefId,
424        extern_id: DefId,
425    ) -> Result<(), ExternSpecMappingErr> {
426        #[expect(
427            clippy::disallowed_methods,
428            reason = "we are inserting the extern spec mapping and we want to ensure it doesn't point to a local item"
429        )]
430        if let Some(local) = extern_id.as_local() {
431            return Err(ExternSpecMappingErr::IsLocal(local));
432        }
433        if let Err(err) = self.extern_id_to_local_id.try_insert(extern_id, local_id) {
434            return Err(ExternSpecMappingErr::Dup(*err.entry.get()));
435        }
436        self.local_id_to_extern_id.insert(local_id, extern_id);
437        Ok(())
438    }
439
440    pub fn insert_dummy(&mut self, def_id: LocalDefId) {
441        self.dummy_extern.insert(def_id);
442    }
443
444    pub fn set_spec_attr_span(&mut self, def_id: DefId, span: Span) {
445        self.spec_attr_spans.insert(def_id, span);
446    }
447
448    pub fn get_spec_attr_span(&self, def_id: DefId) -> Option<Span> {
449        self.spec_attr_spans.get(&def_id).copied()
450    }
451
452    pub fn get_item(&self, owner_id: OwnerId) -> Option<&surface::Item> {
453        self.items.get(&owner_id)
454    }
455
456    pub fn insert_item(&mut self, owner_id: OwnerId, item: surface::Item) -> Option<surface::Item> {
457        if let Some(old) = self.items.insert(owner_id, item) {
458            return Some(old);
459        }
460        None
461    }
462
463    pub fn get_trait_item(&self, owner_id: OwnerId) -> Option<&surface::TraitItemFn> {
464        self.trait_items.get(&owner_id)
465    }
466
467    pub fn insert_trait_item(
468        &mut self,
469        owner_id: OwnerId,
470        trait_item: surface::TraitItemFn,
471    ) -> Option<surface::TraitItemFn> {
472        if let Some(old) = self.trait_items.insert(owner_id, trait_item) {
473            return Some(old);
474        }
475        None
476    }
477
478    pub fn get_impl_item(&self, owner_id: OwnerId) -> Option<&surface::ImplItemFn> {
479        self.impl_items.get(&owner_id)
480    }
481
482    pub fn insert_impl_item(
483        &mut self,
484        owner_id: OwnerId,
485        impl_item: surface::ImplItemFn,
486    ) -> Option<surface::ImplItemFn> {
487        if let Some(old) = self.impl_items.insert(owner_id, impl_item) {
488            return Some(old);
489        }
490        None
491    }
492}
493
494/// Represents errors that can occur when inserting a mapping between a `LocalDefId` and a `DefId`
495/// for an extern spec.
496pub enum ExternSpecMappingErr {
497    /// Indicates that the [`DefId`] we are trying to add extern specs to is actually local. Returns
498    /// the [`DefId`] as a [`LocalDefId`].
499    IsLocal(LocalDefId),
500
501    /// Indicates that there is an existing extern spec for the given extern id. Returns the existing
502    /// `LocalDefId` that maps to the extern id.
503    ///
504    /// NOTE: This currently only considers extern specs defined in the local crate. There could still
505    /// be duplicates if an extern spec is imported from an external crate. In such cases, the local
506    /// extern spec takes precedence. Probably, we should at least warn about this, but it's a bit
507    /// tricky because we need to look at the crate metadata which we don't have handy when
508    /// collecting specs.
509    Dup(LocalDefId),
510}
511
512#[derive(Default)]
513pub struct ResolverOutput {
514    /// Resolution of type, refinement, and sort paths
515    pub path_res_map: UnordMap<NodeId, fhir::PartialRes<NodeId>>,
516    /// Resolution of explicitly and implicitly scoped parameters. The [`fhir::ParamId`] is unique
517    /// per item. The [`NodeId`] used as the key corresponds to the node introducing the parameter.
518    /// When explicit, this is the id of the [`surface::GenericArg`] or [`surface::RefineParam`],
519    /// when implicit, this is the id of the [`surface::RefineArg::Bind`] or [`surface::FnInput`].
520    pub param_res_map: UnordMap<NodeId, (fhir::ParamId, fhir::ParamKind)>,
521    /// List of implicitly scoped params defined in a scope. The [`NodeId`] used as key is the id of
522    /// the node introducing the scope, e.g., [`surface::FnSig`], [`surface::FnOutput`], or
523    /// [`surface::VariantDef`]. The [`NodeId`]s in the vectors are keys in [`Self::param_res_map`].
524    pub implicit_params: UnordMap<NodeId, Vec<(Ident, NodeId)>>,
525    /// The resolved list of local qualifiers per function.
526    /// The [`NodeId`] corresponds to the [`surface::FnSpec`].
527    pub qualifier_res_map: UnordMap<NodeId, Vec<def_id::FluxLocalDefId>>,
528    /// The resolved list of local reveals per function
529    /// The [`NodeId`] corresponds to the [`surface::FnSpec`].
530    pub reveal_res_map: UnordMap<NodeId, Vec<def_id::FluxDefId>>,
531    /// The resolved type param `DefId`s for `#[assume_parametric(...)]` per function.
532    /// The [`NodeId`] corresponds to the surface item's `node_id`.
533    pub parametric_param_res_map: UnordMap<NodeId, Vec<DefId>>,
534}
535
536#[extension(pub trait PlaceExt)]
537impl flux_rustc_bridge::mir::Place {
538    fn ty(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<PlaceTy> {
539        self.projection
540            .iter()
541            .try_fold(PlaceTy::from_ty(local_decls[self.local].ty.clone()), |place_ty, elem| {
542                place_ty.projection_ty(genv, *elem)
543            })
544    }
545
546    fn behind_raw_ptr(&self, genv: GlobalEnv, local_decls: &LocalDecls) -> QueryResult<bool> {
547        let mut place_ty = PlaceTy::from_ty(local_decls[self.local].ty.clone());
548        for elem in &self.projection {
549            if let (PlaceElem::Deref, ty::TyKind::RawPtr(..)) = (elem, place_ty.ty.kind()) {
550                return Ok(true);
551            }
552            place_ty = place_ty.projection_ty(genv, *elem)?;
553        }
554        Ok(false)
555    }
556}
557
558#[derive(Debug)]
559pub struct PlaceTy {
560    pub ty: ty::Ty,
561    /// Downcast to a particular variant of an enum or a generator, if included.
562    pub variant_index: Option<VariantIdx>,
563}
564
565impl PlaceTy {
566    fn from_ty(ty: ty::Ty) -> PlaceTy {
567        PlaceTy { ty, variant_index: None }
568    }
569
570    fn projection_ty(&self, genv: GlobalEnv, elem: PlaceElem) -> QueryResult<PlaceTy> {
571        if self.variant_index.is_some() && !matches!(elem, PlaceElem::Field(..)) {
572            Err(query_bug!("cannot use non field projection on downcasted place"))?;
573        }
574        let place_ty = match elem {
575            PlaceElem::Deref => PlaceTy::from_ty(self.ty.deref()),
576            PlaceElem::Field(fld) => PlaceTy::from_ty(self.field_ty(genv, fld)?),
577            PlaceElem::Downcast(_, variant_idx) => {
578                PlaceTy { ty: self.ty.clone(), variant_index: Some(variant_idx) }
579            }
580            PlaceElem::Index(_) | PlaceElem::ConstantIndex { .. } => {
581                if let ty::TyKind::Array(ty, _) | ty::TyKind::Slice(ty) = self.ty.kind() {
582                    PlaceTy::from_ty(ty.clone())
583                } else {
584                    return Err(query_bug!("cannot use non field projection on downcasted place"));
585                }
586            }
587        };
588        Ok(place_ty)
589    }
590
591    fn field_ty(&self, genv: GlobalEnv, f: FieldIdx) -> QueryResult<ty::Ty> {
592        match self.ty.kind() {
593            ty::TyKind::Adt(adt_def, args) => {
594                let variant_def = match self.variant_index {
595                    None => adt_def.non_enum_variant(),
596                    Some(variant_index) => {
597                        assert!(adt_def.is_enum());
598                        adt_def.variant(variant_index)
599                    }
600                };
601                let field_def = &variant_def.fields[f];
602                let ty = genv.lower_type_of(field_def.did)?;
603                Ok(ty.subst(args))
604            }
605            ty::TyKind::Tuple(tys) => Ok(tys[f.index()].clone()),
606            ty::TyKind::Closure(_, args) => Ok(args.as_closure().upvar_tys()[f.index()].clone()),
607            _ => Err(query_bug!("extracting field of non-tuple non-adt non-closure: {self:?}")),
608        }
609    }
610}
611
612/// The different reasons we issue fixpoint queries. This is used to dissambiguate queries that
613/// are issued for the same item.
614///
615/// NOTE: This is defined here because it's also used in [`metrics`]
616#[derive(Debug, Hash, Clone, Copy)]
617pub enum FixpointQueryKind {
618    /// Query issued when checking an impl method is a subtype of the trait
619    Impl,
620    /// Query issued to check the body of a function
621    Body,
622    /// Query issued to check an (enum) invariant is implied by the type definition
623    Invariant,
624}
625
626impl FixpointQueryKind {
627    pub fn ext(self) -> &'static str {
628        match self {
629            FixpointQueryKind::Impl => "sub.fluxc",
630            FixpointQueryKind::Body => "fluxc",
631            FixpointQueryKind::Invariant => "fluxc",
632        }
633    }
634
635    /// A string that uniquely identifies a query given an item `DefId`
636    pub fn task_key(self, tcx: TyCtxt, def_id: DefId) -> String {
637        format!("{}###{:?}", tcx.def_path_str(def_id), self)
638    }
639
640    /// Returns `true` if the fixpoint query kind is [`Body`].
641    ///
642    /// [`Body`]: FixpointQueryKind::Body
643    #[must_use]
644    pub fn is_body(&self) -> bool {
645        matches!(self, Self::Body)
646    }
647}