flux_middle/rty/
mod.rs

1//! Defines how flux represents refinement types internally. Definitions in this module are used
2//! during refinement type checking. A couple of important differences between definitions in this
3//! module and in [`crate::fhir`] are:
4//!
5//! * Types in this module use debruijn indices to represent local binders.
6//! * Data structures are interned so they can be cheaply cloned.
7mod binder;
8pub mod canonicalize;
9mod expr;
10pub mod fold;
11pub mod normalize;
12mod pretty;
13pub mod refining;
14pub mod region_matching;
15pub mod subst;
16use std::{borrow::Cow, cmp::Ordering, fmt, hash::Hash, sync::LazyLock};
17
18pub use binder::{Binder, BoundReftKind, BoundVariableKind, BoundVariableKinds, EarlyBinder};
19use bitflags::bitflags;
20pub use expr::{
21    AggregateKind, AliasReft, BinOp, BoundReft, Constant, Ctor, ESpan, EVid, EarlyReftParam, Expr,
22    ExprKind, FieldProj, HoleKind, InternalFuncKind, KVar, KVid, Lambda, Loc, Name, Path, Real,
23    SpecFuncKind, UnOp, Var,
24};
25pub use flux_arc_interner::List;
26use flux_arc_interner::{Interned, impl_internable, impl_slice_internable};
27use flux_common::{bug, tracked_span_assert_eq, tracked_span_bug};
28use flux_config::OverflowMode;
29use flux_macros::{TypeFoldable, TypeVisitable};
30pub use flux_rustc_bridge::ty::{
31    AliasKind, BoundRegion, BoundRegionKind, BoundVar, Const, ConstKind, ConstVid, DebruijnIndex,
32    EarlyParamRegion, LateParamRegion, LateParamRegionKind,
33    Region::{self, *},
34    RegionVid,
35};
36use flux_rustc_bridge::{
37    ToRustc,
38    mir::{Place, RawPtrKind},
39    ty::{self, GenericArgsExt as _, VariantDef},
40};
41use itertools::Itertools;
42pub use normalize::{NormalizeInfo, NormalizedDefns, local_deps};
43use refining::{Refine as _, Refiner};
44use rustc_abi;
45pub use rustc_abi::{FIRST_VARIANT, VariantIdx};
46use rustc_data_structures::{fx::FxIndexMap, snapshot_map::SnapshotMap, unord::UnordMap};
47use rustc_hir::{LangItem, Safety, def_id::DefId};
48use rustc_index::{IndexSlice, IndexVec, newtype_index};
49use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable, extension};
50use rustc_middle::ty::{TyCtxt, fast_reject::SimplifiedType};
51pub use rustc_middle::{
52    mir::Mutability,
53    ty::{AdtFlags, ClosureKind, FloatTy, IntTy, ParamConst, ParamTy, ScalarInt, UintTy},
54};
55use rustc_span::{DUMMY_SP, Span, Symbol, sym, symbol::kw};
56use rustc_type_ir::Upcast as _;
57pub use rustc_type_ir::{INNERMOST, TyVid};
58
59use self::fold::TypeFoldable;
60pub use crate::fhir::InferMode;
61use crate::{
62    LocalDefId,
63    def_id::{FluxDefId, FluxLocalDefId},
64    fhir::{self, FhirId, FluxOwnerId},
65    global_env::GlobalEnv,
66    pretty::{Pretty, PrettyCx},
67    queries::{QueryErr, QueryResult},
68    rty::subst::SortSubst,
69};
70
71/// The definition of the data sort automatically generated for a struct or enum.
72#[derive(Debug, Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
73pub struct AdtSortDef(Interned<AdtSortDefData>);
74
75#[derive(Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
76pub struct AdtSortVariant {
77    /// The list of field names as declared in the `#[flux::refined_by(...)]` annotation
78    field_names: Vec<Symbol>,
79    /// The sort of each of the fields. Note that these can contain [sort variables]. Methods used
80    /// to access these sorts guarantee they are properly instantiated.
81    ///
82    /// [sort variables]: Sort::Var
83    sorts: List<Sort>,
84}
85
86impl AdtSortVariant {
87    pub fn new(fields: Vec<(Symbol, Sort)>) -> Self {
88        let (field_names, sorts) = fields.into_iter().unzip();
89        AdtSortVariant { field_names, sorts: List::from_vec(sorts) }
90    }
91
92    pub fn fields(&self) -> usize {
93        self.sorts.len()
94    }
95
96    pub fn field_names(&self) -> &Vec<Symbol> {
97        &self.field_names
98    }
99
100    pub fn sort_by_field_name(&self, args: &[Sort]) -> FxIndexMap<Symbol, Sort> {
101        std::iter::zip(&self.field_names, &self.sorts.fold_with(&mut SortSubst::new(args)))
102            .map(|(name, sort)| (*name, sort.clone()))
103            .collect()
104    }
105
106    pub fn field_by_name(
107        &self,
108        def_id: DefId,
109        args: &[Sort],
110        name: Symbol,
111    ) -> Option<(FieldProj, Sort)> {
112        let idx = self.field_names.iter().position(|it| name == *it)?;
113        let proj = FieldProj::Adt { def_id, field: idx as u32 };
114        let sort = self.sorts[idx].fold_with(&mut SortSubst::new(args));
115        Some((proj, sort))
116    }
117
118    pub fn field_sorts(&self, args: &[Sort]) -> List<Sort> {
119        self.sorts.fold_with(&mut SortSubst::new(args))
120    }
121
122    pub fn field_sorts_instantiate_identity(&self) -> List<Sort> {
123        self.sorts.clone()
124    }
125
126    pub fn projections(&self, def_id: DefId) -> impl Iterator<Item = FieldProj> {
127        (0..self.fields()).map(move |i| FieldProj::Adt { def_id, field: i as u32 })
128    }
129}
130
131#[derive(Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
132struct AdtSortDefData {
133    /// [`DefId`] of the struct or enum this data sort is associated to.
134    def_id: DefId,
135    /// The list of the type parameters used in the `#[flux::refined_by(..)]` annotation.
136    ///
137    /// See [`fhir::RefinedBy::sort_params`] for more details. This is a version of that but using
138    /// [`ParamTy`] instead of [`DefId`].
139    ///
140    /// The length of this list corresponds to the number of sort variables bound by this definition.
141    params: Vec<ParamTy>,
142    /// A vec of variants of the ADT;
143    /// - a `struct` sort -- used for types with a `refined_by` has a single variant;
144    /// - a `reflected` sort -- used for `reflected` enums have multiple variants
145    variants: IndexVec<VariantIdx, AdtSortVariant>,
146    is_reflected: bool,
147    is_struct: bool,
148}
149
150impl AdtSortDef {
151    pub fn new(
152        def_id: DefId,
153        params: Vec<ParamTy>,
154        variants: IndexVec<VariantIdx, AdtSortVariant>,
155        is_reflected: bool,
156        is_struct: bool,
157    ) -> Self {
158        Self(Interned::new(AdtSortDefData { def_id, params, variants, is_reflected, is_struct }))
159    }
160
161    pub fn did(&self) -> DefId {
162        self.0.def_id
163    }
164
165    pub fn variant(&self, idx: VariantIdx) -> &AdtSortVariant {
166        &self.0.variants[idx]
167    }
168
169    pub fn variants(&self) -> &IndexSlice<VariantIdx, AdtSortVariant> {
170        &self.0.variants
171    }
172
173    pub fn opt_struct_variant(&self) -> Option<&AdtSortVariant> {
174        if self.is_struct() { Some(self.struct_variant()) } else { None }
175    }
176
177    #[track_caller]
178    pub fn struct_variant(&self) -> &AdtSortVariant {
179        tracked_span_assert_eq!(self.0.is_struct, true);
180        &self.0.variants[FIRST_VARIANT]
181    }
182
183    pub fn is_reflected(&self) -> bool {
184        self.0.is_reflected
185    }
186
187    pub fn is_struct(&self) -> bool {
188        self.0.is_struct
189    }
190
191    pub fn to_sort(&self, args: &[GenericArg]) -> Sort {
192        let sorts = self
193            .filter_generic_args(args)
194            .map(|arg| arg.expect_base().sort())
195            .collect();
196
197        Sort::App(SortCtor::Adt(self.clone()), sorts)
198    }
199
200    /// Given a list of generic args, returns an iterator of the generic arguments that should be
201    /// mapped to sorts for instantiation.
202    pub fn filter_generic_args<'a, A>(&'a self, args: &'a [A]) -> impl Iterator<Item = &'a A> + 'a {
203        self.0.params.iter().map(|p| &args[p.index as usize])
204    }
205
206    pub fn identity_args(&self) -> List<Sort> {
207        (0..self.0.params.len())
208            .map(|i| Sort::Var(ParamSort::from(i)))
209            .collect()
210    }
211
212    /// Gives the number of sort variables bound by this definition.
213    pub fn param_count(&self) -> usize {
214        self.0.params.len()
215    }
216}
217
218#[derive(Debug, Clone, Default, Encodable, Decodable)]
219pub struct Generics {
220    pub parent: Option<DefId>,
221    pub parent_count: usize,
222    pub own_params: List<GenericParamDef>,
223    pub has_self: bool,
224}
225
226impl Generics {
227    pub fn count(&self) -> usize {
228        self.parent_count + self.own_params.len()
229    }
230
231    pub fn own_default_count(&self) -> usize {
232        self.own_params
233            .iter()
234            .filter(|param| {
235                match param.kind {
236                    GenericParamDefKind::Type { has_default }
237                    | GenericParamDefKind::Const { has_default }
238                    | GenericParamDefKind::Base { has_default } => has_default,
239                    GenericParamDefKind::Lifetime => false,
240                }
241            })
242            .count()
243    }
244
245    pub fn param_at(&self, param_index: usize, genv: GlobalEnv) -> QueryResult<GenericParamDef> {
246        if let Some(index) = param_index.checked_sub(self.parent_count) {
247            Ok(self.own_params[index].clone())
248        } else {
249            let parent = self.parent.expect("parent_count > 0 but no parent?");
250            genv.generics_of(parent)?.param_at(param_index, genv)
251        }
252    }
253
254    pub fn const_params(&self, genv: GlobalEnv) -> QueryResult<Vec<(ParamConst, Sort)>> {
255        let mut res = vec![];
256        for i in 0..self.count() {
257            let param = self.param_at(i, genv)?;
258            if let GenericParamDefKind::Const { .. } = param.kind
259                && let Some(sort) = genv.sort_of_def_id(param.def_id)?
260            {
261                let param_const = ParamConst { name: param.name, index: param.index };
262                res.push((param_const, sort));
263            }
264        }
265        Ok(res)
266    }
267}
268
269#[derive(Debug, Clone, TyEncodable, TyDecodable)]
270pub struct RefinementGenerics {
271    pub parent: Option<DefId>,
272    pub parent_count: usize,
273    pub own_params: List<RefineParam>,
274}
275
276#[derive(
277    PartialEq, Eq, Debug, Clone, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
278)]
279pub struct RefineParam {
280    pub sort: Sort,
281    pub name: Symbol,
282    pub mode: InferMode,
283}
284
285#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
286pub struct GenericParamDef {
287    pub kind: GenericParamDefKind,
288    pub def_id: DefId,
289    pub index: u32,
290    pub name: Symbol,
291}
292
293#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
294pub enum GenericParamDefKind {
295    Type { has_default: bool },
296    Base { has_default: bool },
297    Lifetime,
298    Const { has_default: bool },
299}
300
301pub const SELF_PARAM_TY: ParamTy = ParamTy { index: 0, name: kw::SelfUpper };
302
303#[derive(Debug, Clone, TyEncodable, TyDecodable)]
304pub struct GenericPredicates {
305    pub parent: Option<DefId>,
306    pub predicates: List<Clause>,
307}
308
309#[derive(
310    Debug, PartialEq, Eq, Hash, Clone, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
311)]
312pub struct Clause {
313    kind: Binder<ClauseKind>,
314}
315
316impl Clause {
317    pub fn new(vars: impl Into<List<BoundVariableKind>>, kind: ClauseKind) -> Self {
318        Clause { kind: Binder::bind_with_vars(kind, vars.into()) }
319    }
320
321    pub fn kind(&self) -> Binder<ClauseKind> {
322        self.kind.clone()
323    }
324
325    fn as_trait_clause(&self) -> Option<Binder<TraitPredicate>> {
326        let clause = self.kind();
327        if let ClauseKind::Trait(trait_clause) = clause.skip_binder_ref() {
328            Some(clause.rebind(trait_clause.clone()))
329        } else {
330            None
331        }
332    }
333
334    pub fn as_projection_clause(&self) -> Option<Binder<ProjectionPredicate>> {
335        let clause = self.kind();
336        if let ClauseKind::Projection(proj_clause) = clause.skip_binder_ref() {
337            Some(clause.rebind(proj_clause.clone()))
338        } else {
339            None
340        }
341    }
342
343    // FIXME(nilehmann) we should deal with the binder in all the places this is used instead of
344    // blindly skipping it here
345    pub fn kind_skipping_binder(&self) -> ClauseKind {
346        self.kind.clone().skip_binder()
347    }
348
349    /// Group `Fn` trait clauses with their corresponding `FnOnce::Output` projection
350    /// predicate. This assumes there's exactly one corresponding projection predicate and will
351    /// crash otherwise.
352    pub fn split_off_fn_trait_clauses(
353        genv: GlobalEnv,
354        clauses: &Clauses,
355    ) -> (Vec<Clause>, Vec<Binder<FnTraitPredicate>>) {
356        let mut fn_trait_clauses = vec![];
357        let mut fn_trait_output_clauses = vec![];
358        let mut rest = vec![];
359        for clause in clauses {
360            if let Some(trait_clause) = clause.as_trait_clause()
361                && let Some(kind) = genv.tcx().fn_trait_kind_from_def_id(trait_clause.def_id())
362            {
363                fn_trait_clauses.push((kind, trait_clause));
364            } else if let Some(proj_clause) = clause.as_projection_clause()
365                && genv.is_fn_output(proj_clause.projection_def_id())
366            {
367                fn_trait_output_clauses.push(proj_clause);
368            } else {
369                rest.push(clause.clone());
370            }
371        }
372        let fn_trait_clauses = fn_trait_clauses
373            .into_iter()
374            .map(|(kind, fn_trait_clause)| {
375                let mut candidates = vec![];
376                for fn_trait_output_clause in &fn_trait_output_clauses {
377                    if fn_trait_output_clause.self_ty() == fn_trait_clause.self_ty() {
378                        candidates.push(fn_trait_output_clause.clone());
379                    }
380                }
381                tracked_span_assert_eq!(candidates.len(), 1);
382                let proj_pred = candidates.pop().unwrap().skip_binder();
383                fn_trait_clause.map(|fn_trait_clause| {
384                    FnTraitPredicate {
385                        kind,
386                        self_ty: fn_trait_clause.self_ty().to_ty(),
387                        tupled_args: fn_trait_clause.trait_ref.args[1].expect_base().to_ty(),
388                        output: proj_pred.term.to_ty(),
389                    }
390                })
391            })
392            .collect_vec();
393        (rest, fn_trait_clauses)
394    }
395}
396
397impl<'tcx> ToRustc<'tcx> for Clause {
398    type T = rustc_middle::ty::Clause<'tcx>;
399
400    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
401        self.kind.to_rustc(tcx).upcast(tcx)
402    }
403}
404
405impl From<Binder<ClauseKind>> for Clause {
406    fn from(kind: Binder<ClauseKind>) -> Self {
407        Clause { kind }
408    }
409}
410
411pub type Clauses = List<Clause>;
412
413#[derive(
414    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
415)]
416pub enum ClauseKind {
417    Trait(TraitPredicate),
418    Projection(ProjectionPredicate),
419    RegionOutlives(RegionOutlivesPredicate),
420    TypeOutlives(TypeOutlivesPredicate),
421    ConstArgHasType(Const, Ty),
422}
423
424impl<'tcx> ToRustc<'tcx> for ClauseKind {
425    type T = rustc_middle::ty::ClauseKind<'tcx>;
426
427    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
428        match self {
429            ClauseKind::Trait(trait_predicate) => {
430                rustc_middle::ty::ClauseKind::Trait(trait_predicate.to_rustc(tcx))
431            }
432            ClauseKind::Projection(projection_predicate) => {
433                rustc_middle::ty::ClauseKind::Projection(projection_predicate.to_rustc(tcx))
434            }
435            ClauseKind::RegionOutlives(outlives_predicate) => {
436                rustc_middle::ty::ClauseKind::RegionOutlives(outlives_predicate.to_rustc(tcx))
437            }
438            ClauseKind::TypeOutlives(outlives_predicate) => {
439                rustc_middle::ty::ClauseKind::TypeOutlives(outlives_predicate.to_rustc(tcx))
440            }
441            ClauseKind::ConstArgHasType(constant, ty) => {
442                rustc_middle::ty::ClauseKind::ConstArgHasType(
443                    constant.to_rustc(tcx),
444                    ty.to_rustc(tcx),
445                )
446            }
447        }
448    }
449}
450
451#[derive(Eq, PartialEq, Hash, Clone, Debug, TyEncodable, TyDecodable)]
452pub struct OutlivesPredicate<T>(pub T, pub Region);
453
454pub type TypeOutlivesPredicate = OutlivesPredicate<Ty>;
455pub type RegionOutlivesPredicate = OutlivesPredicate<Region>;
456
457impl<'tcx, V: ToRustc<'tcx>> ToRustc<'tcx> for OutlivesPredicate<V> {
458    type T = rustc_middle::ty::OutlivesPredicate<'tcx, V::T>;
459
460    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
461        rustc_middle::ty::OutlivesPredicate(self.0.to_rustc(tcx), self.1.to_rustc(tcx))
462    }
463}
464
465#[derive(
466    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
467)]
468pub struct TraitPredicate {
469    pub trait_ref: TraitRef,
470}
471
472impl TraitPredicate {
473    fn self_ty(&self) -> SubsetTyCtor {
474        self.trait_ref.self_ty()
475    }
476}
477
478impl<'tcx> ToRustc<'tcx> for TraitPredicate {
479    type T = rustc_middle::ty::TraitPredicate<'tcx>;
480
481    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
482        rustc_middle::ty::TraitPredicate {
483            polarity: rustc_middle::ty::PredicatePolarity::Positive,
484            trait_ref: self.trait_ref.to_rustc(tcx),
485        }
486    }
487}
488
489pub type PolyTraitPredicate = Binder<TraitPredicate>;
490
491impl PolyTraitPredicate {
492    fn def_id(&self) -> DefId {
493        self.skip_binder_ref().trait_ref.def_id
494    }
495
496    fn self_ty(&self) -> Binder<SubsetTyCtor> {
497        self.clone().map(|predicate| predicate.self_ty())
498    }
499}
500
501#[derive(
502    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
503)]
504pub struct TraitRef {
505    pub def_id: DefId,
506    pub args: GenericArgs,
507}
508
509impl TraitRef {
510    pub fn self_ty(&self) -> SubsetTyCtor {
511        self.args[0].expect_base().clone()
512    }
513}
514
515impl<'tcx> ToRustc<'tcx> for TraitRef {
516    type T = rustc_middle::ty::TraitRef<'tcx>;
517
518    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
519        rustc_middle::ty::TraitRef::new(tcx, self.def_id, self.args.to_rustc(tcx))
520    }
521}
522
523pub type PolyTraitRef = Binder<TraitRef>;
524
525impl PolyTraitRef {
526    pub fn def_id(&self) -> DefId {
527        self.as_ref().skip_binder().def_id
528    }
529}
530
531#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
532pub enum ExistentialPredicate {
533    Trait(ExistentialTraitRef),
534    Projection(ExistentialProjection),
535    AutoTrait(DefId),
536}
537
538pub type PolyExistentialPredicate = Binder<ExistentialPredicate>;
539
540impl ExistentialPredicate {
541    /// See [`rustc_middle::ty::ExistentialPredicateStableCmpExt`]
542    pub fn stable_cmp(&self, tcx: TyCtxt, other: &Self) -> Ordering {
543        match (self, other) {
544            (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal,
545            (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => {
546                tcx.def_path_hash(a.def_id)
547                    .cmp(&tcx.def_path_hash(b.def_id))
548            }
549            (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) => {
550                tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
551            }
552            (ExistentialPredicate::Trait(_), _) => Ordering::Less,
553            (ExistentialPredicate::Projection(_), ExistentialPredicate::Trait(_)) => {
554                Ordering::Greater
555            }
556            (ExistentialPredicate::Projection(_), _) => Ordering::Less,
557            (ExistentialPredicate::AutoTrait(_), _) => Ordering::Greater,
558        }
559    }
560}
561
562impl<'tcx> ToRustc<'tcx> for ExistentialPredicate {
563    type T = rustc_middle::ty::ExistentialPredicate<'tcx>;
564
565    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
566        match self {
567            ExistentialPredicate::Trait(trait_ref) => {
568                let trait_ref = rustc_middle::ty::ExistentialTraitRef::new_from_args(
569                    tcx,
570                    trait_ref.def_id,
571                    trait_ref.args.to_rustc(tcx),
572                );
573                rustc_middle::ty::ExistentialPredicate::Trait(trait_ref)
574            }
575            ExistentialPredicate::Projection(projection) => {
576                rustc_middle::ty::ExistentialPredicate::Projection(
577                    rustc_middle::ty::ExistentialProjection::new_from_args(
578                        tcx,
579                        projection.def_id,
580                        projection.args.to_rustc(tcx),
581                        projection.term.skip_binder_ref().to_rustc(tcx).into(),
582                    ),
583                )
584            }
585            ExistentialPredicate::AutoTrait(def_id) => {
586                rustc_middle::ty::ExistentialPredicate::AutoTrait(*def_id)
587            }
588        }
589    }
590}
591
592#[derive(
593    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
594)]
595pub struct ExistentialTraitRef {
596    pub def_id: DefId,
597    pub args: GenericArgs,
598}
599
600pub type PolyExistentialTraitRef = Binder<ExistentialTraitRef>;
601
602impl PolyExistentialTraitRef {
603    pub fn def_id(&self) -> DefId {
604        self.as_ref().skip_binder().def_id
605    }
606}
607
608#[derive(
609    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
610)]
611pub struct ExistentialProjection {
612    pub def_id: DefId,
613    pub args: GenericArgs,
614    pub term: SubsetTyCtor,
615}
616
617#[derive(
618    PartialEq, Eq, Hash, Debug, Clone, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
619)]
620pub struct ProjectionPredicate {
621    pub projection_ty: AliasTy,
622    pub term: SubsetTyCtor,
623}
624
625impl Pretty for ProjectionPredicate {
626    fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627        write!(
628            f,
629            "ProjectionPredicate << projection_ty = {:?}, term = {:?} >>",
630            self.projection_ty, self.term
631        )
632    }
633}
634
635impl ProjectionPredicate {
636    pub fn self_ty(&self) -> SubsetTyCtor {
637        self.projection_ty.self_ty().clone()
638    }
639}
640
641impl<'tcx> ToRustc<'tcx> for ProjectionPredicate {
642    type T = rustc_middle::ty::ProjectionPredicate<'tcx>;
643
644    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
645        rustc_middle::ty::ProjectionPredicate {
646            projection_term: rustc_middle::ty::AliasTerm::new_from_args(
647                tcx,
648                self.projection_ty.def_id,
649                self.projection_ty.args.to_rustc(tcx),
650            ),
651            term: self.term.as_bty_skipping_binder().to_rustc(tcx).into(),
652        }
653    }
654}
655
656pub type PolyProjectionPredicate = Binder<ProjectionPredicate>;
657
658impl PolyProjectionPredicate {
659    pub fn projection_def_id(&self) -> DefId {
660        self.skip_binder_ref().projection_ty.def_id
661    }
662
663    pub fn self_ty(&self) -> Binder<SubsetTyCtor> {
664        self.clone().map(|predicate| predicate.self_ty())
665    }
666}
667
668#[derive(
669    Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
670)]
671pub struct FnTraitPredicate {
672    pub self_ty: Ty,
673    pub tupled_args: Ty,
674    pub output: Ty,
675    pub kind: ClosureKind,
676}
677
678impl Pretty for FnTraitPredicate {
679    fn fmt(&self, _cx: &PrettyCx, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680        write!(
681            f,
682            "self = {:?}, args = {:?}, output = {:?}, kind = {}",
683            self.self_ty, self.tupled_args, self.output, self.kind
684        )
685    }
686}
687
688impl FnTraitPredicate {
689    pub fn fndef_sig(&self) -> FnSig {
690        let inputs = self.tupled_args.expect_tuple().iter().cloned().collect();
691        let ret = self.output.clone().shift_in_escaping(1);
692        let output = Binder::bind_with_vars(FnOutput::new(ret, vec![]), List::empty());
693        FnSig::new(Safety::Safe, rustc_abi::ExternAbi::Rust, List::empty(), inputs, output)
694    }
695}
696
697pub fn to_closure_sig(
698    tcx: TyCtxt,
699    closure_id: LocalDefId,
700    tys: &[Ty],
701    args: &flux_rustc_bridge::ty::GenericArgs,
702    poly_sig: &PolyFnSig,
703) -> PolyFnSig {
704    let closure_args = args.as_closure();
705    let kind_ty = closure_args.kind_ty().to_rustc(tcx);
706    let Some(kind) = kind_ty.to_opt_closure_kind() else {
707        bug!("to_closure_sig: expected closure kind, found {kind_ty:?}");
708    };
709
710    let mut vars = poly_sig.vars().clone().to_vec();
711    let fn_sig = poly_sig.clone().skip_binder();
712    let closure_ty = Ty::closure(closure_id.into(), tys, args);
713    let env_ty = match kind {
714        ClosureKind::Fn => {
715            vars.push(BoundVariableKind::Region(BoundRegionKind::ClosureEnv));
716            let br = BoundRegion {
717                var: BoundVar::from_usize(vars.len() - 1),
718                kind: BoundRegionKind::ClosureEnv,
719            };
720            Ty::mk_ref(ReBound(INNERMOST, br), closure_ty, Mutability::Not)
721        }
722        ClosureKind::FnMut => {
723            vars.push(BoundVariableKind::Region(BoundRegionKind::ClosureEnv));
724            let br = BoundRegion {
725                var: BoundVar::from_usize(vars.len() - 1),
726                kind: BoundRegionKind::ClosureEnv,
727            };
728            Ty::mk_ref(ReBound(INNERMOST, br), closure_ty, Mutability::Mut)
729        }
730        ClosureKind::FnOnce => closure_ty,
731    };
732
733    let inputs = std::iter::once(env_ty)
734        .chain(fn_sig.inputs().iter().cloned())
735        .collect::<Vec<_>>();
736    let output = fn_sig.output().clone();
737
738    let fn_sig = crate::rty::FnSig::new(
739        fn_sig.safety,
740        fn_sig.abi,
741        fn_sig.requires.clone(), // crate::rty::List::empty(),
742        inputs.into(),
743        output,
744    );
745
746    PolyFnSig::bind_with_vars(fn_sig, List::from(vars))
747}
748
749#[derive(
750    Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
751)]
752pub struct CoroutineObligPredicate {
753    pub def_id: DefId,
754    pub resume_ty: Ty,
755    pub upvar_tys: List<Ty>,
756    pub output: Ty,
757}
758
759#[derive(Copy, Clone, Encodable, Decodable, Hash, PartialEq, Eq)]
760pub struct AssocReft {
761    pub def_id: FluxDefId,
762    // NOTE: Field is used to denote final associated generic refinements on Traits
763    pub final_: bool,
764    pub span: Span,
765}
766
767impl AssocReft {
768    pub fn new(def_id: FluxDefId, final_: bool, span: Span) -> Self {
769        Self { def_id, final_, span }
770    }
771
772    pub fn name(&self) -> Symbol {
773        self.def_id.name()
774    }
775
776    pub fn def_id(&self) -> FluxDefId {
777        self.def_id
778    }
779}
780
781#[derive(Clone, Encodable, Decodable)]
782pub struct AssocRefinements {
783    pub items: List<AssocReft>,
784}
785
786impl Default for AssocRefinements {
787    fn default() -> Self {
788        Self { items: List::empty() }
789    }
790}
791
792impl AssocRefinements {
793    pub fn get(&self, assoc_id: FluxDefId) -> AssocReft {
794        *self
795            .items
796            .into_iter()
797            .find(|it| it.def_id == assoc_id)
798            .unwrap_or_else(|| bug!("caller should guarantee existence of associated refinement"))
799    }
800
801    pub fn find(&self, name: Symbol) -> Option<AssocReft> {
802        Some(*self.items.into_iter().find(|it| it.name() == name)?)
803    }
804}
805
806#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
807pub enum SortCtor {
808    Set,
809    Map,
810    Adt(AdtSortDef),
811    User(FluxDefId),
812}
813
814newtype_index! {
815    /// [`ParamSort`] is used for polymorphic sorts (`Set`, `Map`, etc.) and [bit-vector size parameters].
816    /// They should occur "bound" under a [`PolyFuncSort`] or an [`AdtSortDef`]. We assume there's a
817    /// single binder and a [`ParamSort`] represents a variable as an index into the list of variables
818    /// bound by that binder, i.e., the representation doesnt't support higher-ranked sorts.
819    ///
820    /// [bit-vector size parameters]: BvSize::Param
821    #[debug_format = "?{}s"]
822    #[encodable]
823    pub struct ParamSort {}
824}
825
826newtype_index! {
827    /// A *sort* *v*variable *id*
828    #[debug_format = "?{}s"]
829    #[encodable]
830    pub struct SortVid {}
831}
832
833impl ena::unify::UnifyKey for SortVid {
834    type Value = SortVarVal;
835
836    #[inline]
837    fn index(&self) -> u32 {
838        self.as_u32()
839    }
840
841    #[inline]
842    fn from_index(u: u32) -> Self {
843        SortVid::from_u32(u)
844    }
845
846    fn tag() -> &'static str {
847        "SortVid"
848    }
849}
850
851bitflags! {
852    /// A *sort constraint* is a set of operations a sort must support.
853    ///
854    /// During sort checking, we accumulate the operations required for each sort variable. As
855    /// unification progresses, these constraints become more specific, i.e, a sort must support
856    /// more operations to satisfy them.
857    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
858    pub struct SortCstr: u16 {
859        /// An empty constraint (any sort satisfies it)
860        const BOT     = 0b0000000000;
861        /// `*`
862        const MUL     = 0b0000000001;
863        /// `/`
864        const DIV     = 0b0000000010;
865        /// `%`
866        const MOD     = 0b0000000100;
867        /// `+`
868        const ADD     = 0b0000001000;
869        /// `-`
870        const SUB     = 0b0000010000;
871        /// `|`
872        const BIT_OR  = 0b0000100000;
873        /// `&`
874        const BIT_AND = 0b0001000000;
875        /// `>>`
876        const BIT_SHL = 0b0010000000;
877        /// `<<`
878        const BIT_SHR = 0b0100000000;
879        /// `^`
880        const BIT_XOR = 0b1000000000;
881
882        /// The set of operations supported by all _numeric_ sorts.
883        const NUMERIC = Self::ADD.bits() | Self::SUB.bits() | Self::MUL.bits() | Self::DIV.bits();
884        /// The set of operations supported by integers.
885        const INT = Self::DIV.bits()
886            | Self::MUL.bits()
887            | Self::MOD.bits()
888            | Self::ADD.bits()
889            | Self::SUB.bits();
890        /// The set of operations supported by reals.
891        const REAL = Self::ADD.bits() | Self::SUB.bits() | Self::MUL.bits() | Self::DIV.bits();
892        /// The set of operations supported by bit vectors.
893        const BITVEC =  Self::DIV.bits()
894            | Self::MUL.bits()
895            | Self::MOD.bits()
896            | Self::ADD.bits()
897            | Self::SUB.bits()
898            | Self::BIT_OR.bits()
899            | Self::BIT_AND.bits()
900            | Self::BIT_SHL.bits()
901            | Self::BIT_SHR.bits()
902            | Self::BIT_XOR.bits();
903        /// The set of operations supported by sets.
904        const SET = Self::SUB.bits() | Self::BIT_OR.bits() | Self::BIT_AND.bits();
905    }
906}
907
908impl SortCstr {
909    /// Returns a constraint that only requires the specified binary operation.
910    pub fn from_bin_op(op: fhir::BinOp) -> Self {
911        match op {
912            fhir::BinOp::Add => Self::ADD,
913            fhir::BinOp::Sub => Self::SUB,
914            fhir::BinOp::Mul => Self::MUL,
915            fhir::BinOp::Div => Self::DIV,
916            fhir::BinOp::Mod => Self::MOD,
917            fhir::BinOp::BitAnd => Self::BIT_AND,
918            fhir::BinOp::BitOr => Self::BIT_OR,
919            fhir::BinOp::BitXor => Self::BIT_XOR,
920            fhir::BinOp::BitShl => Self::BIT_SHL,
921            fhir::BinOp::BitShr => Self::BIT_SHR,
922            _ => bug!("{op:?} not supported as a constraint"),
923        }
924    }
925
926    /// Returns whether a sort satisfies this constraint
927    fn satisfy(self, sort: &Sort) -> bool {
928        match sort {
929            Sort::Int => SortCstr::INT.contains(self),
930            Sort::Real => SortCstr::REAL.contains(self),
931            Sort::BitVec(_) => SortCstr::BITVEC.contains(self),
932            Sort::App(SortCtor::Set, _) => SortCstr::SET.contains(self),
933            _ => self == SortCstr::BOT,
934        }
935    }
936}
937
938/// Unification value for sort variables used during sort checking.
939#[derive(Debug, Clone, PartialEq, Eq)]
940pub enum SortVarVal {
941    /// The variable is not yet solved but the solution must satisfy some constraint.
942    Unsolved(SortCstr),
943    /// The variable has been solved to a sort.
944    Solved(Sort),
945}
946
947impl Default for SortVarVal {
948    fn default() -> Self {
949        SortVarVal::Unsolved(SortCstr::BOT)
950    }
951}
952
953impl SortVarVal {
954    pub fn solved_or(&self, sort: &Sort) -> Sort {
955        match self {
956            SortVarVal::Unsolved(_) => sort.clone(),
957            SortVarVal::Solved(sort) => sort.clone(),
958        }
959    }
960
961    pub fn map_solved(&self, f: impl FnOnce(&Sort) -> Sort) -> SortVarVal {
962        match self {
963            SortVarVal::Unsolved(cstr) => SortVarVal::Unsolved(*cstr),
964            SortVarVal::Solved(sort) => SortVarVal::Solved(f(sort)),
965        }
966    }
967}
968
969impl ena::unify::UnifyValue for SortVarVal {
970    type Error = ();
971
972    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
973        match (value1, value2) {
974            (SortVarVal::Solved(s1), SortVarVal::Solved(s2)) if s1 == s2 => {
975                Ok(SortVarVal::Solved(s1.clone()))
976            }
977            (SortVarVal::Unsolved(a), SortVarVal::Unsolved(b)) => Ok(SortVarVal::Unsolved(*a | *b)),
978            (SortVarVal::Unsolved(v), SortVarVal::Solved(sort))
979            | (SortVarVal::Solved(sort), SortVarVal::Unsolved(v))
980                if v.satisfy(sort) =>
981            {
982                Ok(SortVarVal::Solved(sort.clone()))
983            }
984            _ => Err(()),
985        }
986    }
987}
988
989newtype_index! {
990    /// A *b*it *v*ector *size* *v*variable *id*
991    #[debug_format = "?{}size"]
992    #[encodable]
993    pub struct BvSizeVid {}
994}
995
996impl ena::unify::UnifyKey for BvSizeVid {
997    type Value = Option<BvSize>;
998
999    #[inline]
1000    fn index(&self) -> u32 {
1001        self.as_u32()
1002    }
1003
1004    #[inline]
1005    fn from_index(u: u32) -> Self {
1006        BvSizeVid::from_u32(u)
1007    }
1008
1009    fn tag() -> &'static str {
1010        "BvSizeVid"
1011    }
1012}
1013
1014impl ena::unify::EqUnifyValue for BvSize {}
1015
1016#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1017pub enum Sort {
1018    Int,
1019    Bool,
1020    Real,
1021    BitVec(BvSize),
1022    Str,
1023    Char,
1024    Loc,
1025    Param(ParamTy),
1026    Tuple(List<Sort>),
1027    Alias(AliasKind, AliasTy),
1028    Func(PolyFuncSort),
1029    App(SortCtor, List<Sort>),
1030    Var(ParamSort),
1031    Infer(SortVid),
1032    Err,
1033}
1034
1035pub enum CastKind {
1036    /// Identity cast, which is erasable (e.g. int -> int, char -> int)
1037    Identity,
1038    /// From bool to int
1039    BoolToInt,
1040    /// Casts to unit index, (e.g. int -> float)
1041    IntoUnit,
1042    /// Uninterpreted casts, only allowed with explicit flag
1043    Uninterpreted,
1044}
1045
1046impl Sort {
1047    pub fn tuple(sorts: impl Into<List<Sort>>) -> Self {
1048        Sort::Tuple(sorts.into())
1049    }
1050
1051    pub fn app(ctor: SortCtor, sorts: List<Sort>) -> Self {
1052        Sort::App(ctor, sorts)
1053    }
1054
1055    pub fn unit() -> Self {
1056        Self::tuple(vec![])
1057    }
1058
1059    #[track_caller]
1060    pub fn expect_func(&self) -> &PolyFuncSort {
1061        if let Sort::Func(sort) = self { sort } else { bug!("expected `Sort::Func`") }
1062    }
1063
1064    pub fn is_loc(&self) -> bool {
1065        matches!(self, Sort::Loc)
1066    }
1067
1068    pub fn is_unit(&self) -> bool {
1069        matches!(self, Sort::Tuple(sorts) if sorts.is_empty())
1070    }
1071
1072    pub fn is_unit_adt(&self) -> Option<DefId> {
1073        if let Sort::App(SortCtor::Adt(sort_def), _) = self
1074            && let Some(variant) = sort_def.opt_struct_variant()
1075            && variant.fields() == 0
1076        {
1077            Some(sort_def.did())
1078        } else {
1079            None
1080        }
1081    }
1082
1083    /// Whether the sort is a function with return sort bool
1084    pub fn is_pred(&self) -> bool {
1085        matches!(self, Sort::Func(fsort) if fsort.skip_binders().output().is_bool())
1086    }
1087
1088    /// Returns `true` if the sort is [`Bool`].
1089    ///
1090    /// [`Bool`]: Sort::Bool
1091    #[must_use]
1092    pub fn is_bool(&self) -> bool {
1093        matches!(self, Self::Bool)
1094    }
1095
1096    pub fn cast_kind(self: &Sort, to: &Sort) -> CastKind {
1097        if self == to
1098            || (matches!(self, Sort::Char | Sort::Int) && matches!(to, Sort::Char | Sort::Int))
1099        {
1100            CastKind::Identity
1101        } else if matches!(self, Sort::Bool) && matches!(to, Sort::Int) {
1102            CastKind::BoolToInt
1103        } else if to.is_unit() {
1104            CastKind::IntoUnit
1105        } else {
1106            CastKind::Uninterpreted
1107        }
1108    }
1109
1110    pub fn walk(&self, mut f: impl FnMut(&Sort, &[FieldProj])) {
1111        fn go(sort: &Sort, f: &mut impl FnMut(&Sort, &[FieldProj]), proj: &mut Vec<FieldProj>) {
1112            match sort {
1113                Sort::Tuple(flds) => {
1114                    for (i, sort) in flds.iter().enumerate() {
1115                        proj.push(FieldProj::Tuple { arity: flds.len(), field: i as u32 });
1116                        go(sort, f, proj);
1117                        proj.pop();
1118                    }
1119                }
1120                Sort::App(SortCtor::Adt(sort_def), args) if sort_def.is_struct() => {
1121                    let field_sorts = sort_def.struct_variant().field_sorts(args);
1122                    for (i, sort) in field_sorts.iter().enumerate() {
1123                        proj.push(FieldProj::Adt { def_id: sort_def.did(), field: i as u32 });
1124                        go(sort, f, proj);
1125                        proj.pop();
1126                    }
1127                }
1128                _ => {
1129                    f(sort, proj);
1130                }
1131            }
1132        }
1133        go(self, &mut f, &mut vec![]);
1134    }
1135}
1136
1137/// The size of a [bit-vector]
1138///
1139/// [bit-vector]: Sort::BitVec
1140#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1141pub enum BvSize {
1142    /// A fixed size
1143    Fixed(u32),
1144    /// A size that has been parameterized, e.g., bound under a [`PolyFuncSort`]
1145    Param(ParamSort),
1146    /// A size that needs to be inferred. Used during sort checking to instantiate bit-vector
1147    /// sizes at call-sites.
1148    Infer(BvSizeVid),
1149}
1150
1151impl rustc_errors::IntoDiagArg for Sort {
1152    fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
1153        rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
1154    }
1155}
1156
1157impl rustc_errors::IntoDiagArg for FuncSort {
1158    fn into_diag_arg(self, _path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
1159        rustc_errors::DiagArgValue::Str(Cow::Owned(format!("{self:?}")))
1160    }
1161}
1162
1163#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1164pub struct FuncSort {
1165    pub inputs_and_output: List<Sort>,
1166}
1167
1168impl FuncSort {
1169    pub fn new(mut inputs: Vec<Sort>, output: Sort) -> Self {
1170        inputs.push(output);
1171        FuncSort { inputs_and_output: List::from_vec(inputs) }
1172    }
1173
1174    pub fn inputs(&self) -> &[Sort] {
1175        &self.inputs_and_output[0..self.inputs_and_output.len() - 1]
1176    }
1177
1178    pub fn output(&self) -> &Sort {
1179        &self.inputs_and_output[self.inputs_and_output.len() - 1]
1180    }
1181
1182    pub fn to_poly(&self) -> PolyFuncSort {
1183        PolyFuncSort::new(List::empty(), self.clone())
1184    }
1185}
1186
1187/// See [`PolyFuncSort`]
1188#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
1189pub enum SortParamKind {
1190    Sort,
1191    BvSize,
1192}
1193
1194/// A polymorphic function sort parametric over [sorts] or [bit-vector sizes].
1195///
1196/// Parameterizing over bit-vector sizes is a bit of a stretch, because smtlib doesn't support full
1197/// parametric reasoning over them. As long as we used functions parameterized over a size monomorphically
1198/// we should be fine. Right now, we can guarantee this, because size parameters are not exposed in
1199/// the surface syntax and they are only used for predefined (interpreted) theory functions.
1200///
1201/// [sorts]: Sort
1202/// [bit-vector sizes]: BvSize::Param
1203#[derive(Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
1204pub struct PolyFuncSort {
1205    /// The list of parameters including sorts and bit vector sizes
1206    params: List<SortParamKind>,
1207    fsort: FuncSort,
1208}
1209
1210impl PolyFuncSort {
1211    pub fn new(params: List<SortParamKind>, fsort: FuncSort) -> Self {
1212        PolyFuncSort { params, fsort }
1213    }
1214
1215    pub fn skip_binders(&self) -> FuncSort {
1216        self.fsort.clone()
1217    }
1218
1219    pub fn instantiate_identity(&self) -> FuncSort {
1220        self.fsort.clone()
1221    }
1222
1223    pub fn expect_mono(&self) -> FuncSort {
1224        assert!(self.params.is_empty());
1225        self.fsort.clone()
1226    }
1227
1228    pub fn params(&self) -> impl ExactSizeIterator<Item = SortParamKind> + '_ {
1229        self.params.iter().copied()
1230    }
1231
1232    pub fn instantiate(&self, args: &[SortArg]) -> FuncSort {
1233        self.fsort.fold_with(&mut SortSubst::new(args))
1234    }
1235}
1236
1237/// An argument for a generic parameter in a [`Sort`] which can be either a generic sort or a
1238/// generic bit-vector size.
1239#[derive(
1240    Debug, Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
1241)]
1242pub enum SortArg {
1243    Sort(Sort),
1244    BvSize(BvSize),
1245}
1246
1247#[derive(Debug, Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
1248pub enum ConstantInfo {
1249    /// An uninterpreted constant
1250    Uninterpreted,
1251    /// A non-integral constant whose value is specified by the user
1252    Interpreted(Expr, Sort),
1253}
1254
1255#[derive(Debug, Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
1256pub struct AdtDef(Interned<AdtDefData>);
1257
1258#[derive(Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
1259pub struct AdtDefData {
1260    invariants: Vec<Invariant>,
1261    sort_def: AdtSortDef,
1262    opaque: bool,
1263    rustc: ty::AdtDef,
1264}
1265
1266/// Option-like enum to explicitly mark that we don't have information about an ADT because it was
1267/// annotated with `#[flux::opaque]`. Note that only structs can be marked as opaque.
1268#[derive(Clone, Debug, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1269pub enum Opaqueness<T> {
1270    Opaque,
1271    Transparent(T),
1272}
1273
1274impl<T> Opaqueness<T> {
1275    pub fn map<S>(self, f: impl FnOnce(T) -> S) -> Opaqueness<S> {
1276        match self {
1277            Opaqueness::Opaque => Opaqueness::Opaque,
1278            Opaqueness::Transparent(value) => Opaqueness::Transparent(f(value)),
1279        }
1280    }
1281
1282    pub fn as_ref(&self) -> Opaqueness<&T> {
1283        match self {
1284            Opaqueness::Opaque => Opaqueness::Opaque,
1285            Opaqueness::Transparent(value) => Opaqueness::Transparent(value),
1286        }
1287    }
1288
1289    pub fn as_deref(&self) -> Opaqueness<&T::Target>
1290    where
1291        T: std::ops::Deref,
1292    {
1293        match self {
1294            Opaqueness::Opaque => Opaqueness::Opaque,
1295            Opaqueness::Transparent(value) => Opaqueness::Transparent(value.deref()),
1296        }
1297    }
1298
1299    pub fn ok_or_else<E>(self, err: impl FnOnce() -> E) -> Result<T, E> {
1300        match self {
1301            Opaqueness::Transparent(v) => Ok(v),
1302            Opaqueness::Opaque => Err(err()),
1303        }
1304    }
1305
1306    #[track_caller]
1307    pub fn expect(self, msg: &str) -> T {
1308        match self {
1309            Opaqueness::Transparent(val) => val,
1310            Opaqueness::Opaque => bug!("{}", msg),
1311        }
1312    }
1313
1314    pub fn ok_or_query_err(self, struct_id: DefId) -> Result<T, QueryErr> {
1315        self.ok_or_else(|| QueryErr::OpaqueStruct { struct_id })
1316    }
1317}
1318
1319impl<T, E> Opaqueness<Result<T, E>> {
1320    pub fn transpose(self) -> Result<Opaqueness<T>, E> {
1321        match self {
1322            Opaqueness::Transparent(Ok(x)) => Ok(Opaqueness::Transparent(x)),
1323            Opaqueness::Transparent(Err(e)) => Err(e),
1324            Opaqueness::Opaque => Ok(Opaqueness::Opaque),
1325        }
1326    }
1327}
1328
1329pub static INT_TYS: [IntTy; 6] =
1330    [IntTy::Isize, IntTy::I8, IntTy::I16, IntTy::I32, IntTy::I64, IntTy::I128];
1331pub static UINT_TYS: [UintTy; 6] =
1332    [UintTy::Usize, UintTy::U8, UintTy::U16, UintTy::U32, UintTy::U64, UintTy::U128];
1333
1334#[derive(
1335    Debug, Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable,
1336)]
1337pub struct Invariant {
1338    // This predicate may have sort variables, but we don't explicitly mark it like in `PolyFuncSort`.
1339    // See comment on `apply` for details.
1340    pred: Binder<Expr>,
1341}
1342
1343impl Invariant {
1344    pub fn new(pred: Binder<Expr>) -> Self {
1345        Self { pred }
1346    }
1347
1348    pub fn apply(&self, idx: &Expr) -> Expr {
1349        // The predicate may have sort variables but we don't explicitly instantiate them. This
1350        // works because within an expression, sort variables can only appear inside the sort
1351        // annotation for a lambda and invariants cannot have lambdas. It remains to instantiate
1352        // variables in the sort of the binder itself, but since we are removing it, we can avoid
1353        // the explicit instantiation. Ultimately, this works because the expression we generate in
1354        // fixpoint doesn't need sort annotations (sorts are re-inferred).
1355        self.pred.replace_bound_reft(idx)
1356    }
1357}
1358
1359pub type PolyVariants = List<Binder<VariantSig>>;
1360pub type PolyVariant = Binder<VariantSig>;
1361
1362#[derive(Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
1363pub struct VariantSig {
1364    pub adt_def: AdtDef,
1365    pub args: GenericArgs,
1366    pub fields: List<Ty>,
1367    pub idx: Expr,
1368    pub requires: List<Expr>,
1369}
1370
1371pub type PolyFnSig = Binder<FnSig>;
1372
1373#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
1374pub struct FnSig {
1375    pub safety: Safety,
1376    pub abi: rustc_abi::ExternAbi,
1377    pub requires: List<Expr>,
1378    pub inputs: List<Ty>,
1379    pub output: Binder<FnOutput>,
1380}
1381
1382#[derive(
1383    Debug, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
1384)]
1385pub struct FnOutput {
1386    pub ret: Ty,
1387    pub ensures: List<Ensures>,
1388}
1389
1390#[derive(Clone, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
1391pub enum Ensures {
1392    Type(Path, Ty),
1393    Pred(Expr),
1394}
1395
1396#[derive(Debug, TypeVisitable, TypeFoldable)]
1397pub struct Qualifier {
1398    pub def_id: FluxLocalDefId,
1399    pub body: Binder<Expr>,
1400    pub kind: QualifierKind,
1401}
1402
1403#[derive(Debug, TypeFoldable, TypeVisitable, Copy, Clone)]
1404pub enum QualifierKind {
1405    Global,
1406    Local,
1407    Hint,
1408}
1409
1410/// A `PrimOpProp` is a single property for a primitive operation which
1411/// can be conjoined to get the definition of the [`PrimRel`] for that
1412/// primitive operation.
1413#[derive(Debug, TypeVisitable, TypeFoldable)]
1414pub struct PrimOpProp {
1415    pub def_id: FluxLocalDefId,
1416    pub op: BinOp,
1417    pub body: Binder<Expr>,
1418}
1419
1420#[derive(Debug, TypeVisitable, TypeFoldable)]
1421pub struct PrimRel {
1422    pub body: Binder<Expr>,
1423}
1424
1425pub type TyCtor = Binder<Ty>;
1426
1427impl TyCtor {
1428    pub fn to_ty(&self) -> Ty {
1429        match &self.vars()[..] {
1430            [] => {
1431                return self.skip_binder_ref().shift_out_escaping(1);
1432            }
1433            [BoundVariableKind::Refine(sort, ..)] => {
1434                if sort.is_unit() {
1435                    return self.replace_bound_reft(&Expr::unit());
1436                }
1437                if let Some(def_id) = sort.is_unit_adt() {
1438                    return self.replace_bound_reft(&Expr::unit_struct(def_id));
1439                }
1440            }
1441            _ => {}
1442        }
1443        Ty::exists(self.clone())
1444    }
1445}
1446
1447#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1448pub struct Ty(Interned<TyKind>);
1449
1450impl Ty {
1451    pub fn kind(&self) -> &TyKind {
1452        &self.0
1453    }
1454
1455    /// Dummy type used for the `Self` of a `TraitRef` created when converting a trait object, and
1456    /// which gets removed in `ExistentialTraitRef`. This type must not appear anywhere in other
1457    /// converted types and must be a valid `rustc` type (i.e., we must be able to call `to_rustc`
1458    /// on it). `TyKind::Infer(TyVid(0))` does the job, with the caveat that we must skip 0 when
1459    /// generating `TyKind::Infer` for "type holes".
1460    pub fn trait_object_dummy_self() -> Ty {
1461        Ty::infer(TyVid::from_u32(0))
1462    }
1463
1464    pub fn dynamic(preds: impl Into<List<Binder<ExistentialPredicate>>>, region: Region) -> Ty {
1465        BaseTy::Dynamic(preds.into(), region).to_ty()
1466    }
1467
1468    pub fn strg_ref(re: Region, path: Path, ty: Ty) -> Ty {
1469        TyKind::StrgRef(re, path, ty).intern()
1470    }
1471
1472    pub fn ptr(pk: impl Into<PtrKind>, path: impl Into<Path>) -> Ty {
1473        TyKind::Ptr(pk.into(), path.into()).intern()
1474    }
1475
1476    pub fn constr(p: impl Into<Expr>, ty: Ty) -> Ty {
1477        TyKind::Constr(p.into(), ty).intern()
1478    }
1479
1480    pub fn uninit() -> Ty {
1481        TyKind::Uninit.intern()
1482    }
1483
1484    pub fn indexed(bty: BaseTy, idx: impl Into<Expr>) -> Ty {
1485        TyKind::Indexed(bty, idx.into()).intern()
1486    }
1487
1488    pub fn exists(ty: Binder<Ty>) -> Ty {
1489        TyKind::Exists(ty).intern()
1490    }
1491
1492    pub fn exists_with_constr(bty: BaseTy, pred: Expr) -> Ty {
1493        let sort = bty.sort();
1494        let ty = Ty::indexed(bty, Expr::nu());
1495        Ty::exists(Binder::bind_with_sort(Ty::constr(pred, ty), sort))
1496    }
1497
1498    pub fn discr(adt_def: AdtDef, place: Place) -> Ty {
1499        TyKind::Discr(adt_def, place).intern()
1500    }
1501
1502    pub fn unit() -> Ty {
1503        Ty::tuple(vec![])
1504    }
1505
1506    pub fn bool() -> Ty {
1507        BaseTy::Bool.to_ty()
1508    }
1509
1510    pub fn int(int_ty: IntTy) -> Ty {
1511        BaseTy::Int(int_ty).to_ty()
1512    }
1513
1514    pub fn uint(uint_ty: UintTy) -> Ty {
1515        BaseTy::Uint(uint_ty).to_ty()
1516    }
1517
1518    pub fn param(param_ty: ParamTy) -> Ty {
1519        TyKind::Param(param_ty).intern()
1520    }
1521
1522    pub fn downcast(
1523        adt: AdtDef,
1524        args: GenericArgs,
1525        ty: Ty,
1526        variant: VariantIdx,
1527        fields: List<Ty>,
1528    ) -> Ty {
1529        TyKind::Downcast(adt, args, ty, variant, fields).intern()
1530    }
1531
1532    pub fn blocked(ty: Ty) -> Ty {
1533        TyKind::Blocked(ty).intern()
1534    }
1535
1536    pub fn str() -> Ty {
1537        BaseTy::Str.to_ty()
1538    }
1539
1540    pub fn char() -> Ty {
1541        BaseTy::Char.to_ty()
1542    }
1543
1544    pub fn float(float_ty: FloatTy) -> Ty {
1545        BaseTy::Float(float_ty).to_ty()
1546    }
1547
1548    pub fn mk_ref(region: Region, ty: Ty, mutbl: Mutability) -> Ty {
1549        BaseTy::Ref(region, ty, mutbl).to_ty()
1550    }
1551
1552    pub fn mk_slice(ty: Ty) -> Ty {
1553        BaseTy::Slice(ty).to_ty()
1554    }
1555
1556    pub fn mk_box(genv: GlobalEnv, deref_ty: Ty, alloc_ty: Ty) -> QueryResult<Ty> {
1557        let def_id = genv.tcx().require_lang_item(LangItem::OwnedBox, DUMMY_SP);
1558        let adt_def = genv.adt_def(def_id)?;
1559
1560        let args = List::from_arr([GenericArg::Ty(deref_ty), GenericArg::Ty(alloc_ty)]);
1561
1562        let bty = BaseTy::adt(adt_def, args);
1563        Ok(Ty::indexed(bty, Expr::unit_struct(def_id)))
1564    }
1565
1566    pub fn mk_box_with_default_alloc(genv: GlobalEnv, deref_ty: Ty) -> QueryResult<Ty> {
1567        let def_id = genv.tcx().require_lang_item(LangItem::OwnedBox, DUMMY_SP);
1568
1569        let generics = genv.generics_of(def_id)?;
1570        let alloc_ty = genv
1571            .lower_type_of(generics.own_params[1].def_id)?
1572            .skip_binder()
1573            .refine(&Refiner::default_for_item(genv, def_id)?)?;
1574
1575        Ty::mk_box(genv, deref_ty, alloc_ty)
1576    }
1577
1578    pub fn tuple(tys: impl Into<List<Ty>>) -> Ty {
1579        BaseTy::Tuple(tys.into()).to_ty()
1580    }
1581
1582    pub fn array(ty: Ty, c: Const) -> Ty {
1583        BaseTy::Array(ty, c).to_ty()
1584    }
1585
1586    pub fn closure(
1587        did: DefId,
1588        tys: impl Into<List<Ty>>,
1589        args: &flux_rustc_bridge::ty::GenericArgs,
1590    ) -> Ty {
1591        BaseTy::Closure(did, tys.into(), args.clone()).to_ty()
1592    }
1593
1594    pub fn coroutine(did: DefId, resume_ty: Ty, upvar_tys: List<Ty>) -> Ty {
1595        BaseTy::Coroutine(did, resume_ty, upvar_tys).to_ty()
1596    }
1597
1598    pub fn never() -> Ty {
1599        BaseTy::Never.to_ty()
1600    }
1601
1602    pub fn infer(vid: TyVid) -> Ty {
1603        TyKind::Infer(vid).intern()
1604    }
1605
1606    pub fn unconstr(&self) -> (Ty, Expr) {
1607        fn go(this: &Ty, preds: &mut Vec<Expr>) -> Ty {
1608            if let TyKind::Constr(pred, ty) = this.kind() {
1609                preds.push(pred.clone());
1610                go(ty, preds)
1611            } else {
1612                this.clone()
1613            }
1614        }
1615        let mut preds = vec![];
1616        (go(self, &mut preds), Expr::and_from_iter(preds))
1617    }
1618
1619    pub fn unblocked(&self) -> Ty {
1620        match self.kind() {
1621            TyKind::Blocked(ty) => ty.clone(),
1622            _ => self.clone(),
1623        }
1624    }
1625
1626    /// Whether the type is an `int` or a `uint`
1627    pub fn is_integral(&self) -> bool {
1628        self.as_bty_skipping_existentials()
1629            .map(BaseTy::is_integral)
1630            .unwrap_or_default()
1631    }
1632
1633    /// Whether the type is a `bool`
1634    pub fn is_bool(&self) -> bool {
1635        self.as_bty_skipping_existentials()
1636            .map(BaseTy::is_bool)
1637            .unwrap_or_default()
1638    }
1639
1640    /// Whether the type is a `char`
1641    pub fn is_char(&self) -> bool {
1642        self.as_bty_skipping_existentials()
1643            .map(BaseTy::is_char)
1644            .unwrap_or_default()
1645    }
1646
1647    pub fn is_uninit(&self) -> bool {
1648        matches!(self.kind(), TyKind::Uninit)
1649    }
1650
1651    pub fn is_box(&self) -> bool {
1652        self.as_bty_skipping_existentials()
1653            .map(BaseTy::is_box)
1654            .unwrap_or_default()
1655    }
1656
1657    pub fn is_struct(&self) -> bool {
1658        self.as_bty_skipping_existentials()
1659            .map(BaseTy::is_struct)
1660            .unwrap_or_default()
1661    }
1662
1663    pub fn is_array(&self) -> bool {
1664        self.as_bty_skipping_existentials()
1665            .map(BaseTy::is_array)
1666            .unwrap_or_default()
1667    }
1668
1669    pub fn is_slice(&self) -> bool {
1670        self.as_bty_skipping_existentials()
1671            .map(BaseTy::is_slice)
1672            .unwrap_or_default()
1673    }
1674
1675    pub fn as_bty_skipping_existentials(&self) -> Option<&BaseTy> {
1676        match self.kind() {
1677            TyKind::Indexed(bty, _) => Some(bty),
1678            TyKind::Exists(ty) => Some(ty.skip_binder_ref().as_bty_skipping_existentials()?),
1679            TyKind::Constr(_, ty) => ty.as_bty_skipping_existentials(),
1680            _ => None,
1681        }
1682    }
1683
1684    #[track_caller]
1685    pub fn expect_discr(&self) -> (&AdtDef, &Place) {
1686        if let TyKind::Discr(adt_def, place) = self.kind() {
1687            (adt_def, place)
1688        } else {
1689            tracked_span_bug!("expected discr")
1690        }
1691    }
1692
1693    #[track_caller]
1694    pub fn expect_adt(&self) -> (&AdtDef, &[GenericArg], &Expr) {
1695        if let TyKind::Indexed(BaseTy::Adt(adt_def, args), idx) = self.kind() {
1696            (adt_def, args, idx)
1697        } else {
1698            tracked_span_bug!("expected adt `{self:?}`")
1699        }
1700    }
1701
1702    #[track_caller]
1703    pub fn expect_tuple(&self) -> &[Ty] {
1704        if let TyKind::Indexed(BaseTy::Tuple(tys), _) = self.kind() {
1705            tys
1706        } else {
1707            tracked_span_bug!("expected tuple found `{self:?}` (kind: `{:?}`)", self.kind())
1708        }
1709    }
1710
1711    pub fn simplify_type(&self) -> Option<SimplifiedType> {
1712        self.as_bty_skipping_existentials()
1713            .and_then(BaseTy::simplify_type)
1714    }
1715}
1716
1717impl<'tcx> ToRustc<'tcx> for Ty {
1718    type T = rustc_middle::ty::Ty<'tcx>;
1719
1720    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
1721        match self.kind() {
1722            TyKind::Indexed(bty, _) => bty.to_rustc(tcx),
1723            TyKind::Exists(ty) => ty.skip_binder_ref().to_rustc(tcx),
1724            TyKind::Constr(_, ty) => ty.to_rustc(tcx),
1725            TyKind::Param(pty) => pty.to_ty(tcx),
1726            TyKind::StrgRef(re, _, ty) => {
1727                rustc_middle::ty::Ty::new_ref(
1728                    tcx,
1729                    re.to_rustc(tcx),
1730                    ty.to_rustc(tcx),
1731                    Mutability::Mut,
1732                )
1733            }
1734            TyKind::Infer(vid) => rustc_middle::ty::Ty::new_var(tcx, *vid),
1735            TyKind::Uninit
1736            | TyKind::Ptr(_, _)
1737            | TyKind::Discr(..)
1738            | TyKind::Downcast(..)
1739            | TyKind::Blocked(_) => bug!("TODO: to_rustc for `{self:?}`"),
1740        }
1741    }
1742}
1743
1744#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1745pub enum TyKind {
1746    Indexed(BaseTy, Expr),
1747    Exists(Binder<Ty>),
1748    Constr(Expr, Ty),
1749    Uninit,
1750    StrgRef(Region, Path, Ty),
1751    Ptr(PtrKind, Path),
1752    /// This is a bit of a hack. We use this type internally to represent the result of
1753    /// [`Rvalue::Discriminant`] in a way that we can recover the necessary control information
1754    /// when checking a [`match`]. The hack is that we assume the dicriminant remains the same from
1755    /// the creation of this type until we use it in a [`match`].
1756    ///
1757    ///
1758    /// [`Rvalue::Discriminant`]: flux_rustc_bridge::mir::Rvalue::Discriminant
1759    /// [`match`]: flux_rustc_bridge::mir::TerminatorKind::SwitchInt
1760    Discr(AdtDef, Place),
1761    Param(ParamTy),
1762    Downcast(AdtDef, GenericArgs, Ty, VariantIdx, List<Ty>),
1763    Blocked(Ty),
1764    /// A type that needs to be inferred by matching the signature against a rust signature.
1765    /// [`TyKind::Infer`] appear as an intermediate step during `conv` and should not be present in
1766    /// the final signature.
1767    Infer(TyVid),
1768}
1769
1770#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1771pub enum PtrKind {
1772    Mut(Region),
1773    Box,
1774}
1775
1776#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1777pub enum BaseTy {
1778    Int(IntTy),
1779    Uint(UintTy),
1780    Bool,
1781    Str,
1782    Char,
1783    Slice(Ty),
1784    Adt(AdtDef, GenericArgs),
1785    Float(FloatTy),
1786    RawPtr(Ty, Mutability),
1787    RawPtrMetadata(Ty),
1788    Ref(Region, Ty, Mutability),
1789    FnPtr(PolyFnSig),
1790    FnDef(DefId, GenericArgs),
1791    Tuple(List<Ty>),
1792    Alias(AliasKind, AliasTy),
1793    Array(Ty, Const),
1794    Never,
1795    Closure(DefId, /* upvar_tys */ List<Ty>, flux_rustc_bridge::ty::GenericArgs),
1796    Coroutine(DefId, /*resume_ty: */ Ty, /* upvar_tys: */ List<Ty>),
1797    Dynamic(List<Binder<ExistentialPredicate>>, Region),
1798    Param(ParamTy),
1799    Infer(TyVid),
1800    Foreign(DefId),
1801}
1802
1803impl BaseTy {
1804    pub fn opaque(alias_ty: AliasTy) -> BaseTy {
1805        BaseTy::Alias(AliasKind::Opaque, alias_ty)
1806    }
1807
1808    pub fn projection(alias_ty: AliasTy) -> BaseTy {
1809        BaseTy::Alias(AliasKind::Projection, alias_ty)
1810    }
1811
1812    pub fn adt(adt_def: AdtDef, args: GenericArgs) -> BaseTy {
1813        BaseTy::Adt(adt_def, args)
1814    }
1815
1816    pub fn fn_def(def_id: DefId, args: impl Into<GenericArgs>) -> BaseTy {
1817        BaseTy::FnDef(def_id, args.into())
1818    }
1819
1820    pub fn from_primitive_str(s: &str) -> Option<BaseTy> {
1821        match s {
1822            "i8" => Some(BaseTy::Int(IntTy::I8)),
1823            "i16" => Some(BaseTy::Int(IntTy::I16)),
1824            "i32" => Some(BaseTy::Int(IntTy::I32)),
1825            "i64" => Some(BaseTy::Int(IntTy::I64)),
1826            "i128" => Some(BaseTy::Int(IntTy::I128)),
1827            "u8" => Some(BaseTy::Uint(UintTy::U8)),
1828            "u16" => Some(BaseTy::Uint(UintTy::U16)),
1829            "u32" => Some(BaseTy::Uint(UintTy::U32)),
1830            "u64" => Some(BaseTy::Uint(UintTy::U64)),
1831            "u128" => Some(BaseTy::Uint(UintTy::U128)),
1832            "f16" => Some(BaseTy::Float(FloatTy::F16)),
1833            "f32" => Some(BaseTy::Float(FloatTy::F32)),
1834            "f64" => Some(BaseTy::Float(FloatTy::F64)),
1835            "f128" => Some(BaseTy::Float(FloatTy::F128)),
1836            "isize" => Some(BaseTy::Int(IntTy::Isize)),
1837            "usize" => Some(BaseTy::Uint(UintTy::Usize)),
1838            "bool" => Some(BaseTy::Bool),
1839            "char" => Some(BaseTy::Char),
1840            "str" => Some(BaseTy::Str),
1841            _ => None,
1842        }
1843    }
1844
1845    /// If `self` is a primitive, return its [`Symbol`].
1846    pub fn primitive_symbol(&self) -> Option<Symbol> {
1847        match self {
1848            BaseTy::Bool => Some(sym::bool),
1849            BaseTy::Char => Some(sym::char),
1850            BaseTy::Float(f) => {
1851                match f {
1852                    FloatTy::F16 => Some(sym::f16),
1853                    FloatTy::F32 => Some(sym::f32),
1854                    FloatTy::F64 => Some(sym::f64),
1855                    FloatTy::F128 => Some(sym::f128),
1856                }
1857            }
1858            BaseTy::Int(f) => {
1859                match f {
1860                    IntTy::Isize => Some(sym::isize),
1861                    IntTy::I8 => Some(sym::i8),
1862                    IntTy::I16 => Some(sym::i16),
1863                    IntTy::I32 => Some(sym::i32),
1864                    IntTy::I64 => Some(sym::i64),
1865                    IntTy::I128 => Some(sym::i128),
1866                }
1867            }
1868            BaseTy::Uint(f) => {
1869                match f {
1870                    UintTy::Usize => Some(sym::usize),
1871                    UintTy::U8 => Some(sym::u8),
1872                    UintTy::U16 => Some(sym::u16),
1873                    UintTy::U32 => Some(sym::u32),
1874                    UintTy::U64 => Some(sym::u64),
1875                    UintTy::U128 => Some(sym::u128),
1876                }
1877            }
1878            BaseTy::Str => Some(sym::str),
1879            _ => None,
1880        }
1881    }
1882
1883    pub fn is_integral(&self) -> bool {
1884        matches!(self, BaseTy::Int(_) | BaseTy::Uint(_))
1885    }
1886
1887    pub fn is_signed(&self) -> bool {
1888        matches!(self, BaseTy::Int(_))
1889    }
1890
1891    pub fn is_unsigned(&self) -> bool {
1892        matches!(self, BaseTy::Uint(_))
1893    }
1894
1895    pub fn is_float(&self) -> bool {
1896        matches!(self, BaseTy::Float(_))
1897    }
1898
1899    pub fn is_bool(&self) -> bool {
1900        matches!(self, BaseTy::Bool)
1901    }
1902
1903    fn is_struct(&self) -> bool {
1904        matches!(self, BaseTy::Adt(adt_def, _) if adt_def.is_struct())
1905    }
1906
1907    fn is_array(&self) -> bool {
1908        matches!(self, BaseTy::Array(..))
1909    }
1910
1911    fn is_slice(&self) -> bool {
1912        matches!(self, BaseTy::Slice(..))
1913    }
1914
1915    pub fn is_box(&self) -> bool {
1916        matches!(self, BaseTy::Adt(adt_def, _) if adt_def.is_box())
1917    }
1918
1919    pub fn is_char(&self) -> bool {
1920        matches!(self, BaseTy::Char)
1921    }
1922
1923    pub fn is_str(&self) -> bool {
1924        matches!(self, BaseTy::Str)
1925    }
1926
1927    pub fn invariants(
1928        &self,
1929        tcx: TyCtxt,
1930        overflow_mode: OverflowMode,
1931    ) -> impl Iterator<Item = Invariant> {
1932        let (invariants, args) = match self {
1933            BaseTy::Adt(adt_def, args) => (adt_def.invariants().skip_binder(), &args[..]),
1934            BaseTy::Uint(uint_ty) => (uint_invariants(*uint_ty, overflow_mode), &[][..]),
1935            BaseTy::Int(int_ty) => (int_invariants(*int_ty, overflow_mode), &[][..]),
1936            BaseTy::Char => (char_invariants(), &[][..]),
1937            BaseTy::Slice(_) => (slice_invariants(overflow_mode), &[][..]),
1938            _ => (&[][..], &[][..]),
1939        };
1940        invariants
1941            .iter()
1942            .map(move |inv| EarlyBinder(inv).instantiate_ref(tcx, args, &[]))
1943    }
1944
1945    pub fn to_ty(&self) -> Ty {
1946        let sort = self.sort();
1947        if sort.is_unit() {
1948            Ty::indexed(self.clone(), Expr::unit())
1949        } else {
1950            Ty::exists(Binder::bind_with_sort(
1951                Ty::indexed(self.shift_in_escaping(1), Expr::nu()),
1952                sort,
1953            ))
1954        }
1955    }
1956
1957    pub fn to_subset_ty_ctor(&self) -> SubsetTyCtor {
1958        let sort = self.sort();
1959        Binder::bind_with_sort(SubsetTy::trivial(self.clone(), Expr::nu()), sort)
1960    }
1961
1962    #[track_caller]
1963    pub fn expect_adt(&self) -> (&AdtDef, &[GenericArg]) {
1964        if let BaseTy::Adt(adt_def, args) = self {
1965            (adt_def, args)
1966        } else {
1967            tracked_span_bug!("expected adt `{self:?}`")
1968        }
1969    }
1970
1971    /// A type is an *atom* if it is "self-delimiting", i.e., it has a clear boundary
1972    /// when printed. This is used to avoid unnecessary parenthesis when pretty printing.
1973    pub fn is_atom(&self) -> bool {
1974        // (nilehmann) I'm not sure about this list, please adjust if you get any odd behavior
1975        matches!(
1976            self,
1977            BaseTy::Int(_)
1978                | BaseTy::Uint(_)
1979                | BaseTy::Slice(_)
1980                | BaseTy::Bool
1981                | BaseTy::Char
1982                | BaseTy::Str
1983                | BaseTy::Adt(..)
1984                | BaseTy::Tuple(..)
1985                | BaseTy::Param(_)
1986                | BaseTy::Array(..)
1987                | BaseTy::Never
1988                | BaseTy::Closure(..)
1989                | BaseTy::Coroutine(..)
1990                // opaque alias are atoms the way we print them now, but they won't
1991                // be if we print them as `impl Trait`
1992                | BaseTy::Alias(..)
1993        )
1994    }
1995
1996    /// Similar to [`rustc_infer::infer::canonical::ir::fast_reject::simplify_type`].
1997    ///
1998    /// This implementation is currently incomplete, so it should only be used in contexts
1999    /// where completeness is not required. Currently, it's used to find incoherent
2000    /// implementations when resolving associated constants. In this context, incompleteness
2001    /// is acceptable since the worst case outcome is simply failing to resolve a type-relative
2002    /// constant.
2003    fn simplify_type(&self) -> Option<SimplifiedType> {
2004        match self {
2005            BaseTy::Bool => Some(SimplifiedType::Bool),
2006            BaseTy::Char => Some(SimplifiedType::Char),
2007            BaseTy::Int(int_type) => Some(SimplifiedType::Int(*int_type)),
2008            BaseTy::Uint(uint_type) => Some(SimplifiedType::Uint(*uint_type)),
2009            BaseTy::Float(float_type) => Some(SimplifiedType::Float(*float_type)),
2010            BaseTy::Adt(def, _) => Some(SimplifiedType::Adt(def.did())),
2011            BaseTy::Str => Some(SimplifiedType::Str),
2012            BaseTy::Array(..) => Some(SimplifiedType::Array),
2013            BaseTy::Slice(..) => Some(SimplifiedType::Slice),
2014            BaseTy::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(*mutbl)),
2015            BaseTy::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(*mutbl)),
2016            BaseTy::FnDef(def_id, _) | BaseTy::Closure(def_id, ..) => {
2017                Some(SimplifiedType::Closure(*def_id))
2018            }
2019            BaseTy::Coroutine(def_id, ..) => Some(SimplifiedType::Coroutine(*def_id)),
2020            BaseTy::Never => Some(SimplifiedType::Never),
2021            BaseTy::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
2022            BaseTy::FnPtr(poly_fn_sig) => {
2023                Some(SimplifiedType::Function(poly_fn_sig.skip_binder_ref().inputs().len()))
2024            }
2025            BaseTy::Foreign(def_id) => Some(SimplifiedType::Foreign(*def_id)),
2026            BaseTy::RawPtrMetadata(_)
2027            | BaseTy::Alias(..)
2028            | BaseTy::Param(_)
2029            | BaseTy::Dynamic(..)
2030            | BaseTy::Infer(_) => None,
2031        }
2032    }
2033}
2034
2035impl<'tcx> ToRustc<'tcx> for BaseTy {
2036    type T = rustc_middle::ty::Ty<'tcx>;
2037
2038    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2039        use rustc_middle::ty;
2040        match self {
2041            BaseTy::Int(i) => ty::Ty::new_int(tcx, *i),
2042            BaseTy::Uint(i) => ty::Ty::new_uint(tcx, *i),
2043            BaseTy::Param(pty) => pty.to_ty(tcx),
2044            BaseTy::Slice(ty) => ty::Ty::new_slice(tcx, ty.to_rustc(tcx)),
2045            BaseTy::Bool => tcx.types.bool,
2046            BaseTy::Char => tcx.types.char,
2047            BaseTy::Str => tcx.types.str_,
2048            BaseTy::Adt(adt_def, args) => {
2049                let did = adt_def.did();
2050                let adt_def = tcx.adt_def(did);
2051                let args = args.to_rustc(tcx);
2052                ty::Ty::new_adt(tcx, adt_def, args)
2053            }
2054            BaseTy::FnDef(def_id, args) => {
2055                let args = args.to_rustc(tcx);
2056                ty::Ty::new_fn_def(tcx, *def_id, args)
2057            }
2058            BaseTy::Float(f) => ty::Ty::new_float(tcx, *f),
2059            BaseTy::RawPtr(ty, mutbl) => ty::Ty::new_ptr(tcx, ty.to_rustc(tcx), *mutbl),
2060            BaseTy::Ref(re, ty, mutbl) => {
2061                ty::Ty::new_ref(tcx, re.to_rustc(tcx), ty.to_rustc(tcx), *mutbl)
2062            }
2063            BaseTy::FnPtr(poly_sig) => ty::Ty::new_fn_ptr(tcx, poly_sig.to_rustc(tcx)),
2064            BaseTy::Tuple(tys) => {
2065                let ts = tys.iter().map(|ty| ty.to_rustc(tcx)).collect_vec();
2066                ty::Ty::new_tup(tcx, &ts)
2067            }
2068            BaseTy::Alias(kind, alias_ty) => {
2069                ty::Ty::new_alias(tcx, kind.to_rustc(tcx), alias_ty.to_rustc(tcx))
2070            }
2071            BaseTy::Array(ty, n) => {
2072                let ty = ty.to_rustc(tcx);
2073                let n = n.to_rustc(tcx);
2074                ty::Ty::new_array_with_const_len(tcx, ty, n)
2075            }
2076            BaseTy::Never => tcx.types.never,
2077            BaseTy::Closure(did, _, args) => ty::Ty::new_closure(tcx, *did, args.to_rustc(tcx)),
2078            BaseTy::Dynamic(exi_preds, re) => {
2079                let preds: Vec<_> = exi_preds
2080                    .iter()
2081                    .map(|pred| pred.to_rustc(tcx))
2082                    .collect_vec();
2083                let preds = tcx.mk_poly_existential_predicates(&preds);
2084                ty::Ty::new_dynamic(tcx, preds, re.to_rustc(tcx))
2085            }
2086            BaseTy::Coroutine(def_id, resume_ty, upvars) => {
2087                bug!("TODO: Generator {def_id:?} {resume_ty:?} {upvars:?}")
2088                // let args = args.iter().map(|arg| into_rustc_generic_arg(tcx, arg));
2089                // let args = tcx.mk_args_from_iter(args);
2090                // ty::Ty::new_generator(*tcx, *def_id, args, mov)
2091            }
2092            BaseTy::Infer(ty_vid) => ty::Ty::new_var(tcx, *ty_vid),
2093            BaseTy::Foreign(def_id) => ty::Ty::new_foreign(tcx, *def_id),
2094            BaseTy::RawPtrMetadata(ty) => {
2095                ty::Ty::new_ptr(
2096                    tcx,
2097                    ty.to_rustc(tcx),
2098                    RawPtrKind::FakeForPtrMetadata.to_mutbl_lossy(),
2099                )
2100            }
2101        }
2102    }
2103}
2104
2105#[derive(
2106    Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
2107)]
2108pub struct AliasTy {
2109    pub def_id: DefId,
2110    pub args: GenericArgs,
2111    /// Holds the refinement-arguments for opaque-types; empty for projections
2112    pub refine_args: RefineArgs,
2113}
2114
2115impl AliasTy {
2116    pub fn new(def_id: DefId, args: GenericArgs, refine_args: RefineArgs) -> Self {
2117        AliasTy { args, refine_args, def_id }
2118    }
2119}
2120
2121/// This methods work only with associated type projections (i.e., no opaque types)
2122impl AliasTy {
2123    pub fn self_ty(&self) -> SubsetTyCtor {
2124        self.args[0].expect_base().clone()
2125    }
2126
2127    pub fn with_self_ty(&self, self_ty: SubsetTyCtor) -> Self {
2128        Self {
2129            def_id: self.def_id,
2130            args: [GenericArg::Base(self_ty)]
2131                .into_iter()
2132                .chain(self.args.iter().skip(1).cloned())
2133                .collect(),
2134            refine_args: self.refine_args.clone(),
2135        }
2136    }
2137}
2138
2139impl<'tcx> ToRustc<'tcx> for AliasTy {
2140    type T = rustc_middle::ty::AliasTy<'tcx>;
2141
2142    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2143        rustc_middle::ty::AliasTy::new(tcx, self.def_id, self.args.to_rustc(tcx))
2144    }
2145}
2146
2147pub type RefineArgs = List<Expr>;
2148
2149#[extension(pub trait RefineArgsExt)]
2150impl RefineArgs {
2151    fn identity_for_item(genv: GlobalEnv, def_id: DefId) -> QueryResult<RefineArgs> {
2152        Self::for_item(genv, def_id, |param, index| {
2153            Ok(Expr::var(Var::EarlyParam(EarlyReftParam {
2154                index: index as u32,
2155                name: param.name(),
2156            })))
2157        })
2158    }
2159
2160    fn for_item<F>(genv: GlobalEnv, def_id: DefId, mut mk: F) -> QueryResult<RefineArgs>
2161    where
2162        F: FnMut(EarlyBinder<RefineParam>, usize) -> QueryResult<Expr>,
2163    {
2164        let reft_generics = genv.refinement_generics_of(def_id)?;
2165        let count = reft_generics.count();
2166        let mut args = Vec::with_capacity(count);
2167        reft_generics.fill_item(genv, &mut args, &mut mk)?;
2168        Ok(List::from_vec(args))
2169    }
2170}
2171
2172/// A type constructor meant to be used as generic a argument of [kind base]. This is just an alias
2173/// to [`Binder<SubsetTy>`], but we expect the binder to have a single bound variable of the sort of
2174/// the underlying [base type].
2175///
2176/// [kind base]: GenericParamDefKind::Base
2177/// [base type]: SubsetTy::bty
2178pub type SubsetTyCtor = Binder<SubsetTy>;
2179
2180impl SubsetTyCtor {
2181    pub fn as_bty_skipping_binder(&self) -> &BaseTy {
2182        &self.as_ref().skip_binder().bty
2183    }
2184
2185    pub fn to_ty(&self) -> Ty {
2186        let sort = self.sort();
2187        if sort.is_unit() {
2188            self.replace_bound_reft(&Expr::unit()).to_ty()
2189        } else if let Some(def_id) = sort.is_unit_adt() {
2190            self.replace_bound_reft(&Expr::unit_struct(def_id)).to_ty()
2191        } else {
2192            Ty::exists(self.as_ref().map(SubsetTy::to_ty))
2193        }
2194    }
2195
2196    pub fn to_ty_ctor(&self) -> TyCtor {
2197        self.as_ref().map(SubsetTy::to_ty)
2198    }
2199}
2200
2201/// A subset type is a simplified version of a type that has the form `{b[e] | p}` where `b` is a
2202/// [`BaseTy`], `e` a refinement index, and `p` a predicate.
2203///
2204/// These are mainly found under a [`Binder`] with a single variable of the base type's sort. This
2205/// can be interpreted as a type constructor or an existential type. For example, under a binder with a
2206/// variable `v` of sort `int`, we can interpret `{i32[v] | v > 0}` as:
2207/// - A lambda `λv:int. {i32[v] | v > 0}` that "constructs" types when applied to ints, or
2208/// - An existential type `∃v:int. {i32[v] | v > 0}`.
2209///
2210/// This second interpretation is the reason we call this a subset type, i.e., the type `∃v. {b[v] | p}`
2211/// corresponds to the subset of values of  type `b` whose index satisfies `p`. These are the types
2212/// written as `B{v: p}` in the surface syntax and correspond to the types supported in other
2213/// refinement type systems like Liquid Haskell (with the difference that we are explicit
2214/// about separating refinements from program values via an index).
2215///
2216/// The main purpose for subset types is to be used as generic arguments of [kind base] when
2217/// interpreted as type constructors. They have two key properties that makes them suitable
2218/// for this:
2219///
2220/// 1. **Syntactic Restriction**: Subset types are syntactically restricted, making it easier to
2221///    relate them structurally (e.g., for subtyping). For instance, given two types `S<λv. T1>` and
2222///    `S<λ. T2>`, if `T1` and `T2` are subset types, we know they match structurally (at least
2223///    shallowly). In particularly, the syntactic restriction rules out complex types like
2224///    `S<λv. (i32[v], i32[v])>` simplifying some operations.
2225///
2226/// 2. **Eager Canonicalization**: Subset types can be eagerly canonicalized via [*strengthening*]
2227///    during substitution. For example, suppose we have a function:
2228///    ```text
2229///    fn foo<T>(x: T[@a], y: { T[@b] | b == a }) { }
2230///    ```
2231///    If we instantiate `T` with `λv. { i32[v] | v > 0}`, after substitution and applying the
2232///    lambda (the indexing syntax `T[a]` corresponds to an application of the lambda), we get:
2233///    ```text
2234///    fn foo(x: {i32[@a] | a > 0}, y: { { i32[@b] | b > 0 } | b == a }) { }
2235///    ```
2236///    Via *strengthening* we can canonicalize this to
2237///    ```text
2238///    fn foo(x: {i32[@a] | a > 0}, y: { i32[@b] | b == a && b > 0 }) { }
2239///    ```
2240///    As a result, we can guarantee the syntactic restriction through substitution.
2241///
2242/// [kind base]: GenericParamDefKind::Base
2243/// [*strengthening*]: https://arxiv.org/pdf/2010.07763.pdf
2244#[derive(PartialEq, Clone, Eq, Hash, TyEncodable, TyDecodable)]
2245pub struct SubsetTy {
2246    /// The base type `b` in the subset type `{b[e] | p}`.
2247    ///
2248    /// **NOTE:** This is mostly going to be under a [`Binder`]. It is not yet clear to me whether
2249    /// this [`BaseTy`] should be able to mention variables in the binder. In general, in a type
2250    /// `∃v. {b[e] | p}`, it's fine to mention `v` inside `b`, but since [`SubsetTy`] is meant to
2251    /// facilitate syntactic manipulation we may want to restrict this.
2252    pub bty: BaseTy,
2253    /// The refinement index `e` in the subset type `{b[e] | p}`. This can be an arbitrary expression,
2254    /// which makes manipulation easier. However, since this is mostly found under a binder, we expect
2255    /// it to be [`Expr::nu()`].
2256    pub idx: Expr,
2257    /// The predicate `p` in the subset type `{b[e] | p}`.
2258    pub pred: Expr,
2259}
2260
2261impl SubsetTy {
2262    pub fn new(bty: BaseTy, idx: impl Into<Expr>, pred: impl Into<Expr>) -> Self {
2263        Self { bty, idx: idx.into(), pred: pred.into() }
2264    }
2265
2266    pub fn trivial(bty: BaseTy, idx: impl Into<Expr>) -> Self {
2267        Self::new(bty, idx, Expr::tt())
2268    }
2269
2270    pub fn strengthen(&self, pred: impl Into<Expr>) -> Self {
2271        let this = self.clone();
2272        let pred = Expr::and(this.pred, pred).simplify(&SnapshotMap::default());
2273        Self { bty: this.bty, idx: this.idx, pred }
2274    }
2275
2276    pub fn to_ty(&self) -> Ty {
2277        let bty = self.bty.clone();
2278        if self.pred.is_trivially_true() {
2279            Ty::indexed(bty, &self.idx)
2280        } else {
2281            Ty::constr(&self.pred, Ty::indexed(bty, &self.idx))
2282        }
2283    }
2284}
2285
2286impl<'tcx> ToRustc<'tcx> for SubsetTy {
2287    type T = rustc_middle::ty::Ty<'tcx>;
2288
2289    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::Ty<'tcx> {
2290        self.bty.to_rustc(tcx)
2291    }
2292}
2293
2294#[derive(PartialEq, Clone, Eq, Hash, TyEncodable, TyDecodable)]
2295pub enum GenericArg {
2296    Ty(Ty),
2297    Base(SubsetTyCtor),
2298    Lifetime(Region),
2299    Const(Const),
2300}
2301
2302impl GenericArg {
2303    #[track_caller]
2304    pub fn expect_type(&self) -> &Ty {
2305        if let GenericArg::Ty(ty) = self {
2306            ty
2307        } else {
2308            bug!("expected `rty::GenericArg::Ty`, found `{self:?}`")
2309        }
2310    }
2311
2312    #[track_caller]
2313    pub fn expect_base(&self) -> &SubsetTyCtor {
2314        if let GenericArg::Base(ctor) = self {
2315            ctor
2316        } else {
2317            bug!("expected `rty::GenericArg::Base`, found `{self:?}`")
2318        }
2319    }
2320
2321    pub fn from_param_def(param: &GenericParamDef) -> Self {
2322        match param.kind {
2323            GenericParamDefKind::Type { .. } => {
2324                let param_ty = ParamTy { index: param.index, name: param.name };
2325                GenericArg::Ty(Ty::param(param_ty))
2326            }
2327            GenericParamDefKind::Base { .. } => {
2328                // λv. T[v]
2329                let param_ty = ParamTy { index: param.index, name: param.name };
2330                GenericArg::Base(Binder::bind_with_sort(
2331                    SubsetTy::trivial(BaseTy::Param(param_ty), Expr::nu()),
2332                    Sort::Param(param_ty),
2333                ))
2334            }
2335            GenericParamDefKind::Lifetime => {
2336                let region = EarlyParamRegion { index: param.index, name: param.name };
2337                GenericArg::Lifetime(Region::ReEarlyParam(region))
2338            }
2339            GenericParamDefKind::Const { .. } => {
2340                let param_const = ParamConst { index: param.index, name: param.name };
2341                let kind = ConstKind::Param(param_const);
2342                GenericArg::Const(Const { kind })
2343            }
2344        }
2345    }
2346
2347    /// Creates a `GenericArgs` from the definition of generic parameters, by calling a closure to
2348    /// obtain arg. The closures get to observe the `GenericArgs` as they're being built, which can
2349    /// be used to correctly replace defaults of generic parameters.
2350    pub fn for_item<F>(genv: GlobalEnv, def_id: DefId, mut mk_kind: F) -> QueryResult<GenericArgs>
2351    where
2352        F: FnMut(&GenericParamDef, &[GenericArg]) -> GenericArg,
2353    {
2354        let defs = genv.generics_of(def_id)?;
2355        let count = defs.count();
2356        let mut args = Vec::with_capacity(count);
2357        Self::fill_item(genv, &mut args, &defs, &mut mk_kind)?;
2358        Ok(List::from_vec(args))
2359    }
2360
2361    pub fn identity_for_item(genv: GlobalEnv, def_id: DefId) -> QueryResult<GenericArgs> {
2362        Self::for_item(genv, def_id, |param, _| GenericArg::from_param_def(param))
2363    }
2364
2365    fn fill_item<F>(
2366        genv: GlobalEnv,
2367        args: &mut Vec<GenericArg>,
2368        generics: &Generics,
2369        mk_kind: &mut F,
2370    ) -> QueryResult<()>
2371    where
2372        F: FnMut(&GenericParamDef, &[GenericArg]) -> GenericArg,
2373    {
2374        if let Some(def_id) = generics.parent {
2375            let parent_generics = genv.generics_of(def_id)?;
2376            Self::fill_item(genv, args, &parent_generics, mk_kind)?;
2377        }
2378        for param in &generics.own_params {
2379            let kind = mk_kind(param, args);
2380            tracked_span_assert_eq!(param.index as usize, args.len());
2381            args.push(kind);
2382        }
2383        Ok(())
2384    }
2385}
2386
2387impl From<TyOrBase> for GenericArg {
2388    fn from(v: TyOrBase) -> Self {
2389        match v {
2390            TyOrBase::Ty(ty) => GenericArg::Ty(ty),
2391            TyOrBase::Base(ctor) => GenericArg::Base(ctor),
2392        }
2393    }
2394}
2395
2396impl<'tcx> ToRustc<'tcx> for GenericArg {
2397    type T = rustc_middle::ty::GenericArg<'tcx>;
2398
2399    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2400        use rustc_middle::ty;
2401        match self {
2402            GenericArg::Ty(ty) => ty::GenericArg::from(ty.to_rustc(tcx)),
2403            GenericArg::Base(ctor) => ty::GenericArg::from(ctor.skip_binder_ref().to_rustc(tcx)),
2404            GenericArg::Lifetime(re) => ty::GenericArg::from(re.to_rustc(tcx)),
2405            GenericArg::Const(c) => ty::GenericArg::from(c.to_rustc(tcx)),
2406        }
2407    }
2408}
2409
2410pub type GenericArgs = List<GenericArg>;
2411
2412#[extension(pub trait GenericArgsExt)]
2413impl GenericArgs {
2414    #[track_caller]
2415    fn box_args(&self) -> (&Ty, &Ty) {
2416        if let [GenericArg::Ty(deref), GenericArg::Ty(alloc)] = &self[..] {
2417            (deref, alloc)
2418        } else {
2419            bug!("invalid generic arguments for box");
2420        }
2421    }
2422
2423    // We can't implement [`ToRustc`] because of coherence so we add it here
2424    fn to_rustc<'tcx>(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::GenericArgsRef<'tcx> {
2425        tcx.mk_args_from_iter(self.iter().map(|arg| arg.to_rustc(tcx)))
2426    }
2427
2428    fn rebase_onto(
2429        &self,
2430        tcx: &TyCtxt,
2431        source_ancestor: DefId,
2432        target_args: &GenericArgs,
2433    ) -> List<GenericArg> {
2434        let defs = tcx.generics_of(source_ancestor);
2435        target_args
2436            .iter()
2437            .chain(self.iter().skip(defs.count()))
2438            .cloned()
2439            .collect()
2440    }
2441}
2442
2443#[derive(Debug)]
2444pub enum TyOrBase {
2445    Ty(Ty),
2446    Base(SubsetTyCtor),
2447}
2448
2449impl TyOrBase {
2450    pub fn into_ty(self) -> Ty {
2451        match self {
2452            TyOrBase::Ty(ty) => ty,
2453            TyOrBase::Base(ctor) => ctor.to_ty(),
2454        }
2455    }
2456
2457    #[track_caller]
2458    pub fn expect_base(self) -> SubsetTyCtor {
2459        match self {
2460            TyOrBase::Base(ctor) => ctor,
2461            TyOrBase::Ty(_) => tracked_span_bug!("expected `TyOrBase::Base`"),
2462        }
2463    }
2464
2465    pub fn as_base(self) -> Option<SubsetTyCtor> {
2466        match self {
2467            TyOrBase::Base(ctor) => Some(ctor),
2468            TyOrBase::Ty(_) => None,
2469        }
2470    }
2471}
2472
2473#[derive(Debug, Clone, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
2474pub enum TyOrCtor {
2475    Ty(Ty),
2476    Ctor(TyCtor),
2477}
2478
2479impl TyOrCtor {
2480    #[track_caller]
2481    pub fn expect_ctor(self) -> TyCtor {
2482        match self {
2483            TyOrCtor::Ctor(ctor) => ctor,
2484            TyOrCtor::Ty(_) => tracked_span_bug!("expected `TyOrCtor::Ctor`"),
2485        }
2486    }
2487
2488    pub fn expect_subset_ty_ctor(self) -> SubsetTyCtor {
2489        self.expect_ctor().map(|ty| {
2490            if let canonicalize::CanonicalTy::Constr(constr_ty) = ty.shallow_canonicalize()
2491                && let TyKind::Indexed(bty, idx) = constr_ty.ty().kind()
2492                && idx.is_nu()
2493            {
2494                SubsetTy::new(bty.clone(), Expr::nu(), constr_ty.pred())
2495            } else {
2496                tracked_span_bug!()
2497            }
2498        })
2499    }
2500
2501    pub fn to_ty(&self) -> Ty {
2502        match self {
2503            TyOrCtor::Ctor(ctor) => ctor.to_ty(),
2504            TyOrCtor::Ty(ty) => ty.clone(),
2505        }
2506    }
2507}
2508
2509impl From<TyOrBase> for TyOrCtor {
2510    fn from(v: TyOrBase) -> Self {
2511        match v {
2512            TyOrBase::Ty(ty) => TyOrCtor::Ty(ty),
2513            TyOrBase::Base(ctor) => TyOrCtor::Ctor(ctor.to_ty_ctor()),
2514        }
2515    }
2516}
2517
2518impl CoroutineObligPredicate {
2519    pub fn to_poly_fn_sig(&self) -> PolyFnSig {
2520        let vars = vec![];
2521
2522        let resume_ty = &self.resume_ty;
2523        let env_ty = Ty::coroutine(self.def_id, resume_ty.clone(), self.upvar_tys.clone());
2524
2525        let inputs = List::from_arr([env_ty, resume_ty.clone()]);
2526        let output =
2527            Binder::bind_with_vars(FnOutput::new(self.output.clone(), vec![]), List::empty());
2528
2529        PolyFnSig::bind_with_vars(
2530            FnSig::new(Safety::Safe, rustc_abi::ExternAbi::RustCall, List::empty(), inputs, output),
2531            List::from(vars),
2532        )
2533    }
2534}
2535
2536impl RefinementGenerics {
2537    pub fn count(&self) -> usize {
2538        self.parent_count + self.own_params.len()
2539    }
2540
2541    pub fn own_count(&self) -> usize {
2542        self.own_params.len()
2543    }
2544}
2545
2546impl EarlyBinder<RefinementGenerics> {
2547    pub fn parent(&self) -> Option<DefId> {
2548        self.skip_binder_ref().parent
2549    }
2550
2551    pub fn parent_count(&self) -> usize {
2552        self.skip_binder_ref().parent_count
2553    }
2554
2555    pub fn count(&self) -> usize {
2556        self.skip_binder_ref().count()
2557    }
2558
2559    pub fn own_count(&self) -> usize {
2560        self.skip_binder_ref().own_count()
2561    }
2562
2563    pub fn own_param_at(&self, index: usize) -> EarlyBinder<RefineParam> {
2564        self.as_ref().map(|this| this.own_params[index].clone())
2565    }
2566
2567    pub fn param_at(
2568        &self,
2569        param_index: usize,
2570        genv: GlobalEnv,
2571    ) -> QueryResult<EarlyBinder<RefineParam>> {
2572        if let Some(index) = param_index.checked_sub(self.parent_count()) {
2573            Ok(self.own_param_at(index))
2574        } else {
2575            let parent = self.parent().expect("parent_count > 0 but no parent?");
2576            genv.refinement_generics_of(parent)?
2577                .param_at(param_index, genv)
2578        }
2579    }
2580
2581    pub fn iter_own_params(&self) -> impl Iterator<Item = EarlyBinder<RefineParam>> + use<'_> {
2582        self.skip_binder_ref()
2583            .own_params
2584            .iter()
2585            .cloned()
2586            .map(EarlyBinder)
2587    }
2588
2589    pub fn fill_item<F, R>(&self, genv: GlobalEnv, vec: &mut Vec<R>, mk: &mut F) -> QueryResult
2590    where
2591        F: FnMut(EarlyBinder<RefineParam>, usize) -> QueryResult<R>,
2592    {
2593        if let Some(def_id) = self.parent() {
2594            genv.refinement_generics_of(def_id)?
2595                .fill_item(genv, vec, mk)?;
2596        }
2597        for param in self.iter_own_params() {
2598            vec.push(mk(param, vec.len())?);
2599        }
2600        Ok(())
2601    }
2602}
2603
2604impl EarlyBinder<GenericPredicates> {
2605    pub fn predicates(&self) -> EarlyBinder<List<Clause>> {
2606        EarlyBinder(self.0.predicates.clone())
2607    }
2608}
2609
2610impl EarlyBinder<FuncSort> {
2611    /// See [`subst::GenericsSubstForSort`]
2612    pub fn instantiate_func_sort<E>(
2613        self,
2614        sort_for_param: impl FnMut(ParamTy) -> Result<Sort, E>,
2615    ) -> Result<FuncSort, E> {
2616        self.0.try_fold_with(&mut subst::GenericsSubstFolder::new(
2617            subst::GenericsSubstForSort { sort_for_param },
2618            &[],
2619        ))
2620    }
2621}
2622
2623impl VariantSig {
2624    pub fn new(
2625        adt_def: AdtDef,
2626        args: GenericArgs,
2627        fields: List<Ty>,
2628        idx: Expr,
2629        requires: List<Expr>,
2630    ) -> Self {
2631        VariantSig { adt_def, args, fields, idx, requires }
2632    }
2633
2634    pub fn fields(&self) -> &[Ty] {
2635        &self.fields
2636    }
2637
2638    pub fn ret(&self) -> Ty {
2639        let bty = BaseTy::Adt(self.adt_def.clone(), self.args.clone());
2640        let idx = self.idx.clone();
2641        Ty::indexed(bty, idx)
2642    }
2643}
2644
2645impl FnSig {
2646    pub fn new(
2647        safety: Safety,
2648        abi: rustc_abi::ExternAbi,
2649        requires: List<Expr>,
2650        inputs: List<Ty>,
2651        output: Binder<FnOutput>,
2652    ) -> Self {
2653        FnSig { safety, abi, requires, inputs, output }
2654    }
2655
2656    pub fn requires(&self) -> &[Expr] {
2657        &self.requires
2658    }
2659
2660    pub fn inputs(&self) -> &[Ty] {
2661        &self.inputs
2662    }
2663
2664    pub fn output(&self) -> Binder<FnOutput> {
2665        self.output.clone()
2666    }
2667}
2668
2669impl<'tcx> ToRustc<'tcx> for FnSig {
2670    type T = rustc_middle::ty::FnSig<'tcx>;
2671
2672    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2673        tcx.mk_fn_sig(
2674            self.inputs().iter().map(|ty| ty.to_rustc(tcx)),
2675            self.output().as_ref().skip_binder().to_rustc(tcx),
2676            false,
2677            self.safety,
2678            self.abi,
2679        )
2680    }
2681}
2682
2683impl FnOutput {
2684    pub fn new(ret: Ty, ensures: impl Into<List<Ensures>>) -> Self {
2685        Self { ret, ensures: ensures.into() }
2686    }
2687}
2688
2689impl<'tcx> ToRustc<'tcx> for FnOutput {
2690    type T = rustc_middle::ty::Ty<'tcx>;
2691
2692    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2693        self.ret.to_rustc(tcx)
2694    }
2695}
2696
2697impl AdtDef {
2698    pub fn new(
2699        rustc: ty::AdtDef,
2700        sort_def: AdtSortDef,
2701        invariants: Vec<Invariant>,
2702        opaque: bool,
2703    ) -> Self {
2704        AdtDef(Interned::new(AdtDefData { invariants, sort_def, opaque, rustc }))
2705    }
2706
2707    pub fn did(&self) -> DefId {
2708        self.0.rustc.did()
2709    }
2710
2711    pub fn sort_def(&self) -> &AdtSortDef {
2712        &self.0.sort_def
2713    }
2714
2715    pub fn sort(&self, args: &[GenericArg]) -> Sort {
2716        self.sort_def().to_sort(args)
2717    }
2718
2719    pub fn is_box(&self) -> bool {
2720        self.0.rustc.is_box()
2721    }
2722
2723    pub fn is_enum(&self) -> bool {
2724        self.0.rustc.is_enum()
2725    }
2726
2727    pub fn is_struct(&self) -> bool {
2728        self.0.rustc.is_struct()
2729    }
2730
2731    pub fn is_union(&self) -> bool {
2732        self.0.rustc.is_union()
2733    }
2734
2735    pub fn variants(&self) -> &IndexSlice<VariantIdx, VariantDef> {
2736        self.0.rustc.variants()
2737    }
2738
2739    pub fn variant(&self, idx: VariantIdx) -> &VariantDef {
2740        self.0.rustc.variant(idx)
2741    }
2742
2743    pub fn invariants(&self) -> EarlyBinder<&[Invariant]> {
2744        EarlyBinder(&self.0.invariants)
2745    }
2746
2747    pub fn discriminants(&self) -> impl Iterator<Item = (VariantIdx, u128)> + '_ {
2748        self.0.rustc.discriminants()
2749    }
2750
2751    pub fn is_opaque(&self) -> bool {
2752        self.0.opaque
2753    }
2754}
2755
2756impl EarlyBinder<PolyVariant> {
2757    // The field_idx is `Some(i)` when we have the `i`-th field of a `union`, in which case,
2758    // the `inputs` are _just_ the `i`-th type (and not all the types...)
2759    pub fn to_poly_fn_sig(&self, field_idx: Option<crate::FieldIdx>) -> EarlyBinder<PolyFnSig> {
2760        self.as_ref().map(|poly_variant| {
2761            poly_variant.as_ref().map(|variant| {
2762                let ret = variant.ret().shift_in_escaping(1);
2763                let output = Binder::bind_with_vars(FnOutput::new(ret, vec![]), List::empty());
2764                let inputs = match field_idx {
2765                    None => variant.fields.clone(),
2766                    Some(i) => List::singleton(variant.fields[i.index()].clone()),
2767                };
2768                FnSig::new(
2769                    Safety::Safe,
2770                    rustc_abi::ExternAbi::Rust,
2771                    variant.requires.clone(),
2772                    inputs,
2773                    output,
2774                )
2775            })
2776        })
2777    }
2778}
2779
2780impl TyKind {
2781    fn intern(self) -> Ty {
2782        Ty(Interned::new(self))
2783    }
2784}
2785
2786/// returns the same invariants as for `usize` which is the length of a slice
2787fn slice_invariants(overflow_mode: OverflowMode) -> &'static [Invariant] {
2788    static DEFAULT: LazyLock<[Invariant; 1]> = LazyLock::new(|| {
2789        [Invariant { pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int) }]
2790    });
2791    static OVERFLOW: LazyLock<[Invariant; 2]> = LazyLock::new(|| {
2792        [
2793            Invariant {
2794                pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int),
2795            },
2796            Invariant {
2797                pred: Binder::bind_with_sort(
2798                    Expr::le(Expr::nu(), Expr::uint_max(UintTy::Usize)),
2799                    Sort::Int,
2800                ),
2801            },
2802        ]
2803    });
2804    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2805        &*OVERFLOW
2806    } else {
2807        &*DEFAULT
2808    }
2809}
2810
2811fn uint_invariants(uint_ty: UintTy, overflow_mode: OverflowMode) -> &'static [Invariant] {
2812    static DEFAULT: LazyLock<[Invariant; 1]> = LazyLock::new(|| {
2813        [Invariant { pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int) }]
2814    });
2815
2816    static OVERFLOW: LazyLock<UnordMap<UintTy, [Invariant; 2]>> = LazyLock::new(|| {
2817        UINT_TYS
2818            .into_iter()
2819            .map(|uint_ty| {
2820                let invariants = [
2821                    Invariant {
2822                        pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int),
2823                    },
2824                    Invariant {
2825                        pred: Binder::bind_with_sort(
2826                            Expr::le(Expr::nu(), Expr::uint_max(uint_ty)),
2827                            Sort::Int,
2828                        ),
2829                    },
2830                ];
2831                (uint_ty, invariants)
2832            })
2833            .collect()
2834    });
2835    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2836        &OVERFLOW[&uint_ty]
2837    } else {
2838        &*DEFAULT
2839    }
2840}
2841
2842fn char_invariants() -> &'static [Invariant] {
2843    static INVARIANTS: LazyLock<[Invariant; 2]> = LazyLock::new(|| {
2844        [
2845            Invariant {
2846                pred: Binder::bind_with_sort(
2847                    Expr::le(
2848                        Expr::cast(Sort::Char, Sort::Int, Expr::nu()),
2849                        Expr::constant((char::MAX as u32).into()),
2850                    ),
2851                    Sort::Int,
2852                ),
2853            },
2854            Invariant {
2855                pred: Binder::bind_with_sort(
2856                    Expr::le(Expr::zero(), Expr::cast(Sort::Char, Sort::Int, Expr::nu())),
2857                    Sort::Int,
2858                ),
2859            },
2860        ]
2861    });
2862    &*INVARIANTS
2863}
2864
2865fn int_invariants(int_ty: IntTy, overflow_mode: OverflowMode) -> &'static [Invariant] {
2866    static DEFAULT: [Invariant; 0] = [];
2867
2868    static OVERFLOW: LazyLock<UnordMap<IntTy, [Invariant; 2]>> = LazyLock::new(|| {
2869        INT_TYS
2870            .into_iter()
2871            .map(|int_ty| {
2872                let invariants = [
2873                    Invariant {
2874                        pred: Binder::bind_with_sort(
2875                            Expr::ge(Expr::nu(), Expr::int_min(int_ty)),
2876                            Sort::Int,
2877                        ),
2878                    },
2879                    Invariant {
2880                        pred: Binder::bind_with_sort(
2881                            Expr::le(Expr::nu(), Expr::int_max(int_ty)),
2882                            Sort::Int,
2883                        ),
2884                    },
2885                ];
2886                (int_ty, invariants)
2887            })
2888            .collect()
2889    });
2890    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2891        &OVERFLOW[&int_ty]
2892    } else {
2893        &DEFAULT
2894    }
2895}
2896
2897impl_internable!(AdtDefData, AdtSortDefData, TyKind);
2898impl_slice_internable!(
2899    Ty,
2900    GenericArg,
2901    Ensures,
2902    InferMode,
2903    Sort,
2904    SortArg,
2905    GenericParamDef,
2906    TraitRef,
2907    Binder<ExistentialPredicate>,
2908    Clause,
2909    PolyVariant,
2910    Invariant,
2911    RefineParam,
2912    FluxDefId,
2913    SortParamKind,
2914    AssocReft
2915);
2916
2917#[macro_export]
2918macro_rules! _Int {
2919    ($int_ty:pat, $idxs:pat) => {
2920        TyKind::Indexed(BaseTy::Int($int_ty), $idxs)
2921    };
2922}
2923pub use crate::_Int as Int;
2924
2925#[macro_export]
2926macro_rules! _Uint {
2927    ($uint_ty:pat, $idxs:pat) => {
2928        TyKind::Indexed(BaseTy::Uint($uint_ty), $idxs)
2929    };
2930}
2931pub use crate::_Uint as Uint;
2932
2933#[macro_export]
2934macro_rules! _Bool {
2935    ($idxs:pat) => {
2936        TyKind::Indexed(BaseTy::Bool, $idxs)
2937    };
2938}
2939pub use crate::_Bool as Bool;
2940
2941#[macro_export]
2942macro_rules! _Char {
2943    ($idxs:pat) => {
2944        TyKind::Indexed(BaseTy::Char, $idxs)
2945    };
2946}
2947pub use crate::_Char as Char;
2948
2949#[macro_export]
2950macro_rules! _Ref {
2951    ($($pats:pat),+ $(,)?) => {
2952        $crate::rty::TyKind::Indexed($crate::rty::BaseTy::Ref($($pats),+), _)
2953    };
2954}
2955pub use crate::_Ref as Ref;
2956
2957pub struct WfckResults {
2958    pub owner: FluxOwnerId,
2959    param_sorts: UnordMap<fhir::ParamId, Sort>,
2960    bin_op_sorts: ItemLocalMap<Sort>,
2961    fn_app_sorts: ItemLocalMap<List<SortArg>>,
2962    coercions: ItemLocalMap<Vec<Coercion>>,
2963    field_projs: ItemLocalMap<FieldProj>,
2964    node_sorts: ItemLocalMap<Sort>,
2965    record_ctors: ItemLocalMap<DefId>,
2966}
2967
2968#[derive(Clone, Copy, Debug)]
2969pub enum Coercion {
2970    Inject(DefId),
2971    Project(DefId),
2972}
2973
2974pub type ItemLocalMap<T> = UnordMap<fhir::ItemLocalId, T>;
2975
2976#[derive(Debug)]
2977pub struct LocalTableInContext<'a, T> {
2978    owner: FluxOwnerId,
2979    data: &'a ItemLocalMap<T>,
2980}
2981
2982pub struct LocalTableInContextMut<'a, T> {
2983    owner: FluxOwnerId,
2984    data: &'a mut ItemLocalMap<T>,
2985}
2986
2987impl WfckResults {
2988    pub fn new(owner: impl Into<FluxOwnerId>) -> Self {
2989        Self {
2990            owner: owner.into(),
2991            param_sorts: UnordMap::default(),
2992            bin_op_sorts: ItemLocalMap::default(),
2993            coercions: ItemLocalMap::default(),
2994            field_projs: ItemLocalMap::default(),
2995            node_sorts: ItemLocalMap::default(),
2996            record_ctors: ItemLocalMap::default(),
2997            fn_app_sorts: ItemLocalMap::default(),
2998        }
2999    }
3000
3001    pub fn param_sorts_mut(&mut self) -> &mut UnordMap<fhir::ParamId, Sort> {
3002        &mut self.param_sorts
3003    }
3004
3005    pub fn param_sorts(&self) -> &UnordMap<fhir::ParamId, Sort> {
3006        &self.param_sorts
3007    }
3008
3009    pub fn bin_op_sorts_mut(&mut self) -> LocalTableInContextMut<'_, Sort> {
3010        LocalTableInContextMut { owner: self.owner, data: &mut self.bin_op_sorts }
3011    }
3012
3013    pub fn fn_app_sorts_mut(&mut self) -> LocalTableInContextMut<'_, List<SortArg>> {
3014        LocalTableInContextMut { owner: self.owner, data: &mut self.fn_app_sorts }
3015    }
3016
3017    pub fn fn_app_sorts(&self) -> LocalTableInContext<'_, List<SortArg>> {
3018        LocalTableInContext { owner: self.owner, data: &self.fn_app_sorts }
3019    }
3020
3021    pub fn bin_op_sorts(&self) -> LocalTableInContext<'_, Sort> {
3022        LocalTableInContext { owner: self.owner, data: &self.bin_op_sorts }
3023    }
3024
3025    pub fn coercions_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Coercion>> {
3026        LocalTableInContextMut { owner: self.owner, data: &mut self.coercions }
3027    }
3028
3029    pub fn coercions(&self) -> LocalTableInContext<'_, Vec<Coercion>> {
3030        LocalTableInContext { owner: self.owner, data: &self.coercions }
3031    }
3032
3033    pub fn field_projs_mut(&mut self) -> LocalTableInContextMut<'_, FieldProj> {
3034        LocalTableInContextMut { owner: self.owner, data: &mut self.field_projs }
3035    }
3036
3037    pub fn field_projs(&self) -> LocalTableInContext<'_, FieldProj> {
3038        LocalTableInContext { owner: self.owner, data: &self.field_projs }
3039    }
3040
3041    pub fn node_sorts_mut(&mut self) -> LocalTableInContextMut<'_, Sort> {
3042        LocalTableInContextMut { owner: self.owner, data: &mut self.node_sorts }
3043    }
3044
3045    pub fn node_sorts(&self) -> LocalTableInContext<'_, Sort> {
3046        LocalTableInContext { owner: self.owner, data: &self.node_sorts }
3047    }
3048
3049    pub fn record_ctors_mut(&mut self) -> LocalTableInContextMut<'_, DefId> {
3050        LocalTableInContextMut { owner: self.owner, data: &mut self.record_ctors }
3051    }
3052
3053    pub fn record_ctors(&self) -> LocalTableInContext<'_, DefId> {
3054        LocalTableInContext { owner: self.owner, data: &self.record_ctors }
3055    }
3056}
3057
3058impl<T> LocalTableInContextMut<'_, T> {
3059    pub fn insert(&mut self, fhir_id: FhirId, value: T) {
3060        tracked_span_assert_eq!(self.owner, fhir_id.owner);
3061        self.data.insert(fhir_id.local_id, value);
3062    }
3063}
3064
3065impl<'a, T> LocalTableInContext<'a, T> {
3066    pub fn get(&self, fhir_id: FhirId) -> Option<&'a T> {
3067        tracked_span_assert_eq!(self.owner, fhir_id.owner);
3068        self.data.get(&fhir_id.local_id)
3069    }
3070}