charon_lib/ast/
types_utils.rs

1//! This file groups everything which is linked to implementations about [crate::types]
2use crate::ast::*;
3use crate::ids::IndexMap;
4use derive_generic_visitor::*;
5use itertools::Itertools;
6use std::collections::HashSet;
7use std::convert::Infallible;
8use std::fmt::Debug;
9use std::iter::Iterator;
10use std::mem;
11
12impl TraitParam {
13    /// Constructs the trait ref that refers to this clause.
14    pub fn identity_tref(&self) -> TraitRef {
15        self.identity_tref_at_depth(DeBruijnId::zero())
16    }
17
18    /// Like `identity_tref` but uses variables bound at the given depth.
19    pub fn identity_tref_at_depth(&self, depth: DeBruijnId) -> TraitRef {
20        TraitRef::new(
21            TraitRefKind::Clause(DeBruijnVar::bound(depth, self.clause_id)),
22            self.trait_.clone().move_under_binders(depth),
23        )
24    }
25}
26
27impl GenericParams {
28    pub fn empty() -> Self {
29        Self::default()
30    }
31
32    pub fn is_empty(&self) -> bool {
33        self.len() == 0
34    }
35    /// Whether this has any explicit arguments (types, regions or const generics).
36    pub fn has_explicits(&self) -> bool {
37        !self.regions.is_empty() || !self.types.is_empty() || !self.const_generics.is_empty()
38    }
39    /// Whether this has any implicit arguments (trait clauses, outlives relations, associated type
40    /// equality constraints).
41    pub fn has_predicates(&self) -> bool {
42        !self.trait_clauses.is_empty()
43            || !self.types_outlive.is_empty()
44            || !self.regions_outlive.is_empty()
45            || !self.trait_type_constraints.is_empty()
46    }
47
48    /// Run some sanity checks.
49    pub fn check_consistency(&self) {
50        // Sanity check: check the clause ids are consistent.
51        assert!(
52            self.trait_clauses
53                .iter()
54                .enumerate()
55                .all(|(i, c)| c.clause_id.index() == i)
56        );
57
58        // Sanity check: region names are pairwise distinct (this caused trouble when generating
59        // names for the backward functions in Aeneas): at some point, Rustc introduced names equal
60        // to `Some("'_")` for the anonymous regions, instead of using `None` (we now check in
61        // [translate_region_name] and ignore names equal to "'_").
62        let mut s = HashSet::new();
63        for r in &self.regions {
64            if let Some(name) = &r.name {
65                assert!(
66                    !s.contains(name),
67                    "Name \"{}\" reused for two different lifetimes",
68                    name
69                );
70                s.insert(name);
71            }
72        }
73    }
74
75    pub fn len(&self) -> usize {
76        let GenericParams {
77            regions,
78            types,
79            const_generics,
80            trait_clauses,
81            regions_outlive,
82            types_outlive,
83            trait_type_constraints,
84        } = self;
85        regions.elem_count()
86            + types.elem_count()
87            + const_generics.elem_count()
88            + trait_clauses.elem_count()
89            + regions_outlive.len()
90            + types_outlive.len()
91            + trait_type_constraints.elem_count()
92    }
93
94    /// Construct a set of generic arguments in the scope of `self` that matches `self` and feeds
95    /// each required parameter with itself. E.g. given parameters for `<T, U> where U:
96    /// PartialEq<T>`, the arguments would be `<T, U>[@TraitClause0]`.
97    pub fn identity_args(&self) -> GenericArgs {
98        self.identity_args_at_depth(DeBruijnId::zero())
99    }
100
101    /// Like `identity_args` but uses variables bound at the given depth.
102    pub fn identity_args_at_depth(&self, depth: DeBruijnId) -> GenericArgs {
103        GenericArgs {
104            regions: self
105                .regions
106                .map_ref_indexed(|id, _| Region::Var(DeBruijnVar::bound(depth, id))),
107            types: self
108                .types
109                .map_ref_indexed(|id, _| TyKind::TypeVar(DeBruijnVar::bound(depth, id)).into_ty()),
110            const_generics: self
111                .const_generics
112                .map_ref_indexed(|id, _| ConstGeneric::Var(DeBruijnVar::bound(depth, id))),
113            trait_refs: self
114                .trait_clauses
115                .map_ref(|clause| clause.identity_tref_at_depth(depth)),
116        }
117    }
118
119    /// Take the predicates from the another `GenericParams`. This assumes the clause ids etc are
120    /// already consistent.
121    pub fn take_predicates_from(&mut self, other: GenericParams) {
122        assert!(!other.has_explicits());
123        let num_clauses = self.trait_clauses.slot_count();
124        let GenericParams {
125            regions: _,
126            types: _,
127            const_generics: _,
128            trait_clauses,
129            regions_outlive,
130            types_outlive,
131            trait_type_constraints,
132        } = other;
133        self.trait_clauses
134            .extend(trait_clauses.into_iter().update(|clause| {
135                clause.clause_id += num_clauses;
136            }));
137        self.regions_outlive.extend(regions_outlive);
138        self.types_outlive.extend(types_outlive);
139        self.trait_type_constraints.extend(trait_type_constraints);
140    }
141
142    /// Take the predicates from the another `GenericParams`. This assumes that the two
143    /// `GenericParams` are independent, hence will shift clause ids if `other` has any
144    /// trait refs that reference its own clauses.
145    pub fn merge_predicates_from(&mut self, mut other: GenericParams) {
146        // Drop the explicits params.
147        other.types.clear();
148        other.regions.clear();
149        other.const_generics.clear();
150        // The contents of `other` may refer to its own trait clauses, so we must shift clause ids.
151        struct ShiftClausesVisitor(usize);
152        impl VarsVisitor for ShiftClausesVisitor {
153            fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
154                if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
155                    // Replace clause 0 and decrement the others.
156                    Some(TraitRefKind::Clause(DeBruijnVar::Bound(
157                        DeBruijnId::ZERO,
158                        clause_id + self.0,
159                    )))
160                } else {
161                    None
162                }
163            }
164        }
165        let num_clauses = self.trait_clauses.slot_count();
166        other.visit_vars(&mut ShiftClausesVisitor(num_clauses));
167        self.take_predicates_from(other);
168    }
169}
170
171impl<T> Binder<T> {
172    /// Wrap the value in an empty binder, shifting variables appropriately.
173    pub fn empty(kind: BinderKind, x: T) -> Self
174    where
175        T: TyVisitable,
176    {
177        Binder {
178            params: Default::default(),
179            skip_binder: x.move_under_binder(),
180            kind,
181        }
182    }
183    pub fn new(kind: BinderKind, params: GenericParams, skip_binder: T) -> Self {
184        Self {
185            params,
186            skip_binder,
187            kind,
188        }
189    }
190
191    /// Whether this binder binds any variables.
192    pub fn binds_anything(&self) -> bool {
193        !self.params.is_empty()
194    }
195
196    /// Retreive the contents of this binder if the binder binds no variables. This is the invers
197    /// of `Binder::empty`.
198    pub fn get_if_binds_nothing(&self) -> Option<T>
199    where
200        T: TyVisitable + Clone,
201    {
202        self.params
203            .is_empty()
204            .then(|| self.skip_binder.clone().move_from_under_binder().unwrap())
205    }
206
207    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binder<U> {
208        Binder {
209            params: self.params,
210            skip_binder: f(self.skip_binder),
211            kind: self.kind.clone(),
212        }
213    }
214
215    pub fn map_ref<U>(&self, f: impl FnOnce(&T) -> U) -> Binder<U> {
216        Binder {
217            params: self.params.clone(),
218            skip_binder: f(&self.skip_binder),
219            kind: self.kind.clone(),
220        }
221    }
222
223    /// Substitute the provided arguments for the variables bound in this binder and return the
224    /// substituted inner value.
225    pub fn apply(self, args: &GenericArgs) -> T
226    where
227        T: TyVisitable,
228    {
229        self.skip_binder.substitute(args)
230    }
231}
232
233impl<T: AstVisitable> Binder<Binder<T>> {
234    /// Flatten two levels of binders into a single one.
235    pub fn flatten(self) -> Binder<T> {
236        #[derive(Visitor)]
237        struct FlattenVisitor<'a> {
238            shift_by: &'a GenericParams,
239            binder_depth: DeBruijnId,
240        }
241        impl VisitorWithBinderDepth for FlattenVisitor<'_> {
242            fn binder_depth_mut(&mut self) -> &mut DeBruijnId {
243                &mut self.binder_depth
244            }
245        }
246        impl VisitAstMut for FlattenVisitor<'_> {
247            fn visit<'a, T: AstVisitable>(&'a mut self, x: &mut T) -> ControlFlow<Self::Break> {
248                VisitWithBinderDepth::new(self).visit(x)
249            }
250
251            fn enter_de_bruijn_id(&mut self, db_id: &mut DeBruijnId) {
252                if *db_id > self.binder_depth {
253                    // We started visiting at the inner binder, so in this branch we're either
254                    // mentioning the outer binder or a binder further beyond. Either way we
255                    // decrease the depth; variables that point to the outer binder don't have to
256                    // be shifted.
257                    *db_id = db_id.decr();
258                }
259            }
260            fn enter_region(&mut self, x: &mut Region) {
261                if let Region::Var(var) = x
262                    && let Some(id) = var.bound_at_depth_mut(self.binder_depth)
263                {
264                    *id += self.shift_by.regions.slot_count();
265                }
266            }
267            fn enter_ty_kind(&mut self, x: &mut TyKind) {
268                if let TyKind::TypeVar(var) = x
269                    && let Some(id) = var.bound_at_depth_mut(self.binder_depth)
270                {
271                    *id += self.shift_by.types.slot_count();
272                }
273            }
274            fn enter_const_generic(&mut self, x: &mut ConstGeneric) {
275                if let ConstGeneric::Var(var) = x
276                    && let Some(id) = var.bound_at_depth_mut(self.binder_depth)
277                {
278                    *id += self.shift_by.const_generics.slot_count();
279                }
280            }
281            fn enter_trait_ref_kind(&mut self, x: &mut TraitRefKind) {
282                if let TraitRefKind::Clause(var) = x
283                    && let Some(id) = var.bound_at_depth_mut(self.binder_depth)
284                {
285                    *id += self.shift_by.trait_clauses.slot_count();
286                }
287            }
288        }
289
290        // We will concatenate both sets of params.
291        let mut outer_params = self.params;
292
293        // The inner value needs to change:
294        // - at binder level 0 we shift all variable ids to match the concatenated params;
295        // - at binder level > 0 we decrease binding level because there's one fewer binder.
296        let mut bound_value = self.skip_binder.skip_binder;
297        let _ = bound_value.drive_mut(&mut FlattenVisitor {
298            shift_by: &outer_params,
299            binder_depth: Default::default(),
300        });
301
302        // The inner params must also be updated, as they can refer to themselves and the outer
303        // one.
304        let mut inner_params = self.skip_binder.params;
305        let _ = inner_params.drive_mut(&mut FlattenVisitor {
306            shift_by: &outer_params,
307            binder_depth: Default::default(),
308        });
309        inner_params
310            .regions
311            .iter_mut()
312            .for_each(|v| v.index += outer_params.regions.slot_count());
313        inner_params
314            .types
315            .iter_mut()
316            .for_each(|v| v.index += outer_params.types.slot_count());
317        inner_params
318            .const_generics
319            .iter_mut()
320            .for_each(|v| v.index += outer_params.const_generics.slot_count());
321        inner_params
322            .trait_clauses
323            .iter_mut()
324            .for_each(|v| v.clause_id += outer_params.trait_clauses.slot_count());
325
326        let GenericParams {
327            regions,
328            types,
329            const_generics,
330            trait_clauses,
331            regions_outlive,
332            types_outlive,
333            trait_type_constraints,
334        } = &inner_params;
335        outer_params.regions.extend_from_slice(regions);
336        outer_params.types.extend_from_slice(types);
337        outer_params
338            .const_generics
339            .extend_from_slice(const_generics);
340        outer_params.trait_clauses.extend_from_slice(trait_clauses);
341        outer_params
342            .regions_outlive
343            .extend_from_slice(regions_outlive);
344        outer_params.types_outlive.extend_from_slice(types_outlive);
345        outer_params
346            .trait_type_constraints
347            .extend_from_slice(trait_type_constraints);
348
349        Binder {
350            params: outer_params,
351            skip_binder: bound_value,
352            kind: BinderKind::Other,
353        }
354    }
355}
356
357impl<T> RegionBinder<T> {
358    /// Wrap the value in an empty region binder, shifting variables appropriately.
359    pub fn empty(x: T) -> Self
360    where
361        T: TyVisitable,
362    {
363        RegionBinder {
364            regions: Default::default(),
365            skip_binder: x.move_under_binder(),
366        }
367    }
368
369    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> RegionBinder<U> {
370        RegionBinder {
371            regions: self.regions,
372            skip_binder: f(self.skip_binder),
373        }
374    }
375
376    pub fn map_ref<U>(&self, f: impl FnOnce(&T) -> U) -> RegionBinder<U> {
377        RegionBinder {
378            regions: self.regions.clone(),
379            skip_binder: f(&self.skip_binder),
380        }
381    }
382
383    /// Substitute the bound variables with the given lifetimes.
384    pub fn apply(self, regions: IndexMap<RegionId, Region>) -> T
385    where
386        T: AstVisitable,
387    {
388        assert_eq!(regions.slot_count(), self.regions.slot_count());
389        let args = GenericArgs {
390            regions,
391            ..GenericArgs::empty()
392        };
393        self.skip_binder.substitute(&args)
394    }
395
396    /// Substitute the bound variables with erased lifetimes.
397    pub fn erase(self) -> T
398    where
399        T: AstVisitable,
400    {
401        let regions = self.regions.map_ref_indexed(|_, _| Region::Erased);
402        self.apply(regions)
403    }
404}
405
406impl GenericArgs {
407    pub fn len(&self) -> usize {
408        let GenericArgs {
409            regions,
410            types,
411            const_generics,
412            trait_refs,
413        } = self;
414        regions.elem_count()
415            + types.elem_count()
416            + const_generics.elem_count()
417            + trait_refs.elem_count()
418    }
419
420    pub fn is_empty(&self) -> bool {
421        self.len() == 0
422    }
423    /// Whether this has any explicit arguments (types, regions or const generics).
424    pub fn has_explicits(&self) -> bool {
425        !self.regions.is_empty() || !self.types.is_empty() || !self.const_generics.is_empty()
426    }
427    /// Whether this has any implicit arguments (trait refs).
428    pub fn has_implicits(&self) -> bool {
429        !self.trait_refs.is_empty()
430    }
431
432    pub fn empty() -> Self {
433        GenericArgs {
434            regions: Default::default(),
435            types: Default::default(),
436            const_generics: Default::default(),
437            trait_refs: Default::default(),
438        }
439    }
440
441    pub fn new_for_builtin(types: IndexMap<TypeVarId, Ty>) -> Self {
442        GenericArgs {
443            types,
444            ..Self::empty()
445        }
446    }
447
448    pub fn new(
449        regions: IndexMap<RegionId, Region>,
450        types: IndexMap<TypeVarId, Ty>,
451        const_generics: IndexMap<ConstGenericVarId, ConstGeneric>,
452        trait_refs: IndexMap<TraitClauseId, TraitRef>,
453    ) -> Self {
454        Self {
455            regions,
456            types,
457            const_generics,
458            trait_refs,
459        }
460    }
461
462    pub fn new_types(types: IndexMap<TypeVarId, Ty>) -> Self {
463        Self {
464            types,
465            ..Self::empty()
466        }
467    }
468
469    /// Check whether this matches the given `GenericParams`.
470    /// TODO: check more things, e.g. that the trait refs use the correct trait and generics.
471    pub fn matches(&self, params: &GenericParams) -> bool {
472        params.regions.elem_count() == self.regions.elem_count()
473            && params.types.elem_count() == self.types.elem_count()
474            && params.const_generics.elem_count() == self.const_generics.elem_count()
475            && params.trait_clauses.elem_count() == self.trait_refs.elem_count()
476    }
477
478    /// Return the same generics, but where we pop the first type arguments.
479    /// This is useful for trait references (for pretty printing for instance),
480    /// because the first type argument is the type for which the trait is
481    /// implemented.
482    pub fn pop_first_type_arg(&self) -> (Ty, Self) {
483        let mut generics = self.clone();
484        let mut it = mem::take(&mut generics.types).into_iter();
485        let ty = it.next().unwrap();
486        generics.types = it.collect();
487        (ty, generics)
488    }
489
490    /// Concatenate this set of arguments with another one. Use with care, you must manage the
491    /// order of arguments correctly.
492    pub fn concat(mut self, other: &Self) -> Self {
493        let Self {
494            regions,
495            types,
496            const_generics,
497            trait_refs,
498        } = other;
499        self.regions.extend_from_slice(regions);
500        self.types.extend_from_slice(types);
501        self.const_generics.extend_from_slice(const_generics);
502        self.trait_refs.extend_from_slice(trait_refs);
503        self
504    }
505}
506
507impl IntTy {
508    /// Important: this returns the target byte count for the types.
509    /// Must not be used for host types from rustc.
510    pub fn target_size(&self, ptr_size: ByteCount) -> usize {
511        match self {
512            IntTy::Isize => ptr_size as usize,
513            IntTy::I8 => size_of::<i8>(),
514            IntTy::I16 => size_of::<i16>(),
515            IntTy::I32 => size_of::<i32>(),
516            IntTy::I64 => size_of::<i64>(),
517            IntTy::I128 => size_of::<i128>(),
518        }
519    }
520}
521impl UIntTy {
522    /// Important: this returns the target byte count for the types.
523    /// Must not be used for host types from rustc.
524    pub fn target_size(&self, ptr_size: ByteCount) -> usize {
525        match self {
526            UIntTy::Usize => ptr_size as usize,
527            UIntTy::U8 => size_of::<u8>(),
528            UIntTy::U16 => size_of::<u16>(),
529            UIntTy::U32 => size_of::<u32>(),
530            UIntTy::U64 => size_of::<u64>(),
531            UIntTy::U128 => size_of::<u128>(),
532        }
533    }
534}
535impl FloatTy {
536    /// Important: this returns the target byte count for the types.
537    /// Must not be used for host types from rustc.
538    pub fn target_size(&self) -> usize {
539        match self {
540            FloatTy::F16 => size_of::<u16>(),
541            FloatTy::F32 => size_of::<u32>(),
542            FloatTy::F64 => size_of::<u64>(),
543            FloatTy::F128 => size_of::<u128>(),
544        }
545    }
546}
547
548impl IntegerTy {
549    pub fn to_unsigned(&self) -> Self {
550        match self {
551            IntegerTy::Signed(IntTy::Isize) => IntegerTy::Unsigned(UIntTy::Usize),
552            IntegerTy::Signed(IntTy::I8) => IntegerTy::Unsigned(UIntTy::U8),
553            IntegerTy::Signed(IntTy::I16) => IntegerTy::Unsigned(UIntTy::U16),
554            IntegerTy::Signed(IntTy::I32) => IntegerTy::Unsigned(UIntTy::U32),
555            IntegerTy::Signed(IntTy::I64) => IntegerTy::Unsigned(UIntTy::U64),
556            IntegerTy::Signed(IntTy::I128) => IntegerTy::Unsigned(UIntTy::U128),
557            _ => *self,
558        }
559    }
560
561    /// Important: this returns the target byte count for the types.
562    /// Must not be used for host types from rustc.
563    pub fn target_size(&self, ptr_size: ByteCount) -> usize {
564        match self {
565            IntegerTy::Signed(ty) => ty.target_size(ptr_size),
566            IntegerTy::Unsigned(ty) => ty.target_size(ptr_size),
567        }
568    }
569}
570
571impl LiteralTy {
572    pub fn to_integer_ty(&self) -> Option<IntegerTy> {
573        match self {
574            Self::Int(int_ty) => Some(IntegerTy::Signed(*int_ty)),
575            Self::UInt(uint_ty) => Some(IntegerTy::Unsigned(*uint_ty)),
576            _ => None,
577        }
578    }
579
580    /// Important: this returns the target byte count for the types.
581    /// Must not be used for host types from rustc.
582    pub fn target_size(&self, ptr_size: ByteCount) -> usize {
583        match self {
584            LiteralTy::Int(int_ty) => int_ty.target_size(ptr_size),
585            LiteralTy::UInt(uint_ty) => uint_ty.target_size(ptr_size),
586            LiteralTy::Float(float_ty) => float_ty.target_size(),
587            LiteralTy::Char => 4,
588            LiteralTy::Bool => 1,
589        }
590    }
591}
592
593impl From<LiteralTy> for Ty {
594    fn from(value: LiteralTy) -> Self {
595        TyKind::Literal(value).into_ty()
596    }
597}
598
599/// A value of type `T` bound by the generic parameters of item
600/// `item`. Used when dealing with multiple items at a time, to
601/// ensure we don't mix up generics.
602///
603/// To get the value, use `under_binder_of` or `subst_for`.
604#[derive(Debug, Clone, Copy)]
605pub struct ItemBinder<ItemId, T> {
606    pub item_id: ItemId,
607    val: T,
608}
609
610impl<ItemId, T> ItemBinder<ItemId, T>
611where
612    ItemId: Debug + Copy + PartialEq,
613{
614    pub fn new(item_id: ItemId, val: T) -> Self {
615        Self { item_id, val }
616    }
617
618    pub fn as_ref(&self) -> ItemBinder<ItemId, &T> {
619        ItemBinder {
620            item_id: self.item_id,
621            val: &self.val,
622        }
623    }
624
625    pub fn map_bound<U>(self, f: impl FnOnce(T) -> U) -> ItemBinder<ItemId, U> {
626        ItemBinder {
627            item_id: self.item_id,
628            val: f(self.val),
629        }
630    }
631
632    fn assert_item_id(&self, item_id: ItemId) {
633        assert_eq!(
634            self.item_id, item_id,
635            "Trying to use item bound for {:?} as if it belonged to {:?}",
636            self.item_id, item_id
637        );
638    }
639
640    /// Assert that the value is bound for item `item_id`, and returns it. This is used when we
641    /// plan to store the returned value inside that item.
642    pub fn under_binder_of(self, item_id: ItemId) -> T {
643        self.assert_item_id(item_id);
644        self.val
645    }
646
647    /// Given generic args for `item_id`, assert that the value is bound for `item_id` and
648    /// substitute it with the provided generic arguments. Because the arguments are bound in the
649    /// context of another item, so it the resulting substituted value.
650    pub fn substitute<OtherItem: Debug + Copy + PartialEq>(
651        self,
652        args: ItemBinder<OtherItem, &GenericArgs>,
653    ) -> ItemBinder<OtherItem, T>
654    where
655        ItemId: Into<ItemId>,
656        T: TyVisitable,
657    {
658        args.map_bound(|args| self.val.substitute(args))
659    }
660}
661
662/// Dummy item identifier that represents the current item when not ambiguous.
663#[derive(Debug, Clone, Copy, PartialEq, Eq)]
664pub struct CurrentItem;
665
666impl<T> ItemBinder<CurrentItem, T> {
667    pub fn under_current_binder(self) -> T {
668        self.val
669    }
670}
671
672impl Ty {
673    pub fn new(kind: TyKind) -> Self {
674        Ty(HashConsed::new(kind))
675    }
676
677    pub fn kind(&self) -> &TyKind {
678        self.0.inner()
679    }
680
681    pub fn with_kind_mut<R>(&mut self, f: impl FnOnce(&mut TyKind) -> R) -> R {
682        self.0.with_inner_mut(f)
683    }
684
685    /// Return the unit type
686    pub fn mk_unit() -> Ty {
687        Self::mk_tuple(vec![])
688    }
689
690    pub fn mk_usize() -> Ty {
691        TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)).into()
692    }
693
694    pub fn mk_tuple(tys: Vec<Ty>) -> Ty {
695        TyKind::Adt(TypeDeclRef {
696            id: TypeId::Tuple,
697            generics: Box::new(GenericArgs::new_for_builtin(tys.into())),
698        })
699        .into_ty()
700    }
701
702    pub fn mk_array(ty: Ty, len: ConstGeneric) -> Ty {
703        TyKind::Adt(TypeDeclRef {
704            id: TypeId::Builtin(BuiltinTy::Array),
705            generics: Box::new(GenericArgs::new(
706                vec![].into(),
707                vec![ty].into(),
708                vec![len].into(),
709                vec![].into(),
710            )),
711        })
712        .into_ty()
713    }
714
715    pub fn mk_slice(ty: Ty) -> Ty {
716        TyKind::Adt(TypeDeclRef {
717            id: TypeId::Builtin(BuiltinTy::Slice),
718            generics: Box::new(GenericArgs::new_for_builtin(vec![ty].into())),
719        })
720        .into_ty()
721    }
722    /// Return true if it is actually unit (i.e.: 0-tuple)
723    pub fn is_unit(&self) -> bool {
724        match self.as_tuple() {
725            Some(tys) => tys.is_empty(),
726            None => false,
727        }
728    }
729
730    /// Return true if this is a scalar type
731    pub fn is_scalar(&self) -> bool {
732        match self.kind() {
733            TyKind::Literal(kind) => kind.is_int() || kind.is_uint(),
734            _ => false,
735        }
736    }
737
738    pub fn is_unsigned_scalar(&self) -> bool {
739        matches!(self.kind(), TyKind::Literal(LiteralTy::UInt(_)))
740    }
741
742    pub fn is_signed_scalar(&self) -> bool {
743        matches!(self.kind(), TyKind::Literal(LiteralTy::Int(_)))
744    }
745
746    pub fn is_str(&self) -> bool {
747        match self.kind() {
748            TyKind::Adt(ty_ref) if let TypeId::Builtin(BuiltinTy::Str) = ty_ref.id => true,
749            _ => false,
750        }
751    }
752
753    pub fn is_slice(&self) -> bool {
754        match self.kind() {
755            TyKind::Adt(ty_ref) if let TypeId::Builtin(BuiltinTy::Slice) = ty_ref.id => true,
756            _ => false,
757        }
758    }
759
760    /// Return true if the type is Box
761    pub fn is_box(&self) -> bool {
762        match self.kind() {
763            TyKind::Adt(ty_ref) if let TypeId::Builtin(BuiltinTy::Box) = ty_ref.id => true,
764            _ => false,
765        }
766    }
767
768    pub fn as_box(&self) -> Option<&Ty> {
769        match self.kind() {
770            TyKind::Adt(ty_ref) if let TypeId::Builtin(BuiltinTy::Box) = ty_ref.id => {
771                Some(&ty_ref.generics.types[0])
772            }
773            _ => None,
774        }
775    }
776
777    pub fn get_ptr_metadata(&self, translated: &TranslatedCrate) -> PtrMetadata {
778        let ref ty_decls = translated.type_decls;
779        match self.kind() {
780            TyKind::Adt(ty_ref) => {
781                // there are two cases:
782                // 1. if the declared type has a fixed metadata, just returns it
783                // 2. if it depends on some other types or the generic itself
784                match ty_ref.id {
785                    TypeId::Adt(type_decl_id) => {
786                        let Some(decl) = ty_decls.get(type_decl_id) else {
787                            return PtrMetadata::InheritFrom(self.clone());
788                        };
789                        match decl.ptr_metadata.clone().substitute(&ty_ref.generics) {
790                            // if it depends on some type, recursion with the binding env
791                            PtrMetadata::InheritFrom(ty) => ty.get_ptr_metadata(translated),
792                            // otherwise, simply return it
793                            meta => meta,
794                        }
795                    }
796                    // the metadata of a tuple is simply the last field
797                    TypeId::Tuple => {
798                        match ty_ref.generics.types.iter().last() {
799                            // `None` refers to the unit type `()`
800                            None => PtrMetadata::None,
801                            // Otherwise, simply recurse
802                            Some(ty) => ty.get_ptr_metadata(translated),
803                        }
804                    }
805                    // Box is a pointer like ref & raw ptr, hence no metadata
806                    TypeId::Builtin(BuiltinTy::Box) => PtrMetadata::None,
807                    // Array: `[T; N]` has no metadata
808                    TypeId::Builtin(BuiltinTy::Array) => PtrMetadata::None,
809                    // `[T]` & `str` all have metadata length
810                    TypeId::Builtin(BuiltinTy::Slice) => PtrMetadata::Length,
811                    TypeId::Builtin(BuiltinTy::Str) => PtrMetadata::Length,
812                }
813            }
814            TyKind::DynTrait(pred) => match pred.vtable_ref(translated) {
815                Some(vtable) => PtrMetadata::VTable(vtable),
816                None => PtrMetadata::InheritFrom(self.clone()),
817            },
818            TyKind::TraitType(..) | TyKind::TypeVar(_) => PtrMetadata::InheritFrom(self.clone()),
819            TyKind::Literal(_)
820            | TyKind::Never
821            | TyKind::Ref(..)
822            | TyKind::RawPtr(..)
823            | TyKind::FnPtr(..)
824            | TyKind::FnDef(..)
825            | TyKind::Error(_) => PtrMetadata::None,
826            // The metadata itself must be Sized, hence must with `PtrMetadata::None`
827            TyKind::PtrMetadata(_) => PtrMetadata::None,
828        }
829    }
830
831    pub fn as_array_or_slice(&self) -> Option<&Ty> {
832        match self.kind() {
833            TyKind::Adt(ty_ref)
834                if let TypeId::Builtin(BuiltinTy::Array | BuiltinTy::Slice) = ty_ref.id =>
835            {
836                Some(&ty_ref.generics.types[0])
837            }
838            _ => None,
839        }
840    }
841
842    pub fn as_tuple(&self) -> Option<&IndexMap<TypeVarId, Ty>> {
843        match self.kind() {
844            TyKind::Adt(ty_ref) if let TypeId::Tuple = ty_ref.id => Some(&ty_ref.generics.types),
845            _ => None,
846        }
847    }
848
849    pub fn as_adt(&self) -> Option<&TypeDeclRef> {
850        self.kind().as_adt()
851    }
852}
853
854impl TyKind {
855    pub fn into_ty(self) -> Ty {
856        Ty::new(self)
857    }
858}
859
860impl From<TyKind> for Ty {
861    fn from(kind: TyKind) -> Ty {
862        kind.into_ty()
863    }
864}
865
866/// Convenience for migration purposes.
867impl std::ops::Deref for Ty {
868    type Target = TyKind;
869
870    fn deref(&self) -> &Self::Target {
871        self.kind()
872    }
873}
874/// For deref patterns.
875unsafe impl std::ops::DerefPure for Ty {}
876
877impl TypeDeclRef {
878    pub fn new(id: TypeId, generics: GenericArgs) -> Self {
879        Self {
880            id,
881            generics: Box::new(generics),
882        }
883    }
884}
885
886impl TraitDeclRef {
887    pub fn self_ty<'a>(&'a self, krate: &'a TranslatedCrate) -> Option<&'a Ty> {
888        match self.generics.types.iter().next() {
889            Some(ty) => return Some(ty),
890            // TODO(mono): A monomorphized trait takes no arguments.
891            None => {
892                let name = krate.item_name(self.id)?;
893                let args = name.name.last()?.as_monomorphized()?;
894                args.types.iter().next()
895            }
896        }
897    }
898}
899
900impl TraitRef {
901    pub fn new(kind: TraitRefKind, trait_decl_ref: PolyTraitDeclRef) -> Self {
902        TraitRefContents {
903            kind,
904            trait_decl_ref,
905        }
906        .intern()
907    }
908
909    pub fn new_builtin(
910        trait_id: TraitDeclId,
911        ty: Ty,
912        parents: IndexMap<TraitClauseId, TraitRef>,
913        builtin_data: BuiltinImplData,
914    ) -> Self {
915        let trait_decl_ref = RegionBinder::empty(TraitDeclRef {
916            id: trait_id,
917            generics: Box::new(GenericArgs::new_types([ty].into())),
918        });
919        Self::new(
920            TraitRefKind::BuiltinOrAuto {
921                builtin_data,
922                parent_trait_refs: parents,
923                types: Default::default(),
924            },
925            trait_decl_ref,
926        )
927    }
928
929    /// Get mutable access to the contents. This cloned the value and will re-intern the modified
930    /// value at the end of the function.
931    pub fn with_contents_mut<R>(&mut self, f: impl FnOnce(&mut TraitRefContents) -> R) -> R {
932        self.0.with_inner_mut(f)
933    }
934}
935impl TraitRefContents {
936    pub fn intern(self) -> TraitRef {
937        TraitRef(HashConsed::new(self))
938    }
939}
940
941impl std::ops::Deref for TraitRef {
942    type Target = TraitRefContents;
943    fn deref(&self) -> &Self::Target {
944        &self.0
945    }
946}
947
948impl BuiltinImplData {
949    pub fn as_closure_kind(&self) -> Option<ClosureKind> {
950        match self {
951            BuiltinImplData::FnOnce => Some(ClosureKind::FnOnce),
952            BuiltinImplData::FnMut => Some(ClosureKind::FnMut),
953            BuiltinImplData::Fn => Some(ClosureKind::Fn),
954            _ => None,
955        }
956    }
957}
958
959impl PtrMetadata {
960    pub fn into_type(self) -> Ty {
961        match self {
962            PtrMetadata::None => Ty::mk_unit(),
963            PtrMetadata::Length => Ty::mk_usize(),
964            PtrMetadata::VTable(type_decl_ref) => Ty::new(TyKind::Ref(
965                Region::Static,
966                Ty::new(TyKind::Adt(type_decl_ref)),
967                RefKind::Shared,
968            )),
969            PtrMetadata::InheritFrom(ty) => Ty::new(TyKind::PtrMetadata(ty)),
970        }
971    }
972}
973
974impl Field {
975    /// The new name for this field, as suggested by the `#[charon::rename]` attribute.
976    pub fn renamed_name(&self) -> Option<&str> {
977        self.attr_info.rename.as_deref().or(self.name.as_deref())
978    }
979
980    /// Whether this field has a `#[charon::opaque]` annotation.
981    pub fn is_opaque(&self) -> bool {
982        self.attr_info
983            .attributes
984            .iter()
985            .any(|attr| attr.is_opaque())
986    }
987}
988
989impl Variant {
990    /// The new name for this variant, as suggested by the `#[charon::rename]` and
991    /// `#[charon::variants_prefix]` attributes.
992    pub fn renamed_name(&self) -> &str {
993        self.attr_info
994            .rename
995            .as_deref()
996            .unwrap_or(self.name.as_ref())
997    }
998
999    /// Whether this variant has a `#[charon::opaque]` annotation.
1000    pub fn is_opaque(&self) -> bool {
1001        self.attr_info
1002            .attributes
1003            .iter()
1004            .any(|attr| attr.is_opaque())
1005    }
1006}
1007
1008impl DynPredicate {
1009    /// Get a reference to the vtable type that corresponds to this predicate.
1010    pub fn vtable_ref(&self, translated: &TranslatedCrate) -> Option<TypeDeclRef> {
1011        // The first clause is the one relevant for the vtable.
1012        let relevant_tref = self.binder.params.trait_clauses[0].trait_.clone().erase();
1013
1014        // Get the vtable ref from the trait decl
1015        let trait_decl = translated.trait_decls.get(relevant_tref.id)?;
1016        let vtable_ref = trait_decl
1017            .vtable
1018            .clone()?
1019            .substitute(&relevant_tref.generics);
1020        Some(vtable_ref)
1021    }
1022}
1023
1024impl RefKind {
1025    pub fn mutable(x: bool) -> Self {
1026        if x { Self::Mut } else { Self::Shared }
1027    }
1028}
1029
1030/// Visitor for type-level variables. Used to visit the variables contained in a value, as seen
1031/// from the outside of the value. This means that any variable bound inside the value will be
1032/// skipped, and all the seen De Bruijn indices will count from the outside of the value. The
1033/// returned value, if any, will be put in place of the variable.
1034pub trait VarsVisitor {
1035    fn visit_region_var(&mut self, _v: RegionDbVar) -> Option<Region> {
1036        None
1037    }
1038    fn visit_type_var(&mut self, _v: TypeDbVar) -> Option<Ty> {
1039        None
1040    }
1041    fn visit_const_generic_var(&mut self, _v: ConstGenericDbVar) -> Option<ConstGeneric> {
1042        None
1043    }
1044    fn visit_clause_var(&mut self, _v: ClauseDbVar) -> Option<TraitRefKind> {
1045        None
1046    }
1047    fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
1048        None
1049    }
1050}
1051
1052/// Visitor for the [TyVisitable::substitute] function.
1053/// This substitutes variables bound at the level where we start to substitute (level 0).
1054#[derive(Visitor)]
1055pub(crate) struct SubstVisitor<'a> {
1056    generics: &'a GenericArgs,
1057    self_ref: &'a TraitRefKind,
1058    /// Whether to substitute explicit variables only (types, regions, const generics).
1059    explicits_only: bool,
1060    had_error: bool,
1061}
1062impl<'a> SubstVisitor<'a> {
1063    pub(crate) fn new(
1064        generics: &'a GenericArgs,
1065        self_ref: &'a TraitRefKind,
1066        explicits_only: bool,
1067    ) -> Self {
1068        Self {
1069            generics,
1070            self_ref,
1071            explicits_only,
1072            had_error: false,
1073        }
1074    }
1075
1076    pub fn visit<T: TyVisitable>(mut self, mut x: T) -> Result<T, GenericsMismatch> {
1077        let _ = x.visit_vars(&mut self);
1078        if self.had_error {
1079            Err(GenericsMismatch)
1080        } else {
1081            Ok(x)
1082        }
1083    }
1084
1085    /// Returns the value for this variable, if any.
1086    fn process_var<Id, T>(
1087        &mut self,
1088        var: DeBruijnVar<Id>,
1089        get: impl Fn(Id) -> Option<&'a T>,
1090    ) -> Option<T>
1091    where
1092        Id: Copy,
1093        T: Clone + TyVisitable,
1094        DeBruijnVar<Id>: Into<T>,
1095    {
1096        match var {
1097            DeBruijnVar::Bound(dbid, varid) => {
1098                Some(if let Some(dbid) = dbid.sub(DeBruijnId::one()) {
1099                    // This is bound outside the binder we're substituting for.
1100                    DeBruijnVar::Bound(dbid, varid).into()
1101                } else {
1102                    match get(varid) {
1103                        Some(v) => v.clone(),
1104                        None => {
1105                            self.had_error = true;
1106                            return None;
1107                        }
1108                    }
1109                })
1110            }
1111            DeBruijnVar::Free(..) => None,
1112        }
1113    }
1114}
1115impl VarsVisitor for SubstVisitor<'_> {
1116    fn visit_region_var(&mut self, v: RegionDbVar) -> Option<Region> {
1117        self.process_var(v, |id| self.generics.regions.get(id))
1118    }
1119    fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
1120        self.process_var(v, |id| self.generics.types.get(id))
1121    }
1122    fn visit_const_generic_var(&mut self, v: ConstGenericDbVar) -> Option<ConstGeneric> {
1123        self.process_var(v, |id| self.generics.const_generics.get(id))
1124    }
1125    fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
1126        if self.explicits_only {
1127            None
1128        } else {
1129            self.process_var(v, |id| Some(&self.generics.trait_refs.get(id)?.kind))
1130        }
1131    }
1132    fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
1133        Some(self.self_ref.clone())
1134    }
1135}
1136
1137#[derive(Debug)]
1138pub struct GenericsMismatch;
1139
1140/// Types that are involved at the type-level and may be substituted around.
1141pub trait TyVisitable: Sized + AstVisitable {
1142    /// Visit the variables contained in `self`, as seen from the outside of `self`. This means
1143    /// that any variable bound inside `self` will be skipped, and all the seen De Bruijn indices
1144    /// will count from the outside of `self`.
1145    fn visit_vars(&mut self, v: &mut impl VarsVisitor) {
1146        #[derive(Visitor)]
1147        struct Wrap<'v, V> {
1148            v: &'v mut V,
1149            depth: DeBruijnId,
1150        }
1151        impl<V: VarsVisitor> VisitAstMut for Wrap<'_, V> {
1152            fn enter_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
1153                self.depth = self.depth.incr()
1154            }
1155            fn exit_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
1156                self.depth = self.depth.decr()
1157            }
1158            fn enter_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
1159                self.depth = self.depth.incr()
1160            }
1161            fn exit_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
1162                self.depth = self.depth.decr()
1163            }
1164
1165            fn exit_region(&mut self, r: &mut Region) {
1166                if let Region::Var(var) = r
1167                    && let Some(var) = var.move_out_from_depth(self.depth)
1168                    && let Some(new_r) = self.v.visit_region_var(var)
1169                {
1170                    *r = new_r.move_under_binders(self.depth);
1171                }
1172            }
1173            fn exit_ty(&mut self, ty: &mut Ty) {
1174                if let TyKind::TypeVar(var) = ty.kind()
1175                    && let Some(var) = var.move_out_from_depth(self.depth)
1176                    && let Some(new_ty) = self.v.visit_type_var(var)
1177                {
1178                    *ty = new_ty.move_under_binders(self.depth);
1179                }
1180            }
1181            fn exit_const_generic(&mut self, cg: &mut ConstGeneric) {
1182                if let ConstGeneric::Var(var) = cg
1183                    && let Some(var) = var.move_out_from_depth(self.depth)
1184                    && let Some(new_cg) = self.v.visit_const_generic_var(var)
1185                {
1186                    *cg = new_cg.move_under_binders(self.depth);
1187                }
1188            }
1189            fn exit_constant_expr(&mut self, ce: &mut ConstantExpr) {
1190                if let ConstantExprKind::Var(var) = &mut ce.kind
1191                    && let Some(var) = var.move_out_from_depth(self.depth)
1192                    && let Some(new_cg) = self.v.visit_const_generic_var(var)
1193                {
1194                    ce.kind = new_cg.move_under_binders(self.depth).into();
1195                }
1196            }
1197            fn exit_trait_ref_kind(&mut self, kind: &mut TraitRefKind) {
1198                match kind {
1199                    TraitRefKind::SelfId => {
1200                        if let Some(new_kind) = self.v.visit_self_clause() {
1201                            *kind = new_kind.move_under_binders(self.depth);
1202                        }
1203                    }
1204                    TraitRefKind::Clause(var) => {
1205                        if let Some(var) = var.move_out_from_depth(self.depth)
1206                            && let Some(new_kind) = self.v.visit_clause_var(var)
1207                        {
1208                            *kind = new_kind.move_under_binders(self.depth);
1209                        }
1210                    }
1211                    _ => {}
1212                }
1213            }
1214        }
1215        let _ = self.drive_mut(&mut Wrap {
1216            v,
1217            depth: DeBruijnId::zero(),
1218        });
1219    }
1220
1221    /// Substitute the generic variables inside `self` by replacing them with the provided values.
1222    /// Note: if `self` is an item that comes from a `TraitDecl`, you most likely want to use
1223    /// `substitute_with_self`.
1224    fn substitute(self, generics: &GenericArgs) -> Self {
1225        self.substitute_with_self(generics, &TraitRefKind::SelfId)
1226    }
1227    /// Substitute only the type, region and const generic args.
1228    fn substitute_explicits(self, generics: &GenericArgs) -> Self {
1229        SubstVisitor::new(generics, &TraitRefKind::SelfId, true)
1230            .visit(self)
1231            .unwrap()
1232    }
1233    /// Substitute the generic variables as well as the `TraitRefKind::Self` trait ref.
1234    fn substitute_with_self(self, generics: &GenericArgs, self_ref: &TraitRefKind) -> Self {
1235        self.try_substitute_with_self(generics, self_ref).unwrap()
1236    }
1237
1238    fn try_substitute(self, generics: &GenericArgs) -> Result<Self, GenericsMismatch> {
1239        self.try_substitute_with_self(generics, &TraitRefKind::SelfId)
1240    }
1241    fn try_substitute_with_self(
1242        self,
1243        generics: &GenericArgs,
1244        self_ref: &TraitRefKind,
1245    ) -> Result<Self, GenericsMismatch> {
1246        SubstVisitor::new(generics, self_ref, false).visit(self)
1247    }
1248
1249    /// Move under one binder.
1250    fn move_under_binder(self) -> Self {
1251        self.move_under_binders(DeBruijnId::one())
1252    }
1253
1254    /// Move under `depth` binders.
1255    fn move_under_binders(mut self, depth: DeBruijnId) -> Self {
1256        if !depth.is_zero() {
1257            let Continue(()) = self.visit_db_id::<Infallible>(|id| {
1258                *id = id.plus(depth);
1259                Continue(())
1260            });
1261        }
1262        self
1263    }
1264
1265    /// Move from under one binder.
1266    fn move_from_under_binder(self) -> Option<Self> {
1267        self.move_from_under_binders(DeBruijnId::one())
1268    }
1269
1270    /// Move the value out of `depth` binders. Returns `None` if it contains a variable bound in
1271    /// one of these `depth` binders.
1272    fn move_from_under_binders(mut self, depth: DeBruijnId) -> Option<Self> {
1273        self.visit_db_id::<()>(|id| match id.sub(depth) {
1274            Some(sub) => {
1275                *id = sub;
1276                Continue(())
1277            }
1278            None => Break(()),
1279        })
1280        .is_continue()
1281        .then_some(self)
1282    }
1283
1284    /// Visit the de Bruijn ids contained in `self`, as seen from the outside of `self`. This means
1285    /// that any variable bound inside `self` will be skipped, and all the seen indices will count
1286    /// from the outside of self.
1287    fn visit_db_id<B>(
1288        &mut self,
1289        f: impl FnMut(&mut DeBruijnId) -> ControlFlow<B>,
1290    ) -> ControlFlow<B> {
1291        struct Wrap<F> {
1292            f: F,
1293            depth: DeBruijnId,
1294        }
1295        impl<B, F> Visitor for Wrap<F>
1296        where
1297            F: FnMut(&mut DeBruijnId) -> ControlFlow<B>,
1298        {
1299            type Break = B;
1300        }
1301        impl<B, F> VisitAstMut for Wrap<F>
1302        where
1303            F: FnMut(&mut DeBruijnId) -> ControlFlow<B>,
1304        {
1305            fn enter_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
1306                self.depth = self.depth.incr()
1307            }
1308            fn exit_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
1309                self.depth = self.depth.decr()
1310            }
1311            fn enter_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
1312                self.depth = self.depth.incr()
1313            }
1314            fn exit_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
1315                self.depth = self.depth.decr()
1316            }
1317
1318            fn visit_de_bruijn_id(&mut self, x: &mut DeBruijnId) -> ControlFlow<Self::Break> {
1319                if let Some(mut shifted) = x.sub(self.depth) {
1320                    (self.f)(&mut shifted)?;
1321                    *x = shifted.plus(self.depth)
1322                }
1323                Continue(())
1324            }
1325        }
1326        self.drive_mut(&mut Wrap {
1327            f,
1328            depth: DeBruijnId::zero(),
1329        })
1330    }
1331}
1332
1333/// A value of type `T` applied to some `GenericArgs`, except we havent applied them yet to avoid a
1334/// deep clone.
1335#[derive(Debug, Clone, Copy)]
1336pub struct Substituted<'a, T> {
1337    pub val: &'a T,
1338    pub generics: &'a GenericArgs,
1339}
1340
1341impl<'a, T> Substituted<'a, T> {
1342    pub fn new(val: &'a T, generics: &'a GenericArgs) -> Self {
1343        Self { val, generics }
1344    }
1345
1346    pub fn rebind<U>(&self, val: &'a U) -> Substituted<'a, U> {
1347        Substituted::new(val, self.generics)
1348    }
1349
1350    pub fn substitute(&self) -> T
1351    where
1352        T: TyVisitable + Clone,
1353    {
1354        self.val.clone().substitute(self.generics)
1355    }
1356    pub fn try_substitute(&self) -> Result<T, GenericsMismatch>
1357    where
1358        T: TyVisitable + Clone,
1359    {
1360        self.val.clone().try_substitute(self.generics)
1361    }
1362
1363    pub fn iter<Item: 'a>(&self) -> impl Iterator<Item = Substituted<'a, Item>>
1364    where
1365        &'a T: IntoIterator<Item = &'a Item>,
1366    {
1367        self.val.into_iter().map(move |x| self.rebind(x))
1368    }
1369}
1370
1371impl TypeDecl {
1372    /// Looks up the variant corresponding to the tag (i.e. the in-memory bytes that represent the discriminant).
1373    /// Returns `None` for types that don't have a relevant discriminant (e.g. uninhabited types).
1374    ///
1375    /// If the `tag` does not correspond to any valid discriminant but there is a niche,
1376    /// the resulting `VariantId` will be for the untagged variant [`TagEncoding::Niche::untagged_variant`].
1377    pub fn get_variant_from_tag(&self, tag: ScalarValue) -> Option<VariantId> {
1378        let layout = self.layout.as_ref()?;
1379        if layout.uninhabited {
1380            return None;
1381        };
1382        let discr_layout = layout.discriminant_layout.as_ref()?;
1383
1384        let variant_for_tag =
1385            layout
1386                .variant_layouts
1387                .iter_enumerated()
1388                .find_map(|(id, variant_layout)| {
1389                    if variant_layout.tag == Some(tag) {
1390                        Some(id)
1391                    } else {
1392                        None
1393                    }
1394                });
1395
1396        match &discr_layout.encoding {
1397            TagEncoding::Direct => {
1398                assert_eq!(tag.get_integer_ty(), discr_layout.tag_ty);
1399                variant_for_tag
1400            }
1401            TagEncoding::Niche { untagged_variant } => variant_for_tag.or(Some(*untagged_variant)),
1402        }
1403    }
1404
1405    pub fn is_c_repr(&self) -> bool {
1406        self.repr
1407            .as_ref()
1408            .is_some_and(|repr| repr.repr_algo == ReprAlgorithm::C)
1409    }
1410
1411    pub fn get_field_by_name(
1412        &self,
1413        variant: Option<VariantId>,
1414        field_name: &str,
1415    ) -> Option<(FieldId, &Field)> {
1416        let fields = match &self.kind {
1417            TypeDeclKind::Struct(fields) | TypeDeclKind::Union(fields) => fields,
1418            TypeDeclKind::Enum(variants) => &variants[variant.unwrap()].fields,
1419            _ => return None,
1420        };
1421        fields
1422            .iter_indexed()
1423            .find(|(_, field)| field.name.as_deref() == Some(field_name))
1424    }
1425}
1426
1427impl Layout {
1428    pub fn is_variant_uninhabited(&self, variant_id: VariantId) -> bool {
1429        if let Some(v) = self.variant_layouts.get(variant_id) {
1430            v.uninhabited
1431        } else {
1432            false
1433        }
1434    }
1435}
1436
1437impl ReprOptions {
1438    /// Whether this representation options guarantee a fixed
1439    /// field ordering for the type.
1440    ///
1441    /// Since we don't support `repr(simd)` or `repr(linear)` yet, this is
1442    /// the case if it's either `repr(C)` or an explicit discriminant type for
1443    /// an enum with fields (if it doesn't have fields, this obviously doesn't matter anyway).
1444    ///
1445    /// Cf. <https://doc.rust-lang.org/reference/type-layout.html#r-layout.repr.c.struct>
1446    /// and <https://doc.rust-lang.org/reference/type-layout.html#r-layout.repr.primitive.adt>.
1447    pub fn guarantees_fixed_field_order(&self) -> bool {
1448        self.repr_algo == ReprAlgorithm::C || self.explicit_discr_type
1449    }
1450}
1451
1452impl<T: AstVisitable> TyVisitable for T {}
1453
1454impl Eq for TraitParam {}
1455
1456mk_index_impls!(GenericArgs.regions[RegionId]: Region);
1457mk_index_impls!(GenericArgs.types[TypeVarId]: Ty);
1458mk_index_impls!(GenericArgs.const_generics[ConstGenericVarId]: ConstGeneric);
1459mk_index_impls!(GenericArgs.trait_refs[TraitClauseId]: TraitRef);
1460mk_index_impls!(GenericParams.regions[RegionId]: RegionParam);
1461mk_index_impls!(GenericParams.types[TypeVarId]: TypeParam);
1462mk_index_impls!(GenericParams.const_generics[ConstGenericVarId]: ConstGenericParam);
1463mk_index_impls!(GenericParams.trait_clauses[TraitClauseId]: TraitParam);