From 19dbd0ec78cc297f942aa9a29f7a566f7dad09f2 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Mon, 24 Jul 2023 22:45:15 +0530 Subject: [PATCH 1/7] Introduce filter in VariableSizedArray type --- runtime/interpreter/value.go | 97 +++++++++++ runtime/sema/type.go | 60 +++++++ .../tests/checker/arrays_dictionaries_test.go | 103 ++++++++++++ runtime/tests/interpreter/interpreter_test.go | 153 ++++++++++++++++++ 4 files changed, 413 insertions(+) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 6b11e3737a..7767571b24 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2443,6 +2443,28 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR ) }, ) + + case sema.ArrayTypeFilterFunctionName: + return NewHostFunctionValue( + interpreter, + sema.ArrayFilterFunctionType( + v.SemaType(interpreter).ElementType(false), + ), + func(invocation Invocation) Value { + interpreter := invocation.Interpreter + + funcArgument, ok := invocation.Arguments[0].(FunctionValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + return v.Filter( + interpreter, + invocation.LocationRange, + funcArgument, + ) + }, + ) } return nil @@ -2946,6 +2968,81 @@ func (v *ArrayValue) Reverse( ) } +func (v *ArrayValue) Filter( + interpreter *Interpreter, + locationRange LocationRange, + procedure FunctionValue, +) Value { + filteredValues := make([]Value, 0) + filteredValuesCount := 0 + i := 0 + + iterationInvocation := func(arrayElement Value) Invocation { + return NewInvocation( + interpreter, + nil, + nil, + []Value{arrayElement}, + []sema.Type{sema.BoolType}, + nil, + locationRange, + ) + } + + iterate := func() { + err := v.array.Iterate( + func(item atree.Value) (bool, error) { + arrayElement := MustConvertStoredValue(interpreter, item) + + shouldInclude, ok := procedure.invoke(iterationInvocation(arrayElement)).(BoolValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + if shouldInclude { + filteredValues = append(filteredValues, arrayElement) + filteredValuesCount++ + } + + i++ + return true, nil + }, + ) + + if err != nil { + panic(errors.NewExternalError(err)) + } + } + + iterate() + + iterationIndex := 0 + return NewArrayValueWithIterator( + interpreter, + NewVariableSizedStaticType(interpreter, v.Type.ElementType()), + common.ZeroAddress, + uint64(filteredValuesCount), + func() Value { + + if iterationIndex == filteredValuesCount { + return nil + } + + value := filteredValues[iterationIndex] + iterationIndex++ + + return value.Transfer( + interpreter, + locationRange, + atree.Address{}, + false, + nil, + nil, + ) + }, + ) +} + // NumberValue type NumberValue interface { ComparableValue diff --git a/runtime/sema/type.go b/runtime/sema/type.go index e57342f501..80d3e4e1d6 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1795,6 +1795,13 @@ Returns a new array with contents in the reversed order. Available if the array element type is not resource-kinded. ` +const ArrayTypeFilterFunctionName = "filter" + +const arrayTypeFilterFunctionDocString = ` +Returns a new array whose elements are filtered by applying the filter function on each element of the original array. +Available if the array element type is not resource-kinded. +` + func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { members := map[string]MemberResolver{ @@ -2083,6 +2090,32 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { ) }, } + + members[ArrayTypeFilterFunctionName] = MemberResolver{ + Kind: common.DeclarationKindFunction, + Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { + + elementType := arrayType.ElementType(false) + + if elementType.IsResourceType() { + report( + &InvalidResourceArrayMemberError{ + Name: identifier, + DeclarationKind: common.DeclarationKindFunction, + Range: targetRange, + }, + ) + } + + return NewPublicFunctionMember( + memoryGauge, + arrayType, + identifier, + ArrayFilterFunctionType(elementType), + arrayTypeFilterFunctionDocString, + ) + }, + } } return withBuiltinMembers(arrayType, members) @@ -2232,6 +2265,33 @@ func ArrayReverseFunctionType(arrayType ArrayType) *FunctionType { } } +func ArrayFilterFunctionType(elementType Type) *FunctionType { + // fun filter(_ function: ((T): Bool)): [T] + // funcType: elementType -> Bool + funcType := &FunctionType{ + Parameters: []Parameter{ + { + Identifier: "element", + TypeAnnotation: NewTypeAnnotation(elementType), + }, + }, + ReturnTypeAnnotation: NewTypeAnnotation(BoolType), + } + + return &FunctionType{ + Parameters: []Parameter{ + { + Label: ArgumentLabelNotRequired, + Identifier: "f", + TypeAnnotation: NewTypeAnnotation(funcType), + }, + }, + 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 a7d47a673e..cfea7f1c34 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1128,6 +1128,109 @@ func TestCheckResourceArrayReverseInvalid(t *testing.T) { assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0]) } +func TestCheckArrayFilter(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + fun test() { + let x = [1, 2, 3] + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + let y = x.filter(onlyEven) + } + `) + + require.NoError(t, err) +} + +func TestCheckArrayFilterInvalidArgs(t *testing.T) { + + t.Parallel() + + testInvalidArgs := func(code string, expectedErrors []sema.SemanticError) { + _, err := ParseAndCheck(t, code) + + errs := RequireCheckerErrors(t, err, len(expectedErrors)) + + for i, e := range expectedErrors { + assert.IsType(t, e, errs[i]) + } + } + + testInvalidArgs(` + fun test() { + let x = [1, 2, 3] + let y = x.filter(100) + } + `, + []sema.SemanticError{ + &sema.TypeMismatchError{}, + }, + ) + + testInvalidArgs(` + fun test() { + let x = [1, 2, 3] + let onlyEvenInt16 = + fun (_ x: Int16): Bool { + return x % 2 == 0 + } + + let y = x.filter(onlyEvenInt16) + } + `, + []sema.SemanticError{ + &sema.TypeMismatchError{}, + }, + ) + + testInvalidArgs(` + fun test() { + let x : [Int; 5] = [1, 2, 3, 21, 30] + let onlyEvenInt = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + let y = x.filter(onlyEvenInt) + } + `, + []sema.SemanticError{ + &sema.NotDeclaredMemberError{}, + }, + ) +} + +func TestCheckResourceArrayFilterInvalid(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + resource X {} + + fun test(): @[X] { + let xs <- [<-create X()] + let allResources = + fun (_ x: @X): Bool { + destroy x + return true + } + + let filteredXs <-xs.filter(allResources) + destroy xs + return <- filteredXs + } + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0]) +} + func TestCheckArrayContains(t *testing.T) { t.Parallel() diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 2ef3540596..a876b86d2e 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10741,6 +10741,159 @@ func TestInterpretArrayReverse(t *testing.T) { } } +func TestInterpretArrayFilter(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + let xs = [1, 2, 3, 100, 200] + let emptyVals: [Int] = [] + + fun filterxs(): [Int] { + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + return xs.filter(onlyEven) + } + fun originalxs(): [Int] { + return xs + } + + fun filterempty(): [Int] { + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + return emptyVals.filter(onlyEven) + } + 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 filtersa(): [Int] { + let onlyOdd = + fun (_ x: TestStruct): Bool { + return x.test % 2 == 1 + } + + let sa_filtered = sa.filter(onlyOdd) + + let res: [Int] = []; + for s in sa_filtered { + 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, filterFuncName, originalFuncName string, filteredArray, originalArray *interpreter.ArrayValue) { + val, err := inter.Invoke(filterFuncName) + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + filteredArray, + val, + ) + + origVal, err := inter.Invoke(originalFuncName) + require.NoError(t, err) + + // Original array remains unchanged + AssertValuesEqual( + t, + inter, + originalArray, + origVal, + ) + } + + runValidCase(t, "filterempty", "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, "filterxs", "originalxs", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(200), + ), 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, "filtersa", "originalsa", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(3), + ), 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 ae5936a69c72d4847162c3332c52aa4e3ff93262 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sun, 30 Jul 2023 01:52:17 +0530 Subject: [PATCH 2/7] Also support fixed sized array types --- runtime/sema/type.go | 51 ++-- .../tests/checker/arrays_dictionaries_test.go | 26 +- runtime/tests/interpreter/interpreter_test.go | 259 +++++++++++------- 3 files changed, 190 insertions(+), 146 deletions(-) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 80d3e4e1d6..6cc205609d 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1920,6 +1920,31 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { ) }, }, + ArrayTypeFilterFunctionName: { + Kind: common.DeclarationKindFunction, + Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { + + elementType := arrayType.ElementType(false) + + if elementType.IsResourceType() { + report( + &InvalidResourceArrayMemberError{ + Name: identifier, + DeclarationKind: common.DeclarationKindFunction, + Range: targetRange, + }, + ) + } + + return NewPublicFunctionMember( + memoryGauge, + arrayType, + identifier, + ArrayFilterFunctionType(elementType), + arrayTypeFilterFunctionDocString, + ) + }, + }, } // TODO: maybe still return members but report a helpful error? @@ -2090,32 +2115,6 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { ) }, } - - members[ArrayTypeFilterFunctionName] = MemberResolver{ - Kind: common.DeclarationKindFunction, - Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { - - elementType := arrayType.ElementType(false) - - if elementType.IsResourceType() { - report( - &InvalidResourceArrayMemberError{ - Name: identifier, - DeclarationKind: common.DeclarationKindFunction, - Range: targetRange, - }, - ) - } - - return NewPublicFunctionMember( - memoryGauge, - arrayType, - identifier, - ArrayFilterFunctionType(elementType), - arrayTypeFilterFunctionDocString, - ) - }, - } } return withBuiltinMembers(arrayType, members) diff --git a/runtime/tests/checker/arrays_dictionaries_test.go b/runtime/tests/checker/arrays_dictionaries_test.go index cfea7f1c34..2b75256fa0 100644 --- a/runtime/tests/checker/arrays_dictionaries_test.go +++ b/runtime/tests/checker/arrays_dictionaries_test.go @@ -1142,6 +1142,16 @@ func TestCheckArrayFilter(t *testing.T) { let y = x.filter(onlyEven) } + + fun testFixedSize() { + let x : [Int; 5] = [1, 2, 3, 21, 30] + let onlyEvenInt = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + let y = x.filter(onlyEvenInt) + } `) require.NoError(t, err) @@ -1187,22 +1197,6 @@ func TestCheckArrayFilterInvalidArgs(t *testing.T) { &sema.TypeMismatchError{}, }, ) - - testInvalidArgs(` - fun test() { - let x : [Int; 5] = [1, 2, 3, 21, 30] - let onlyEvenInt = - fun (_ x: Int): Bool { - return x % 2 == 0 - } - - let y = x.filter(onlyEvenInt) - } - `, - []sema.SemanticError{ - &sema.NotDeclaredMemberError{}, - }, - ) } func TestCheckResourceArrayFilterInvalid(t *testing.T) { diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index a876b86d2e..03e86c6b03 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10745,68 +10745,99 @@ func TestInterpretArrayFilter(t *testing.T) { t.Parallel() inter := parseCheckAndInterpret(t, ` - let xs = [1, 2, 3, 100, 200] - let emptyVals: [Int] = [] + let xs = [1, 2, 3, 100, 200] + let xs_fixed: [Int; 5] = [1, 2, 3, 100, 200] + let emptyVals: [Int] = [] + let emptyVals_fixed: [Int; 0] = [] - fun filterxs(): [Int] { let onlyEven = fun (_ x: Int): Bool { return x % 2 == 0 } - return xs.filter(onlyEven) - } - fun originalxs(): [Int] { - return xs - } + fun filterxs(): [Int] { + return xs.filter(onlyEven) + } + fun originalxs(): [Int] { + return xs + } - fun filterempty(): [Int] { - let onlyEven = - fun (_ x: Int): Bool { - return x % 2 == 0 - } + fun filterxs_fixed(): [Int] { + return xs_fixed.filter(onlyEven) + } + fun originalxs_fixed(): [Int; 5] { + return xs_fixed + } + + fun filterempty(): [Int] { + return emptyVals.filter(onlyEven) + } + fun originalempty(): [Int] { + return emptyVals + } - return emptyVals.filter(onlyEven) - } - fun originalempty(): [Int] { - return emptyVals - } - - pub struct TestStruct { - pub var test: Int - - init(_ t: Int) { - self.test = t + fun filterempty_fixed(): [Int] { + return emptyVals_fixed.filter(onlyEven) } - } - let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] - - fun filtersa(): [Int] { - let onlyOdd = + fun originalempty_fixed(): [Int; 0] { + return emptyVals_fixed + } + + pub struct TestStruct { + pub var test: Int + + init(_ t: Int) { + self.test = t + } + } + + let onlyOddStruct = fun (_ x: TestStruct): Bool { return x.test % 2 == 1 } - let sa_filtered = sa.filter(onlyOdd) + let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] + let sa_fixed: [TestStruct; 3] = [TestStruct(1), TestStruct(2), TestStruct(3)] - let res: [Int] = []; - for s in sa_filtered { - res.append(s.test) + fun filtersa(): [Int] { + let sa_filtered = sa.filter(onlyOddStruct) + let res: [Int] = []; + for s in sa_filtered { + res.append(s.test) + } + return res + } + fun originalsa(): [Int] { + let res: [Int] = []; + for s in sa { + res.append(s.test) + } + return res } - - return res - } - fun originalsa(): [Int] { - let res: [Int] = []; - for s in sa { - res.append(s.test) + + fun filtersa_fixed(): [Int] { + let sa_rev = sa_fixed.filter(onlyOddStruct) + let res: [Int] = []; + for s in sa_rev { + res.append(s.test) + } + return res } - - return res - } - `) + fun originalsa_fixed(): [Int] { + let res: [Int] = []; + for s in sa_fixed { + res.append(s.test) + } + return res + } + `) - runValidCase := func(t *testing.T, filterFuncName, originalFuncName string, filteredArray, originalArray *interpreter.ArrayValue) { + runValidCase := func( + t *testing.T, + filterFuncName, + originalFuncName string, + filteredArray, originalArray *interpreter.ArrayValue, + ) { val, err := inter.Invoke(filterFuncName) require.NoError(t, err) @@ -10829,69 +10860,89 @@ func TestInterpretArrayFilter(t *testing.T) { ) } - runValidCase(t, "filterempty", "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, "filterxs", "originalxs", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ + var originalArrayType interpreter.ArrayStaticType + if fixed { + originalArrayType = &interpreter.ConstantSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(200), - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ + } + } else { + originalArrayType = &interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(1), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(3), - interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(200), - )) + } + } + // Return type is always variable sized array. + var returnArrayType = &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + } - runValidCase(t, "filtersa", "originalsa", - interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(1), - interpreter.NewUnmeteredIntValueFromInt64(3), - ), interpreter.NewArrayValue( - inter, - interpreter.EmptyLocationRange, - interpreter.VariableSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, - }, - common.ZeroAddress, - interpreter.NewUnmeteredIntValueFromInt64(1), - interpreter.NewUnmeteredIntValueFromInt64(2), - interpreter.NewUnmeteredIntValueFromInt64(3), - )) + setFixedSize := func(size int64) { + if fixed { + constSized, ok := originalArrayType.(*interpreter.ConstantSizedStaticType) + assert.True(t, ok) + + constSized.Size = size + } + } + + setFixedSize(0) + runValidCase(t, "filterempty"+suffix, "originalempty"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + returnArrayType, + common.ZeroAddress, + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + originalArrayType, + common.ZeroAddress, + )) + + setFixedSize(5) + runValidCase(t, "filterxs"+suffix, "originalxs"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + returnArrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(200), + ), interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + originalArrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(200), + )) + + runValidCase(t, "filtersa"+suffix, "originalsa"+suffix, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + returnArrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(3), + ), 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 ff1207f83ada34432951c46632fdc6360d2f84ef Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 1 Aug 2023 00:33:37 +0530 Subject: [PATCH 3/7] Address review comments --- runtime/interpreter/value.go | 94 +++++++++++-------- runtime/tests/interpreter/interpreter_test.go | 7 +- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 7767571b24..b0858ce317 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2973,50 +2973,46 @@ func (v *ArrayValue) Filter( locationRange LocationRange, procedure FunctionValue, ) Value { - filteredValues := make([]Value, 0) filteredValuesCount := 0 - i := 0 + invocation := NewInvocation( + interpreter, + nil, + nil, + []Value{}, // Set later during invocation. + []sema.Type{v.semaType.ElementType(false)}, + nil, + locationRange, + ) iterationInvocation := func(arrayElement Value) Invocation { - return NewInvocation( - interpreter, - nil, - nil, - []Value{arrayElement}, - []sema.Type{sema.BoolType}, - nil, - locationRange, - ) + invocation.Arguments = []Value{arrayElement} + return invocation } - iterate := func() { - err := v.array.Iterate( - func(item atree.Value) (bool, error) { - arrayElement := MustConvertStoredValue(interpreter, item) + iterator, err := v.array.Iterator() - shouldInclude, ok := procedure.invoke(iterationInvocation(arrayElement)).(BoolValue) - if !ok { - panic(errors.NewUnreachableError()) - } + i := 0 + err = v.array.Iterate( + func(item atree.Value) (bool, error) { + arrayElement := MustConvertStoredValue(interpreter, item) - if shouldInclude { - filteredValues = append(filteredValues, arrayElement) - filteredValuesCount++ - } + shouldInclude, ok := procedure.invoke(iterationInvocation(arrayElement)).(BoolValue) + if !ok { + panic(errors.NewUnreachableError()) + } - i++ - return true, nil - }, - ) + if shouldInclude { + filteredValuesCount++ + } - if err != nil { - panic(errors.NewExternalError(err)) - } + i++ + return true, nil + }, + ) + if err != nil { + panic(errors.NewExternalError(err)) } - iterate() - - iterationIndex := 0 return NewArrayValueWithIterator( interpreter, NewVariableSizedStaticType(interpreter, v.Type.ElementType()), @@ -3024,12 +3020,34 @@ func (v *ArrayValue) Filter( uint64(filteredValuesCount), func() Value { - if iterationIndex == filteredValuesCount { - return nil - } + var value Value + + for { + atreeValue, err := iterator.Next() + if err != nil { + panic(errors.NewExternalError(err)) + } + + // Also handles the end of array case since iterator.Next() returns nil for that. + if atreeValue == nil { + return nil + } + + value = MustConvertStoredValue(interpreter, atreeValue) + if value == nil { + return nil + } - value := filteredValues[iterationIndex] - iterationIndex++ + shouldInclude, ok := procedure.invoke(iterationInvocation(value)).(BoolValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + // We found the next entry of the filtered array. + if shouldInclude { + break + } + } return value.Transfer( interpreter, diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 03e86c6b03..ea0b4b0662 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10745,8 +10745,8 @@ func TestInterpretArrayFilter(t *testing.T) { t.Parallel() inter := parseCheckAndInterpret(t, ` - let xs = [1, 2, 3, 100, 200] - let xs_fixed: [Int; 5] = [1, 2, 3, 100, 200] + let xs = [1, 2, 3, 100, 201] + let xs_fixed: [Int; 5] = [1, 2, 3, 100, 201] let emptyVals: [Int] = [] let emptyVals_fixed: [Int; 0] = [] @@ -10910,7 +10910,6 @@ func TestInterpretArrayFilter(t *testing.T) { common.ZeroAddress, interpreter.NewUnmeteredIntValueFromInt64(2), interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(200), ), interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, @@ -10920,7 +10919,7 @@ func TestInterpretArrayFilter(t *testing.T) { interpreter.NewUnmeteredIntValueFromInt64(2), interpreter.NewUnmeteredIntValueFromInt64(3), interpreter.NewUnmeteredIntValueFromInt64(100), - interpreter.NewUnmeteredIntValueFromInt64(200), + interpreter.NewUnmeteredIntValueFromInt64(201), )) runValidCase(t, "filtersa"+suffix, "originalsa"+suffix, From 4cac1eb725aa0605f2c120a76b2b1825b0fed73e Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 1 Aug 2023 00:34:52 +0530 Subject: [PATCH 4/7] fix lint --- runtime/interpreter/value.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index b0858ce317..782673d4a3 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2989,10 +2989,8 @@ func (v *ArrayValue) Filter( return invocation } - iterator, err := v.array.Iterator() - i := 0 - err = v.array.Iterate( + err := v.array.Iterate( func(item atree.Value) (bool, error) { arrayElement := MustConvertStoredValue(interpreter, item) @@ -3013,6 +3011,11 @@ func (v *ArrayValue) Filter( panic(errors.NewExternalError(err)) } + iterator, err := v.array.Iterator() + if err != nil { + panic(errors.NewExternalError(err)) + } + return NewArrayValueWithIterator( interpreter, NewVariableSizedStaticType(interpreter, v.Type.ElementType()), From ae0b24600c3e4ace05b3a5f0a246440125d6efcc Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Tue, 1 Aug 2023 00:38:52 +0530 Subject: [PATCH 5/7] get rid of useless variable i --- runtime/interpreter/value.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 782673d4a3..f65c1d3b97 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2989,7 +2989,6 @@ func (v *ArrayValue) Filter( return invocation } - i := 0 err := v.array.Iterate( func(item atree.Value) (bool, error) { arrayElement := MustConvertStoredValue(interpreter, item) @@ -3003,7 +3002,6 @@ func (v *ArrayValue) Filter( filteredValuesCount++ } - i++ return true, nil }, ) From f9d584c433948f15175df368e5b35cc378c53abc Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Thu, 3 Aug 2023 23:22:22 +0530 Subject: [PATCH 6/7] Address review comments --- runtime/interpreter/value.go | 51 +++++++++++------------------------- runtime/sema/type.go | 8 +++--- 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index f65c1d3b97..ef81e143a1 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1607,7 +1607,7 @@ func NewArrayValueWithIterator( interpreter *Interpreter, arrayType ArrayStaticType, address common.Address, - count uint64, + countOverestimate uint64, values func() Value, ) *ArrayValue { interpreter.ReportComputation(common.ComputationKindCreateArrayValue, 1) @@ -1652,7 +1652,7 @@ func NewArrayValueWithIterator( return array } // must assign to v here for tracing to work properly - v = newArrayValueFromConstructor(interpreter, arrayType, count, constructor) + v = newArrayValueFromConstructor(interpreter, arrayType, countOverestimate, constructor) return v } @@ -1669,14 +1669,14 @@ func newArrayValueFromAtreeValue( func newArrayValueFromConstructor( gauge common.MemoryGauge, staticType ArrayStaticType, - count uint64, + countOverestimate uint64, constructor func() *atree.Array, ) (array *ArrayValue) { var elementSize uint if staticType != nil { elementSize = staticType.ElementType().elementSize() } - baseUsage, elementUsage, dataSlabs, metaDataSlabs := common.NewArrayMemoryUsages(count, elementSize) + baseUsage, elementUsage, dataSlabs, metaDataSlabs := common.NewArrayMemoryUsages(countOverestimate, elementSize) common.UseMemory(gauge, baseUsage) common.UseMemory(gauge, elementUsage) common.UseMemory(gauge, dataSlabs) @@ -2448,6 +2448,7 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR return NewHostFunctionValue( interpreter, sema.ArrayFilterFunctionType( + interpreter, v.SemaType(interpreter).ElementType(false), ), func(invocation Invocation) Value { @@ -2973,42 +2974,20 @@ func (v *ArrayValue) Filter( locationRange LocationRange, procedure FunctionValue, ) Value { - filteredValuesCount := 0 - invocation := NewInvocation( - interpreter, - nil, - nil, - []Value{}, // Set later during invocation. - []sema.Type{v.semaType.ElementType(false)}, - nil, - locationRange, - ) iterationInvocation := func(arrayElement Value) Invocation { - invocation.Arguments = []Value{arrayElement} + invocation := NewInvocation( + interpreter, + nil, + nil, + []Value{arrayElement}, + []sema.Type{v.semaType.ElementType(false)}, + nil, + locationRange, + ) return invocation } - err := v.array.Iterate( - func(item atree.Value) (bool, error) { - arrayElement := MustConvertStoredValue(interpreter, item) - - shouldInclude, ok := procedure.invoke(iterationInvocation(arrayElement)).(BoolValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - if shouldInclude { - filteredValuesCount++ - } - - return true, nil - }, - ) - if err != nil { - panic(errors.NewExternalError(err)) - } - iterator, err := v.array.Iterator() if err != nil { panic(errors.NewExternalError(err)) @@ -3018,7 +2997,7 @@ func (v *ArrayValue) Filter( interpreter, NewVariableSizedStaticType(interpreter, v.Type.ElementType()), common.ZeroAddress, - uint64(filteredValuesCount), + uint64(v.Count()), // worst case estimation. func() Value { var value Value diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 6cc205609d..a15eaed396 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -1940,7 +1940,7 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver { memoryGauge, arrayType, identifier, - ArrayFilterFunctionType(elementType), + ArrayFilterFunctionType(memoryGauge, elementType), arrayTypeFilterFunctionDocString, ) }, @@ -2264,7 +2264,7 @@ func ArrayReverseFunctionType(arrayType ArrayType) *FunctionType { } } -func ArrayFilterFunctionType(elementType Type) *FunctionType { +func ArrayFilterFunctionType(memoryGauge common.MemoryGauge, elementType Type) *FunctionType { // fun filter(_ function: ((T): Bool)): [T] // funcType: elementType -> Bool funcType := &FunctionType{ @@ -2285,9 +2285,7 @@ func ArrayFilterFunctionType(elementType Type) *FunctionType { TypeAnnotation: NewTypeAnnotation(funcType), }, }, - ReturnTypeAnnotation: NewTypeAnnotation(&VariableSizedType{ - Type: elementType, - }), + ReturnTypeAnnotation: NewTypeAnnotation(NewVariableSizedType(memoryGauge, elementType)), } } From 9c2eb9dbd38a2ee81368cec0c657f08112cbe2ab Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sat, 12 Aug 2023 19:54:28 +0530 Subject: [PATCH 7/7] Reuse type slice and reorganize tests --- runtime/interpreter/value.go | 3 +- runtime/tests/interpreter/interpreter_test.go | 385 ++++++++++++------ 2 files changed, 265 insertions(+), 123 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index ef81e143a1..10d5c82823 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2975,13 +2975,14 @@ func (v *ArrayValue) Filter( procedure FunctionValue, ) Value { + elementTypeSlice := []sema.Type{v.semaType.ElementType(false)} iterationInvocation := func(arrayElement Value) Invocation { invocation := NewInvocation( interpreter, nil, nil, []Value{arrayElement}, - []sema.Type{v.semaType.ElementType(false)}, + elementTypeSlice, nil, locationRange, ) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index ea0b4b0662..88dfd1063c 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -10742,98 +10742,10 @@ func TestInterpretArrayReverse(t *testing.T) { } func TestInterpretArrayFilter(t *testing.T) { - t.Parallel() - - inter := parseCheckAndInterpret(t, ` - let xs = [1, 2, 3, 100, 201] - let xs_fixed: [Int; 5] = [1, 2, 3, 100, 201] - let emptyVals: [Int] = [] - let emptyVals_fixed: [Int; 0] = [] - - let onlyEven = - fun (_ x: Int): Bool { - return x % 2 == 0 - } - - fun filterxs(): [Int] { - return xs.filter(onlyEven) - } - fun originalxs(): [Int] { - return xs - } - - fun filterxs_fixed(): [Int] { - return xs_fixed.filter(onlyEven) - } - fun originalxs_fixed(): [Int; 5] { - return xs_fixed - } - - fun filterempty(): [Int] { - return emptyVals.filter(onlyEven) - } - fun originalempty(): [Int] { - return emptyVals - } - - fun filterempty_fixed(): [Int] { - return emptyVals_fixed.filter(onlyEven) - } - fun originalempty_fixed(): [Int; 0] { - return emptyVals_fixed - } - - pub struct TestStruct { - pub var test: Int - - init(_ t: Int) { - self.test = t - } - } - - let onlyOddStruct = - fun (_ x: TestStruct): Bool { - return x.test % 2 == 1 - } - - let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] - let sa_fixed: [TestStruct; 3] = [TestStruct(1), TestStruct(2), TestStruct(3)] - - fun filtersa(): [Int] { - let sa_filtered = sa.filter(onlyOddStruct) - let res: [Int] = []; - for s in sa_filtered { - res.append(s.test) - } - return res - } - fun originalsa(): [Int] { - let res: [Int] = []; - for s in sa { - res.append(s.test) - } - return res - } - - fun filtersa_fixed(): [Int] { - let sa_rev = sa_fixed.filter(onlyOddStruct) - 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 - } - `) runValidCase := func( t *testing.T, + inter *interpreter.Interpreter, filterFuncName, originalFuncName string, filteredArray, originalArray *interpreter.ArrayValue, @@ -10860,77 +10772,305 @@ func TestInterpretArrayFilter(t *testing.T) { ) } - for _, suffix := range []string{"_fixed", ""} { - fixed := suffix == "_fixed" + t.Run("with variable sized empty array", func(t *testing.T) { + t.Parallel() - var originalArrayType interpreter.ArrayStaticType - if fixed { - originalArrayType = &interpreter.ConstantSizedStaticType{ - Type: interpreter.PrimitiveStaticTypeInt, + inter := parseCheckAndInterpret(t, ` + let emptyVals: [Int] = [] + + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + fun filterempty(): [Int] { + return emptyVals.filter(onlyEven) } - } else { - originalArrayType = &interpreter.VariableSizedStaticType{ + fun originalempty(): [Int] { + return emptyVals + } + `) + + emptyVarSizedArray := interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + &interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + ) + + runValidCase( + t, + inter, + "filterempty", + "originalempty", + emptyVarSizedArray, + emptyVarSizedArray, + ) + }) + + t.Run("with variable sized array of integer", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + let xs = [1, 2, 3, 100, 201] + + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + fun filterxs(): [Int] { + return xs.filter(onlyEven) } - } - // Return type is always variable sized array. - var returnArrayType = &interpreter.VariableSizedStaticType{ + fun originalxs(): [Int] { + return xs + } + `) + + varSizedArrayType := &interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, } - setFixedSize := func(size int64) { - if fixed { - constSized, ok := originalArrayType.(*interpreter.ConstantSizedStaticType) - assert.True(t, ok) + runValidCase( + t, + inter, + "filterxs", + "originalxs", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedArrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(100), + ), + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedArrayType, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + interpreter.NewUnmeteredIntValueFromInt64(100), + interpreter.NewUnmeteredIntValueFromInt64(201), + ), + ) + }) - constSized.Size = size + t.Run("with variable sized array of struct", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + pub struct TestStruct { + pub var test: Int + + init(_ t: Int) { + self.test = t + } + } + + let onlyOddStruct = + fun (_ x: TestStruct): Bool { + return x.test % 2 == 1 + } + + let sa = [TestStruct(1), TestStruct(2), TestStruct(3)] + fun filtersa(): [Int] { + let sa_filtered = sa.filter(onlyOddStruct) + let res: [Int] = []; + for s in sa_filtered { + res.append(s.test) + } + return res + } + fun originalsa(): [Int] { + let res: [Int] = []; + for s in sa { + res.append(s.test) + } + return res } + `) + + varSizedArrayType := &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, } - setFixedSize(0) - runValidCase(t, "filterempty"+suffix, "originalempty"+suffix, + runValidCase( + t, + inter, + "filtersa", + "originalsa", interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, - returnArrayType, + varSizedArrayType, common.ZeroAddress, - ), interpreter.NewArrayValue( + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(3), + ), + interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, - originalArrayType, + varSizedArrayType, common.ZeroAddress, - )) + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + interpreter.NewUnmeteredIntValueFromInt64(3), + ), + ) + }) - setFixedSize(5) - runValidCase(t, "filterxs"+suffix, "originalxs"+suffix, + t.Run("with fixed sized empty array", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + let emptyVals_fixed: [Int; 0] = [] + + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + fun filterempty_fixed(): [Int] { + return emptyVals_fixed.filter(onlyEven) + } + fun originalempty_fixed(): [Int; 0] { + return emptyVals_fixed + } + `) + + runValidCase( + t, + inter, + "filterempty_fixed", + "originalempty_fixed", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + ), interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, - returnArrayType, + &interpreter.ConstantSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + Size: 0, + }, + common.ZeroAddress, + ), + ) + }) + + t.Run("with fixed sized array of integer", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + let xs_fixed: [Int; 5] = [1, 2, 3, 100, 201] + + let onlyEven = + fun (_ x: Int): Bool { + return x % 2 == 0 + } + + fun filterxs_fixed(): [Int] { + return xs_fixed.filter(onlyEven) + } + fun originalxs_fixed(): [Int; 5] { + return xs_fixed + } + `) + + runValidCase( + t, + inter, + "filterxs_fixed", + "originalxs_fixed", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, common.ZeroAddress, interpreter.NewUnmeteredIntValueFromInt64(2), interpreter.NewUnmeteredIntValueFromInt64(100), - ), interpreter.NewArrayValue( + ), + interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, - originalArrayType, + &interpreter.ConstantSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + Size: 5, + }, common.ZeroAddress, interpreter.NewUnmeteredIntValueFromInt64(1), interpreter.NewUnmeteredIntValueFromInt64(2), interpreter.NewUnmeteredIntValueFromInt64(3), interpreter.NewUnmeteredIntValueFromInt64(100), interpreter.NewUnmeteredIntValueFromInt64(201), - )) + ), + ) + }) + + t.Run("with fixed sized array of struct", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + pub struct TestStruct { + pub var test: Int + + init(_ t: Int) { + self.test = t + } + } - runValidCase(t, "filtersa"+suffix, "originalsa"+suffix, + let onlyOddStruct = + fun (_ x: TestStruct): Bool { + return x.test % 2 == 1 + } + + let sa_fixed: [TestStruct; 3] = [TestStruct(1), TestStruct(2), TestStruct(3)] + + fun filtersa_fixed(): [Int] { + let sa_rev = sa_fixed.filter(onlyOddStruct) + 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 + } + `) + + runValidCase( + t, + inter, + "filtersa_fixed", + "originalsa_fixed", interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, - returnArrayType, + &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, common.ZeroAddress, interpreter.NewUnmeteredIntValueFromInt64(1), interpreter.NewUnmeteredIntValueFromInt64(3), - ), interpreter.NewArrayValue( + ), + interpreter.NewArrayValue( inter, interpreter.EmptyLocationRange, &interpreter.VariableSizedStaticType{ @@ -10940,8 +11080,9 @@ func TestInterpretArrayFilter(t *testing.T) { interpreter.NewUnmeteredIntValueFromInt64(1), interpreter.NewUnmeteredIntValueFromInt64(2), interpreter.NewUnmeteredIntValueFromInt64(3), - )) - } + ), + ) + }) } func TestInterpretOptionalReference(t *testing.T) {