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 wildcards: List<bool>,
1451    pub kind: QualifierKind,
1452}
1453
1454#[derive(Debug, TypeFoldable, TypeVisitable, Copy, Clone)]
1455pub enum QualifierKind {
1456    Global,
1457    Local,
1458    Hint,
1459}
1460
1461/// A `PrimOpProp` is a single property for a primitive operation which
1462/// can be conjoined to get the definition of the [`PrimRel`] for that
1463/// primitive operation.
1464#[derive(Debug, TypeVisitable, TypeFoldable)]
1465pub struct PrimOpProp {
1466    pub def_id: FluxLocalDefId,
1467    pub op: BinOp,
1468    pub body: Binder<Expr>,
1469}
1470
1471#[derive(Debug, TypeVisitable, TypeFoldable)]
1472pub struct PrimRel {
1473    pub body: Binder<Expr>,
1474}
1475
1476pub type TyCtor = Binder<Ty>;
1477
1478impl TyCtor {
1479    pub fn to_ty(&self) -> Ty {
1480        match &self.vars()[..] {
1481            [] => {
1482                return self.skip_binder_ref().shift_out_escaping(1);
1483            }
1484            [BoundVariableKind::Refine(sort, ..)] => {
1485                if sort.is_unit() {
1486                    return self.replace_bound_reft(&Expr::unit());
1487                }
1488                if let Some(def_id) = sort.is_unit_adt() {
1489                    return self.replace_bound_reft(&Expr::unit_struct(def_id));
1490                }
1491            }
1492            _ => {}
1493        }
1494        Ty::exists(self.clone())
1495    }
1496}
1497
1498#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1499pub struct Ty(Interned<TyKind>);
1500
1501impl Ty {
1502    pub fn kind(&self) -> &TyKind {
1503        &self.0
1504    }
1505
1506    /// Dummy type used for the `Self` of a `TraitRef` created when converting a trait object, and
1507    /// which gets removed in `ExistentialTraitRef`. This type must not appear anywhere in other
1508    /// converted types and must be a valid `rustc` type (i.e., we must be able to call `to_rustc`
1509    /// on it). `TyKind::Infer(TyVid(0))` does the job, with the caveat that we must skip 0 when
1510    /// generating `TyKind::Infer` for "type holes".
1511    pub fn trait_object_dummy_self() -> Ty {
1512        Ty::infer(TyVid::from_u32(0))
1513    }
1514
1515    pub fn dynamic(preds: impl Into<List<Binder<ExistentialPredicate>>>, region: Region) -> Ty {
1516        BaseTy::Dynamic(preds.into(), region).to_ty()
1517    }
1518
1519    pub fn strg_ref(re: Region, path: Path, ty: Ty) -> Ty {
1520        TyKind::StrgRef(re, path, ty).intern()
1521    }
1522
1523    pub fn ptr(pk: impl Into<PtrKind>, path: impl Into<Path>) -> Ty {
1524        TyKind::Ptr(pk.into(), path.into()).intern()
1525    }
1526
1527    pub fn constr(p: impl Into<Expr>, ty: Ty) -> Ty {
1528        TyKind::Constr(p.into(), ty).intern()
1529    }
1530
1531    pub fn uninit() -> Ty {
1532        TyKind::Uninit.intern()
1533    }
1534
1535    pub fn indexed(bty: BaseTy, idx: impl Into<Expr>) -> Ty {
1536        TyKind::Indexed(bty, idx.into()).intern()
1537    }
1538
1539    pub fn exists(ty: Binder<Ty>) -> Ty {
1540        TyKind::Exists(ty).intern()
1541    }
1542
1543    pub fn exists_with_constr(bty: BaseTy, pred: Expr) -> Ty {
1544        let sort = bty.sort();
1545        let ty = Ty::indexed(bty, Expr::nu());
1546        Ty::exists(Binder::bind_with_sort(Ty::constr(pred, ty), sort))
1547    }
1548
1549    pub fn discr(adt_def: AdtDef, place: Place) -> Ty {
1550        TyKind::Discr(adt_def, place).intern()
1551    }
1552
1553    pub fn unit() -> Ty {
1554        Ty::tuple(vec![])
1555    }
1556
1557    pub fn bool() -> Ty {
1558        BaseTy::Bool.to_ty()
1559    }
1560
1561    pub fn int(int_ty: IntTy) -> Ty {
1562        BaseTy::Int(int_ty).to_ty()
1563    }
1564
1565    pub fn uint(uint_ty: UintTy) -> Ty {
1566        BaseTy::Uint(uint_ty).to_ty()
1567    }
1568
1569    pub fn param(param_ty: ParamTy) -> Ty {
1570        TyKind::Param(param_ty).intern()
1571    }
1572
1573    pub fn downcast(
1574        adt: AdtDef,
1575        args: GenericArgs,
1576        ty: Ty,
1577        variant: VariantIdx,
1578        fields: List<Ty>,
1579    ) -> Ty {
1580        TyKind::Downcast(adt, args, ty, variant, fields).intern()
1581    }
1582
1583    pub fn blocked(ty: Ty) -> Ty {
1584        TyKind::Blocked(ty).intern()
1585    }
1586
1587    pub fn str() -> Ty {
1588        BaseTy::Str.to_ty()
1589    }
1590
1591    pub fn char() -> Ty {
1592        BaseTy::Char.to_ty()
1593    }
1594
1595    pub fn float(float_ty: FloatTy) -> Ty {
1596        BaseTy::Float(float_ty).to_ty()
1597    }
1598
1599    pub fn mk_ref(region: Region, ty: Ty, mutbl: Mutability) -> Ty {
1600        BaseTy::Ref(region, ty, mutbl).to_ty()
1601    }
1602
1603    pub fn mk_slice(ty: Ty) -> Ty {
1604        BaseTy::Slice(ty).to_ty()
1605    }
1606
1607    pub fn mk_box(genv: GlobalEnv, deref_ty: Ty, alloc_ty: GenericArg) -> QueryResult<Ty> {
1608        let def_id = genv.tcx().require_lang_item(LangItem::OwnedBox, DUMMY_SP);
1609        let adt_def = genv.adt_def(def_id)?;
1610
1611        let args = List::from_arr([GenericArg::Ty(deref_ty), alloc_ty]);
1612
1613        let bty = BaseTy::adt(adt_def, args);
1614        Ok(Ty::indexed(bty, Expr::unit_struct(def_id)))
1615    }
1616
1617    pub fn mk_box_with_default_alloc(genv: GlobalEnv, deref_ty: Ty) -> QueryResult<Ty> {
1618        let def_id = genv.tcx().require_lang_item(LangItem::OwnedBox, DUMMY_SP);
1619
1620        let generics = genv.generics_of(def_id)?;
1621        let alloc_ty = genv
1622            .lower_type_of(generics.own_params[1].def_id)?
1623            .skip_binder();
1624        let alloc_ty = Refiner::default_for_item(genv, def_id)?.refine_generic_arg(
1625            &generics.own_params[1],
1626            &flux_rustc_bridge::ty::GenericArg::Ty(alloc_ty),
1627        )?;
1628
1629        Ty::mk_box(genv, deref_ty, alloc_ty)
1630    }
1631
1632    pub fn tuple(tys: impl Into<List<Ty>>) -> Ty {
1633        BaseTy::Tuple(tys.into()).to_ty()
1634    }
1635
1636    pub fn array(ty: Ty, c: Const) -> Ty {
1637        BaseTy::Array(ty, c).to_ty()
1638    }
1639
1640    pub fn closure(
1641        did: DefId,
1642        tys: impl Into<List<Ty>>,
1643        args: &flux_rustc_bridge::ty::GenericArgs,
1644        no_panic: bool,
1645    ) -> Ty {
1646        BaseTy::Closure(did, tys.into(), args.clone(), no_panic).to_ty()
1647    }
1648
1649    pub fn coroutine(
1650        did: DefId,
1651        resume_ty: Ty,
1652        upvar_tys: List<Ty>,
1653        args: flux_rustc_bridge::ty::GenericArgs,
1654    ) -> Ty {
1655        BaseTy::Coroutine(did, resume_ty, upvar_tys, args.clone()).to_ty()
1656    }
1657
1658    pub fn never() -> Ty {
1659        BaseTy::Never.to_ty()
1660    }
1661
1662    pub fn infer(vid: TyVid) -> Ty {
1663        TyKind::Infer(vid).intern()
1664    }
1665
1666    pub fn unconstr(&self) -> (Ty, Expr) {
1667        fn go(this: &Ty, preds: &mut Vec<Expr>) -> Ty {
1668            if let TyKind::Constr(pred, ty) = this.kind() {
1669                preds.push(pred.clone());
1670                go(ty, preds)
1671            } else {
1672                this.clone()
1673            }
1674        }
1675        let mut preds = vec![];
1676        (go(self, &mut preds), Expr::and_from_iter(preds))
1677    }
1678
1679    pub fn unblocked(&self) -> Ty {
1680        match self.kind() {
1681            TyKind::Blocked(ty) => ty.clone(),
1682            _ => self.clone(),
1683        }
1684    }
1685
1686    /// Whether the type is an `int` or a `uint`
1687    pub fn is_integral(&self) -> bool {
1688        self.as_bty_skipping_existentials()
1689            .map(BaseTy::is_integral)
1690            .unwrap_or_default()
1691    }
1692
1693    /// Whether the type is a `bool`
1694    pub fn is_bool(&self) -> bool {
1695        self.as_bty_skipping_existentials()
1696            .map(BaseTy::is_bool)
1697            .unwrap_or_default()
1698    }
1699
1700    /// Whether the type is a `char`
1701    pub fn is_char(&self) -> bool {
1702        self.as_bty_skipping_existentials()
1703            .map(BaseTy::is_char)
1704            .unwrap_or_default()
1705    }
1706
1707    pub fn is_uninit(&self) -> bool {
1708        matches!(self.kind(), TyKind::Uninit)
1709    }
1710
1711    pub fn is_box(&self) -> bool {
1712        self.as_bty_skipping_existentials()
1713            .map(BaseTy::is_box)
1714            .unwrap_or_default()
1715    }
1716
1717    pub fn is_struct(&self) -> bool {
1718        self.as_bty_skipping_existentials()
1719            .map(BaseTy::is_struct)
1720            .unwrap_or_default()
1721    }
1722
1723    pub fn is_array(&self) -> bool {
1724        self.as_bty_skipping_existentials()
1725            .map(BaseTy::is_array)
1726            .unwrap_or_default()
1727    }
1728
1729    pub fn is_slice(&self) -> bool {
1730        self.as_bty_skipping_existentials()
1731            .map(BaseTy::is_slice)
1732            .unwrap_or_default()
1733    }
1734
1735    pub fn as_bty_skipping_existentials(&self) -> Option<&BaseTy> {
1736        match self.kind() {
1737            TyKind::Indexed(bty, _) => Some(bty),
1738            TyKind::Exists(ty) => Some(ty.skip_binder_ref().as_bty_skipping_existentials()?),
1739            TyKind::Constr(_, ty) => ty.as_bty_skipping_existentials(),
1740            _ => None,
1741        }
1742    }
1743
1744    #[track_caller]
1745    pub fn expect_discr(&self) -> (&AdtDef, &Place) {
1746        if let TyKind::Discr(adt_def, place) = self.kind() {
1747            (adt_def, place)
1748        } else {
1749            tracked_span_bug!("expected discr")
1750        }
1751    }
1752
1753    #[track_caller]
1754    pub fn expect_adt(&self) -> (&AdtDef, &[GenericArg], &Expr) {
1755        if let TyKind::Indexed(BaseTy::Adt(adt_def, args), idx) = self.kind() {
1756            (adt_def, args, idx)
1757        } else {
1758            tracked_span_bug!("expected adt `{self:?}`")
1759        }
1760    }
1761
1762    #[track_caller]
1763    pub fn expect_tuple(&self) -> &[Ty] {
1764        if let TyKind::Indexed(BaseTy::Tuple(tys), _) = self.kind() {
1765            tys
1766        } else {
1767            tracked_span_bug!("expected tuple found `{self:?}` (kind: `{:?}`)", self.kind())
1768        }
1769    }
1770
1771    pub fn simplify_type(&self) -> Option<SimplifiedType> {
1772        self.as_bty_skipping_existentials()
1773            .and_then(BaseTy::simplify_type)
1774    }
1775}
1776
1777impl<'tcx> ToRustc<'tcx> for Ty {
1778    type T = rustc_middle::ty::Ty<'tcx>;
1779
1780    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
1781        match self.kind() {
1782            TyKind::Indexed(bty, _) => bty.to_rustc(tcx),
1783            TyKind::Exists(ty) => ty.skip_binder_ref().to_rustc(tcx),
1784            TyKind::Constr(_, ty) => ty.to_rustc(tcx),
1785            TyKind::Param(pty) => pty.to_ty(tcx),
1786            TyKind::StrgRef(re, _, ty) => {
1787                rustc_middle::ty::Ty::new_ref(
1788                    tcx,
1789                    re.to_rustc(tcx),
1790                    ty.to_rustc(tcx),
1791                    Mutability::Mut,
1792                )
1793            }
1794            TyKind::Infer(vid) => rustc_middle::ty::Ty::new_var(tcx, *vid),
1795            TyKind::Uninit
1796            | TyKind::Ptr(_, _)
1797            | TyKind::Discr(..)
1798            | TyKind::Downcast(..)
1799            | TyKind::Blocked(_) => bug!("TODO: to_rustc for `{self:?}`"),
1800        }
1801    }
1802}
1803
1804#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)]
1805pub enum TyKind {
1806    Indexed(BaseTy, Expr),
1807    Exists(Binder<Ty>),
1808    Constr(Expr, Ty),
1809    Uninit,
1810    StrgRef(Region, Path, Ty),
1811    Ptr(PtrKind, Path),
1812    /// This is a bit of a hack. We use this type internally to represent the result of
1813    /// [`Rvalue::Discriminant`] in a way that we can recover the necessary control information
1814    /// when checking a [`match`]. The hack is that we assume the dicriminant remains the same from
1815    /// the creation of this type until we use it in a [`match`].
1816    ///
1817    ///
1818    /// [`Rvalue::Discriminant`]: flux_rustc_bridge::mir::Rvalue::Discriminant
1819    /// [`match`]: flux_rustc_bridge::mir::TerminatorKind::SwitchInt
1820    Discr(AdtDef, Place),
1821    Param(ParamTy),
1822    /// These only arise when you "narrow" an ADT down to a particular variant;
1823    /// either EXPLICITLY in a `match-of`, or IMPLICITLY when you access a field
1824    /// of a struct to "UNPACK" the struct.
1825    Downcast(AdtDef, GenericArgs, Ty, VariantIdx, List<Ty>),
1826    Blocked(Ty),
1827    /// A type that needs to be inferred by matching the signature against a rust signature.
1828    /// [`TyKind::Infer`] appear as an intermediate step during `conv` and should not be present in
1829    /// the final signature.
1830    Infer(TyVid),
1831}
1832
1833#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1834pub enum PtrKind {
1835    Mut(Region),
1836    Box,
1837}
1838
1839#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
1840pub enum BaseTy {
1841    Int(IntTy),
1842    Uint(UintTy),
1843    Bool,
1844    Str,
1845    Char,
1846    Slice(Ty),
1847    Adt(AdtDef, GenericArgs),
1848    Float(FloatTy),
1849    RawPtr(Ty, Mutability),
1850    RawPtrMetadata(Ty),
1851    Ref(Region, Ty, Mutability),
1852    FnPtr(PolyFnSig),
1853    FnDef(DefId, GenericArgs),
1854    Tuple(List<Ty>),
1855    Alias(AliasKind, AliasTy),
1856    Array(Ty, Const),
1857    Never,
1858    Closure(DefId, /* upvar_tys */ List<Ty>, flux_rustc_bridge::ty::GenericArgs, bool),
1859    Coroutine(
1860        DefId,
1861        /*resume_ty: */ Ty,
1862        /* upvar_tys: */ List<Ty>,
1863        flux_rustc_bridge::ty::GenericArgs,
1864    ),
1865    Dynamic(List<Binder<ExistentialPredicate>>, Region),
1866    Param(ParamTy),
1867    Infer(TyVid),
1868    Foreign(DefId),
1869    Pat,
1870}
1871
1872impl BaseTy {
1873    pub fn opaque(alias_ty: AliasTy) -> BaseTy {
1874        BaseTy::Alias(AliasKind::Opaque, alias_ty)
1875    }
1876
1877    pub fn projection(alias_ty: AliasTy) -> BaseTy {
1878        BaseTy::Alias(AliasKind::Projection, alias_ty)
1879    }
1880
1881    pub fn adt(adt_def: AdtDef, args: GenericArgs) -> BaseTy {
1882        BaseTy::Adt(adt_def, args)
1883    }
1884
1885    pub fn fn_def(def_id: DefId, args: impl Into<GenericArgs>) -> BaseTy {
1886        BaseTy::FnDef(def_id, args.into())
1887    }
1888
1889    pub fn from_primitive_str(s: &str) -> Option<BaseTy> {
1890        match s {
1891            "i8" => Some(BaseTy::Int(IntTy::I8)),
1892            "i16" => Some(BaseTy::Int(IntTy::I16)),
1893            "i32" => Some(BaseTy::Int(IntTy::I32)),
1894            "i64" => Some(BaseTy::Int(IntTy::I64)),
1895            "i128" => Some(BaseTy::Int(IntTy::I128)),
1896            "u8" => Some(BaseTy::Uint(UintTy::U8)),
1897            "u16" => Some(BaseTy::Uint(UintTy::U16)),
1898            "u32" => Some(BaseTy::Uint(UintTy::U32)),
1899            "u64" => Some(BaseTy::Uint(UintTy::U64)),
1900            "u128" => Some(BaseTy::Uint(UintTy::U128)),
1901            "f16" => Some(BaseTy::Float(FloatTy::F16)),
1902            "f32" => Some(BaseTy::Float(FloatTy::F32)),
1903            "f64" => Some(BaseTy::Float(FloatTy::F64)),
1904            "f128" => Some(BaseTy::Float(FloatTy::F128)),
1905            "isize" => Some(BaseTy::Int(IntTy::Isize)),
1906            "usize" => Some(BaseTy::Uint(UintTy::Usize)),
1907            "bool" => Some(BaseTy::Bool),
1908            "char" => Some(BaseTy::Char),
1909            "str" => Some(BaseTy::Str),
1910            _ => None,
1911        }
1912    }
1913
1914    /// If `self` is a primitive, return its [`Symbol`].
1915    pub fn primitive_symbol(&self) -> Option<Symbol> {
1916        match self {
1917            BaseTy::Bool => Some(sym::bool),
1918            BaseTy::Char => Some(sym::char),
1919            BaseTy::Float(f) => {
1920                match f {
1921                    FloatTy::F16 => Some(sym::f16),
1922                    FloatTy::F32 => Some(sym::f32),
1923                    FloatTy::F64 => Some(sym::f64),
1924                    FloatTy::F128 => Some(sym::f128),
1925                }
1926            }
1927            BaseTy::Int(f) => {
1928                match f {
1929                    IntTy::Isize => Some(sym::isize),
1930                    IntTy::I8 => Some(sym::i8),
1931                    IntTy::I16 => Some(sym::i16),
1932                    IntTy::I32 => Some(sym::i32),
1933                    IntTy::I64 => Some(sym::i64),
1934                    IntTy::I128 => Some(sym::i128),
1935                }
1936            }
1937            BaseTy::Uint(f) => {
1938                match f {
1939                    UintTy::Usize => Some(sym::usize),
1940                    UintTy::U8 => Some(sym::u8),
1941                    UintTy::U16 => Some(sym::u16),
1942                    UintTy::U32 => Some(sym::u32),
1943                    UintTy::U64 => Some(sym::u64),
1944                    UintTy::U128 => Some(sym::u128),
1945                }
1946            }
1947            BaseTy::Str => Some(sym::str),
1948            _ => None,
1949        }
1950    }
1951
1952    pub fn is_integral(&self) -> bool {
1953        matches!(self, BaseTy::Int(_) | BaseTy::Uint(_))
1954    }
1955
1956    pub fn is_signed(&self) -> bool {
1957        matches!(self, BaseTy::Int(_))
1958    }
1959
1960    pub fn is_unsigned(&self) -> bool {
1961        matches!(self, BaseTy::Uint(_))
1962    }
1963
1964    pub fn is_float(&self) -> bool {
1965        matches!(self, BaseTy::Float(_))
1966    }
1967
1968    pub fn is_bool(&self) -> bool {
1969        matches!(self, BaseTy::Bool)
1970    }
1971
1972    fn is_struct(&self) -> bool {
1973        matches!(self, BaseTy::Adt(adt_def, _) if adt_def.is_struct())
1974    }
1975
1976    fn is_array(&self) -> bool {
1977        matches!(self, BaseTy::Array(..))
1978    }
1979
1980    fn is_slice(&self) -> bool {
1981        matches!(self, BaseTy::Slice(..))
1982    }
1983
1984    pub fn is_box(&self) -> bool {
1985        matches!(self, BaseTy::Adt(adt_def, _) if adt_def.is_box())
1986    }
1987
1988    pub fn is_char(&self) -> bool {
1989        matches!(self, BaseTy::Char)
1990    }
1991
1992    pub fn is_str(&self) -> bool {
1993        matches!(self, BaseTy::Str)
1994    }
1995
1996    pub fn invariants(
1997        &self,
1998        tcx: TyCtxt,
1999        overflow_mode: OverflowMode,
2000    ) -> impl Iterator<Item = Invariant> {
2001        let (invariants, args) = match self {
2002            BaseTy::Adt(adt_def, args) => (adt_def.invariants().skip_binder(), &args[..]),
2003            BaseTy::Uint(uint_ty) => (uint_invariants(*uint_ty, overflow_mode), &[][..]),
2004            BaseTy::Int(int_ty) => (int_invariants(*int_ty, overflow_mode), &[][..]),
2005            BaseTy::Char => (char_invariants(), &[][..]),
2006            BaseTy::Slice(_) => (slice_invariants(overflow_mode), &[][..]),
2007            _ => (&[][..], &[][..]),
2008        };
2009        invariants
2010            .iter()
2011            .map(move |inv| EarlyBinder(inv).instantiate_ref(tcx, args, &[]))
2012    }
2013
2014    pub fn to_ty(&self) -> Ty {
2015        let sort = self.sort();
2016        if sort.is_unit() {
2017            Ty::indexed(self.clone(), Expr::unit())
2018        } else {
2019            Ty::exists(Binder::bind_with_sort(
2020                Ty::indexed(self.shift_in_escaping(1), Expr::nu()),
2021                sort,
2022            ))
2023        }
2024    }
2025
2026    pub fn to_subset_ty_ctor(&self) -> SubsetTyCtor {
2027        let sort = self.sort();
2028        Binder::bind_with_sort(SubsetTy::trivial(self.clone(), Expr::nu()), sort)
2029    }
2030
2031    #[track_caller]
2032    pub fn expect_adt(&self) -> (&AdtDef, &[GenericArg]) {
2033        if let BaseTy::Adt(adt_def, args) = self {
2034            (adt_def, args)
2035        } else {
2036            tracked_span_bug!("expected adt `{self:?}`")
2037        }
2038    }
2039
2040    /// A type is an *atom* if it is "self-delimiting", i.e., it has a clear boundary
2041    /// when printed. This is used to avoid unnecessary parenthesis when pretty printing.
2042    pub fn is_atom(&self) -> bool {
2043        // (nilehmann) I'm not sure about this list, please adjust if you get any odd behavior
2044        matches!(
2045            self,
2046            BaseTy::Int(_)
2047                | BaseTy::Uint(_)
2048                | BaseTy::Slice(_)
2049                | BaseTy::Bool
2050                | BaseTy::Char
2051                | BaseTy::Str
2052                | BaseTy::Adt(..)
2053                | BaseTy::Tuple(..)
2054                | BaseTy::Param(_)
2055                | BaseTy::Array(..)
2056                | BaseTy::Never
2057                | BaseTy::Closure(..)
2058                | BaseTy::Coroutine(..)
2059                // opaque alias are atoms the way we print them now, but they won't
2060                // be if we print them as `impl Trait`
2061                | BaseTy::Alias(..)
2062        )
2063    }
2064
2065    /// Similar to [`rustc_infer::infer::canonical::ir::fast_reject::simplify_type`].
2066    ///
2067    /// This implementation is currently incomplete, so it should only be used in contexts
2068    /// where completeness is not required. Currently, it's used to find incoherent
2069    /// implementations when resolving associated constants. In this context, incompleteness
2070    /// is acceptable since the worst case outcome is simply failing to resolve a type-relative
2071    /// constant.
2072    fn simplify_type(&self) -> Option<SimplifiedType> {
2073        match self {
2074            BaseTy::Bool => Some(SimplifiedType::Bool),
2075            BaseTy::Char => Some(SimplifiedType::Char),
2076            BaseTy::Int(int_type) => Some(SimplifiedType::Int(*int_type)),
2077            BaseTy::Uint(uint_type) => Some(SimplifiedType::Uint(*uint_type)),
2078            BaseTy::Float(float_type) => Some(SimplifiedType::Float(*float_type)),
2079            BaseTy::Adt(def, _) => Some(SimplifiedType::Adt(def.did())),
2080            BaseTy::Str => Some(SimplifiedType::Str),
2081            BaseTy::Array(..) => Some(SimplifiedType::Array),
2082            BaseTy::Slice(..) => Some(SimplifiedType::Slice),
2083            BaseTy::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(*mutbl)),
2084            BaseTy::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(*mutbl)),
2085            BaseTy::FnDef(def_id, _) | BaseTy::Closure(def_id, ..) => {
2086                Some(SimplifiedType::Closure(*def_id))
2087            }
2088            BaseTy::Coroutine(def_id, ..) => Some(SimplifiedType::Coroutine(*def_id)),
2089            BaseTy::Never => Some(SimplifiedType::Never),
2090            BaseTy::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
2091            BaseTy::FnPtr(poly_fn_sig) => {
2092                Some(SimplifiedType::Function(poly_fn_sig.skip_binder_ref().inputs().len()))
2093            }
2094            BaseTy::Foreign(def_id) => Some(SimplifiedType::Foreign(*def_id)),
2095            BaseTy::RawPtrMetadata(_)
2096            | BaseTy::Alias(..)
2097            | BaseTy::Param(_)
2098            | BaseTy::Dynamic(..)
2099            | BaseTy::Infer(_) => None,
2100            BaseTy::Pat => todo!(),
2101        }
2102    }
2103}
2104
2105impl<'tcx> ToRustc<'tcx> for BaseTy {
2106    type T = rustc_middle::ty::Ty<'tcx>;
2107
2108    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2109        use rustc_middle::ty;
2110        match self {
2111            BaseTy::Int(i) => ty::Ty::new_int(tcx, *i),
2112            BaseTy::Uint(i) => ty::Ty::new_uint(tcx, *i),
2113            BaseTy::Param(pty) => pty.to_ty(tcx),
2114            BaseTy::Slice(ty) => ty::Ty::new_slice(tcx, ty.to_rustc(tcx)),
2115            BaseTy::Bool => tcx.types.bool,
2116            BaseTy::Char => tcx.types.char,
2117            BaseTy::Str => tcx.types.str_,
2118            BaseTy::Adt(adt_def, args) => {
2119                let did = adt_def.did();
2120                let adt_def = tcx.adt_def(did);
2121                let args = args.to_rustc(tcx);
2122                ty::Ty::new_adt(tcx, adt_def, args)
2123            }
2124            BaseTy::FnDef(def_id, args) => {
2125                let args = args.to_rustc(tcx);
2126                ty::Ty::new_fn_def(tcx, *def_id, args)
2127            }
2128            BaseTy::Float(f) => ty::Ty::new_float(tcx, *f),
2129            BaseTy::RawPtr(ty, mutbl) => ty::Ty::new_ptr(tcx, ty.to_rustc(tcx), *mutbl),
2130            BaseTy::Ref(re, ty, mutbl) => {
2131                ty::Ty::new_ref(tcx, re.to_rustc(tcx), ty.to_rustc(tcx), *mutbl)
2132            }
2133            BaseTy::FnPtr(poly_sig) => ty::Ty::new_fn_ptr(tcx, poly_sig.to_rustc(tcx)),
2134            BaseTy::Tuple(tys) => {
2135                let ts = tys.iter().map(|ty| ty.to_rustc(tcx)).collect_vec();
2136                ty::Ty::new_tup(tcx, &ts)
2137            }
2138            BaseTy::Alias(kind, alias_ty) => {
2139                ty::Ty::new_alias(tcx, kind.to_rustc(tcx), alias_ty.to_rustc(tcx))
2140            }
2141            BaseTy::Array(ty, n) => {
2142                let ty = ty.to_rustc(tcx);
2143                let n = n.to_rustc(tcx);
2144                ty::Ty::new_array_with_const_len(tcx, ty, n)
2145            }
2146            BaseTy::Never => tcx.types.never,
2147            BaseTy::Closure(did, _, args, _) => ty::Ty::new_closure(tcx, *did, args.to_rustc(tcx)),
2148            BaseTy::Dynamic(exi_preds, re) => {
2149                let preds: Vec<_> = exi_preds
2150                    .iter()
2151                    .map(|pred| pred.to_rustc(tcx))
2152                    .collect_vec();
2153                let preds = tcx.mk_poly_existential_predicates(&preds);
2154                ty::Ty::new_dynamic(tcx, preds, re.to_rustc(tcx))
2155            }
2156            BaseTy::Coroutine(did, _, _, args) => {
2157                ty::Ty::new_coroutine(tcx, *did, args.to_rustc(tcx))
2158            }
2159            BaseTy::Infer(ty_vid) => ty::Ty::new_var(tcx, *ty_vid),
2160            BaseTy::Foreign(def_id) => ty::Ty::new_foreign(tcx, *def_id),
2161            BaseTy::RawPtrMetadata(ty) => {
2162                ty::Ty::new_ptr(
2163                    tcx,
2164                    ty.to_rustc(tcx),
2165                    RawPtrKind::FakeForPtrMetadata.to_mutbl_lossy(),
2166                )
2167            }
2168            BaseTy::Pat => todo!(),
2169        }
2170    }
2171}
2172
2173#[derive(
2174    Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable,
2175)]
2176pub struct AliasTy {
2177    pub def_id: DefId,
2178    pub args: GenericArgs,
2179    /// Holds the refinement-arguments for opaque-types; empty for projections
2180    pub refine_args: RefineArgs,
2181}
2182
2183impl AliasTy {
2184    pub fn new(def_id: DefId, args: GenericArgs, refine_args: RefineArgs) -> Self {
2185        AliasTy { args, refine_args, def_id }
2186    }
2187}
2188
2189/// This methods work only with associated type projections (i.e., no opaque types)
2190impl AliasTy {
2191    pub fn self_ty(&self) -> SubsetTyCtor {
2192        self.args[0].expect_base().clone()
2193    }
2194
2195    pub fn with_self_ty(&self, self_ty: SubsetTyCtor) -> Self {
2196        Self {
2197            def_id: self.def_id,
2198            args: [GenericArg::Base(self_ty)]
2199                .into_iter()
2200                .chain(self.args.iter().skip(1).cloned())
2201                .collect(),
2202            refine_args: self.refine_args.clone(),
2203        }
2204    }
2205}
2206
2207impl<'tcx> ToRustc<'tcx> for AliasTy {
2208    type T = rustc_middle::ty::AliasTy<'tcx>;
2209
2210    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2211        rustc_middle::ty::AliasTy::new(tcx, self.def_id, self.args.to_rustc(tcx))
2212    }
2213}
2214
2215pub type RefineArgs = List<Expr>;
2216
2217#[extension(pub trait RefineArgsExt)]
2218impl RefineArgs {
2219    fn identity_for_item(genv: GlobalEnv, def_id: DefId) -> QueryResult<RefineArgs> {
2220        Self::for_item(genv, def_id, |param, index| {
2221            Ok(Expr::var(Var::EarlyParam(EarlyReftParam {
2222                index: index as u32,
2223                name: param.name(),
2224            })))
2225        })
2226    }
2227
2228    fn for_item<F>(genv: GlobalEnv, def_id: DefId, mut mk: F) -> QueryResult<RefineArgs>
2229    where
2230        F: FnMut(EarlyBinder<RefineParam>, usize) -> QueryResult<Expr>,
2231    {
2232        let reft_generics = genv.refinement_generics_of(def_id)?;
2233        let count = reft_generics.count();
2234        let mut args = Vec::with_capacity(count);
2235        reft_generics.fill_item(genv, &mut args, &mut mk)?;
2236        Ok(List::from_vec(args))
2237    }
2238}
2239
2240/// A type constructor meant to be used as generic a argument of [kind base]. This is just an alias
2241/// to [`Binder<SubsetTy>`], but we expect the binder to have a single bound variable of the sort of
2242/// the underlying [base type].
2243///
2244/// [kind base]: GenericParamDefKind::Base
2245/// [base type]: SubsetTy::bty
2246pub type SubsetTyCtor = Binder<SubsetTy>;
2247
2248impl SubsetTyCtor {
2249    pub fn as_bty_skipping_binder(&self) -> &BaseTy {
2250        &self.as_ref().skip_binder().bty
2251    }
2252
2253    pub fn to_ty(&self) -> Ty {
2254        let sort = self.sort();
2255        if sort.is_unit() {
2256            self.replace_bound_reft(&Expr::unit()).to_ty()
2257        } else if let Some(def_id) = sort.is_unit_adt() {
2258            self.replace_bound_reft(&Expr::unit_struct(def_id)).to_ty()
2259        } else {
2260            Ty::exists(self.as_ref().map(SubsetTy::to_ty))
2261        }
2262    }
2263
2264    pub fn to_ty_ctor(&self) -> TyCtor {
2265        self.as_ref().map(SubsetTy::to_ty)
2266    }
2267}
2268
2269/// A subset type is a simplified version of a type that has the form `{b[e] | p}` where `b` is a
2270/// [`BaseTy`], `e` a refinement index, and `p` a predicate.
2271///
2272/// These are mainly found under a [`Binder`] with a single variable of the base type's sort. This
2273/// can be interpreted as a type constructor or an existential type. For example, under a binder with a
2274/// variable `v` of sort `int`, we can interpret `{i32[v] | v > 0}` as:
2275/// - A lambda `λv:int. {i32[v] | v > 0}` that "constructs" types when applied to ints, or
2276/// - An existential type `∃v:int. {i32[v] | v > 0}`.
2277///
2278/// This second interpretation is the reason we call this a subset type, i.e., the type `∃v. {b[v] | p}`
2279/// corresponds to the subset of values of  type `b` whose index satisfies `p`. These are the types
2280/// written as `B{v: p}` in the surface syntax and correspond to the types supported in other
2281/// refinement type systems like Liquid Haskell (with the difference that we are explicit
2282/// about separating refinements from program values via an index).
2283///
2284/// The main purpose for subset types is to be used as generic arguments of [kind base] when
2285/// interpreted as type constructors. They have two key properties that makes them suitable
2286/// for this:
2287///
2288/// 1. **Syntactic Restriction**: Subset types are syntactically restricted, making it easier to
2289///    relate them structurally (e.g., for subtyping). For instance, given two types `S<λv. T1>` and
2290///    `S<λ. T2>`, if `T1` and `T2` are subset types, we know they match structurally (at least
2291///    shallowly). In particularly, the syntactic restriction rules out complex types like
2292///    `S<λv. (i32[v], i32[v])>` simplifying some operations.
2293///
2294/// 2. **Eager Canonicalization**: Subset types can be eagerly canonicalized via [*strengthening*]
2295///    during substitution. For example, suppose we have a function:
2296///    ```text
2297///    fn foo<T>(x: T[@a], y: { T[@b] | b == a }) { }
2298///    ```
2299///    If we instantiate `T` with `λv. { i32[v] | v > 0}`, after substitution and applying the
2300///    lambda (the indexing syntax `T[a]` corresponds to an application of the lambda), we get:
2301///    ```text
2302///    fn foo(x: {i32[@a] | a > 0}, y: { { i32[@b] | b > 0 } | b == a }) { }
2303///    ```
2304///    Via *strengthening* we can canonicalize this to
2305///    ```text
2306///    fn foo(x: {i32[@a] | a > 0}, y: { i32[@b] | b == a && b > 0 }) { }
2307///    ```
2308///    As a result, we can guarantee the syntactic restriction through substitution.
2309///
2310/// [kind base]: GenericParamDefKind::Base
2311/// [*strengthening*]: https://arxiv.org/pdf/2010.07763.pdf
2312#[derive(PartialEq, Clone, Eq, Hash, TyEncodable, TyDecodable)]
2313pub struct SubsetTy {
2314    /// The base type `b` in the subset type `{b[e] | p}`.
2315    ///
2316    /// **NOTE:** This is mostly going to be under a [`Binder`]. It is not yet clear to me whether
2317    /// this [`BaseTy`] should be able to mention variables in the binder. In general, in a type
2318    /// `∃v. {b[e] | p}`, it's fine to mention `v` inside `b`, but since [`SubsetTy`] is meant to
2319    /// facilitate syntactic manipulation we may want to restrict this.
2320    pub bty: BaseTy,
2321    /// The refinement index `e` in the subset type `{b[e] | p}`. This can be an arbitrary expression,
2322    /// which makes manipulation easier. However, since this is mostly found under a binder, we expect
2323    /// it to be [`Expr::nu()`].
2324    pub idx: Expr,
2325    /// The predicate `p` in the subset type `{b[e] | p}`.
2326    pub pred: Expr,
2327}
2328
2329impl SubsetTy {
2330    pub fn new(bty: BaseTy, idx: impl Into<Expr>, pred: impl Into<Expr>) -> Self {
2331        Self { bty, idx: idx.into(), pred: pred.into() }
2332    }
2333
2334    pub fn trivial(bty: BaseTy, idx: impl Into<Expr>) -> Self {
2335        Self::new(bty, idx, Expr::tt())
2336    }
2337
2338    pub fn strengthen(&self, pred: impl Into<Expr>) -> Self {
2339        let this = self.clone();
2340        let pred = Expr::and(this.pred, pred).simplify(&SnapshotMap::default());
2341        Self { bty: this.bty, idx: this.idx, pred }
2342    }
2343
2344    pub fn to_ty(&self) -> Ty {
2345        let bty = self.bty.clone();
2346        if self.pred.is_trivially_true() {
2347            Ty::indexed(bty, &self.idx)
2348        } else {
2349            Ty::constr(&self.pred, Ty::indexed(bty, &self.idx))
2350        }
2351    }
2352}
2353
2354impl<'tcx> ToRustc<'tcx> for SubsetTy {
2355    type T = rustc_middle::ty::Ty<'tcx>;
2356
2357    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::Ty<'tcx> {
2358        self.bty.to_rustc(tcx)
2359    }
2360}
2361
2362#[derive(PartialEq, Clone, Eq, Hash, TyEncodable, TyDecodable)]
2363pub enum GenericArg {
2364    Ty(Ty),
2365    Base(SubsetTyCtor),
2366    Lifetime(Region),
2367    Const(Const),
2368}
2369
2370impl GenericArg {
2371    #[track_caller]
2372    pub fn expect_type(&self) -> &Ty {
2373        if let GenericArg::Ty(ty) = self {
2374            ty
2375        } else {
2376            bug!("expected `rty::GenericArg::Ty`, found `{self:?}`")
2377        }
2378    }
2379
2380    #[track_caller]
2381    pub fn expect_base(&self) -> &SubsetTyCtor {
2382        if let GenericArg::Base(ctor) = self {
2383            ctor
2384        } else {
2385            bug!("expected `rty::GenericArg::Base`, found `{self:?}`")
2386        }
2387    }
2388
2389    pub fn from_param_def(param: &GenericParamDef) -> Self {
2390        match param.kind {
2391            GenericParamDefKind::Type { .. } => {
2392                let param_ty = ParamTy { index: param.index, name: param.name };
2393                GenericArg::Ty(Ty::param(param_ty))
2394            }
2395            GenericParamDefKind::Base { .. } => {
2396                // λv. T[v]
2397                let param_ty = ParamTy { index: param.index, name: param.name };
2398                GenericArg::Base(Binder::bind_with_sort(
2399                    SubsetTy::trivial(BaseTy::Param(param_ty), Expr::nu()),
2400                    Sort::Param(param_ty),
2401                ))
2402            }
2403            GenericParamDefKind::Lifetime => {
2404                let region = EarlyParamRegion { index: param.index, name: param.name };
2405                GenericArg::Lifetime(Region::ReEarlyParam(region))
2406            }
2407            GenericParamDefKind::Const { .. } => {
2408                let param_const = ParamConst { index: param.index, name: param.name };
2409                let kind = ConstKind::Param(param_const);
2410                GenericArg::Const(Const { kind })
2411            }
2412        }
2413    }
2414
2415    /// Creates a `GenericArgs` from the definition of generic parameters, by calling a closure to
2416    /// obtain arg. The closures get to observe the `GenericArgs` as they're being built, which can
2417    /// be used to correctly replace defaults of generic parameters.
2418    pub fn for_item<F>(genv: GlobalEnv, def_id: DefId, mut mk_kind: F) -> QueryResult<GenericArgs>
2419    where
2420        F: FnMut(&GenericParamDef, &[GenericArg]) -> GenericArg,
2421    {
2422        let defs = genv.generics_of(def_id)?;
2423        let count = defs.count();
2424        let mut args = Vec::with_capacity(count);
2425        Self::fill_item(genv, &mut args, &defs, &mut mk_kind)?;
2426        Ok(List::from_vec(args))
2427    }
2428
2429    pub fn identity_for_item(genv: GlobalEnv, def_id: DefId) -> QueryResult<GenericArgs> {
2430        Self::for_item(genv, def_id, |param, _| GenericArg::from_param_def(param))
2431    }
2432
2433    fn fill_item<F>(
2434        genv: GlobalEnv,
2435        args: &mut Vec<GenericArg>,
2436        generics: &Generics,
2437        mk_kind: &mut F,
2438    ) -> QueryResult<()>
2439    where
2440        F: FnMut(&GenericParamDef, &[GenericArg]) -> GenericArg,
2441    {
2442        if let Some(def_id) = generics.parent {
2443            let parent_generics = genv.generics_of(def_id)?;
2444            Self::fill_item(genv, args, &parent_generics, mk_kind)?;
2445        }
2446        for param in &generics.own_params {
2447            let kind = mk_kind(param, args);
2448            tracked_span_assert_eq!(param.index as usize, args.len());
2449            args.push(kind);
2450        }
2451        Ok(())
2452    }
2453}
2454
2455impl From<TyOrBase> for GenericArg {
2456    fn from(v: TyOrBase) -> Self {
2457        match v {
2458            TyOrBase::Ty(ty) => GenericArg::Ty(ty),
2459            TyOrBase::Base(ctor) => GenericArg::Base(ctor),
2460        }
2461    }
2462}
2463
2464impl<'tcx> ToRustc<'tcx> for GenericArg {
2465    type T = rustc_middle::ty::GenericArg<'tcx>;
2466
2467    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2468        use rustc_middle::ty;
2469        match self {
2470            GenericArg::Ty(ty) => ty::GenericArg::from(ty.to_rustc(tcx)),
2471            GenericArg::Base(ctor) => ty::GenericArg::from(ctor.skip_binder_ref().to_rustc(tcx)),
2472            GenericArg::Lifetime(re) => ty::GenericArg::from(re.to_rustc(tcx)),
2473            GenericArg::Const(c) => ty::GenericArg::from(c.to_rustc(tcx)),
2474        }
2475    }
2476}
2477
2478pub type GenericArgs = List<GenericArg>;
2479
2480#[extension(pub trait GenericArgsExt)]
2481impl GenericArgs {
2482    #[track_caller]
2483    fn box_args(&self) -> (&Ty, &GenericArg) {
2484        if let [GenericArg::Ty(deref), alloc] = &self[..] {
2485            (deref, alloc)
2486        } else {
2487            bug!("invalid generic arguments for box");
2488        }
2489    }
2490
2491    // We can't implement [`ToRustc`] because of coherence so we add it here
2492    fn to_rustc<'tcx>(&self, tcx: TyCtxt<'tcx>) -> rustc_middle::ty::GenericArgsRef<'tcx> {
2493        tcx.mk_args_from_iter(self.iter().map(|arg| arg.to_rustc(tcx)))
2494    }
2495
2496    fn rebase_onto(
2497        &self,
2498        tcx: &TyCtxt,
2499        source_ancestor: DefId,
2500        target_args: &GenericArgs,
2501    ) -> List<GenericArg> {
2502        let defs = tcx.generics_of(source_ancestor);
2503        target_args
2504            .iter()
2505            .chain(self.iter().skip(defs.count()))
2506            .cloned()
2507            .collect()
2508    }
2509}
2510
2511#[derive(Debug)]
2512pub enum TyOrBase {
2513    Ty(Ty),
2514    Base(SubsetTyCtor),
2515}
2516
2517impl TyOrBase {
2518    pub fn into_ty(self) -> Ty {
2519        match self {
2520            TyOrBase::Ty(ty) => ty,
2521            TyOrBase::Base(ctor) => ctor.to_ty(),
2522        }
2523    }
2524
2525    #[track_caller]
2526    pub fn expect_base(self) -> SubsetTyCtor {
2527        match self {
2528            TyOrBase::Base(ctor) => ctor,
2529            TyOrBase::Ty(_) => tracked_span_bug!("expected `TyOrBase::Base`"),
2530        }
2531    }
2532
2533    pub fn as_base(self) -> Option<SubsetTyCtor> {
2534        match self {
2535            TyOrBase::Base(ctor) => Some(ctor),
2536            TyOrBase::Ty(_) => None,
2537        }
2538    }
2539}
2540
2541#[derive(Debug, Clone, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
2542pub enum TyOrCtor {
2543    Ty(Ty),
2544    Ctor(TyCtor),
2545}
2546
2547impl TyOrCtor {
2548    #[track_caller]
2549    pub fn expect_ctor(self) -> TyCtor {
2550        match self {
2551            TyOrCtor::Ctor(ctor) => ctor,
2552            TyOrCtor::Ty(_) => tracked_span_bug!("expected `TyOrCtor::Ctor`"),
2553        }
2554    }
2555
2556    pub fn expect_subset_ty_ctor(self) -> SubsetTyCtor {
2557        self.expect_ctor().map(|ty| {
2558            if let canonicalize::CanonicalTy::Constr(constr_ty) = ty.shallow_canonicalize()
2559                && let TyKind::Indexed(bty, idx) = constr_ty.ty().kind()
2560                && idx.is_nu()
2561            {
2562                SubsetTy::new(bty.clone(), Expr::nu(), constr_ty.pred())
2563            } else {
2564                tracked_span_bug!()
2565            }
2566        })
2567    }
2568
2569    pub fn to_ty(&self) -> Ty {
2570        match self {
2571            TyOrCtor::Ctor(ctor) => ctor.to_ty(),
2572            TyOrCtor::Ty(ty) => ty.clone(),
2573        }
2574    }
2575}
2576
2577impl From<TyOrBase> for TyOrCtor {
2578    fn from(v: TyOrBase) -> Self {
2579        match v {
2580            TyOrBase::Ty(ty) => TyOrCtor::Ty(ty),
2581            TyOrBase::Base(ctor) => TyOrCtor::Ctor(ctor.to_ty_ctor()),
2582        }
2583    }
2584}
2585
2586impl CoroutineObligPredicate {
2587    pub fn to_poly_fn_sig(&self) -> PolyFnSig {
2588        let vars = vec![];
2589
2590        let resume_ty = &self.resume_ty;
2591        let env_ty = Ty::coroutine(
2592            self.def_id,
2593            resume_ty.clone(),
2594            self.upvar_tys.clone(),
2595            self.args.clone(),
2596        );
2597
2598        let inputs = List::from_arr([env_ty, resume_ty.clone()]);
2599        let output =
2600            Binder::bind_with_vars(FnOutput::new(self.output.clone(), vec![]), List::empty());
2601
2602        PolyFnSig::bind_with_vars(
2603            FnSig::new(
2604                Safety::Safe,
2605                rustc_abi::ExternAbi::RustCall,
2606                List::empty(),
2607                inputs,
2608                output,
2609                Expr::ff(),
2610                false,
2611            ),
2612            List::from(vars),
2613        )
2614    }
2615}
2616
2617impl RefinementGenerics {
2618    pub fn count(&self) -> usize {
2619        self.parent_count + self.own_params.len()
2620    }
2621
2622    pub fn own_count(&self) -> usize {
2623        self.own_params.len()
2624    }
2625}
2626
2627impl EarlyBinder<RefinementGenerics> {
2628    pub fn parent(&self) -> Option<DefId> {
2629        self.skip_binder_ref().parent
2630    }
2631
2632    pub fn parent_count(&self) -> usize {
2633        self.skip_binder_ref().parent_count
2634    }
2635
2636    pub fn count(&self) -> usize {
2637        self.skip_binder_ref().count()
2638    }
2639
2640    pub fn own_count(&self) -> usize {
2641        self.skip_binder_ref().own_count()
2642    }
2643
2644    pub fn own_param_at(&self, index: usize) -> EarlyBinder<RefineParam> {
2645        self.as_ref().map(|this| this.own_params[index].clone())
2646    }
2647
2648    pub fn param_at(
2649        &self,
2650        param_index: usize,
2651        genv: GlobalEnv,
2652    ) -> QueryResult<EarlyBinder<RefineParam>> {
2653        if let Some(index) = param_index.checked_sub(self.parent_count()) {
2654            Ok(self.own_param_at(index))
2655        } else {
2656            let parent = self.parent().expect("parent_count > 0 but no parent?");
2657            genv.refinement_generics_of(parent)?
2658                .param_at(param_index, genv)
2659        }
2660    }
2661
2662    pub fn iter_own_params(&self) -> impl Iterator<Item = EarlyBinder<RefineParam>> + use<'_> {
2663        self.skip_binder_ref()
2664            .own_params
2665            .iter()
2666            .cloned()
2667            .map(EarlyBinder)
2668    }
2669
2670    pub fn fill_item<F, R>(&self, genv: GlobalEnv, vec: &mut Vec<R>, mk: &mut F) -> QueryResult
2671    where
2672        F: FnMut(EarlyBinder<RefineParam>, usize) -> QueryResult<R>,
2673    {
2674        if let Some(def_id) = self.parent() {
2675            genv.refinement_generics_of(def_id)?
2676                .fill_item(genv, vec, mk)?;
2677        }
2678        for param in self.iter_own_params() {
2679            vec.push(mk(param, vec.len())?);
2680        }
2681        Ok(())
2682    }
2683}
2684
2685impl EarlyBinder<GenericPredicates> {
2686    pub fn predicates(&self) -> EarlyBinder<List<Clause>> {
2687        EarlyBinder(self.0.predicates.clone())
2688    }
2689}
2690
2691impl EarlyBinder<FuncSort> {
2692    /// See [`subst::GenericsSubstForSort`]
2693    pub fn instantiate_func_sort<E>(
2694        self,
2695        sort_for_param: impl FnMut(ParamTy) -> Result<Sort, E>,
2696    ) -> Result<FuncSort, E> {
2697        self.0.try_fold_with(&mut subst::GenericsSubstFolder::new(
2698            subst::GenericsSubstForSort { sort_for_param },
2699            &[],
2700        ))
2701    }
2702}
2703
2704impl VariantSig {
2705    pub fn new(
2706        adt_def: AdtDef,
2707        args: GenericArgs,
2708        fields: List<Ty>,
2709        idx: Expr,
2710        requires: List<Expr>,
2711    ) -> Self {
2712        VariantSig { adt_def, args, fields, idx, requires }
2713    }
2714
2715    pub fn fields(&self) -> &[Ty] {
2716        &self.fields
2717    }
2718
2719    pub fn ret(&self) -> Ty {
2720        let bty = BaseTy::Adt(self.adt_def.clone(), self.args.clone());
2721        let idx = self.idx.clone();
2722        Ty::indexed(bty, idx)
2723    }
2724}
2725
2726impl FnSig {
2727    pub fn new(
2728        safety: Safety,
2729        abi: rustc_abi::ExternAbi,
2730        requires: List<Expr>,
2731        inputs: List<Ty>,
2732        output: Binder<FnOutput>,
2733        no_panic: Expr,
2734        lifted: bool,
2735    ) -> Self {
2736        FnSig { safety, abi, requires, inputs, output, no_panic, lifted }
2737    }
2738
2739    pub fn requires(&self) -> &[Expr] {
2740        &self.requires
2741    }
2742
2743    pub fn inputs(&self) -> &[Ty] {
2744        &self.inputs
2745    }
2746
2747    pub fn no_panic(&self) -> Expr {
2748        self.no_panic.clone()
2749    }
2750
2751    pub fn output(&self) -> Binder<FnOutput> {
2752        self.output.clone()
2753    }
2754}
2755
2756impl<'tcx> ToRustc<'tcx> for FnSig {
2757    type T = rustc_middle::ty::FnSig<'tcx>;
2758
2759    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2760        tcx.mk_fn_sig(
2761            self.inputs().iter().map(|ty| ty.to_rustc(tcx)),
2762            self.output().as_ref().skip_binder().to_rustc(tcx),
2763            false,
2764            self.safety,
2765            self.abi,
2766        )
2767    }
2768}
2769
2770impl FnOutput {
2771    pub fn new(ret: Ty, ensures: impl Into<List<Ensures>>) -> Self {
2772        Self { ret, ensures: ensures.into() }
2773    }
2774}
2775
2776impl<'tcx> ToRustc<'tcx> for FnOutput {
2777    type T = rustc_middle::ty::Ty<'tcx>;
2778
2779    fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Self::T {
2780        self.ret.to_rustc(tcx)
2781    }
2782}
2783
2784impl AdtDef {
2785    pub fn new(
2786        rustc: ty::AdtDef,
2787        sort_def: AdtSortDef,
2788        invariants: Vec<Invariant>,
2789        opaque: bool,
2790    ) -> Self {
2791        AdtDef(Interned::new(AdtDefData { invariants, sort_def, opaque, rustc }))
2792    }
2793
2794    pub fn did(&self) -> DefId {
2795        self.0.rustc.did()
2796    }
2797
2798    pub fn sort_def(&self) -> &AdtSortDef {
2799        &self.0.sort_def
2800    }
2801
2802    pub fn sort(&self, args: &[GenericArg]) -> Sort {
2803        self.sort_def().to_sort(args)
2804    }
2805
2806    pub fn is_box(&self) -> bool {
2807        self.0.rustc.is_box()
2808    }
2809
2810    pub fn is_enum(&self) -> bool {
2811        self.0.rustc.is_enum()
2812    }
2813
2814    pub fn is_struct(&self) -> bool {
2815        self.0.rustc.is_struct()
2816    }
2817
2818    pub fn is_union(&self) -> bool {
2819        self.0.rustc.is_union()
2820    }
2821
2822    pub fn variants(&self) -> &IndexSlice<VariantIdx, VariantDef> {
2823        self.0.rustc.variants()
2824    }
2825
2826    pub fn variant(&self, idx: VariantIdx) -> &VariantDef {
2827        self.0.rustc.variant(idx)
2828    }
2829
2830    pub fn invariants(&self) -> EarlyBinder<&[Invariant]> {
2831        EarlyBinder(&self.0.invariants)
2832    }
2833
2834    pub fn discriminants(&self) -> impl Iterator<Item = (VariantIdx, u128)> + '_ {
2835        self.0.rustc.discriminants()
2836    }
2837
2838    pub fn is_opaque(&self) -> bool {
2839        self.0.opaque
2840    }
2841}
2842
2843impl EarlyBinder<PolyVariant> {
2844    // The field_idx is `Some(i)` when we have the `i`-th field of a `union`, in which case,
2845    // the `inputs` are _just_ the `i`-th type (and not all the types...)
2846    pub fn to_poly_fn_sig(&self, field_idx: Option<crate::FieldIdx>) -> EarlyBinder<PolyFnSig> {
2847        self.as_ref().map(|poly_variant| {
2848            poly_variant.as_ref().map(|variant| {
2849                let ret = variant.ret().shift_in_escaping(1);
2850                let output = Binder::bind_with_vars(FnOutput::new(ret, vec![]), List::empty());
2851                let inputs = match field_idx {
2852                    None => variant.fields.clone(),
2853                    Some(i) => List::singleton(variant.fields[i.index()].clone()),
2854                };
2855                FnSig::new(
2856                    Safety::Safe,
2857                    rustc_abi::ExternAbi::Rust,
2858                    variant.requires.clone(),
2859                    inputs,
2860                    output,
2861                    Expr::tt(),
2862                    false,
2863                )
2864            })
2865        })
2866    }
2867}
2868
2869impl TyKind {
2870    fn intern(self) -> Ty {
2871        Ty(Interned::new(self))
2872    }
2873}
2874
2875/// returns the same invariants as for `usize` which is the length of a slice
2876fn slice_invariants(overflow_mode: OverflowMode) -> &'static [Invariant] {
2877    static DEFAULT: LazyLock<[Invariant; 1]> = LazyLock::new(|| {
2878        [Invariant { pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int) }]
2879    });
2880    static OVERFLOW: LazyLock<[Invariant; 2]> = LazyLock::new(|| {
2881        [
2882            Invariant {
2883                pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int),
2884            },
2885            Invariant {
2886                pred: Binder::bind_with_sort(
2887                    Expr::le(Expr::nu(), Expr::uint_max(UintTy::Usize)),
2888                    Sort::Int,
2889                ),
2890            },
2891        ]
2892    });
2893    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2894        &*OVERFLOW
2895    } else {
2896        &*DEFAULT
2897    }
2898}
2899
2900fn uint_invariants(uint_ty: UintTy, overflow_mode: OverflowMode) -> &'static [Invariant] {
2901    static DEFAULT: LazyLock<[Invariant; 1]> = LazyLock::new(|| {
2902        [Invariant { pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int) }]
2903    });
2904
2905    static OVERFLOW: LazyLock<UnordMap<UintTy, [Invariant; 2]>> = LazyLock::new(|| {
2906        UINT_TYS
2907            .into_iter()
2908            .map(|uint_ty| {
2909                let invariants = [
2910                    Invariant {
2911                        pred: Binder::bind_with_sort(Expr::ge(Expr::nu(), Expr::zero()), Sort::Int),
2912                    },
2913                    Invariant {
2914                        pred: Binder::bind_with_sort(
2915                            Expr::le(Expr::nu(), Expr::uint_max(uint_ty)),
2916                            Sort::Int,
2917                        ),
2918                    },
2919                ];
2920                (uint_ty, invariants)
2921            })
2922            .collect()
2923    });
2924    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2925        &OVERFLOW[&uint_ty]
2926    } else {
2927        &*DEFAULT
2928    }
2929}
2930
2931fn char_invariants() -> &'static [Invariant] {
2932    static INVARIANTS: LazyLock<[Invariant; 2]> = LazyLock::new(|| {
2933        [
2934            Invariant {
2935                pred: Binder::bind_with_sort(
2936                    Expr::le(
2937                        Expr::cast(Sort::Char, Sort::Int, Expr::nu()),
2938                        Expr::constant((char::MAX as u32).into()),
2939                    ),
2940                    Sort::Int,
2941                ),
2942            },
2943            Invariant {
2944                pred: Binder::bind_with_sort(
2945                    Expr::le(Expr::zero(), Expr::cast(Sort::Char, Sort::Int, Expr::nu())),
2946                    Sort::Int,
2947                ),
2948            },
2949        ]
2950    });
2951    &*INVARIANTS
2952}
2953
2954fn int_invariants(int_ty: IntTy, overflow_mode: OverflowMode) -> &'static [Invariant] {
2955    static DEFAULT: [Invariant; 0] = [];
2956
2957    static OVERFLOW: LazyLock<UnordMap<IntTy, [Invariant; 2]>> = LazyLock::new(|| {
2958        INT_TYS
2959            .into_iter()
2960            .map(|int_ty| {
2961                let invariants = [
2962                    Invariant {
2963                        pred: Binder::bind_with_sort(
2964                            Expr::ge(Expr::nu(), Expr::int_min(int_ty)),
2965                            Sort::Int,
2966                        ),
2967                    },
2968                    Invariant {
2969                        pred: Binder::bind_with_sort(
2970                            Expr::le(Expr::nu(), Expr::int_max(int_ty)),
2971                            Sort::Int,
2972                        ),
2973                    },
2974                ];
2975                (int_ty, invariants)
2976            })
2977            .collect()
2978    });
2979    if matches!(overflow_mode, OverflowMode::Strict | OverflowMode::Lazy) {
2980        &OVERFLOW[&int_ty]
2981    } else {
2982        &DEFAULT
2983    }
2984}
2985
2986impl_internable!(AdtDefData, AdtSortDefData, TyKind);
2987impl_slice_internable!(
2988    Ty,
2989    GenericArg,
2990    Ensures,
2991    InferMode,
2992    Sort,
2993    SortArg,
2994    GenericParamDef,
2995    TraitRef,
2996    Binder<ExistentialPredicate>,
2997    Clause,
2998    PolyVariant,
2999    Invariant,
3000    RefineParam,
3001    FluxDefId,
3002    SortParamKind,
3003    AssocReft
3004);
3005
3006#[macro_export]
3007macro_rules! _Int {
3008    ($int_ty:pat, $idxs:pat) => {
3009        TyKind::Indexed(BaseTy::Int($int_ty), $idxs)
3010    };
3011}
3012pub use crate::_Int as Int;
3013
3014#[macro_export]
3015macro_rules! _Uint {
3016    ($uint_ty:pat, $idxs:pat) => {
3017        TyKind::Indexed(BaseTy::Uint($uint_ty), $idxs)
3018    };
3019}
3020pub use crate::_Uint as Uint;
3021
3022#[macro_export]
3023macro_rules! _Bool {
3024    ($idxs:pat) => {
3025        TyKind::Indexed(BaseTy::Bool, $idxs)
3026    };
3027}
3028pub use crate::_Bool as Bool;
3029
3030#[macro_export]
3031macro_rules! _Char {
3032    ($idxs:pat) => {
3033        TyKind::Indexed(BaseTy::Char, $idxs)
3034    };
3035}
3036pub use crate::_Char as Char;
3037
3038#[macro_export]
3039macro_rules! _Ref {
3040    ($($pats:pat),+ $(,)?) => {
3041        $crate::rty::TyKind::Indexed($crate::rty::BaseTy::Ref($($pats),+), _)
3042    };
3043}
3044pub use crate::_Ref as Ref;
3045
3046pub struct WfckResults {
3047    pub owner: FluxOwnerId,
3048    param_sorts: UnordMap<fhir::ParamId, Sort>,
3049    bin_op_sorts: ItemLocalMap<Sort>,
3050    fn_app_sorts: ItemLocalMap<List<SortArg>>,
3051    coercions: ItemLocalMap<Vec<Coercion>>,
3052    field_projs: ItemLocalMap<FieldProj>,
3053    node_sorts: ItemLocalMap<Sort>,
3054    record_ctors: ItemLocalMap<RecordCtor>,
3055}
3056
3057#[derive(Clone, Copy, Debug)]
3058pub enum Coercion {
3059    Inject(DefId),
3060    Project(DefId),
3061}
3062
3063#[derive(Clone, Copy, Debug)]
3064pub enum RecordCtor {
3065    Struct(DefId),
3066    RawPtr,
3067}
3068
3069pub type ItemLocalMap<T> = UnordMap<fhir::ItemLocalId, T>;
3070
3071#[derive(Debug)]
3072pub struct LocalTableInContext<'a, T> {
3073    owner: FluxOwnerId,
3074    data: &'a ItemLocalMap<T>,
3075}
3076
3077pub struct LocalTableInContextMut<'a, T> {
3078    owner: FluxOwnerId,
3079    data: &'a mut ItemLocalMap<T>,
3080}
3081
3082impl WfckResults {
3083    pub fn new(owner: impl Into<FluxOwnerId>) -> Self {
3084        Self {
3085            owner: owner.into(),
3086            param_sorts: UnordMap::default(),
3087            bin_op_sorts: ItemLocalMap::default(),
3088            coercions: ItemLocalMap::default(),
3089            field_projs: ItemLocalMap::default(),
3090            node_sorts: ItemLocalMap::default(),
3091            record_ctors: ItemLocalMap::default(),
3092            fn_app_sorts: ItemLocalMap::default(),
3093        }
3094    }
3095
3096    pub fn param_sorts_mut(&mut self) -> &mut UnordMap<fhir::ParamId, Sort> {
3097        &mut self.param_sorts
3098    }
3099
3100    pub fn param_sorts(&self) -> &UnordMap<fhir::ParamId, Sort> {
3101        &self.param_sorts
3102    }
3103
3104    pub fn bin_op_sorts_mut(&mut self) -> LocalTableInContextMut<'_, Sort> {
3105        LocalTableInContextMut { owner: self.owner, data: &mut self.bin_op_sorts }
3106    }
3107
3108    pub fn fn_app_sorts_mut(&mut self) -> LocalTableInContextMut<'_, List<SortArg>> {
3109        LocalTableInContextMut { owner: self.owner, data: &mut self.fn_app_sorts }
3110    }
3111
3112    pub fn fn_app_sorts(&self) -> LocalTableInContext<'_, List<SortArg>> {
3113        LocalTableInContext { owner: self.owner, data: &self.fn_app_sorts }
3114    }
3115
3116    pub fn bin_op_sorts(&self) -> LocalTableInContext<'_, Sort> {
3117        LocalTableInContext { owner: self.owner, data: &self.bin_op_sorts }
3118    }
3119
3120    pub fn coercions_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Coercion>> {
3121        LocalTableInContextMut { owner: self.owner, data: &mut self.coercions }
3122    }
3123
3124    pub fn coercions(&self) -> LocalTableInContext<'_, Vec<Coercion>> {
3125        LocalTableInContext { owner: self.owner, data: &self.coercions }
3126    }
3127
3128    pub fn field_projs_mut(&mut self) -> LocalTableInContextMut<'_, FieldProj> {
3129        LocalTableInContextMut { owner: self.owner, data: &mut self.field_projs }
3130    }
3131
3132    pub fn field_projs(&self) -> LocalTableInContext<'_, FieldProj> {
3133        LocalTableInContext { owner: self.owner, data: &self.field_projs }
3134    }
3135
3136    pub fn node_sorts_mut(&mut self) -> LocalTableInContextMut<'_, Sort> {
3137        LocalTableInContextMut { owner: self.owner, data: &mut self.node_sorts }
3138    }
3139
3140    pub fn node_sorts(&self) -> LocalTableInContext<'_, Sort> {
3141        LocalTableInContext { owner: self.owner, data: &self.node_sorts }
3142    }
3143
3144    pub fn record_ctors_mut(&mut self) -> LocalTableInContextMut<'_, RecordCtor> {
3145        LocalTableInContextMut { owner: self.owner, data: &mut self.record_ctors }
3146    }
3147
3148    pub fn record_ctors(&self) -> LocalTableInContext<'_, RecordCtor> {
3149        LocalTableInContext { owner: self.owner, data: &self.record_ctors }
3150    }
3151}
3152
3153impl<T> LocalTableInContextMut<'_, T> {
3154    pub fn insert(&mut self, fhir_id: FhirId, value: T) {
3155        tracked_span_assert_eq!(self.owner, fhir_id.owner);
3156        self.data.insert(fhir_id.local_id, value);
3157    }
3158}
3159
3160impl<'a, T> LocalTableInContext<'a, T> {
3161    pub fn get(&self, fhir_id: FhirId) -> Option<&'a T> {
3162        tracked_span_assert_eq!(self.owner, fhir_id.owner);
3163        self.data.get(&fhir_id.local_id)
3164    }
3165}
3166
3167fn can_auto_strong(fn_sig: &PolyFnSig) -> bool {
3168    struct RegionDetector {
3169        has_region: bool,
3170    }
3171
3172    impl fold::TypeFolder for RegionDetector {
3173        fn fold_region(&mut self, re: &Region) -> Region {
3174            self.has_region = true;
3175            *re
3176        }
3177    }
3178    let mut detector = RegionDetector { has_region: false };
3179    fn_sig
3180        .skip_binder_ref()
3181        .output()
3182        .skip_binder_ref()
3183        .ret
3184        .fold_with(&mut detector);
3185
3186    !detector.has_region
3187}
3188/// The [`auto_strong`] function transforms function signatures by automatically converting
3189/// mutable reference parameters into strong references with associated ensures clauses. This
3190/// transformation is applied only when the function signature does not already contain region
3191/// variables in its return type.
3192///
3193/// Specifically, given a source function of type
3194///
3195///    fn (x: &mut InnerTy) -> bool
3196///
3197/// By default the above gives us an `rty::FnSig`
3198///
3199///    forall<>. fn (x: &mut InnerTy) -> bool
3200///
3201/// Which this function then transforms to
3202///
3203///     forall<l0: Loc>. fn (x: &strg<l0:InnerTy>) -> bool ensures l0:InnerTy
3204pub fn auto_strong(
3205    genv: GlobalEnv,
3206    def_id: impl IntoQueryParam<DefId>,
3207    fn_sig: PolyFnSig,
3208) -> PolyFnSig {
3209    // TODO(auto-strong): we only *really* need the first check `can_auto_strong` here.
3210    // The other two skip `auto-strong` as doing it breaks various downstream things
3211    // that should be fixed.
3212    if !can_auto_strong(&fn_sig)
3213        || matches!(genv.def_kind(def_id), rustc_hir::def::DefKind::Closure)
3214        || !fn_sig.skip_binder_ref().lifted
3215    {
3216        return fn_sig;
3217    }
3218    let kind = BoundReftKind::Anon;
3219    let mut vars = fn_sig.vars().to_vec();
3220    let fn_sig = fn_sig.skip_binder();
3221    // new list of (bound_var, inner_ty)
3222    let mut strg_bvars = vec![];
3223    // new list of input types
3224    let mut strg_inputs = vec![];
3225    // 1. Traverse inputs collecting strong locations
3226    for ty in &fn_sig.inputs {
3227        let strg_ty = if let TyKind::Indexed(BaseTy::Ref(re, inner_ty, Mutability::Mut), _) =
3228            ty.kind()
3229            && !inner_ty.is_slice()
3230        // TODO(auto-strong): including `slice` breaks `tock` for some reason we should replicate in our own tests...
3231        {
3232            // if input is &mut InnerTy create a new bound var `loc` for the strong location
3233            let var = {
3234                let idx = vars.len() + strg_bvars.len();
3235                BoundVar::from_usize(idx)
3236            };
3237            strg_bvars.push((var, inner_ty.clone()));
3238            let loc = Loc::Var(Var::Bound(INNERMOST, BoundReft { var, kind }));
3239            // and transform to &strg<loc:InnerTy>
3240            Ty::strg_ref(*re, Path::new(loc, List::empty()), inner_ty.clone())
3241        } else {
3242            // else leave input type unchanged
3243            ty.clone()
3244        };
3245        strg_inputs.push(strg_ty);
3246    }
3247    // 2. Add bound vars for strong locations
3248    for _ in 0..strg_bvars.len() {
3249        vars.push(BoundVariableKind::Refine(Sort::Loc, InferMode::EVar, kind));
3250    }
3251    // 3. Add ensures for strong locations
3252    let output = fn_sig.output.map(|out| {
3253        let mut ens = out.ensures.to_vec();
3254        for (var, inner_ty) in strg_bvars {
3255            let loc = Loc::Var(Var::Bound(INNERMOST.shifted_in(1), BoundReft { var, kind }));
3256            let path = Path::new(loc, List::empty());
3257            ens.push(Ensures::Type(path, inner_ty.shift_in_escaping(1)));
3258        }
3259        FnOutput { ensures: List::from_vec(ens), ..out }
3260    });
3261
3262    // 4. Reconstruct fn sig with new inputs and output and vars
3263    let fn_sig = FnSig { inputs: List::from_vec(strg_inputs), output, ..fn_sig };
3264    Binder::bind_with_vars(fn_sig, vars.into())
3265}