Skip to main content

flux_middle/
fhir.rs

1//! Flux High-Level Intermediate Representation
2//!
3//! The fhir corresponds to the desugared version of source level flux annotations. The main
4//! difference with the surface syntax is that the list of refinement parameters is explicit
5//! in fhir. For example, the following signature
6//!
7//! `fn(x: &strg i32[@n]) ensures x: i32[n + 1]`
8//!
9//! desugars to
10//!
11//! `for<n: int, l: loc> fn(&strg<l: i32[n]>) ensures l: i32[n + 1]`.
12//!
13//! The name fhir is borrowed (pun intended) from rustc's hir to refer to something a bit lower
14//! than the surface syntax.
15
16pub mod visit;
17
18use std::{borrow::Cow, fmt, iter};
19
20use flux_common::{bug, span_bug};
21use flux_config::PartialInferOpts;
22pub use flux_syntax::surface::{BinOp, UnOp};
23use flux_syntax::{
24    surface::{self, Ignored, Trusted},
25    symbols::sym,
26};
27use itertools::Itertools;
28use rustc_abi;
29pub use rustc_abi::VariantIdx;
30use rustc_ast::TraitObjectSyntax;
31use rustc_data_structures::{
32    fx::{FxIndexMap, FxIndexSet},
33    unord::UnordMap,
34};
35pub use rustc_hir::PrimTy;
36use rustc_hir::{
37    FnHeader, OwnerId, ParamName, Safety,
38    def::DefKind,
39    def_id::{DefId, LocalDefId},
40};
41use rustc_index::newtype_index;
42use rustc_macros::{Decodable, Encodable};
43pub use rustc_middle::mir::Mutability;
44use rustc_middle::ty::TyCtxt;
45use rustc_span::{ErrorGuaranteed, Span, Symbol, symbol::Ident};
46
47use crate::{
48    def_id::{FluxDefId, FluxLocalDefId, MaybeExternId},
49    global_env::GlobalEnv,
50    rty::QualifierKind,
51};
52
53pub enum Attr {
54    Trusted(Trusted),
55    TrustedImpl(Trusted),
56    Ignore(Ignored),
57    ProvenExternally(Span),
58    ShouldFail,
59    InferOpts(PartialInferOpts),
60    NoPanic,
61    NoSuggestions,
62}
63
64#[derive(Clone, Copy, Default)]
65pub struct AttrMap<'fhir> {
66    pub attrs: &'fhir [Attr],
67    pub qualifiers: &'fhir [FluxLocalDefId],
68    pub reveals: &'fhir [FluxDefId],
69    /// The `DefId`s of type params listed in `#[assume_parametric(...)]`. They match
70    /// the `DefId` entries in `generics_of(callee_id)`. These are `DefId`s and not
71    /// `LocalDefId`s such that they are correct for extern specs as well.
72    pub parametric_params: &'fhir [DefId],
73}
74
75impl AttrMap<'_> {
76    pub(crate) fn proven_externally(&self) -> Option<Span> {
77        self.attrs.iter().find_map(|attr| {
78            if let Attr::ProvenExternally(span) = *attr { Some(span) } else { None }
79        })
80    }
81
82    pub(crate) fn ignored(&self) -> Option<Ignored> {
83        self.attrs
84            .iter()
85            .find_map(|attr| if let Attr::Ignore(ignored) = *attr { Some(ignored) } else { None })
86    }
87
88    pub(crate) fn trusted(&self) -> Option<Trusted> {
89        self.attrs
90            .iter()
91            .find_map(|attr| if let Attr::Trusted(trusted) = *attr { Some(trusted) } else { None })
92    }
93
94    pub(crate) fn trusted_impl(&self) -> Option<Trusted> {
95        self.attrs.iter().find_map(|attr| {
96            if let Attr::TrustedImpl(trusted) = *attr { Some(trusted) } else { None }
97        })
98    }
99
100    pub(crate) fn should_fail(&self) -> bool {
101        self.attrs
102            .iter()
103            .any(|attr| matches!(attr, Attr::ShouldFail))
104    }
105
106    pub(crate) fn infer_opts(&self) -> Option<PartialInferOpts> {
107        self.attrs
108            .iter()
109            .find_map(|attr| if let Attr::InferOpts(opts) = *attr { Some(opts) } else { None })
110    }
111
112    pub(crate) fn no_panic(&self) -> bool {
113        self.attrs.iter().any(|attr| matches!(attr, Attr::NoPanic))
114    }
115
116    pub(crate) fn parametric_params(&self) -> &[DefId] {
117        self.parametric_params
118    }
119
120    pub(crate) fn no_suggestions(&self) -> bool {
121        self.attrs
122            .iter()
123            .any(|attr| matches!(attr, Attr::NoSuggestions))
124    }
125}
126
127#[derive(Debug, Clone, Copy)]
128pub struct Generics<'fhir> {
129    pub params: &'fhir [GenericParam<'fhir>],
130    pub refinement_params: &'fhir [RefineParam<'fhir>],
131    pub predicates: Option<&'fhir [WhereBoundPredicate<'fhir>]>,
132}
133
134#[derive(Debug, Clone, Copy)]
135pub struct GenericParam<'fhir> {
136    pub def_id: MaybeExternId,
137    pub name: ParamName,
138    pub kind: GenericParamKind<'fhir>,
139}
140
141#[derive(Debug, Clone, Copy)]
142pub enum GenericParamKind<'fhir> {
143    Type { default: Option<Ty<'fhir>> },
144    Lifetime,
145    Const { ty: Ty<'fhir> },
146}
147
148#[derive(Debug)]
149pub struct Qualifier<'fhir> {
150    pub def_id: FluxLocalDefId,
151    pub args: &'fhir [RefineParam<'fhir>],
152    pub expr: Expr<'fhir>,
153    pub kind: QualifierKind,
154}
155
156#[derive(Clone, Copy, Debug)]
157pub enum Node<'fhir> {
158    Item(&'fhir Item<'fhir>),
159    TraitItem(&'fhir TraitItem<'fhir>),
160    ImplItem(&'fhir ImplItem<'fhir>),
161    OpaqueTy(&'fhir OpaqueTy<'fhir>),
162    ForeignItem(&'fhir ForeignItem<'fhir>),
163    Ctor,
164    AnonConst,
165    Expr,
166}
167
168impl<'fhir> Node<'fhir> {
169    pub fn as_owner(self) -> Option<OwnerNode<'fhir>> {
170        match self {
171            Node::Item(item) => Some(OwnerNode::Item(item)),
172            Node::TraitItem(trait_item) => Some(OwnerNode::TraitItem(trait_item)),
173            Node::ImplItem(impl_item) => Some(OwnerNode::ImplItem(impl_item)),
174            Node::ForeignItem(foreign_item) => Some(OwnerNode::ForeignItem(foreign_item)),
175            Node::OpaqueTy(_) | Node::AnonConst | Node::Expr | Node::Ctor => None,
176        }
177    }
178
179    pub fn expect_opaque_ty(&self) -> &'fhir OpaqueTy<'fhir> {
180        if let Node::OpaqueTy(opaque_ty) = &self { opaque_ty } else { bug!("expected opaque type") }
181    }
182}
183
184#[derive(Clone, Copy, Debug)]
185pub enum OwnerNode<'fhir> {
186    Item(&'fhir Item<'fhir>),
187    TraitItem(&'fhir TraitItem<'fhir>),
188    ImplItem(&'fhir ImplItem<'fhir>),
189    ForeignItem(&'fhir ForeignItem<'fhir>),
190}
191
192impl<'fhir> OwnerNode<'fhir> {
193    pub fn fn_sig(&self) -> Option<&'fhir FnSig<'fhir>> {
194        match self {
195            OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, ..), .. })
196            | OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig), .. })
197            | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig), .. })
198            | OwnerNode::ForeignItem(ForeignItem {
199                kind: ForeignItemKind::Fn(fn_sig, ..), ..
200            }) => Some(fn_sig),
201            _ => None,
202        }
203    }
204
205    pub fn generics(self) -> &'fhir Generics<'fhir> {
206        match self {
207            OwnerNode::Item(item) => &item.generics,
208            OwnerNode::TraitItem(trait_item) => &trait_item.generics,
209            OwnerNode::ImplItem(impl_item) => &impl_item.generics,
210            OwnerNode::ForeignItem(foreign_item) => {
211                match foreign_item.kind {
212                    ForeignItemKind::Fn(.., generics) | ForeignItemKind::Static(.., generics) => {
213                        generics
214                    }
215                }
216            }
217        }
218    }
219
220    pub fn owner_id(&self) -> MaybeExternId<OwnerId> {
221        match self {
222            OwnerNode::Item(item) => item.owner_id,
223            OwnerNode::TraitItem(trait_item) => trait_item.owner_id,
224            OwnerNode::ImplItem(impl_item) => impl_item.owner_id,
225            OwnerNode::ForeignItem(foreign_item) => foreign_item.owner_id,
226        }
227    }
228}
229
230#[derive(Debug)]
231pub struct Item<'fhir> {
232    pub owner_id: MaybeExternId<OwnerId>,
233    pub generics: Generics<'fhir>,
234    pub kind: ItemKind<'fhir>,
235}
236
237impl<'fhir> Item<'fhir> {
238    pub fn expect_enum(&self) -> &EnumDef<'fhir> {
239        if let ItemKind::Enum(enum_def) = &self.kind { enum_def } else { bug!("expected enum") }
240    }
241
242    pub fn expect_struct(&self) -> &StructDef<'fhir> {
243        if let ItemKind::Struct(struct_def) = &self.kind {
244            struct_def
245        } else {
246            bug!("expected struct")
247        }
248    }
249
250    pub fn expect_type_alias(&self) -> &TyAlias<'fhir> {
251        if let ItemKind::TyAlias(ty_alias) = &self.kind {
252            ty_alias
253        } else {
254            bug!("expected type alias")
255        }
256    }
257
258    pub fn expect_impl(&self) -> &Impl<'fhir> {
259        if let ItemKind::Impl(impl_) = &self.kind { impl_ } else { bug!("expected impl") }
260    }
261
262    pub fn expect_trait(&self) -> &Trait<'fhir> {
263        if let ItemKind::Trait(trait_) = &self.kind { trait_ } else { bug!("expected trait") }
264    }
265}
266
267#[derive(Debug)]
268pub enum ItemKind<'fhir> {
269    Enum(EnumDef<'fhir>),
270    Struct(StructDef<'fhir>),
271    TyAlias(&'fhir TyAlias<'fhir>),
272    Trait(Trait<'fhir>),
273    Impl(Impl<'fhir>),
274    Fn(FnSig<'fhir>),
275    Const(Option<Expr<'fhir>>),
276    Static(Option<Ty<'fhir>>),
277}
278
279#[derive(Debug)]
280pub struct TraitItem<'fhir> {
281    pub owner_id: MaybeExternId<OwnerId>,
282    pub generics: Generics<'fhir>,
283    pub kind: TraitItemKind<'fhir>,
284}
285
286#[derive(Debug)]
287pub enum TraitItemKind<'fhir> {
288    Fn(FnSig<'fhir>),
289    Const,
290    Type,
291}
292
293#[derive(Debug)]
294pub struct ImplItem<'fhir> {
295    pub owner_id: MaybeExternId<OwnerId>,
296    pub kind: ImplItemKind<'fhir>,
297    pub generics: Generics<'fhir>,
298}
299
300#[derive(Debug)]
301pub enum ImplItemKind<'fhir> {
302    Fn(FnSig<'fhir>),
303    Const,
304    Type,
305}
306
307#[derive(Copy, Clone, Debug)]
308pub enum FluxItem<'fhir> {
309    Qualifier(&'fhir Qualifier<'fhir>),
310    Func(&'fhir SpecFunc<'fhir>),
311    PrimOpProp(&'fhir PrimOpProp<'fhir>),
312    SortDecl(&'fhir SortDecl),
313}
314
315impl FluxItem<'_> {
316    pub fn def_id(self) -> FluxLocalDefId {
317        match self {
318            FluxItem::Qualifier(qualifier) => qualifier.def_id,
319            FluxItem::Func(func) => func.def_id,
320            FluxItem::PrimOpProp(prop) => prop.def_id,
321            FluxItem::SortDecl(sort_decl) => sort_decl.def_id,
322        }
323    }
324}
325
326#[derive(Debug)]
327pub struct ForeignItem<'fhir> {
328    pub ident: Ident,
329    pub kind: ForeignItemKind<'fhir>,
330    pub owner_id: MaybeExternId<OwnerId>,
331    pub span: Span,
332}
333
334#[derive(Debug)]
335pub enum ForeignItemKind<'fhir> {
336    Fn(FnSig<'fhir>, &'fhir Generics<'fhir>),
337    Static(Ty<'fhir>, Mutability, Safety, &'fhir Generics<'fhir>),
338}
339
340#[derive(Debug, Clone, Copy)]
341pub struct SortDecl {
342    pub def_id: FluxLocalDefId,
343    pub params: usize,
344    pub span: Span,
345}
346
347pub type SortDecls = UnordMap<Symbol, SortDecl>;
348
349#[derive(Debug, Clone, Copy)]
350pub struct WhereBoundPredicate<'fhir> {
351    pub span: Span,
352    pub bounded_ty: Ty<'fhir>,
353    pub bounds: GenericBounds<'fhir>,
354}
355
356pub type GenericBounds<'fhir> = &'fhir [GenericBound<'fhir>];
357
358#[derive(Debug, Clone, Copy)]
359pub enum GenericBound<'fhir> {
360    Trait(PolyTraitRef<'fhir>),
361    Outlives(Lifetime),
362}
363
364#[derive(Debug, Clone, Copy)]
365pub struct PolyTraitRef<'fhir> {
366    pub bound_generic_params: &'fhir [GenericParam<'fhir>],
367    /// To represent binders for closures i.e. in Fn* traits; see tests/pos/surface/closure{07,08,09,10}.rs
368    pub refine_params: &'fhir [RefineParam<'fhir>],
369    pub modifiers: TraitBoundModifier,
370    pub trait_ref: Path<'fhir>,
371    pub span: Span,
372}
373
374#[derive(Debug, Copy, Clone)]
375pub enum TraitBoundModifier {
376    None,
377    Maybe,
378}
379
380#[derive(Debug)]
381pub struct Trait<'fhir> {
382    pub assoc_refinements: &'fhir [TraitAssocReft<'fhir>],
383}
384
385impl<'fhir> Trait<'fhir> {
386    pub fn find_assoc_reft(&self, name: Symbol) -> Option<&'fhir TraitAssocReft<'fhir>> {
387        self.assoc_refinements
388            .iter()
389            .find(|assoc_reft| assoc_reft.name == name)
390    }
391}
392
393#[derive(Debug, Clone, Copy)]
394pub struct TraitAssocReft<'fhir> {
395    pub name: Symbol,
396    pub params: &'fhir [RefineParam<'fhir>],
397    pub output: Sort<'fhir>,
398    pub body: Option<Expr<'fhir>>,
399    pub span: Span,
400    pub final_: bool,
401}
402
403#[derive(Debug)]
404pub struct Impl<'fhir> {
405    pub assoc_refinements: &'fhir [ImplAssocReft<'fhir>],
406}
407
408impl<'fhir> Impl<'fhir> {
409    pub fn find_assoc_reft(&self, name: Symbol) -> Option<&'fhir ImplAssocReft<'fhir>> {
410        self.assoc_refinements
411            .iter()
412            .find(|assoc_reft| assoc_reft.name == name)
413    }
414}
415
416#[derive(Clone, Copy, Debug)]
417pub struct ImplAssocReft<'fhir> {
418    pub name: Symbol,
419    pub params: &'fhir [RefineParam<'fhir>],
420    pub output: Sort<'fhir>,
421    pub body: Expr<'fhir>,
422    pub span: Span,
423}
424
425#[derive(Debug)]
426pub struct OpaqueTy<'fhir> {
427    pub def_id: MaybeExternId,
428    pub bounds: GenericBounds<'fhir>,
429}
430
431pub type Arena = bumpalo::Bump;
432
433/// A map between rust definitions and flux annotations in their desugared `fhir` form.
434///
435/// note: most items in this struct have been moved out into their own query or method in genv.
436/// We should eventually get rid of this or change its name.
437#[derive(Default)]
438pub struct FluxItems<'fhir> {
439    pub items: FxIndexMap<FluxLocalDefId, FluxItem<'fhir>>,
440}
441
442impl FluxItems<'_> {
443    pub fn new() -> Self {
444        Self { items: Default::default() }
445    }
446}
447
448#[derive(Debug)]
449pub struct TyAlias<'fhir> {
450    pub index: Option<RefineParam<'fhir>>,
451    pub ty: Ty<'fhir>,
452    pub span: Span,
453    /// Whether this alias was lifted from a `hir` alias
454    pub lifted: bool,
455}
456
457#[derive(Debug, Clone, Copy)]
458pub struct StructDef<'fhir> {
459    pub refinement: &'fhir RefinementKind<'fhir>,
460    pub params: &'fhir [RefineParam<'fhir>],
461    pub kind: StructKind<'fhir>,
462    pub invariants: &'fhir [Expr<'fhir>],
463}
464
465#[derive(Debug, Clone, Copy)]
466pub enum StructKind<'fhir> {
467    Transparent { fields: &'fhir [FieldDef<'fhir>] },
468    Opaque,
469}
470
471#[derive(Debug, Clone, Copy)]
472pub struct FieldDef<'fhir> {
473    pub ty: Ty<'fhir>,
474    /// Whether this field was lifted from a `hir` field
475    pub lifted: bool,
476}
477
478#[derive(Debug)]
479pub enum RefinementKind<'fhir> {
480    /// User specified indices (e.g. length, elems, etc.)
481    Refined(RefinedBy<'fhir>),
482    /// Singleton refinements e.g. `State[On]`, `State[Off]`
483    Reflected,
484}
485
486impl RefinementKind<'_> {
487    pub fn is_reflected(&self) -> bool {
488        matches!(self, RefinementKind::Reflected)
489    }
490}
491
492#[derive(Debug)]
493pub struct EnumDef<'fhir> {
494    pub refinement: &'fhir RefinementKind<'fhir>,
495    pub params: &'fhir [RefineParam<'fhir>],
496    pub variants: &'fhir [VariantDef<'fhir>],
497    pub invariants: &'fhir [Expr<'fhir>],
498}
499
500#[derive(Debug, Clone, Copy)]
501pub struct VariantDef<'fhir> {
502    pub def_id: LocalDefId,
503    pub params: &'fhir [RefineParam<'fhir>],
504    pub fields: &'fhir [FieldDef<'fhir>],
505    pub ret: VariantRet<'fhir>,
506    pub span: Span,
507    /// Whether this variant was lifted from a hir variant
508    pub lifted: bool,
509}
510
511#[derive(Debug, Clone, Copy)]
512pub struct VariantRet<'fhir> {
513    pub enum_id: DefId,
514    pub idx: Expr<'fhir>,
515}
516
517#[derive(Clone, Copy)]
518pub struct FnDecl<'fhir> {
519    pub requires: &'fhir [Requires<'fhir>],
520    pub inputs: &'fhir [Ty<'fhir>],
521    pub output: FnOutput<'fhir>,
522    pub span: Span,
523    /// Whether the sig was lifted from a hir signature
524    pub lifted: bool,
525}
526
527/// A predicate required to hold before calling a function.
528#[derive(Clone, Copy)]
529pub struct Requires<'fhir> {
530    /// An (optional) list of universally quantified parameters
531    pub params: &'fhir [RefineParam<'fhir>],
532    pub pred: Expr<'fhir>,
533}
534
535#[derive(Clone, Copy)]
536pub struct FnSig<'fhir> {
537    pub header: FnHeader,
538    pub decl: &'fhir FnDecl<'fhir>,
539    pub no_panic_if: Option<Expr<'fhir>>,
540}
541
542#[derive(Clone, Copy)]
543pub struct FnOutput<'fhir> {
544    pub params: &'fhir [RefineParam<'fhir>],
545    pub ret: Ty<'fhir>,
546    pub ensures: &'fhir [Ensures<'fhir>],
547}
548
549#[derive(Clone, Copy)]
550pub enum Ensures<'fhir> {
551    /// A type constraint on a location
552    Type(PathExpr<'fhir>, &'fhir Ty<'fhir>),
553    /// A predicate that needs to hold on function exit
554    Pred(Expr<'fhir>),
555}
556
557#[derive(Clone, Copy)]
558pub struct Ty<'fhir> {
559    pub kind: TyKind<'fhir>,
560    pub span: Span,
561}
562
563#[derive(Clone, Copy)]
564pub enum TyKind<'fhir> {
565    /// A type that parses as a [`BaseTy`] but was written without refinements. Most types in
566    /// this category are base types and will be converted into an [existential], e.g., `i32` is
567    /// converted into `∃v:int. i32[v]`. However, this category also contains generic variables
568    /// of kind [type]. We cannot distinguish these syntactially so we resolve them later in the
569    /// analysis.
570    ///
571    /// [existential]: crate::rty::TyKind::Exists
572    /// [type]: GenericParamKind::Type
573    BaseTy(BaseTy<'fhir>),
574    Indexed(BaseTy<'fhir>, Expr<'fhir>),
575    Exists(&'fhir [RefineParam<'fhir>], &'fhir Ty<'fhir>),
576    /// Constrained types `{T | p}` are like existentials but without binders, and are useful
577    /// for specifying constraints on indexed values e.g. `{i32[@a] | 0 <= a}`
578    Constr(Expr<'fhir>, &'fhir Ty<'fhir>),
579    StrgRef(Lifetime, &'fhir PathExpr<'fhir>, &'fhir Ty<'fhir>),
580    Ref(Lifetime, MutTy<'fhir>),
581    BareFn(&'fhir BareFnTy<'fhir>),
582    Tuple(&'fhir [Ty<'fhir>]),
583    Array(&'fhir Ty<'fhir>, ConstArg),
584    OpaqueDef(&'fhir OpaqueTy<'fhir>),
585    TraitObject(&'fhir [PolyTraitRef<'fhir>], Lifetime, TraitObjectSyntax),
586    Never,
587    Infer,
588    Err(ErrorGuaranteed),
589}
590
591pub struct BareFnTy<'fhir> {
592    pub safety: Safety,
593    pub abi: rustc_abi::ExternAbi,
594    pub generic_params: &'fhir [GenericParam<'fhir>],
595    pub decl: &'fhir FnDecl<'fhir>,
596    pub param_idents: &'fhir [Option<Ident>],
597}
598
599#[derive(Clone, Copy)]
600pub struct MutTy<'fhir> {
601    pub ty: &'fhir Ty<'fhir>,
602    pub mutbl: Mutability,
603}
604
605/// Our surface syntax doesn't have lifetimes. To deal with them we create a *hole* for every lifetime
606/// which we then resolve when we check for structural compatibility against the rust type.
607// This struct usede to be an enum with an extra variant carrying a `resolve_bound_vars::ResolvedArg`
608// that we lifted from `hir`, but we simplified tto just a struct to treat all lifetimes uniformely.
609// We are currently not using the `FirHid` so we could potentially remove the struct and remove
610// lifetime from fhir syntax, but we keep it here to mark places in fhir where there ought to be a
611// lifetime.
612#[derive(Copy, Clone, PartialEq, Eq)]
613pub struct Lifetime(pub FhirId);
614
615/// Owner version of [`FluxLocalDefId`]
616#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Encodable, Decodable)]
617pub enum FluxOwnerId {
618    Flux(FluxLocalDefId),
619    Rust(MaybeExternId<OwnerId>),
620}
621
622impl FluxOwnerId {
623    pub fn as_rust(self) -> Option<MaybeExternId<OwnerId>> {
624        match self {
625            FluxOwnerId::Flux(_) => None,
626            FluxOwnerId::Rust(owner_id) => Some(owner_id),
627        }
628    }
629
630    pub fn resolved_id(self) -> Option<DefId> {
631        self.as_rust().map(MaybeExternId::resolved_id)
632    }
633}
634
635/// A unique identifier for a node in the AST. Like [`HirId`] it is composed of an `owner` and a
636/// `local_id`. We don't generate ids for all nodes, but only for those we need to remember
637/// information elaborated during well-formedness checking to later be used during conversion into
638/// [`rty`].
639///
640/// [`rty`]: crate::rty
641/// [`HirId`]: rustc_hir::HirId
642#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone, Encodable, Decodable)]
643pub struct FhirId {
644    pub owner: FluxOwnerId,
645    pub local_id: ItemLocalId,
646}
647
648newtype_index! {
649    /// An `ItemLocalId` uniquely identifies something within a given "item-like".
650    #[encodable]
651    pub struct ItemLocalId {}
652}
653
654/// These are types of things that may be refined with indices or existentials
655#[derive(Clone, Copy)]
656pub struct BaseTy<'fhir> {
657    pub kind: BaseTyKind<'fhir>,
658    pub fhir_id: FhirId,
659    pub span: Span,
660}
661
662impl<'fhir> BaseTy<'fhir> {
663    pub fn from_qpath(qpath: QPath<'fhir>, fhir_id: FhirId) -> Self {
664        let span = qpath.span();
665        Self { kind: BaseTyKind::Path(qpath), fhir_id, span }
666    }
667
668    fn as_path(&self) -> Option<Path<'fhir>> {
669        match self.kind {
670            BaseTyKind::Path(QPath::Resolved(None, path)) => Some(path),
671            _ => None,
672        }
673    }
674}
675
676#[derive(Clone, Copy)]
677pub enum BaseTyKind<'fhir> {
678    Path(QPath<'fhir>),
679    Slice(&'fhir Ty<'fhir>),
680    RawPtr(&'fhir Ty<'fhir>, Mutability),
681    Err(ErrorGuaranteed),
682}
683
684#[derive(Clone, Copy)]
685pub enum QPath<'fhir> {
686    Resolved(Option<&'fhir Ty<'fhir>>, Path<'fhir>),
687    TypeRelative(&'fhir Ty<'fhir>, &'fhir PathSegment<'fhir>),
688}
689
690#[derive(Clone, Copy)]
691pub struct Path<'fhir> {
692    pub res: Res,
693    pub fhir_id: FhirId,
694    pub segments: &'fhir [PathSegment<'fhir>],
695    pub refine: &'fhir [Expr<'fhir>],
696    pub span: Span,
697}
698
699impl<'fhir> Path<'fhir> {
700    pub fn last_segment(&self) -> &'fhir PathSegment<'fhir> {
701        self.segments.last().unwrap()
702    }
703}
704
705#[derive(Clone, Copy)]
706pub struct PathSegment<'fhir> {
707    pub ident: Ident,
708    pub res: Res,
709    pub args: &'fhir [GenericArg<'fhir>],
710    pub constraints: &'fhir [AssocItemConstraint<'fhir>],
711}
712
713#[derive(Clone, Copy)]
714pub struct AssocItemConstraint<'fhir> {
715    pub ident: Ident,
716    pub kind: AssocItemConstraintKind<'fhir>,
717}
718
719#[derive(Clone, Copy)]
720pub enum AssocItemConstraintKind<'fhir> {
721    Equality { term: Ty<'fhir> },
722}
723
724#[derive(Clone, Copy)]
725pub enum GenericArg<'fhir> {
726    Lifetime(Lifetime),
727    Type(&'fhir Ty<'fhir>),
728    Const(ConstArg),
729    Infer,
730}
731
732impl<'fhir> GenericArg<'fhir> {
733    pub fn expect_type(&self) -> &'fhir Ty<'fhir> {
734        if let GenericArg::Type(ty) = self { ty } else { bug!("expected `GenericArg::Type`") }
735    }
736}
737
738#[derive(PartialEq, Eq, Clone, Copy)]
739pub struct ConstArg {
740    pub kind: ConstArgKind,
741    pub span: Span,
742}
743
744#[derive(PartialEq, Eq, Clone, Copy)]
745pub enum ConstArgKind {
746    Lit(usize),
747    Param(DefId),
748    Infer,
749}
750
751/// Different kinds of symbols can coexist even if they share the same textual name.
752/// Therefore, they each have a separate universe (known as a "namespace").
753#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
754pub enum Namespace {
755    /// We also put sorts in this namespace.
756    ///
757    /// See [`rustc_hir::def::Namespace::TypeNS`]
758    TypeNS,
759    /// See [`rustc_hir::def::Namespace::ValueNS`]
760    ValueNS,
761    /// See [`rustc_hir::def::Namespace::MacroNS`]
762    MacroNS,
763    /// The refinement namespace includes refinement functions, theory function,
764    /// refinement parameters, ...
765    ReftNS,
766}
767
768impl Namespace {
769    /// A human-readable description, used in diagnostics.
770    pub fn descr(self) -> &'static str {
771        match self {
772            Namespace::TypeNS => "type",
773            Namespace::ValueNS => "value",
774            Namespace::MacroNS => "macro",
775            Namespace::ReftNS => "value",
776        }
777    }
778
779    /// The corresponding [`rustc_hir::def::Namespace`], or `None` for the flux-only namespaces.
780    pub fn to_rustc(self) -> Option<rustc_hir::def::Namespace> {
781        match self {
782            Namespace::TypeNS => Some(rustc_hir::def::Namespace::TypeNS),
783            Namespace::ValueNS => Some(rustc_hir::def::Namespace::ValueNS),
784            Namespace::MacroNS => Some(rustc_hir::def::Namespace::MacroNS),
785            Namespace::ReftNS => None,
786        }
787    }
788}
789
790impl From<rustc_hir::def::Namespace> for Namespace {
791    fn from(ns: rustc_hir::def::Namespace) -> Self {
792        match ns {
793            rustc_hir::def::Namespace::TypeNS => Namespace::TypeNS,
794            rustc_hir::def::Namespace::ValueNS => Namespace::ValueNS,
795            rustc_hir::def::Namespace::MacroNS => Namespace::MacroNS,
796        }
797    }
798}
799
800/// Flux's analogue of [`rustc_hir::def::PerNS`], carrying one `T` per [`Namespace`] (including the
801/// flux-specific ones), indexable by [`Namespace`].
802#[derive(Debug, Clone)]
803pub struct PerNS<T> {
804    pub type_ns: T,
805    pub value_ns: T,
806    pub macro_ns: T,
807    pub flux_fn_ns: T,
808}
809
810impl<T> std::ops::Index<Namespace> for PerNS<T> {
811    type Output = T;
812
813    fn index(&self, ns: Namespace) -> &T {
814        match ns {
815            Namespace::TypeNS => &self.type_ns,
816            Namespace::ValueNS => &self.value_ns,
817            Namespace::MacroNS => &self.macro_ns,
818            Namespace::ReftNS => &self.flux_fn_ns,
819        }
820    }
821}
822
823impl<T> std::ops::IndexMut<Namespace> for PerNS<T> {
824    fn index_mut(&mut self, ns: Namespace) -> &mut T {
825        match ns {
826            Namespace::TypeNS => &mut self.type_ns,
827            Namespace::ValueNS => &mut self.value_ns,
828            Namespace::MacroNS => &mut self.macro_ns,
829            Namespace::ReftNS => &mut self.flux_fn_ns,
830        }
831    }
832}
833
834/// The resolution of a path
835///
836/// The enum contains a subset of the variants in [`rustc_hir::def::Res`] plus some extra variants
837/// for stuff refinements resolve to.
838#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable)]
839pub enum Res<Id = ParamId> {
840    /// See [`rustc_hir::def::Res::Def`]
841    Def(DefKind, DefId),
842    /// See [`rustc_hir::def::Res::PrimTy`]
843    PrimTy(PrimTy),
844    /// See [`rustc_hir::def::Res::SelfTyAlias`]
845    SelfTyAlias {
846        alias_to: DefId,
847        is_trait_impl: bool,
848    },
849    /// See [`rustc_hir::def::Res::SelfTyParam`]
850    SelfTyParam {
851        trait_: DefId,
852    },
853    /// A refinement parameter, e.g., declared with `@n` syntax
854    Param(ParamKind, Id),
855    /// A refinement function defined with `flux::defs! { ... }`
856    GlobalFunc(SpecFuncKind),
857    /// A primitive sort, e.g., `int`, `bool`, `Set`, `Map`.
858    PrimSort(PrimSort),
859    /// A sort parameter inside a polymorphic function or data sort.
860    SortParam(usize),
861    /// A user declared sort.
862    UserSort(FluxDefId),
863    Err,
864}
865
866/// Akin to `rustc_middle::metadata::ModChild` but for flux items defined in a module
867#[derive(Debug, Clone, Copy, Encodable, Decodable)]
868pub struct FluxModChild {
869    pub ident: Ident,
870    pub res: Res<!>,
871}
872
873/// See [`rustc_hir::def::PartialRes`]
874#[derive(Copy, Clone, Debug)]
875pub struct PartialRes<Id = ParamId> {
876    base_res: Res<Id>,
877    unresolved_segments: usize,
878}
879
880impl<Id: Copy> PartialRes<Id> {
881    pub fn new(base_res: Res<Id>) -> Self {
882        Self { base_res, unresolved_segments: 0 }
883    }
884
885    pub fn with_unresolved_segments(base_res: Res<Id>, unresolved_segments: usize) -> Self {
886        Self { base_res, unresolved_segments }
887    }
888
889    #[inline]
890    pub fn base_res(&self) -> Res<Id> {
891        self.base_res
892    }
893
894    pub fn unresolved_segments(&self) -> usize {
895        self.unresolved_segments
896    }
897
898    #[inline]
899    pub fn full_res(&self) -> Option<Res<Id>> {
900        (self.unresolved_segments == 0).then_some(self.base_res)
901    }
902
903    #[inline]
904    pub fn expect_full_res(&self) -> Res<Id> {
905        self.full_res().unwrap_or_else(|| bug!("expected full res"))
906    }
907
908    pub fn is_box(&self, tcx: TyCtxt) -> bool {
909        self.full_res().is_some_and(|res| res.is_box(tcx))
910    }
911
912    pub fn map_param_id<R>(&self, f: impl FnOnce(Id) -> R) -> PartialRes<R> {
913        PartialRes {
914            base_res: self.base_res.map_param_id(f),
915            unresolved_segments: self.unresolved_segments,
916        }
917    }
918}
919
920#[derive(Debug, Clone, Copy)]
921pub struct RefineParam<'fhir> {
922    pub id: ParamId,
923    pub name: Symbol,
924    pub span: Span,
925    pub sort: Sort<'fhir>,
926    pub kind: ParamKind,
927    pub fhir_id: FhirId,
928}
929
930#[derive(Clone, Copy, Debug, PartialEq, Eq, Encodable, Decodable)]
931pub enum ParamMode {
932    Horn,
933    Hindley,
934}
935
936impl From<surface::ParamMode> for ParamMode {
937    fn from(value: surface::ParamMode) -> Self {
938        match value {
939            surface::ParamMode::Horn => Self::Horn,
940            surface::ParamMode::Hindley => Self::Hindley,
941        }
942    }
943}
944
945/// How a parameter was declared in the surface syntax.
946#[derive(PartialEq, Eq, Debug, Clone, Copy, Encodable, Decodable)]
947pub enum ParamKind {
948    /// A parameter declared in an explicit scope, e.g., `fn foo[hdl n: int](x: i32[n])`
949    Explicit(Option<ParamMode>),
950    /// An implicitly scoped parameter declared with `@a` syntax
951    At,
952    /// An implicitly scoped parameter declared with `#a` syntax
953    Pound,
954    /// An implicitly scoped parameter declared with `x: T` syntax.
955    Colon,
956    /// A location declared with `x: &strg T` syntax.
957    Loc,
958    /// A parameter introduced with `x: T` syntax that we know *syntactically* is always and error
959    /// to use inside a refinement. For example, consider the following:
960    /// ```ignore
961    /// fn(x: {v. i32[v] | v > 0}) -> i32[x]
962    /// ```
963    /// In this definition, we know syntactically that `x` binds to a non-base type so it's an error
964    /// to use `x` as an index in the return type.
965    ///
966    /// These parameters should not appear in a desugared item and we only track them during name
967    /// resolution to report errors at the use site.
968    Error,
969}
970
971impl ParamKind {
972    pub fn is_loc(&self) -> bool {
973        matches!(self, ParamKind::Loc)
974    }
975}
976
977/// *Infer*ence *mode* for a parameter.
978#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
979pub enum InferMode {
980    /// Generate a fresh evar for the parameter and solve it via syntactic unification. The parameter
981    /// must appear at least once as an index for unification to succeed, but otherwise it can appear
982    /// (mostly) freely.
983    EVar,
984    /// Generate a fresh kvar and let fixpoint infer it. This mode can only be used with abstract
985    /// refinement predicates. If the parameter is marked as kvar then it can only appear in
986    /// positions that will result in a _horn_ constraint as required by fixpoint.
987    KVar,
988}
989
990impl InferMode {
991    pub fn from_param_kind(kind: ParamKind) -> InferMode {
992        if let ParamKind::Explicit(Some(ParamMode::Horn)) = kind {
993            InferMode::KVar
994        } else {
995            InferMode::EVar
996        }
997    }
998
999    pub fn prefix_str(self) -> &'static str {
1000        match self {
1001            InferMode::EVar => "?",
1002            InferMode::KVar => "$",
1003        }
1004    }
1005}
1006
1007/// `bool`, `char`, and `str` are primitive sorts, but because sorts and types are in the same
1008/// namespace we resolve them to [`Res::PrimTy`] and then make them into a sort during `conv`
1009/// they share their name with the
1010#[derive(Debug, Eq, PartialEq, Clone, Copy, Encodable, Decodable)]
1011pub enum PrimSort {
1012    Int,
1013    Real,
1014    Set,
1015    Map,
1016    RawPtr,
1017    Bool,
1018    Char,
1019    Str,
1020}
1021
1022impl PrimSort {
1023    pub const ALL: [Self; 8] = [
1024        Self::Int,
1025        Self::Real,
1026        Self::Set,
1027        Self::Map,
1028        Self::RawPtr,
1029        Self::Bool,
1030        Self::Char,
1031        Self::Str,
1032    ];
1033
1034    pub fn name(self) -> Symbol {
1035        match self {
1036            PrimSort::Int => sym::int,
1037            PrimSort::Real => sym::real,
1038            PrimSort::Set => sym::Set,
1039            PrimSort::Map => sym::Map,
1040            PrimSort::RawPtr => sym::ptr,
1041            PrimSort::Bool => sym::bool,
1042            PrimSort::Char => sym::char,
1043            PrimSort::Str => sym::str,
1044        }
1045    }
1046    pub fn name_str(self) -> &'static str {
1047        match self {
1048            PrimSort::Int => "int",
1049            PrimSort::Real => "real",
1050            PrimSort::Set => "Set",
1051            PrimSort::Map => "Map",
1052            PrimSort::RawPtr => "ptr",
1053            PrimSort::Bool => "bool",
1054            PrimSort::Char => "char",
1055            PrimSort::Str => "str",
1056        }
1057    }
1058
1059    /// Number of generics expected by this primitive sort
1060    pub fn generics(self) -> usize {
1061        match self {
1062            PrimSort::Bool
1063            | PrimSort::Char
1064            | PrimSort::Str
1065            | PrimSort::Int
1066            | PrimSort::Real
1067            | PrimSort::RawPtr => 0,
1068            PrimSort::Set => 1,
1069            PrimSort::Map => 2,
1070        }
1071    }
1072}
1073
1074#[derive(Clone, Copy)]
1075pub enum Sort<'fhir> {
1076    Path(SortPath<'fhir>),
1077    /// The sort of a location parameter introduced with the `x: &strg T` syntax.
1078    Loc,
1079    /// A bit vector with the given width.
1080    BitVec(u32),
1081    /// A polymorphic sort function.
1082    Func(PolyFuncSort<'fhir>),
1083    /// The sort associated with a base type. This is normalized into a concrete sort during
1084    /// conversion
1085    SortOf(BaseTy<'fhir>),
1086    /// A tuple sort, e.g., (int, bool)
1087    Tuple(&'fhir [Sort<'fhir>]),
1088    /// A sort that needs to be inferred.
1089    Infer,
1090    Err(ErrorGuaranteed),
1091}
1092
1093/// See [`flux_syntax::surface::SortPath`]
1094#[derive(Clone, Copy)]
1095pub struct SortPath<'fhir> {
1096    pub res: PartialRes,
1097    pub segments: &'fhir [Ident],
1098    pub args: &'fhir [Sort<'fhir>],
1099}
1100
1101#[derive(Clone, Copy)]
1102pub struct FuncSort<'fhir> {
1103    /// inputs and output in order
1104    pub inputs_and_output: &'fhir [Sort<'fhir>],
1105}
1106
1107#[derive(Clone, Copy)]
1108pub struct PolyFuncSort<'fhir> {
1109    pub params: usize,
1110    pub fsort: FuncSort<'fhir>,
1111}
1112
1113impl<'fhir> PolyFuncSort<'fhir> {
1114    pub fn new(params: usize, inputs_and_output: &'fhir [Sort]) -> Self {
1115        let fsort = FuncSort { inputs_and_output };
1116        Self { params, fsort }
1117    }
1118}
1119
1120/// `<qself as path>::name`
1121#[derive(Clone, Copy)]
1122pub enum AliasReft<'fhir> {
1123    /// A fully qualified associated refinement `<qself as trait_>::name`
1124    Qualified { qself: &'fhir Ty<'fhir>, trait_: Path<'fhir>, name: Ident },
1125    /// A type-relative associated refinement, e.g., `Self::name`. Note that
1126    /// we can only resolve this when `ty` is a parameter, similar to how
1127    /// type-relative associated types are resolved.
1128    TypeRelative { qself: &'fhir Ty<'fhir>, name: Ident },
1129}
1130
1131#[derive(Debug, Clone, Copy)]
1132pub struct FieldExpr<'fhir> {
1133    pub ident: Ident,
1134    pub expr: Expr<'fhir>,
1135    pub fhir_id: FhirId,
1136    pub span: Span,
1137}
1138
1139#[derive(Debug, Clone, Copy)]
1140pub struct Spread<'fhir> {
1141    pub expr: Expr<'fhir>,
1142    pub span: Span,
1143    pub fhir_id: FhirId,
1144}
1145
1146#[derive(Clone, Copy)]
1147pub struct Expr<'fhir> {
1148    pub kind: ExprKind<'fhir>,
1149    pub fhir_id: FhirId,
1150    pub span: Span,
1151}
1152
1153#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1154pub enum QuantKind {
1155    Forall,
1156    Exists,
1157}
1158
1159#[derive(Clone, Copy)]
1160pub enum QuantDom {
1161    Bounded { start: usize, end: usize },
1162    Unbounded,
1163}
1164
1165#[derive(Clone, Copy)]
1166pub enum ExprKind<'fhir> {
1167    Var(QPathExpr<'fhir>),
1168    Dot(&'fhir Expr<'fhir>, Ident),
1169    Literal(Lit),
1170    BinaryOp(BinOp, &'fhir Expr<'fhir>, &'fhir Expr<'fhir>),
1171    UnaryOp(UnOp, &'fhir Expr<'fhir>),
1172    App(PathExpr<'fhir>, &'fhir [Expr<'fhir>]),
1173    /// UIF application representing a primitive operation, e.g. `[<<](x, y)`
1174    PrimApp(BinOp, &'fhir Expr<'fhir>, &'fhir Expr<'fhir>),
1175    Alias(AliasReft<'fhir>, &'fhir [Expr<'fhir>]),
1176    IfThenElse(&'fhir Expr<'fhir>, &'fhir Expr<'fhir>, &'fhir Expr<'fhir>),
1177    Abs(&'fhir [RefineParam<'fhir>], &'fhir Expr<'fhir>),
1178    Quant(QuantKind, RefineParam<'fhir>, QuantDom, &'fhir Expr<'fhir>),
1179    Record(&'fhir [Expr<'fhir>]),
1180    SetLiteral(&'fhir [Expr<'fhir>]),
1181    Constructor(Option<PathExpr<'fhir>>, &'fhir [FieldExpr<'fhir>], Option<&'fhir Spread<'fhir>>),
1182    Block(&'fhir [LetDecl<'fhir>], &'fhir Expr<'fhir>),
1183    Tuple(&'fhir [Expr<'fhir>]),
1184    Err(ErrorGuaranteed),
1185}
1186
1187#[derive(Clone, Copy)]
1188pub enum QPathExpr<'fhir> {
1189    Resolved(PathExpr<'fhir>, Option<ParamKind>),
1190    TypeRelative(&'fhir Ty<'fhir>, Ident),
1191}
1192
1193#[derive(Clone, Copy)]
1194pub struct LetDecl<'fhir> {
1195    pub param: RefineParam<'fhir>,
1196    pub init: Expr<'fhir>,
1197}
1198
1199#[derive(Clone, Copy)]
1200pub enum Lit {
1201    Int(u128),
1202    Real(Symbol),
1203    Bool(bool),
1204    Str(Symbol),
1205    Char(char),
1206}
1207
1208#[derive(Clone, Copy)]
1209pub struct PathExpr<'fhir> {
1210    pub segments: &'fhir [Ident],
1211    pub res: Res,
1212    pub fhir_id: FhirId,
1213    pub span: Span,
1214}
1215
1216impl<'fhir> PathExpr<'fhir> {
1217    pub fn name(&self) -> Option<Symbol> {
1218        self.segments.last().map(|ident| ident.name)
1219    }
1220}
1221
1222newtype_index! {
1223    #[debug_format = "a{}"]
1224    #[encodable]
1225    pub struct ParamId {}
1226}
1227
1228impl PolyTraitRef<'_> {
1229    pub fn trait_def_id(&self) -> DefId {
1230        let path = &self.trait_ref;
1231        if let Res::Def(DefKind::Trait, did) = path.res {
1232            did
1233        } else {
1234            span_bug!(path.span, "unexpected resolution {:?}", path.res);
1235        }
1236    }
1237}
1238
1239impl From<MaybeExternId<OwnerId>> for FluxOwnerId {
1240    fn from(owner_id: MaybeExternId<OwnerId>) -> Self {
1241        FluxOwnerId::Rust(owner_id)
1242    }
1243}
1244
1245impl<'fhir> Ty<'fhir> {
1246    pub fn as_path(&self) -> Option<Path<'fhir>> {
1247        match &self.kind {
1248            TyKind::BaseTy(bty) => bty.as_path(),
1249            _ => None,
1250        }
1251    }
1252}
1253
1254impl<Id> Res<Id> {
1255    pub fn descr(&self) -> &'static str {
1256        match self {
1257            Res::PrimTy(_) => "builtin type",
1258            Res::Def(kind, def_id) => kind.descr(*def_id),
1259            Res::SelfTyAlias { .. } | Res::SelfTyParam { .. } => "self type",
1260            Res::Param(..) => "refinement parameter",
1261            Res::GlobalFunc(..) => "refinement function",
1262            Res::PrimSort(..) => "primitive sort",
1263            Res::SortParam(..) => "sort parameter",
1264            Res::UserSort(..) => "user-defined sort",
1265            Res::Err => "unresolved item",
1266        }
1267    }
1268
1269    pub fn is_box(&self, tcx: TyCtxt) -> bool {
1270        if let Res::Def(DefKind::Struct, def_id) = self {
1271            tcx.adt_def(def_id).is_box()
1272        } else {
1273            false
1274        }
1275    }
1276
1277    /// Returns `None` if this is `Res::Err`
1278    pub fn ns(&self) -> Option<Namespace> {
1279        match self {
1280            Res::Def(kind, ..) => kind.ns().map(Namespace::from),
1281            Res::PrimTy(..) | Res::SelfTyAlias { .. } | Res::SelfTyParam { .. } => {
1282                Some(Namespace::TypeNS)
1283            }
1284            Res::Param(..) | Res::GlobalFunc(..) => Some(Namespace::ReftNS),
1285            // Sorts share the type namespace: primitive sorts live in the type prelude and
1286            // sort parameters in the type ribs, so they resolve through `TypeNS` alongside types.
1287            Res::PrimSort(..) | Res::SortParam(..) | Res::UserSort(..) => Some(Namespace::TypeNS),
1288            Res::Err => None,
1289        }
1290    }
1291
1292    /// Always returns `true` if `self` is `Res::Err`
1293    pub fn matches_ns(&self, ns: Namespace) -> bool {
1294        self.ns().is_none_or(|actual_ns| actual_ns == ns)
1295    }
1296
1297    pub fn map_param_id<R>(self, f: impl FnOnce(Id) -> R) -> Res<R> {
1298        match self {
1299            Res::Param(kind, param_id) => Res::Param(kind, f(param_id)),
1300            Res::Def(def_kind, def_id) => Res::Def(def_kind, def_id),
1301            Res::PrimTy(prim_ty) => Res::PrimTy(prim_ty),
1302            Res::SelfTyAlias { alias_to, is_trait_impl } => {
1303                Res::SelfTyAlias { alias_to, is_trait_impl }
1304            }
1305            Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
1306            Res::GlobalFunc(spec_func_kind) => Res::GlobalFunc(spec_func_kind),
1307            Res::PrimSort(prim_sort) => Res::PrimSort(prim_sort),
1308            Res::SortParam(n) => Res::SortParam(n),
1309            Res::UserSort(def_id) => Res::UserSort(def_id),
1310            Res::Err => Res::Err,
1311        }
1312    }
1313
1314    pub fn expect_param(self) -> (ParamKind, Id) {
1315        if let Res::Param(kind, id) = self { (kind, id) } else { bug!("expected param") }
1316    }
1317}
1318
1319impl<Id1, Id2> TryFrom<rustc_hir::def::Res<Id1>> for Res<Id2> {
1320    type Error = ();
1321
1322    fn try_from(res: rustc_hir::def::Res<Id1>) -> Result<Self, Self::Error> {
1323        match res {
1324            rustc_hir::def::Res::Def(kind, did) => Ok(Res::Def(kind, did)),
1325            rustc_hir::def::Res::PrimTy(prim_ty) => Ok(Res::PrimTy(prim_ty)),
1326            rustc_hir::def::Res::SelfTyAlias { alias_to, is_trait_impl } => {
1327                Ok(Res::SelfTyAlias { alias_to, is_trait_impl })
1328            }
1329            rustc_hir::def::Res::SelfTyParam { trait_ } => Ok(Res::SelfTyParam { trait_ }),
1330            rustc_hir::def::Res::Err => Ok(Res::Err),
1331            _ => Err(()),
1332        }
1333    }
1334}
1335
1336impl QPath<'_> {
1337    pub fn span(&self) -> Span {
1338        match self {
1339            QPath::Resolved(_, path) => path.span,
1340            QPath::TypeRelative(qself, assoc) => qself.span.to(assoc.ident.span),
1341        }
1342    }
1343}
1344
1345impl Lit {
1346    pub const TRUE: Lit = Lit::Bool(true);
1347}
1348
1349/// Information about the refinement parameters associated with an adt (struct/enum).
1350#[derive(Clone, Debug)]
1351pub struct RefinedBy<'fhir> {
1352    /// When a `#[flux::refined_by(..)]` annotation mentions generic type parameters we implicitly
1353    /// generate a *polymorphic* data sort.
1354    ///
1355    /// For example, if we have:
1356    /// ```ignore
1357    /// #[refined_by(keys: Set<K>)]
1358    /// RMap<K, V> { ... }
1359    /// ```
1360    /// we implicitly create a data sort of the form `forall #0. { keys: Set<#0> }`, where `#0` is a
1361    /// *sort variable*.
1362    ///
1363    /// This [`FxIndexSet`] is used to track a mapping between sort variables and their corresponding
1364    /// type parameter. The [`DefId`] is the id of the type parameter and its index in the set is the
1365    /// position of the sort variable.
1366    pub sort_params: FxIndexSet<DefId>,
1367    /// Fields indexed by their name in the same order they appear in the `#[refined_by(..)]` annotation.
1368    pub fields: FxIndexMap<Symbol, Sort<'fhir>>,
1369}
1370
1371#[derive(Debug)]
1372pub struct SpecFunc<'fhir> {
1373    pub def_id: FluxLocalDefId,
1374    pub params: usize,
1375    pub args: &'fhir [RefineParam<'fhir>],
1376    pub sort: Sort<'fhir>,
1377    pub body: Option<Expr<'fhir>>,
1378    pub hide: bool,
1379    pub ident_span: Span,
1380}
1381#[derive(Debug)]
1382pub struct PrimOpProp<'fhir> {
1383    pub def_id: FluxLocalDefId,
1384    pub op: BinOp,
1385    pub args: &'fhir [RefineParam<'fhir>],
1386    pub body: Expr<'fhir>,
1387    pub span: Span,
1388}
1389
1390#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)]
1391pub enum SpecFuncKind {
1392    /// Theory symbols *interpreted* by the SMT solver
1393    Thy(liquid_fixpoint::ThyFunc),
1394    /// User-defined function. This can be either a function with a body or a UIF.
1395    Def(FluxDefId),
1396    /// Casts between sorts: id for char, int; if-then-else for bool-int; uninterpreted otherwise.
1397    Cast,
1398}
1399
1400impl SpecFuncKind {
1401    pub fn def_id(&self) -> Option<FluxDefId> {
1402        match self {
1403            SpecFuncKind::Def(flux_id) => Some(*flux_id),
1404            _ => None,
1405        }
1406    }
1407}
1408
1409impl<'fhir> Generics<'fhir> {
1410    pub fn get_param(&self, def_id: LocalDefId) -> &'fhir GenericParam<'fhir> {
1411        self.params
1412            .iter()
1413            .find(|p| p.def_id.local_id() == def_id)
1414            .unwrap()
1415    }
1416
1417    pub fn empty(genv: GlobalEnv<'fhir, '_>) -> Self {
1418        let params = genv.alloc_slice_fill_iter(iter::empty());
1419        Self { params, refinement_params: &[], predicates: None }
1420    }
1421}
1422
1423impl<'fhir> RefinedBy<'fhir> {
1424    pub fn new(fields: FxIndexMap<Symbol, Sort<'fhir>>, sort_params: FxIndexSet<DefId>) -> Self {
1425        RefinedBy { sort_params, fields }
1426    }
1427
1428    pub fn trivial() -> Self {
1429        RefinedBy { sort_params: Default::default(), fields: Default::default() }
1430    }
1431}
1432
1433impl<'fhir> From<PolyFuncSort<'fhir>> for Sort<'fhir> {
1434    fn from(fsort: PolyFuncSort<'fhir>) -> Self {
1435        Self::Func(fsort)
1436    }
1437}
1438
1439impl FuncSort<'_> {
1440    pub fn inputs(&self) -> &[Sort<'_>] {
1441        &self.inputs_and_output[..self.inputs_and_output.len() - 1]
1442    }
1443
1444    pub fn output(&self) -> &Sort<'_> {
1445        &self.inputs_and_output[self.inputs_and_output.len() - 1]
1446    }
1447}
1448
1449impl rustc_errors::IntoDiagArg for Ty<'_> {
1450    fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
1451        rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
1452    }
1453}
1454
1455impl rustc_errors::IntoDiagArg for Path<'_> {
1456    fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
1457        rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
1458    }
1459}
1460
1461impl StructDef<'_> {
1462    pub fn is_opaque(&self) -> bool {
1463        matches!(self.kind, StructKind::Opaque)
1464    }
1465}
1466
1467impl fmt::Debug for FnSig<'_> {
1468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1469        write!(f, "{:?}", self.decl)
1470    }
1471}
1472
1473impl fmt::Debug for FnDecl<'_> {
1474    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1475        if !self.requires.is_empty() {
1476            write!(f, "[{:?}] ", self.requires.iter().format(", "))?;
1477        }
1478        write!(f, "fn({:?}) -> {:?}", self.inputs.iter().format(", "), self.output)
1479    }
1480}
1481
1482impl fmt::Debug for FnOutput<'_> {
1483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1484        if !self.params.is_empty() {
1485            write!(
1486                f,
1487                "exists<{}> ",
1488                self.params.iter().format_with(", ", |param, f| {
1489                    f(&format_args!("{}: {:?}", param.name, param.sort))
1490                })
1491            )?;
1492        }
1493        write!(f, "{:?}", self.ret)?;
1494        if !self.ensures.is_empty() {
1495            write!(f, "; [{:?}]", self.ensures.iter().format(", "))?;
1496        }
1497
1498        Ok(())
1499    }
1500}
1501
1502impl fmt::Debug for Requires<'_> {
1503    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1504        if !self.params.is_empty() {
1505            write!(
1506                f,
1507                "forall {}.",
1508                self.params.iter().format_with(",", |param, f| {
1509                    f(&format_args!("{}:{:?}", param.name, param.sort))
1510                })
1511            )?;
1512        }
1513        write!(f, "{:?}", self.pred)
1514    }
1515}
1516
1517impl fmt::Debug for Ensures<'_> {
1518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1519        match self {
1520            Ensures::Type(loc, ty) => write!(f, "{loc:?}: {ty:?}"),
1521            Ensures::Pred(e) => write!(f, "{e:?}"),
1522        }
1523    }
1524}
1525
1526impl fmt::Debug for Ty<'_> {
1527    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1528        match &self.kind {
1529            TyKind::BaseTy(bty) => write!(f, "{bty:?}"),
1530            TyKind::Indexed(bty, idx) => write!(f, "{bty:?}[{idx:?}]"),
1531            TyKind::Exists(params, ty) => {
1532                write!(f, "{{")?;
1533                write!(
1534                    f,
1535                    "{}",
1536                    params.iter().format_with(",", |param, f| {
1537                        f(&format_args!("{}:{:?}", param.name, param.sort))
1538                    })
1539                )?;
1540                if let TyKind::Constr(pred, ty) = &ty.kind {
1541                    write!(f, ". {ty:?} | {pred:?}}}")
1542                } else {
1543                    write!(f, ". {ty:?}}}")
1544                }
1545            }
1546            TyKind::StrgRef(_lft, loc, ty) => write!(f, "&strg <{loc:?}: {ty:?}>"),
1547            TyKind::Ref(_lft, mut_ty) => {
1548                write!(f, "&{}{:?}", mut_ty.mutbl.prefix_str(), mut_ty.ty)
1549            }
1550            TyKind::BareFn(bare_fn_ty) => {
1551                write!(f, "{bare_fn_ty:?}")
1552            }
1553            TyKind::Tuple(tys) => write!(f, "({:?})", tys.iter().format(", ")),
1554            TyKind::Array(ty, len) => write!(f, "[{ty:?}; {len:?}]"),
1555            TyKind::Never => write!(f, "!"),
1556            TyKind::Constr(pred, ty) => write!(f, "{{{ty:?} | {pred:?}}}"),
1557            TyKind::Infer => write!(f, "_"),
1558            TyKind::OpaqueDef(opaque_ty) => {
1559                write!(f, "impl trait <def_id = {:?}>", opaque_ty.def_id.resolved_id(),)
1560            }
1561            TyKind::TraitObject(poly_traits, _lft, _syntax) => {
1562                write!(f, "dyn {poly_traits:?}")
1563            }
1564            TyKind::Err(_) => write!(f, "err"),
1565        }
1566    }
1567}
1568
1569impl fmt::Debug for BareFnTy<'_> {
1570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1571        if !self.generic_params.is_empty() {
1572            write!(
1573                f,
1574                "for<{}>",
1575                self.generic_params
1576                    .iter()
1577                    .map(|param| param.name.ident())
1578                    .format(",")
1579            )?;
1580        }
1581        write!(f, "{:?}", self.decl)
1582    }
1583}
1584
1585impl fmt::Debug for Lifetime {
1586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1587        write!(f, "'_")
1588    }
1589}
1590
1591impl fmt::Debug for ConstArg {
1592    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1593        write!(f, "{:?}", self.kind)
1594    }
1595}
1596
1597impl fmt::Debug for ConstArgKind {
1598    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1599        match self {
1600            ConstArgKind::Lit(n) => write!(f, "{n}"),
1601            ConstArgKind::Param(p) => write!(f, "{p:?}"),
1602            ConstArgKind::Infer => write!(f, "_"),
1603        }
1604    }
1605}
1606
1607impl fmt::Debug for BaseTy<'_> {
1608    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1609        match &self.kind {
1610            BaseTyKind::Path(qpath) => write!(f, "{qpath:?}"),
1611            BaseTyKind::Slice(ty) => write!(f, "[{ty:?}]"),
1612            BaseTyKind::RawPtr(ty, Mutability::Not) => write!(f, "*const {ty:?}"),
1613            BaseTyKind::RawPtr(ty, Mutability::Mut) => write!(f, "*mut {ty:?}"),
1614            BaseTyKind::Err(_) => write!(f, "err"),
1615        }
1616    }
1617}
1618
1619impl fmt::Debug for QPath<'_> {
1620    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1621        match self {
1622            QPath::Resolved(_, path) => write!(f, "{path:?}"),
1623            QPath::TypeRelative(qself, assoc) => write!(f, "<{qself:?}>::{assoc:?}"),
1624        }
1625    }
1626}
1627
1628impl fmt::Debug for Path<'_> {
1629    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1630        write!(f, "{:?}", self.segments.iter().format("::"))?;
1631        if !self.refine.is_empty() {
1632            write!(f, "({:?})", self.refine.iter().format(", "))?;
1633        }
1634        Ok(())
1635    }
1636}
1637
1638impl fmt::Debug for PathSegment<'_> {
1639    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1640        write!(f, "{}", self.ident)?;
1641        let args: Vec<_> = self
1642            .args
1643            .iter()
1644            .map(|a| a as &dyn std::fmt::Debug)
1645            .chain(self.constraints.iter().map(|b| b as &dyn std::fmt::Debug))
1646            .collect();
1647        if !args.is_empty() {
1648            write!(f, "<{:?}>", args.iter().format(", "))?;
1649        }
1650        Ok(())
1651    }
1652}
1653
1654impl fmt::Debug for GenericArg<'_> {
1655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1656        match self {
1657            GenericArg::Type(ty) => write!(f, "{ty:?}"),
1658            GenericArg::Lifetime(lft) => write!(f, "{lft:?}"),
1659            GenericArg::Const(cst) => write!(f, "{cst:?}"),
1660            GenericArg::Infer => write!(f, "_"),
1661        }
1662    }
1663}
1664
1665impl fmt::Debug for AssocItemConstraint<'_> {
1666    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1667        match &self.kind {
1668            AssocItemConstraintKind::Equality { term } => {
1669                write!(f, "{:?} = {:?}", self.ident, term)
1670            }
1671        }
1672    }
1673}
1674
1675impl fmt::Debug for AliasReft<'_> {
1676    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1677        match self {
1678            AliasReft::Qualified { qself, trait_, name } => {
1679                write!(f, "<{qself:?} as {trait_:?}>::{name}")
1680            }
1681            AliasReft::TypeRelative { qself, name } => {
1682                write!(f, "{qself:?}::{name}")
1683            }
1684        }
1685    }
1686}
1687
1688impl fmt::Debug for QuantKind {
1689    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1690        match self {
1691            QuantKind::Forall => write!(f, "∀"),
1692            QuantKind::Exists => write!(f, "∃"),
1693        }
1694    }
1695}
1696
1697impl fmt::Debug for QuantDom {
1698    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1699        match self {
1700            QuantDom::Bounded { start, end } => write!(f, "in {start:?} .. {end:?}"),
1701            QuantDom::Unbounded => Ok(()),
1702        }
1703    }
1704}
1705
1706impl fmt::Debug for Expr<'_> {
1707    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1708        match self.kind {
1709            ExprKind::Var(QPathExpr::Resolved(path, ..)) => write!(f, "{path:?}"),
1710            ExprKind::Var(QPathExpr::TypeRelative(qself, assoc)) => {
1711                write!(f, "<{qself:?}>::{assoc}")
1712            }
1713            ExprKind::BinaryOp(op, e1, e2) => write!(f, "({e1:?} {op:?} {e2:?})"),
1714            ExprKind::PrimApp(op, e1, e2) => write!(f, "[{op:?}]({e1:?}, {e2:?})"),
1715            ExprKind::UnaryOp(op, e) => write!(f, "{op:?}{e:?}"),
1716            ExprKind::Literal(lit) => write!(f, "{lit:?}"),
1717            ExprKind::App(uf, es) => write!(f, "{uf:?}({:?})", es.iter().format(", ")),
1718            ExprKind::Alias(alias, refine_args) => {
1719                write!(f, "{alias:?}({:?})", refine_args.iter().format(", "))
1720            }
1721            ExprKind::IfThenElse(p, e1, e2) => {
1722                write!(f, "(if {p:?} {{ {e1:?} }} else {{ {e2:?} }})")
1723            }
1724            ExprKind::Dot(var, fld) => write!(f, "{var:?}.{fld}"),
1725            ExprKind::Abs(params, body) => {
1726                write!(
1727                    f,
1728                    "|{}| {body:?}",
1729                    params.iter().format_with(", ", |param, f| {
1730                        f(&format_args!("{}: {:?}", param.name, param.sort))
1731                    })
1732                )
1733            }
1734            ExprKind::Record(flds) => {
1735                write!(f, "{{ {:?} }}", flds.iter().format(", "))
1736            }
1737            ExprKind::SetLiteral(elems) => {
1738                write!(f, "#{{ {:?} }}", elems.iter().format(", "))
1739            }
1740            ExprKind::Constructor(path, exprs, spread) => {
1741                if let Some(path) = path
1742                    && let Some(s) = spread
1743                {
1744                    write!(f, "{:?} {{ {:?}, ..{:?} }}", path, exprs.iter().format(", "), s)
1745                } else if let Some(path) = path {
1746                    write!(f, "{:?} {{ {:?} }}", path, exprs.iter().format(", "))
1747                } else if let Some(s) = spread {
1748                    write!(f, "{{ {:?} ..{:?} }}", exprs.iter().format(", "), s)
1749                } else {
1750                    write!(f, "{{ {:?} }}", exprs.iter().format(", "))
1751                }
1752            }
1753            ExprKind::Quant(kind, refine_param, dom, expr) => {
1754                write!(f, "{kind:?} {refine_param:?} {dom:?} {{ {expr:?} }}")
1755            }
1756            ExprKind::Err(_) => write!(f, "err"),
1757            ExprKind::Block(decls, body) => {
1758                for decl in decls {
1759                    write!(f, "let {:?} = {:?};", decl.param, decl.init)?;
1760                }
1761                write!(f, "{body:?}")
1762            }
1763            ExprKind::Tuple(exprs) => {
1764                write!(f, "({:?})", exprs.iter().format(", "))
1765            }
1766        }
1767    }
1768}
1769
1770impl fmt::Debug for PathExpr<'_> {
1771    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1772        write!(f, "{}", self.segments.iter().format("::"))
1773    }
1774}
1775
1776impl fmt::Debug for Lit {
1777    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1778        match self {
1779            Lit::Int(i) => write!(f, "{i}"),
1780            Lit::Real(s) => write!(f, "{s}"),
1781            Lit::Bool(b) => write!(f, "{b}"),
1782            Lit::Str(s) => write!(f, "\"{s:?}\""),
1783            Lit::Char(c) => write!(f, "\'{c}\'"),
1784        }
1785    }
1786}
1787
1788impl fmt::Debug for Sort<'_> {
1789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1790        match self {
1791            Sort::Path(path) => write!(f, "{path:?}"),
1792            Sort::BitVec(w) => write!(f, "bitvec({w})"),
1793            Sort::Loc => write!(f, "loc"),
1794            Sort::Func(fsort) => write!(f, "{fsort:?}"),
1795            Sort::SortOf(bty) => write!(f, "<{bty:?}>::sort"),
1796            Sort::Tuple(sorts) => write!(f, "({:?})", sorts.iter().format(", ")),
1797            Sort::Infer => write!(f, "_"),
1798            Sort::Err(_) => write!(f, "err"),
1799        }
1800    }
1801}
1802
1803impl fmt::Debug for SortPath<'_> {
1804    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1805        write!(f, "{:?}", self.res)?;
1806        if !self.args.is_empty() {
1807            write!(f, "<{:?}>", self.args.iter().format(", "))?;
1808        }
1809        Ok(())
1810    }
1811}
1812
1813impl fmt::Debug for PolyFuncSort<'_> {
1814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1815        if self.params > 0 {
1816            write!(f, "for<{}>{:?}", self.params, self.fsort)
1817        } else {
1818            write!(f, "{:?}", self.fsort)
1819        }
1820    }
1821}
1822
1823impl fmt::Debug for FuncSort<'_> {
1824    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1825        match self.inputs() {
1826            [input] => {
1827                write!(f, "{:?} -> {:?}", input, self.output())
1828            }
1829            inputs => {
1830                write!(f, "({:?}) -> {:?}", inputs.iter().format(", "), self.output())
1831            }
1832        }
1833    }
1834}