From 1f7ec56d57a56be1fe65b70b2110671b8c70c1fd Mon Sep 17 00:00:00 2001 From: Lior Goldberg Date: Tue, 27 Aug 2024 21:45:36 +0300 Subject: [PATCH] Modify int_range_try_new to return an empty range on failure. commit-id:312d2d4b --- corelib/src/ops/range.cairo | 6 +- .../src/invocations/range.rs | 2 +- .../src/extensions/modules/range.rs | 13 +- tests/e2e_test_data/libfuncs/range | 264 ++++++++---------- 4 files changed, 124 insertions(+), 161 deletions(-) diff --git a/corelib/src/ops/range.cairo b/corelib/src/ops/range.cairo index 8555e8041fe..d55927474f7 100644 --- a/corelib/src/ops/range.cairo +++ b/corelib/src/ops/range.cairo @@ -79,7 +79,7 @@ mod internal { pub extern type IntRange; pub extern fn int_range_try_new( x: T, y: T - ) -> Option> implicits(core::RangeCheck) nopanic; + ) -> Result, IntRange> implicits(core::RangeCheck) nopanic; pub extern fn int_range_pop_front(range: IntRange) -> OptionRev<(IntRange, T)> nopanic; impl IntRangeIteratorImpl, +Drop> of Iterator> { @@ -107,8 +107,8 @@ impl SierraRangeIntoIterator< fn into_iter(self: Range) -> Self::IntoIter { match internal::int_range_try_new(self.start, self.end) { - Option::Some(range) => range, - Option::None => internal::int_range_try_new(self.end, self.end).unwrap(), + Result::Ok(range) => range, + Result::Err(range) => range, } } } diff --git a/crates/cairo-lang-sierra-to-casm/src/invocations/range.rs b/crates/cairo-lang-sierra-to-casm/src/invocations/range.rs index 7cd40294f20..29e10e639da 100644 --- a/crates/cairo-lang-sierra-to-casm/src/invocations/range.rs +++ b/crates/cairo-lang-sierra-to-casm/src/invocations/range.rs @@ -58,7 +58,7 @@ fn build_try_new( casm_builder, [ ("Fallthrough", &[&[range_check], &[start, end]], None), - ("Failure", &[&[range_check]], Some(failure_handle)), + ("Failure", &[&[range_check], &[end, end]], Some(failure_handle)), ], CostValidationInfo { builtin_infos: vec![BuiltinInfo { diff --git a/crates/cairo-lang-sierra/src/extensions/modules/range.rs b/crates/cairo-lang-sierra/src/extensions/modules/range.rs index 687e14f264a..4b73d342a69 100644 --- a/crates/cairo-lang-sierra/src/extensions/modules/range.rs +++ b/crates/cairo-lang-sierra/src/extensions/modules/range.rs @@ -79,7 +79,8 @@ define_libfunc_hierarchy! { }, IntRangeConcreteLibfunc } -/// Libfunc that constructs the range `[x, y)` if `x <= y` and fails otherwise. +/// Libfunc that constructs the range `[x, y)` if `x <= y`. +/// Otherwise, returns the empty range `[y, y)`. #[derive(Default)] pub struct IntRangeTryNewLibfunc {} impl SignatureOnlyGenericLibfunc for IntRangeTryNewLibfunc { @@ -110,7 +111,7 @@ impl SignatureOnlyGenericLibfunc for IntRangeTryNewLibfunc { vars: vec![ OutputVarInfo::new_builtin(range_check_type.clone(), 0), OutputVarInfo { - ty: range_ty, + ty: range_ty.clone(), ref_info: OutputVarReferenceInfo::SimpleDerefs, }, ], @@ -118,7 +119,13 @@ impl SignatureOnlyGenericLibfunc for IntRangeTryNewLibfunc { }, // Failure. BranchSignature { - vars: vec![OutputVarInfo::new_builtin(range_check_type, 0)], + vars: vec![ + OutputVarInfo::new_builtin(range_check_type, 0), + OutputVarInfo { + ty: range_ty, + ref_info: OutputVarReferenceInfo::SimpleDerefs, + }, + ], ap_change: SierraApChange::Known { new_vars_only: false }, }, ], diff --git a/tests/e2e_test_data/libfuncs/range b/tests/e2e_test_data/libfuncs/range index 8d4652f02ec..160923fb3db 100644 --- a/tests/e2e_test_data/libfuncs/range +++ b/tests/e2e_test_data/libfuncs/range @@ -67,7 +67,7 @@ SmallE2ETestRunner //! > cairo use core::ops::range::internal::{IntRange, int_range_try_new}; -fn foo(x: i16, y: i16) -> Option> { +fn foo(x: i16, y: i16) -> Result, IntRange> { int_range_try_new(x, y) } @@ -87,8 +87,8 @@ ap += 1; ret; [ap + 0] = [fp + -5] + 1, ap++; [ap + 0] = 1, ap++; -[ap + 0] = 0, ap++; -[ap + 0] = 0, ap++; +[ap + 0] = [fp + -3], ap++; +[ap + 0] = [fp + -3], ap++; ret; //! > function_costs @@ -96,33 +96,30 @@ test::foo: OrderedHashMap({Const: 970}) //! > sierra_code type RangeCheck = RangeCheck [storable: true, drop: false, dup: false, zero_sized: false]; -type Unit = Struct [storable: true, drop: true, dup: true, zero_sized: true]; type IntRange = IntRange [storable: true, drop: true, dup: true, zero_sized: false]; -type core::option::Option::> = Enum>, IntRange, Unit> [storable: true, drop: true, dup: true, zero_sized: false]; +type core::result::Result::, core::ops::range::internal::IntRange::> = Enum, core::ops::range::internal::IntRange::>, IntRange, IntRange> [storable: true, drop: true, dup: true, zero_sized: false]; type i16 = i16 [storable: true, drop: true, dup: true, zero_sized: false]; libfunc int_range_try_new = int_range_try_new; libfunc branch_align = branch_align; -libfunc enum_init>, 0> = enum_init>, 0>; +libfunc enum_init, core::ops::range::internal::IntRange::>, 0> = enum_init, core::ops::range::internal::IntRange::>, 0>; libfunc store_temp = store_temp; -libfunc store_temp>> = store_temp>>; -libfunc struct_construct = struct_construct; -libfunc enum_init>, 1> = enum_init>, 1>; +libfunc store_temp, core::ops::range::internal::IntRange::>> = store_temp, core::ops::range::internal::IntRange::>>; +libfunc enum_init, core::ops::range::internal::IntRange::>, 1> = enum_init, core::ops::range::internal::IntRange::>, 1>; -int_range_try_new([0], [1], [2]) { fallthrough([3], [4]) 6([5]) }; // 0 +int_range_try_new([0], [1], [2]) { fallthrough([3], [4]) 6([5], [6]) }; // 0 branch_align() -> (); // 1 -enum_init>, 0>([4]) -> ([6]); // 2 +enum_init, core::ops::range::internal::IntRange::>, 0>([4]) -> ([7]); // 2 store_temp([3]) -> ([3]); // 3 -store_temp>>([6]) -> ([6]); // 4 -return([3], [6]); // 5 +store_temp, core::ops::range::internal::IntRange::>>([7]) -> ([7]); // 4 +return([3], [7]); // 5 branch_align() -> (); // 6 -struct_construct() -> ([7]); // 7 -enum_init>, 1>([7]) -> ([8]); // 8 -store_temp([5]) -> ([5]); // 9 -store_temp>>([8]) -> ([8]); // 10 -return([5], [8]); // 11 +enum_init, core::ops::range::internal::IntRange::>, 1>([6]) -> ([8]); // 7 +store_temp([5]) -> ([5]); // 8 +store_temp, core::ops::range::internal::IntRange::>>([8]) -> ([8]); // 9 +return([5], [8]); // 10 -test::foo@0([0]: RangeCheck, [1]: i16, [2]: i16) -> (RangeCheck, core::option::Option::>); +test::foo@0([0]: RangeCheck, [1]: i16, [2]: i16) -> (RangeCheck, core::result::Result::, core::ops::range::internal::IntRange::>); //! > ========================================================================== @@ -153,24 +150,15 @@ jmp rel 9; [ap + 0] = [fp + -4] + 1, ap++; [ap + 0] = [ap + -5], ap++; [ap + 0] = [ap + -5], ap++; -jmp rel 19; -[ap + 0] = 10, ap++; -[ap + 0] = 10, ap++; -[ap + -1] = [ap + 0] + [ap + -2], ap++; -%{ memory[ap + 0] = memory[ap + -1] < 340282366920938463463374607431768211456 %} -jmp rel 7 if [ap + 0] != 0, ap++; -[ap + 0] = [ap + -2] + 340282366920938463463374607431768211456, ap++; -[ap + -1] = [[fp + -4] + 1]; -jmp rel 31; -[ap + -2] = [[fp + -4] + 1]; -[ap + 0] = [fp + -4] + 2, ap++; -[ap + 0] = [ap + -5], ap++; +jmp rel 6; +[ap + 0] = [fp + -4] + 1, ap++; [ap + 0] = [ap + -5], ap++; +[ap + 0] = [ap + -6], ap++; [ap + 0] = [ap + -3], ap++; [ap + 0] = [fp + -3], ap++; [ap + 0] = [ap + -4], ap++; [ap + 0] = [ap + -4], ap++; -call rel 34; +call rel 20; jmp rel 11 if [ap + -3] != 0; [ap + 0] = [ap + -5], ap++; [ap + 0] = [ap + -5], ap++; @@ -184,16 +172,6 @@ ret; [ap + 0] = [ap + -5], ap++; [ap + 0] = [ap + -5], ap++; ret; -%{ memory[ap + 0] = segments.add() %} -ap += 1; -[ap + 0] = 29721761890975875353235833581453094220424382983267374, ap++; -[ap + -1] = [[ap + -2] + 0]; -[ap + 0] = [fp + -4] + 2, ap++; -[ap + 0] = [fp + -3], ap++; -[ap + 0] = 1, ap++; -[ap + 0] = [ap + -5], ap++; -[ap + 0] = [ap + -6] + 1, ap++; -ret; %{ memory[ap + 0] = 1870 <= memory[fp + -5] %} jmp rel 7 if [ap + 0] != 0, ap++; [ap + 0] = [fp + -5] + 340282366920938463463374607431768209586, ap++; @@ -239,13 +217,12 @@ ret; //! > sierra_code type u8 = u8 [storable: true, drop: true, dup: true, zero_sized: false]; -type Const = Const [storable: false, drop: false, dup: false, zero_sized: false]; -type Unit = Struct [storable: true, drop: true, dup: true, zero_sized: true]; -type core::option::Option:: = Enum, u8, Unit> [storable: true, drop: true, dup: true, zero_sized: false]; type core::panics::Panic = Struct [storable: true, drop: true, dup: true, zero_sized: true]; -type Const = Const [storable: false, drop: false, dup: false, zero_sized: false]; +type Const = Const [storable: false, drop: false, dup: false, zero_sized: false]; type felt252 = felt252 [storable: true, drop: true, dup: true, zero_sized: false]; type Array = Array [storable: true, drop: true, dup: false, zero_sized: false]; +type Unit = Struct [storable: true, drop: true, dup: true, zero_sized: true]; +type core::option::Option:: = Enum, u8, Unit> [storable: true, drop: true, dup: true, zero_sized: false]; type Tuple = Struct [storable: true, drop: true, dup: true, zero_sized: true]; type Tuple> = Struct> [storable: true, drop: true, dup: false, zero_sized: false]; type core::panics::PanicResult::<((),)> = Enum, Tuple, Tuple>> [storable: true, drop: true, dup: false, zero_sized: false]; @@ -260,11 +237,9 @@ type Const = Const [storable: false, drop: false, dup: false, zero libfunc disable_ap_tracking = disable_ap_tracking; libfunc const_as_immediate> = const_as_immediate>; libfunc const_as_immediate> = const_as_immediate>; -libfunc dup = dup; libfunc store_temp = store_temp; libfunc int_range_try_new = int_range_try_new; libfunc branch_align = branch_align; -libfunc drop = drop; libfunc store_temp = store_temp; libfunc store_temp> = store_temp>; libfunc jump = jump; @@ -277,12 +252,6 @@ libfunc struct_construct> = struct_construct>; libfunc enum_init, 0> = enum_init, 0>; libfunc store_temp> = store_temp>; libfunc enum_init, 1> = enum_init, 1>; -libfunc array_new = array_new; -libfunc const_as_immediate> = const_as_immediate>; -libfunc store_temp = store_temp; -libfunc array_append = array_append; -libfunc struct_construct = struct_construct; -libfunc struct_construct>> = struct_construct>>; libfunc withdraw_gas = withdraw_gas; libfunc enable_ap_tracking = enable_ap_tracking; libfunc dup> = dup>; @@ -292,119 +261,106 @@ libfunc enum_init, 1> = enum_init> = store_temp>; libfunc enum_init, 0> = enum_init, 0>; libfunc enum_match> = enum_match>; +libfunc drop = drop; libfunc drop = drop; libfunc struct_construct, Unit>> = struct_construct, Unit>>; libfunc enum_init, ())>, 0> = enum_init, ())>, 0>; libfunc store_temp, ())>> = store_temp, ())>>; +libfunc array_new = array_new; libfunc const_as_immediate> = const_as_immediate>; +libfunc store_temp = store_temp; +libfunc array_append = array_append; +libfunc struct_construct = struct_construct; +libfunc struct_construct>> = struct_construct>>; libfunc enum_init, ())>, 1> = enum_init, ())>, 1>; disable_ap_tracking() -> (); // 0 const_as_immediate>() -> ([2]); // 1 const_as_immediate>() -> ([3]); // 2 -dup([3]) -> ([3], [4]); // 3 -store_temp([2]) -> ([2]); // 4 -store_temp([4]) -> ([4]); // 5 -int_range_try_new([0], [2], [4]) { fallthrough([5], [6]) 12([7]) }; // 6 -branch_align() -> (); // 7 -drop([3]) -> (); // 8 -store_temp([5]) -> ([8]); // 9 -store_temp>([6]) -> ([9]); // 10 -jump() { 20() }; // 11 -branch_align() -> (); // 12 -dup([3]) -> ([3], [10]); // 13 -store_temp([10]) -> ([10]); // 14 -store_temp([3]) -> ([3]); // 15 -int_range_try_new([7], [10], [3]) { fallthrough([11], [12]) 40([13]) }; // 16 -branch_align() -> (); // 17 -store_temp([11]) -> ([8]); // 18 -store_temp>([12]) -> ([9]); // 19 -store_temp([8]) -> ([8]); // 20 -store_temp([1]) -> ([1]); // 21 -store_temp>([9]) -> ([9]); // 22 -function_call([8], [1], [9]) -> ([14], [15], [16]); // 23 -enum_match, ())>>([16]) { fallthrough([17]) 34([18]) }; // 24 -branch_align() -> (); // 25 -struct_deconstruct, Unit>>([17]) -> ([19], [20]); // 26 -drop>([19]) -> (); // 27 -struct_construct>([20]) -> ([21]); // 28 -enum_init, 0>([21]) -> ([22]); // 29 -store_temp([14]) -> ([14]); // 30 -store_temp([15]) -> ([15]); // 31 -store_temp>([22]) -> ([22]); // 32 -return([14], [15], [22]); // 33 -branch_align() -> (); // 34 -enum_init, 1>([18]) -> ([23]); // 35 -store_temp([14]) -> ([14]); // 36 -store_temp([15]) -> ([15]); // 37 -store_temp>([23]) -> ([23]); // 38 -return([14], [15], [23]); // 39 +store_temp([2]) -> ([2]); // 3 +store_temp([3]) -> ([3]); // 4 +int_range_try_new([0], [2], [3]) { fallthrough([4], [5]) 10([6], [7]) }; // 5 +branch_align() -> (); // 6 +store_temp([4]) -> ([8]); // 7 +store_temp>([5]) -> ([9]); // 8 +jump() { 13() }; // 9 +branch_align() -> (); // 10 +store_temp([6]) -> ([8]); // 11 +store_temp>([7]) -> ([9]); // 12 +store_temp([8]) -> ([8]); // 13 +store_temp([1]) -> ([1]); // 14 +store_temp>([9]) -> ([9]); // 15 +function_call([8], [1], [9]) -> ([10], [11], [12]); // 16 +enum_match, ())>>([12]) { fallthrough([13]) 27([14]) }; // 17 +branch_align() -> (); // 18 +struct_deconstruct, Unit>>([13]) -> ([15], [16]); // 19 +drop>([15]) -> (); // 20 +struct_construct>([16]) -> ([17]); // 21 +enum_init, 0>([17]) -> ([18]); // 22 +store_temp([10]) -> ([10]); // 23 +store_temp([11]) -> ([11]); // 24 +store_temp>([18]) -> ([18]); // 25 +return([10], [11], [18]); // 26 +branch_align() -> (); // 27 +enum_init, 1>([14]) -> ([19]); // 28 +store_temp([10]) -> ([10]); // 29 +store_temp([11]) -> ([11]); // 30 +store_temp>([19]) -> ([19]); // 31 +return([10], [11], [19]); // 32 +disable_ap_tracking() -> (); // 33 +withdraw_gas([0], [1]) { fallthrough([3], [4]) 70([5], [6]) }; // 34 +branch_align() -> (); // 35 +enable_ap_tracking() -> (); // 36 +dup>([2]) -> ([2], [7]); // 37 +store_temp([3]) -> ([3]); // 38 +int_range_pop_front([7]) { fallthrough() 46([8], [9]) }; // 39 branch_align() -> (); // 40 -array_new() -> ([24]); // 41 -const_as_immediate>() -> ([25]); // 42 -store_temp([25]) -> ([25]); // 43 -array_append([24], [25]) -> ([26]); // 44 -struct_construct() -> ([27]); // 45 -struct_construct>>([27], [26]) -> ([28]); // 46 -enum_init, 1>([28]) -> ([29]); // 47 -store_temp([13]) -> ([13]); // 48 -store_temp([1]) -> ([1]); // 49 -store_temp>([29]) -> ([29]); // 50 -return([13], [1], [29]); // 51 -disable_ap_tracking() -> (); // 52 -withdraw_gas([0], [1]) { fallthrough([3], [4]) 89([5], [6]) }; // 53 -branch_align() -> (); // 54 -enable_ap_tracking() -> (); // 55 -dup>([2]) -> ([2], [7]); // 56 -store_temp([3]) -> ([3]); // 57 -int_range_pop_front([7]) { fallthrough() 65([8], [9]) }; // 58 -branch_align() -> (); // 59 -struct_construct() -> ([10]); // 60 -enum_init, 1>([10]) -> ([11]); // 61 -store_temp>([2]) -> ([12]); // 62 -store_temp>([11]) -> ([13]); // 63 -jump() { 70() }; // 64 -branch_align() -> (); // 65 -drop>([2]) -> (); // 66 -enum_init, 0>([9]) -> ([14]); // 67 -store_temp>([8]) -> ([12]); // 68 -store_temp>([14]) -> ([13]); // 69 -enum_match>([13]) { fallthrough([15]) 79([16]) }; // 70 -branch_align() -> (); // 71 -disable_ap_tracking() -> (); // 72 -drop([15]) -> (); // 73 -store_temp([3]) -> ([3]); // 74 -store_temp([4]) -> ([4]); // 75 -store_temp>([12]) -> ([12]); // 76 -function_call([3], [4], [12]) -> ([17], [18], [19]); // 77 -return([17], [18], [19]); // 78 -branch_align() -> (); // 79 -disable_ap_tracking() -> (); // 80 -drop([16]) -> (); // 81 -struct_construct() -> ([20]); // 82 -struct_construct, Unit>>([12], [20]) -> ([21]); // 83 -enum_init, ())>, 0>([21]) -> ([22]); // 84 -store_temp([3]) -> ([3]); // 85 -store_temp([4]) -> ([4]); // 86 -store_temp, ())>>([22]) -> ([22]); // 87 -return([3], [4], [22]); // 88 -branch_align() -> (); // 89 -drop>([2]) -> (); // 90 -array_new() -> ([23]); // 91 -const_as_immediate>() -> ([24]); // 92 -store_temp([24]) -> ([24]); // 93 -array_append([23], [24]) -> ([25]); // 94 -struct_construct() -> ([26]); // 95 -struct_construct>>([26], [25]) -> ([27]); // 96 -enum_init, ())>, 1>([27]) -> ([28]); // 97 -store_temp([5]) -> ([5]); // 98 -store_temp([6]) -> ([6]); // 99 -store_temp, ())>>([28]) -> ([28]); // 100 -return([5], [6], [28]); // 101 +struct_construct() -> ([10]); // 41 +enum_init, 1>([10]) -> ([11]); // 42 +store_temp>([2]) -> ([12]); // 43 +store_temp>([11]) -> ([13]); // 44 +jump() { 51() }; // 45 +branch_align() -> (); // 46 +drop>([2]) -> (); // 47 +enum_init, 0>([9]) -> ([14]); // 48 +store_temp>([8]) -> ([12]); // 49 +store_temp>([14]) -> ([13]); // 50 +enum_match>([13]) { fallthrough([15]) 60([16]) }; // 51 +branch_align() -> (); // 52 +disable_ap_tracking() -> (); // 53 +drop([15]) -> (); // 54 +store_temp([3]) -> ([3]); // 55 +store_temp([4]) -> ([4]); // 56 +store_temp>([12]) -> ([12]); // 57 +function_call([3], [4], [12]) -> ([17], [18], [19]); // 58 +return([17], [18], [19]); // 59 +branch_align() -> (); // 60 +disable_ap_tracking() -> (); // 61 +drop([16]) -> (); // 62 +struct_construct() -> ([20]); // 63 +struct_construct, Unit>>([12], [20]) -> ([21]); // 64 +enum_init, ())>, 0>([21]) -> ([22]); // 65 +store_temp([3]) -> ([3]); // 66 +store_temp([4]) -> ([4]); // 67 +store_temp, ())>>([22]) -> ([22]); // 68 +return([3], [4], [22]); // 69 +branch_align() -> (); // 70 +drop>([2]) -> (); // 71 +array_new() -> ([23]); // 72 +const_as_immediate>() -> ([24]); // 73 +store_temp([24]) -> ([24]); // 74 +array_append([23], [24]) -> ([25]); // 75 +struct_construct() -> ([26]); // 76 +struct_construct>>([26], [25]) -> ([27]); // 77 +enum_init, ())>, 1>([27]) -> ([28]); // 78 +store_temp([5]) -> ([5]); // 79 +store_temp([6]) -> ([6]); // 80 +store_temp, ())>>([28]) -> ([28]); // 81 +return([5], [6], [28]); // 82 test::foo@0([0]: RangeCheck, [1]: GasBuiltin) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<((),)>); -test::foo[expr5]@52([0]: RangeCheck, [1]: GasBuiltin, [2]: IntRange) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<(core::ops::range::internal::IntRange::, ())>); +test::foo[expr5]@33([0]: RangeCheck, [1]: GasBuiltin, [2]: IntRange) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<(core::ops::range::internal::IntRange::, ())>); //! > function_costs -test::foo: OrderedHashMap({Const: 4110}) +test::foo: OrderedHashMap({Const: 3540}) test::foo[expr5]: OrderedHashMap({Const: 1270})