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