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