Skip to content

Commit

Permalink
bring back members of path capability value
Browse files Browse the repository at this point in the history
needed for unmigrated path capabilities
  • Loading branch information
turbolent committed Jul 24, 2024
1 parent 7ff9b1a commit 17b0f54
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 7 deletions.
70 changes: 63 additions & 7 deletions runtime/interpreter/value_pathcapability.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/errors"
"github.com/onflow/cadence/runtime/sema"
)

// TODO: remove once migrated
Expand All @@ -50,8 +51,9 @@ func (v *PathCapabilityValue) Accept(_ *Interpreter, _ Visitor, _ LocationRange)
panic(errors.NewUnreachableError())
}

func (v *PathCapabilityValue) Walk(_ *Interpreter, _ func(Value), _ LocationRange) {
panic(errors.NewUnreachableError())
func (v *PathCapabilityValue) Walk(_ *Interpreter, walkChild func(Value), _ LocationRange) {
walkChild(v.Address)
walkChild(v.Path)
}

func (v *PathCapabilityValue) StaticType(inter *Interpreter) StaticType {
Expand All @@ -62,7 +64,7 @@ func (v *PathCapabilityValue) StaticType(inter *Interpreter) StaticType {
}

func (v *PathCapabilityValue) IsImportable(_ *Interpreter, _ LocationRange) bool {
panic(errors.NewUnreachableError())
return false
}
func (v *PathCapabilityValue) String() string {
return v.RecursiveString(SeenReferences{})
Expand Down Expand Up @@ -110,8 +112,62 @@ func (v *PathCapabilityValue) MeteredString(
}
}

func (v *PathCapabilityValue) GetMember(_ *Interpreter, _ LocationRange, _ string) Value {
panic(errors.NewUnreachableError())
func (v *PathCapabilityValue) newBorrowFunction(
interpreter *Interpreter,
borrowType *sema.ReferenceType,
) BoundFunctionValue {
return NewBoundHostFunctionValue(
interpreter,
v,
sema.CapabilityTypeBorrowFunctionType(borrowType),
func(_ Invocation) Value {
// Borrowing is never allowed
return Nil
},
)
}

func (v *PathCapabilityValue) newCheckFunction(
interpreter *Interpreter,
borrowType *sema.ReferenceType,
) BoundFunctionValue {
return NewBoundHostFunctionValue(
interpreter,
v,
sema.CapabilityTypeCheckFunctionType(borrowType),
func(_ Invocation) Value {
// Borrowing is never allowed
return FalseValue
},
)
}

func (v *PathCapabilityValue) GetMember(interpreter *Interpreter, _ LocationRange, name string) Value {
switch name {
case sema.CapabilityTypeBorrowFunctionName:
var borrowType *sema.ReferenceType
if v.BorrowType != nil {
// this function will panic already if this conversion fails
borrowType, _ = interpreter.MustConvertStaticToSemaType(v.BorrowType).(*sema.ReferenceType)
}
return v.newBorrowFunction(interpreter, borrowType)

case sema.CapabilityTypeCheckFunctionName:
var borrowType *sema.ReferenceType
if v.BorrowType != nil {
// this function will panic already if this conversion fails
borrowType, _ = interpreter.MustConvertStaticToSemaType(v.BorrowType).(*sema.ReferenceType)
}
return v.newCheckFunction(interpreter, borrowType)

case sema.CapabilityTypeAddressFieldName:
return v.Address

case sema.CapabilityTypeIDFieldName:
return InvalidCapabilityID
}

return nil
}

func (*PathCapabilityValue) RemoveMember(_ *Interpreter, _ LocationRange, _ string) Value {
Expand All @@ -127,7 +183,7 @@ func (v *PathCapabilityValue) ConformsToStaticType(
_ LocationRange,
_ TypeConformanceResults,
) bool {
panic(errors.NewUnreachableError())
return true
}

func (v *PathCapabilityValue) Equal(interpreter *Interpreter, locationRange LocationRange, other Value) bool {
Expand All @@ -151,7 +207,7 @@ func (v *PathCapabilityValue) Equal(interpreter *Interpreter, locationRange Loca
}

func (*PathCapabilityValue) IsStorable() bool {
panic(errors.NewUnreachableError())
return true
}

func (v *PathCapabilityValue) Storable(
Expand Down
147 changes: 147 additions & 0 deletions runtime/tests/interpreter/pathcapability_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Cadence - The resource-oriented smart contract programming language
*
* Copyright Flow Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package interpreter_test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/onflow/cadence/runtime/activations"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
)

func TestInterpretPathCapability(t *testing.T) {

t.Parallel()

test := func(t *testing.T, code string) (*interpreter.Interpreter, error) {
borrowType := &sema.ReferenceType{
Type: sema.StringType,
Authorization: sema.UnauthorizedAccess,
}

borrowStaticType := interpreter.ConvertSemaToStaticType(nil, borrowType)

value := stdlib.StandardLibraryValue{
Type: &sema.CapabilityType{
BorrowType: borrowType,
},
Value: &interpreter.PathCapabilityValue{ //nolint:staticcheck
BorrowType: borrowStaticType,
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: "foo",
},
Address: interpreter.AddressValue{0x42},
},
Name: "cap",
Kind: common.DeclarationKindConstant,
}

baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
baseValueActivation.DeclareValue(value)

baseActivation := activations.NewActivation(nil, interpreter.BaseActivation)
interpreter.Declare(baseActivation, value)

return parseCheckAndInterpretWithOptions(
t,
code,
ParseCheckAndInterpretOptions{
Config: &interpreter.Config{
BaseActivationHandler: func(_ common.Location) *interpreter.VariableActivation {
return baseActivation
},
},
CheckerConfig: &sema.Config{
BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation {
return baseValueActivation
},
},
HandleCheckerError: nil,
},
)
}

t.Run("transfer", func(t *testing.T) {

t.Parallel()

_, err := test(t, `
fun f(_ cap: Capability<&String>): Capability<&String>? {
return cap
}
let capOpt: Capability<&String>? = f(cap)
`)
require.NoError(t, err)
})

t.Run("borrow", func(t *testing.T) {

t.Parallel()

inter, err := test(t, `
fun test(): &String? {
return cap.borrow()
}
`)
require.NoError(t, err)

res, err := inter.Invoke("test")
require.NoError(t, err)
require.Equal(t, interpreter.Nil, res)
})

t.Run("check", func(t *testing.T) {

t.Parallel()

inter, err := test(t, `
fun test(): Bool {
return cap.check()
}
`)
require.NoError(t, err)

res, err := inter.Invoke("test")
require.NoError(t, err)
require.Equal(t, interpreter.FalseValue, res)
})

t.Run("id", func(t *testing.T) {

t.Parallel()

inter, err := test(t, `
fun test(): UInt64 {
return cap.id
}
`)
require.NoError(t, err)

res, err := inter.Invoke("test")
require.NoError(t, err)
require.Equal(t, interpreter.UInt64Value(0), res)
})
}

0 comments on commit 17b0f54

Please sign in to comment.