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