flux_middle/
fhir.rs

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