Skip to main content

flux_middle/rty/
mod.rs

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