Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce reverse in Fixed/Variable sized Array type #2654

Merged
merged 8 commits into from
Jul 19, 2023
46 changes: 46 additions & 0 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -2429,6 +2429,20 @@ func (v *ArrayValue) GetMember(interpreter *Interpreter, locationRange LocationR
)
},
)

case sema.ArrayTypeReverseFunctionName:
return NewHostFunctionValue(
interpreter,
sema.ArrayReverseFunctionType(
v.SemaType(interpreter),
),
func(invocation Invocation) Value {
return v.Reverse(
invocation.Interpreter,
invocation.LocationRange,
)
},
)
}

return nil
Expand Down Expand Up @@ -2900,6 +2914,38 @@ func (v *ArrayValue) Slice(
)
}

func (v *ArrayValue) Reverse(
interpreter *Interpreter,
locationRange LocationRange,
) Value {
count := v.Count()
idx := count - 1
darkdrag00nv2 marked this conversation as resolved.
Show resolved Hide resolved

return NewArrayValueWithIterator(
interpreter,
v.Type,
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,
nil,
)
},
)
}

// NumberValue
type NumberValue interface {
ComparableValue
Expand Down
39 changes: 39 additions & 0 deletions runtime/sema/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,13 @@ 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 ArrayTypeReverseFunctionName = "reverse"

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 {

members := map[string]MemberResolver{
Expand Down Expand Up @@ -1881,6 +1888,31 @@ func getArrayMembers(arrayType ArrayType) map[string]MemberResolver {
)
},
},
ArrayTypeReverseFunctionName: {
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,
ArrayReverseFunctionType(arrayType),
arrayTypeReverseFunctionDocString,
)
},
},
}

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

func ArrayReverseFunctionType(arrayType Type) *FunctionType {
darkdrag00nv2 marked this conversation as resolved.
Show resolved Hide resolved
return &FunctionType{
Parameters: []Parameter{},
ReturnTypeAnnotation: NewTypeAnnotation(arrayType),
}
}

// VariableSizedType is a variable sized array type
type VariableSizedType struct {
Type Type
Expand Down
49 changes: 49 additions & 0 deletions runtime/tests/checker/arrays_dictionaries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,55 @@ func TestCheckInvalidResourceFirstIndex(t *testing.T) {
assert.IsType(t, &sema.ResourceLossError{}, errs[2])
}

func TestCheckArrayReverse(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
fun test() {
let x = [1, 2, 3]
let y = x.reverse()
}
`)

require.NoError(t, err)
}

func TestCheckArrayReverseInvalidArgs(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
fun test() {
let x = [1, 2, 3]
let y = x.reverse(100)
}
`)

errs := RequireCheckerErrors(t, err, 1)

assert.IsType(t, &sema.ExcessiveArgumentsError{}, errs[0])
}

func TestCheckResourceArrayReverseInvalid(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
resource X {}

fun test(): @[X] {
let xs <- [<-create X()]
return <-xs.reverse()
}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidResourceArrayMemberError{}, errs[0])
assert.IsType(t, &sema.ResourceLossError{}, errs[1])
darkdrag00nv2 marked this conversation as resolved.
Show resolved Hide resolved
}

func TestCheckArrayContains(t *testing.T) {

t.Parallel()
Expand Down
Loading