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