From ae5936a69c72d4847162c3332c52aa4e3ff93262 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sun, 30 Jul 2023 01:52:17 +0530 Subject: [PATCH] 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) {