cairo_lang_sierra/extensions/modules/
array.rs

1use super::boxing::box_ty;
2use super::range_check::RangeCheckType;
3use super::snapshot::snapshot_ty;
4use super::structure::StructConcreteType;
5use crate::define_libfunc_hierarchy;
6use crate::extensions::lib_func::{
7    BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
8    SierraApChange, SignatureAndTypeGenericLibfunc, SignatureOnlyGenericLibfunc,
9    SignatureSpecializationContext, SpecializationContext, WrapSignatureAndTypeGenericLibfunc,
10};
11use crate::extensions::type_specialization_context::TypeSpecializationContext;
12use crate::extensions::types::{
13    GenericTypeArgGenericType, GenericTypeArgGenericTypeWrapper, TypeInfo,
14};
15use crate::extensions::{
16    NamedLibfunc, NamedType, OutputVarReferenceInfo, SignatureBasedConcreteLibfunc,
17    SpecializationError, args_as_single_type,
18};
19use crate::ids::{ConcreteTypeId, GenericTypeId};
20use crate::program::GenericArg;
21
22type ArrayIndexType = super::int::unsigned::Uint32Type;
23
24/// Type representing an array.
25#[derive(Default)]
26pub struct ArrayTypeWrapped {}
27impl GenericTypeArgGenericType for ArrayTypeWrapped {
28    const ID: GenericTypeId = GenericTypeId::new_inline("Array");
29
30    fn calc_info(
31        &self,
32        _context: &dyn TypeSpecializationContext,
33        long_id: crate::program::ConcreteTypeLongId,
34        TypeInfo { storable, droppable, zero_sized, .. }: TypeInfo,
35    ) -> Result<TypeInfo, SpecializationError> {
36        if storable && !zero_sized {
37            Ok(TypeInfo {
38                long_id,
39                duplicatable: false,
40                droppable,
41                storable: true,
42                zero_sized: false,
43            })
44        } else {
45            Err(SpecializationError::UnsupportedGenericArg)
46        }
47    }
48}
49pub type ArrayType = GenericTypeArgGenericTypeWrapper<ArrayTypeWrapped>;
50
51define_libfunc_hierarchy! {
52    pub enum ArrayLibfunc {
53        New(ArrayNewLibfunc),
54        SpanFromTuple(SpanFromTupleLibfunc),
55        TupleFromSpan(TupleFromSpanLibfunc),
56        Append(ArrayAppendLibfunc),
57        PopFront(ArrayPopFrontLibfunc),
58        PopFrontConsume(ArrayPopFrontConsumeLibfunc),
59        Get(ArrayGetLibfunc),
60        Slice(ArraySliceLibfunc),
61        Len(ArrayLenLibfunc),
62        SnapshotPopFront(ArraySnapshotPopFrontLibfunc),
63        SnapshotPopBack(ArraySnapshotPopBackLibfunc),
64        SnapshotMultiPopFront(ArraySnapshotMultiPopFrontLibfunc),
65        SnapshotMultiPopBack(ArraySnapshotMultiPopBackLibfunc),
66    }, ArrayConcreteLibfunc
67}
68
69/// Libfunc for creating a new array.
70#[derive(Default)]
71pub struct ArrayNewLibfunc {}
72impl SignatureOnlyGenericLibfunc for ArrayNewLibfunc {
73    const STR_ID: &'static str = "array_new";
74
75    fn specialize_signature(
76        &self,
77        context: &dyn SignatureSpecializationContext,
78        args: &[GenericArg],
79    ) -> Result<LibfuncSignature, SpecializationError> {
80        let ty = args_as_single_type(args)?;
81        Ok(LibfuncSignature::new_non_branch(
82            vec![],
83            vec![OutputVarInfo {
84                ty: context.get_wrapped_concrete_type(ArrayType::id(), ty)?,
85                ref_info: OutputVarReferenceInfo::SimpleDerefs,
86            }],
87            SierraApChange::Known { new_vars_only: false },
88        ))
89    }
90}
91
92/// Libfunc for creating a span from a box of struct of members of the same type.
93#[derive(Default)]
94pub struct SpanFromTupleLibfuncWrapped;
95impl SignatureAndTypeGenericLibfunc for SpanFromTupleLibfuncWrapped {
96    const STR_ID: &'static str = "span_from_tuple";
97
98    fn specialize_signature(
99        &self,
100        context: &dyn SignatureSpecializationContext,
101        ty: ConcreteTypeId,
102    ) -> Result<LibfuncSignature, SpecializationError> {
103        let member_type = validate_tuple_and_fetch_ty(context, &ty)?;
104
105        Ok(LibfuncSignature::new_non_branch(
106            vec![box_ty(context, snapshot_ty(context, ty)?)?],
107            vec![OutputVarInfo {
108                ty: snapshot_ty(
109                    context,
110                    context.get_wrapped_concrete_type(ArrayType::id(), member_type.clone())?,
111                )?,
112                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::AddConst {
113                    param_idx: 0,
114                }),
115            }],
116            SierraApChange::Known { new_vars_only: true },
117        ))
118    }
119}
120
121pub type SpanFromTupleLibfunc = WrapSignatureAndTypeGenericLibfunc<SpanFromTupleLibfuncWrapped>;
122
123/// Libfunc for creating a box of struct of members of the same type from a span.
124#[derive(Default)]
125pub struct TupleFromSpanLibfuncWrapped;
126impl SignatureAndTypeGenericLibfunc for TupleFromSpanLibfuncWrapped {
127    const STR_ID: &'static str = "tuple_from_span";
128
129    fn specialize_signature(
130        &self,
131        context: &dyn SignatureSpecializationContext,
132        ty: ConcreteTypeId,
133    ) -> Result<LibfuncSignature, SpecializationError> {
134        let member_type = validate_tuple_and_fetch_ty(context, &ty)?;
135
136        Ok(LibfuncSignature {
137            param_signatures: vec![ParamSignature::new(snapshot_ty(
138                context,
139                context.get_wrapped_concrete_type(ArrayType::id(), member_type)?,
140            )?)],
141            branch_signatures: vec![
142                BranchSignature {
143                    vars: vec![OutputVarInfo {
144                        ty: snapshot_ty(context, box_ty(context, ty)?)?,
145                        ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
146                    }],
147                    ap_change: SierraApChange::Known { new_vars_only: false },
148                },
149                BranchSignature {
150                    vars: vec![],
151                    ap_change: SierraApChange::Known { new_vars_only: false },
152                },
153            ],
154            fallthrough: Some(0),
155        })
156    }
157}
158
159/// Validates that the given type is a tuple with all members of the same type, and returns the type
160/// of the members.
161/// Any user type with such members is also considered a tuple.
162fn validate_tuple_and_fetch_ty(
163    context: &dyn SignatureSpecializationContext,
164    ty: &ConcreteTypeId,
165) -> Result<ConcreteTypeId, SpecializationError> {
166    let struct_type = StructConcreteType::try_from_concrete_type(context, ty)?;
167    if struct_type.info.zero_sized {
168        return Err(SpecializationError::UnsupportedGenericArg);
169    }
170    let mut members = struct_type.members.into_iter();
171    let member_type = members.next().ok_or(SpecializationError::UnsupportedGenericArg)?;
172    for member in members {
173        if member != member_type {
174            return Err(SpecializationError::UnsupportedGenericArg);
175        }
176    }
177    Ok(member_type)
178}
179
180pub type TupleFromSpanLibfunc = WrapSignatureAndTypeGenericLibfunc<TupleFromSpanLibfuncWrapped>;
181
182/// Libfunc for getting the length of the array.
183#[derive(Default)]
184pub struct ArrayLenLibfuncWrapped {}
185impl SignatureAndTypeGenericLibfunc for ArrayLenLibfuncWrapped {
186    const STR_ID: &'static str = "array_len";
187
188    fn specialize_signature(
189        &self,
190        context: &dyn SignatureSpecializationContext,
191        ty: ConcreteTypeId,
192    ) -> Result<LibfuncSignature, SpecializationError> {
193        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty)?;
194        Ok(LibfuncSignature::new_non_branch(
195            vec![snapshot_ty(context, arr_ty)?],
196            vec![OutputVarInfo {
197                ty: context.get_concrete_type(ArrayIndexType::id(), &[])?,
198                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
199            }],
200            SierraApChange::Known { new_vars_only: false },
201        ))
202    }
203}
204pub type ArrayLenLibfunc = WrapSignatureAndTypeGenericLibfunc<ArrayLenLibfuncWrapped>;
205
206/// Libfunc for pushing a value into the end of an array.
207#[derive(Default)]
208pub struct ArrayAppendLibfuncWrapped {}
209impl SignatureAndTypeGenericLibfunc for ArrayAppendLibfuncWrapped {
210    const STR_ID: &'static str = "array_append";
211
212    fn specialize_signature(
213        &self,
214        context: &dyn SignatureSpecializationContext,
215        ty: ConcreteTypeId,
216    ) -> Result<LibfuncSignature, SpecializationError> {
217        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
218        Ok(LibfuncSignature::new_non_branch_ex(
219            vec![
220                ParamSignature::new(arr_ty.clone()).with_allow_add_const(),
221                ParamSignature::new(ty),
222            ],
223            vec![OutputVarInfo {
224                ty: arr_ty,
225                ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::AddConst {
226                    param_idx: 0,
227                }),
228            }],
229            SierraApChange::Known { new_vars_only: true },
230        ))
231    }
232}
233pub type ArrayAppendLibfunc = WrapSignatureAndTypeGenericLibfunc<ArrayAppendLibfuncWrapped>;
234
235/// Libfunc for popping the first value from the beginning of an array.
236#[derive(Default)]
237pub struct ArrayPopFrontLibfuncWrapped {}
238impl SignatureAndTypeGenericLibfunc for ArrayPopFrontLibfuncWrapped {
239    const STR_ID: &'static str = "array_pop_front";
240
241    fn specialize_signature(
242        &self,
243        context: &dyn SignatureSpecializationContext,
244        ty: ConcreteTypeId,
245    ) -> Result<LibfuncSignature, SpecializationError> {
246        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
247        Ok(LibfuncSignature {
248            param_signatures: vec![ParamSignature::new(arr_ty.clone())],
249            branch_signatures: vec![
250                // Non-empty.
251                BranchSignature {
252                    vars: vec![
253                        OutputVarInfo {
254                            ty: arr_ty.clone(),
255                            ref_info: OutputVarReferenceInfo::Deferred(
256                                DeferredOutputKind::AddConst { param_idx: 0 },
257                            ),
258                        },
259                        OutputVarInfo {
260                            ty: box_ty(context, ty)?,
261                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
262                        },
263                    ],
264                    ap_change: SierraApChange::Known { new_vars_only: false },
265                },
266                // Empty.
267                BranchSignature {
268                    vars: vec![OutputVarInfo {
269                        ty: arr_ty,
270                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
271                    }],
272                    ap_change: SierraApChange::Known { new_vars_only: false },
273                },
274            ],
275            fallthrough: Some(0),
276        })
277    }
278}
279pub type ArrayPopFrontLibfunc = WrapSignatureAndTypeGenericLibfunc<ArrayPopFrontLibfuncWrapped>;
280
281/// Libfunc for popping the first value from the beginning of an array.
282#[derive(Default)]
283pub struct ArrayPopFrontConsumeLibfuncWrapped {}
284impl SignatureAndTypeGenericLibfunc for ArrayPopFrontConsumeLibfuncWrapped {
285    const STR_ID: &'static str = "array_pop_front_consume";
286
287    fn specialize_signature(
288        &self,
289        context: &dyn SignatureSpecializationContext,
290        ty: ConcreteTypeId,
291    ) -> Result<LibfuncSignature, SpecializationError> {
292        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
293        Ok(LibfuncSignature {
294            param_signatures: vec![ParamSignature::new(arr_ty.clone())],
295            branch_signatures: vec![
296                // Non-empty.
297                BranchSignature {
298                    vars: vec![
299                        OutputVarInfo {
300                            ty: arr_ty,
301                            ref_info: OutputVarReferenceInfo::Deferred(
302                                DeferredOutputKind::AddConst { param_idx: 0 },
303                            ),
304                        },
305                        OutputVarInfo {
306                            ty: box_ty(context, ty)?,
307                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
308                        },
309                    ],
310                    ap_change: SierraApChange::Known { new_vars_only: false },
311                },
312                // Empty.
313                BranchSignature {
314                    vars: vec![],
315                    ap_change: SierraApChange::Known { new_vars_only: false },
316                },
317            ],
318            fallthrough: Some(0),
319        })
320    }
321}
322pub type ArrayPopFrontConsumeLibfunc =
323    WrapSignatureAndTypeGenericLibfunc<ArrayPopFrontConsumeLibfuncWrapped>;
324
325/// Libfunc for fetching a value from a specific array index.
326#[derive(Default)]
327pub struct ArrayGetLibfuncWrapped {}
328impl SignatureAndTypeGenericLibfunc for ArrayGetLibfuncWrapped {
329    const STR_ID: &'static str = "array_get";
330
331    fn specialize_signature(
332        &self,
333        context: &dyn SignatureSpecializationContext,
334        ty: ConcreteTypeId,
335    ) -> Result<LibfuncSignature, SpecializationError> {
336        let arr_type = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
337        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
338        let index_type = context.get_concrete_type(ArrayIndexType::id(), &[])?;
339        let param_signatures = vec![
340            ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
341            ParamSignature::new(snapshot_ty(context, arr_type)?),
342            ParamSignature::new(index_type),
343        ];
344        let rc_output_info = OutputVarInfo::new_builtin(range_check_type, 0);
345        let branch_signatures = vec![
346            // First (success) branch returns rc, array and element; failure branch does not return
347            // an element.
348            BranchSignature {
349                vars: vec![
350                    rc_output_info.clone(),
351                    OutputVarInfo {
352                        ty: box_ty(context, snapshot_ty(context, ty)?)?,
353                        ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
354                    },
355                ],
356                ap_change: SierraApChange::Known { new_vars_only: false },
357            },
358            BranchSignature {
359                vars: vec![rc_output_info],
360                ap_change: SierraApChange::Known { new_vars_only: false },
361            },
362        ];
363        Ok(LibfuncSignature { param_signatures, branch_signatures, fallthrough: Some(0) })
364    }
365}
366pub type ArrayGetLibfunc = WrapSignatureAndTypeGenericLibfunc<ArrayGetLibfuncWrapped>;
367
368/// Libfunc for getting a slice of an array snapshot.
369#[derive(Default)]
370pub struct ArraySliceLibfuncWrapped {}
371impl SignatureAndTypeGenericLibfunc for ArraySliceLibfuncWrapped {
372    const STR_ID: &'static str = "array_slice";
373
374    fn specialize_signature(
375        &self,
376        context: &dyn SignatureSpecializationContext,
377        ty: ConcreteTypeId,
378    ) -> Result<LibfuncSignature, SpecializationError> {
379        let arr_snapshot_type =
380            snapshot_ty(context, context.get_wrapped_concrete_type(ArrayType::id(), ty)?)?;
381        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
382        let index_type = context.get_concrete_type(ArrayIndexType::id(), &[])?;
383        let param_signatures = vec![
384            ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
385            ParamSignature::new(arr_snapshot_type.clone()),
386            // Start
387            ParamSignature::new(index_type.clone()),
388            // Length
389            ParamSignature::new(index_type),
390        ];
391        let rc_output_info = OutputVarInfo::new_builtin(range_check_type, 0);
392        let branch_signatures = vec![
393            // Success.
394            BranchSignature {
395                vars: vec![
396                    // Range check.
397                    rc_output_info.clone(),
398                    // Array slice snapshot.
399                    OutputVarInfo {
400                        ty: arr_snapshot_type,
401                        ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
402                    },
403                ],
404                ap_change: SierraApChange::Known { new_vars_only: false },
405            },
406            // Failure - returns only the range check buffer.
407            BranchSignature {
408                vars: vec![rc_output_info],
409                ap_change: SierraApChange::Known { new_vars_only: false },
410            },
411        ];
412        Ok(LibfuncSignature { param_signatures, branch_signatures, fallthrough: Some(0) })
413    }
414}
415pub type ArraySliceLibfunc = WrapSignatureAndTypeGenericLibfunc<ArraySliceLibfuncWrapped>;
416
417/// Libfunc for popping the first value from the beginning of an array snapshot.
418#[derive(Default)]
419pub struct ArraySnapshotPopFrontLibfuncWrapped {}
420impl SignatureAndTypeGenericLibfunc for ArraySnapshotPopFrontLibfuncWrapped {
421    const STR_ID: &'static str = "array_snapshot_pop_front";
422
423    fn specialize_signature(
424        &self,
425        context: &dyn SignatureSpecializationContext,
426        ty: ConcreteTypeId,
427    ) -> Result<LibfuncSignature, SpecializationError> {
428        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
429        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
430        Ok(LibfuncSignature {
431            param_signatures: vec![ParamSignature::new(arr_snapshot_ty.clone())],
432            branch_signatures: vec![
433                BranchSignature {
434                    vars: vec![
435                        OutputVarInfo {
436                            ty: arr_snapshot_ty.clone(),
437                            ref_info: OutputVarReferenceInfo::Deferred(
438                                DeferredOutputKind::AddConst { param_idx: 0 },
439                            ),
440                        },
441                        OutputVarInfo {
442                            ty: box_ty(context, snapshot_ty(context, ty)?)?,
443                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
444                        },
445                    ],
446                    ap_change: SierraApChange::Known { new_vars_only: false },
447                },
448                BranchSignature {
449                    vars: vec![OutputVarInfo {
450                        ty: arr_snapshot_ty,
451                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
452                    }],
453                    ap_change: SierraApChange::Known { new_vars_only: false },
454                },
455            ],
456            fallthrough: Some(0),
457        })
458    }
459}
460pub type ArraySnapshotPopFrontLibfunc =
461    WrapSignatureAndTypeGenericLibfunc<ArraySnapshotPopFrontLibfuncWrapped>;
462
463/// Libfunc for popping the last value from the end of an array snapshot.
464#[derive(Default)]
465pub struct ArraySnapshotPopBackLibfuncWrapped {}
466impl SignatureAndTypeGenericLibfunc for ArraySnapshotPopBackLibfuncWrapped {
467    const STR_ID: &'static str = "array_snapshot_pop_back";
468
469    fn specialize_signature(
470        &self,
471        context: &dyn SignatureSpecializationContext,
472        ty: ConcreteTypeId,
473    ) -> Result<LibfuncSignature, SpecializationError> {
474        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
475        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
476        Ok(LibfuncSignature {
477            param_signatures: vec![ParamSignature::new(arr_snapshot_ty.clone())],
478            branch_signatures: vec![
479                BranchSignature {
480                    vars: vec![
481                        OutputVarInfo {
482                            ty: arr_snapshot_ty.clone(),
483                            ref_info: OutputVarReferenceInfo::Deferred(
484                                DeferredOutputKind::AddConst { param_idx: 0 },
485                            ),
486                        },
487                        OutputVarInfo {
488                            ty: box_ty(context, snapshot_ty(context, ty)?)?,
489                            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
490                        },
491                    ],
492                    ap_change: SierraApChange::Known { new_vars_only: false },
493                },
494                BranchSignature {
495                    vars: vec![OutputVarInfo {
496                        ty: arr_snapshot_ty,
497                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
498                    }],
499                    ap_change: SierraApChange::Known { new_vars_only: false },
500                },
501            ],
502            fallthrough: Some(0),
503        })
504    }
505}
506pub type ArraySnapshotPopBackLibfunc =
507    WrapSignatureAndTypeGenericLibfunc<ArraySnapshotPopBackLibfuncWrapped>;
508
509/// Libfunc for popping multiple first values from the beginning of an array snapshot.
510#[derive(Default)]
511pub struct ArraySnapshotMultiPopFrontLibfunc {}
512impl NamedLibfunc for ArraySnapshotMultiPopFrontLibfunc {
513    const STR_ID: &'static str = "array_snapshot_multi_pop_front";
514
515    type Concrete = ConcreteMultiPopLibfunc;
516
517    fn specialize_signature(
518        &self,
519        context: &dyn SignatureSpecializationContext,
520        args: &[GenericArg],
521    ) -> Result<LibfuncSignature, SpecializationError> {
522        let popped_ty = args_as_single_type(args)?;
523        let ty = validate_tuple_and_fetch_ty(context, &popped_ty)?;
524        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
525        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
526        let range_check_ty = context.get_concrete_type(RangeCheckType::id(), &[])?;
527        Ok(LibfuncSignature {
528            param_signatures: vec![
529                ParamSignature::new(range_check_ty.clone()).with_allow_add_const(),
530                ParamSignature::new(arr_snapshot_ty.clone()),
531            ],
532            branch_signatures: vec![
533                // Success.
534                BranchSignature {
535                    vars: vec![
536                        OutputVarInfo::new_builtin(range_check_ty.clone(), 0),
537                        OutputVarInfo {
538                            ty: arr_snapshot_ty.clone(),
539                            ref_info: OutputVarReferenceInfo::SimpleDerefs,
540                        },
541                        OutputVarInfo {
542                            ty: snapshot_ty(context, box_ty(context, popped_ty)?)?,
543                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 1 },
544                        },
545                    ],
546                    ap_change: SierraApChange::Known { new_vars_only: false },
547                },
548                // Failure.
549                BranchSignature {
550                    vars: vec![
551                        OutputVarInfo::new_builtin(range_check_ty, 0),
552                        OutputVarInfo {
553                            ty: arr_snapshot_ty,
554                            ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
555                        },
556                    ],
557                    ap_change: SierraApChange::Known { new_vars_only: false },
558                },
559            ],
560            fallthrough: Some(0),
561        })
562    }
563
564    fn specialize(
565        &self,
566        context: &dyn SpecializationContext,
567        args: &[GenericArg],
568    ) -> Result<Self::Concrete, SpecializationError> {
569        let popped_ty = args_as_single_type(args)?;
570        Ok(ConcreteMultiPopLibfunc {
571            popped_ty,
572            signature: self.specialize_signature(context.upcast(), args)?,
573        })
574    }
575}
576
577/// Libfunc for popping the last value from the end of an array snapshot.
578#[derive(Default)]
579pub struct ArraySnapshotMultiPopBackLibfunc {}
580impl NamedLibfunc for ArraySnapshotMultiPopBackLibfunc {
581    const STR_ID: &'static str = "array_snapshot_multi_pop_back";
582
583    type Concrete = ConcreteMultiPopLibfunc;
584
585    fn specialize_signature(
586        &self,
587        context: &dyn SignatureSpecializationContext,
588        args: &[GenericArg],
589    ) -> Result<LibfuncSignature, SpecializationError> {
590        let popped_ty = args_as_single_type(args)?;
591        let ty = validate_tuple_and_fetch_ty(context, &popped_ty)?;
592        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
593        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
594        let range_check_ty = context.get_concrete_type(RangeCheckType::id(), &[])?;
595        Ok(LibfuncSignature {
596            param_signatures: vec![
597                ParamSignature::new(range_check_ty.clone()).with_allow_add_const(),
598                ParamSignature::new(arr_snapshot_ty.clone()),
599            ],
600            branch_signatures: vec![
601                // Success.
602                BranchSignature {
603                    vars: vec![
604                        OutputVarInfo::new_builtin(range_check_ty.clone(), 0),
605                        OutputVarInfo {
606                            ty: arr_snapshot_ty.clone(),
607                            ref_info: OutputVarReferenceInfo::SimpleDerefs,
608                        },
609                        OutputVarInfo {
610                            ty: snapshot_ty(context, box_ty(context, popped_ty)?)?,
611                            ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
612                        },
613                    ],
614                    ap_change: SierraApChange::Known { new_vars_only: false },
615                },
616                // Failure.
617                BranchSignature {
618                    vars: vec![
619                        OutputVarInfo::new_builtin(range_check_ty, 0),
620                        OutputVarInfo {
621                            ty: arr_snapshot_ty,
622                            ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
623                        },
624                    ],
625                    ap_change: SierraApChange::Known { new_vars_only: false },
626                },
627            ],
628            fallthrough: Some(0),
629        })
630    }
631
632    fn specialize(
633        &self,
634        context: &dyn SpecializationContext,
635        args: &[GenericArg],
636    ) -> Result<Self::Concrete, SpecializationError> {
637        let popped_ty = args_as_single_type(args)?;
638        Ok(ConcreteMultiPopLibfunc {
639            popped_ty,
640            signature: self.specialize_signature(context.upcast(), args)?,
641        })
642    }
643}
644
645/// Struct the data for a multi pop action.
646pub struct ConcreteMultiPopLibfunc {
647    pub popped_ty: ConcreteTypeId,
648    pub signature: LibfuncSignature,
649}
650impl SignatureBasedConcreteLibfunc for ConcreteMultiPopLibfunc {
651    fn signature(&self) -> &LibfuncSignature {
652        &self.signature
653    }
654}