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![rc_output_info.clone(), OutputVarInfo {
350                    ty: box_ty(context, snapshot_ty(context, ty)?)?,
351                    ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
352                }],
353                ap_change: SierraApChange::Known { new_vars_only: false },
354            },
355            BranchSignature {
356                vars: vec![rc_output_info],
357                ap_change: SierraApChange::Known { new_vars_only: false },
358            },
359        ];
360        Ok(LibfuncSignature { param_signatures, branch_signatures, fallthrough: Some(0) })
361    }
362}
363pub type ArrayGetLibfunc = WrapSignatureAndTypeGenericLibfunc<ArrayGetLibfuncWrapped>;
364
365/// Libfunc for getting a slice of an array snapshot.
366#[derive(Default)]
367pub struct ArraySliceLibfuncWrapped {}
368impl SignatureAndTypeGenericLibfunc for ArraySliceLibfuncWrapped {
369    const STR_ID: &'static str = "array_slice";
370
371    fn specialize_signature(
372        &self,
373        context: &dyn SignatureSpecializationContext,
374        ty: ConcreteTypeId,
375    ) -> Result<LibfuncSignature, SpecializationError> {
376        let arr_snapshot_type =
377            snapshot_ty(context, context.get_wrapped_concrete_type(ArrayType::id(), ty)?)?;
378        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
379        let index_type = context.get_concrete_type(ArrayIndexType::id(), &[])?;
380        let param_signatures = vec![
381            ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
382            ParamSignature::new(arr_snapshot_type.clone()),
383            // Start
384            ParamSignature::new(index_type.clone()),
385            // Length
386            ParamSignature::new(index_type),
387        ];
388        let rc_output_info = OutputVarInfo::new_builtin(range_check_type, 0);
389        let branch_signatures = vec![
390            // Success.
391            BranchSignature {
392                vars: vec![
393                    // Range check.
394                    rc_output_info.clone(),
395                    // Array slice snapshot.
396                    OutputVarInfo {
397                        ty: arr_snapshot_type,
398                        ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
399                    },
400                ],
401                ap_change: SierraApChange::Known { new_vars_only: false },
402            },
403            // Failure - returns only the range check buffer.
404            BranchSignature {
405                vars: vec![rc_output_info],
406                ap_change: SierraApChange::Known { new_vars_only: false },
407            },
408        ];
409        Ok(LibfuncSignature { param_signatures, branch_signatures, fallthrough: Some(0) })
410    }
411}
412pub type ArraySliceLibfunc = WrapSignatureAndTypeGenericLibfunc<ArraySliceLibfuncWrapped>;
413
414/// Libfunc for popping the first value from the beginning of an array snapshot.
415#[derive(Default)]
416pub struct ArraySnapshotPopFrontLibfuncWrapped {}
417impl SignatureAndTypeGenericLibfunc for ArraySnapshotPopFrontLibfuncWrapped {
418    const STR_ID: &'static str = "array_snapshot_pop_front";
419
420    fn specialize_signature(
421        &self,
422        context: &dyn SignatureSpecializationContext,
423        ty: ConcreteTypeId,
424    ) -> Result<LibfuncSignature, SpecializationError> {
425        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
426        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
427        Ok(LibfuncSignature {
428            param_signatures: vec![ParamSignature::new(arr_snapshot_ty.clone())],
429            branch_signatures: vec![
430                BranchSignature {
431                    vars: vec![
432                        OutputVarInfo {
433                            ty: arr_snapshot_ty.clone(),
434                            ref_info: OutputVarReferenceInfo::Deferred(
435                                DeferredOutputKind::AddConst { param_idx: 0 },
436                            ),
437                        },
438                        OutputVarInfo {
439                            ty: box_ty(context, snapshot_ty(context, ty)?)?,
440                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
441                        },
442                    ],
443                    ap_change: SierraApChange::Known { new_vars_only: false },
444                },
445                BranchSignature {
446                    vars: vec![OutputVarInfo {
447                        ty: arr_snapshot_ty,
448                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
449                    }],
450                    ap_change: SierraApChange::Known { new_vars_only: false },
451                },
452            ],
453            fallthrough: Some(0),
454        })
455    }
456}
457pub type ArraySnapshotPopFrontLibfunc =
458    WrapSignatureAndTypeGenericLibfunc<ArraySnapshotPopFrontLibfuncWrapped>;
459
460/// Libfunc for popping the last value from the end of an array snapshot.
461#[derive(Default)]
462pub struct ArraySnapshotPopBackLibfuncWrapped {}
463impl SignatureAndTypeGenericLibfunc for ArraySnapshotPopBackLibfuncWrapped {
464    const STR_ID: &'static str = "array_snapshot_pop_back";
465
466    fn specialize_signature(
467        &self,
468        context: &dyn SignatureSpecializationContext,
469        ty: ConcreteTypeId,
470    ) -> Result<LibfuncSignature, SpecializationError> {
471        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
472        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
473        Ok(LibfuncSignature {
474            param_signatures: vec![ParamSignature::new(arr_snapshot_ty.clone())],
475            branch_signatures: vec![
476                BranchSignature {
477                    vars: vec![
478                        OutputVarInfo {
479                            ty: arr_snapshot_ty.clone(),
480                            ref_info: OutputVarReferenceInfo::Deferred(
481                                DeferredOutputKind::AddConst { param_idx: 0 },
482                            ),
483                        },
484                        OutputVarInfo {
485                            ty: box_ty(context, snapshot_ty(context, ty)?)?,
486                            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
487                        },
488                    ],
489                    ap_change: SierraApChange::Known { new_vars_only: false },
490                },
491                BranchSignature {
492                    vars: vec![OutputVarInfo {
493                        ty: arr_snapshot_ty,
494                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
495                    }],
496                    ap_change: SierraApChange::Known { new_vars_only: false },
497                },
498            ],
499            fallthrough: Some(0),
500        })
501    }
502}
503pub type ArraySnapshotPopBackLibfunc =
504    WrapSignatureAndTypeGenericLibfunc<ArraySnapshotPopBackLibfuncWrapped>;
505
506/// Libfunc for popping multiple first values from the beginning of an array snapshot.
507#[derive(Default)]
508pub struct ArraySnapshotMultiPopFrontLibfunc {}
509impl NamedLibfunc for ArraySnapshotMultiPopFrontLibfunc {
510    const STR_ID: &'static str = "array_snapshot_multi_pop_front";
511
512    type Concrete = ConcreteMultiPopLibfunc;
513
514    fn specialize_signature(
515        &self,
516        context: &dyn SignatureSpecializationContext,
517        args: &[GenericArg],
518    ) -> Result<LibfuncSignature, SpecializationError> {
519        let popped_ty = args_as_single_type(args)?;
520        let ty = validate_tuple_and_fetch_ty(context, &popped_ty)?;
521        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
522        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
523        let range_check_ty = context.get_concrete_type(RangeCheckType::id(), &[])?;
524        Ok(LibfuncSignature {
525            param_signatures: vec![
526                ParamSignature::new(range_check_ty.clone()).with_allow_add_const(),
527                ParamSignature::new(arr_snapshot_ty.clone()),
528            ],
529            branch_signatures: vec![
530                // Success.
531                BranchSignature {
532                    vars: vec![
533                        OutputVarInfo::new_builtin(range_check_ty.clone(), 0),
534                        OutputVarInfo {
535                            ty: arr_snapshot_ty.clone(),
536                            ref_info: OutputVarReferenceInfo::SimpleDerefs,
537                        },
538                        OutputVarInfo {
539                            ty: snapshot_ty(context, box_ty(context, popped_ty)?)?,
540                            ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 1 },
541                        },
542                    ],
543                    ap_change: SierraApChange::Known { new_vars_only: false },
544                },
545                // Failure.
546                BranchSignature {
547                    vars: vec![OutputVarInfo::new_builtin(range_check_ty, 0), OutputVarInfo {
548                        ty: arr_snapshot_ty,
549                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
550                    }],
551                    ap_change: SierraApChange::Known { new_vars_only: false },
552                },
553            ],
554            fallthrough: Some(0),
555        })
556    }
557
558    fn specialize(
559        &self,
560        context: &dyn SpecializationContext,
561        args: &[GenericArg],
562    ) -> Result<Self::Concrete, SpecializationError> {
563        let popped_ty = args_as_single_type(args)?;
564        Ok(ConcreteMultiPopLibfunc {
565            popped_ty,
566            signature: self.specialize_signature(context.upcast(), args)?,
567        })
568    }
569}
570
571/// Libfunc for popping the last value from the end of an array snapshot.
572#[derive(Default)]
573pub struct ArraySnapshotMultiPopBackLibfunc {}
574impl NamedLibfunc for ArraySnapshotMultiPopBackLibfunc {
575    const STR_ID: &'static str = "array_snapshot_multi_pop_back";
576
577    type Concrete = ConcreteMultiPopLibfunc;
578
579    fn specialize_signature(
580        &self,
581        context: &dyn SignatureSpecializationContext,
582        args: &[GenericArg],
583    ) -> Result<LibfuncSignature, SpecializationError> {
584        let popped_ty = args_as_single_type(args)?;
585        let ty = validate_tuple_and_fetch_ty(context, &popped_ty)?;
586        let arr_ty = context.get_wrapped_concrete_type(ArrayType::id(), ty.clone())?;
587        let arr_snapshot_ty = snapshot_ty(context, arr_ty)?;
588        let range_check_ty = context.get_concrete_type(RangeCheckType::id(), &[])?;
589        Ok(LibfuncSignature {
590            param_signatures: vec![
591                ParamSignature::new(range_check_ty.clone()).with_allow_add_const(),
592                ParamSignature::new(arr_snapshot_ty.clone()),
593            ],
594            branch_signatures: vec![
595                // Success.
596                BranchSignature {
597                    vars: vec![
598                        OutputVarInfo::new_builtin(range_check_ty.clone(), 0),
599                        OutputVarInfo {
600                            ty: arr_snapshot_ty.clone(),
601                            ref_info: OutputVarReferenceInfo::SimpleDerefs,
602                        },
603                        OutputVarInfo {
604                            ty: snapshot_ty(context, box_ty(context, popped_ty)?)?,
605                            ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
606                        },
607                    ],
608                    ap_change: SierraApChange::Known { new_vars_only: false },
609                },
610                // Failure.
611                BranchSignature {
612                    vars: vec![OutputVarInfo::new_builtin(range_check_ty, 0), OutputVarInfo {
613                        ty: arr_snapshot_ty,
614                        ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
615                    }],
616                    ap_change: SierraApChange::Known { new_vars_only: false },
617                },
618            ],
619            fallthrough: Some(0),
620        })
621    }
622
623    fn specialize(
624        &self,
625        context: &dyn SpecializationContext,
626        args: &[GenericArg],
627    ) -> Result<Self::Concrete, SpecializationError> {
628        let popped_ty = args_as_single_type(args)?;
629        Ok(ConcreteMultiPopLibfunc {
630            popped_ty,
631            signature: self.specialize_signature(context.upcast(), args)?,
632        })
633    }
634}
635
636/// Struct the data for a multi pop action.
637pub struct ConcreteMultiPopLibfunc {
638    pub popped_ty: ConcreteTypeId,
639    pub signature: LibfuncSignature,
640}
641impl SignatureBasedConcreteLibfunc for ConcreteMultiPopLibfunc {
642    fn signature(&self) -> &LibfuncSignature {
643        &self.signature
644    }
645}