Skip to main content

charon_lib/ast/
gast.rs

1//! Definitions common to [crate::ullbc_ast] and [crate::llbc_ast]
2use crate::ast::*;
3use crate::common::serialize_map_to_array::SeqHashMapToArray;
4use crate::ids::IndexVec;
5use crate::llbc_ast;
6use crate::ullbc_ast;
7use derive_generic_visitor::{Drive, DriveMut};
8use macros::EnumAsGetters;
9use macros::{EnumIsA, EnumToGetters};
10use serde_state::DeserializeState;
11use serde_state::SerializeState;
12
13/// A variable
14#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
15pub struct Local {
16    /// Unique index identifying the variable
17    pub index: LocalId,
18    /// Variable name - may be `None` if the variable was introduced by Rust
19    /// through desugaring.
20    #[drive(skip)]
21    pub name: Option<String>,
22    /// Span of the variable declaration.
23    pub span: Span,
24    /// The variable type
25    #[cfg_attr(feature = "charon_on_charon", charon::rename("local_ty"))]
26    pub ty: Ty,
27}
28#[deprecated(note = "use `Local` intead")]
29pub type Var = Local;
30#[deprecated(note = "use `LocalId` intead")]
31pub type VarId = LocalId;
32
33/// The local variables of a body.
34#[derive(
35    Debug, PartialEq, Eq, Default, Clone, SerializeState, DeserializeState, Drive, DriveMut,
36)]
37pub struct Locals {
38    /// The number of local variables used for the input arguments.
39    #[drive(skip)]
40    pub arg_count: usize,
41    /// The local variables.
42    /// We always have, in the following order:
43    /// - the local used for the return value (index 0)
44    /// - the `arg_count` input arguments
45    /// - the remaining locals, used for the intermediate computations
46    pub locals: IndexVec<LocalId, Local>,
47}
48
49/// An expression body.
50/// TODO: arg_count should be stored in GFunDecl below. But then,
51///       the print is obfuscated and Aeneas may need some refactoring.
52#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
53#[cfg_attr(feature = "charon_on_charon", charon::rename("GexprBody"))]
54pub struct GExprBody<T> {
55    pub span: Span,
56    /// The number of regions existentially bound in this body. We introduce fresh such regions
57    /// during translation instead of the erased regions that rustc gives us.
58    #[drive(skip)]
59    pub bound_body_regions: usize,
60    /// The local variables.
61    pub locals: Locals,
62    /// The statements and blocks that compose this body.
63    pub body: T,
64    /// For each line inside the body, we record any whole-line `//` comments found before it. They
65    /// are added to statements in the late `recover_body_comments` pass.
66    #[cfg_attr(feature = "charon_on_charon", charon::opaque)]
67    #[drive(skip)]
68    pub comments: Vec<(usize, Vec<String>)>,
69}
70
71/// The body of a function.
72#[derive(
73    Debug,
74    PartialEq,
75    Eq,
76    Clone,
77    SerializeState,
78    DeserializeState,
79    Drive,
80    DriveMut,
81    EnumIsA,
82    EnumAsGetters,
83    EnumToGetters,
84)]
85#[serde_state(state_implements = HashConsSerializerState)]
86#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Body"))]
87pub enum Body {
88    /// Body represented as a CFG. This is what ullbc is made of, and what we get after translating MIR.
89    Unstructured(ullbc_ast::ExprBody),
90    /// Body represented with structured control flow. This is what llbc is made of. We restructure
91    /// the control flow in the `ullbc_to_llbc` pass.
92    Structured(llbc_ast::ExprBody),
93    /// A façade body that dispatches to one of several per-target function bodies. Created during
94    /// multi-target merging for functions with the same signature but different bodies across
95    /// targets.
96    TargetDispatch(
97        #[serde(with = "SeqHashMapToArray::<TargetTriple, FunDeclRef>")]
98        SeqHashMap<TargetTriple, FunDeclRef>,
99    ),
100    /// The body of the function item we add for each trait method declaration, if the trait
101    /// doesn't provide a default for that method.
102    TraitMethodWithoutDefault,
103    /// Function declared in an `extern { ... }` block. The string is the foreign symbol name.
104    Extern(#[drive(skip)] String),
105    /// Rust intrinsic function.
106    Intrinsic {
107        /// The intrinsic name.
108        #[drive(skip)]
109        name: String,
110        /// The argument names, None if not available.
111        #[drive(skip)]
112        arg_names: Vec<Option<String>>,
113    },
114    /// A body that the user chose not to translate, based on opacity settings like
115    /// `--include`/`--opaque`.
116    Opaque,
117    /// A body that was not available. Typically that's function bodies for non-generic and
118    /// non-inlineable std functions, as these are not present in the compiled standard library
119    /// `.rmeta` file shipped with a rust toolchain.
120    Missing,
121    /// We encountered an error while translating this body.
122    #[drive(skip)]
123    #[serde_state(stateless)]
124    Error(Error),
125}
126
127/// Item kind: whether this function/const is part of a trait declaration, trait implementation, or
128/// neither.
129///
130/// Example:
131/// ```text
132/// trait Foo {
133///     fn bar(x : u32) -> u32; // trait item decl without default
134///
135///     fn baz(x : bool) -> bool { x } // trait item decl with default
136/// }
137///
138/// impl Foo for ... {
139///     fn bar(x : u32) -> u32 { x } // trait item implementation
140/// }
141///
142/// fn test(...) { ... } // regular
143///
144/// impl Type {
145///     fn test(...) { ... } // regular
146/// }
147/// ```
148#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut, PartialEq, Eq)]
149#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Item"))]
150pub enum ItemSource {
151    /// This item stands on its own.
152    TopLevel,
153    /// This is a closure in a function body.
154    Closure {
155        info: ClosureInfo,
156    },
157    /// This is an associated item in a trait declaration. It has a body if and only if the trait
158    /// provided a default implementation.
159    TraitDecl {
160        /// The trait declaration this item belongs to.
161        trait_ref: TraitDeclRef,
162        /// The associated item this corresponds to. Note that a function could have
163        /// `AssocItemId::Const` if it's the initializer of a trait const.
164        // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
165        item_id: AssocItemId,
166        /// Whether the trait declaration provides a default implementation.
167        #[drive(skip)]
168        has_default: bool,
169    },
170    /// This is an associated item in a trait implementation.
171    TraitImpl {
172        /// The trait implementation the method belongs to.
173        impl_ref: TraitImplRef,
174        /// The trait declaration that the impl block implements.
175        trait_ref: TraitDeclRef,
176        /// The associated item this corresponds to. Note that a function could have
177        /// `AssocItemId::Const` if it's the initializer of a trait const.
178        // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
179        item_id: AssocItemId,
180        /// True if the trait decl had a default implementation for this function/const and this
181        /// item is a copy of the default item.
182        #[drive(skip)]
183        reuses_default: bool,
184    },
185    /// This function is a target-specific variant behind a `TargetDispatch` façade. The dispatcher
186    /// is the function with the `Body::TargetDispatch` body that dispatches to this function.
187    TargetDependent {
188        dispatcher: FunDeclRef,
189    },
190    /// This is a vtable struct for a trait.
191    VTableTy {
192        /// The `dyn Trait` predicate implemented by this vtable.
193        dyn_predicate: DynPredicate,
194        /// Record what each vtable field means.
195        field_map: IndexVec<FieldId, VTableField>,
196        /// For each implied clause that is also a supertrait clause, reords which field id
197        /// corresponds to it.
198        supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
199    },
200    /// This is a vtable value for an impl.
201    VTableInstance {
202        impl_ref: TraitImplRef,
203    },
204    /// The method shim wraps a concrete implementation of a method into a function that takes `dyn
205    /// Trait` as its `Self` type. This shim casts the receiver to the known concrete type and
206    /// calls the real method.
207    VTableMethodShim,
208    VTableInstanceMono,
209}
210
211#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut, PartialEq, Eq)]
212#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("VTable"))]
213pub enum VTableField {
214    Size,
215    Align,
216    Drop,
217    Method(TraitMethodId),
218    SuperTrait(TraitClauseId),
219}
220
221/// A function definition
222#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
223pub struct FunDecl {
224    pub def_id: FunDeclId,
225    /// The meta data associated with the declaration.
226    pub item_meta: ItemMeta,
227    pub generics: GenericParams,
228    /// The signature contains the inputs/output types and ABI details.
229    pub signature: Box<FunSig>,
230    /// The function kind: "regular" function, trait method declaration, etc.
231    pub src: ItemSource,
232    /// Whether this function is in fact the body of a constant/static that we turned into an
233    /// initializer function.
234    pub is_global_initializer: Option<GlobalDeclId>,
235    /// The function body.
236    pub body: Body,
237}
238
239/// Reference to a function declaration.
240#[derive(Debug, Clone, SerializeState, DeserializeState, PartialEq, Eq, Hash, Drive, DriveMut)]
241pub struct FunDeclRef {
242    pub id: FunDeclId,
243    /// Generic arguments passed to the function.
244    pub generics: BoxedArgs,
245}
246
247#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
248pub enum GlobalKind {
249    /// A static.
250    Static,
251    /// A thread-local static.
252    ThreadLocal,
253    /// A const with a name (either top-level or an associated const in a trait).
254    NamedConst,
255    /// A const without a name:
256    /// - An inline const expression (`const { 1 + 1 }`);
257    /// - A const expression in a type (`[u8; sizeof::<T>()]`);
258    /// - A promoted constant, automatically lifted from a body (`&0`).
259    AnonConst,
260}
261
262/// A global variable definition (constant or static).
263#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
264pub struct GlobalDecl {
265    pub def_id: GlobalDeclId,
266    /// The meta data associated with the declaration.
267    pub item_meta: ItemMeta,
268    pub generics: GenericParams,
269    pub ty: Ty,
270    /// The context of the global: distinguishes top-level items from trait-associated items.
271    pub src: ItemSource,
272    /// The kind of global (static or const).
273    #[drive(skip)]
274    pub global_kind: GlobalKind,
275    /// The value of this constant/static. By default this is a [`ConstantExprKind::Call`] to the
276    /// initializer function that computes the value (the function uses the same generic parameters
277    /// as the global).
278    pub value: ConstantExpr,
279}
280
281/// Reference to a global declaration.
282#[derive(Debug, Clone, SerializeState, DeserializeState, PartialEq, Eq, Hash, Drive, DriveMut)]
283pub struct GlobalDeclRef {
284    pub id: GlobalDeclId,
285    pub generics: BoxedArgs,
286}
287
288#[derive(
289    Debug,
290    Clone,
291    Copy,
292    SerializeState,
293    DeserializeState,
294    Drive,
295    DriveMut,
296    PartialEq,
297    Eq,
298    Hash,
299    PartialOrd,
300    Ord,
301)]
302#[drive(skip)]
303#[serde_state(stateless)]
304pub struct TraitItemName(pub ustr::Ustr);
305
306generate_index_type!(TraitMethodId, "TraitMethod");
307generate_index_type!(AssocTypeId, "AssocType");
308generate_index_type!(AssocConstId, "AssocConst");
309
310/// A trait **declaration**.
311///
312/// For instance:
313/// ```text
314/// trait Foo {
315///   type Bar;
316///
317///   fn baz(...); // required method (see below)
318///
319///   fn test() -> bool { true } // provided method (see below)
320/// }
321/// ```
322///
323/// In case of a trait declaration, we don't include the provided methods (the methods
324/// with a default implementation): they will be translated on a per-need basis. This is
325/// important for two reasons:
326/// - this makes the trait definitions a lot smaller (the Iterator trait
327///   has *one* declared function and more than 70 provided functions)
328/// - this is important for the external traits, whose provided methods
329///   often use features we don't support yet
330///
331/// Remark:
332/// In Aeneas, we still translate the provided methods on an individual basis,
333/// and in such a way thay they take as input a trait instance. This means that
334/// we can use default methods *but*:
335/// - implementations of required methods shoudln't call default methods
336/// - trait implementations shouldn't redefine required methods
337///
338/// The use case we have in mind is [std::iter::Iterator]: it declares one required
339/// method (`next`) that should be implemented for every iterator, and defines many
340/// helpers like `all`, `map`, etc. that shouldn't be re-implemented.
341/// Of course, this forbids other useful use cases such as visitors implemented
342/// by means of traits.
343#[allow(clippy::type_complexity)]
344#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
345pub struct TraitDecl {
346    pub def_id: TraitDeclId,
347    pub item_meta: ItemMeta,
348    pub generics: GenericParams,
349    /// The "parent" clauses: the supertraits.
350    ///
351    /// Supertraits are actually regular where clauses, but we decided to have
352    /// a custom treatment.
353    /// ```text
354    /// trait Foo : Bar {
355    ///             ^^^
356    ///         supertrait, that we treat as a parent predicate
357    /// }
358    /// ```
359    /// TODO: actually, as of today, we consider that all trait clauses of
360    /// trait declarations are parent clauses.
361    pub implied_clauses: IndexVec<TraitClauseId, TraitParam>,
362    /// The associated constants declared in the trait.
363    pub consts: IndexMap<AssocConstId, TraitAssocConst>,
364    /// The associated types declared in the trait. The binder binds the generic parameters of the
365    /// type if it is a GAT (Generic Associated Type). For a plain associated type the binder binds
366    /// nothing.
367    pub types: IndexMap<AssocTypeId, Binder<TraitAssocTy>>,
368    /// The methods declared by the trait. The binder binds the generic parameters of the method.
369    ///
370    /// ```rust
371    /// trait Trait<T> {
372    ///   // The `Binder` for this method binds `'a` and `U`.
373    ///   fn method<'a, U>(x: &'a U);
374    /// }
375    /// ```
376    pub methods: IndexMap<TraitMethodId, Binder<TraitMethod>>,
377    /// The virtual table struct for this trait, if it has one.
378    /// It is guaranteed that the trait has a vtable iff it is dyn-compatible.
379    pub vtable: Option<TypeDeclRef>,
380}
381
382/// An associated constant in a trait.
383#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
384pub struct TraitAssocConst {
385    pub name: TraitItemName,
386    #[drive(skip)]
387    #[serde_state(stateless)]
388    pub attr_info: AttrInfo,
389    pub ty: Ty,
390    pub default: Option<GlobalDeclRef>,
391}
392
393/// An associated type in a trait.
394#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
395pub struct TraitAssocTy {
396    pub name: TraitItemName,
397    #[drive(skip)]
398    #[serde_state(stateless)]
399    pub attr_info: AttrInfo,
400    pub default: Option<TraitAssocTyImpl>,
401    /// List of trait clauses that apply to this type.
402    pub implied_clauses: IndexVec<TraitClauseId, TraitParam>,
403}
404
405/// A trait method.
406#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
407pub struct TraitMethod {
408    pub name: TraitItemName,
409    #[drive(skip)]
410    #[serde_state(stateless)]
411    pub attr_info: AttrInfo,
412    pub signature: FunSig,
413    /// Each method declaration is represented by a function item. That function contains the
414    /// signature of the method as well as information like attributes. It has a body iff the
415    /// method declaration has a default implementation; otherwise it has an `Opaque` body.
416    pub item: FunDeclRef,
417}
418
419/// A trait **implementation**.
420///
421/// For instance:
422/// ```text
423/// impl Foo for List {
424///   type Bar = ...
425///
426///   fn baz(...) { ... }
427/// }
428/// ```
429#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
430pub struct TraitImpl {
431    pub def_id: TraitImplId,
432    pub item_meta: ItemMeta,
433    /// The information about the implemented trait.
434    /// Note that this contains the instantiation of the "parent"
435    /// clauses.
436    pub impl_trait: TraitDeclRef,
437    pub generics: GenericParams,
438    /// The trait references for the parent clauses (see [TraitDecl]).
439    pub implied_trait_refs: IndexVec<TraitClauseId, TraitRef>,
440    /// The implemented associated constants.
441    pub consts: IndexMap<AssocConstId, GlobalDeclRef>,
442    /// The implemented associated types.
443    pub types: IndexMap<AssocTypeId, Binder<TraitAssocTyImpl>>,
444    /// The implemented methods
445    pub methods: IndexMap<TraitMethodId, Binder<FunDeclRef>>,
446    /// The virtual table instance for this trait implementation. This is `Some` iff the trait is
447    /// dyn-compatible.
448    pub vtable: Option<GlobalDeclRef>,
449}
450
451/// The value of a trait associated type.
452#[derive(Debug, Clone, PartialEq, Eq, Hash, SerializeState, DeserializeState, Drive, DriveMut)]
453pub struct TraitAssocTyImpl {
454    pub value: Ty,
455    /// This matches the corresponding vector in `TraitAssocTy`. In the same way, this is empty
456    /// after the `lift_associated_item_clauses` pass.
457    pub implied_trait_refs: IndexVec<TraitClauseId, TraitRef>,
458}
459
460/// A function operand is used in function calls.
461/// It either designates a top-level function, or a place in case
462/// we are using function pointers stored in local variables.
463#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
464#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("FnOp"))]
465pub enum FnOperand {
466    /// Regular case: call to a top-level function, trait method, etc.
467    Regular(FnPtr),
468    /// Use of a function pointer.
469    Dynamic(Operand),
470}
471
472#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
473pub struct Call {
474    pub func: FnOperand,
475    pub args: Vec<Operand>,
476    pub dest: Place,
477}
478
479#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
480pub struct CopyNonOverlapping {
481    pub src: Operand,
482    pub dst: Operand,
483    pub count: Operand,
484}
485
486/// The kind of a built-in assertion, which may panic and unwind. These are removed
487/// by `reconstruct_fallible_operations` because they're implicit in the semantics of (U)LLBC.
488/// This kind should only be used for error-reporting purposes, as the check itself
489/// is performed in the instructions preceding the assert.
490#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
491pub enum BuiltinAssertKind {
492    BoundsCheck { len: Operand, index: Operand },
493    Overflow(BinOp, Operand, Operand),
494    OverflowNeg(Operand),
495    DivisionByZero(Operand),
496    RemainderByZero(Operand),
497    MisalignedPointerDereference { required: Operand, found: Operand },
498    NullPointerDereference,
499    InvalidEnumConstruction(Operand),
500    ResumedAfterReturn,
501    ResumedAfterPanic,
502    ResumedAfterDrop,
503}
504
505/// (U)LLBC is a language with side-effects: a statement may abort in a way that isn't tracked by
506/// control-flow. The three kinds of abort are:
507/// - Panic
508/// - Undefined behavior (caused by an "assume")
509/// - Unwind termination
510#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
511pub enum AbortKind {
512    /// A built-in panicking function, or a panic due to a failed built-in check (e.g. for out-of-bounds accesses).
513    Panic(Option<Name>),
514    /// Undefined behavior in the rust abstract machine.
515    UndefinedBehavior,
516    /// Unwind had to stop for ABI reasons or because cleanup code panicked again.
517    UnwindTerminate,
518}
519
520/// A `Drop` statement/terminator can mean two things, depending on what MIR phase we retrieved
521/// from rustc: it could be a real drop, or it could be a "conditional drop", which is where drop
522/// may happen depending on whether the borrow-checker determines a drop is needed.
523#[derive(Debug, PartialEq, Eq, Clone, Copy, SerializeState, DeserializeState, Drive, DriveMut)]
524pub enum DropKind {
525    /// A real drop. This calls `<T as Destruct>::drop_glue(&mut place)` and marks the
526    /// place as moved-out-of. Use `--desugar-drops` to transform all such drops to an actual
527    /// function call.
528    ///
529    /// The `drop_glue` method is added by Charon to the `Destruct` trait to make it possible
530    /// to track drop code in polymorphic code. It contains the same code as the
531    /// `core::ptr::drop_glue<T>` builtin would.
532    ///
533    /// Drop are precise in MIR `elaborated` and `optimized`.
534    Precise,
535    /// A conditional drop, which may or may not end up running drop code depending on the code
536    /// path that led to it. A conditional drop may also become a partial drop (dropping only the
537    /// subplaces that haven't been moved out of), may be conditional on the code path that led to
538    /// it, or become an async drop. The exact semantics are left intentionally unspecified by
539    /// rustc developers. To elaborate such drops into precise drops, pass `--precise-drops` to
540    /// Charon.
541    ///
542    /// A conditional drop may also be passed an unaligned place when dropping fields of packed
543    /// structs. Such a thing is UB for a precise drop.
544    ///
545    /// Drop are conditional in MIR `built` and `promoted`.
546    Conditional,
547}
548
549/// Check the value of an operand and abort if the value is not expected. This is introduced to
550/// avoid a lot of small branches.
551///
552/// We translate MIR asserts (introduced for out-of-bounds accesses or divisions by zero for
553/// instance) to this. We then eliminate them in [crate::transform::resugar::reconstruct_fallible_operations],
554/// because they're implicit in the semantics of our array accesses etc. Finally we introduce new asserts in
555/// [crate::transform::resugar::reconstruct_asserts].
556#[derive(Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
557#[cfg_attr(feature = "charon_on_charon", charon::rename("Assertion"))]
558pub struct Assert {
559    pub cond: Operand,
560    /// The value that the operand should evaluate to for the assert to succeed.
561    #[drive(skip)]
562    pub expected: bool,
563    /// The kind of check performed by this assert. This is only used for error reporting, as the check
564    /// is actually performed by the instructions preceding the assert.
565    pub check_kind: Option<BuiltinAssertKind>,
566}
567
568/// A generic `*DeclRef`-shaped struct, used when we're generic over the type of item.
569#[derive(Debug, PartialEq, Eq, Clone, Drive, DriveMut)]
570pub struct DeclRef<Id> {
571    pub id: Id,
572    pub generics: BoxedArgs,
573    /// If the item is a trait associated item, `generics` are only those of the item, and this
574    /// contains a reference to the trait.
575    pub trait_ref: Option<TraitRef>,
576}
577
578impl DeclRef<ItemId> {
579    pub fn try_convert_id<Id>(self) -> Result<DeclRef<Id>, <ItemId as TryInto<Id>>::Error>
580    where
581        ItemId: TryInto<Id>,
582    {
583        Ok(DeclRef {
584            id: self.id.try_into()?,
585            generics: self.generics,
586            trait_ref: self.trait_ref,
587        })
588    }
589}
590
591// Implement `DeclRef<_>` -> `FooDeclRef` conversions.
592macro_rules! convert_item_ref {
593    ($item_ref_ty:ident($id:ident)) => {
594        impl TryFrom<DeclRef<ItemId>> for $item_ref_ty {
595            type Error = ();
596            fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
597                assert!(item.trait_ref.is_none());
598                Ok($item_ref_ty {
599                    id: item.id.try_into()?,
600                    generics: item.generics,
601                })
602            }
603        }
604        impl From<DeclRef<$id>> for $item_ref_ty {
605            fn from(item: DeclRef<$id>) -> Self {
606                assert!(item.trait_ref.is_none());
607                $item_ref_ty {
608                    id: item.id,
609                    generics: item.generics,
610                }
611            }
612        }
613    };
614}
615convert_item_ref!(TypeDeclRef(TypeId));
616convert_item_ref!(FunDeclRef(FunDeclId));
617convert_item_ref!(GlobalDeclRef(GlobalDeclId));
618convert_item_ref!(TraitDeclRef(TraitDeclId));
619convert_item_ref!(TraitImplRef(TraitImplId));
620impl TryFrom<DeclRef<ItemId>> for FnPtr {
621    type Error = ();
622    fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
623        let id: FunId = item.id.try_into()?;
624        Ok(FnPtr::new(id.into(), item.generics))
625    }
626}
627
628impl TryFrom<DeclRef<ItemId>> for MaybeBuiltinFunDeclRef {
629    type Error = ();
630    fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
631        Ok(item.try_convert_id::<FunId>()?.into())
632    }
633}
634impl From<DeclRef<FunId>> for MaybeBuiltinFunDeclRef {
635    fn from(item: DeclRef<FunId>) -> Self {
636        MaybeBuiltinFunDeclRef {
637            id: item.id,
638            generics: item.generics,
639            trait_ref: item.trait_ref,
640        }
641    }
642}