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