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