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