Skip to main content

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