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