cadence
cadence copied to clipboard
Enable iteration over resource arrays
Issue To Be Solved
Currently the for-in loop is only supported for struct arrays, not resource arrays.
Enable for-in loops to iterate over arrays of resources, binding an authorized reference:
pub resource R {
pub let name: String
init(name: String) {
self.name = name
}
}
let rs <- [
<-create R(name: "bar"),
<-create R(name: "foo")
]
for ref in rs {
// ref has type `&R`
log(ref.name)
}
for ref: auth &R in rs {
// ref has type `auth &R`
log(ref.name)
}
destroy rs
Definition of Done
- Parser:
- [ ] Allow optional type annotation for value variable of for-loop
- Checker:
- [ ] Check optional type annotation for value variable of for-loop
- [ ] Bind references when looping over resource arrays. Use optional type annotation to determine if authorized or not. Default to unauthorized to prevent security issues. Store type in elaboration
- Interpreter:
- [ ] Bind reference when looping over resource arrays. Use type of elaboration
- [ ] Tests
- [ ] Documentation
Hey @turbolent I'd also be interested in working on this one as well with some guidance (since the other issue was pretty fun to tackle). Any other code snippets I could look at for reference?
@ceelo777 Nice! 🎉
Here are some first pointers:
-
The checker currently forbids iterating over resources of any kind:
https://github.com/onflow/cadence/blob/3bbc8c8a1a85f729a6a7ae1537769f6cb8de4964/runtime/sema/check_for.go#L43-L48
This needs to be removed.
-
Now that the value that is iterated over may be a resource,
checkUnusedExpressionResourceLoss
must be called:https://github.com/onflow/cadence/blob/3bbc8c8a1a85f729a6a7ae1537769f6cb8de4964/runtime/sema/checker.go#L1607-L1624
-
The checker declares the iteration variable as the element type:
https://github.com/onflow/cadence/blob/3bbc8c8a1a85f729a6a7ae1537769f6cb8de4964/runtime/sema/check_for.go#L66-L66
This needs to be changed to an authorized reference of the element type, if the iterated over value is an array of resources.
-
The interpreter sets the iteration value to each element of the array:
https://github.com/onflow/cadence/blob/3bbc8c8a1a85f729a6a7ae1537769f6cb8de4964/runtime/interpreter/interpreter_statement.go#L240-L240
This needs to be changed to an authorized ephemeral reference to the element.
Iterating over a resource array is already possible, but requires some boilerplate code (Playground: https://play.onflow.org/58c1529b-7df0-4a8c-8cbe-3c78d72514b2?type=script&id=9bb82938-eedf-4ae6-b914-f266d2837016&storage=none):
pub contract Test {
pub resource R {}
pub fun createR(): @R {
return <-create Test.R()
}
}
import Test from 0x1
pub fun main() {
let rs <- [
<- Test.createR(),
<- Test.createR(),
<- Test.createR()
]
var i = 0
while i < rs.length {
let ref = &rs[i] as &Test.R
log(ref.uuid)
i = i + 1
}
destroy rs
}