Skip to main content

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