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