Skip to content

Commit

Permalink
Merge pull request #3604 from onflow/supun/sync-v1.0-master
Browse files Browse the repository at this point in the history
Merge v1.0 into master
  • Loading branch information
SupunS authored Oct 8, 2024
2 parents ed99fbf + 4de9544 commit 58650ca
Show file tree
Hide file tree
Showing 36 changed files with 1,600 additions and 398 deletions.
32 changes: 32 additions & 0 deletions runtime/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,38 @@ func TestRuntimePublicAccountKeys(t *testing.T) {
keys[keyIdx] = nil // no key should be passed to the callback twice
}
})

t.Run("keys.forEach, box and convert argument", func(t *testing.T) {
t.Parallel()

testEnv := initTestEnv(revokedAccountKeyA, accountKeyB)
test := accountKeyTestCase{
//language=Cadence
code: `
access(all)
fun main(): String? {
var res: String? = nil
// NOTE: The function has a parameter of type AccountKey? instead of just AccountKey
getAccount(0x02).keys.forEach(fun(key: AccountKey?): Bool {
// The map should call Optional.map, not fail,
// because path is AccountKey?, not AccountKey
res = key.map(fun(string: AnyStruct): String {
return "Optional.map"
})
return true
})
return res
}
`,
}

value, err := test.executeScript(testEnv.runtime, testEnv.runtimeInterface)
require.NoError(t, err)
utils.AssertEqualWithDiff(t,
cadence.NewOptional(cadence.String("Optional.map")),
value,
)
})
}

func TestRuntimeHashAlgorithm(t *testing.T) {
Expand Down
81 changes: 81 additions & 0 deletions runtime/capabilitycontrollers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2036,6 +2036,48 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
nonDeploymentEventStrings(events),
)
})

t.Run("forEachController, box and convert argument", func(t *testing.T) {

t.Parallel()

err, _, _ := test(
t,
// language=cadence
`
import Test from 0x1
transaction {
prepare(signer: auth(Capabilities) &Account) {
let storagePath = /storage/r
// Arrange
signer.capabilities.storage.issue<&Test.R>(storagePath)
// Act
var res: String? = nil
signer.capabilities.storage.forEachController(
forPath: storagePath,
// NOTE: The function has a parameter of type &StorageCapabilityController?
// instead of just &StorageCapabilityController
fun (controller: &StorageCapabilityController?): Bool {
// The map should call Optional.map, not fail,
// because path is PublicPath?, not PublicPath
res = controller.map(fun(string: AnyStruct): String {
return "Optional.map"
})
return true
}
)
// Assert
assert(res == "Optional.map")
}
}
`,
)
require.NoError(t, err)
})
})

t.Run("Account.AccountCapabilities", func(t *testing.T) {
Expand Down Expand Up @@ -2606,6 +2648,45 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
nonDeploymentEventStrings(events),
)
})

t.Run("forEachController, box and convert argument", func(t *testing.T) {

t.Parallel()

err, _, _ := test(
t,
// language=cadence
`
import Test from 0x1
transaction {
prepare(signer: auth(Capabilities) &Account) {
// Arrange
signer.capabilities.account.issue<&Account>()
// Act
var res: String? = nil
signer.capabilities.account.forEachController(
// NOTE: The function has a parameter of type &AccountCapabilityController?
// instead of just &AccountCapabilityController
fun (controller: &AccountCapabilityController?): Bool {
// The map should call Optional.map, not fail,
// because path is PublicPath?, not PublicPath
res = controller.map(fun(string: AnyStruct): String {
return "Optional.map"
})
return true
}
)
// Assert
assert(res == "Optional.map")
}
}
`,
)
require.NoError(t, err)
})
})

t.Run("StorageCapabilityController", func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions runtime/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ func (e *interpreterEnvironment) newContractValueHandler() interpreter.ContractV
invocation.ConstructorArguments,
invocation.ArgumentTypes,
invocation.ParameterTypes,
invocation.ContractType,
invocationRange,
)
if err != nil {
Expand Down
19 changes: 0 additions & 19 deletions runtime/interpreter/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,25 +620,6 @@ func (e UseBeforeInitializationError) Error() string {
return fmt.Sprintf("member `%s` is used before it has been initialized", e.Name)
}

// InvocationArgumentTypeError
type InvocationArgumentTypeError struct {
LocationRange
ParameterType sema.Type
Index int
}

var _ errors.UserError = InvocationArgumentTypeError{}

func (InvocationArgumentTypeError) IsUserError() {}

func (e InvocationArgumentTypeError) Error() string {
return fmt.Sprintf(
"invalid invocation with argument at index %d: expected `%s`",
e.Index,
e.ParameterType.QualifiedString(),
)
}

// MemberAccessTypeError
type MemberAccessTypeError struct {
ExpectedType sema.Type
Expand Down
60 changes: 37 additions & 23 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,11 @@ func (interpreter *Interpreter) InvokeExternally(
var base *EphemeralReferenceValue
var boundAuth Authorization
if boundFunc, ok := functionValue.(BoundFunctionValue); ok {
self = boundFunc.Self
self = boundFunc.SelfReference.ReferencedValue(
interpreter,
EmptyLocationRange,
true,
)
base = boundFunc.Base
boundAuth = boundFunc.BoundAuthorization
}
Expand Down Expand Up @@ -4147,22 +4151,25 @@ func (interpreter *Interpreter) newStorageIterationFunction(
interpreter,
storageValue,
functionType,
func(invocation Invocation) Value {
interpreter := invocation.Interpreter
func(_ *SimpleCompositeValue, invocation Invocation) Value {
inter := invocation.Interpreter
locationRange := invocation.LocationRange

fn, ok := invocation.Arguments[0].(FunctionValue)
if !ok {
panic(errors.NewUnreachableError())
}

locationRange := invocation.LocationRange
inter := invocation.Interpreter
fnType := fn.FunctionType()
parameterTypes := fnType.ParameterTypes()
returnType := fnType.ReturnTypeAnnotation.Type

storageMap := config.Storage.GetStorageMap(address, domain.Identifier(), false)
if storageMap == nil {
// if nothing is stored, no iteration is required
return Void
}
storageIterator := storageMap.Iterator(interpreter)
storageIterator := storageMap.Iterator(inter)

invocationArgumentTypes := []sema.Type{pathType, sema.MetaType}

Expand All @@ -4174,7 +4181,7 @@ func (interpreter *Interpreter) newStorageIterationFunction(

for key, value := storageIterator.Next(); key != nil && value != nil; key, value = storageIterator.Next() {

staticType := value.StaticType(interpreter)
staticType := value.StaticType(inter)

// Perform a forced value de-referencing to see if the associated type is not broken.
// If broken, skip this value from the iteration.
Expand All @@ -4193,18 +4200,18 @@ func (interpreter *Interpreter) newStorageIterationFunction(
pathValue := NewPathValue(inter, domain, identifier)
runtimeType := NewTypeValue(inter, staticType)

subInvocation := NewInvocation(
inter,
nil,
nil,
nil,
result := inter.invokeFunctionValue(
fn,
[]Value{pathValue, runtimeType},
nil,
invocationArgumentTypes,
parameterTypes,
returnType,
nil,
locationRange,
)

shouldContinue, ok := fn.invoke(subInvocation).(BoolValue)
shouldContinue, ok := result.(BoolValue)
if !ok {
panic(errors.NewUnreachableError())
}
Expand Down Expand Up @@ -4310,7 +4317,7 @@ func (interpreter *Interpreter) authAccountSaveFunction(
interpreter,
storageValue,
sema.Account_StorageTypeSaveFunctionType,
func(invocation Invocation) Value {
func(_ *SimpleCompositeValue, invocation Invocation) Value {
interpreter := invocation.Interpreter

value := invocation.Arguments[0]
Expand Down Expand Up @@ -4375,7 +4382,7 @@ func (interpreter *Interpreter) authAccountTypeFunction(
interpreter,
storageValue,
sema.Account_StorageTypeTypeFunctionType,
func(invocation Invocation) Value {
func(_ *SimpleCompositeValue, invocation Invocation) Value {
interpreter := invocation.Interpreter

path, ok := invocation.Arguments[0].(PathValue)
Expand Down Expand Up @@ -4433,7 +4440,7 @@ func (interpreter *Interpreter) authAccountReadFunction(
storageValue,
// same as sema.Account_StorageTypeCopyFunctionType
sema.Account_StorageTypeLoadFunctionType,
func(invocation Invocation) Value {
func(_ *SimpleCompositeValue, invocation Invocation) Value {
interpreter := invocation.Interpreter

path, ok := invocation.Arguments[0].(PathValue)
Expand Down Expand Up @@ -4517,7 +4524,7 @@ func (interpreter *Interpreter) authAccountBorrowFunction(
interpreter,
storageValue,
sema.Account_StorageTypeBorrowFunctionType,
func(invocation Invocation) Value {
func(_ *SimpleCompositeValue, invocation Invocation) Value {
interpreter := invocation.Interpreter

path, ok := invocation.Arguments[0].(PathValue)
Expand Down Expand Up @@ -4574,7 +4581,7 @@ func (interpreter *Interpreter) authAccountCheckFunction(
interpreter,
storageValue,
sema.Account_StorageTypeCheckFunctionType,
func(invocation Invocation) Value {
func(_ *SimpleCompositeValue, invocation Invocation) Value {
interpreter := invocation.Interpreter

path, ok := invocation.Arguments[0].(PathValue)
Expand Down Expand Up @@ -5043,7 +5050,14 @@ func (interpreter *Interpreter) mapMemberValueAuthorization(
case *StorageReferenceValue:
return NewStorageReferenceValue(interpreter, auth, refValue.TargetStorageAddress, refValue.TargetPath, refValue.BorrowedType)
case BoundFunctionValue:
return NewBoundFunctionValue(interpreter, refValue.Function, refValue.Self, refValue.Base, auth)
return NewBoundFunctionValueFromSelfReference(
interpreter,
refValue.Function,
refValue.SelfReference,
refValue.selfIsReference,
refValue.Base,
auth,
)
}
}
return resultValue
Expand Down Expand Up @@ -5098,7 +5112,7 @@ func (interpreter *Interpreter) isInstanceFunction(self Value) FunctionValue {
interpreter,
self,
sema.IsInstanceFunctionType,
func(invocation Invocation) Value {
func(self Value, invocation Invocation) Value {
interpreter := invocation.Interpreter

firstArgument := invocation.Arguments[0]
Expand Down Expand Up @@ -5129,7 +5143,7 @@ func (interpreter *Interpreter) getTypeFunction(self Value) FunctionValue {
interpreter,
self,
sema.GetTypeFunctionType,
func(invocation Invocation) Value {
func(self Value, invocation Invocation) Value {
interpreter := invocation.Interpreter
staticType := self.StaticType(interpreter)
return NewTypeValue(interpreter, staticType)
Expand Down Expand Up @@ -5566,7 +5580,7 @@ func (interpreter *Interpreter) capabilityBorrowFunction(
interpreter,
capabilityValue,
sema.CapabilityTypeBorrowFunctionType(capabilityBorrowType),
func(invocation Invocation) Value {
func(_ CapabilityValue, invocation Invocation) Value {

inter := invocation.Interpreter
locationRange := invocation.LocationRange
Expand Down Expand Up @@ -5613,7 +5627,7 @@ func (interpreter *Interpreter) capabilityCheckFunction(
interpreter,
capabilityValue,
sema.CapabilityTypeCheckFunctionType(capabilityBorrowType),
func(invocation Invocation) Value {
func(_ CapabilityValue, invocation Invocation) Value {

if capabilityID == InvalidCapabilityID {
return FalseValue
Expand Down
14 changes: 14 additions & 0 deletions runtime/interpreter/interpreter_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,18 @@ func (interpreter *Interpreter) checkMemberAccess(

targetStaticType := target.StaticType(interpreter)

if _, ok := expectedType.(*sema.OptionalType); ok {
if _, ok := targetStaticType.(*OptionalStaticType); !ok {
targetSemaType := interpreter.MustConvertStaticToSemaType(targetStaticType)

panic(MemberAccessTypeError{
ExpectedType: expectedType,
ActualType: targetSemaType,
LocationRange: locationRange,
})
}
}

if !interpreter.IsSubTypeOfSemaType(targetStaticType, expectedType) {
targetSemaType := interpreter.MustConvertStaticToSemaType(targetStaticType)

Expand Down Expand Up @@ -1207,6 +1219,7 @@ func (interpreter *Interpreter) visitInvocationExpressionWithImplicitArgument(in
typeParameterTypes := invocationExpressionTypes.TypeArguments
argumentTypes := invocationExpressionTypes.ArgumentTypes
parameterTypes := invocationExpressionTypes.TypeParameterTypes
returnType := invocationExpressionTypes.ReturnType

// add the implicit argument to the end of the argument list, if it exists
if implicitArg != nil {
Expand All @@ -1222,6 +1235,7 @@ func (interpreter *Interpreter) visitInvocationExpressionWithImplicitArgument(in
argumentExpressions,
argumentTypes,
parameterTypes,
returnType,
typeParameterTypes,
invocationExpression,
)
Expand Down
Loading

0 comments on commit 58650ca

Please sign in to comment.