flux_middle/rty/
mod.rs

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