Skip to content

Commit 24ca444

Browse files
authored
Merge pull request #2654 from darkdrag00nv2/reversed_array
Introduce `reverse` in Fixed/Variable sized Array type
2 parents 21efa9b + 4d42e5f commit 24ca444

File tree

4 files changed

+369
-0
lines changed

4 files changed

+369
-0
lines changed

runtime/interpreter/value.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,20 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR
24292429
)
24302430
},
24312431
)
2432+
2433+
case sema.ArrayTypeReverseFunctionName:
2434+
return NewHostFunctionValue(
2435+
interpreter,
2436+
sema.ArrayReverseFunctionType(
2437+
v.SemaType(interpreter),
2438+
),
2439+
func(invocation Invocation) Value {
2440+
return v.Reverse(
2441+
invocation.Interpreter,
2442+
invocation.LocationRange,
2443+
)
2444+
},
2445+
)
24322446
}
24332447

24342448
return nil
@@ -2900,6 +2914,38 @@ func (v *ArrayValue) Slice(
29002914
)
29012915
}
29022916

2917+
func (v *ArrayValue) Reverse(
2918+
interpreter *Interpreter,
2919+
locationRange LocationRange,
2920+
) Value {
2921+
count := v.Count()
2922+
index := count - 1
2923+
2924+
return NewArrayValueWithIterator(
2925+
interpreter,
2926+
v.Type,
2927+
common.ZeroAddress,
2928+
uint64(count),
2929+
func() Value {
2930+
if index < 0 {
2931+
return nil
2932+
}
2933+
2934+
value := v.Get(interpreter, locationRange, index)
2935+
index--
2936+
2937+
return value.Transfer(
2938+
interpreter,
2939+
locationRange,
2940+
atree.Address{},
2941+
false,
2942+
nil,
2943+
nil,
2944+
)
2945+
},
2946+
)
2947+
}
2948+
29032949
// NumberValue
29042950
type NumberValue interface {
29052951
ComparableValue

runtime/sema/type.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,13 @@ It does not modify the original array.
17881788
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.
17891789
`
17901790

1791+
const ArrayTypeReverseFunctionName = "reverse"
1792+
1793+
const arrayTypeReverseFunctionDocString = `
1794+
Returns a new array with contents in the reversed order.
1795+
Available if the array element type is not resource-kinded.
1796+
`
1797+
17911798
func getArrayMembers(arrayType ArrayType) map[string]MemberResolver {
17921799

17931800
members := map[string]MemberResolver{
@@ -1881,6 +1888,31 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver {
18811888
)
18821889
},
18831890
},
1891+
ArrayTypeReverseFunctionName: {
1892+
Kind: common.DeclarationKindFunction,
1893+
Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member {
1894+
elementType := arrayType.ElementType(false)
1895+
1896+
// It is impossible for a resource to be present in two arrays.
1897+
if elementType.IsResourceType() {
1898+
report(
1899+
&InvalidResourceArrayMemberError{
1900+
Name: identifier,
1901+
DeclarationKind: common.DeclarationKindFunction,
1902+
Range: targetRange,
1903+
},
1904+
)
1905+
}
1906+
1907+
return NewPublicFunctionMember(
1908+
memoryGauge,
1909+
arrayType,
1910+
identifier,
1911+
ArrayReverseFunctionType(arrayType),
1912+
arrayTypeReverseFunctionDocString,
1913+
)
1914+
},
1915+
},
18841916
}
18851917

18861918
// TODO: maybe still return members but report a helpful error?
@@ -2193,6 +2225,13 @@ func ArraySliceFunctionType(elementType Type) *FunctionType {
21932225
}
21942226
}
21952227

2228+
func ArrayReverseFunctionType(arrayType ArrayType) *FunctionType {
2229+
return &FunctionType{
2230+
Parameters: []Parameter{},
2231+
ReturnTypeAnnotation: NewTypeAnnotation(arrayType),
2232+
}
2233+
}
2234+
21962235
// VariableSizedType is a variable sized array type
21972236
type VariableSizedType struct {
21982237
Type Type

runtime/tests/checker/arrays_dictionaries_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,56 @@ func TestCheckInvalidResourceFirstIndex(t *testing.T) {
10781078
assert.IsType(t, &sema.ResourceLossError{}, errs[2])
10791079
}
10801080

1081+
func TestCheckArrayReverse(t *testing.T) {
1082+
1083+
t.Parallel()
1084+
1085+
_, err := ParseAndCheck(t, `
1086+
fun test() {
1087+
let x = [1, 2, 3]
1088+
let y = x.reverse()
1089+
}
1090+
`)
1091+
1092+
require.NoError(t, err)
1093+
}
1094+
1095+
func TestCheckArrayReverseInvalidArgs(t *testing.T) {
1096+
1097+
t.Parallel()
1098+
1099+
_, err := ParseAndCheck(t, `
1100+
fun test() {
1101+
let x = [1, 2, 3]
1102+
let y = x.reverse(100)
1103+
}
1104+
`)
1105+
1106+
errs := RequireCheckerErrors(t, err, 1)
1107+
1108+
assert.IsType(t, &sema.ExcessiveArgumentsError{}, errs[0])
1109+
}
1110+
1111+
func TestCheckResourceArrayReverseInvalid(t *testing.T) {
1112+
1113+
t.Parallel()
1114+
1115+
_, err := ParseAndCheck(t, `
1116+
resource X {}
1117+
1118+
fun test(): @[X] {
1119+
let xs <- [<-create X()]
1120+
let revxs <-xs.reverse()
1121+
destroy xs
1122+
return <- revxs
1123+
}
1124+
`)
1125+
1126+
errs := RequireCheckerErrors(t, err, 1)
1127+
1128+
assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0])
1129+
}
1130+
10811131
func TestCheckArrayContains(t *testing.T) {
10821132

10831133
t.Parallel()

0 commit comments

Comments
 (0)