From 0803ed1960cd05b4d23ba1612bf65455efee733e Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 11 Jul 2023 22:59:28 +0530 Subject: [PATCH 1/8] Introduce reversed in Array type --- runtime/interpreter/value.go | 45 +++++ runtime/sema/type.go | 40 ++++ .../tests/checker/arrays_dictionaries_test.go | 49 +++++ runtime/tests/interpreter/interpreter_test.go | 175 ++++++++++++++++++ 4 files changed, 309 insertions(+) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 6d96bebbe5..0d9f084856 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2429,6 +2429,20 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR ) }, ) + + case sema.ArrayTypeReversedFunctionName: + return NewHostFunctionValue( + interpreter, + sema.ArrayReversedFunctionType( + v.SemaType(interpreter).ElementType(false), + ), + func(invocation Invocation) Value { + return v.Reversed( + invocation.Interpreter, + invocation.LocationRange, + ) + }, + ) } return nil @@ -2900,6 +2914,37 @@ func (v *ArrayValue) Slice( ) } +func (v *ArrayValue) Reversed( + interpreter *Interpreter, + locationRange LocationRange, +) Value { + count := v.Count() + idx := count - 1 + + return NewArrayValueWithIterator( + interpreter, + NewVariableSizedStaticType(interpreter, v.Type.ElementType()), + common.ZeroAddress, + uint64(count), + func() Value { + if idx < 0 { + return nil + } + + value := v.Get(interpreter, locationRange, idx) + idx-- + + return value.Transfer( + interpreter, + locationRange, + atree.Address{}, + false, + nil, + ) + }, + ) +} + // NumberValue type NumberValue interface { ComparableValue diff --git a/runtime/sema/type.go b/runtime/sema/type.go index b5a6d31c54..d2248dac40 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1788,6 +1788,12 @@ It does not modify the original array. If either of the parameters are out of the bounds of the array, or the indices are invalid (` + "`from > upTo`" + `), then the function will fail. ` +const ArrayTypeReversedFunctionName = "reversed" + +const arrayTypeReversedFunctionDocString = ` +Returns a new array with contents in the reversed order. +` + func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { members := map[string]MemberResolver{ @@ -1881,6 +1887,31 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { ) }, }, + ArrayTypeReversedFunctionName: { + Kind: common.DeclarationKindFunction, + Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { + elementType := arrayType.ElementType(false) + + // It is impossible for a resource to be present in two arrays. + if elementType.IsResourceType() { + report( + &InvalidResourceArrayMemberError{ + Name: identifier, + DeclarationKind: common.DeclarationKindFunction, + Range: targetRange, + }, + ) + } + + return NewPublicFunctionMember( + memoryGauge, + arrayType, + identifier, + ArrayReversedFunctionType(elementType), + arrayTypeReversedFunctionDocString, + ) + }, + }, } // TODO: maybe still return members but report a helpful error? @@ -2193,6 +2224,15 @@ func ArraySliceFunctionType(elementType Type) *FunctionType { } } +func ArrayReversedFunctionType(elementType Type) *FunctionType { + return &FunctionType{ + Parameters: []Parameter{}, + ReturnTypeAnnotation: NewTypeAnnotation(&VariableSizedType{ + Type: elementType, + }), + } +} + // VariableSizedType is a variable sized array type type VariableSizedType struct { Type Type diff --git a/runtime/tests/checker/arrays_dictionaries_test.go b/runtime/tests/checker/arrays_dictionaries_test.go index ad551e260b..bf83cb9994 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1078,6 +1078,55 @@ func TestCheckInvalidResourceFirstIndex(t *testing.T) { assert.IsType(t, &sema.ResourceLossError{}, errs[2]) } +func TestCheckArrayReversed(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + fun test() { + let x = [1, 2, 3] + let y = x.reversed() + } + `) + + require.NoError(t, err) +} + +func TestCheckArrayReversedInvalidArgs(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + fun test() { + let x = [1, 2, 3] + let y = x.reversed(100) + } + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.ArgumentCountError{}, errs[0]) +} + +func TestCheckResourceArrayReversedInvalid(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + resource X {} + + fun test(): @[X] { + let xs <- [<-create X()] + return <-xs.reversed() + } + `) + + errs := RequireCheckerErrors(t, err, 2) + + assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0]) + assert.IsType(t, &sema.ResourceLossError{}, errs[1]) +} + func TestCheckArrayContains(t *testing.T) { t.Parallel() diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index c90f6e181e..e5a2c38a03 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10507,6 +10507,181 @@ func TestInterpretArrayFirstIndexDoesNotExist(t *testing.T) { ) } +func TestInterpretArrayReversed(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + let xs = [1, 2, 3, 100, 200] + let ys = [100, 467, 297, 23] + let emptyVals: [Int] = [] + + fun reversedxs(): [Int] { + return xs.reversed() + } + fun originalxs(): [Int] { + return xs + } + + fun reversedys(): [Int] { + return ys.reversed() + } + fun originalys(): [Int] { + return ys + } + + fun reverseempty(): [Int] { + return emptyVals.reversed() + } + fun originalempty(): [Int] { + return emptyVals + } + + pub struct TestStruct { + pub var test: Int + + init(_ t: Int) { + self.test = t + } + } + + let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] + + fun reversedsa(): [Int] { + let sa_rev = sa.reversed() + + let res: [Int] = []; + for s in sa_rev { + res.append(s.test) + } + + return res + } + fun originalsa(): [Int] { + let res: [Int] = []; + for s in sa { + res.append(s.test) + } + + return res + } + `) + + runValidCase := func(t *testing.T, reverseFuncName, originalFuncName string, reversedArray, originalArray *interpreter.ArrayValue) { + val, err := inter.Invoke(reverseFuncName) + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + reversedArray, + val, + ) + + origVal, err := inter.Invoke(originalFuncName) + require.NoError(t, err) + + // Original array remains unchanged + AssertValuesEqual( + t, + inter, + originalArray, + origVal, + ) + } + + runValidCase(t, "reverseempty", "originalempty", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + )) + + runValidCase(t, "reversedxs", "originalxs", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(200), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(1), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(200), + )) + + runValidCase(t, "reversedys", "originalys", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(23), + interpreter.NewUnmeteredIntValueFromInt64(297), + interpreter.NewUnmeteredIntValueFromInt64(467), + interpreter.NewUnmeteredIntValueFromInt64(100), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(467), + interpreter.NewUnmeteredIntValueFromInt64(297), + interpreter.NewUnmeteredIntValueFromInt64(23), + )) + + runValidCase(t, "reversedsa", "originalsa", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(1), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + )) +} + func TestInterpretOptionalReference(t *testing.T) { t.Parallel() From 34549f7641aaa6dfca2f24a32f5ed4d015c91132 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 11 Jul 2023 23:33:23 +0530 Subject: [PATCH 2/8] Rename function to reverse from reversed --- runtime/interpreter/value.go | 8 +++---- runtime/sema/type.go | 13 ++++++----- .../tests/checker/arrays_dictionaries_test.go | 12 +++++----- runtime/tests/interpreter/interpreter_test.go | 22 +++++++++---------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 0d9f084856..1f2cb01bec 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2430,14 +2430,14 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR }, ) - case sema.ArrayTypeReversedFunctionName: + case sema.ArrayTypeReverseFunctionName: return NewHostFunctionValue( interpreter, - sema.ArrayReversedFunctionType( + sema.ArrayReverseFunctionType( v.SemaType(interpreter).ElementType(false), ), func(invocation Invocation) Value { - return v.Reversed( + return v.Reverse( invocation.Interpreter, invocation.LocationRange, ) @@ -2914,7 +2914,7 @@ func (v *ArrayValue) Slice( ) } -func (v *ArrayValue) Reversed( +func (v *ArrayValue) Reverse( interpreter *Interpreter, locationRange LocationRange, ) Value { diff --git a/runtime/sema/type.go b/runtime/sema/type.go index d2248dac40..95e5a3af64 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1788,10 +1788,11 @@ It does not modify the original array. If either of the parameters are out of the bounds of the array, or the indices are invalid (` + "`from > upTo`" + `), then the function will fail. ` -const ArrayTypeReversedFunctionName = "reversed" +const ArrayTypeReverseFunctionName = "reverse" -const arrayTypeReversedFunctionDocString = ` +const arrayTypeReverseFunctionDocString = ` Returns a new array with contents in the reversed order. +Available if the array element type is not resource-kinded. ` func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { @@ -1887,7 +1888,7 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { ) }, }, - ArrayTypeReversedFunctionName: { + ArrayTypeReverseFunctionName: { Kind: common.DeclarationKindFunction, Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { elementType := arrayType.ElementType(false) @@ -1907,8 +1908,8 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { memoryGauge, arrayType, identifier, - ArrayReversedFunctionType(elementType), - arrayTypeReversedFunctionDocString, + ArrayReverseFunctionType(elementType), + arrayTypeReverseFunctionDocString, ) }, }, @@ -2224,7 +2225,7 @@ func ArraySliceFunctionType(elementType Type) *FunctionType { } } -func ArrayReversedFunctionType(elementType Type) *FunctionType { +func ArrayReverseFunctionType(elementType Type) *FunctionType { return &FunctionType{ Parameters: []Parameter{}, ReturnTypeAnnotation: NewTypeAnnotation(&VariableSizedType{ diff --git a/runtime/tests/checker/arrays_dictionaries_test.go b/runtime/tests/checker/arrays_dictionaries_test.go index bf83cb9994..961c57cbf6 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1078,28 +1078,28 @@ func TestCheckInvalidResourceFirstIndex(t *testing.T) { assert.IsType(t, &sema.ResourceLossError{}, errs[2]) } -func TestCheckArrayReversed(t *testing.T) { +func TestCheckArrayReverse(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` fun test() { let x = [1, 2, 3] - let y = x.reversed() + let y = x.reverse() } `) require.NoError(t, err) } -func TestCheckArrayReversedInvalidArgs(t *testing.T) { +func TestCheckArrayReverseInvalidArgs(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` fun test() { let x = [1, 2, 3] - let y = x.reversed(100) + let y = x.reverse(100) } `) @@ -1108,7 +1108,7 @@ func TestCheckArrayReversedInvalidArgs(t *testing.T) { assert.IsType(t, &sema.ArgumentCountError{}, errs[0]) } -func TestCheckResourceArrayReversedInvalid(t *testing.T) { +func TestCheckResourceArrayReverseInvalid(t *testing.T) { t.Parallel() @@ -1117,7 +1117,7 @@ func TestCheckResourceArrayReversedInvalid(t *testing.T) { fun test(): @[X] { let xs <- [<-create X()] - return <-xs.reversed() + return <-xs.reverse() } `) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index e5a2c38a03..af46cd2f24 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10507,7 +10507,7 @@ func TestInterpretArrayFirstIndexDoesNotExist(t *testing.T) { ) } -func TestInterpretArrayReversed(t *testing.T) { +func TestInterpretArrayReverse(t *testing.T) { t.Parallel() inter := parseCheckAndInterpret(t, ` @@ -10515,22 +10515,22 @@ func TestInterpretArrayReversed(t *testing.T) { let ys = [100, 467, 297, 23] let emptyVals: [Int] = [] - fun reversedxs(): [Int] { - return xs.reversed() + fun reversexs(): [Int] { + return xs.reverse() } fun originalxs(): [Int] { return xs } - fun reversedys(): [Int] { - return ys.reversed() + fun reverseys(): [Int] { + return ys.reverse() } fun originalys(): [Int] { return ys } fun reverseempty(): [Int] { - return emptyVals.reversed() + return emptyVals.reverse() } fun originalempty(): [Int] { return emptyVals @@ -10546,8 +10546,8 @@ func TestInterpretArrayReversed(t *testing.T) { let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] - fun reversedsa(): [Int] { - let sa_rev = sa.reversed() + fun reversesa(): [Int] { + let sa_rev = sa.reverse() let res: [Int] = []; for s in sa_rev { @@ -10606,7 +10606,7 @@ func TestInterpretArrayReversed(t *testing.T) { common.ZeroAddress, )) - runValidCase(t, "reversedxs", "originalxs", + runValidCase(t, "reversexs", "originalxs", interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, @@ -10633,7 +10633,7 @@ func TestInterpretArrayReversed(t *testing.T) { interpreter.NewUnmeteredIntValueFromInt64(200), )) - runValidCase(t, "reversedys", "originalys", + runValidCase(t, "reverseys", "originalys", interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, @@ -10658,7 +10658,7 @@ func TestInterpretArrayReversed(t *testing.T) { interpreter.NewUnmeteredIntValueFromInt64(23), )) - runValidCase(t, "reversedsa", "originalsa", + runValidCase(t, "reversesa", "originalsa", interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, From 84e7a9e4b7a21e9f920e178efb3558ed30850b8b Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Mon, 17 Jul 2023 02:03:30 +0530 Subject: [PATCH 3/8] Use v.Type instead of creating new type. Co-authored-by: Supun Setunga --- runtime/interpreter/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 1f2cb01bec..35b0b19838 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2923,7 +2923,7 @@ func (v *ArrayValue) Reverse( return NewArrayValueWithIterator( interpreter, - NewVariableSizedStaticType(interpreter, v.Type.ElementType()), + v.Type, common.ZeroAddress, uint64(count), func() Value { From bbb3bdd0763fb46a92d82136b3a20216691b234f Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Mon, 17 Jul 2023 02:05:36 +0530 Subject: [PATCH 4/8] reformat to tabs --- runtime/tests/interpreter/interpreter_test.go | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index af46cd2f24..b4dc3ad856 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10511,60 +10511,60 @@ func TestInterpretArrayReverse(t *testing.T) { t.Parallel() inter := parseCheckAndInterpret(t, ` - let xs = [1, 2, 3, 100, 200] - let ys = [100, 467, 297, 23] - let emptyVals: [Int] = [] - - fun reversexs(): [Int] { - return xs.reverse() - } - fun originalxs(): [Int] { - return xs - } - - fun reverseys(): [Int] { - return ys.reverse() - } - fun originalys(): [Int] { - return ys - } - - fun reverseempty(): [Int] { - return emptyVals.reverse() - } - fun originalempty(): [Int] { - return emptyVals - } - - pub struct TestStruct { - pub var test: Int - - init(_ t: Int) { - self.test = t + let xs = [1, 2, 3, 100, 200] + let ys = [100, 467, 297, 23] + let emptyVals: [Int] = [] + + fun reversexs(): [Int] { + return xs.reverse() + } + fun originalxs(): [Int] { + return xs } - } - let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] - - fun reversesa(): [Int] { - let sa_rev = sa.reverse() - - let res: [Int] = []; - for s in sa_rev { - res.append(s.test) + fun reverseys(): [Int] { + return ys.reverse() } - - return res - } - fun originalsa(): [Int] { - let res: [Int] = []; - for s in sa { - res.append(s.test) + fun originalys(): [Int] { + return ys } - - return res - } - `) + + fun reverseempty(): [Int] { + return emptyVals.reverse() + } + fun originalempty(): [Int] { + return emptyVals + } + + pub struct TestStruct { + pub var test: Int + + init(_ t: Int) { + self.test = t + } + } + + let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] + + fun reversesa(): [Int] { + let sa_rev = sa.reverse() + + let res: [Int] = []; + for s in sa_rev { + res.append(s.test) + } + + return res + } + fun originalsa(): [Int] { + let res: [Int] = []; + for s in sa { + res.append(s.test) + } + + return res + } + `) runValidCase := func(t *testing.T, reverseFuncName, originalFuncName string, reversedArray, originalArray *interpreter.ArrayValue) { val, err := inter.Invoke(reverseFuncName) From 344ce6a1097e98f08dd0c85292048f67c36a8385 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Mon, 17 Jul 2023 02:47:31 +0530 Subject: [PATCH 5/8] add tests for fixed-sized array and fix return type of function --- runtime/interpreter/value.go | 3 +- runtime/sema/type.go | 10 +- .../tests/checker/arrays_dictionaries_test.go | 2 +- runtime/tests/interpreter/interpreter_test.go | 233 +++++++++++------- 4 files changed, 153 insertions(+), 95 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 35b0b19838..781aa349dd 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2434,7 +2434,7 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR return NewHostFunctionValue( interpreter, sema.ArrayReverseFunctionType( - v.SemaType(interpreter).ElementType(false), + v.SemaType(interpreter), ), func(invocation Invocation) Value { return v.Reverse( @@ -2940,6 +2940,7 @@ func (v *ArrayValue) Reverse( atree.Address{}, false, nil, + nil, ) }, ) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 95e5a3af64..3b6f32054b 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1908,7 +1908,7 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { memoryGauge, arrayType, identifier, - ArrayReverseFunctionType(elementType), + ArrayReverseFunctionType(arrayType), arrayTypeReverseFunctionDocString, ) }, @@ -2225,12 +2225,10 @@ func ArraySliceFunctionType(elementType Type) *FunctionType { } } -func ArrayReverseFunctionType(elementType Type) *FunctionType { +func ArrayReverseFunctionType(arrayType Type) *FunctionType { return &FunctionType{ - Parameters: []Parameter{}, - ReturnTypeAnnotation: NewTypeAnnotation(&VariableSizedType{ - Type: elementType, - }), + Parameters: []Parameter{}, + ReturnTypeAnnotation: NewTypeAnnotation(arrayType), } } diff --git a/runtime/tests/checker/arrays_dictionaries_test.go b/runtime/tests/checker/arrays_dictionaries_test.go index 961c57cbf6..3fbe9c2b56 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1105,7 +1105,7 @@ func TestCheckArrayReverseInvalidArgs(t *testing.T) { errs := RequireCheckerErrors(t, err, 1) - assert.IsType(t, &sema.ArgumentCountError{}, errs[0]) + assert.IsType(t, &sema.ExcessiveArgumentsError{}, errs[0]) } func TestCheckResourceArrayReverseInvalid(t *testing.T) { diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index b4dc3ad856..2ef3540596 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10513,7 +10513,10 @@ func TestInterpretArrayReverse(t *testing.T) { inter := parseCheckAndInterpret(t, ` let xs = [1, 2, 3, 100, 200] let ys = [100, 467, 297, 23] + let xs_fixed: [Int; 5] = [1, 2, 3, 100, 200] + let ys_fixed: [Int; 4] = [100, 467, 297, 23] let emptyVals: [Int] = [] + let emptyVals_fixed: [Int; 0] = [] fun reversexs(): [Int] { return xs.reverse() @@ -10529,6 +10532,20 @@ func TestInterpretArrayReverse(t *testing.T) { return ys } + fun reversexs_fixed(): [Int; 5] { + return xs_fixed.reverse() + } + fun originalxs_fixed(): [Int; 5] { + return xs_fixed + } + + fun reverseys_fixed(): [Int; 4] { + return ys_fixed.reverse() + } + fun originalys_fixed(): [Int; 4] { + return ys_fixed + } + fun reverseempty(): [Int] { return emptyVals.reverse() } @@ -10536,6 +10553,13 @@ func TestInterpretArrayReverse(t *testing.T) { return emptyVals } + fun reverseempty_fixed(): [Int; 0] { + return emptyVals_fixed.reverse() + } + fun originalempty_fixed(): [Int; 0] { + return emptyVals_fixed + } + pub struct TestStruct { pub var test: Int @@ -10545,6 +10569,7 @@ func TestInterpretArrayReverse(t *testing.T) { } let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] + let sa_fixed: [TestStruct; 3] = [TestStruct(1), TestStruct(2), TestStruct(3)] fun reversesa(): [Int] { let sa_rev = sa.reverse() @@ -10559,7 +10584,26 @@ func TestInterpretArrayReverse(t *testing.T) { fun originalsa(): [Int] { let res: [Int] = []; for s in sa { - res.append(s.test) + res.append(s.test) + } + + return res + } + + fun reversesa_fixed(): [Int] { + let sa_rev = sa_fixed.reverse() + + let res: [Int] = []; + for s in sa_rev { + res.append(s.test) + } + + return res + } + fun originalsa_fixed(): [Int] { + let res: [Int] = []; + for s in sa_fixed { + res.append(s.test) } return res @@ -10589,97 +10633,112 @@ func TestInterpretArrayReverse(t *testing.T) { ) } - runValidCase(t, "reverseempty", "originalempty", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - )) + for _, suffix := range []string{"_fixed", ""} { + fixed := suffix == "_fixed" - runValidCase(t, "reversexs", "originalxs", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ + var arrayType interpreter.ArrayStaticType + if fixed { + arrayType = &interpreter.ConstantSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(200), - interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(3), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(1), - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ + } + } else { + arrayType = &interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(1), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(3), - interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(200), - )) + } + } - runValidCase(t, "reverseys", "originalys", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(23), - interpreter.NewUnmeteredIntValueFromInt64(297), - interpreter.NewUnmeteredIntValueFromInt64(467), - interpreter.NewUnmeteredIntValueFromInt64(100), - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(467), - interpreter.NewUnmeteredIntValueFromInt64(297), - interpreter.NewUnmeteredIntValueFromInt64(23), - )) + setFixedSize := func(size int64) { + if fixed { + constSized, ok := arrayType.(*interpreter.ConstantSizedStaticType) + assert.True(t, ok) - runValidCase(t, "reversesa", "originalsa", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(3), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(1), - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(1), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(3), - )) + constSized.Size = size + } + } + + setFixedSize(0) + runValidCase(t, "reverseempty"+suffix, "originalempty"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + )) + + setFixedSize(5) + runValidCase(t, "reversexs"+suffix, "originalxs"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(200), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(1), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(200), + )) + + setFixedSize(4) + runValidCase(t, "reverseys"+suffix, "originalys"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(23), + interpreter.NewUnmeteredIntValueFromInt64(297), + interpreter.NewUnmeteredIntValueFromInt64(467), + interpreter.NewUnmeteredIntValueFromInt64(100), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + arrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(467), + interpreter.NewUnmeteredIntValueFromInt64(297), + interpreter.NewUnmeteredIntValueFromInt64(23), + )) + + runValidCase(t, "reversesa"+suffix, "originalsa"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(1), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + )) + } } func TestInterpretOptionalReference(t *testing.T) { From f774a65e6e2e1544cbd4f655f41d688492effb7c Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Wed, 19 Jul 2023 19:49:04 +0530 Subject: [PATCH 6/8] Ensure ArrayReverseFunctionType only accepts sema.ArrayType Co-authored-by: Supun Setunga --- runtime/sema/type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 3b6f32054b..77f005aa2d 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -2225,7 +2225,7 @@ func ArraySliceFunctionType(elementType Type) *FunctionType { } } -func ArrayReverseFunctionType(arrayType Type) *FunctionType { +func ArrayReverseFunctionType(arrayType sema.ArrayType) *FunctionType { return &FunctionType{ Parameters: []Parameter{}, ReturnTypeAnnotation: NewTypeAnnotation(arrayType), From 3960890ebf052ab92760eeaa184101e100d3b108 Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Wed, 19 Jul 2023 19:49:22 +0530 Subject: [PATCH 7/8] Use "index" instead of "idx" Co-authored-by: Supun Setunga --- runtime/interpreter/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 781aa349dd..1869a025dc 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2919,7 +2919,7 @@ func (v *ArrayValue) Reverse( locationRange LocationRange, ) Value { count := v.Count() - idx := count - 1 + index := count - 1 return NewArrayValueWithIterator( interpreter, From 4d42e5fb64d0598e37cefb9b0c1723c7602f33dd Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Wed, 19 Jul 2023 20:01:15 +0530 Subject: [PATCH 8/8] Improve test case --- runtime/interpreter/value.go | 6 +++--- runtime/sema/type.go | 2 +- runtime/tests/checker/arrays_dictionaries_test.go | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 1869a025dc..6b11e3737a 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2927,12 +2927,12 @@ func (v *ArrayValue) Reverse( common.ZeroAddress, uint64(count), func() Value { - if idx < 0 { + if index < 0 { return nil } - value := v.Get(interpreter, locationRange, idx) - idx-- + value := v.Get(interpreter, locationRange, index) + index-- return value.Transfer( interpreter, diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 77f005aa2d..e57342f501 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -2225,7 +2225,7 @@ func ArraySliceFunctionType(elementType Type) *FunctionType { } } -func ArrayReverseFunctionType(arrayType sema.ArrayType) *FunctionType { +func ArrayReverseFunctionType(arrayType ArrayType) *FunctionType { return &FunctionType{ Parameters: []Parameter{}, ReturnTypeAnnotation: NewTypeAnnotation(arrayType), diff --git a/runtime/tests/checker/arrays_dictionaries_test.go b/runtime/tests/checker/arrays_dictionaries_test.go index 3fbe9c2b56..a7d47a673e 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1117,14 +1117,15 @@ func TestCheckResourceArrayReverseInvalid(t *testing.T) { fun test(): @[X] { let xs <- [<-create X()] - return <-xs.reverse() + let revxs <-xs.reverse() + destroy xs + return <- revxs } `) - errs := RequireCheckerErrors(t, err, 2) + errs := RequireCheckerErrors(t, err, 1) assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0]) - assert.IsType(t, &sema.ResourceLossError{}, errs[1]) } func TestCheckArrayContains(t *testing.T) {