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