diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 4971aab65..4b8b57b8d 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -1309,11 +1309,27 @@ fn is_shared<'ctx, 'this>( mod test { use crate::{ utils::{ - felt252_str, - test::{jit_enum, jit_panic, jit_struct, load_cairo, run_program}, + sierra_gen::SierraGenerator, + test::{jit_enum, jit_struct, load_cairo, run_program, run_sierra_program}, }, values::Value, }; + use cairo_lang_sierra::{ + extensions::{ + array::{ + ArrayAppendLibfunc, ArrayGetLibfunc, ArrayLenLibfunc, ArrayNewLibfunc, + ArrayPopFrontConsumeLibfunc, ArrayPopFrontLibfunc, ArraySliceLibfunc, + ArraySnapshotMultiPopBackLibfunc, ArraySnapshotMultiPopFrontLibfunc, + ArraySnapshotPopBackLibfunc, ArrayType, + }, + felt252::Felt252Type, + int::unsigned::Uint32Type, + snapshot::SnapshotTakeLibfunc, + structure::StructType, + }, + ids::UserTypeId, + program::GenericArg, + }; use pretty_assertions_sorted::assert_eq; use starknet_types_core::felt::Felt; @@ -1333,321 +1349,319 @@ mod test { #[test] fn run_append() { - let program = load_cairo! { - use array::ArrayTrait; + let program_new = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Array { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers - } + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) }; - let result = run_program(&program, "run_test", &[]).return_value; + let program_append = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let result = run_sierra_program(&program_new, &[]).return_value; + let result = run_sierra_program(&program_append, &[result, Value::Uint32(4)]).return_value; assert_eq!(result, [4u32].into()); } #[test] fn run_len() { - let program = load_cairo!( - use array::ArrayTrait; + let program_len = { + let mut generator = SierraGenerator::::default(); + let u32_ty = generator.push_type_declaration::(&[]).clone(); - fn run_test() -> u32 { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.append(2_u32); - numbers.len() - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let array = vec![4, 3, 2].into(); + + let result = run_sierra_program(&program_len, &[array]).return_value; assert_eq!(result, 3u32.into()); } #[test] fn run_get() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> (u32, u32, u32, u32) { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.append(2_u32); - numbers.append(1_u32); - ( - *numbers.at(0), - *numbers.at(1), - *numbers.at(2), - *numbers.at(3), - ) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let program_get = { + let mut generator = SierraGenerator::::default(); + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!( - result, - jit_enum!( - 0, - jit_struct!(jit_struct!( - 4u32.into(), - 3u32.into(), - 2u32.into(), - 1u32.into() - )) - ) - ); + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let array = Value::Array(vec![ + Value::Uint32(4), + Value::Uint32(3), + Value::Uint32(2), + Value::Uint32(1), + ]); + + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(0)]).return_value; + assert_eq!(result, jit_enum!(0, 4u32.into())); + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(1)]).return_value; + assert_eq!(result, jit_enum!(0, 3u32.into())); + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(2)]).return_value; + assert_eq!(result, jit_enum!(0, 2u32.into())); + let result = run_sierra_program(&program_get, &[array, Value::Uint32(3)]).return_value; + assert_eq!(result, jit_enum!(0, 1u32.into())); } #[test] fn run_get_big() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> (u32, u32, u32, u32) { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(2_u32); - numbers.append(17_u32); - numbers.append(17_u32); - numbers.append(18_u32); - numbers.append(19_u32); - numbers.append(20_u32); - numbers.append(21_u32); - numbers.append(22_u32); - numbers.append(23_u32); - ( - *numbers.at(20), - *numbers.at(21), - *numbers.at(22), - *numbers.at(23), - ) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let program_get = { + let mut generator = SierraGenerator::::default(); + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!( - result, - jit_enum!( - 0, - jit_struct!(jit_struct!( - 20u32.into(), - 21u32.into(), - 22u32.into(), - 23u32.into() - )) - ) - ); + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let array = Value::Array(vec![ + Value::Uint32(4), + Value::Uint32(3), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(2), + Value::Uint32(17), + Value::Uint32(17), + Value::Uint32(18), + Value::Uint32(19), + Value::Uint32(20), + Value::Uint32(21), + Value::Uint32(22), + Value::Uint32(23), + ]); + + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(20)]).return_value; + assert_eq!(result, jit_enum!(0, 20u32.into())); + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(21)]).return_value; + assert_eq!(result, jit_enum!(0, 21u32.into())); + let result = + run_sierra_program(&program_get, &[array.clone(), Value::Uint32(22)]).return_value; + assert_eq!(result, jit_enum!(0, 22u32.into())); + let result = run_sierra_program(&program_get, &[array, Value::Uint32(23)]).return_value; + assert_eq!(result, jit_enum!(0, 23u32.into())); } #[test] fn run_pop_front() { - let program = load_cairo!( - use array::ArrayTrait; + let program_pop = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> u32 { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - let _ = numbers.pop_front(); - numbers.append(1_u32); - *numbers.at(0) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_append = { + let mut generator = SierraGenerator::::default(); - assert_eq!(result, jit_enum!(0, jit_struct!(3u32.into()))); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_get = { + let mut generator = SierraGenerator::::default(); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let array = [4, 3].into(); + // pop_front -> enum( struct( [array, poped_value] ) ) + let Value::Enum { value, .. } = run_sierra_program(&program_pop, &[array]).return_value + else { + panic!("pop_front should return an enum"); + }; + // pop_front success path returns an struct the a vector: [rem_array, popped_value] + let Value::Struct { fields, .. } = *value else { + panic!("enum should contain an struct"); + }; + let result = run_sierra_program(&program_append, &[fields[0].clone(), Value::Uint32(1)]) + .return_value; + let result = run_sierra_program(&program_get, &[result, Value::Uint32(0)]).return_value; + + assert_eq!(result, jit_enum!(0, 3u32.into())); } #[test] fn run_pop_front_result() { - let program = load_cairo!( - use array::ArrayTrait; + let program_pop = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Option { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.pop_front() - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!(result, jit_enum!(0, 4u32.into())); + generator.build(&[GenericArg::Type(u32_ty)]) + }; - let program = load_cairo!( - use array::ArrayTrait; + let array = [4, 3].into(); + let result = run_sierra_program(&program_pop, &[array]).return_value; - fn run_test() -> Option { - let mut numbers = ArrayTrait::new(); - numbers.pop_front() - } + assert_eq!( + result, + jit_enum!(0, jit_struct!([3u32].into(), 4u32.into())) ); - let result = run_program(&program, "run_test", &[]).return_value; - assert_eq!(result, jit_enum!(1, jit_struct!())); + let result = run_sierra_program(&program_pop, &[Value::Array(vec![])]).return_value; + + assert_eq!(result, jit_enum!(1, Value::Array(vec![]))); } #[test] fn run_pop_front_consume() { - let program = load_cairo!( - use array::ArrayTrait; + let program_pop = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> u32 { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - match numbers.pop_front_consume() { - Option::Some((_, x)) => x, - Option::None(()) => 0_u32, - } - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!(result, 4u32.into()); - } + generator.build(&[GenericArg::Type(u32_ty)]) + }; - #[test] - fn run_pop_back() { - let program = load_cairo!( - use array::ArrayTrait; + let array = [4u32, 3u32].into(); - fn run_test() -> (Option<@u32>, Option<@u32>, Option<@u32>, Option<@u32>) { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.append(1_u32); - let mut numbers = numbers.span(); - ( - numbers.pop_back(), - numbers.pop_back(), - numbers.pop_back(), - numbers.pop_back(), - ) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let result = run_sierra_program(&program_pop, &[array]).return_value; assert_eq!( result, - jit_struct!( - jit_enum!(0, 1u32.into()), - jit_enum!(0, 3u32.into()), - jit_enum!(0, 4u32.into()), - jit_enum!( - 1, - Value::Struct { - fields: Vec::new(), - debug_name: None, - } - ), - ), + jit_enum!(0, jit_struct!([3u32].into(), 4u32.into())) ); } + #[test] + fn run_pop_back() { + let program_pop = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let array = [4u32, 3u32, 1u32].into(); + let Value::Enum { value, .. } = run_sierra_program(&program_pop, &[array]).return_value + else { + panic!("pop_front should return an enum"); + }; + let Value::Struct { fields, .. } = *value else { + panic!("enum should contain an struct"); + }; + assert_eq!(fields[1], 1u32.into()); + let Value::Enum { value, .. } = + run_sierra_program(&program_pop, &[fields[0].clone()]).return_value + else { + panic!("pop_front should return an enum"); + }; + // pop_front success path returns an struct the a vector: [rem_array, popped_value] + let Value::Struct { fields, .. } = *value else { + panic!("enum should contain an struct"); + }; + assert_eq!(fields[1], 3u32.into()); + let Value::Enum { value, .. } = + run_sierra_program(&program_pop, &[fields[0].clone()]).return_value + else { + panic!("pop_front should return an enum"); + }; + let Value::Struct { fields, .. } = *value else { + panic!("enum should contain an struct"); + }; + assert_eq!(fields[1], 4u32.into()); + let Value::Enum { value, .. } = + run_sierra_program(&program_pop, &[fields[0].clone()]).return_value + else { + panic!("pop_front should return an enum"); + }; + assert_eq!(*value, Value::Array(vec![])); + } + #[test] fn run_slice() { - let program = load_cairo!( - use array::Array; - use array::ArrayTrait; - use array::SpanTrait; - use option::OptionTrait; - use box::BoxTrait; + let program_get = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> u32 { - let mut data: Array = ArrayTrait::new(); // Alloca (freed). - data.append(1_u32); - data.append(2_u32); - data.append(3_u32); - data.append(4_u32); - let sp = data.span(); // Alloca (leaked). - let slice = sp.slice(1, 2); - data.append(5_u32); - data.append(5_u32); - data.append(5_u32); - data.append(5_u32); - data.append(5_u32); // Realloc (freed). - data.append(5_u32); - *slice.get(1).unwrap().unbox() - } + let u32_ty = generator.push_type_declaration::(&[]).clone(); - ); - let result = run_program(&program, "run_test", &[]).return_value; + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_slice = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let array = [4, 3, 1].into(); + + let Value::Enum { value, .. } = + run_sierra_program(&program_slice, &[array, Value::Uint32(1), Value::Uint32(2)]) + .return_value + else { + panic!("enum should contain an array") + }; + let result = run_sierra_program(&program_get, &[*value, Value::Uint32(0)]).return_value; - assert_eq!(result, jit_enum!(0, jit_struct!(3u32.into()))); + assert_eq!(result, jit_enum!(0, 3u32.into())); } #[test] fn run_slice_fail() { - let program = load_cairo!( - use array::Array; - use array::ArrayTrait; - use array::SpanTrait; - use option::OptionTrait; - use box::BoxTrait; + let program_slice = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> u32 { - let mut data: Array = ArrayTrait::new(); - data.append(1_u32); - data.append(2_u32); - data.append(3_u32); - data.append(4_u32); - let sp = data.span(); - let slice = sp.slice(1, 4); // oob - //data.append(5_u32); - *slice.get(0).unwrap().unbox() - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!( - result, - jit_panic!(felt252_str( - "1637570914057682275393755530660268060279989363" - )) - ); + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let array = [1, 2, 3, 4].into(); + + let Value::Enum { value, .. } = + run_sierra_program(&program_slice, &[array, Value::Uint32(1), Value::Uint32(4)]) + .return_value + else { + panic!("enum should contain an array") + }; + + assert_eq!(*value, jit_struct!()); } #[test] fn run_slice_empty_array() { - let program = load_cairo!( - fn run_test() -> Span { - let x: Span = array![].span(); - x.slice(0, 0) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let program_slice = { + let mut generator = SierraGenerator::::default(); - assert_eq!( - result, - Value::Enum { - tag: 0, - value: Box::new(Value::Struct { - fields: vec![Value::Struct { - fields: vec![Value::Array(vec![])], - debug_name: None, - }], - debug_name: None, - }), - debug_name: None - }, - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let Value::Enum { value, .. } = run_sierra_program( + &program_slice, + &[Value::Array(vec![]), Value::Uint32(0), Value::Uint32(0)], + ) + .return_value + else { + panic!("enum should contain an array") + }; + + assert_eq!(*value, Value::Array(vec![])); } #[test] @@ -1701,100 +1715,129 @@ mod test { #[test] fn seq_append1() { - let program = load_cairo!( - use array::ArrayTrait; + let program_append = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Array { - let mut data = ArrayTrait::new(); - data.append(1); - data - } - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; assert_eq!( - run_program(&program, "run_test", &[]).return_value, + run_sierra_program(&program_append, &[Value::Array(vec![]), Value::Uint32(1)]) + .return_value, Value::from([1u32]), ); } #[test] fn seq_append2() { - let program = load_cairo!( - use array::ArrayTrait; + let program_append = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Array { - let mut data = ArrayTrait::new(); - data.append(1); - data.append(2); - data - } - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let result = run_sierra_program(&program_append, &[Value::Array(vec![]), Value::Uint32(1)]) + .return_value; assert_eq!( - run_program(&program, "run_test", &[]).return_value, + run_sierra_program(&program_append, &[result, Value::Uint32(2)]).return_value, Value::from([1u32, 2u32]), ); } #[test] fn seq_append2_popf1() { - let program = load_cairo!( - use array::ArrayTrait; + let program_append = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Array { - let mut data = ArrayTrait::new(); - data.append(1); - data.append(2); - let _ = data.pop_front(); - data - } - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!( - run_program(&program, "run_test", &[]).return_value, - Value::from([2u32]), - ); + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_pop = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let result = run_sierra_program(&program_append, &[Value::Array(vec![]), Value::Uint32(1)]) + .return_value; + let result = run_sierra_program(&program_append, &[result, Value::Uint32(2)]).return_value; + let Value::Enum { value, .. } = run_sierra_program(&program_pop, &[result]).return_value + else { + panic!("should be an enum") + }; + let Value::Struct { fields, .. } = *value else { + panic!("should be an struct"); + }; + + assert_eq!(fields[0], Value::from([2u32]),); } #[test] fn seq_append2_popb1() { - let program = load_cairo!( - use array::ArrayTrait; + let program_append = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Span { - let mut data = ArrayTrait::new(); - data.append(1); - data.append(2); - let mut data = data.span(); - let _ = data.pop_back(); - data - } - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_pop = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let result = run_sierra_program(&program_append, &[Value::Array(vec![]), Value::Uint32(1)]) + .return_value; + let result = run_sierra_program(&program_append, &[result, Value::Uint32(2)]).return_value; + let result = run_sierra_program(&program_pop, &[result]).return_value; assert_eq!( - run_program(&program, "run_test", &[]).return_value, - jit_struct!([1u32].into()) + result, + jit_enum!(0, jit_struct!([1u32].into(), 2u32.into())) ); } #[test] fn seq_append1_popf1_append1() { - let program = load_cairo!( - use array::ArrayTrait; + let program_append = { + let mut generator = SierraGenerator::::default(); - fn run_test() -> Array { - let mut data = ArrayTrait::new(); - data.append(1); - let _ = data.pop_front(); - data.append(2); - data - } - ); + let u32_ty = generator.push_type_declaration::(&[]).clone(); - assert_eq!( - run_program(&program, "run_test", &[]).return_value, - Value::from([2u32]), - ); + generator.build(&[GenericArg::Type(u32_ty)]) + }; + let program_pop = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + generator.build(&[GenericArg::Type(u32_ty)]) + }; + + let array = Value::Array(vec![1u32.into()]); + + let Value::Enum { value, .. } = run_sierra_program(&program_pop, &[array]).return_value + else { + panic!("should be an enum") + }; + let Value::Struct { fields, .. } = *value else { + panic!("should be an struct"); + }; + let result = run_sierra_program(&program_append, &[fields[0].clone(), Value::Uint32(2)]) + .return_value; + + assert_eq!(result, Value::from([2u32]),); } #[test] @@ -1976,17 +2019,23 @@ mod test { #[test] fn array_empty_span() { - // Tests snapshot_take on a empty array. - let program = load_cairo!( - fn run_test() -> Span { - let x = ArrayTrait::new(); - x.span() - } - ); + let program_span = { + let mut generator = SierraGenerator::::default(); + + let u32_ty = generator.push_type_declaration::(&[]).clone(); + + let array_ty = generator + .push_type_declaration::(&[GenericArg::Type(u32_ty)]) + .clone(); + + generator.build(&[GenericArg::Type(array_ty)]) + }; + + let result = run_sierra_program(&program_span, &[Value::Array(vec![])]).return_value; assert_eq!( - run_program(&program, "run_test", &[]).return_value, - jit_struct!(Value::Array(vec![])), + result, + jit_struct!(Value::Array(vec![]), Value::Array(vec![])), ); } @@ -2101,39 +2150,50 @@ mod test { #[test] fn snapshot_multi_pop_front() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> (Span, @Box<[felt252; 3]>) { - let mut numbers = array![1, 2, 3, 4, 5, 6].span(); - let popped = numbers.multi_pop_front::<3>().unwrap(); - - (numbers, popped) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let program_multi = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; + let array = [ + Value::Felt252(1.into()), + Value::Felt252(2.into()), + Value::Felt252(3.into()), + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()), + ] + .into(); + + let result = run_sierra_program(&program_multi, &[array, Value::Uint32(3)]).return_value; assert_eq!( result, - // Panic result jit_enum!( 0, jit_struct!( - // Tuple + // Span of original array + Value::Array(vec![ + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()), + ]), + // Box of fixed array jit_struct!( - // Span of original array - jit_struct!(Value::Array(vec![ - Value::Felt252(4.into()), - Value::Felt252(5.into()), - Value::Felt252(6.into()), - ])), - // Box of fixed array - jit_struct!( - Value::Felt252(1.into()), - Value::Felt252(2.into()), - Value::Felt252(3.into()) - ), - ) + Value::Felt252(1.into()), + Value::Felt252(2.into()), + Value::Felt252(3.into()) + ), ) ) ); @@ -2141,50 +2201,63 @@ mod test { #[test] fn snapshot_failed_multi_pop_front() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> Span { - let mut numbers = array![1, 2].span(); - - // should fail (return none) - assert!(numbers.multi_pop_front::<3>().is_none()); - - numbers - } - ); + let program_multi = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; + let array = Value::Array(vec![Value::Felt252(1.into()), Value::Felt252(2.into())]); - let result = run_program(&program, "run_test", &[]).return_value; + let result = + run_sierra_program(&program_multi, &[array.clone(), Value::Uint32(3)]).return_value; assert_eq!( result, // Panic result - jit_enum!( - 0, - jit_struct!( - // Span of original array - jit_struct!(Value::Array(vec![ - Value::Felt252(1.into()), - Value::Felt252(2.into()), - ]),) - ) - ) + jit_enum!(1, array) ); } #[test] fn snapshot_multi_pop_back() { - let program = load_cairo!( - use array::ArrayTrait; + let program_multi_back = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; - fn run_test() -> (Span, @Box<[felt252; 3]>) { - let mut numbers = array![1, 2, 3, 4, 5, 6].span(); - let popped = numbers.multi_pop_back::<3>().unwrap(); + let array = [ + Value::Felt252(1.into()), + Value::Felt252(2.into()), + Value::Felt252(3.into()), + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()), + ] + .into(); - (numbers, popped) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let result = + run_sierra_program(&program_multi_back, &[array, Value::Uint32(3)]).return_value; assert_eq!( result, @@ -2192,20 +2265,17 @@ mod test { jit_enum!( 0, jit_struct!( - // Tuple + // Span of original array + Value::Array(vec![ + Value::Felt252(1.into()), + Value::Felt252(2.into()), + Value::Felt252(3.into()), + ]), + // Box of fixed array jit_struct!( - // Span of original array - jit_struct!(Value::Array(vec![ - Value::Felt252(1.into()), - Value::Felt252(2.into()), - Value::Felt252(3.into()), - ])), - // Box of fixed array - jit_struct!( - Value::Felt252(4.into()), - Value::Felt252(5.into()), - Value::Felt252(6.into()) - ), + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()) ) ) ) @@ -2214,51 +2284,104 @@ mod test { #[test] fn snapshot_failed_multi_pop_back() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> Span { - let mut numbers = array![1, 2].span(); + let program_multi = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; + let array = Value::Array(vec![Value::Felt252(1.into()), Value::Felt252(2.into())]); - // should fail (return none) - assert!(numbers.multi_pop_back::<3>().is_none()); + let result = + run_sierra_program(&program_multi, &[array.clone(), Value::Uint32(3)]).return_value; - numbers - } + assert_eq!( + result, + // Panic result + jit_enum!(1, array) ); + } - let result = run_program(&program, "run_test", &[]).return_value; + #[test] + fn snapshot_multi_pop_back_front() { + let program_multi_front = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; + let program_multi_back = { + let mut generator = SierraGenerator::::default(); + + let felt252_ty = generator.push_type_declaration::(&[]).clone(); + let struct_ty = generator + .push_type_declaration::(&[ + GenericArg::UserType(UserTypeId::from_string("Tuple")), + GenericArg::Type(felt252_ty.clone()), + GenericArg::Type(felt252_ty), + ]) + .clone(); + + generator.build(&[GenericArg::Type(struct_ty)]) + }; + let array = [ + Value::Felt252(1.into()), + Value::Felt252(2.into()), + Value::Felt252(3.into()), + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()), + ] + .into(); + let enum_res = + run_sierra_program(&program_multi_front, &[array, Value::Uint32(2)]).return_value; + let Value::Enum { value, .. } = enum_res.clone() else { + panic!("should be an enum"); + }; + // fields is a array -> [rem_array, popped_elem_array] + let Value::Struct { fields, .. } = *value else { + panic!("should be a struct"); + }; assert_eq!( - result, + enum_res, // Panic result jit_enum!( 0, jit_struct!( // Span of original array - jit_struct!(Value::Array(vec![ - Value::Felt252(1.into()), - Value::Felt252(2.into()), - ]),) + Value::Array(vec![ + Value::Felt252(3.into()), + Value::Felt252(4.into()), + Value::Felt252(5.into()), + Value::Felt252(6.into()), + ]), + // Box of fixed array + jit_struct!(Value::Felt252(1.into()), Value::Felt252(2.into())), ) ) ); - } - - #[test] - fn snapshot_multi_pop_back_front() { - let program = load_cairo!( - use array::ArrayTrait; - - fn run_test() -> (Span, @Box<[felt252; 2]>, @Box<[felt252; 2]>) { - let mut numbers = array![1, 2, 3, 4, 5, 6].span(); - let popped_front = numbers.multi_pop_front::<2>().unwrap(); - let popped_back = numbers.multi_pop_back::<2>().unwrap(); - (numbers, popped_front, popped_back) - } - ); - let result = run_program(&program, "run_test", &[]).return_value; + let result = + run_sierra_program(&program_multi_back, &[fields[0].clone(), Value::Uint32(2)]) + .return_value; assert_eq!( result, @@ -2266,18 +2389,10 @@ mod test { jit_enum!( 0, jit_struct!( - // Tuple - jit_struct!( - // Span of original array - jit_struct!(Value::Array(vec![ - Value::Felt252(3.into()), - Value::Felt252(4.into()), - ])), - // Box of fixed array - jit_struct!(Value::Felt252(1.into()), Value::Felt252(2.into()),), - // Box of fixed array - jit_struct!(Value::Felt252(5.into()), Value::Felt252(6.into())), - ) + // Span of original array + Value::Array(vec![Value::Felt252(3.into()), Value::Felt252(4.into()),]), + // Box of fixed array + jit_struct!(Value::Felt252(5.into()), Value::Felt252(6.into()),), ) ) ); diff --git a/src/utils.rs b/src/utils.rs index 1dda89185..cd918c362 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -622,6 +622,34 @@ pub mod test { .unwrap() } + // This function receives a sierra program and runs its first entrypoint + // It is used primarely along with the sierra generator + // The difference between this function and run_program is that the latter + // also receives the name of the entrypoint to run + pub fn run_sierra_program(program: &Program, args: &[Value]) -> ExecutionResult { + let entry_point_id = &program + .funcs + .first() + .expect("program entry point not found.") + .id; + + let context = NativeContext::new(); + + let module = context + .compile(program, false, Some(Default::default())) + .expect("Could not compile test program to MLIR."); + + let executor = JitNativeExecutor::from_native_module(module, OptLevel::Less).unwrap(); + executor + .invoke_dynamic_with_syscall_handler( + entry_point_id, + args, + Some(u64::MAX), + &mut StubSyscallHandler::default(), + ) + .unwrap() + } + #[track_caller] pub fn run_program_assert_output( program: &(String, Program), diff --git a/src/values.rs b/src/values.rs index 7e7c8ecf9..36e9af130 100644 --- a/src/values.rs +++ b/src/values.rs @@ -170,6 +170,16 @@ impl Value { ) -> Result, Error> { let ty = registry.get_type(type_id)?; + match ty { + CoreTypeConcrete::Box(info) + | CoreTypeConcrete::NonZero(info) + | CoreTypeConcrete::Nullable(info) + | CoreTypeConcrete::Snapshot(info) => { + return self.to_ptr(arena, registry, &info.ty, find_dict_drop_override); + } + _ => {} + } + Ok(unsafe { match self { Self::Felt252(value) => { @@ -747,9 +757,7 @@ impl Value { CoreTypeConcrete::Uint32(_) => Self::Uint32(*ptr.cast::().as_ref()), CoreTypeConcrete::Uint64(_) => Self::Uint64(*ptr.cast::().as_ref()), CoreTypeConcrete::Uint128(_) => Self::Uint128(*ptr.cast::().as_ref()), - CoreTypeConcrete::Uint128MulGuarantee(_) => { - native_panic!("todo: implement uint128mulguarantee from_ptr") - } + CoreTypeConcrete::Uint128MulGuarantee(_) => Self::Null, CoreTypeConcrete::Sint8(_) => Self::Sint8(*ptr.cast::().as_ref()), CoreTypeConcrete::Sint16(_) => Self::Sint16(*ptr.cast::().as_ref()), CoreTypeConcrete::Sint32(_) => Self::Sint32(*ptr.cast::().as_ref()),