From 3b19728db8ae468160a5fc58a6353924ede2b951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 May 2023 16:44:29 -0700 Subject: [PATCH 01/47] fix memory metering for loading stored array --- runtime/common/metering.go | 57 +- runtime/interpreter/storage.go | 7 +- runtime/interpreter/value.go | 145 +- .../tests/interpreter/memory_metering_test.go | 3163 +++++++++-------- 4 files changed, 1706 insertions(+), 1666 deletions(-) diff --git a/runtime/common/metering.go b/runtime/common/metering.go index 0675135d8d..6dc5b99b30 100644 --- a/runtime/common/metering.go +++ b/runtime/common/metering.go @@ -313,25 +313,28 @@ func atreeNodes(count uint64, elementSize uint) (leafNodeCount uint64, branchNod return } -func newAtreeMemoryUsage(count uint64, elementSize uint, array bool) (MemoryUsage, MemoryUsage) { +func newAtreeArrayMemoryUsage(count uint64, elementSize uint) (MemoryUsage, MemoryUsage) { newLeafNodes, newBranchNodes := atreeNodes(count, elementSize) - if array { - return MemoryUsage{ - Kind: MemoryKindAtreeArrayDataSlab, - Amount: newLeafNodes, - }, MemoryUsage{ - Kind: MemoryKindAtreeArrayMetaDataSlab, - Amount: newBranchNodes, - } - } else { - return MemoryUsage{ - Kind: MemoryKindAtreeMapDataSlab, - Amount: newLeafNodes, - }, MemoryUsage{ - Kind: MemoryKindAtreeMapMetaDataSlab, - Amount: newBranchNodes, - } - } + return MemoryUsage{ + Kind: MemoryKindAtreeArrayDataSlab, + Amount: newLeafNodes, + }, + MemoryUsage{ + Kind: MemoryKindAtreeArrayMetaDataSlab, + Amount: newBranchNodes, + } +} + +func newAtreeMapMemoryUsage(count uint64, elementSize uint) (MemoryUsage, MemoryUsage) { + newLeafNodes, newBranchNodes := atreeNodes(count, elementSize) + return MemoryUsage{ + Kind: MemoryKindAtreeMapDataSlab, + Amount: newLeafNodes, + }, + MemoryUsage{ + Kind: MemoryKindAtreeMapMetaDataSlab, + Amount: newBranchNodes, + } } func NewCadenceArrayMemoryUsages(length int) (MemoryUsage, MemoryUsage) { @@ -363,16 +366,18 @@ func AdditionalAtreeMemoryUsage(originalCount uint64, elementSize uint, array bo } } -func NewArrayMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { - leaves, branches := newAtreeMemoryUsage(count, elementSize, true) - return ArrayValueBaseMemoryUsage, MemoryUsage{ - Kind: MemoryKindAtreeArrayElementOverhead, - Amount: count, - }, leaves, branches +func NewAtreeArrayMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage) { + leaves, branches := newAtreeArrayMemoryUsage(count, elementSize) + return MemoryUsage{ + Kind: MemoryKindAtreeArrayElementOverhead, + Amount: count, + }, + leaves, + branches } func NewDictionaryMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { - leaves, branches := newAtreeMemoryUsage(count, elementSize, false) + leaves, branches := newAtreeMapMemoryUsage(count, elementSize) return DictionaryValueBaseMemoryUsage, MemoryUsage{ Kind: MemoryKindAtreeMapElementOverhead, Amount: count, @@ -380,7 +385,7 @@ func NewDictionaryMemoryUsages(count uint64, elementSize uint) (MemoryUsage, Mem } func NewCompositeMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { - leaves, branches := newAtreeMemoryUsage(count, elementSize, false) + leaves, branches := newAtreeMapMemoryUsage(count, elementSize) return CompositeValueBaseMemoryUsage, MemoryUsage{ Kind: MemoryKindAtreeMapElementOverhead, Amount: count, diff --git a/runtime/interpreter/storage.go b/runtime/interpreter/storage.go index a84c967ac9..7246c8c51d 100644 --- a/runtime/interpreter/storage.go +++ b/runtime/interpreter/storage.go @@ -64,7 +64,12 @@ func ConvertStoredValue(gauge common.MemoryGauge, value atree.Value) (Value, err if !ok { panic(errors.NewUnreachableError()) } - return newArrayValueFromConstructor(gauge, staticType, value.Count(), func() *atree.Array { return value }), nil + return newArrayValueFromAtreeArray( + gauge, + staticType, + ArrayElementSize(staticType), + value, + ), nil case *atree.OrderedMap: typeInfo := value.Type() diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index f0aa2a80aa..fa511578c5 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1660,14 +1660,11 @@ func NewArrayValueWithIterator( return v } -func newArrayValueFromAtreeValue( - array *atree.Array, - staticType ArrayStaticType, -) *ArrayValue { - return &ArrayValue{ - Type: staticType, - array: array, +func ArrayElementSize(staticType ArrayStaticType) uint { + if staticType == nil { + return 0 } + return staticType.ElementType().elementSize() } func newArrayValueFromConstructor( @@ -1675,20 +1672,38 @@ func newArrayValueFromConstructor( staticType ArrayStaticType, countOverestimate uint64, constructor func() *atree.Array, -) (array *ArrayValue) { - var elementSize uint - if staticType != nil { - elementSize = staticType.ElementType().elementSize() - } - baseUsage, elementUsage, dataSlabs, metaDataSlabs := common.NewArrayMemoryUsages(countOverestimate, elementSize) - common.UseMemory(gauge, baseUsage) +) *ArrayValue { + + elementSize := ArrayElementSize(staticType) + + elementUsage, dataSlabs, metaDataSlabs := + common.NewAtreeArrayMemoryUsages(countOverestimate, elementSize) common.UseMemory(gauge, elementUsage) common.UseMemory(gauge, dataSlabs) common.UseMemory(gauge, metaDataSlabs) - array = newArrayValueFromAtreeValue(constructor(), staticType) - array.elementSize = elementSize - return + return newArrayValueFromAtreeArray( + gauge, + staticType, + elementSize, + constructor(), + ) +} + +func newArrayValueFromAtreeArray( + gauge common.MemoryGauge, + staticType ArrayStaticType, + elementSize uint, + atreeArray *atree.Array, +) *ArrayValue { + + common.UseMemory(gauge, common.ArrayValueBaseMemoryUsage) + + return &ArrayValue{ + Type: staticType, + array: atreeArray, + elementSize: elementSize, + } } var _ Value = &ArrayValue{} @@ -2647,11 +2662,6 @@ func (v *ArrayValue) Transfer( storable atree.Storable, preventTransfer map[atree.StorageID]struct{}, ) Value { - baseUsage, elementUsage, dataSlabs, metaDataSlabs := common.NewArrayMemoryUsages(v.array.Count(), v.elementSize) - common.UseMemory(interpreter, baseUsage) - common.UseMemory(interpreter, elementUsage) - common.UseMemory(interpreter, dataSlabs) - common.UseMemory(interpreter, metaDataSlabs) config := interpreter.SharedState.Config @@ -2700,6 +2710,14 @@ func (v *ArrayValue) Transfer( panic(errors.NewExternalError(err)) } + elementUsage, dataSlabs, metaDataSlabs := common.NewAtreeArrayMemoryUsages( + v.array.Count(), + v.elementSize, + ) + common.UseMemory(interpreter, elementUsage) + common.UseMemory(interpreter, dataSlabs) + common.UseMemory(interpreter, metaDataSlabs) + array, err = atree.NewArrayFromBatchData( config.Storage, address, @@ -2724,9 +2742,7 @@ func (v *ArrayValue) Transfer( } if remove { - err = v.array.PopIterate(func(storable atree.Storable) { - interpreter.RemoveReferencedSlab(storable) - }) + err = v.array.PopIterate(interpreter.RemoveReferencedSlab) if err != nil { panic(errors.NewExternalError(err)) } @@ -2759,8 +2775,13 @@ func (v *ArrayValue) Transfer( } if res == nil { - res = newArrayValueFromAtreeValue(array, v.Type) - res.elementSize = v.elementSize + res = newArrayValueFromAtreeArray( + interpreter, + v.Type, + v.elementSize, + array, + ) + res.semaType = v.semaType res.isResourceKinded = v.isResourceKinded res.isDestroyed = v.isDestroyed @@ -2772,46 +2793,48 @@ func (v *ArrayValue) Transfer( func (v *ArrayValue) Clone(interpreter *Interpreter) Value { config := interpreter.SharedState.Config - iterator, err := v.array.Iterator() - if err != nil { - panic(errors.NewExternalError(err)) - } - - baseUsage, elementUsage, dataSlabs, metaDataSlabs := common.NewArrayMemoryUsages(v.array.Count(), v.elementSize) - common.UseMemory(interpreter, baseUsage) - common.UseMemory(interpreter, elementUsage) - common.UseMemory(interpreter, dataSlabs) - common.UseMemory(interpreter, metaDataSlabs) - - array, err := atree.NewArrayFromBatchData( - config.Storage, - v.StorageAddress(), - v.array.Type(), - func() (atree.Value, error) { - value, err := iterator.Next() + array := newArrayValueFromConstructor( + interpreter, + v.Type, + v.array.Count(), + func() *atree.Array { + iterator, err := v.array.Iterator() if err != nil { - return nil, err - } - if value == nil { - return nil, nil + panic(errors.NewExternalError(err)) } - element := MustConvertStoredValue(interpreter, value). - Clone(interpreter) + array, err := atree.NewArrayFromBatchData( + config.Storage, + v.StorageID().Address, + v.array.Type(), + func() (atree.Value, error) { + value, err := iterator.Next() + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + + element := MustConvertStoredValue(interpreter, value). + Clone(interpreter) + + return element, nil + }, + ) + if err != nil { + panic(errors.NewExternalError(err)) + } - return element, nil + return array }, ) - if err != nil { - panic(errors.NewExternalError(err)) - } - return &ArrayValue{ - Type: v.Type, - semaType: v.semaType, - isResourceKinded: v.isResourceKinded, - array: array, - isDestroyed: v.isDestroyed, - } + + array.semaType = v.semaType + array.isResourceKinded = v.isResourceKinded + array.isDestroyed = v.isDestroyed + + return array } func (v *ArrayValue) DeepRemove(interpreter *Interpreter) { diff --git a/runtime/tests/interpreter/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 69bef281d7..9e77f4cb17 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -71,12 +71,12 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int8] = [] - let y: [[String]] = [[]] - let z: [[[Bool]]] = [[[]]] - } -` + fun main() { + let x: [Int8] = [] + let y: [[String]] = [[]] + let z: [[[Bool]]] = [[[]]] + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -85,9 +85,9 @@ func TestInterpretArrayMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(25), meter.getMemory(common.MemoryKindArrayValueBase)) - assert.Equal(t, uint64(25), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) + assert.Equal(t, uint64(20), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeArrayMetaDataSlab)) - assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeArrayElementOverhead)) + assert.Equal(t, uint64(8), meter.getMemory(common.MemoryKindAtreeArrayElementOverhead)) assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindVariable)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindElaboration)) // 1 Int8 for type @@ -104,10 +104,10 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() const script = ` - access(all) fun main() { + fun main() { let values: [[Int128]] = [[], [], []] for value in values { - let a = value + let a = value } } ` @@ -119,7 +119,7 @@ func TestInterpretArrayMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(30), meter.getMemory(common.MemoryKindArrayValueBase)) - assert.Equal(t, uint64(33), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) + assert.Equal(t, uint64(24), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeArrayMetaDataSlab)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeArrayElementOverhead)) assert.Equal(t, uint64(8), meter.getMemory(common.MemoryKindVariable)) @@ -134,11 +134,11 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [] - x.contains(5) - } -` + fun main() { + let x: [Int128] = [] + x.contains(5) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -157,12 +157,12 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int8] = [] - x.append(3) - x.append(4) - } -` + fun main() { + let x: [Int8] = [] + x.append(3) + x.append(4) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -180,19 +180,19 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [] // 2 data slabs - x.append(0) // fits in existing slab - x.append(1) // fits in existing slab - x.append(2) // adds 1 data and metadata slab - x.append(3) // fits in existing slab - x.append(4) // adds 1 data slab - x.append(5) // fits in existing slab - x.append(6) // adds 1 data slab - x.append(7) // fits in existing slab - x.append(8) // adds 1 data slab - } -` + fun main() { + let x: [Int128] = [] // 2 data slabs + x.append(0) // fits in existing slab + x.append(1) // fits in existing slab + x.append(2) // adds 1 data and metadata slab + x.append(3) // fits in existing slab + x.append(4) // adds 1 data slab + x.append(5) // fits in existing slab + x.append(6) // adds 1 data slab + x.append(7) // fits in existing slab + x.append(8) // adds 1 data slab + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -210,15 +210,15 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var i = 0; - let x: [Int128] = [] // 2 data slabs - while i < 120 { // should result in 4 meta data slabs and 60 slabs - x.append(0) - i = i + 1 - } - } -` + fun main() { + var i = 0; + let x: [Int128] = [] // 2 data slabs + while i < 120 { // should result in 4 meta data slabs and 60 slabs + x.append(0) + i = i + 1 + } + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -236,12 +236,12 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [] - x.insert(at:0, 3) - x.insert(at:1, 3) - } -` + fun main() { + let x: [Int128] = [] + x.insert(at: 0, 3) + x.insert(at: 1, 3) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -258,12 +258,12 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int8] = [] - x.insert(at:0, 3) - x.insert(at:1, 3) - } -` + fun main() { + let x: [Int8] = [] + x.insert(at: 0, 3) + x.insert(at: 1, 3) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -282,12 +282,12 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [0, 1, 2, 3] // uses 2 data slabs and 1 metadata slab - x[0] = 1 // adds 1 data and 1 metadata slab - x[2] = 1 // adds 1 data and 1 metadata slab - } -` + fun main() { + let x: [Int128] = [0, 1, 2, 3] // uses 2 data slabs and 1 metadata slab + x[0] = 1 // adds 1 data and 1 metadata slab + x[2] = 1 // adds 1 data and 1 metadata slab + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -304,11 +304,11 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [0, 1, 2] // uses 2 data slabs and 1 metadata slab - x[0] = 1 // fits in existing slab - x[2] = 1 // fits in existing slab - } + fun main() { + let x: [Int128] = [0, 1, 2] // uses 2 data slabs and 1 metadata slab + x[0] = 1 // fits in existing slab + x[2] = 1 // fits in existing slab + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -326,15 +326,15 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int8; 0] = [] - let y: [Int8; 1] = [2] - let z: [Int8; 2] = [2, 4] - let w: [[Int8; 2]] = [[2, 4]] - let r: [[Int8; 2]] = [[2, 4], [8, 16]] - let q: [[Int8; 2]; 2] = [[2, 4], [8, 16]] - } -` + fun main() { + let x: [Int8; 0] = [] + let y: [Int8; 1] = [2] + let z: [Int8; 2] = [2, 4] + let w: [[Int8; 2]] = [[2, 4]] + let r: [[Int8; 2]] = [[2, 4], [8, 16]] + let q: [[Int8; 2]; 2] = [[2, 4], [8, 16]] + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -342,9 +342,9 @@ func TestInterpretArrayMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(37), meter.getMemory(common.MemoryKindArrayValueBase)) - assert.Equal(t, uint64(37), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) + assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeArrayDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeArrayMetaDataSlab)) - assert.Equal(t, uint64(66), meter.getMemory(common.MemoryKindAtreeArrayElementOverhead)) + assert.Equal(t, uint64(56), meter.getMemory(common.MemoryKindAtreeArrayElementOverhead)) // 1 for `w`: 1 for the element // 2 for `r`: 1 for each element @@ -359,16 +359,16 @@ func TestInterpretArrayMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: [Int128] = [] // 2 data slabs - x.insert(at:0, 3) // fits in existing slab - x.insert(at:1, 3) // fits in existing slab - x.insert(at:2, 3) // adds 1 metadata and data slab - x.insert(at:3, 3) // fits in existing slab - x.insert(at:4, 3) // adds 1 data slab - x.insert(at:5, 3) // fits in existing slab - } -` + fun main() { + let x: [Int128] = [] // 2 data slabs + x.insert(at:0, 3) // fits in existing slab + x.insert(at:1, 3) // fits in existing slab + x.insert(at:2, 3) // adds 1 metadata and data slab + x.insert(at:3, 3) // fits in existing slab + x.insert(at:4, 3) // adds 1 data slab + x.insert(at:5, 3) // fits in existing slab + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -396,11 +396,11 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {} - let y: {String: {Int8: String}} = {"a": {}} - } - ` + fun main() { + let x: {Int8: String} = {} + let y: {String: {Int8: String}} = {"a": {}} + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -428,13 +428,13 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let values: [{Int8: String}] = [{}, {}, {}] - for value in values { - let a = value - } - } - ` + fun main() { + let values: [{Int8: String}] = [{}, {}, {}] + for value in values { + let a = value + } + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -459,11 +459,11 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {} - x.containsKey(5) - } - ` + fun main() { + let x: {Int8: String} = {} + x.containsKey(5) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -478,12 +478,12 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {} - x.insert(key: 5, "") - x.insert(key: 4, "") - } - ` + fun main() { + let x: {Int8: String} = {} + x.insert(key: 5, "") + x.insert(key: 4, "") + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -504,19 +504,19 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {} // 2 data slabs - x.insert(key: 0, "") // fits in slab - x.insert(key: 1, "") // fits in slab - x.insert(key: 2, "") // adds 1 data and metadata slab - x.insert(key: 3, "") // fits in slab - x.insert(key: 4, "") // adds 1 data slab - x.insert(key: 5, "") // fits in slab - x.insert(key: 6, "") // adds 1 data slab - x.insert(key: 7, "") // fits in slab - x.insert(key: 8, "") // adds 1 data slab - } - ` + fun main() { + let x: {Int8: String} = {} // 2 data slabs + x.insert(key: 0, "") // fits in slab + x.insert(key: 1, "") // fits in slab + x.insert(key: 2, "") // adds 1 data and metadata slab + x.insert(key: 3, "") // fits in slab + x.insert(key: 4, "") // adds 1 data slab + x.insert(key: 5, "") // fits in slab + x.insert(key: 6, "") // adds 1 data slab + x.insert(key: 7, "") // fits in slab + x.insert(key: 8, "") // adds 1 data slab + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -535,19 +535,19 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: Int8} = {} // 2 data slabs - x.insert(key: 0, 0) // all fit in slab - x.insert(key: 1, 1) - x.insert(key: 2, 2) - x.insert(key: 3, 3) - x.insert(key: 4, 4) - x.insert(key: 5, 5) - x.insert(key: 6, 6) - x.insert(key: 7, 7) - x.insert(key: 8, 8) - } - ` + fun main() { + let x: {Int8: Int8} = {} // 2 data slabs + x.insert(key: 0, 0) // all fit in slab + x.insert(key: 1, 1) + x.insert(key: 2, 2) + x.insert(key: 3, 3) + x.insert(key: 4, 4) + x.insert(key: 5, 5) + x.insert(key: 6, 6) + x.insert(key: 7, 7) + x.insert(key: 8, 8) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -566,12 +566,12 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {3: "a"} // 2 data slabs - x[3] = "b" // fits in existing slab - x[3] = "c" // fits in existing slab - x[4] = "d" // fits in existing slab - } + fun main() { + let x: {Int8: String} = {3: "a"} // 2 data slabs + x[3] = "b" // fits in existing slab + x[3] = "c" // fits in existing slab + x[4] = "d" // fits in existing slab + } ` meter := newTestMemoryGauge() @@ -591,12 +591,12 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {3: "a"} // 2 data slabs - x[3] = "b" // fits in existing slab - x[4] = "d" // fits in existing slab - x[3] = "c" // adds 1 data slab and metadata slab - } + fun main() { + let x: {Int8: String} = {3: "a"} // 2 data slabs + x[3] = "b" // fits in existing slab + x[4] = "d" // fits in existing slab + x[3] = "c" // adds 1 data slab and metadata slab + } ` meter := newTestMemoryGauge() @@ -618,23 +618,23 @@ func TestInterpretCompositeMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct S {} + struct S {} - access(all) resource R { - access(all) let a: String - access(all) let b: String + resource R { + let a: String + let b: String - init(a: String, b: String) { - self.a = a - self.b = b - } - } + init(a: String, b: String) { + self.a = a + self.b = b + } + } - access(all) fun main() { - let s = S() - let r <- create R(a: "a", b: "b") - destroy r - } + fun main() { + let s = S() + let r <- create R(a: "a", b: "b") + destroy r + } ` meter := newTestMemoryGauge() @@ -661,14 +661,14 @@ func TestInterpretCompositeMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct S {} + struct S {} - access(all) fun main() { - let values = [S(), S(), S()] - for value in values { + fun main() { + let values = [S(), S(), S()] + for value in values { let a = value - } - } + } + } ` meter := newTestMemoryGauge() @@ -697,7 +697,7 @@ func TestInterpretSimpleCompositeMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main(a: &Account) {} + fun main(a: &Account) {} ` meter := newTestMemoryGauge() @@ -727,8 +727,9 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct S {} - access(all) fun main() { + struct S {} + + fun main() { let s = S() } ` @@ -750,15 +751,17 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct S { - access(all) let a: String - init(_ a: String) { - self.a = a - } - } - access(all) fun main() { - let s = S("a") - } + struct S { + let a: String + + init(_ a: String) { + self.a = a + } + } + + fun main() { + let s = S("a") + } ` meter := newTestMemoryGauge() @@ -779,17 +782,19 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct S { - access(all) let a: String - access(all) let b: String - init(_ a: String, _ b: String) { - self.a = a - self.b = b - } - } - access(all) fun main() { - let s = S("a", "b") - } + struct S { + let a: String + let b: String + + init(_ a: String, _ b: String) { + self.a = a + self.b = b + } + } + + fun main() { + let s = S("a", "b") + } ` meter := newTestMemoryGauge() @@ -814,7 +819,7 @@ func TestInterpretInterpretedFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -831,11 +836,11 @@ func TestInterpretInterpretedFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let funcPointer = fun(a: String): String { - return a - } - } + fun main() { + let funcPointer = fun(a: String): String { + return a + } + } ` meter := newTestMemoryGauge() @@ -852,16 +857,16 @@ func TestInterpretInterpretedFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let funcPointer1 = fun(a: String): String { - return a - } + fun main() { + let funcPointer1 = fun(a: String): String { + return a + } - let funcPointer2 = funcPointer1 - let funcPointer3 = funcPointer2 + let funcPointer2 = funcPointer1 + let funcPointer3 = funcPointer2 - let value = funcPointer3("hello") - } + let value = funcPointer3("hello") + } ` meter := newTestMemoryGauge() @@ -881,11 +886,11 @@ func TestInterpretInterpretedFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - access(all) fun bar() {} - } + struct Foo { + fun bar() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -902,11 +907,11 @@ func TestInterpretInterpretedFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - init() {} - } + struct Foo { + init() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -929,7 +934,7 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -944,16 +949,16 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let funcPointer1 = fun(a: String): String { - return a - } + fun main() { + let funcPointer1 = fun(a: String): String { + return a + } - let funcPointer2 = funcPointer1 - let funcPointer3 = funcPointer2 + let funcPointer2 = funcPointer1 + let funcPointer3 = funcPointer2 - let value = funcPointer3("hello") - } + let value = funcPointer3("hello") + } ` meter := newTestMemoryGauge() @@ -968,11 +973,11 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - access(all) fun bar() {} - } + struct Foo { + fun bar() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -989,11 +994,11 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - init() {} - } + struct Foo { + init() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -1010,11 +1015,11 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let a = Int8(5) + fun main() { + let a = Int8(5) - let b = CompositeType("PublicKey") - } + let b = CompositeType("PublicKey") + } ` meter := newTestMemoryGauge() @@ -1033,9 +1038,9 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - assert(true) - } + fun main() { + assert(true) + } ` meter := newTestMemoryGauge() @@ -1073,12 +1078,12 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let publicKey = PublicKey( - publicKey: "0102".decodeHex(), - signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 - ) - } + fun main() { + let publicKey = PublicKey( + publicKey: "0102".decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + } ` baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) @@ -1122,17 +1127,17 @@ func TestInterpretHostFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let publicKey1 = PublicKey( - publicKey: "0102".decodeHex(), - signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 - ) + fun main() { + let publicKey1 = PublicKey( + publicKey: "0102".decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) - let publicKey2 = PublicKey( - publicKey: "0102".decodeHex(), - signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 - ) - } + let publicKey2 = PublicKey( + publicKey: "0102".decodeHex(), + signatureAlgorithm: SignatureAlgorithm.ECDSA_P256 + ) + } ` baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) @@ -1180,11 +1185,11 @@ func TestInterpretBoundFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - access(all) fun bar() {} - } + struct Foo { + fun bar() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -1201,11 +1206,11 @@ func TestInterpretBoundFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - init() {} - } + struct Foo { + init() {} + } - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -1222,16 +1227,16 @@ func TestInterpretBoundFunctionMetering(t *testing.T) { t.Parallel() script := ` - access(all) struct Foo { - access(all) fun bar() {} - } + struct Foo { + fun bar() {} + } - access(all) fun main() { - let foo = Foo() - foo.bar() - foo.bar() - foo.bar() - } + fun main() { + let foo = Foo() + foo.bar() + foo.bar() + foo.bar() + } ` meter := newTestMemoryGauge() @@ -1253,9 +1258,9 @@ func TestInterpretOptionalValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: String? = "hello" - } + fun main() { + let x: String? = "hello" + } ` meter := newTestMemoryGauge() @@ -1271,11 +1276,11 @@ func TestInterpretOptionalValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {1: "foo", 2: "bar"} - let y = x[0] - let z = x[1] - } + fun main() { + let x: {Int8: String} = {1: "foo", 2: "bar"} + let y = x[0] + let z = x[1] + } ` meter := newTestMemoryGauge() @@ -1295,11 +1300,11 @@ func TestInterpretOptionalValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: {Int8: String} = {1: "foo", 2: "bar"} - x[0] = "a" - x[1] = "b" - } + fun main() { + let x: {Int8: String} = {1: "foo", 2: "bar"} + x[0] = "a" + x[1] = "b" + } ` meter := newTestMemoryGauge() @@ -1318,10 +1323,10 @@ func TestInterpretOptionalValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let type: Type = Type() - let a = OptionalType(type) - } + fun main() { + let type: Type = Type() + let a = OptionalType(type) + } ` meter := newTestMemoryGauge() @@ -1346,9 +1351,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 - } + fun main() { + let x = 1 + } ` meter := newTestMemoryGauge() @@ -1365,9 +1370,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 + 2 - } + fun main() { + let x = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -1384,9 +1389,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 - 2 - } + fun main() { + let x = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -1403,9 +1408,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 * 2 - } + fun main() { + let x = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -1422,9 +1427,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 / 2 - } + fun main() { + let x = 10 / 2 + } ` meter := newTestMemoryGauge() @@ -1441,9 +1446,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 % 2 - } + fun main() { + let x = 10 % 2 + } ` meter := newTestMemoryGauge() @@ -1460,9 +1465,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 | 2 - } + fun main() { + let x = 10 | 2 + } ` meter := newTestMemoryGauge() @@ -1479,9 +1484,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 ^ 2 - } + fun main() { + let x = 10 ^ 2 + } ` meter := newTestMemoryGauge() @@ -1498,9 +1503,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 & 2 - } + fun main() { + let x = 10 & 2 + } ` meter := newTestMemoryGauge() @@ -1517,9 +1522,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 << 2 - } + fun main() { + let x = 10 << 2 + } ` meter := newTestMemoryGauge() @@ -1536,9 +1541,9 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 >> 2 - } + fun main() { + let x = 10 >> 2 + } ` meter := newTestMemoryGauge() @@ -1555,10 +1560,10 @@ func TestInterpretIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 - let y = -x - } + fun main() { + let x = 1 + let y = -x + } ` meter := newTestMemoryGauge() @@ -1580,9 +1585,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt - } + fun main() { + let x = 1 as UInt + } ` meter := newTestMemoryGauge() @@ -1600,9 +1605,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt + 2 as UInt - } + fun main() { + let x = 1 as UInt + 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1619,9 +1624,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt - 2 as UInt - } + fun main() { + let x = 3 as UInt - 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1638,9 +1643,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt).saturatingSubtract(2 as UInt) - } + fun main() { + let x = (1 as UInt).saturatingSubtract(2 as UInt) + } ` meter := newTestMemoryGauge() @@ -1657,9 +1662,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt * 2 as UInt - } + fun main() { + let x = 1 as UInt * 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1676,9 +1681,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt / 2 as UInt - } + fun main() { + let x = 10 as UInt / 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1695,9 +1700,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt % 2 as UInt - } + fun main() { + let x = 10 as UInt % 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1714,9 +1719,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt | 2 as UInt - } + fun main() { + let x = 10 as UInt | 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1733,9 +1738,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt ^ 2 as UInt - } + fun main() { + let x = 10 as UInt ^ 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1752,9 +1757,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt & 2 as UInt - } + fun main() { + let x = 10 as UInt & 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1771,9 +1776,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt << 2 as UInt - } + fun main() { + let x = 10 as UInt << 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1790,9 +1795,9 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt >> 2 as UInt - } + fun main() { + let x = 10 as UInt >> 2 as UInt + } ` meter := newTestMemoryGauge() @@ -1809,10 +1814,10 @@ func TestInterpretUIntMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 - let y = -x - } + fun main() { + let x = 1 + let y = -x + } ` meter := newTestMemoryGauge() @@ -1834,9 +1839,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt8 - } + fun main() { + let x = 1 as UInt8 + } ` meter := newTestMemoryGauge() @@ -1854,9 +1859,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt8 + 2 as UInt8 - } + fun main() { + let x = 1 as UInt8 + 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -1875,9 +1880,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt8).saturatingAdd(2 as UInt8) - } + fun main() { + let x = (1 as UInt8).saturatingAdd(2 as UInt8) + } ` meter := newTestMemoryGauge() @@ -1896,9 +1901,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt8 - 2 as UInt8 - } + fun main() { + let x = 3 as UInt8 - 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -1917,9 +1922,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt8).saturatingSubtract(2 as UInt8) - } + fun main() { + let x = (1 as UInt8).saturatingSubtract(2 as UInt8) + } ` meter := newTestMemoryGauge() @@ -1938,9 +1943,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt8 * 2 as UInt8 - } + fun main() { + let x = 1 as UInt8 * 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -1959,9 +1964,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt8).saturatingMultiply(2 as UInt8) - } + fun main() { + let x = (1 as UInt8).saturatingMultiply(2 as UInt8) + } ` meter := newTestMemoryGauge() @@ -1980,9 +1985,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 / 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 / 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2001,9 +2006,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 % 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 % 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2022,9 +2027,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 | 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 | 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2043,9 +2048,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 ^ 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 ^ 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2064,9 +2069,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 & 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 & 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2086,9 +2091,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 << 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 << 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2107,9 +2112,9 @@ func TestInterpretUInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt8 >> 2 as UInt8 - } + fun main() { + let x = 10 as UInt8 >> 2 as UInt8 + } ` meter := newTestMemoryGauge() @@ -2133,9 +2138,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt16 - } + fun main() { + let x = 1 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2153,9 +2158,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt16 + 2 as UInt16 - } + fun main() { + let x = 1 as UInt16 + 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2174,9 +2179,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt16).saturatingAdd(2 as UInt16) - } + fun main() { + let x = (1 as UInt16).saturatingAdd(2 as UInt16) + } ` meter := newTestMemoryGauge() @@ -2195,9 +2200,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt16 - 2 as UInt16 - } + fun main() { + let x = 3 as UInt16 - 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2216,9 +2221,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt16).saturatingSubtract(2 as UInt16) - } + fun main() { + let x = (1 as UInt16).saturatingSubtract(2 as UInt16) + } ` meter := newTestMemoryGauge() @@ -2237,9 +2242,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt16 * 2 as UInt16 - } + fun main() { + let x = 1 as UInt16 * 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2258,9 +2263,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt16).saturatingMultiply(2 as UInt16) - } + fun main() { + let x = (1 as UInt16).saturatingMultiply(2 as UInt16) + } ` meter := newTestMemoryGauge() @@ -2279,9 +2284,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 / 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 / 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2300,9 +2305,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 % 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 % 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2321,9 +2326,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 | 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 | 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2342,9 +2347,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 ^ 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 ^ 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2363,9 +2368,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 & 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 & 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2384,9 +2389,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 << 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 << 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2405,9 +2410,9 @@ func TestInterpretUInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt16 >> 2 as UInt16 - } + fun main() { + let x = 10 as UInt16 >> 2 as UInt16 + } ` meter := newTestMemoryGauge() @@ -2431,9 +2436,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt32 - } + fun main() { + let x = 1 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2451,9 +2456,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt32 + 2 as UInt32 - } + fun main() { + let x = 1 as UInt32 + 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2472,9 +2477,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt32).saturatingAdd(2 as UInt32) - } + fun main() { + let x = (1 as UInt32).saturatingAdd(2 as UInt32) + } ` meter := newTestMemoryGauge() @@ -2493,9 +2498,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt32 - 2 as UInt32 - } + fun main() { + let x = 3 as UInt32 - 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2514,9 +2519,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt32).saturatingSubtract(2 as UInt32) - } + fun main() { + let x = (1 as UInt32).saturatingSubtract(2 as UInt32) + } ` meter := newTestMemoryGauge() @@ -2535,9 +2540,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt32 * 2 as UInt32 - } + fun main() { + let x = 1 as UInt32 * 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2556,9 +2561,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt32).saturatingMultiply(2 as UInt32) - } + fun main() { + let x = (1 as UInt32).saturatingMultiply(2 as UInt32) + } ` meter := newTestMemoryGauge() @@ -2577,9 +2582,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 / 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 / 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2598,9 +2603,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 % 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 % 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2619,9 +2624,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 | 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 | 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2640,9 +2645,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 ^ 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 ^ 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2661,9 +2666,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 & 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 & 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2682,9 +2687,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 << 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 << 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2703,9 +2708,9 @@ func TestInterpretUInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt32 >> 2 as UInt32 - } + fun main() { + let x = 10 as UInt32 >> 2 as UInt32 + } ` meter := newTestMemoryGauge() @@ -2729,9 +2734,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt64 - } + fun main() { + let x = 1 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2749,9 +2754,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt64 + 2 as UInt64 - } + fun main() { + let x = 1 as UInt64 + 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2770,9 +2775,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt64).saturatingAdd(2 as UInt64) - } + fun main() { + let x = (1 as UInt64).saturatingAdd(2 as UInt64) + } ` meter := newTestMemoryGauge() @@ -2791,9 +2796,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt64 - 2 as UInt64 - } + fun main() { + let x = 3 as UInt64 - 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2812,9 +2817,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt64).saturatingSubtract(2 as UInt64) - } + fun main() { + let x = (1 as UInt64).saturatingSubtract(2 as UInt64) + } ` meter := newTestMemoryGauge() @@ -2833,9 +2838,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt64 * 2 as UInt64 - } + fun main() { + let x = 1 as UInt64 * 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2854,9 +2859,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt64).saturatingMultiply(2 as UInt64) - } + fun main() { + let x = (1 as UInt64).saturatingMultiply(2 as UInt64) + } ` meter := newTestMemoryGauge() @@ -2875,9 +2880,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 / 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 / 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2896,9 +2901,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 % 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 % 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2917,9 +2922,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 | 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 | 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2938,9 +2943,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 ^ 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 ^ 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2959,9 +2964,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 & 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 & 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -2980,9 +2985,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 << 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 << 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -3001,9 +3006,9 @@ func TestInterpretUInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt64 >> 2 as UInt64 - } + fun main() { + let x = 10 as UInt64 >> 2 as UInt64 + } ` meter := newTestMemoryGauge() @@ -3027,9 +3032,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt128 - } + fun main() { + let x = 1 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3047,9 +3052,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt128 + 2 as UInt128 - } + fun main() { + let x = 1 as UInt128 + 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3068,9 +3073,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt128).saturatingAdd(2 as UInt128) - } + fun main() { + let x = (1 as UInt128).saturatingAdd(2 as UInt128) + } ` meter := newTestMemoryGauge() @@ -3089,9 +3094,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt128 - 2 as UInt128 - } + fun main() { + let x = 3 as UInt128 - 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3110,9 +3115,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt128).saturatingSubtract(2 as UInt128) - } + fun main() { + let x = (1 as UInt128).saturatingSubtract(2 as UInt128) + } ` meter := newTestMemoryGauge() @@ -3132,9 +3137,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt128 * 2 as UInt128 - } + fun main() { + let x = 1 as UInt128 * 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3153,9 +3158,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt128).saturatingMultiply(2 as UInt128) - } + fun main() { + let x = (1 as UInt128).saturatingMultiply(2 as UInt128) + } ` meter := newTestMemoryGauge() @@ -3174,9 +3179,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 / 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 / 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3195,9 +3200,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 % 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 % 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3216,9 +3221,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 | 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 | 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3237,9 +3242,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 ^ 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 ^ 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3258,9 +3263,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 & 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 & 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3279,9 +3284,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 << 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 << 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3300,9 +3305,9 @@ func TestInterpretUInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt128 >> 2 as UInt128 - } + fun main() { + let x = 10 as UInt128 >> 2 as UInt128 + } ` meter := newTestMemoryGauge() @@ -3326,9 +3331,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt256 - } + fun main() { + let x = 1 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3346,9 +3351,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt256 + 2 as UInt256 - } + fun main() { + let x = 1 as UInt256 + 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3367,9 +3372,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt256).saturatingAdd(2 as UInt256) - } + fun main() { + let x = (1 as UInt256).saturatingAdd(2 as UInt256) + } ` meter := newTestMemoryGauge() @@ -3388,9 +3393,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as UInt256 - 2 as UInt256 - } + fun main() { + let x = 3 as UInt256 - 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3409,9 +3414,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt256).saturatingSubtract(2 as UInt256) - } + fun main() { + let x = (1 as UInt256).saturatingSubtract(2 as UInt256) + } ` meter := newTestMemoryGauge() @@ -3430,9 +3435,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as UInt256 * 2 as UInt256 - } + fun main() { + let x = 1 as UInt256 * 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3451,9 +3456,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = (1 as UInt256).saturatingMultiply(2 as UInt256) - } + fun main() { + let x = (1 as UInt256).saturatingMultiply(2 as UInt256) + } ` meter := newTestMemoryGauge() @@ -3472,9 +3477,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 / 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 / 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3493,9 +3498,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 % 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 % 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3514,9 +3519,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 | 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 | 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3535,9 +3540,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 ^ 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 ^ 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3556,9 +3561,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 & 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 & 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3577,9 +3582,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 << 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 << 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3598,9 +3603,9 @@ func TestInterpretUInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as UInt256 >> 2 as UInt256 - } + fun main() { + let x = 10 as UInt256 >> 2 as UInt256 + } ` meter := newTestMemoryGauge() @@ -3624,9 +3629,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - } + fun main() { + let x: Int8 = 1 + } ` meter := newTestMemoryGauge() @@ -3643,9 +3648,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 + 2 - } + fun main() { + let x: Int8 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -3664,10 +3669,10 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - let y: Int8 = x.saturatingAdd(2) - } + fun main() { + let x: Int8 = 1 + let y: Int8 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -3686,9 +3691,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - 2 - } + fun main() { + let x: Int8 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -3707,10 +3712,10 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - let y: Int8 = x.saturatingSubtract(2) - } + fun main() { + let x: Int8 = 1 + let y: Int8 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -3729,9 +3734,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 * 2 - } + fun main() { + let x: Int8 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -3750,10 +3755,10 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - let y: Int8 = x.saturatingMultiply(2) - } + fun main() { + let x: Int8 = 1 + let y: Int8 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -3772,9 +3777,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 / 2 - } + fun main() { + let x: Int8 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -3793,10 +3798,10 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 - let y: Int8 = x.saturatingMultiply(2) - } + fun main() { + let x: Int8 = 3 + let y: Int8 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -3815,9 +3820,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 % 2 - } + fun main() { + let x: Int8 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -3836,10 +3841,10 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 1 - let y: Int8 = -x - } + fun main() { + let x: Int8 = 1 + let y: Int8 = -x + } ` meter := newTestMemoryGauge() @@ -3858,9 +3863,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 | 2 - } + fun main() { + let x: Int8 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -3879,9 +3884,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 ^ 2 - } + fun main() { + let x: Int8 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -3900,9 +3905,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 & 2 - } + fun main() { + let x: Int8 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -3921,9 +3926,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 << 2 - } + fun main() { + let x: Int8 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -3942,9 +3947,9 @@ func TestInterpretInt8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int8 = 3 >> 2 - } + fun main() { + let x: Int8 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -3969,9 +3974,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - } + fun main() { + let x: Int16 = 1 + } ` meter := newTestMemoryGauge() @@ -3988,9 +3993,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 + 2 - } + fun main() { + let x: Int16 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -4009,10 +4014,10 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - let y: Int16 = x.saturatingAdd(2) - } + fun main() { + let x: Int16 = 1 + let y: Int16 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -4031,9 +4036,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - 2 - } + fun main() { + let x: Int16 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -4052,10 +4057,10 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - let y: Int16 = x.saturatingSubtract(2) - } + fun main() { + let x: Int16 = 1 + let y: Int16 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -4074,9 +4079,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 * 2 - } + fun main() { + let x: Int16 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -4095,10 +4100,10 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - let y: Int16 = x.saturatingMultiply(2) - } + fun main() { + let x: Int16 = 1 + let y: Int16 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4117,9 +4122,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 / 2 - } + fun main() { + let x: Int16 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -4138,10 +4143,10 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 - let y: Int16 = x.saturatingMultiply(2) - } + fun main() { + let x: Int16 = 3 + let y: Int16 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4160,9 +4165,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 % 2 - } + fun main() { + let x: Int16 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -4181,10 +4186,10 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 1 - let y: Int16 = -x - } + fun main() { + let x: Int16 = 1 + let y: Int16 = -x + } ` meter := newTestMemoryGauge() @@ -4203,9 +4208,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 | 2 - } + fun main() { + let x: Int16 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -4224,9 +4229,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 ^ 2 - } + fun main() { + let x: Int16 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -4245,9 +4250,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 & 2 - } + fun main() { + let x: Int16 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -4266,9 +4271,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 << 2 - } + fun main() { + let x: Int16 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -4287,9 +4292,9 @@ func TestInterpretInt16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int16 = 3 >> 2 - } + fun main() { + let x: Int16 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -4313,9 +4318,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - } + fun main() { + let x: Int32 = 1 + } ` meter := newTestMemoryGauge() @@ -4332,9 +4337,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 + 2 - } + fun main() { + let x: Int32 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -4353,10 +4358,10 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - let y: Int32 = x.saturatingAdd(2) - } + fun main() { + let x: Int32 = 1 + let y: Int32 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -4375,9 +4380,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - 2 - } + fun main() { + let x: Int32 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -4396,10 +4401,10 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - let y: Int32 = x.saturatingSubtract(2) - } + fun main() { + let x: Int32 = 1 + let y: Int32 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -4418,9 +4423,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 * 2 - } + fun main() { + let x: Int32 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -4439,10 +4444,10 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - let y: Int32 = x.saturatingMultiply(2) - } + fun main() { + let x: Int32 = 1 + let y: Int32 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4461,9 +4466,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 / 2 - } + fun main() { + let x: Int32 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -4482,10 +4487,10 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 - let y: Int32 = x.saturatingMultiply(2) - } + fun main() { + let x: Int32 = 3 + let y: Int32 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4504,9 +4509,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 % 2 - } + fun main() { + let x: Int32 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -4525,10 +4530,10 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 1 - let y: Int32 = -x - } + fun main() { + let x: Int32 = 1 + let y: Int32 = -x + } ` meter := newTestMemoryGauge() @@ -4547,9 +4552,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 | 2 - } + fun main() { + let x: Int32 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -4568,9 +4573,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 ^ 2 - } + fun main() { + let x: Int32 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -4589,9 +4594,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 & 2 - } + fun main() { + let x: Int32 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -4610,9 +4615,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 << 2 - } + fun main() { + let x: Int32 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -4631,9 +4636,9 @@ func TestInterpretInt32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int32 = 3 >> 2 - } + fun main() { + let x: Int32 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -4657,9 +4662,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - } + fun main() { + let x: Int64 = 1 + } ` meter := newTestMemoryGauge() @@ -4676,9 +4681,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 + 2 - } + fun main() { + let x: Int64 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -4697,10 +4702,10 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - let y: Int64 = x.saturatingAdd(2) - } + fun main() { + let x: Int64 = 1 + let y: Int64 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -4719,9 +4724,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - 2 - } + fun main() { + let x: Int64 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -4740,10 +4745,10 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - let y: Int64 = x.saturatingSubtract(2) - } + fun main() { + let x: Int64 = 1 + let y: Int64 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -4762,9 +4767,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 * 2 - } + fun main() { + let x: Int64 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -4783,10 +4788,10 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - let y: Int64 = x.saturatingMultiply(2) - } + fun main() { + let x: Int64 = 1 + let y: Int64 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4805,9 +4810,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 / 2 - } + fun main() { + let x: Int64 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -4826,10 +4831,10 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 - let y: Int64 = x.saturatingMultiply(2) - } + fun main() { + let x: Int64 = 3 + let y: Int64 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -4848,9 +4853,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 % 2 - } + fun main() { + let x: Int64 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -4869,10 +4874,10 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 1 - let y: Int64 = -x - } + fun main() { + let x: Int64 = 1 + let y: Int64 = -x + } ` meter := newTestMemoryGauge() @@ -4891,9 +4896,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 | 2 - } + fun main() { + let x: Int64 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -4912,9 +4917,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 ^ 2 - } + fun main() { + let x: Int64 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -4933,9 +4938,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 & 2 - } + fun main() { + let x: Int64 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -4954,9 +4959,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 << 2 - } + fun main() { + let x: Int64 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -4975,9 +4980,9 @@ func TestInterpretInt64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int64 = 3 >> 2 - } + fun main() { + let x: Int64 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -5001,9 +5006,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - } + fun main() { + let x: Int128 = 1 + } ` meter := newTestMemoryGauge() @@ -5020,9 +5025,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 + 2 - } + fun main() { + let x: Int128 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -5041,10 +5046,10 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - let y: Int128 = x.saturatingAdd(2) - } + fun main() { + let x: Int128 = 1 + let y: Int128 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -5063,9 +5068,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - 2 - } + fun main() { + let x: Int128 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -5084,10 +5089,10 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - let y: Int128 = x.saturatingSubtract(2) - } + fun main() { + let x: Int128 = 1 + let y: Int128 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -5106,9 +5111,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 * 2 - } + fun main() { + let x: Int128 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -5127,10 +5132,10 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - let y: Int128 = x.saturatingMultiply(2) - } + fun main() { + let x: Int128 = 1 + let y: Int128 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -5149,9 +5154,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 / 2 - } + fun main() { + let x: Int128 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -5170,10 +5175,10 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 - let y: Int128 = x.saturatingMultiply(2) - } + fun main() { + let x: Int128 = 3 + let y: Int128 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -5192,9 +5197,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 % 2 - } + fun main() { + let x: Int128 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -5213,10 +5218,10 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - let y: Int128 = -x - } + fun main() { + let x: Int128 = 1 + let y: Int128 = -x + } ` meter := newTestMemoryGauge() @@ -5235,9 +5240,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 | 2 - } + fun main() { + let x: Int128 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -5256,9 +5261,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 ^ 2 - } + fun main() { + let x: Int128 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -5277,9 +5282,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 & 2 - } + fun main() { + let x: Int128 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -5298,9 +5303,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 << 2 - } + fun main() { + let x: Int128 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -5319,9 +5324,9 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 3 >> 2 - } + fun main() { + let x: Int128 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -5340,15 +5345,15 @@ func TestInterpretInt128Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int128 = 1 - x == 1 - x != 1 - x > 1 - x >= 1 - x < 1 - x <= 1 - } + fun main() { + let x: Int128 = 1 + x == 1 + x != 1 + x > 1 + x >= 1 + x < 1 + x <= 1 + } ` meter := newTestMemoryGauge() @@ -5370,9 +5375,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - } + fun main() { + let x: Int256 = 1 + } ` meter := newTestMemoryGauge() @@ -5389,9 +5394,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 + 2 - } + fun main() { + let x: Int256 = 1 + 2 + } ` meter := newTestMemoryGauge() @@ -5410,10 +5415,10 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - let y: Int256 = x.saturatingAdd(2) - } + fun main() { + let x: Int256 = 1 + let y: Int256 = x.saturatingAdd(2) + } ` meter := newTestMemoryGauge() @@ -5432,9 +5437,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - 2 - } + fun main() { + let x: Int256 = 1 - 2 + } ` meter := newTestMemoryGauge() @@ -5453,10 +5458,10 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - let y: Int256 = x.saturatingSubtract(2) - } + fun main() { + let x: Int256 = 1 + let y: Int256 = x.saturatingSubtract(2) + } ` meter := newTestMemoryGauge() @@ -5475,9 +5480,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 * 2 - } + fun main() { + let x: Int256 = 1 * 2 + } ` meter := newTestMemoryGauge() @@ -5496,10 +5501,10 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - let y: Int256 = x.saturatingMultiply(2) - } + fun main() { + let x: Int256 = 1 + let y: Int256 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -5518,9 +5523,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 / 2 - } + fun main() { + let x: Int256 = 3 / 2 + } ` meter := newTestMemoryGauge() @@ -5539,10 +5544,10 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 - let y: Int256 = x.saturatingMultiply(2) - } + fun main() { + let x: Int256 = 3 + let y: Int256 = x.saturatingMultiply(2) + } ` meter := newTestMemoryGauge() @@ -5561,9 +5566,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 % 2 - } + fun main() { + let x: Int256 = 3 % 2 + } ` meter := newTestMemoryGauge() @@ -5582,10 +5587,10 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 1 - let y: Int256 = -x - } + fun main() { + let x: Int256 = 1 + let y: Int256 = -x + } ` meter := newTestMemoryGauge() @@ -5604,9 +5609,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 | 2 - } + fun main() { + let x: Int256 = 3 | 2 + } ` meter := newTestMemoryGauge() @@ -5625,9 +5630,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 ^ 2 - } + fun main() { + let x: Int256 = 3 ^ 2 + } ` meter := newTestMemoryGauge() @@ -5646,9 +5651,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 & 2 - } + fun main() { + let x: Int256 = 3 & 2 + } ` meter := newTestMemoryGauge() @@ -5667,9 +5672,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 << 2 - } + fun main() { + let x: Int256 = 3 << 2 + } ` meter := newTestMemoryGauge() @@ -5688,9 +5693,9 @@ func TestInterpretInt256Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Int256 = 3 >> 2 - } + fun main() { + let x: Int256 = 3 >> 2 + } ` meter := newTestMemoryGauge() @@ -5714,9 +5719,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word8 - } + fun main() { + let x = 1 as Word8 + } ` meter := newTestMemoryGauge() @@ -5735,9 +5740,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word8 + 2 as Word8 - } + fun main() { + let x = 1 as Word8 + 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5756,9 +5761,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as Word8 - 2 as Word8 - } + fun main() { + let x = 3 as Word8 - 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5777,9 +5782,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word8 * 2 as Word8 - } + fun main() { + let x = 1 as Word8 * 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5798,9 +5803,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 / 2 as Word8 - } + fun main() { + let x = 10 as Word8 / 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5819,9 +5824,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 % 2 as Word8 - } + fun main() { + let x = 10 as Word8 % 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5840,9 +5845,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 | 2 as Word8 - } + fun main() { + let x = 10 as Word8 | 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5861,9 +5866,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 ^ 2 as Word8 - } + fun main() { + let x = 10 as Word8 ^ 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5882,9 +5887,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 & 2 as Word8 - } + fun main() { + let x = 10 as Word8 & 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5903,9 +5908,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 << 2 as Word8 - } + fun main() { + let x = 10 as Word8 << 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5924,9 +5929,9 @@ func TestInterpretWord8Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word8 >> 2 as Word8 - } + fun main() { + let x = 10 as Word8 >> 2 as Word8 + } ` meter := newTestMemoryGauge() @@ -5950,9 +5955,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word16 - } + fun main() { + let x = 1 as Word16 + } ` meter := newTestMemoryGauge() @@ -5970,9 +5975,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word16 + 2 as Word16 - } + fun main() { + let x = 1 as Word16 + 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -5991,9 +5996,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as Word16 - 2 as Word16 - } + fun main() { + let x = 3 as Word16 - 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6012,9 +6017,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word16 * 2 as Word16 - } + fun main() { + let x = 1 as Word16 * 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6033,9 +6038,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 / 2 as Word16 - } + fun main() { + let x = 10 as Word16 / 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6054,9 +6059,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 % 2 as Word16 - } + fun main() { + let x = 10 as Word16 % 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6075,9 +6080,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 | 2 as Word16 - } + fun main() { + let x = 10 as Word16 | 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6096,9 +6101,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 ^ 2 as Word16 - } + fun main() { + let x = 10 as Word16 ^ 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6117,9 +6122,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 & 2 as Word16 - } + fun main() { + let x = 10 as Word16 & 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6138,9 +6143,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 << 2 as Word16 - } + fun main() { + let x = 10 as Word16 << 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6159,9 +6164,9 @@ func TestInterpretWord16Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word16 >> 2 as Word16 - } + fun main() { + let x = 10 as Word16 >> 2 as Word16 + } ` meter := newTestMemoryGauge() @@ -6185,9 +6190,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word32 - } + fun main() { + let x = 1 as Word32 + } ` meter := newTestMemoryGauge() @@ -6205,9 +6210,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word32 + 2 as Word32 - } + fun main() { + let x = 1 as Word32 + 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6226,9 +6231,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as Word32 - 2 as Word32 - } + fun main() { + let x = 3 as Word32 - 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6247,9 +6252,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word32 * 2 as Word32 - } + fun main() { + let x = 1 as Word32 * 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6268,9 +6273,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 / 2 as Word32 - } + fun main() { + let x = 10 as Word32 / 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6289,9 +6294,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 % 2 as Word32 - } + fun main() { + let x = 10 as Word32 % 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6310,9 +6315,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 | 2 as Word32 - } + fun main() { + let x = 10 as Word32 | 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6331,9 +6336,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 ^ 2 as Word32 - } + fun main() { + let x = 10 as Word32 ^ 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6352,9 +6357,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 & 2 as Word32 - } + fun main() { + let x = 10 as Word32 & 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6373,9 +6378,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 << 2 as Word32 - } + fun main() { + let x = 10 as Word32 << 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6394,9 +6399,9 @@ func TestInterpretWord32Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word32 >> 2 as Word32 - } + fun main() { + let x = 10 as Word32 >> 2 as Word32 + } ` meter := newTestMemoryGauge() @@ -6420,9 +6425,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word64 - } + fun main() { + let x = 1 as Word64 + } ` meter := newTestMemoryGauge() @@ -6440,9 +6445,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word64 + 2 as Word64 - } + fun main() { + let x = 1 as Word64 + 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6461,9 +6466,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 3 as Word64 - 2 as Word64 - } + fun main() { + let x = 3 as Word64 - 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6482,9 +6487,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 1 as Word64 * 2 as Word64 - } + fun main() { + let x = 1 as Word64 * 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6503,9 +6508,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 / 2 as Word64 - } + fun main() { + let x = 10 as Word64 / 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6524,9 +6529,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 % 2 as Word64 - } + fun main() { + let x = 10 as Word64 % 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6545,9 +6550,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 | 2 as Word64 - } + fun main() { + let x = 10 as Word64 | 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6566,9 +6571,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 ^ 2 as Word64 - } + fun main() { + let x = 10 as Word64 ^ 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6587,9 +6592,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 & 2 as Word64 - } + fun main() { + let x = 10 as Word64 & 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6608,9 +6613,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 << 2 as Word64 - } + fun main() { + let x = 10 as Word64 << 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6629,9 +6634,9 @@ func TestInterpretWord64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 10 as Word64 >> 2 as Word64 - } + fun main() { + let x = 10 as Word64 >> 2 as Word64 + } ` meter := newTestMemoryGauge() @@ -6653,12 +6658,12 @@ func TestInterpretStorageReferenceValueMetering(t *testing.T) { t.Parallel() script := ` - resource R {} + resource R {} - access(all) fun main(account: auth(Storage) &Account) { - account.storage.borrow<&R>(from: /storage/r) - } - ` + fun main(account: auth(Storage) &Account) { + account.storage.borrow<&R>(from: /storage/r) + } + ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6692,10 +6697,10 @@ func TestInterpretEphemeralReferenceValueMetering(t *testing.T) { script := ` resource R {} - access(all) fun main(): &Int { - let x: Int = 1 - let y = &x as &Int - return y + fun main(): &Int { + let x: Int = 1 + let y = &x as &Int + return y } ` @@ -6714,10 +6719,10 @@ func TestInterpretEphemeralReferenceValueMetering(t *testing.T) { script := ` resource R {} - access(all) fun main(): &Int { - let x: Int? = 1 - let y = &x as &Int? - return y! + fun main(): &Int { + let x: Int? = 1 + let y = &x as &Int? + return y! } ` @@ -6740,9 +6745,9 @@ func TestInterpretStringMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = "a" - } + fun main() { + let x = "a" + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6758,10 +6763,10 @@ func TestInterpretStringMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = "a" - let y = x - } + fun main() { + let x = "a" + let y = x + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6777,9 +6782,9 @@ func TestInterpretStringMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = "İ" - } + fun main() { + let x = "İ" + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6795,9 +6800,9 @@ func TestInterpretStringMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = "ABC".toLower() - } + fun main() { + let x = "ABC".toLower() + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6814,9 +6819,9 @@ func TestInterpretStringMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = "İ".toLower() - } + fun main() { + let x = "İ".toLower() + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6836,9 +6841,9 @@ func TestInterpretCharacterMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Character = "a" - } + fun main() { + let x: Character = "a" + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6854,10 +6859,10 @@ func TestInterpretCharacterMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Character = "a" - let y = x - } + fun main() { + let x: Character = "a" + let y = x + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6873,10 +6878,10 @@ func TestInterpretCharacterMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: String = "a" - let y: Character = x[0] - } + fun main() { + let x: String = "a" + let y: Character = x[0] + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6895,9 +6900,9 @@ func TestInterpretAddressValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Address = 0x0 - } + fun main() { + let x: Address = 0x0 + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6912,9 +6917,9 @@ func TestInterpretAddressValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = Address(0x0) - } + fun main() { + let x = Address(0x0) + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6933,9 +6938,9 @@ func TestInterpretPathValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = /public/bar - } + fun main() { + let x = /public/bar + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6950,9 +6955,9 @@ func TestInterpretPathValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = PublicPath(identifier: "bar") - } + fun main() { + let x = PublicPath(identifier: "bar") + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -6985,9 +6990,9 @@ func TestInterpretTypeValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let t: Type = Type() - } + fun main() { + let t: Type = Type() + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7002,9 +7007,9 @@ func TestInterpretTypeValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let t: Type = ConstantSizedArrayType(type: Type(), size: 2) - } + fun main() { + let t: Type = ConstantSizedArrayType(type: Type(), size: 2) + } ` meter := newTestMemoryGauge() @@ -7020,10 +7025,10 @@ func TestInterpretTypeValueMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let v = 5 - let t: Type = v.getType() - } + fun main() { + let v = 5 + let t: Type = v.getType() + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7042,12 +7047,12 @@ func TestInterpretVariableMetering(t *testing.T) { t.Parallel() script := ` - var a = 3 - let b = false + var a = 3 + let b = false - access(all) fun main() { - - } + fun main() { + + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7062,9 +7067,9 @@ func TestInterpretVariableMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main(a: String, b: Bool) { - - } + fun main(a: String, b: Bool) { + + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7083,9 +7088,9 @@ func TestInterpretVariableMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var x = fun (x: String, y: Bool) {} - } + fun main() { + var x = fun (x: String, y: Bool) {} + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7100,10 +7105,10 @@ func TestInterpretVariableMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var x = fun (x: String, y: Bool) {} - x("", false) - } + fun main() { + var x = fun (x: String, y: Bool) {} + x("", false) + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7124,9 +7129,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - } + fun main() { + let x: Fix64 = 1.4 + } ` meter := newTestMemoryGauge() @@ -7144,9 +7149,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 + 2.5 - } + fun main() { + let x: Fix64 = 1.4 + 2.5 + } ` meter := newTestMemoryGauge() @@ -7166,10 +7171,10 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - let y: Fix64 = x.saturatingAdd(2.5) - } + fun main() { + let x: Fix64 = 1.4 + let y: Fix64 = x.saturatingAdd(2.5) + } ` meter := newTestMemoryGauge() @@ -7189,9 +7194,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - 2.5 - } + fun main() { + let x: Fix64 = 1.4 - 2.5 + } ` meter := newTestMemoryGauge() @@ -7211,10 +7216,10 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - let y: Fix64 = x.saturatingSubtract(2.5) - } + fun main() { + let x: Fix64 = 1.4 + let y: Fix64 = x.saturatingSubtract(2.5) + } ` meter := newTestMemoryGauge() @@ -7234,9 +7239,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 * 2.5 - } + fun main() { + let x: Fix64 = 1.4 * 2.5 + } ` meter := newTestMemoryGauge() @@ -7256,10 +7261,10 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - let y: Fix64 = x.saturatingMultiply(2.5) - } + fun main() { + let x: Fix64 = 1.4 + let y: Fix64 = x.saturatingMultiply(2.5) + } ` meter := newTestMemoryGauge() @@ -7279,9 +7284,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 3.4 / 2.5 - } + fun main() { + let x: Fix64 = 3.4 / 2.5 + } ` meter := newTestMemoryGauge() @@ -7301,10 +7306,10 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 3.4 - let y: Fix64 = x.saturatingMultiply(2.5) - } + fun main() { + let x: Fix64 = 3.4 + let y: Fix64 = x.saturatingMultiply(2.5) + } ` meter := newTestMemoryGauge() @@ -7324,9 +7329,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 3.4 % 2.5 - } + fun main() { + let x: Fix64 = 3.4 % 2.5 + } ` meter := newTestMemoryGauge() @@ -7349,10 +7354,10 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.4 - let y: Fix64 = -x - } + fun main() { + let x: Fix64 = 1.4 + let y: Fix64 = -x + } ` meter := newTestMemoryGauge() @@ -7373,9 +7378,9 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: FixedPoint = -1.4 - } + fun main() { + let x: FixedPoint = -1.4 + } ` meter := newTestMemoryGauge() @@ -7393,15 +7398,15 @@ func TestInterpretFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Fix64 = 1.0 - x == 1.0 - x != 1.0 - x > 1.0 - x >= 1.0 - x < 1.0 - x <= 1.0 - } + fun main() { + let x: Fix64 = 1.0 + x == 1.0 + x != 1.0 + x > 1.0 + x >= 1.0 + x < 1.0 + x <= 1.0 + } ` meter := newTestMemoryGauge() @@ -7423,9 +7428,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 - } + fun main() { + let x: UFix64 = 1.4 + } ` meter := newTestMemoryGauge() @@ -7443,9 +7448,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 + 2.5 - } + fun main() { + let x: UFix64 = 1.4 + 2.5 + } ` meter := newTestMemoryGauge() @@ -7465,10 +7470,10 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 - let y: UFix64 = x.saturatingAdd(2.5) - } + fun main() { + let x: UFix64 = 1.4 + let y: UFix64 = x.saturatingAdd(2.5) + } ` meter := newTestMemoryGauge() @@ -7488,9 +7493,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 2.5 - 1.4 - } + fun main() { + let x: UFix64 = 2.5 - 1.4 + } ` meter := newTestMemoryGauge() @@ -7510,10 +7515,10 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 - let y: UFix64 = x.saturatingSubtract(2.5) - } + fun main() { + let x: UFix64 = 1.4 + let y: UFix64 = x.saturatingSubtract(2.5) + } ` meter := newTestMemoryGauge() @@ -7533,9 +7538,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 * 2.5 - } + fun main() { + let x: UFix64 = 1.4 * 2.5 + } ` meter := newTestMemoryGauge() @@ -7555,10 +7560,10 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.4 - let y: UFix64 = x.saturatingMultiply(2.5) - } + fun main() { + let x: UFix64 = 1.4 + let y: UFix64 = x.saturatingMultiply(2.5) + } ` meter := newTestMemoryGauge() @@ -7578,9 +7583,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 3.4 / 2.5 - } + fun main() { + let x: UFix64 = 3.4 / 2.5 + } ` meter := newTestMemoryGauge() @@ -7600,10 +7605,10 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 3.4 - let y: UFix64 = x.saturatingMultiply(2.5) - } + fun main() { + let x: UFix64 = 3.4 + let y: UFix64 = x.saturatingMultiply(2.5) + } ` meter := newTestMemoryGauge() @@ -7623,9 +7628,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 3.4 % 2.5 - } + fun main() { + let x: UFix64 = 3.4 % 2.5 + } ` meter := newTestMemoryGauge() @@ -7648,9 +7653,9 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: FixedPoint = 1.4 - } + fun main() { + let x: FixedPoint = 1.4 + } ` meter := newTestMemoryGauge() @@ -7668,15 +7673,15 @@ func TestInterpretUFix64Metering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: UFix64 = 1.0 - x == 1.0 - x != 1.0 - x > 1.0 - x >= 1.0 - x < 1.0 - x <= 1.0 - } + fun main() { + let x: UFix64 = 1.0 + x == 1.0 + x != 1.0 + x > 1.0 + x >= 1.0 + x < 1.0 + x <= 1.0 + } ` meter := newTestMemoryGauge() @@ -7696,17 +7701,17 @@ func TestInterpretTokenMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var x: String = "hello" - } + fun main() { + var x: String = "hello" + } - access(all) struct foo { - var x: Int + struct foo { + var x: Int - init() { - self.x = 4 - } - } + init() { + self.x = 4 + } + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7714,8 +7719,8 @@ func TestInterpretTokenMetering(t *testing.T) { _, err := inter.Invoke("main") require.NoError(t, err) - assert.Equal(t, uint64(38), meter.getMemory(common.MemoryKindTypeToken)) - assert.Equal(t, uint64(25), meter.getMemory(common.MemoryKindSpaceToken)) + assert.Equal(t, uint64(30), meter.getMemory(common.MemoryKindTypeToken)) + assert.Equal(t, uint64(23), meter.getMemory(common.MemoryKindSpaceToken)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) }) @@ -7723,20 +7728,20 @@ func TestInterpretTokenMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var a: [String] = [] - var b = 4 + 6 - var c = true && false != false - var d = 4 as! AnyStruct - } + fun main() { + var a: [String] = [] + var b = 4 + 6 + var c = true && false != false + var d = 4 as! AnyStruct + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) _, err := inter.Invoke("main") require.NoError(t, err) - assert.Equal(t, uint64(39), meter.getMemory(common.MemoryKindTypeToken)) - assert.Equal(t, uint64(31), meter.getMemory(common.MemoryKindSpaceToken)) + assert.Equal(t, uint64(35), meter.getMemory(common.MemoryKindTypeToken)) + assert.Equal(t, uint64(30), meter.getMemory(common.MemoryKindSpaceToken)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) }) @@ -7744,20 +7749,20 @@ func TestInterpretTokenMetering(t *testing.T) { t.Parallel() script := ` - /* first line - second line - */ + /* first line + second line + */ - // single line comment - access(all) fun main() {} + // single line comment + fun main() {} ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) _, err := inter.Invoke("main") require.NoError(t, err) - assert.Equal(t, uint64(14), meter.getMemory(common.MemoryKindTypeToken)) - assert.Equal(t, uint64(7), meter.getMemory(common.MemoryKindSpaceToken)) + assert.Equal(t, uint64(10), meter.getMemory(common.MemoryKindTypeToken)) + assert.Equal(t, uint64(6), meter.getMemory(common.MemoryKindSpaceToken)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) }) @@ -7765,21 +7770,21 @@ func TestInterpretTokenMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var a = 1 - var b = 0b1 - var c = 0o1 - var d = 0x1 - var e = 1.4 - } + fun main() { + var a = 1 + var b = 0b1 + var c = 0o1 + var d = 0x1 + var e = 1.4 + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) _, err := inter.Invoke("main") require.NoError(t, err) - assert.Equal(t, uint64(30), meter.getMemory(common.MemoryKindTypeToken)) - assert.Equal(t, uint64(26), meter.getMemory(common.MemoryKindSpaceToken)) + assert.Equal(t, uint64(26), meter.getMemory(common.MemoryKindTypeToken)) + assert.Equal(t, uint64(25), meter.getMemory(common.MemoryKindSpaceToken)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) }) } @@ -7793,11 +7798,11 @@ func TestInterpreterStringLocationMetering(t *testing.T) { // Raw string count with empty location script := ` - struct S {} + struct S {} - access(all) fun main() { - let s = CompositeType("") - } + fun main() { + let s = CompositeType("") + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7810,11 +7815,11 @@ func TestInterpreterStringLocationMetering(t *testing.T) { // Raw string count with non-empty location script = ` - struct S {} + struct S {} - access(all) fun main() { - let s = CompositeType("S.test.S") - } + fun main() { + let s = CompositeType("S.test.S") + } ` meter = newTestMemoryGauge() @@ -7841,10 +7846,10 @@ func TestInterpretIdentifierMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let foo = 4 - let bar = 5 - } + fun main() { + let foo = 4 + let bar = 5 + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7860,8 +7865,8 @@ func TestInterpretIdentifierMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main(foo: String, bar: String) { - } + fun main(foo: String, bar: String) { + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -7881,18 +7886,18 @@ func TestInterpretIdentifierMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() {} + fun main() {} - access(all) struct foo { - var x: String - var y: String + struct foo { + var x: String + var y: String - init() { - self.x = "a" - self.y = "b" - } + init() { + self.x = "a" + self.y = "b" + } - access(all) fun bar() {} + fun bar() {} } ` @@ -7908,13 +7913,13 @@ func TestInterpretIdentifierMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { // 2 - 'main', empty-return-type - let foo = ["a", "b"] // 1 - foo.length // 3 - 'foo', 'length', constant field resolver - foo.length // 3 - 'foo', 'length', constant field resolver (not re-used) - foo.removeFirst() // 3 - 'foo', 'removeFirst', function resolver - foo.removeFirst() // 3 - 'foo', 'removeFirst', function resolver (not re-used) - } + fun main() { // 2 - 'main', empty-return-type + let foo = ["a", "b"] // 1 + foo.length // 3 - 'foo', 'length', constant field resolver + foo.length // 3 - 'foo', 'length', constant field resolver (not re-used) + foo.removeFirst() // 3 - 'foo', 'removeFirst', function resolver + foo.removeFirst() // 3 - 'foo', 'removeFirst', function resolver (not re-used) + } ` meter := newTestMemoryGauge() @@ -7934,15 +7939,15 @@ func TestInterpretInterfaceStaticType(t *testing.T) { t.Parallel() script := ` - struct interface I {} + struct interface I {} - access(all) fun main() { - let type = Type<{I}>() + fun main() { + let type = Type<{I}>() - IntersectionType( - types: [type.identifier] - ) - } + IntersectionType( + types: [type.identifier] + ) + } ` meter := newTestMemoryGauge() @@ -7963,9 +7968,9 @@ func TestInterpretFunctionStaticType(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - FunctionType(parameters: [], return: Type()) - } + fun main() { + FunctionType(parameters: [], return: Type()) + } ` meter := newTestMemoryGauge() @@ -7981,11 +7986,11 @@ func TestInterpretFunctionStaticType(t *testing.T) { t.Parallel() script := ` - access(all) fun hello() {} + fun hello() {} - access(all) fun main() { - let a = [hello] - } + fun main() { + let a = [hello] + } ` meter := newTestMemoryGauge() @@ -8001,14 +8006,14 @@ func TestInterpretFunctionStaticType(t *testing.T) { t.Parallel() script := ` - access(all) struct S { - fun naught() {} - } + struct S { + fun naught() {} + } - access(all) fun main() { - let x = S() - let y = x.naught - } + fun main() { + let x = S() + let y = x.naught + } ` meter := newTestMemoryGauge() @@ -8024,14 +8029,14 @@ func TestInterpretFunctionStaticType(t *testing.T) { t.Parallel() script := ` - access(all) struct S { - fun naught() {} - } + struct S { + fun naught() {} + } - access(all) fun main() { - let x = S() - x.naught.isInstance(Type()) - } + fun main() { + let x = S() + x.naught.isInstance(Type()) + } ` meter := newTestMemoryGauge() @@ -8051,16 +8056,16 @@ func TestInterpretASTMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - foo(a: "hello", b: 23) - bar("hello", 23) - } + fun main() { + foo(a: "hello", b: 23) + bar("hello", 23) + } - access(all) fun foo(a: String, b: Int) { - } + fun foo(a: String, b: Int) { + } - access(all) fun bar(_ a: String, _ b: Int) { - } + fun bar(_ a: String, _ b: Int) { + } ` meter := newTestMemoryGauge() inter := parseCheckAndInterpretWithMemoryMetering(t, script, meter) @@ -8073,26 +8078,26 @@ func TestInterpretASTMetering(t *testing.T) { t.Run("blocks", func(t *testing.T) { script := ` - access(all) fun main() { - var i = 0 - if i != 0 { - i = 0 - } - - while i < 2 { - i = i + 1 - } - - var a = "foo" - switch i { - case 1: - a = "foo_1" - case 2: - a = "foo_2" - case 3: - a = "foo_3" - } - } + fun main() { + var i = 0 + if i != 0 { + i = 0 + } + + while i < 2 { + i = i + 1 + } + + var a = "foo" + switch i { + case 1: + a = "foo_1" + case 2: + a = "foo_2" + case 3: + a = "foo_3" + } + } ` meter := newTestMemoryGauge() @@ -8106,51 +8111,51 @@ func TestInterpretASTMetering(t *testing.T) { t.Run("declarations", func(t *testing.T) { script := ` - import Foo from 0x42 + import Foo from 0x42 - access(all) let x = 1 - access(all) var y = 2 + let x = 1 + var y = 2 - access(all) fun main() { - var z = 3 - } + fun main() { + var z = 3 + } - access(all) fun foo(_ x: String, _ y: Int) {} + fun foo(_ x: String, _ y: Int) {} - access(all) struct A { - access(all) var a: String + struct A { + var a: String - init() { - self.a = "hello" - } - } + init() { + self.a = "hello" + } + } - access(all) struct interface B {} + struct interface B {} - access(all) resource C { - let a: Int + resource C { + let a: Int - init() { - self.a = 6 - } - } + init() { + self.a = 6 + } + } - access(all) resource interface D {} + resource interface D {} - access(all) enum E: Int8 { - access(all) case a - access(all) case b - access(all) case c - } + enum E: Int8 { + case a + case b + case c + } - transaction {} + transaction {} - #pragma + #pragma ` importedChecker, err := checker.ParseAndCheckWithOptions(t, ` - access(all) let Foo = 1 + let Foo = 1 `, checker.ParseAndCheckOptions{ Location: utils.ImportedLocation, @@ -8214,47 +8219,47 @@ func TestInterpretASTMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var a = 5 + fun main() { + var a = 5 - while a < 10 { // while - if a == 5 { // if - a = a + 1 // assignment - continue // continue - } - break // break - } + while a < 10 { // while + if a == 5 { // if + a = a + 1 // assignment + continue // continue + } + break // break + } - foo() // expression statement + foo() // expression statement - for value in [1, 2, 3] {} // for + for value in [1, 2, 3] {} // for - var r1 <- create bar() - var r2 <- create bar() - r1 <-> r2 // swap + var r1 <- create bar() + var r2 <- create bar() + r1 <-> r2 // swap - destroy r1 // expression statement - destroy r2 // expression statement + destroy r1 // expression statement + destroy r2 // expression statement - switch a { // switch - case 1: - a = 2 // assignment - } - } + switch a { // switch + case 1: + a = 2 // assignment + } + } - access(all) fun foo(): Int { - return 5 // return - } + fun foo(): Int { + return 5 // return + } - resource bar {} + resource bar {} - access(all) contract Events { - event FooEvent(x: Int, y: Int) + contract Events { + event FooEvent(x: Int, y: Int) - fun events() { - emit FooEvent(x: 1, y: 2) // emit - } - } + fun events() { + emit FooEvent(x: 1, y: 2) // emit + } + } ` meter := newTestMemoryGauge() @@ -8302,32 +8307,32 @@ func TestInterpretASTMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var a = 5 // integer expr - var b = 1.2 + 2.3 // binary, fixed-point expr - var c = !true // unary, boolean expr - var d: String? = "hello" // string expr - var e = nil // nil expr - var f: [AnyStruct] = [[], [], []] // array expr - var g: {Int: {Int: AnyStruct}} = {1:{}} // nil expr - var h <- create bar() // create, identifier, invocation - var i = h.baz // member access, identifier x2 - destroy h // destroy - var j = f[0] // index access, identifier, integer - var k = fun() {} // function expr - k() // identifier, invocation - var l = c ? 1 : 2 // conditional, identifier, integer x2 - var m = d as AnyStruct // casting, identifier - var n = &d as &AnyStruct? // reference, casting, identifier - var o = d! // force, identifier - var p = /public/somepath // path - } + fun main() { + var a = 5 // integer expr + var b = 1.2 + 2.3 // binary, fixed-point expr + var c = !true // unary, boolean expr + var d: String? = "hello" // string expr + var e = nil // nil expr + var f: [AnyStruct] = [[], [], []] // array expr + var g: {Int: {Int: AnyStruct}} = {1:{}} // nil expr + var h <- create bar() // create, identifier, invocation + var i = h.baz // member access, identifier x2 + destroy h // destroy + var j = f[0] // index access, identifier, integer + var k = fun() {} // function expr + k() // identifier, invocation + var l = c ? 1 : 2 // conditional, identifier, integer x2 + var m = d as AnyStruct // casting, identifier + var n = &d as &AnyStruct? // reference, casting, identifier + var o = d! // force, identifier + var p = /public/somepath // path + } - resource bar { - let baz: Int - init() { - self.baz = 0x4 - } + resource bar { + let baz: Int + init() { + self.baz = 0x4 + } } ` meter := newTestMemoryGauge() @@ -8366,25 +8371,25 @@ func TestInterpretASTMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - var a: Int = 5 // nominal type - var b: String? = "hello" // optional type - var c: [Int; 2] = [1, 2] // constant sized type - var d: [String] = [] // variable sized type - var e: {Int: String} = {} // dictionary type + fun main() { + var a: Int = 5 // nominal type + var b: String? = "hello" // optional type + var c: [Int; 2] = [1, 2] // constant sized type + var d: [String] = [] // variable sized type + var e: {Int: String} = {} // dictionary type - var f: fun(String):Int = fun(_a: String): Int { // function type - return 1 - } + var f: fun(String):Int = fun(_a: String): Int { // function type + return 1 + } - var g = &a as &Int // reference type - var h: {foo} = bar() // intersection type - var i: Capability<&bar>? = nil // instantiation type - } + var g = &a as &Int // reference type + var h: {foo} = bar() // intersection type + var i: Capability<&bar>? = nil // instantiation type + } - struct interface foo {} + struct interface foo {} - struct bar: foo {} + struct bar: foo {} ` meter := newTestMemoryGauge() @@ -8408,24 +8413,24 @@ func TestInterpretASTMetering(t *testing.T) { t.Run("position info", func(t *testing.T) { script := ` - access(all) let x = 1 - access(all) var y = 2 + let x = 1 + var y = 2 - access(all) fun main() { - var z = 3 - } + fun main() { + var z = 3 + } - access(all) fun foo(_ x: String, _ y: Int) {} + fun foo(_ x: String, _ y: Int) {} - access(all) struct A { - access(all) var a: String + struct A { + var a: String - init() { - self.a = "hello" - } - } + init() { + self.a = "hello" + } + } - access(all) struct interface B {} + struct interface B {} ` meter := newTestMemoryGauge() @@ -8435,20 +8440,20 @@ func TestInterpretASTMetering(t *testing.T) { _, err := inter.Invoke("main") require.NoError(t, err) - assert.Equal(t, uint64(271), meter.getMemory(common.MemoryKindPosition)) - assert.Equal(t, uint64(145), meter.getMemory(common.MemoryKindRange)) + assert.Equal(t, uint64(201), meter.getMemory(common.MemoryKindPosition)) + assert.Equal(t, uint64(110), meter.getMemory(common.MemoryKindRange)) }) t.Run("locations", func(t *testing.T) { script := ` - import A from 0x42 - import B from "string-location" + import A from 0x42 + import B from "string-location" ` importedChecker, err := checker.ParseAndCheckWithOptions(t, ` - access(all) let A = 1 - access(all) let B = 1 + let A = 1 + let B = 1 `, checker.ParseAndCheckOptions{ Location: utils.ImportedLocation, @@ -8499,7 +8504,7 @@ func TestInterpretVariableActivationMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() {} + fun main() {} ` meter := newTestMemoryGauge() @@ -8517,12 +8522,12 @@ func TestInterpretVariableActivationMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - foo(a: "hello", b: 23) - } + fun main() { + foo(a: "hello", b: 23) + } - access(all) fun foo(a: String, b: Int) { - } + fun foo(a: String, b: Int) { + } ` meter := newTestMemoryGauge() @@ -8540,11 +8545,11 @@ func TestInterpretVariableActivationMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - if true { - let a = 1 - } - } + fun main() { + if true { + let a = 1 + } + } ` meter := newTestMemoryGauge() @@ -8565,16 +8570,16 @@ func TestInterpretStaticTypeConversionMetering(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let a: {Int: {Foo}} = {} // dictionary + intersection - let b: [&Int] = [] // variable-sized + reference - let c: [Int?; 2] = [1, 2] // constant-sized + optional - let d: [Capability<&Bar>] = [] // capability + variable-sized + reference - } + fun main() { + let a: {Int: {Foo}} = {} // dictionary + intersection + let b: [&Int] = [] // variable-sized + reference + let c: [Int?; 2] = [1, 2] // constant-sized + optional + let d: [Capability<&Bar>] = [] // capability + variable-sized + reference + } - access(all) struct interface Foo {} + struct interface Foo {} - access(all) struct Bar: Foo {} + struct Bar: Foo {} ` meter := newTestMemoryGauge() @@ -8597,12 +8602,12 @@ func TestInterpretStorageMapMetering(t *testing.T) { t.Parallel() script := ` - resource R {} + resource R {} - access(all) fun main(account: auth(Storage) &Account) { - let r <- create R() - account.storage.save(<-r, to: /storage/r) - } + fun main(account: auth(Storage) &Account) { + let r <- create R() + account.storage.save(<-r, to: /storage/r) + } ` meter := newTestMemoryGauge() @@ -8840,11 +8845,11 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := fmt.Sprintf(` - access(all) fun main() { - let x = %s - log(x) - } - `, + fun main() { + let x = %s + log(x) + } + `, test.constructor, ) @@ -8861,17 +8866,17 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = Foo() - log(x) - } + fun main() { + let x = Foo() + log(x) + } - struct Foo { - var a: Word8 - init() { - self.a = 4 - } - } + struct Foo { + var a: Word8 + init() { + self.a = 4 + } + } ` testValueStringConversion(t, script) @@ -8881,10 +8886,10 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = 4 - log(&x as &AnyStruct) - } + fun main() { + let x = 4 + log(&x as &AnyStruct) + } ` testValueStringConversion(t, script) @@ -8894,10 +8899,10 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = fun(a: String, b: Bool) {} - log(&x as &AnyStruct) - } + fun main() { + let x = fun(a: String, b: Bool) {} + log(&x as &AnyStruct) + } ` testValueStringConversion(t, script) @@ -8907,14 +8912,14 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x = Foo() - log(x.bar) - } + fun main() { + let x = Foo() + log(x.bar) + } - struct Foo { - access(all) fun bar(a: String, b: Bool) {} - } + struct Foo { + fun bar(a: String, b: Bool) {} + } ` testValueStringConversion(t, script) @@ -8924,12 +8929,12 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - let x: Void = foo() - log(x) - } + fun main() { + let x: Void = foo() + log(x) + } - fun foo() {} + fun foo() {} ` testValueStringConversion(t, script) @@ -8939,12 +8944,12 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main(a: Capability<&{Foo}>) { - log(a) - } + fun main(a: Capability<&{Foo}>) { + log(a) + } - struct interface Foo {} - struct Bar: Foo {} + struct interface Foo {} + struct Bar: Foo {} ` testValueStringConversion(t, @@ -8960,9 +8965,9 @@ func TestInterpretValueStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - log(Type()) - } + fun main() { + log(Type()) + } ` testValueStringConversion(t, script) @@ -9054,10 +9059,12 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { continue } - script := fmt.Sprintf(` - access(all) fun main() { - log(Type<%s>()) - }`, + script := fmt.Sprintf( + ` + fun main() { + log(Type<%s>()) + } + `, sema.NewTypeAnnotation(semaType).QualifiedString(), ) @@ -9114,8 +9121,8 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { t.Parallel() script := fmt.Sprintf(` - entitlement X - access(all) fun main() { + entitlement X + fun main() { log(Type<%s>()) } `, @@ -9135,16 +9142,16 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - log(Type()) - } + fun main() { + log(Type()) + } - struct Foo { - var a: Word8 - init() { - self.a = 4 - } - } + struct Foo { + var a: Word8 + init() { + self.a = 4 + } + } ` testStaticTypeStringConversion(t, script) @@ -9154,11 +9161,11 @@ func TestInterpretStaticTypeStringConversion(t *testing.T) { t.Parallel() script := ` - access(all) fun main() { - log(Type<{Foo}>()) - } + fun main() { + log(Type<{Foo}>()) + } - struct interface Foo {} + struct interface Foo {} ` testStaticTypeStringConversion(t, script) @@ -9170,9 +9177,9 @@ func TestInterpretBytesMetering(t *testing.T) { t.Parallel() const code = ` - fun test(string: String) { - let utf8 = string.utf8 - } + fun test(string: String) { + let utf8 = string.utf8 + } ` meter := newTestMemoryGauge() From 4aec500e495c6a18c0c305b8d0e7a919a0f87536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 May 2023 17:11:16 -0700 Subject: [PATCH 02/47] fix memory metering for loading stored dictionary --- runtime/common/metering.go | 12 +- runtime/interpreter/storage.go | 15 ++- runtime/interpreter/value.go | 107 +++++++++++------- .../tests/interpreter/memory_metering_test.go | 20 ++-- 4 files changed, 94 insertions(+), 60 deletions(-) diff --git a/runtime/common/metering.go b/runtime/common/metering.go index 6dc5b99b30..46e98f1205 100644 --- a/runtime/common/metering.go +++ b/runtime/common/metering.go @@ -376,12 +376,14 @@ func NewAtreeArrayMemoryUsages(count uint64, elementSize uint) (MemoryUsage, Mem branches } -func NewDictionaryMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { +func NewAtreeMapMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage) { leaves, branches := newAtreeMapMemoryUsage(count, elementSize) - return DictionaryValueBaseMemoryUsage, MemoryUsage{ - Kind: MemoryKindAtreeMapElementOverhead, - Amount: count, - }, leaves, branches + return MemoryUsage{ + Kind: MemoryKindAtreeMapElementOverhead, + Amount: count, + }, + leaves, + branches } func NewCompositeMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { diff --git a/runtime/interpreter/storage.go b/runtime/interpreter/storage.go index 7246c8c51d..62db66fb78 100644 --- a/runtime/interpreter/storage.go +++ b/runtime/interpreter/storage.go @@ -73,13 +73,20 @@ func ConvertStoredValue(gauge common.MemoryGauge, value atree.Value) (Value, err case *atree.OrderedMap: typeInfo := value.Type() - switch typeInfo := typeInfo.(type) { + switch staticType := typeInfo.(type) { case *DictionaryStaticType: - return newDictionaryValueFromConstructor(gauge, typeInfo, value.Count(), func() *atree.OrderedMap { return value }), nil + return newDictionaryValueFromAtreeMap( + gauge, + staticType, + DictionaryElementSize(staticType), + value, + ), nil + case compositeTypeInfo: - return newCompositeValueFromConstructor(gauge, value.Count(), typeInfo, func() *atree.OrderedMap { return value }), nil + return newCompositeValueFromConstructor(gauge, value.Count(), staticType, func() *atree.OrderedMap { return value }), nil + default: - return nil, errors.NewUnexpectedError("invalid ordered map type info: %T", typeInfo) + return nil, errors.NewUnexpectedError("invalid ordered map type info: %T", staticType) } case Value: diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index fa511578c5..66f6390aea 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2669,7 +2669,10 @@ func (v *ArrayValue) Transfer( v.checkInvalidatedResourceUse(interpreter, locationRange) } - interpreter.ReportComputation(common.ComputationKindTransferArrayValue, uint(v.Count())) + interpreter.ReportComputation( + common.ComputationKindTransferArrayValue, + uint(v.Count()), + ) if config.TracingEnabled { startTime := time.Now() @@ -17891,14 +17894,13 @@ func NewDictionaryValueWithAddress( return v } -func newDictionaryValueFromOrderedMap( - dict *atree.OrderedMap, - staticType *DictionaryStaticType, -) *DictionaryValue { - return &DictionaryValue{ - Type: staticType, - dictionary: dict, +func DictionaryElementSize(staticType *DictionaryStaticType) uint { + keySize := staticType.KeyType.elementSize() + valueSize := staticType.ValueType.elementSize() + if keySize == 0 || valueSize == 0 { + return 0 } + return keySize + valueSize } func newDictionaryValueWithIterator( @@ -17968,23 +17970,38 @@ func newDictionaryValueFromConstructor( staticType *DictionaryStaticType, count uint64, constructor func() *atree.OrderedMap, -) (dict *DictionaryValue) { +) *DictionaryValue { - keySize := staticType.KeyType.elementSize() - valueSize := staticType.ValueType.elementSize() - var elementSize uint - if keySize != 0 && valueSize != 0 { - elementSize = keySize + valueSize - } - baseUsage, overheadUsage, dataSlabs, metaDataSlabs := common.NewDictionaryMemoryUsages(count, elementSize) - common.UseMemory(gauge, baseUsage) + elementSize := DictionaryElementSize(staticType) + + overheadUsage, dataSlabs, metaDataSlabs := + common.NewAtreeMapMemoryUsages(count, elementSize) common.UseMemory(gauge, overheadUsage) common.UseMemory(gauge, dataSlabs) common.UseMemory(gauge, metaDataSlabs) - dict = newDictionaryValueFromOrderedMap(constructor(), staticType) - dict.elementSize = elementSize - return + return newDictionaryValueFromAtreeMap( + gauge, + staticType, + elementSize, + constructor(), + ) +} + +func newDictionaryValueFromAtreeMap( + gauge common.MemoryGauge, + staticType *DictionaryStaticType, + elementSize uint, + atreeOrderedMap *atree.OrderedMap, +) *DictionaryValue { + + common.UseMemory(gauge, common.DictionaryValueBaseMemoryUsage) + + return &DictionaryValue{ + Type: staticType, + dictionary: atreeOrderedMap, + elementSize: elementSize, + } } var _ Value = &DictionaryValue{} @@ -18863,16 +18880,6 @@ func (v *DictionaryValue) Transfer( storable atree.Storable, preventTransfer map[atree.StorageID]struct{}, ) Value { - baseUse, elementOverhead, dataUse, metaDataUse := common.NewDictionaryMemoryUsages( - v.dictionary.Count(), - v.elementSize, - ) - common.UseMemory(interpreter, baseUse) - common.UseMemory(interpreter, elementOverhead) - common.UseMemory(interpreter, dataUse) - common.UseMemory(interpreter, metaDataUse) - - interpreter.ReportComputation(common.ComputationKindTransferDictionaryValue, uint(v.Count())) config := interpreter.SharedState.Config @@ -18880,6 +18887,11 @@ func (v *DictionaryValue) Transfer( v.checkInvalidatedResourceUse(interpreter, locationRange) } + interpreter.ReportComputation( + common.ComputationKindTransferDictionaryValue, + uint(v.Count()), + ) + if config.TracingEnabled { startTime := time.Now() @@ -18922,7 +18934,10 @@ func (v *DictionaryValue) Transfer( panic(errors.NewExternalError(err)) } - elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(v.dictionary.Count(), v.elementSize) + elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage( + v.dictionary.Count(), + v.elementSize, + ) common.UseMemory(config.MemoryGauge, elementMemoryUse) dictionary, err = atree.NewMapFromBatchData( @@ -18993,8 +19008,13 @@ func (v *DictionaryValue) Transfer( } if res == nil { - res = newDictionaryValueFromOrderedMap(dictionary, v.Type) - res.elementSize = v.elementSize + res = newDictionaryValueFromAtreeMap( + interpreter, + v.Type, + v.elementSize, + dictionary, + ) + res.semaType = v.semaType res.isResourceKinded = v.isResourceKinded res.isDestroyed = v.isDestroyed @@ -19017,7 +19037,7 @@ func (v *DictionaryValue) Clone(interpreter *Interpreter) Value { elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(v.dictionary.Count(), v.elementSize) common.UseMemory(config.MemoryGauge, elementMemoryUse) - dictionary, err := atree.NewMapFromBatchData( + orderedMap, err := atree.NewMapFromBatchData( config.Storage, v.StorageAddress(), atree.NewDefaultDigesterBuilder(), @@ -19048,13 +19068,18 @@ func (v *DictionaryValue) Clone(interpreter *Interpreter) Value { panic(errors.NewExternalError(err)) } - return &DictionaryValue{ - Type: v.Type, - semaType: v.semaType, - isResourceKinded: v.isResourceKinded, - dictionary: dictionary, - isDestroyed: v.isDestroyed, - } + dictionary := newDictionaryValueFromAtreeMap( + interpreter, + v.Type, + v.elementSize, + orderedMap, + ) + + dictionary.semaType = v.semaType + dictionary.isResourceKinded = v.isResourceKinded + dictionary.isDestroyed = v.isDestroyed + + return dictionary } func (v *DictionaryValue) DeepRemove(interpreter *Interpreter) { diff --git a/runtime/tests/interpreter/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 9e77f4cb17..4557a777c4 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -410,8 +410,8 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindStringValue)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(159), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindVariable)) @@ -431,7 +431,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { fun main() { let values: [{Int8: String}] = [{}, {}, {}] for value in values { - let a = value + let a = value } } ` @@ -493,7 +493,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(10), meter.getMemory(common.MemoryKindPrimitiveStaticType)) assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindDictionaryStaticType)) @@ -526,7 +526,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(6), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(5), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -535,7 +535,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { t.Parallel() script := ` - fun main() { + fun main() { let x: {Int8: Int8} = {} // 2 data slabs x.insert(key: 0, 0) // all fit in slab x.insert(key: 1, 1) @@ -557,7 +557,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -581,8 +581,8 @@ func TestInterpretDictionaryMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(5), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(31), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -606,7 +606,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) }) } From 1bf62fbc1a7049c77b173efa3ba83f7c90e16d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 26 May 2023 17:20:13 -0700 Subject: [PATCH 03/47] fix memory metering for loading stored composites --- runtime/common/metering.go | 8 --- runtime/interpreter/storage.go | 6 +- runtime/interpreter/value.go | 61 +++++++++++-------- .../tests/interpreter/memory_metering_test.go | 18 +++--- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/runtime/common/metering.go b/runtime/common/metering.go index 46e98f1205..86e0b62f83 100644 --- a/runtime/common/metering.go +++ b/runtime/common/metering.go @@ -386,14 +386,6 @@ func NewAtreeMapMemoryUsages(count uint64, elementSize uint) (MemoryUsage, Memor branches } -func NewCompositeMemoryUsages(count uint64, elementSize uint) (MemoryUsage, MemoryUsage, MemoryUsage, MemoryUsage) { - leaves, branches := newAtreeMapMemoryUsage(count, elementSize) - return CompositeValueBaseMemoryUsage, MemoryUsage{ - Kind: MemoryKindAtreeMapElementOverhead, - Amount: count, - }, leaves, branches -} - func NewAtreeMapPreAllocatedElementsMemoryUsage(count uint64, elementSize uint) MemoryUsage { leafNodesCount, _ := atreeNodes(count, elementSize) diff --git a/runtime/interpreter/storage.go b/runtime/interpreter/storage.go index 62db66fb78..a252321324 100644 --- a/runtime/interpreter/storage.go +++ b/runtime/interpreter/storage.go @@ -83,7 +83,11 @@ func ConvertStoredValue(gauge common.MemoryGauge, value atree.Value) (Value, err ), nil case compositeTypeInfo: - return newCompositeValueFromConstructor(gauge, value.Count(), staticType, func() *atree.OrderedMap { return value }), nil + return newCompositeValueFromAtreeMap( + gauge, + staticType, + value, + ), nil default: return nil, errors.NewUnexpectedError("invalid ordered map type info: %T", staticType) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 66f6390aea..e15acb7b78 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -16358,30 +16358,40 @@ func NewCompositeValue( return v } -func newCompositeValueFromOrderedMap( - dict *atree.OrderedMap, - typeInfo compositeTypeInfo, -) *CompositeValue { - return &CompositeValue{ - dictionary: dict, - Location: typeInfo.location, - QualifiedIdentifier: typeInfo.qualifiedIdentifier, - Kind: typeInfo.kind, - } -} - func newCompositeValueFromConstructor( gauge common.MemoryGauge, count uint64, typeInfo compositeTypeInfo, constructor func() *atree.OrderedMap, ) *CompositeValue { - baseUse, elementOverhead, dataUse, metaDataUse := common.NewCompositeMemoryUsages(count, 0) - common.UseMemory(gauge, baseUse) + + elementOverhead, dataUse, metaDataUse := + common.NewAtreeMapMemoryUsages(count, 0) common.UseMemory(gauge, elementOverhead) common.UseMemory(gauge, dataUse) common.UseMemory(gauge, metaDataUse) - return newCompositeValueFromOrderedMap(constructor(), typeInfo) + + return newCompositeValueFromAtreeMap( + gauge, + typeInfo, + constructor(), + ) +} + +func newCompositeValueFromAtreeMap( + gauge common.MemoryGauge, + typeInfo compositeTypeInfo, + atreeOrderedMap *atree.OrderedMap, +) *CompositeValue { + + common.UseMemory(gauge, common.CompositeValueBaseMemoryUsage) + + return &CompositeValue{ + dictionary: atreeOrderedMap, + Location: typeInfo.location, + QualifiedIdentifier: typeInfo.qualifiedIdentifier, + Kind: typeInfo.kind, + } } var _ Value = &CompositeValue{} @@ -17150,20 +17160,17 @@ func (v *CompositeValue) Transfer( preventTransfer map[atree.StorageID]struct{}, ) Value { - baseUse, elementOverhead, dataUse, metaDataUse := common.NewCompositeMemoryUsages(v.dictionary.Count(), 0) - common.UseMemory(interpreter, baseUse) - common.UseMemory(interpreter, elementOverhead) - common.UseMemory(interpreter, dataUse) - common.UseMemory(interpreter, metaDataUse) - - interpreter.ReportComputation(common.ComputationKindTransferCompositeValue, 1) - config := interpreter.SharedState.Config if config.InvalidatedResourceValidationEnabled { v.checkInvalidatedResourceUse(interpreter, locationRange) } + interpreter.ReportComputation( + common.ComputationKindTransferCompositeValue, + 1, + ) + if config.TracingEnabled { startTime := time.Now() @@ -17303,7 +17310,13 @@ func (v *CompositeValue) Transfer( v.QualifiedIdentifier, v.Kind, ) - res = newCompositeValueFromOrderedMap(dictionary, info) + + res = newCompositeValueFromAtreeMap( + interpreter, + info, + dictionary, + ) + res.InjectedFields = v.InjectedFields res.ComputedFields = v.ComputedFields res.NestedVariables = v.NestedVariables diff --git a/runtime/tests/interpreter/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 4557a777c4..e8aec0fca8 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -646,9 +646,9 @@ func TestInterpretCompositeMetering(t *testing.T) { assert.Equal(t, uint64(6), meter.getMemory(common.MemoryKindStringValue)) assert.Equal(t, uint64(66), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(5), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) - assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) assert.Equal(t, uint64(8), meter.getMemory(common.MemoryKindVariable)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeStaticType)) @@ -678,7 +678,7 @@ func TestInterpretCompositeMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(27), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(27), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(480), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindVariable)) @@ -742,7 +742,7 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) }) @@ -772,8 +772,8 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { assert.Equal(t, uint64(16), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) }) @@ -804,8 +804,8 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(34), meter.getMemory(common.MemoryKindRawString)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) From 187ffc6b45cb1c9f80dbeaf25758b0e16a163aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 13 Sep 2023 16:31:52 -0700 Subject: [PATCH 04/47] keep atree map memory usage metering in CompositeValue/DictionaryValue.transfer --- runtime/interpreter/value.go | 21 +++++++++++-- .../tests/interpreter/memory_metering_test.go | 30 +++++++++---------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index e3d0bb781f..16d4c280bc 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -17213,7 +17213,14 @@ func (v *CompositeValue) Transfer( panic(errors.NewExternalError(err)) } - elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(v.dictionary.Count(), 0) + elementCount := v.dictionary.Count() + + elementOverhead, dataUse, metaDataUse := common.NewAtreeMapMemoryUsages(elementCount, 0) + common.UseMemory(interpreter, elementOverhead) + common.UseMemory(interpreter, dataUse) + common.UseMemory(interpreter, metaDataUse) + + elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(elementCount, 0) common.UseMemory(config.MemoryGauge, elementMemoryUse) dictionary, err = atree.NewMapFromBatchData( @@ -18942,8 +18949,18 @@ func (v *DictionaryValue) Transfer( panic(errors.NewExternalError(err)) } + elementCount := v.dictionary.Count() + + elementOverhead, dataUse, metaDataUse := common.NewAtreeMapMemoryUsages( + elementCount, + v.elementSize, + ) + common.UseMemory(interpreter, elementOverhead) + common.UseMemory(interpreter, dataUse) + common.UseMemory(interpreter, metaDataUse) + elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage( - v.dictionary.Count(), + elementCount, v.elementSize, ) common.UseMemory(config.MemoryGauge, elementMemoryUse) diff --git a/runtime/tests/interpreter/memory_metering_test.go b/runtime/tests/interpreter/memory_metering_test.go index 703cf9eaa1..095ca5fabd 100644 --- a/runtime/tests/interpreter/memory_metering_test.go +++ b/runtime/tests/interpreter/memory_metering_test.go @@ -410,8 +410,8 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindStringValue)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(8), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(159), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindVariable)) @@ -493,7 +493,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(10), meter.getMemory(common.MemoryKindPrimitiveStaticType)) assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindDictionaryStaticType)) @@ -526,7 +526,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(5), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(6), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -557,7 +557,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -581,8 +581,8 @@ func TestInterpretDictionaryMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(5), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(31), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) }) @@ -606,7 +606,7 @@ func TestInterpretDictionaryMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindDictionaryValueBase)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) }) } @@ -646,7 +646,7 @@ func TestInterpretCompositeMetering(t *testing.T) { assert.Equal(t, uint64(6), meter.getMemory(common.MemoryKindStringValue)) assert.Equal(t, uint64(72), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(4), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(32), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) @@ -678,7 +678,7 @@ func TestInterpretCompositeMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(27), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(3), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(18), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(480), meter.getMemory(common.MemoryKindAtreeMapPreAllocatedElement)) assert.Equal(t, uint64(9), meter.getMemory(common.MemoryKindVariable)) @@ -742,7 +742,7 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) }) @@ -772,8 +772,8 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { assert.Equal(t, uint64(18), meter.getMemory(common.MemoryKindRawString)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) - assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) }) @@ -804,8 +804,8 @@ func TestInterpretCompositeFieldMetering(t *testing.T) { require.NoError(t, err) assert.Equal(t, uint64(40), meter.getMemory(common.MemoryKindRawString)) - assert.Equal(t, uint64(1), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) - assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapDataSlab)) + assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindAtreeMapElementOverhead)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindAtreeMapMetaDataSlab)) assert.Equal(t, uint64(2), meter.getMemory(common.MemoryKindCompositeValueBase)) assert.Equal(t, uint64(0), meter.getMemory(common.MemoryKindCompositeField)) From 351c3c6d678b2a8adf33562df29eeebc8298a1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 13 Sep 2023 16:32:14 -0700 Subject: [PATCH 05/47] remove unnecessary metering in clone functions --- runtime/interpreter/value.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 16d4c280bc..4464c8fb14 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -17366,9 +17366,6 @@ func (v *CompositeValue) Clone(interpreter *Interpreter) Value { config := interpreter.SharedState.Config - elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(v.dictionary.Count(), 0) - common.UseMemory(config.MemoryGauge, elementMemoryUse) - dictionary, err := atree.NewMapFromBatchData( config.Storage, v.StorageAddress(), @@ -19059,9 +19056,6 @@ func (v *DictionaryValue) Clone(interpreter *Interpreter) Value { panic(errors.NewExternalError(err)) } - elementMemoryUse := common.NewAtreeMapPreAllocatedElementsMemoryUsage(v.dictionary.Count(), v.elementSize) - common.UseMemory(config.MemoryGauge, elementMemoryUse) - orderedMap, err := atree.NewMapFromBatchData( config.Storage, v.StorageAddress(), From 0c1be9b9504548e2446a22d548c1488e79f90fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 13 Sep 2023 16:32:38 -0700 Subject: [PATCH 06/47] use StorageAddress instead of StorageID().Address --- runtime/interpreter/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 4464c8fb14..b955bfaaf6 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -2803,7 +2803,7 @@ func (v *ArrayValue) Clone(interpreter *Interpreter) Value { array, err := atree.NewArrayFromBatchData( config.Storage, - v.StorageID().Address, + v.StorageAddress(), v.array.Type(), func() (atree.Value, error) { value, err := iterator.Next() From cdb811065b9915ee22a31ef8756132aaa52b2250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 14 Sep 2023 15:57:03 -0700 Subject: [PATCH 07/47] fix capability controller deletion --- runtime/capabilitycontrollers_test.go | 182 +++++++++++++++ .../value_accountcapabilitycontroller.go | 89 ++++---- .../value_storagecapabilitycontroller.go | 153 ++++++++----- runtime/stdlib/account.go | 208 +++++++----------- 4 files changed, 410 insertions(+), 222 deletions(-) diff --git a/runtime/capabilitycontrollers_test.go b/runtime/capabilitycontrollers_test.go index fcdbabe440..8f80ebbc95 100644 --- a/runtime/capabilitycontrollers_test.go +++ b/runtime/capabilitycontrollers_test.go @@ -3185,3 +3185,185 @@ func TestRuntimeCapabilityControllers(t *testing.T) { }) } + +func TestRuntimeCapabilityControllerOperationAfterDeletion(t *testing.T) { + + t.Parallel() + + type operation struct { + name string + code string + } + + type testCase struct { + name string + setup string + operations []operation + } + + test := func(testCase testCase, operation operation) { + + testName := fmt.Sprintf("%s: %s", testCase.name, operation.name) + + t.Run(testName, func(t *testing.T) { + t.Parallel() + + rt := newTestInterpreterRuntime() + rt.defaultConfig.CapabilityControllersEnabled = true + + tx := []byte(fmt.Sprintf( + ` + transaction { + prepare(signer: AuthAccount) { + %s + %s + } + } + `, + testCase.setup, + operation.code, + )) + + address := common.MustBytesToAddress([]byte{0x1}) + accountIDs := map[common.Address]uint64{} + + runtimeInterface := &testRuntimeInterface{ + storage: newTestLedger(nil, nil), + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil + }, + emitEvent: func(event cadence.Event) error { + return nil + }, + generateAccountID: func(address common.Address) (uint64, error) { + accountID := accountIDs[address] + 1 + accountIDs[address] = accountID + return accountID, nil + }, + } + + nextTransactionLocation := newTransactionLocationGenerator() + + // Test + + err := rt.ExecuteTransaction( + Script{ + Source: tx, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + + require.ErrorContains(t, err, "controller is deleted") + }) + } + + testCases := []testCase{ + { + name: "Storage capability controller", + setup: ` + // Issue capability and get controller + let storageCapabilities = signer.capabilities.storage + let capability = storageCapabilities.issue<&AnyStruct>(/storage/test1) + let controller = storageCapabilities.getController(byCapabilityID: capability.id)! + + // Prepare bound functions + let delete = controller.delete + let tag = controller.tag + let target = controller.target + let retarget = controller.retarget + + // Delete + controller.delete() + `, + operations: []operation{ + // Read + { + name: "get capability", + code: `controller.capability`, + }, + { + name: "get tag", + code: `controller.tag`, + }, + { + name: "get borrow type", + code: `controller.borrowType`, + }, + { + name: "get ID", + code: `controller.capabilityID`, + }, + // Mutate + { + name: "delete", + code: `delete()`, + }, + { + name: "set tag", + code: `controller.tag = "test"`, + }, + { + name: "target", + code: `target()`, + }, + { + name: "retarget", + code: `retarget(/storage/test2)`, + }, + }, + }, + { + name: "Account capability controller", + setup: ` + // Issue capability and get controller + let accountCapabilities = signer.capabilities.account + let capability = accountCapabilities.issue<&AuthAccount>() + let controller = accountCapabilities.getController(byCapabilityID: capability.id)! + + // Prepare bound functions + let delete = controller.delete + let tag = controller.tag + + // Delete + controller.delete() + `, + operations: []operation{ + // Read + { + name: "get capability", + code: `controller.capability`, + }, + { + name: "get tag", + code: `controller.tag`, + }, + { + name: "get borrow type", + code: `controller.borrowType`, + }, + { + name: "get ID", + code: `controller.capabilityID`, + }, + // Mutate + { + name: "delete", + code: `delete()`, + }, + { + name: "set tag", + code: `controller.tag = "test"`, + }, + }, + }, + } + + for _, testCase := range testCases { + for _, operation := range testCase.operations { + test(testCase, operation) + } + } +} diff --git a/runtime/interpreter/value_accountcapabilitycontroller.go b/runtime/interpreter/value_accountcapabilitycontroller.go index 5f400f5765..da7c96ea4b 100644 --- a/runtime/interpreter/value_accountcapabilitycontroller.go +++ b/runtime/interpreter/value_accountcapabilitycontroller.go @@ -33,18 +33,21 @@ type AccountCapabilityControllerValue struct { BorrowType ReferenceStaticType CapabilityID UInt64Value - // tag is locally cached result of GetTag, and not stored. - // It is populated when the field `tag` is read. - tag *StringValue + // deleted indicates if the controller got deleted. Not stored + deleted bool - // Injected functions + // Lazily initialized function values. + // Host functions based on injected functions (see below). + deleteFunction FunctionValue + + // Injected functions. // Tags are not stored directly inside the controller // to avoid unnecessary storage reads // when the controller is loaded for borrowing/checking - GetCapability func() *IDCapabilityValue - GetTag func() *StringValue - SetTag func(*StringValue) - DeleteFunction FunctionValue + GetCapability func(inter *Interpreter) *IDCapabilityValue + GetTag func(inter *Interpreter) *StringValue + SetTag func(inter *Interpreter, tag *StringValue) + Delete func(inter *Interpreter, locationRange LocationRange) } func NewUnmeteredAccountCapabilityControllerValue( @@ -208,16 +211,12 @@ func (v *AccountCapabilityControllerValue) ChildStorables() []atree.Storable { } func (v *AccountCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() switch name { case sema.AccountCapabilityControllerTypeTagFieldName: - if v.tag == nil { - v.tag = v.GetTag() - if v.tag == nil { - v.tag = EmptyString - } - } - return v.tag + return v.GetTag(inter) case sema.AccountCapabilityControllerTypeCapabilityIDFieldName: return v.CapabilityID @@ -225,11 +224,16 @@ func (v *AccountCapabilityControllerValue) GetMember(inter *Interpreter, _ Locat case sema.AccountCapabilityControllerTypeBorrowTypeFieldName: return NewTypeValue(inter, v.BorrowType) + case sema.AccountCapabilityControllerTypeCapabilityFieldName: + return v.GetCapability(inter) + case sema.AccountCapabilityControllerTypeDeleteFunctionName: - return v.DeleteFunction + if v.deleteFunction == nil { + v.deleteFunction = v.newDeleteFunction(inter) + } + return v.deleteFunction - case sema.AccountCapabilityControllerTypeCapabilityFieldName: - return v.GetCapability() + // NOTE: when adding new functions, ensure checkDeleted is called! } return nil @@ -241,19 +245,21 @@ func (*AccountCapabilityControllerValue) RemoveMember(_ *Interpreter, _ Location } func (v *AccountCapabilityControllerValue) SetMember( - _ *Interpreter, + inter *Interpreter, _ LocationRange, identifier string, value Value, ) bool { + // NOTE: check if controller is already deleted + v.checkDeleted() + switch identifier { case sema.AccountCapabilityControllerTypeTagFieldName: stringValue, ok := value.(*StringValue) if !ok { panic(errors.NewUnreachableError()) } - v.tag = stringValue - v.SetTag(stringValue) + v.SetTag(inter, stringValue) return true } @@ -278,29 +284,32 @@ func (v *AccountCapabilityControllerValue) ReferenceValue( ) } -// SetDeleted sets the controller as deleted, i.e. functions panic from now on -func (v *AccountCapabilityControllerValue) SetDeleted(gauge common.MemoryGauge) { - - raiseError := func() { +// checkDeleted checks if the controller is deleted, +// and panics if it is. +func (v *AccountCapabilityControllerValue) checkDeleted() { + if v.deleted { panic(errors.NewDefaultUserError("controller is deleted")) } +} - v.SetTag = func(s *StringValue) { - raiseError() - } - v.GetTag = func() *StringValue { - raiseError() - return nil - } +func (v *AccountCapabilityControllerValue) newDeleteFunction( + inter *Interpreter, +) *HostFunctionValue { + return NewHostFunctionValue( + inter, + sema.AccountCapabilityControllerTypeDeleteFunctionType, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() - panicHostFunction := func(Invocation) Value { - raiseError() - return nil - } + inter := invocation.Interpreter + locationRange := invocation.LocationRange - v.DeleteFunction = NewHostFunctionValue( - gauge, - sema.AccountCapabilityControllerTypeDeleteFunctionType, - panicHostFunction, + v.Delete(inter, locationRange) + + v.deleted = true + + return Void + }, ) } diff --git a/runtime/interpreter/value_storagecapabilitycontroller.go b/runtime/interpreter/value_storagecapabilitycontroller.go index 470809612c..7f231d4160 100644 --- a/runtime/interpreter/value_storagecapabilitycontroller.go +++ b/runtime/interpreter/value_storagecapabilitycontroller.go @@ -46,20 +46,24 @@ type StorageCapabilityControllerValue struct { CapabilityID UInt64Value TargetPath PathValue - // tag is locally cached result of GetTag, and not stored. - // It is populated when the field `tag` is read. - tag *StringValue + // deleted indicates if the controller got deleted. Not stored + deleted bool + + // Lazily initialized function values. + // Host functions based on injected functions (see below). + deleteFunction FunctionValue + targetFunction FunctionValue + retargetFunction FunctionValue // Injected functions. // Tags are not stored directly inside the controller // to avoid unnecessary storage reads // when the controller is loaded for borrowing/checking - GetCapability func() *IDCapabilityValue - GetTag func() *StringValue - SetTag func(*StringValue) - TargetFunction FunctionValue - RetargetFunction FunctionValue - DeleteFunction FunctionValue + GetCapability func(inter *Interpreter) *IDCapabilityValue + GetTag func(inter *Interpreter) *StringValue + SetTag func(inter *Interpreter, tag *StringValue) + Delete func(inter *Interpreter, locationRange LocationRange) + SetTarget func(inter *Interpreter, locationRange LocationRange, target PathValue) } func NewUnmeteredStorageCapabilityControllerValue( @@ -233,16 +237,12 @@ func (v *StorageCapabilityControllerValue) ChildStorables() []atree.Storable { } func (v *StorageCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() switch name { case sema.StorageCapabilityControllerTypeTagFieldName: - if v.tag == nil { - v.tag = v.GetTag() - if v.tag == nil { - v.tag = EmptyString - } - } - return v.tag + return v.GetTag(inter) case sema.StorageCapabilityControllerTypeCapabilityIDFieldName: return v.CapabilityID @@ -250,17 +250,28 @@ func (v *StorageCapabilityControllerValue) GetMember(inter *Interpreter, _ Locat case sema.StorageCapabilityControllerTypeBorrowTypeFieldName: return NewTypeValue(inter, v.BorrowType) + case sema.StorageCapabilityControllerTypeCapabilityFieldName: + return v.GetCapability(inter) + + case sema.StorageCapabilityControllerTypeDeleteFunctionName: + if v.deleteFunction == nil { + v.deleteFunction = v.newDeleteFunction(inter) + } + return v.deleteFunction + case sema.StorageCapabilityControllerTypeTargetFunctionName: - return v.TargetFunction + if v.targetFunction == nil { + v.targetFunction = v.newTargetFunction(inter) + } + return v.targetFunction case sema.StorageCapabilityControllerTypeRetargetFunctionName: - return v.RetargetFunction - - case sema.StorageCapabilityControllerTypeDeleteFunctionName: - return v.DeleteFunction + if v.retargetFunction == nil { + v.retargetFunction = v.newRetargetFunction(inter) + } + return v.retargetFunction - case sema.StorageCapabilityControllerTypeCapabilityFieldName: - return v.GetCapability() + // NOTE: when adding new functions, ensure checkDeleted is called! } return nil @@ -272,19 +283,21 @@ func (*StorageCapabilityControllerValue) RemoveMember(_ *Interpreter, _ Location } func (v *StorageCapabilityControllerValue) SetMember( - _ *Interpreter, + inter *Interpreter, _ LocationRange, identifier string, value Value, ) bool { + // NOTE: check if controller is already deleted + v.checkDeleted() + switch identifier { case sema.StorageCapabilityControllerTypeTagFieldName: stringValue, ok := value.(*StringValue) if !ok { panic(errors.NewUnreachableError()) } - v.tag = stringValue - v.SetTag(stringValue) + v.SetTag(inter, stringValue) return true } @@ -309,39 +322,75 @@ func (v *StorageCapabilityControllerValue) ReferenceValue( ) } -// SetDeleted sets the controller as deleted, i.e. functions panic from now on -func (v *StorageCapabilityControllerValue) SetDeleted(gauge common.MemoryGauge) { - - raiseError := func() { +// checkDeleted checks if the controller is deleted, +// and panics if it is. +func (v *StorageCapabilityControllerValue) checkDeleted() { + if v.deleted { panic(errors.NewDefaultUserError("controller is deleted")) } +} - v.SetTag = func(s *StringValue) { - raiseError() - } - v.GetTag = func() *StringValue { - raiseError() - return nil - } +func (v *StorageCapabilityControllerValue) newDeleteFunction( + inter *Interpreter, +) *HostFunctionValue { + return NewHostFunctionValue( + inter, + sema.StorageCapabilityControllerTypeDeleteFunctionType, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() - panicHostFunction := func(Invocation) Value { - raiseError() - return nil - } + inter := invocation.Interpreter + locationRange := invocation.LocationRange + + v.Delete(inter, locationRange) - v.TargetFunction = NewHostFunctionValue( - gauge, + v.deleted = true + + return Void + }, + ) +} + +func (v *StorageCapabilityControllerValue) newTargetFunction( + inter *Interpreter, +) *HostFunctionValue { + return NewHostFunctionValue( + inter, sema.StorageCapabilityControllerTypeTargetFunctionType, - panicHostFunction, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() + + return v.TargetPath + }, ) - v.RetargetFunction = NewHostFunctionValue( - gauge, +} + +func (v *StorageCapabilityControllerValue) newRetargetFunction( + inter *Interpreter, +) *HostFunctionValue { + return NewHostFunctionValue( + inter, sema.StorageCapabilityControllerTypeRetargetFunctionType, - panicHostFunction, - ) - v.DeleteFunction = NewHostFunctionValue( - gauge, - sema.StorageCapabilityControllerTypeDeleteFunctionType, - panicHostFunction, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() + + inter := invocation.Interpreter + locationRange := invocation.LocationRange + + // Get path argument + + newTargetPathValue, ok := invocation.Arguments[0].(PathValue) + if !ok || newTargetPathValue.Domain != common.PathDomainStorage { + panic(errors.NewUnreachableError()) + } + + v.SetTarget(inter, locationRange, newTargetPathValue) + v.TargetPath = newTargetPathValue + + return Void + }, ) } diff --git a/runtime/stdlib/account.go b/runtime/stdlib/account.go index b97bcdd2a2..1577c34c9e 100644 --- a/runtime/stdlib/account.go +++ b/runtime/stdlib/account.go @@ -2720,33 +2720,32 @@ func getCapabilityController( capabilityID := controller.CapabilityID controller.GetCapability = - newCapabilityControllerGetCapabilityFunction(inter, address, controller) + newCapabilityControllerGetCapabilityFunction(address, controller) controller.GetTag = - newCapabilityControllerGetTagFunction(inter, address, capabilityID) + newCapabilityControllerGetTagFunction(address, capabilityID) controller.SetTag = - newCapabilityControllerSetTagFunction(inter, address, capabilityID) + newCapabilityControllerSetTagFunction(address, capabilityID) - controller.TargetFunction = - newStorageCapabilityControllerTargetFunction(inter, controller) - controller.RetargetFunction = - newStorageCapabilityControllerRetargetFunction(inter, address, controller) - controller.DeleteFunction = - newStorageCapabilityControllerDeleteFunction(inter, address, controller) + controller.Delete = + newStorageCapabilityControllerDeleteFunction(address, controller) + + controller.SetTarget = + newStorageCapabilityControllerSetTargetFunction(address, controller) case *interpreter.AccountCapabilityControllerValue: capabilityID := controller.CapabilityID controller.GetCapability = - newCapabilityControllerGetCapabilityFunction(inter, address, controller) + newCapabilityControllerGetCapabilityFunction(address, controller) controller.GetTag = - newCapabilityControllerGetTagFunction(inter, address, capabilityID) + newCapabilityControllerGetTagFunction(address, capabilityID) controller.SetTag = - newCapabilityControllerSetTagFunction(inter, address, capabilityID) + newCapabilityControllerSetTagFunction(address, capabilityID) - controller.DeleteFunction = - newAccountCapabilityControllerDeleteFunction(inter, address, controller) + controller.Delete = + newAccountCapabilityControllerDeleteFunction(address, controller) } return controller @@ -2776,94 +2775,59 @@ func getStorageCapabilityControllerReference( ) } -func newStorageCapabilityControllerTargetFunction( - inter *interpreter.Interpreter, - controller *interpreter.StorageCapabilityControllerValue, -) interpreter.FunctionValue { - return interpreter.NewHostFunctionValue( - inter, - sema.StorageCapabilityControllerTypeTargetFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - return controller.TargetPath - }, - ) -} - -func newStorageCapabilityControllerRetargetFunction( - inter *interpreter.Interpreter, +func newStorageCapabilityControllerSetTargetFunction( address common.Address, controller *interpreter.StorageCapabilityControllerValue, -) interpreter.FunctionValue { - return interpreter.NewHostFunctionValue( - inter, - sema.StorageCapabilityControllerTypeTargetFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - locationRange := invocation.LocationRange - - // Get path argument - - newTargetPathValue, ok := invocation.Arguments[0].(interpreter.PathValue) - if !ok || newTargetPathValue.Domain != common.PathDomainStorage { - panic(errors.NewUnreachableError()) - } - - oldTargetPathValue := controller.TargetPath - - capabilityID := controller.CapabilityID - unrecordStorageCapabilityController( - inter, - locationRange, - address, - oldTargetPathValue, - capabilityID, - ) - recordStorageCapabilityController( - inter, - locationRange, - address, - newTargetPathValue, - capabilityID, - ) - - controller.TargetPath = newTargetPathValue +) func(*interpreter.Interpreter, interpreter.LocationRange, interpreter.PathValue) { + return func( + inter *interpreter.Interpreter, + locationRange interpreter.LocationRange, + newTargetPathValue interpreter.PathValue, + ) { + oldTargetPathValue := controller.TargetPath + capabilityID := controller.CapabilityID - return interpreter.Void - }, - ) + unrecordStorageCapabilityController( + inter, + locationRange, + address, + oldTargetPathValue, + capabilityID, + ) + recordStorageCapabilityController( + inter, + locationRange, + address, + newTargetPathValue, + capabilityID, + ) + } } func newStorageCapabilityControllerDeleteFunction( - inter *interpreter.Interpreter, address common.Address, controller *interpreter.StorageCapabilityControllerValue, -) interpreter.FunctionValue { - return interpreter.NewHostFunctionValue( - inter, - sema.StorageCapabilityControllerTypeTargetFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - inter := invocation.Interpreter - locationRange := invocation.LocationRange - - capabilityID := controller.CapabilityID - - unrecordStorageCapabilityController( - inter, - locationRange, - address, - controller.TargetPath, - capabilityID, - ) - removeCapabilityController( - inter, - address, - capabilityID, - ) - - controller.SetDeleted(inter) +) func(*interpreter.Interpreter, interpreter.LocationRange) { + return func( + inter *interpreter.Interpreter, + locationRange interpreter.LocationRange, + ) { + targetPathValue := controller.TargetPath + capabilityID := controller.CapabilityID - return interpreter.Void - }, - ) + unrecordStorageCapabilityController( + inter, + locationRange, + address, + targetPathValue, + capabilityID, + ) + removeCapabilityController( + inter, + address, + capabilityID, + ) + } } var capabilityIDSetStaticType = interpreter.DictionaryStaticType{ @@ -3955,37 +3919,24 @@ func newAuthAccountAccountCapabilitiesForEachControllerFunction( } func newAccountCapabilityControllerDeleteFunction( - inter *interpreter.Interpreter, address common.Address, controller *interpreter.AccountCapabilityControllerValue, -) interpreter.FunctionValue { - return interpreter.NewHostFunctionValue( - inter, - sema.StorageCapabilityControllerTypeTargetFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - - inter := invocation.Interpreter - locationRange := invocation.LocationRange - - capabilityID := controller.CapabilityID - - unrecordAccountCapabilityController( - inter, - locationRange, - address, - capabilityID, - ) - removeCapabilityController( - inter, - address, - capabilityID, - ) - - controller.SetDeleted(inter) +) func(*interpreter.Interpreter, interpreter.LocationRange) { + return func(inter *interpreter.Interpreter, locationRange interpreter.LocationRange) { + capabilityID := controller.CapabilityID - return interpreter.Void - }, - ) + unrecordAccountCapabilityController( + inter, + locationRange, + address, + capabilityID, + ) + removeCapabilityController( + inter, + address, + capabilityID, + ) + } } // CapabilityControllerTagStorageDomain is the storage domain which stores @@ -4016,16 +3967,15 @@ func getCapabilityControllerTag( } func newCapabilityControllerGetCapabilityFunction( - inter *interpreter.Interpreter, address common.Address, controller interpreter.CapabilityControllerValue, -) func() *interpreter.IDCapabilityValue { +) func(inter *interpreter.Interpreter) *interpreter.IDCapabilityValue { addressValue := interpreter.AddressValue(address) capabilityID := controller.ControllerCapabilityID() borrowType := controller.CapabilityControllerBorrowType() - return func() *interpreter.IDCapabilityValue { + return func(inter *interpreter.Interpreter) *interpreter.IDCapabilityValue { return interpreter.NewIDCapabilityValue( inter, capabilityID, @@ -4036,12 +3986,11 @@ func newCapabilityControllerGetCapabilityFunction( } func newCapabilityControllerGetTagFunction( - inter *interpreter.Interpreter, address common.Address, capabilityIDValue interpreter.UInt64Value, -) func() *interpreter.StringValue { +) func(*interpreter.Interpreter) *interpreter.StringValue { - return func() *interpreter.StringValue { + return func(inter *interpreter.Interpreter) *interpreter.StringValue { return getCapabilityControllerTag( inter, address, @@ -4071,11 +4020,10 @@ func setCapabilityControllerTag( } func newCapabilityControllerSetTagFunction( - inter *interpreter.Interpreter, address common.Address, capabilityIDValue interpreter.UInt64Value, -) func(tagValue *interpreter.StringValue) { - return func(tagValue *interpreter.StringValue) { +) func(*interpreter.Interpreter, *interpreter.StringValue) { + return func(inter *interpreter.Interpreter, tagValue *interpreter.StringValue) { setCapabilityControllerTag( inter, address, From 3d4854f96813dbc0a0541540155b7515acc123e5 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Wed, 20 Sep 2023 22:58:04 +0530 Subject: [PATCH 08/47] Introduce String.split function --- runtime/interpreter/value.go | 59 ++++++++++++++ runtime/sema/string_type.go | 26 +++++++ runtime/tests/checker/string_test.go | 43 +++++++++++ runtime/tests/interpreter/string_test.go | 97 ++++++++++++++++++++++++ 4 files changed, 225 insertions(+) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index b80d96da8e..d0c61e65fe 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1043,6 +1043,8 @@ var _ ValueIndexableValue = &StringValue{} var _ MemberAccessibleValue = &StringValue{} var _ IterableValue = &StringValue{} +var VarSizedArrayOfStringType = NewVariableSizedStaticType(nil, PrimitiveStaticTypeString) + func (v *StringValue) prepareGraphemes() { if v.graphemes == nil { v.graphemes = uniseg.NewGraphemes(v.Str) @@ -1342,6 +1344,15 @@ func (v *StringValue) GetMember(interpreter *Interpreter, locationRange Location return v.ToLower(invocation.Interpreter) }, ) + + case sema.StringTypeSplitFunctionName: + return NewHostFunctionValue( + interpreter, + sema.StringTypeSplitFunctionType, + func(invocation Invocation) Value { + return v.Split(invocation) + }, + ) } return nil @@ -1396,6 +1407,54 @@ func (v *StringValue) ToLower(interpreter *Interpreter) *StringValue { ) } +func (v *StringValue) Split(invocation Invocation) Value { + inter := invocation.Interpreter + + separator, ok := invocation.Arguments[0].(*StringValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + split := strings.Split(v.Str, separator.Str) + + var index int + count := len(split) + + return NewArrayValueWithIterator( + inter, + VarSizedArrayOfStringType, + common.ZeroAddress, + uint64(count), + func() Value { + if index >= count { + return nil + } + + str := split[index] + strValue := NewStringValue( + inter, + common.NewStringMemoryUsage(len(str)), + func() string { + return str + }, + ) + + index++ + + value := strValue.Transfer( + inter, + invocation.LocationRange, + atree.Address(common.ZeroAddress), + true, + nil, + nil, + ) + + return value + }, + ) +} + func (v *StringValue) Storable(storage atree.SlabStorage, address atree.Address, maxInlineSize uint64) (atree.Storable, error) { return maybeLargeImmutableStorable(v, storage, address, maxInlineSize) } diff --git a/runtime/sema/string_type.go b/runtime/sema/string_type.go index b4fa762599..691f14db13 100644 --- a/runtime/sema/string_type.go +++ b/runtime/sema/string_type.go @@ -42,6 +42,11 @@ const StringTypeJoinFunctionDocString = ` Returns a string after joining the array of strings with the provided separator. ` +const StringTypeSplitFunctionName = "split" +const StringTypeSplitFunctionDocString = ` +Returns a variable-sized array of strings after splitting the string on the delimiter. +` + // StringType represents the string type var StringType = &SimpleType{ Name: "String", @@ -105,6 +110,12 @@ func init() { StringTypeToLowerFunctionType, stringTypeToLowerFunctionDocString, ), + NewUnmeteredPublicFunctionMember( + t, + StringTypeSplitFunctionName, + StringTypeSplitFunctionType, + StringTypeSplitFunctionDocString, + ), }) } } @@ -335,3 +346,18 @@ var StringTypeJoinFunctionType = NewSimpleFunctionType( }, StringTypeAnnotation, ) + +var StringTypeSplitFunctionType = NewSimpleFunctionType( + FunctionPurityView, + []Parameter{ + { + Identifier: "separator", + TypeAnnotation: StringTypeAnnotation, + }, + }, + NewTypeAnnotation( + &VariableSizedType{ + Type: StringType, + }, + ), +) diff --git a/runtime/tests/checker/string_test.go b/runtime/tests/checker/string_test.go index 2ce9fc681b..5d94c0c077 100644 --- a/runtime/tests/checker/string_test.go +++ b/runtime/tests/checker/string_test.go @@ -408,3 +408,46 @@ func TestCheckStringJoinTypeMissingArgumentLabelSeparator(t *testing.T) { assert.IsType(t, &sema.MissingArgumentLabelError{}, errs[0]) } + +func TestCheckStringSplit(t *testing.T) { + + t.Parallel() + + checker, err := ParseAndCheck(t, ` + let s = "👪.❤️.Abc".split(separator: ".") + `) + require.NoError(t, err) + + assert.Equal(t, + &sema.VariableSizedType{ + Type: sema.StringType, + }, + RequireGlobalValue(t, checker.Elaboration, "s"), + ) +} + +func TestCheckStringSplitTypeMismatchSeparator(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + let s = "Abc:1".split(separator: 1234) + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.TypeMismatchError{}, errs[0]) +} + +func TestCheckStringSplitTypeMissingArgumentLabelSeparator(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + let s = "👪Abc".split("/") + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.MissingArgumentLabelError{}, errs[0]) +} diff --git a/runtime/tests/interpreter/string_test.go b/runtime/tests/interpreter/string_test.go index 51873a5a79..37bba83186 100644 --- a/runtime/tests/interpreter/string_test.go +++ b/runtime/tests/interpreter/string_test.go @@ -499,3 +499,100 @@ func TestInterpretStringJoin(t *testing.T) { testCase(t, "testEmptyArray", interpreter.NewUnmeteredStringValue("")) testCase(t, "testSingletonArray", interpreter.NewUnmeteredStringValue("pqrS")) } + +func TestInterpretStringSplit(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + fun split(): [String] { + return "👪////❤️".split(separator: "////") + } + fun splitBySpace(): [String] { + return "👪 ❤️ Abc6 ;123".split(separator: " ") + } + fun splitWithUnicodeEquivalence(): [String] { + return "Caf\u{65}\u{301}ABc".split(separator: "\u{e9}") + } + fun testEmptyString(): [String] { + return "".split(separator: "//") + } + fun testNoMatch(): [String] { + return "pqrS;asdf".split(separator: ";;") + } + `) + + testCase := func(t *testing.T, funcName string, expected *interpreter.ArrayValue) { + t.Run(funcName, func(t *testing.T) { + result, err := inter.Invoke(funcName) + require.NoError(t, err) + + RequireValuesEqual( + t, + inter, + expected, + result, + ) + }) + } + + varSizedStringType := &interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeString, + } + + testCase(t, + "split", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedStringType, + common.ZeroAddress, + interpreter.NewUnmeteredStringValue("👪"), + interpreter.NewUnmeteredStringValue("❤️"), + ), + ) + testCase(t, + "splitBySpace", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedStringType, + common.ZeroAddress, + interpreter.NewUnmeteredStringValue("👪"), + interpreter.NewUnmeteredStringValue("❤️"), + interpreter.NewUnmeteredStringValue("Abc6"), + interpreter.NewUnmeteredStringValue(";123"), + ), + ) + testCase(t, + "splitWithUnicodeEquivalence", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedStringType, + common.ZeroAddress, + interpreter.NewUnmeteredStringValue("Caf"), + interpreter.NewUnmeteredStringValue("ABc"), + ), + ) + testCase(t, + "testEmptyString", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedStringType, + common.ZeroAddress, + interpreter.NewUnmeteredStringValue(""), + ), + ) + testCase(t, + "testNoMatch", + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + varSizedStringType, + common.ZeroAddress, + interpreter.NewUnmeteredStringValue("pqrS;asdf"), + ), + ) +} From cd2d26c11dd3329e24c1cbf664c63d2fd443046f Mon Sep 17 00:00:00 2001 From: darkdrag00nv2 <122124396+darkdrag00nv2@users.noreply.github.com> Date: Thu, 21 Sep 2023 22:24:32 +0530 Subject: [PATCH 09/47] Update runtime/interpreter/value.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- runtime/interpreter/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index d0c61e65fe..c005d03c4d 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1444,7 +1444,7 @@ func (v *StringValue) Split(invocation Invocation) Value { value := strValue.Transfer( inter, invocation.LocationRange, - atree.Address(common.ZeroAddress), + atree.Address{}, true, nil, nil, From 839556c69d6c5a78a0825207aab3acc183ff07fe Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Thu, 21 Sep 2023 22:28:35 +0530 Subject: [PATCH 10/47] pass interpreter, location range and separator to Split function --- runtime/interpreter/value.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index c005d03c4d..b53445b696 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1350,7 +1350,12 @@ func (v *StringValue) GetMember(interpreter *Interpreter, locationRange Location interpreter, sema.StringTypeSplitFunctionType, func(invocation Invocation) Value { - return v.Split(invocation) + separator, ok := invocation.Arguments[0].(*StringValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + return v.Split(invocation.Interpreter, invocation.LocationRange, separator.Str) }, ) } @@ -1407,15 +1412,8 @@ func (v *StringValue) ToLower(interpreter *Interpreter) *StringValue { ) } -func (v *StringValue) Split(invocation Invocation) Value { - inter := invocation.Interpreter - - separator, ok := invocation.Arguments[0].(*StringValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - split := strings.Split(v.Str, separator.Str) +func (v *StringValue) Split(inter *Interpreter, locationRange LocationRange, separator string) Value { + split := strings.Split(v.Str, separator) var index int count := len(split) @@ -1443,7 +1441,7 @@ func (v *StringValue) Split(invocation Invocation) Value { value := strValue.Transfer( inter, - invocation.LocationRange, + locationRange, atree.Address{}, true, nil, From 4957cb11689d80c2459085ea58f28d897a536057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 21 Sep 2023 12:44:02 -0700 Subject: [PATCH 11/47] check functions from GetMember of capability controller values checked for deletion --- .../value_accountcapabilitycontroller.go | 44 ++++++++++++--- .../value_storagecapabilitycontroller.go | 54 +++++++++++++------ 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/runtime/interpreter/value_accountcapabilitycontroller.go b/runtime/interpreter/value_accountcapabilitycontroller.go index da7c96ea4b..3c90c91e3f 100644 --- a/runtime/interpreter/value_accountcapabilitycontroller.go +++ b/runtime/interpreter/value_accountcapabilitycontroller.go @@ -210,7 +210,20 @@ func (v *AccountCapabilityControllerValue) ChildStorables() []atree.Storable { } } -func (v *AccountCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) Value { +type deletionCheckedFunctionValue struct { + FunctionValue +} + +func (v *AccountCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) (result Value) { + defer func() { + switch typedResult := result.(type) { + case deletionCheckedFunctionValue: + result = typedResult.FunctionValue + case FunctionValue: + panic(errors.NewUnexpectedError("functions need to check deletion. Use newHostFunctionValue")) + } + }() + // NOTE: check if controller is already deleted v.checkDeleted() @@ -233,7 +246,8 @@ func (v *AccountCapabilityControllerValue) GetMember(inter *Interpreter, _ Locat } return v.deleteFunction - // NOTE: when adding new functions, ensure checkDeleted is called! + // NOTE: when adding new functions, ensure checkDeleted is called, + // by e.g. using AccountCapabilityControllerValue.newHostFunction } return nil @@ -292,16 +306,32 @@ func (v *AccountCapabilityControllerValue) checkDeleted() { } } +func (v *AccountCapabilityControllerValue) newHostFunctionValue( + gauge common.MemoryGauge, + funcType *sema.FunctionType, + f func(invocation Invocation) Value, +) FunctionValue { + return deletionCheckedFunctionValue{ + FunctionValue: NewHostFunctionValue( + gauge, + funcType, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() + + return f(invocation) + }, + ), + } +} + func (v *AccountCapabilityControllerValue) newDeleteFunction( inter *Interpreter, -) *HostFunctionValue { - return NewHostFunctionValue( +) FunctionValue { + return v.newHostFunctionValue( inter, sema.AccountCapabilityControllerTypeDeleteFunctionType, func(invocation Invocation) Value { - // NOTE: check if controller is already deleted - v.checkDeleted() - inter := invocation.Interpreter locationRange := invocation.LocationRange diff --git a/runtime/interpreter/value_storagecapabilitycontroller.go b/runtime/interpreter/value_storagecapabilitycontroller.go index 7f231d4160..60e4ca4e13 100644 --- a/runtime/interpreter/value_storagecapabilitycontroller.go +++ b/runtime/interpreter/value_storagecapabilitycontroller.go @@ -236,7 +236,16 @@ func (v *StorageCapabilityControllerValue) ChildStorables() []atree.Storable { } } -func (v *StorageCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) Value { +func (v *StorageCapabilityControllerValue) GetMember(inter *Interpreter, _ LocationRange, name string) (result Value) { + defer func() { + switch typedResult := result.(type) { + case deletionCheckedFunctionValue: + result = typedResult.FunctionValue + case FunctionValue: + panic(errors.NewUnexpectedError("functions need to check deletion. Use newHostFunctionValue")) + } + }() + // NOTE: check if controller is already deleted v.checkDeleted() @@ -271,7 +280,8 @@ func (v *StorageCapabilityControllerValue) GetMember(inter *Interpreter, _ Locat } return v.retargetFunction - // NOTE: when adding new functions, ensure checkDeleted is called! + // NOTE: when adding new functions, ensure checkDeleted is called, + // by e.g. using StorageCapabilityControllerValue.newHostFunction } return nil @@ -330,16 +340,32 @@ func (v *StorageCapabilityControllerValue) checkDeleted() { } } +func (v *StorageCapabilityControllerValue) newHostFunctionValue( + gauge common.MemoryGauge, + funcType *sema.FunctionType, + f func(invocation Invocation) Value, +) FunctionValue { + return deletionCheckedFunctionValue{ + FunctionValue: NewHostFunctionValue( + gauge, + funcType, + func(invocation Invocation) Value { + // NOTE: check if controller is already deleted + v.checkDeleted() + + return f(invocation) + }, + ), + } +} + func (v *StorageCapabilityControllerValue) newDeleteFunction( inter *Interpreter, -) *HostFunctionValue { - return NewHostFunctionValue( +) FunctionValue { + return v.newHostFunctionValue( inter, sema.StorageCapabilityControllerTypeDeleteFunctionType, func(invocation Invocation) Value { - // NOTE: check if controller is already deleted - v.checkDeleted() - inter := invocation.Interpreter locationRange := invocation.LocationRange @@ -354,14 +380,11 @@ func (v *StorageCapabilityControllerValue) newDeleteFunction( func (v *StorageCapabilityControllerValue) newTargetFunction( inter *Interpreter, -) *HostFunctionValue { - return NewHostFunctionValue( +) FunctionValue { + return v.newHostFunctionValue( inter, sema.StorageCapabilityControllerTypeTargetFunctionType, func(invocation Invocation) Value { - // NOTE: check if controller is already deleted - v.checkDeleted() - return v.TargetPath }, ) @@ -369,14 +392,11 @@ func (v *StorageCapabilityControllerValue) newTargetFunction( func (v *StorageCapabilityControllerValue) newRetargetFunction( inter *Interpreter, -) *HostFunctionValue { - return NewHostFunctionValue( +) FunctionValue { + return v.newHostFunctionValue( inter, sema.StorageCapabilityControllerTypeRetargetFunctionType, func(invocation Invocation) Value { - // NOTE: check if controller is already deleted - v.checkDeleted() - inter := invocation.Interpreter locationRange := invocation.LocationRange From 8bf8c38aecd8f0e64af5c181ea8d7c3841dfb56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 21 Sep 2023 21:15:31 -0700 Subject: [PATCH 12/47] add support for initializers/constructors. refactor test cases, and type check and run them --- runtime/sema/account.gen.go | 27 -- runtime/sema/account.go | 27 ++ .../sema/account_capability_controller.gen.go | 2 +- runtime/sema/any_type.go | 2 +- runtime/sema/anyattachment_types.go | 4 +- runtime/sema/anyresource_type.go | 2 +- runtime/sema/anystruct_type.go | 2 +- runtime/sema/block.gen.go | 2 +- runtime/sema/bool_type.go | 2 +- runtime/sema/character.gen.go | 2 +- runtime/sema/deployedcontract.gen.go | 2 +- runtime/sema/entitlements.gen.go | 3 - runtime/sema/entitlements.go | 6 + runtime/sema/gen/golden_test.go | 95 ++++ runtime/sema/gen/main.go | 441 +++++++++++++----- runtime/sema/gen/main_test.go | 17 +- .../sema/gen/testdata/comparable/helper.go | 23 + .../{comparable.cdc => comparable/test.cdc} | 0 .../test.golden.go} | 10 +- .../test.cdc} | 0 .../test.golden.go} | 13 +- .../sema/gen/testdata/constructor/test.cdc | 6 + .../gen/testdata/constructor/test.golden.go | 63 +++ runtime/sema/gen/testdata/contract/test.cdc | 10 + .../sema/gen/testdata/contract/test.golden.go | 93 ++++ .../sema/gen/testdata/docstrings/helper.go | 23 + .../{docstrings.cdc => docstrings/test.cdc} | 0 .../test.golden.go} | 75 +-- .../{entitlement.cdc => entitlement/test.cdc} | 0 .../test.golden.go} | 34 +- runtime/sema/gen/testdata/equatable/helper.go | 23 + .../{equatable.cdc => equatable/test.cdc} | 0 .../test.golden.go} | 10 +- .../sema/gen/testdata/exportable/helper.go | 23 + .../{exportable.cdc => exportable/test.cdc} | 0 .../test.golden.go} | 10 +- runtime/sema/gen/testdata/fields/helper.go | 26 ++ .../testdata/{fields.cdc => fields/test.cdc} | 1 + .../test.golden.go} | 109 ++--- runtime/sema/gen/testdata/functions/helper.go | 23 + .../{functions.cdc => functions/test.cdc} | 0 .../test.golden.go} | 137 +++--- .../sema/gen/testdata/importable/helper.go | 23 + .../{importable.cdc => importable/test.cdc} | 0 .../test.golden.go} | 10 +- .../gen/testdata/member_accessible/helper.go | 23 + .../test.cdc} | 0 .../test.golden.go} | 10 +- .../testdata/{nested.cdc => nested/test.cdc} | 0 .../test.golden.go} | 49 +- .../gen/testdata/simple_resource/helper.go | 23 + .../test.cdc} | 0 .../test.golden.go} | 10 +- .../sema/gen/testdata/simple_struct/helper.go | 23 + .../test.cdc} | 0 .../test.golden.go} | 10 +- runtime/sema/gen/testdata/storable/helper.go | 23 + .../{storable.cdc => storable/test.cdc} | 0 .../test.golden.go} | 10 +- runtime/sema/invalid_type.go | 2 +- runtime/sema/meta_type.go | 2 +- runtime/sema/never_type.go | 2 +- runtime/sema/path_type.go | 10 +- runtime/sema/simple_type.go | 4 +- .../sema/storage_capability_controller.gen.go | 2 +- runtime/sema/string_type.go | 2 +- runtime/sema/type.go | 42 ++ runtime/sema/void_type.go | 2 +- runtime/stdlib/bls.gen.go | 8 +- runtime/stdlib/builtin.go | 4 - runtime/stdlib/flow.go | 2 +- runtime/stdlib/publickey.go | 6 +- runtime/stdlib/rlp.gen.go | 8 +- 73 files changed, 1238 insertions(+), 420 deletions(-) create mode 100644 runtime/sema/gen/golden_test.go create mode 100644 runtime/sema/gen/testdata/comparable/helper.go rename runtime/sema/gen/testdata/{comparable.cdc => comparable/test.cdc} (100%) rename runtime/sema/gen/testdata/{comparable.golden.go => comparable/test.golden.go} (82%) rename runtime/sema/gen/testdata/{composite-type-pragma.cdc => composite_type_pragma/test.cdc} (100%) rename runtime/sema/gen/testdata/{composite-type-pragma.golden.go => composite_type_pragma/test.golden.go} (75%) create mode 100644 runtime/sema/gen/testdata/constructor/test.cdc create mode 100644 runtime/sema/gen/testdata/constructor/test.golden.go create mode 100644 runtime/sema/gen/testdata/contract/test.cdc create mode 100644 runtime/sema/gen/testdata/contract/test.golden.go create mode 100644 runtime/sema/gen/testdata/docstrings/helper.go rename runtime/sema/gen/testdata/{docstrings.cdc => docstrings/test.cdc} (100%) rename runtime/sema/gen/testdata/{docstrings.golden.go => docstrings/test.golden.go} (66%) rename runtime/sema/gen/testdata/{entitlement.cdc => entitlement/test.cdc} (100%) rename runtime/sema/gen/testdata/{entitlement.golden.go => entitlement/test.golden.go} (58%) create mode 100644 runtime/sema/gen/testdata/equatable/helper.go rename runtime/sema/gen/testdata/{equatable.cdc => equatable/test.cdc} (100%) rename runtime/sema/gen/testdata/{equatable.golden.go => equatable/test.golden.go} (83%) create mode 100644 runtime/sema/gen/testdata/exportable/helper.go rename runtime/sema/gen/testdata/{exportable.cdc => exportable/test.cdc} (100%) rename runtime/sema/gen/testdata/{exportable.golden.go => exportable/test.golden.go} (82%) create mode 100644 runtime/sema/gen/testdata/fields/helper.go rename runtime/sema/gen/testdata/{fields.cdc => fields/test.cdc} (99%) rename runtime/sema/gen/testdata/{fields.golden.go => fields/test.golden.go} (67%) create mode 100644 runtime/sema/gen/testdata/functions/helper.go rename runtime/sema/gen/testdata/{functions.cdc => functions/test.cdc} (100%) rename runtime/sema/gen/testdata/{functions.golden.go => functions/test.golden.go} (57%) create mode 100644 runtime/sema/gen/testdata/importable/helper.go rename runtime/sema/gen/testdata/{importable.cdc => importable/test.cdc} (100%) rename runtime/sema/gen/testdata/{importable.golden.go => importable/test.golden.go} (82%) create mode 100644 runtime/sema/gen/testdata/member_accessible/helper.go rename runtime/sema/gen/testdata/{member_accessible.cdc => member_accessible/test.cdc} (100%) rename runtime/sema/gen/testdata/{member_accessible.golden.go => member_accessible/test.golden.go} (81%) rename runtime/sema/gen/testdata/{nested.cdc => nested/test.cdc} (100%) rename runtime/sema/gen/testdata/{nested.golden.go => nested/test.golden.go} (65%) create mode 100644 runtime/sema/gen/testdata/simple_resource/helper.go rename runtime/sema/gen/testdata/{simple-resource.cdc => simple_resource/test.cdc} (100%) rename runtime/sema/gen/testdata/{simple-resource.golden.go => simple_resource/test.golden.go} (82%) create mode 100644 runtime/sema/gen/testdata/simple_struct/helper.go rename runtime/sema/gen/testdata/{simple-struct.cdc => simple_struct/test.cdc} (100%) rename runtime/sema/gen/testdata/{simple-struct.golden.go => simple_struct/test.golden.go} (82%) create mode 100644 runtime/sema/gen/testdata/storable/helper.go rename runtime/sema/gen/testdata/{storable.cdc => storable/test.cdc} (100%) rename runtime/sema/gen/testdata/{storable.golden.go => storable/test.golden.go} (83%) diff --git a/runtime/sema/account.gen.go b/runtime/sema/account.gen.go index 8b69d15bbb..6908cf6063 100644 --- a/runtime/sema/account.gen.go +++ b/runtime/sema/account.gen.go @@ -2099,57 +2099,30 @@ var CapabilitiesMappingType = &EntitlementMapType{ func init() { BuiltinEntitlementMappings[AccountMappingType.Identifier] = AccountMappingType - addToBaseActivation(AccountMappingType) BuiltinEntitlementMappings[CapabilitiesMappingType.Identifier] = CapabilitiesMappingType - addToBaseActivation(CapabilitiesMappingType) BuiltinEntitlements[StorageType.Identifier] = StorageType - addToBaseActivation(StorageType) BuiltinEntitlements[SaveValueType.Identifier] = SaveValueType - addToBaseActivation(SaveValueType) BuiltinEntitlements[LoadValueType.Identifier] = LoadValueType - addToBaseActivation(LoadValueType) BuiltinEntitlements[CopyValueType.Identifier] = CopyValueType - addToBaseActivation(CopyValueType) BuiltinEntitlements[BorrowValueType.Identifier] = BorrowValueType - addToBaseActivation(BorrowValueType) BuiltinEntitlements[ContractsType.Identifier] = ContractsType - addToBaseActivation(ContractsType) BuiltinEntitlements[AddContractType.Identifier] = AddContractType - addToBaseActivation(AddContractType) BuiltinEntitlements[UpdateContractType.Identifier] = UpdateContractType - addToBaseActivation(UpdateContractType) BuiltinEntitlements[RemoveContractType.Identifier] = RemoveContractType - addToBaseActivation(RemoveContractType) BuiltinEntitlements[KeysType.Identifier] = KeysType - addToBaseActivation(KeysType) BuiltinEntitlements[AddKeyType.Identifier] = AddKeyType - addToBaseActivation(AddKeyType) BuiltinEntitlements[RevokeKeyType.Identifier] = RevokeKeyType - addToBaseActivation(RevokeKeyType) BuiltinEntitlements[InboxType.Identifier] = InboxType - addToBaseActivation(InboxType) BuiltinEntitlements[PublishInboxCapabilityType.Identifier] = PublishInboxCapabilityType - addToBaseActivation(PublishInboxCapabilityType) BuiltinEntitlements[UnpublishInboxCapabilityType.Identifier] = UnpublishInboxCapabilityType - addToBaseActivation(UnpublishInboxCapabilityType) BuiltinEntitlements[ClaimInboxCapabilityType.Identifier] = ClaimInboxCapabilityType - addToBaseActivation(ClaimInboxCapabilityType) BuiltinEntitlements[CapabilitiesType.Identifier] = CapabilitiesType - addToBaseActivation(CapabilitiesType) BuiltinEntitlements[StorageCapabilitiesType.Identifier] = StorageCapabilitiesType - addToBaseActivation(StorageCapabilitiesType) BuiltinEntitlements[AccountCapabilitiesType.Identifier] = AccountCapabilitiesType - addToBaseActivation(AccountCapabilitiesType) BuiltinEntitlements[PublishCapabilityType.Identifier] = PublishCapabilityType - addToBaseActivation(PublishCapabilityType) BuiltinEntitlements[UnpublishCapabilityType.Identifier] = UnpublishCapabilityType - addToBaseActivation(UnpublishCapabilityType) BuiltinEntitlements[GetStorageCapabilityControllerType.Identifier] = GetStorageCapabilityControllerType - addToBaseActivation(GetStorageCapabilityControllerType) BuiltinEntitlements[IssueStorageCapabilityControllerType.Identifier] = IssueStorageCapabilityControllerType - addToBaseActivation(IssueStorageCapabilityControllerType) BuiltinEntitlements[GetAccountCapabilityControllerType.Identifier] = GetAccountCapabilityControllerType - addToBaseActivation(GetAccountCapabilityControllerType) BuiltinEntitlements[IssueAccountCapabilityControllerType.Identifier] = IssueAccountCapabilityControllerType - addToBaseActivation(IssueAccountCapabilityControllerType) } diff --git a/runtime/sema/account.go b/runtime/sema/account.go index ad7d988c1a..9d7a371fa0 100644 --- a/runtime/sema/account.go +++ b/runtime/sema/account.go @@ -56,4 +56,31 @@ var FullyEntitledAccountReferenceTypeAnnotation = NewTypeAnnotation(FullyEntitle func init() { Account_ContractsTypeAddFunctionType.Arity = &Arity{Min: 2} + addToBaseActivation(AccountMappingType) + addToBaseActivation(CapabilitiesMappingType) + addToBaseActivation(StorageType) + addToBaseActivation(SaveValueType) + addToBaseActivation(LoadValueType) + addToBaseActivation(CopyValueType) + addToBaseActivation(BorrowValueType) + addToBaseActivation(ContractsType) + addToBaseActivation(AddContractType) + addToBaseActivation(UpdateContractType) + addToBaseActivation(RemoveContractType) + addToBaseActivation(KeysType) + addToBaseActivation(AddKeyType) + addToBaseActivation(RevokeKeyType) + addToBaseActivation(InboxType) + addToBaseActivation(PublishInboxCapabilityType) + addToBaseActivation(UnpublishInboxCapabilityType) + addToBaseActivation(ClaimInboxCapabilityType) + addToBaseActivation(CapabilitiesType) + addToBaseActivation(StorageCapabilitiesType) + addToBaseActivation(AccountCapabilitiesType) + addToBaseActivation(PublishCapabilityType) + addToBaseActivation(UnpublishCapabilityType) + addToBaseActivation(GetStorageCapabilityControllerType) + addToBaseActivation(IssueStorageCapabilityControllerType) + addToBaseActivation(GetAccountCapabilityControllerType) + addToBaseActivation(IssueAccountCapabilityControllerType) } diff --git a/runtime/sema/account_capability_controller.gen.go b/runtime/sema/account_capability_controller.gen.go index c91e435e17..02d09d0769 100644 --- a/runtime/sema/account_capability_controller.gen.go +++ b/runtime/sema/account_capability_controller.gen.go @@ -102,7 +102,7 @@ var AccountCapabilityControllerType = &SimpleType{ Name: AccountCapabilityControllerTypeName, QualifiedName: AccountCapabilityControllerTypeName, TypeID: AccountCapabilityControllerTypeName, - tag: AccountCapabilityControllerTypeTag, + TypeTag: AccountCapabilityControllerTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/any_type.go b/runtime/sema/any_type.go index f5e0d97f41..7feaaf28dc 100644 --- a/runtime/sema/any_type.go +++ b/runtime/sema/any_type.go @@ -24,7 +24,7 @@ var AnyType = &SimpleType{ Name: "Any", QualifiedName: "Any", TypeID: "Any", - tag: AnyTypeTag, + TypeTag: AnyTypeTag, IsResource: false, // `Any` is never a valid type in user programs Storable: true, diff --git a/runtime/sema/anyattachment_types.go b/runtime/sema/anyattachment_types.go index c22f19c583..ef154c4926 100644 --- a/runtime/sema/anyattachment_types.go +++ b/runtime/sema/anyattachment_types.go @@ -25,7 +25,7 @@ var AnyResourceAttachmentType = &SimpleType{ Name: AnyResourceAttachmentTypeName, QualifiedName: AnyResourceAttachmentTypeName, TypeID: AnyResourceAttachmentTypeName, - tag: AnyResourceAttachmentTypeTag, + TypeTag: AnyResourceAttachmentTypeTag, IsResource: true, // The actual storability of a value is checked at run-time Storable: true, @@ -43,7 +43,7 @@ var AnyStructAttachmentType = &SimpleType{ Name: AnyStructAttachmentTypeName, QualifiedName: AnyStructAttachmentTypeName, TypeID: AnyStructAttachmentTypeName, - tag: AnyStructAttachmentTypeTag, + TypeTag: AnyStructAttachmentTypeTag, IsResource: false, // The actual storability of a value is checked at run-time Storable: true, diff --git a/runtime/sema/anyresource_type.go b/runtime/sema/anyresource_type.go index b19d72040f..6b20d9563a 100644 --- a/runtime/sema/anyresource_type.go +++ b/runtime/sema/anyresource_type.go @@ -23,7 +23,7 @@ var AnyResourceType = &SimpleType{ Name: "AnyResource", QualifiedName: "AnyResource", TypeID: "AnyResource", - tag: AnyResourceTypeTag, + TypeTag: AnyResourceTypeTag, IsResource: true, // The actual storability of a value is checked at run-time Storable: true, diff --git a/runtime/sema/anystruct_type.go b/runtime/sema/anystruct_type.go index edbc5e8220..a4739610a3 100644 --- a/runtime/sema/anystruct_type.go +++ b/runtime/sema/anystruct_type.go @@ -23,7 +23,7 @@ var AnyStructType = &SimpleType{ Name: "AnyStruct", QualifiedName: "AnyStruct", TypeID: "AnyStruct", - tag: AnyStructTypeTag, + TypeTag: AnyStructTypeTag, IsResource: false, // The actual storability of a value is checked at run-time Storable: true, diff --git a/runtime/sema/block.gen.go b/runtime/sema/block.gen.go index 058282a4ff..7c490c3a0c 100644 --- a/runtime/sema/block.gen.go +++ b/runtime/sema/block.gen.go @@ -69,7 +69,7 @@ var BlockType = &SimpleType{ Name: BlockTypeName, QualifiedName: BlockTypeName, TypeID: BlockTypeName, - tag: BlockTypeTag, + TypeTag: BlockTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/bool_type.go b/runtime/sema/bool_type.go index c83a2eafc1..1870777d78 100644 --- a/runtime/sema/bool_type.go +++ b/runtime/sema/bool_type.go @@ -23,7 +23,7 @@ var BoolType = &SimpleType{ Name: "Bool", QualifiedName: "Bool", TypeID: "Bool", - tag: BoolTypeTag, + TypeTag: BoolTypeTag, IsResource: false, Storable: true, Equatable: true, diff --git a/runtime/sema/character.gen.go b/runtime/sema/character.gen.go index 36d89e50c4..69909c376f 100644 --- a/runtime/sema/character.gen.go +++ b/runtime/sema/character.gen.go @@ -50,7 +50,7 @@ var CharacterType = &SimpleType{ Name: CharacterTypeName, QualifiedName: CharacterTypeName, TypeID: CharacterTypeName, - tag: CharacterTypeTag, + TypeTag: CharacterTypeTag, IsResource: false, Storable: true, Equatable: true, diff --git a/runtime/sema/deployedcontract.gen.go b/runtime/sema/deployedcontract.gen.go index 1e502abccd..864c5dd718 100644 --- a/runtime/sema/deployedcontract.gen.go +++ b/runtime/sema/deployedcontract.gen.go @@ -78,7 +78,7 @@ var DeployedContractType = &SimpleType{ Name: DeployedContractTypeName, QualifiedName: DeployedContractTypeName, TypeID: DeployedContractTypeName, - tag: DeployedContractTypeTag, + TypeTag: DeployedContractTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/entitlements.gen.go b/runtime/sema/entitlements.gen.go index 559ebf6937..5ae0d1b995 100644 --- a/runtime/sema/entitlements.gen.go +++ b/runtime/sema/entitlements.gen.go @@ -33,9 +33,6 @@ var RemoveType = &EntitlementType{ func init() { BuiltinEntitlements[MutateType.Identifier] = MutateType - addToBaseActivation(MutateType) BuiltinEntitlements[InsertType.Identifier] = InsertType - addToBaseActivation(InsertType) BuiltinEntitlements[RemoveType.Identifier] = RemoveType - addToBaseActivation(RemoveType) } diff --git a/runtime/sema/entitlements.go b/runtime/sema/entitlements.go index d2cbeebd04..3870c6e5cf 100644 --- a/runtime/sema/entitlements.go +++ b/runtime/sema/entitlements.go @@ -19,3 +19,9 @@ package sema //go:generate go run ./gen entitlements.cdc entitlements.gen.go + +func init() { + addToBaseActivation(MutateType) + addToBaseActivation(InsertType) + addToBaseActivation(RemoveType) +} diff --git a/runtime/sema/gen/golden_test.go b/runtime/sema/gen/golden_test.go new file mode 100644 index 0000000000..6eccdc779d --- /dev/null +++ b/runtime/sema/gen/golden_test.go @@ -0,0 +1,95 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 main + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/sema" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/comparable" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/composite_type_pragma" + "github.com/onflow/cadence/runtime/sema/gen/testdata/constructor" + "github.com/onflow/cadence/runtime/sema/gen/testdata/contract" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/contract" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/docstrings" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/entitlement" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/equatable" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/exportable" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/fields" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/functions" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/importable" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/member_accessible" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/nested" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/simple_resource" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/simple_struct" + _ "github.com/onflow/cadence/runtime/sema/gen/testdata/storable" + "github.com/onflow/cadence/runtime/stdlib" + "github.com/onflow/cadence/runtime/tests/checker" +) + +func TestConstructor(t *testing.T) { + + t.Parallel() + + baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) + baseValueActivation.DeclareValue(stdlib.StandardLibraryValue{ + Name: constructor.FooType.Identifier, + Type: constructor.FooTypeConstructorType, + Kind: common.DeclarationKindFunction, + }) + + _, err := checker.ParseAndCheckWithOptions(t, + ` + let x = Foo(bar: 1) + `, + checker.ParseAndCheckOptions{ + Config: &sema.Config{ + BaseValueActivation: baseValueActivation, + }, + }, + ) + require.NoError(t, err) +} + +func TestContract(t *testing.T) { + + t.Parallel() + + baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) + baseValueActivation.DeclareValue(stdlib.StandardLibraryValue{ + Name: contract.TestType.Identifier, + Type: contract.TestType, + Kind: common.DeclarationKindContract, + }) + + _, err := checker.ParseAndCheckWithOptions(t, + ` + let x = Test.Foo(bar: 1) + `, + checker.ParseAndCheckOptions{ + Config: &sema.Config{ + BaseValueActivation: baseValueActivation, + }, + }, + ) + require.NoError(t, err) +} diff --git a/runtime/sema/gen/main.go b/runtime/sema/gen/main.go index 3fd35f3e5b..9238aec01c 100644 --- a/runtime/sema/gen/main.go +++ b/runtime/sema/gen/main.go @@ -38,6 +38,7 @@ import ( "github.com/onflow/cadence/runtime/errors" "github.com/onflow/cadence/runtime/parser" "github.com/onflow/cadence/runtime/pretty" + "github.com/onflow/cadence/runtime/sema" ) const semaPath = "github.com/onflow/cadence/runtime/sema" @@ -161,6 +162,7 @@ type typeDecl struct { memberAccessible bool memberDeclarations []ast.Declaration nestedTypes []*typeDecl + hasConstructor bool } type generator struct { @@ -289,6 +291,7 @@ func (g *generator) addFunctionTypeDeclaration( decl.ParameterList, decl.TypeParameterList, typeParams, + false, ), ), ) @@ -323,8 +326,106 @@ func (g *generator) declarationDocString(decl ast.Declaration) dst.Expr { return renderDocString(docString) } -func (*generator) VisitSpecialFunctionDeclaration(_ *ast.SpecialFunctionDeclaration) struct{} { - panic("special function declarations are not supported") +func (g *generator) VisitSpecialFunctionDeclaration(decl *ast.SpecialFunctionDeclaration) (_ struct{}) { + if decl.Kind != common.DeclarationKindInitializer { + panic(fmt.Errorf( + "%s special function declarations are not supported", + decl.Kind.Name(), + )) + } + + typeDecl := g.currentTypeDecl() + + fullTypeName := typeDecl.fullTypeName + + if typeDecl.hasConstructor { + panic(fmt.Errorf("invalid second initializer for type %s", fullTypeName)) + } + typeDecl.hasConstructor = true + + isResource := typeDecl.compositeKind == common.CompositeKindResource + + typeNames := make([]string, 0, len(g.typeStack)) + for i := 0; i < len(g.typeStack); i++ { + typeNames = append(typeNames, g.typeStack[i].typeName) + } + + g.addConstructorTypeDeclaration(decl, fullTypeName, typeNames, isResource) + + g.addConstructorDocStringDeclaration(decl, fullTypeName) + + return +} + +func (g *generator) addConstructorTypeDeclaration( + initDecl *ast.SpecialFunctionDeclaration, + fullTypeName string, + typeNames []string, + isResource bool, +) { + decl := initDecl.FunctionDeclaration + + parameters := decl.ParameterList.Parameters + + parameterTypeAnnotations := make([]*ast.TypeAnnotation, 0, len(parameters)) + for _, parameter := range parameters { + parameterTypeAnnotations = append( + parameterTypeAnnotations, + parameter.TypeAnnotation, + ) + } + + nestedIdentifiers := make([]ast.Identifier, 0, len(typeNames)-1) + for i := 1; i < len(typeNames); i++ { + typeName := typeNames[i] + nestedIdentifiers = append( + nestedIdentifiers, + ast.Identifier{ + Identifier: typeName, + }, + ) + } + + returnType := &ast.NominalType{ + NestedIdentifiers: nestedIdentifiers, + Identifier: ast.Identifier{ + Identifier: typeNames[0], + }, + } + + g.addDecls( + goVarDecl( + constructorTypeVarName(fullTypeName), + functionTypeExpr( + &ast.FunctionType{ + PurityAnnotation: decl.Purity, + ReturnTypeAnnotation: &ast.TypeAnnotation{ + Type: returnType, + IsResource: isResource, + }, + ParameterTypeAnnotations: parameterTypeAnnotations, + }, + decl.ParameterList, + nil, + nil, + true, + ), + ), + ) +} + +func (g *generator) addConstructorDocStringDeclaration( + decl *ast.SpecialFunctionDeclaration, + fullTypeName string, +) { + docString := g.declarationDocString(decl) + + g.addDecls( + goConstDecl( + constructorDocStringVarName(fullTypeName), + docString, + ), + ) } func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ struct{}) { @@ -471,11 +572,13 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ typeVarDecl = compositeTypeExpr(typeDecl) } - tyVarName := typeVarName(typeDecl.fullTypeName) + fullTypeName := typeDecl.fullTypeName + + tyVarName := typeVarName(fullTypeName) g.addDecls( goConstDecl( - typeNameVarName(typeDecl.fullTypeName), + typeNameVarName(fullTypeName), goStringLit(typeName), ), goVarDecl( @@ -496,7 +599,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ // } // } - memberResolversFunc := simpleTypeMemberResolversFunc(typeDecl.fullTypeName, memberDeclarations) + memberResolversFunc := simpleTypeMemberResolversFunc(fullTypeName, memberDeclarations) g.addDecls( &dst.FuncDecl{ @@ -527,65 +630,93 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ // members := []*Member{...} // t.Members = MembersAsMap(members) // t.Fields = MembersFieldNames(members) + // t.ConstructorParameters = ... // } - members := membersExpr(typeDecl.fullTypeName, tyVarName, memberDeclarations) + members := membersExpr( + fullTypeName, + tyVarName, + memberDeclarations, + ) const membersVariableIdentifier = "members" + stmts := []dst.Stmt{ + &dst.DeclStmt{ + Decl: goVarDecl( + membersVariableIdentifier, + members, + ), + }, + &dst.AssignStmt{ + Lhs: []dst.Expr{ + &dst.SelectorExpr{ + X: dst.NewIdent(tyVarName), + Sel: dst.NewIdent("Members"), + }, + }, + Tok: token.ASSIGN, + Rhs: []dst.Expr{ + &dst.CallExpr{ + Fun: &dst.Ident{ + Name: "MembersAsMap", + Path: semaPath, + }, + Args: []dst.Expr{ + dst.NewIdent(membersVariableIdentifier), + }, + }, + }, + }, + &dst.AssignStmt{ + Lhs: []dst.Expr{ + &dst.SelectorExpr{ + X: dst.NewIdent(tyVarName), + Sel: dst.NewIdent("Fields"), + }, + }, + Tok: token.ASSIGN, + Rhs: []dst.Expr{ + &dst.CallExpr{ + Fun: &dst.Ident{ + Name: "MembersFieldNames", + Path: semaPath, + }, + Args: []dst.Expr{ + dst.NewIdent(membersVariableIdentifier), + }, + }, + }, + }, + } + + if typeDecl.hasConstructor { + stmts = append( + stmts, + &dst.AssignStmt{ + Lhs: []dst.Expr{ + &dst.SelectorExpr{ + X: dst.NewIdent(tyVarName), + Sel: dst.NewIdent("ConstructorParameters"), + }, + }, + Tok: token.ASSIGN, + Rhs: []dst.Expr{ + &dst.SelectorExpr{ + X: dst.NewIdent(constructorTypeVarName(fullTypeName)), + Sel: dst.NewIdent("Parameters"), + }, + }, + }, + ) + } + g.addDecls( &dst.FuncDecl{ Name: dst.NewIdent("init"), Type: &dst.FuncType{}, Body: &dst.BlockStmt{ - List: []dst.Stmt{ - &dst.DeclStmt{ - Decl: goVarDecl( - membersVariableIdentifier, - members, - ), - }, - &dst.AssignStmt{ - Lhs: []dst.Expr{ - &dst.SelectorExpr{ - X: dst.NewIdent(tyVarName), - Sel: dst.NewIdent("Members"), - }, - }, - Tok: token.ASSIGN, - Rhs: []dst.Expr{ - &dst.CallExpr{ - Fun: &dst.Ident{ - Name: "MembersAsMap", - Path: semaPath, - }, - Args: []dst.Expr{ - dst.NewIdent(membersVariableIdentifier), - }, - }, - }, - }, - &dst.AssignStmt{ - Lhs: []dst.Expr{ - &dst.SelectorExpr{ - X: dst.NewIdent(tyVarName), - Sel: dst.NewIdent("Fields"), - }, - }, - Tok: token.ASSIGN, - Rhs: []dst.Expr{ - &dst.CallExpr{ - Fun: &dst.Ident{ - Name: "MembersFieldNames", - Path: semaPath, - }, - Args: []dst.Expr{ - dst.NewIdent(membersVariableIdentifier), - }, - }, - }, - }, - }, + List: stmts, }, }, ) @@ -662,7 +793,11 @@ func (g *generator) VisitFieldDeclaration(decl *ast.FieldDeclaration) (_ struct{ } func (g *generator) currentFullTypeName() string { - return g.typeStack[len(g.typeStack)-1].fullTypeName + return g.currentTypeDecl().fullTypeName +} + +func (g *generator) currentTypeDecl() *typeDecl { + return g.typeStack[len(g.typeStack)-1] } func typeExpr(t ast.Type, typeParams map[string]string) dst.Expr { @@ -686,9 +821,14 @@ func typeExpr(t ast.Type, typeParams map[string]string) dst.Expr { } } + inSema := sema.BaseTypeActivation.Find(identifier) != nil + switch identifier { case "": identifier = "Void" + inSema = true + case "Any": + inSema = true case "Address": identifier = "TheAddress" case "Type": @@ -715,7 +855,11 @@ func typeExpr(t ast.Type, typeParams map[string]string) dst.Expr { identifier = fullIdentifier.String() } - return typeVarIdent(identifier) + ident := typeVarIdent(identifier) + if inSema { + ident.Path = semaPath + } + return ident case *ast.OptionalType: innerType := typeExpr(t.Type, typeParams) @@ -810,7 +954,13 @@ func typeExpr(t ast.Type, typeParams map[string]string) dst.Expr { } case *ast.FunctionType: - return functionTypeExpr(t, nil, nil, typeParams) + return functionTypeExpr( + t, + nil, + nil, + typeParams, + false, + ) case *ast.InstantiationType: typeArguments := t.TypeArguments @@ -888,6 +1038,7 @@ func functionTypeExpr( parameters *ast.ParameterList, typeParameterList *ast.TypeParameterList, typeParams map[string]string, + isConstructor bool, ) dst.Expr { // Function purity @@ -1020,7 +1171,14 @@ func functionTypeExpr( if t.ReturnTypeAnnotation != nil { returnTypeExpr = typeExpr(t.ReturnTypeAnnotation.Type, typeParams) } else { - returnTypeExpr = typeVarIdent("Void") + returnTypeExpr = typeExpr( + &ast.NominalType{ + Identifier: ast.Identifier{ + Identifier: "Void", + }, + }, + nil, + ) } returnTypeExpr.Decorations().Before = dst.NewLine @@ -1040,6 +1198,16 @@ func functionTypeExpr( ) } + if isConstructor { + compositeElements = append( + compositeElements, + goKeyValue( + "IsConstructor", + goBoolLit(true), + ), + ) + } + if typeParametersExpr != nil { compositeElements = append( compositeElements, @@ -1106,11 +1274,7 @@ func (*generator) VisitImportDeclaration(_ *ast.ImportDeclaration) struct{} { const typeNameSeparator = '_' -func (g *generator) newFullTypeName(typeName string) string { - if len(g.typeStack) == 0 { - return typeName - } - parentFullTypeName := g.typeStack[len(g.typeStack)-1].fullTypeName +func joinTypeName(parentFullTypeName string, typeName string) string { return fmt.Sprintf( "%s%c%s", escapeTypeName(parentFullTypeName), @@ -1119,6 +1283,14 @@ func (g *generator) newFullTypeName(typeName string) string { ) } +func (g *generator) newFullTypeName(typeName string) string { + if len(g.typeStack) == 0 { + return typeName + } + parentFullTypeName := g.typeStack[len(g.typeStack)-1].fullTypeName + return joinTypeName(parentFullTypeName, typeName) +} + func escapeTypeName(typeName string) string { return strings.ReplaceAll(typeName, string(typeNameSeparator), "__") } @@ -1157,12 +1329,10 @@ func (g *generator) generateTypeInit(program *ast.Program) { // // func init() { // BuiltinEntitlements[FooEntitlement.Identifier] = FooEntitlement - // addToBaseActivation(FooEntitlement) // // ... // // BuiltinEntitlements[BarEntitlementMapping.Identifier] = BarEntitlementMapping - // addToBaseActivation(BarEntitlementMapping) // // ... // } @@ -1205,7 +1375,10 @@ func entitlementMapInitStatements(declaration *ast.EntitlementMappingDeclaration mapUpdateStmt := &dst.AssignStmt{ Lhs: []dst.Expr{ &dst.IndexExpr{ - X: dst.NewIdent(mapName), + X: &dst.Ident{ + Name: mapName, + Path: semaPath, + }, Index: &dst.SelectorExpr{ X: dst.NewIdent(varName), Sel: dst.NewIdent("Identifier"), @@ -1218,18 +1391,8 @@ func entitlementMapInitStatements(declaration *ast.EntitlementMappingDeclaration }, } - typeRegisterStmt := &dst.ExprStmt{ - X: &dst.CallExpr{ - Fun: dst.NewIdent("addToBaseActivation"), - Args: []dst.Expr{ - dst.NewIdent(varName), - }, - }, - } - return []dst.Stmt{ mapUpdateStmt, - typeRegisterStmt, } } @@ -1240,7 +1403,10 @@ func entitlementInitStatements(declaration *ast.EntitlementDeclaration) []dst.St mapUpdateStmt := &dst.AssignStmt{ Lhs: []dst.Expr{ &dst.IndexExpr{ - X: dst.NewIdent(mapName), + X: &dst.Ident{ + Name: mapName, + Path: semaPath, + }, Index: &dst.SelectorExpr{ X: dst.NewIdent(varName), Sel: dst.NewIdent("Identifier"), @@ -1253,18 +1419,8 @@ func entitlementInitStatements(declaration *ast.EntitlementDeclaration) []dst.St }, } - typeRegisterStmt := &dst.ExprStmt{ - X: &dst.CallExpr{ - Fun: dst.NewIdent("addToBaseActivation"), - Args: []dst.Expr{ - dst.NewIdent(varName), - }, - }, - } - return []dst.Stmt{ mapUpdateStmt, - typeRegisterStmt, } } @@ -1345,24 +1501,24 @@ func compositeKindExpr(compositeKind common.CompositeKind) *dst.Ident { } } -func typeVarName(typeName string) string { - return fmt.Sprintf("%sType", typeName) +func typeVarName(fullTypeName string) string { + return fmt.Sprintf("%sType", fullTypeName) } -func typeVarIdent(typeName string) *dst.Ident { - return dst.NewIdent(typeVarName(typeName)) +func typeVarIdent(fullTypeName string) *dst.Ident { + return dst.NewIdent(typeVarName(fullTypeName)) } -func typeNameVarName(typeName string) string { - return fmt.Sprintf("%sTypeName", typeName) +func typeNameVarName(fullTypeName string) string { + return fmt.Sprintf("%sTypeName", fullTypeName) } -func typeNameVarIdent(typeName string) *dst.Ident { - return dst.NewIdent(typeNameVarName(typeName)) +func typeNameVarIdent(fullTypeName string) *dst.Ident { + return dst.NewIdent(typeNameVarName(fullTypeName)) } -func typeTagVarIdent(typeName string) *dst.Ident { - return dst.NewIdent(fmt.Sprintf("%sTypeTag", typeName)) +func typeTagVarIdent(fullTypeName string) *dst.Ident { + return dst.NewIdent(fmt.Sprintf("%sTypeTag", fullTypeName)) } func memberVarName(fullTypeName, fieldName, kind, part string) string { @@ -1391,6 +1547,10 @@ func functionTypeVarName(fullTypeName, functionName string) string { return memberVarName(fullTypeName, functionName, "Function", "Type") } +func constructorTypeVarName(fullTypeName string) string { + return memberVarName(fullTypeName, "", "Constructor", "Type") +} + func functionTypeParameterVarName(fullTypeName, functionName, typeParameterName string) string { return memberVarName(fullTypeName, functionName, "Function", "TypeParameter"+typeParameterName) } @@ -1403,6 +1563,10 @@ func functionDocStringVarName(fullTypeName, functionName string) string { return memberVarName(fullTypeName, functionName, "Function", "DocString") } +func constructorDocStringVarName(fullTypeName string) string { + return memberVarName(fullTypeName, "", "Constructor", "DocString") +} + func simpleTypeLiteral(ty *typeDecl) dst.Expr { // &SimpleType{ @@ -1423,7 +1587,7 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr { goKeyValue("Name", typeNameVarIdent(ty.fullTypeName)), goKeyValue("QualifiedName", typeNameVarIdent(ty.fullTypeName)), goKeyValue("TypeID", typeNameVarIdent(ty.fullTypeName)), - goKeyValue("tag", typeTagVarIdent(ty.fullTypeName)), + goKeyValue("TypeTag", typeTagVarIdent(ty.fullTypeName)), goKeyValue("IsResource", goBoolLit(isResource)), goKeyValue("Storable", goBoolLit(ty.storable)), goKeyValue("Equatable", goBoolLit(ty.equatable)), @@ -1460,7 +1624,11 @@ func simpleTypeMemberResolversFunc(fullTypeName string, declarations []ast.Decla Path: semaPath, }, Args: []dst.Expr{ - membersExpr(fullTypeName, typeVarName, declarations), + membersExpr( + fullTypeName, + typeVarName, + declarations, + ), }, }, }, @@ -1522,11 +1690,34 @@ func membersExpr( memberName, ) + case common.DeclarationKindInitializer: + // Generated as a member of the container + continue + case common.DeclarationKindStructureInterface, common.DeclarationKindStructure, common.DeclarationKindResource, common.DeclarationKindResourceInterface: + initializers := declaration.DeclarationMembers().Initializers() + if len(initializers) > 0 { + initializer := initializers[0] + + typeName := declaration.DeclarationIdentifier().Identifier + + element := newDeclarationMember( + joinTypeName(fullTypeName, typeName), + typeVarName, + // type name is used instead + "", + initializer, + ) + element.Decorations().Before = dst.NewLine + element.Decorations().After = dst.NewLine + + elements = append(elements, element) + } + continue default: @@ -1536,7 +1727,12 @@ func membersExpr( )) } - element := newDeclarationMember(fullTypeName, typeVarName, memberVarName, declaration) + element := newDeclarationMember( + fullTypeName, + typeVarName, + memberVarName, + declaration, + ) element.Decorations().Before = dst.NewLine element.Decorations().After = dst.NewLine @@ -1658,11 +1854,17 @@ func newDeclarationMember( access := declaration.DeclarationAccess() if access == ast.AccessNotSpecified { - panic(fmt.Errorf( - "member with unspecified access: %s.%s", - fullTypeName, - declarationName, - )) + switch declaration.DeclarationKind() { + case common.DeclarationKindInitializer: + break + + default: + panic(fmt.Errorf( + "member with unspecified access: %s.%s", + fullTypeName, + declarationName, + )) + } } if fieldDeclaration, ok := declaration.(*ast.FieldDeclaration); ok { @@ -1691,9 +1893,10 @@ func newDeclarationMember( declarationKind := declaration.DeclarationKind() - // Function + // Function or initializer - if declarationKind == common.DeclarationKindFunction { + switch declarationKind { + case common.DeclarationKindFunction: args := []dst.Expr{ dst.NewIdent(containerTypeVariableIdentifier), accessExpr(access), @@ -1714,8 +1917,32 @@ func newDeclarationMember( }, Args: args, } + + case common.DeclarationKindInitializer: + args := []dst.Expr{ + dst.NewIdent(containerTypeVariableIdentifier), + accessExpr(access), + typeNameVarIdent(fullTypeName), + dst.NewIdent(constructorTypeVarName(fullTypeName)), + dst.NewIdent(constructorDocStringVarName(fullTypeName)), + } + + for _, arg := range args { + arg.Decorations().Before = dst.NewLine + arg.Decorations().After = dst.NewLine + } + + return &dst.CallExpr{ + Fun: &dst.Ident{ + Name: "NewUnmeteredConstructorMember", + Path: semaPath, + }, + Args: args, + } } + // Unsupported + panic(fmt.Errorf( "%s members are not supported", declarationKind.Name(), diff --git a/runtime/sema/gen/main_test.go b/runtime/sema/gen/main_test.go index 1e8def123d..e1862abb96 100644 --- a/runtime/sema/gen/main_test.go +++ b/runtime/sema/gen/main_test.go @@ -38,21 +38,22 @@ func TestFiles(t *testing.T) { t.Parallel() - test := func(inputPath string) { - // The test name is the filename without the extension. - _, filename := filepath.Split(inputPath) - testname := filename[:len(filename)-len(filepath.Ext(inputPath))] + test := func(dirPath string) { + // The test name is the directory name + _, testName := filepath.Split(dirPath) - t.Run(testname, func(t *testing.T) { + t.Run(testName, func(t *testing.T) { t.Parallel() outFile, err := os.CreateTemp(t.TempDir(), "gen.*.go") require.NoError(t, err) defer outFile.Close() - gen(inputPath, outFile, "github.com/onflow/cadence/runtime/sema") + inputPath := filepath.Join(dirPath, "test.cdc") - goldenPath := filepath.Join(testDataDirectory, testname+".golden.go") + gen(inputPath, outFile, "github.com/onflow/cadence/runtime/sema/gen/"+dirPath) + + goldenPath := filepath.Join(dirPath, "test.golden.go") want, err := os.ReadFile(goldenPath) require.NoError(t, err) @@ -66,7 +67,7 @@ func TestFiles(t *testing.T) { }) } - paths, err := filepath.Glob(filepath.Join(testDataDirectory, "*.cdc")) + paths, err := filepath.Glob(filepath.Join(testDataDirectory, "*")) require.NoError(t, err) for _, path := range paths { diff --git a/runtime/sema/gen/testdata/comparable/helper.go b/runtime/sema/gen/testdata/comparable/helper.go new file mode 100644 index 0000000000..efc83f3b98 --- /dev/null +++ b/runtime/sema/gen/testdata/comparable/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 comparable + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/comparable.cdc b/runtime/sema/gen/testdata/comparable/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/comparable.cdc rename to runtime/sema/gen/testdata/comparable/test.cdc diff --git a/runtime/sema/gen/testdata/comparable.golden.go b/runtime/sema/gen/testdata/comparable/test.golden.go similarity index 82% rename from runtime/sema/gen/testdata/comparable.golden.go rename to runtime/sema/gen/testdata/comparable/test.golden.go index 610a531517..c088f5d175 100644 --- a/runtime/sema/gen/testdata/comparable.golden.go +++ b/runtime/sema/gen/testdata/comparable/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/comparable.cdc. DO NOT EDIT. +// Code generated from testdata/comparable/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package comparable + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/composite-type-pragma.cdc b/runtime/sema/gen/testdata/composite_type_pragma/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/composite-type-pragma.cdc rename to runtime/sema/gen/testdata/composite_type_pragma/test.cdc diff --git a/runtime/sema/gen/testdata/composite-type-pragma.golden.go b/runtime/sema/gen/testdata/composite_type_pragma/test.golden.go similarity index 75% rename from runtime/sema/gen/testdata/composite-type-pragma.golden.go rename to runtime/sema/gen/testdata/composite_type_pragma/test.golden.go index f975ff112f..0ce3c47a03 100644 --- a/runtime/sema/gen/testdata/composite-type-pragma.golden.go +++ b/runtime/sema/gen/testdata/composite_type_pragma/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/composite-type-pragma.cdc. DO NOT EDIT. +// Code generated from testdata/composite_type_pragma/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,14 +17,17 @@ * limitations under the License. */ -package sema +package composite_type_pragma -import "github.com/onflow/cadence/runtime/common" +import ( + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/sema" +) const TestTypeName = "Test" -var TestType = func() *CompositeType { - var t = &CompositeType{ +var TestType = func() *sema.CompositeType { + var t = &sema.CompositeType{ Identifier: TestTypeName, Kind: common.CompositeKindStructure, ImportableBuiltin: false, diff --git a/runtime/sema/gen/testdata/constructor/test.cdc b/runtime/sema/gen/testdata/constructor/test.cdc new file mode 100644 index 0000000000..3c3881ee91 --- /dev/null +++ b/runtime/sema/gen/testdata/constructor/test.cdc @@ -0,0 +1,6 @@ +/// The Foo type +struct Foo { + + /// Constructs a new Foo + init(bar: Int) +} diff --git a/runtime/sema/gen/testdata/constructor/test.golden.go b/runtime/sema/gen/testdata/constructor/test.golden.go new file mode 100644 index 0000000000..3b2809675a --- /dev/null +++ b/runtime/sema/gen/testdata/constructor/test.golden.go @@ -0,0 +1,63 @@ +// Code generated from testdata/constructor/test.cdc. DO NOT EDIT. +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 constructor + +import ( + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/sema" +) + +var FooTypeConstructorType = &sema.FunctionType{ + IsConstructor: true, + Parameters: []sema.Parameter{ + { + Identifier: "bar", + TypeAnnotation: sema.NewTypeAnnotation(sema.IntType), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + FooType, + ), +} + +const FooTypeConstructorDocString = ` +Constructs a new Foo +` + +const FooTypeName = "Foo" + +var FooType = func() *sema.CompositeType { + var t = &sema.CompositeType{ + Identifier: FooTypeName, + Kind: common.CompositeKindStructure, + ImportableBuiltin: false, + HasComputedMembers: true, + } + + return t +}() + +func init() { + var members = []*sema.Member{} + + FooType.Members = sema.MembersAsMap(members) + FooType.Fields = sema.MembersFieldNames(members) + FooType.ConstructorParameters = FooTypeConstructorType.Parameters +} diff --git a/runtime/sema/gen/testdata/contract/test.cdc b/runtime/sema/gen/testdata/contract/test.cdc new file mode 100644 index 0000000000..51ba964699 --- /dev/null +++ b/runtime/sema/gen/testdata/contract/test.cdc @@ -0,0 +1,10 @@ +access(all) +contract Test { + + /// The Foo type + struct Foo { + + /// Constructs a new Foo + init(bar: Int) + } +} diff --git a/runtime/sema/gen/testdata/contract/test.golden.go b/runtime/sema/gen/testdata/contract/test.golden.go new file mode 100644 index 0000000000..57a2fca534 --- /dev/null +++ b/runtime/sema/gen/testdata/contract/test.golden.go @@ -0,0 +1,93 @@ +// Code generated from testdata/contract/test.cdc. DO NOT EDIT. +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 contract + +import ( + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/sema" +) + +var Test_FooTypeConstructorType = &sema.FunctionType{ + IsConstructor: true, + Parameters: []sema.Parameter{ + { + Identifier: "bar", + TypeAnnotation: sema.NewTypeAnnotation(sema.IntType), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + Test_FooType, + ), +} + +const Test_FooTypeConstructorDocString = ` +Constructs a new Foo +` + +const Test_FooTypeName = "Foo" + +var Test_FooType = func() *sema.CompositeType { + var t = &sema.CompositeType{ + Identifier: Test_FooTypeName, + Kind: common.CompositeKindStructure, + ImportableBuiltin: false, + HasComputedMembers: true, + } + + return t +}() + +func init() { + var members = []*sema.Member{} + + Test_FooType.Members = sema.MembersAsMap(members) + Test_FooType.Fields = sema.MembersFieldNames(members) + Test_FooType.ConstructorParameters = Test_FooTypeConstructorType.Parameters +} + +const TestTypeName = "Test" + +var TestType = func() *sema.CompositeType { + var t = &sema.CompositeType{ + Identifier: TestTypeName, + Kind: common.CompositeKindContract, + ImportableBuiltin: false, + HasComputedMembers: true, + } + + t.SetNestedType(Test_FooTypeName, Test_FooType) + return t +}() + +func init() { + var members = []*sema.Member{ + sema.NewUnmeteredConstructorMember( + TestType, + sema.PrimitiveAccess(ast.AccessNotSpecified), + Test_FooTypeName, + Test_FooTypeConstructorType, + Test_FooTypeConstructorDocString, + ), + } + + TestType.Members = sema.MembersAsMap(members) + TestType.Fields = sema.MembersFieldNames(members) +} diff --git a/runtime/sema/gen/testdata/docstrings/helper.go b/runtime/sema/gen/testdata/docstrings/helper.go new file mode 100644 index 0000000000..89877cfac0 --- /dev/null +++ b/runtime/sema/gen/testdata/docstrings/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 docstrings + +import "github.com/onflow/cadence/runtime/sema" + +var DocstringsTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/docstrings.cdc b/runtime/sema/gen/testdata/docstrings/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/docstrings.cdc rename to runtime/sema/gen/testdata/docstrings/test.cdc diff --git a/runtime/sema/gen/testdata/docstrings.golden.go b/runtime/sema/gen/testdata/docstrings/test.golden.go similarity index 66% rename from runtime/sema/gen/testdata/docstrings.golden.go rename to runtime/sema/gen/testdata/docstrings/test.golden.go index 68f4102b92..a35767c913 100644 --- a/runtime/sema/gen/testdata/docstrings.golden.go +++ b/runtime/sema/gen/testdata/docstrings/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/docstrings.cdc. DO NOT EDIT. +// Code generated from testdata/docstrings/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,13 +17,16 @@ * limitations under the License. */ -package sema +package docstrings -import "github.com/onflow/cadence/runtime/ast" +import ( + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/sema" +) const DocstringsTypeOwoFieldName = "owo" -var DocstringsTypeOwoFieldType = IntType +var DocstringsTypeOwoFieldType = sema.IntType const DocstringsTypeOwoFieldDocString = ` This is a 1-line docstring. @@ -31,8 +34,8 @@ This is a 1-line docstring. const DocstringsTypeUwuFieldName = "uwu" -var DocstringsTypeUwuFieldType = &VariableSizedType{ - Type: IntType, +var DocstringsTypeUwuFieldType = &sema.VariableSizedType{ + Type: sema.IntType, } const DocstringsTypeUwuFieldDocString = ` @@ -42,16 +45,16 @@ This is the second line. const DocstringsTypeNwnFunctionName = "nwn" -var DocstringsTypeNwnFunctionType = &FunctionType{ - Parameters: []Parameter{ +var DocstringsTypeNwnFunctionType = &sema.FunctionType{ + Parameters: []sema.Parameter{ { Identifier: "x", - TypeAnnotation: NewTypeAnnotation(IntType), + TypeAnnotation: sema.NewTypeAnnotation(sema.IntType), }, }, - ReturnTypeAnnotation: NewTypeAnnotation( - &OptionalType{ - Type: StringType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + &sema.OptionalType{ + Type: sema.StringType, }, ), } @@ -64,7 +67,7 @@ And the third line! const DocstringsTypeWithBlanksFieldName = "withBlanks" -var DocstringsTypeWithBlanksFieldType = IntType +var DocstringsTypeWithBlanksFieldType = sema.IntType const DocstringsTypeWithBlanksFieldDocString = ` This is a multiline docstring. @@ -74,9 +77,9 @@ There should be two newlines before this line! const DocstringsTypeIsSmolBeanFunctionName = "isSmolBean" -var DocstringsTypeIsSmolBeanFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - BoolType, +var DocstringsTypeIsSmolBeanFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.BoolType, ), } @@ -87,10 +90,10 @@ These should be handled accordingly. const DocstringsTypeRunningOutOfIdeasFunctionName = "runningOutOfIdeas" -var DocstringsTypeRunningOutOfIdeasFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - &OptionalType{ - Type: UInt64Type, +var DocstringsTypeRunningOutOfIdeasFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + &sema.OptionalType{ + Type: sema.UInt64Type, }, ), } @@ -103,11 +106,11 @@ Look, I did it ` + "`again`" + `, wowie!! const DocstringsTypeName = "Docstrings" -var DocstringsType = &SimpleType{ +var DocstringsType = &sema.SimpleType{ Name: DocstringsTypeName, QualifiedName: DocstringsTypeName, TypeID: DocstringsTypeName, - tag: DocstringsTypeTag, + TypeTag: DocstringsTypeTag, IsResource: false, Storable: false, Equatable: false, @@ -118,49 +121,49 @@ var DocstringsType = &SimpleType{ } func init() { - DocstringsType.Members = func(t *SimpleType) map[string]MemberResolver { - return MembersAsResolvers([]*Member{ - NewUnmeteredFieldMember( + DocstringsType.Members = func(t *sema.SimpleType) map[string]sema.MemberResolver { + return sema.MembersAsResolvers([]*sema.Member{ + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, DocstringsTypeOwoFieldName, DocstringsTypeOwoFieldType, DocstringsTypeOwoFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, DocstringsTypeUwuFieldName, DocstringsTypeUwuFieldType, DocstringsTypeUwuFieldDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), DocstringsTypeNwnFunctionName, DocstringsTypeNwnFunctionType, DocstringsTypeNwnFunctionDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, DocstringsTypeWithBlanksFieldName, DocstringsTypeWithBlanksFieldType, DocstringsTypeWithBlanksFieldDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), DocstringsTypeIsSmolBeanFunctionName, DocstringsTypeIsSmolBeanFunctionType, DocstringsTypeIsSmolBeanFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), DocstringsTypeRunningOutOfIdeasFunctionName, DocstringsTypeRunningOutOfIdeasFunctionType, DocstringsTypeRunningOutOfIdeasFunctionDocString, diff --git a/runtime/sema/gen/testdata/entitlement.cdc b/runtime/sema/gen/testdata/entitlement/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/entitlement.cdc rename to runtime/sema/gen/testdata/entitlement/test.cdc diff --git a/runtime/sema/gen/testdata/entitlement.golden.go b/runtime/sema/gen/testdata/entitlement/test.golden.go similarity index 58% rename from runtime/sema/gen/testdata/entitlement.golden.go rename to runtime/sema/gen/testdata/entitlement/test.golden.go index 0296d081f3..1d44250ceb 100644 --- a/runtime/sema/gen/testdata/entitlement.golden.go +++ b/runtime/sema/gen/testdata/entitlement/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/entitlement.cdc. DO NOT EDIT. +// Code generated from testdata/entitlement/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,32 +17,34 @@ * limitations under the License. */ -package sema +package entitlement -var FooType = &EntitlementType{ +import "github.com/onflow/cadence/runtime/sema" + +var FooType = &sema.EntitlementType{ Identifier: "Foo", } -var BarType = &EntitlementType{ +var BarType = &sema.EntitlementType{ Identifier: "Bar", } -var BazType = &EntitlementMapType{ +var BazType = &sema.EntitlementMapType{ Identifier: "Baz", IncludesIdentity: false, - Relations: []EntitlementRelation{ - EntitlementRelation{ + Relations: []sema.EntitlementRelation{ + sema.EntitlementRelation{ Input: FooType, Output: BarType, }, }, } -var QuxType = &EntitlementMapType{ +var QuxType = &sema.EntitlementMapType{ Identifier: "Qux", IncludesIdentity: true, - Relations: []EntitlementRelation{ - EntitlementRelation{ + Relations: []sema.EntitlementRelation{ + sema.EntitlementRelation{ Input: FooType, Output: BarType, }, @@ -50,12 +52,8 @@ var QuxType = &EntitlementMapType{ } func init() { - BuiltinEntitlementMappings[BazType.Identifier] = BazType - addToBaseActivation(BazType) - BuiltinEntitlementMappings[QuxType.Identifier] = QuxType - addToBaseActivation(QuxType) - BuiltinEntitlements[FooType.Identifier] = FooType - addToBaseActivation(FooType) - BuiltinEntitlements[BarType.Identifier] = BarType - addToBaseActivation(BarType) + sema.BuiltinEntitlementMappings[BazType.Identifier] = BazType + sema.BuiltinEntitlementMappings[QuxType.Identifier] = QuxType + sema.BuiltinEntitlements[FooType.Identifier] = FooType + sema.BuiltinEntitlements[BarType.Identifier] = BarType } diff --git a/runtime/sema/gen/testdata/equatable/helper.go b/runtime/sema/gen/testdata/equatable/helper.go new file mode 100644 index 0000000000..1fe9bc6a2a --- /dev/null +++ b/runtime/sema/gen/testdata/equatable/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 equatable + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/equatable.cdc b/runtime/sema/gen/testdata/equatable/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/equatable.cdc rename to runtime/sema/gen/testdata/equatable/test.cdc diff --git a/runtime/sema/gen/testdata/equatable.golden.go b/runtime/sema/gen/testdata/equatable/test.golden.go similarity index 83% rename from runtime/sema/gen/testdata/equatable.golden.go rename to runtime/sema/gen/testdata/equatable/test.golden.go index 82320957ee..e102e7e6de 100644 --- a/runtime/sema/gen/testdata/equatable.golden.go +++ b/runtime/sema/gen/testdata/equatable/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/equatable.cdc. DO NOT EDIT. +// Code generated from testdata/equatable/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package equatable + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: true, diff --git a/runtime/sema/gen/testdata/exportable/helper.go b/runtime/sema/gen/testdata/exportable/helper.go new file mode 100644 index 0000000000..92baaf371c --- /dev/null +++ b/runtime/sema/gen/testdata/exportable/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 exportable + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/exportable.cdc b/runtime/sema/gen/testdata/exportable/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/exportable.cdc rename to runtime/sema/gen/testdata/exportable/test.cdc diff --git a/runtime/sema/gen/testdata/exportable.golden.go b/runtime/sema/gen/testdata/exportable/test.golden.go similarity index 82% rename from runtime/sema/gen/testdata/exportable.golden.go rename to runtime/sema/gen/testdata/exportable/test.golden.go index db6afd0593..3124209d4a 100644 --- a/runtime/sema/gen/testdata/exportable.golden.go +++ b/runtime/sema/gen/testdata/exportable/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/exportable.cdc. DO NOT EDIT. +// Code generated from testdata/exportable/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package exportable + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/fields/helper.go b/runtime/sema/gen/testdata/fields/helper.go new file mode 100644 index 0000000000..0fbaa3f0f8 --- /dev/null +++ b/runtime/sema/gen/testdata/fields/helper.go @@ -0,0 +1,26 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 fields + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag +var FooType = &sema.CapabilityType{} +var BarType *sema.InterfaceType +var BazType *sema.InterfaceType diff --git a/runtime/sema/gen/testdata/fields.cdc b/runtime/sema/gen/testdata/fields/test.cdc similarity index 99% rename from runtime/sema/gen/testdata/fields.cdc rename to runtime/sema/gen/testdata/fields/test.cdc index 1cf74e4f96..2f5338d1e9 100644 --- a/runtime/sema/gen/testdata/fields.cdc +++ b/runtime/sema/gen/testdata/fields/test.cdc @@ -1,3 +1,4 @@ + access(all) struct Test { /// This is a test integer. access(all) let testInt: UInt64 diff --git a/runtime/sema/gen/testdata/fields.golden.go b/runtime/sema/gen/testdata/fields/test.golden.go similarity index 67% rename from runtime/sema/gen/testdata/fields.golden.go rename to runtime/sema/gen/testdata/fields/test.golden.go index f4af42f973..950c618e93 100644 --- a/runtime/sema/gen/testdata/fields.golden.go +++ b/runtime/sema/gen/testdata/fields/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/fields.cdc. DO NOT EDIT. +// Code generated from testdata/fields/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,13 +17,16 @@ * limitations under the License. */ -package sema +package fields -import "github.com/onflow/cadence/runtime/ast" +import ( + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/sema" +) const TestTypeTestIntFieldName = "testInt" -var TestTypeTestIntFieldType = UInt64Type +var TestTypeTestIntFieldType = sema.UInt64Type const TestTypeTestIntFieldDocString = ` This is a test integer. @@ -31,8 +34,8 @@ This is a test integer. const TestTypeTestOptIntFieldName = "testOptInt" -var TestTypeTestOptIntFieldType = &OptionalType{ - Type: UInt64Type, +var TestTypeTestOptIntFieldType = &sema.OptionalType{ + Type: sema.UInt64Type, } const TestTypeTestOptIntFieldDocString = ` @@ -41,9 +44,9 @@ This is a test optional integer. const TestTypeTestRefIntFieldName = "testRefInt" -var TestTypeTestRefIntFieldType = &ReferenceType{ - Type: UInt64Type, - Authorization: UnauthorizedAccess, +var TestTypeTestRefIntFieldType = &sema.ReferenceType{ + Type: sema.UInt64Type, + Authorization: sema.UnauthorizedAccess, } const TestTypeTestRefIntFieldDocString = ` @@ -52,8 +55,8 @@ This is a test integer reference. const TestTypeTestVarIntsFieldName = "testVarInts" -var TestTypeTestVarIntsFieldType = &VariableSizedType{ - Type: UInt64Type, +var TestTypeTestVarIntsFieldType = &sema.VariableSizedType{ + Type: sema.UInt64Type, } const TestTypeTestVarIntsFieldDocString = ` @@ -62,8 +65,8 @@ This is a test variable-sized integer array. const TestTypeTestConstIntsFieldName = "testConstInts" -var TestTypeTestConstIntsFieldType = &ConstantSizedType{ - Type: UInt64Type, +var TestTypeTestConstIntsFieldType = &sema.ConstantSizedType{ + Type: sema.UInt64Type, Size: 2, } @@ -73,9 +76,9 @@ This is a test constant-sized integer array. const TestTypeTestIntDictFieldName = "testIntDict" -var TestTypeTestIntDictFieldType = &DictionaryType{ - KeyType: UInt64Type, - ValueType: BoolType, +var TestTypeTestIntDictFieldType = &sema.DictionaryType{ + KeyType: sema.UInt64Type, + ValueType: sema.BoolType, } const TestTypeTestIntDictFieldDocString = ` @@ -84,7 +87,7 @@ This is a test integer dictionary. const TestTypeTestParamFieldName = "testParam" -var TestTypeTestParamFieldType = MustInstantiate( +var TestTypeTestParamFieldType = sema.MustInstantiate( FooType, BarType, ) @@ -95,7 +98,7 @@ This is a test parameterized-type field. const TestTypeTestAddressFieldName = "testAddress" -var TestTypeTestAddressFieldType = TheAddressType +var TestTypeTestAddressFieldType = sema.TheAddressType const TestTypeTestAddressFieldDocString = ` This is a test address field. @@ -103,7 +106,7 @@ This is a test address field. const TestTypeTestTypeFieldName = "testType" -var TestTypeTestTypeFieldType = MetaType +var TestTypeTestTypeFieldType = sema.MetaType const TestTypeTestTypeFieldDocString = ` This is a test type field. @@ -111,7 +114,7 @@ This is a test type field. const TestTypeTestCapFieldName = "testCap" -var TestTypeTestCapFieldType = &CapabilityType{} +var TestTypeTestCapFieldType = &sema.CapabilityType{} const TestTypeTestCapFieldDocString = ` This is a test unparameterized capability field. @@ -119,9 +122,9 @@ This is a test unparameterized capability field. const TestTypeTestCapIntFieldName = "testCapInt" -var TestTypeTestCapIntFieldType = MustInstantiate( - &CapabilityType{}, - IntType, +var TestTypeTestCapIntFieldType = sema.MustInstantiate( + &sema.CapabilityType{}, + sema.IntType, ) const TestTypeTestCapIntFieldDocString = ` @@ -130,8 +133,8 @@ This is a test parameterized capability field. const TestTypeTestIntersectionWithoutTypeFieldName = "testIntersectionWithoutType" -var TestTypeTestIntersectionWithoutTypeFieldType = &IntersectionType{ - Types: []*InterfaceType{BarType, BazType}, +var TestTypeTestIntersectionWithoutTypeFieldType = &sema.IntersectionType{ + Types: []*sema.InterfaceType{BarType, BazType}, } const TestTypeTestIntersectionWithoutTypeFieldDocString = ` @@ -140,11 +143,11 @@ This is a test intersection type (without type) field. const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, @@ -155,99 +158,99 @@ var TestType = &SimpleType{ } func init() { - TestType.Members = func(t *SimpleType) map[string]MemberResolver { - return MembersAsResolvers([]*Member{ - NewUnmeteredFieldMember( + TestType.Members = func(t *sema.SimpleType) map[string]sema.MemberResolver { + return sema.MembersAsResolvers([]*sema.Member{ + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestIntFieldName, TestTypeTestIntFieldType, TestTypeTestIntFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestOptIntFieldName, TestTypeTestOptIntFieldType, TestTypeTestOptIntFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestRefIntFieldName, TestTypeTestRefIntFieldType, TestTypeTestRefIntFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestVarIntsFieldName, TestTypeTestVarIntsFieldType, TestTypeTestVarIntsFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestConstIntsFieldName, TestTypeTestConstIntsFieldType, TestTypeTestConstIntsFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestIntDictFieldName, TestTypeTestIntDictFieldType, TestTypeTestIntDictFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestParamFieldName, TestTypeTestParamFieldType, TestTypeTestParamFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestAddressFieldName, TestTypeTestAddressFieldType, TestTypeTestAddressFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestTypeFieldName, TestTypeTestTypeFieldType, TestTypeTestTypeFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestCapFieldName, TestTypeTestCapFieldType, TestTypeTestCapFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestCapIntFieldName, TestTypeTestCapIntFieldType, TestTypeTestCapIntFieldDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, TestTypeTestIntersectionWithoutTypeFieldName, TestTypeTestIntersectionWithoutTypeFieldType, diff --git a/runtime/sema/gen/testdata/functions/helper.go b/runtime/sema/gen/testdata/functions/helper.go new file mode 100644 index 0000000000..eb10cbad92 --- /dev/null +++ b/runtime/sema/gen/testdata/functions/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 functions + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/functions.cdc b/runtime/sema/gen/testdata/functions/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/functions.cdc rename to runtime/sema/gen/testdata/functions/test.cdc diff --git a/runtime/sema/gen/testdata/functions.golden.go b/runtime/sema/gen/testdata/functions/test.golden.go similarity index 57% rename from runtime/sema/gen/testdata/functions.golden.go rename to runtime/sema/gen/testdata/functions/test.golden.go index 41226f8238..2c22638b28 100644 --- a/runtime/sema/gen/testdata/functions.golden.go +++ b/runtime/sema/gen/testdata/functions/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/functions.cdc. DO NOT EDIT. +// Code generated from testdata/functions/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,18 @@ * limitations under the License. */ -package sema +package functions -import "github.com/onflow/cadence/runtime/ast" +import ( + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/sema" +) const TestTypeNothingFunctionName = "nothing" -var TestTypeNothingFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, +var TestTypeNothingFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -35,20 +38,20 @@ This is a test function. const TestTypeParamsFunctionName = "params" -var TestTypeParamsFunctionType = &FunctionType{ - Parameters: []Parameter{ +var TestTypeParamsFunctionType = &sema.FunctionType{ + Parameters: []sema.Parameter{ { Identifier: "a", - TypeAnnotation: NewTypeAnnotation(IntType), + TypeAnnotation: sema.NewTypeAnnotation(sema.IntType), }, { - Label: ArgumentLabelNotRequired, + Label: sema.ArgumentLabelNotRequired, Identifier: "b", - TypeAnnotation: NewTypeAnnotation(StringType), + TypeAnnotation: sema.NewTypeAnnotation(sema.StringType), }, }, - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -58,9 +61,9 @@ This is a test function with parameters. const TestTypeReturnBoolFunctionName = "returnBool" -var TestTypeReturnBoolFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - BoolType, +var TestTypeReturnBoolFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.BoolType, ), } @@ -70,20 +73,20 @@ This is a test function with a return type. const TestTypeParamsAndReturnFunctionName = "paramsAndReturn" -var TestTypeParamsAndReturnFunctionType = &FunctionType{ - Parameters: []Parameter{ +var TestTypeParamsAndReturnFunctionType = &sema.FunctionType{ + Parameters: []sema.Parameter{ { Identifier: "a", - TypeAnnotation: NewTypeAnnotation(IntType), + TypeAnnotation: sema.NewTypeAnnotation(sema.IntType), }, { - Label: ArgumentLabelNotRequired, + Label: sema.ArgumentLabelNotRequired, Identifier: "b", - TypeAnnotation: NewTypeAnnotation(StringType), + TypeAnnotation: sema.NewTypeAnnotation(sema.StringType), }, }, - ReturnTypeAnnotation: NewTypeAnnotation( - BoolType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.BoolType, ), } @@ -93,16 +96,16 @@ This is a test function with parameters and a return type. const TestTypeTypeParamFunctionName = "typeParam" -var TestTypeTypeParamFunctionTypeParameterT = &TypeParameter{ +var TestTypeTypeParamFunctionTypeParameterT = &sema.TypeParameter{ Name: "T", } -var TestTypeTypeParamFunctionType = &FunctionType{ - TypeParameters: []*TypeParameter{ +var TestTypeTypeParamFunctionType = &sema.FunctionType{ + TypeParameters: []*sema.TypeParameter{ TestTypeTypeParamFunctionTypeParameterT, }, - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -112,20 +115,20 @@ This is a test function with a type parameter. const TestTypeTypeParamWithBoundFunctionName = "typeParamWithBound" -var TestTypeTypeParamWithBoundFunctionTypeParameterT = &TypeParameter{ +var TestTypeTypeParamWithBoundFunctionTypeParameterT = &sema.TypeParameter{ Name: "T", - TypeBound: &ReferenceType{ - Type: AnyType, - Authorization: UnauthorizedAccess, + TypeBound: &sema.ReferenceType{ + Type: sema.AnyType, + Authorization: sema.UnauthorizedAccess, }, } -var TestTypeTypeParamWithBoundFunctionType = &FunctionType{ - TypeParameters: []*TypeParameter{ +var TestTypeTypeParamWithBoundFunctionType = &sema.FunctionType{ + TypeParameters: []*sema.TypeParameter{ TestTypeTypeParamWithBoundFunctionTypeParameterT, }, - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -135,24 +138,24 @@ This is a test function with a type parameter and a type bound. const TestTypeTypeParamWithBoundAndParamFunctionName = "typeParamWithBoundAndParam" -var TestTypeTypeParamWithBoundAndParamFunctionTypeParameterT = &TypeParameter{ +var TestTypeTypeParamWithBoundAndParamFunctionTypeParameterT = &sema.TypeParameter{ Name: "T", } -var TestTypeTypeParamWithBoundAndParamFunctionType = &FunctionType{ - TypeParameters: []*TypeParameter{ +var TestTypeTypeParamWithBoundAndParamFunctionType = &sema.FunctionType{ + TypeParameters: []*sema.TypeParameter{ TestTypeTypeParamWithBoundAndParamFunctionTypeParameterT, }, - Parameters: []Parameter{ + Parameters: []sema.Parameter{ { Identifier: "t", - TypeAnnotation: NewTypeAnnotation(&GenericType{ + TypeAnnotation: sema.NewTypeAnnotation(&sema.GenericType{ TypeParameter: TestTypeTypeParamWithBoundAndParamFunctionTypeParameterT, }), }, }, - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -162,10 +165,10 @@ This is a test function with a type parameter and a parameter using it. const TestTypeViewFunctionFunctionName = "viewFunction" -var TestTypeViewFunctionFunctionType = &FunctionType{ - Purity: FunctionPurityView, - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, +var TestTypeViewFunctionFunctionType = &sema.FunctionType{ + Purity: sema.FunctionPurityView, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -175,11 +178,11 @@ This is a function with 'view' modifier const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, @@ -190,60 +193,60 @@ var TestType = &SimpleType{ } func init() { - TestType.Members = func(t *SimpleType) map[string]MemberResolver { - return MembersAsResolvers([]*Member{ - NewUnmeteredFunctionMember( + TestType.Members = func(t *sema.SimpleType) map[string]sema.MemberResolver { + return sema.MembersAsResolvers([]*sema.Member{ + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeNothingFunctionName, TestTypeNothingFunctionType, TestTypeNothingFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeParamsFunctionName, TestTypeParamsFunctionType, TestTypeParamsFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeReturnBoolFunctionName, TestTypeReturnBoolFunctionType, TestTypeReturnBoolFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeParamsAndReturnFunctionName, TestTypeParamsAndReturnFunctionType, TestTypeParamsAndReturnFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeTypeParamFunctionName, TestTypeTypeParamFunctionType, TestTypeTypeParamFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeTypeParamWithBoundFunctionName, TestTypeTypeParamWithBoundFunctionType, TestTypeTypeParamWithBoundFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeTypeParamWithBoundAndParamFunctionName, TestTypeTypeParamWithBoundAndParamFunctionType, TestTypeTypeParamWithBoundAndParamFunctionDocString, ), - NewUnmeteredFunctionMember( + sema.NewUnmeteredFunctionMember( t, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), TestTypeViewFunctionFunctionName, TestTypeViewFunctionFunctionType, TestTypeViewFunctionFunctionDocString, diff --git a/runtime/sema/gen/testdata/importable/helper.go b/runtime/sema/gen/testdata/importable/helper.go new file mode 100644 index 0000000000..6a02e2c7c5 --- /dev/null +++ b/runtime/sema/gen/testdata/importable/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 importable + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/importable.cdc b/runtime/sema/gen/testdata/importable/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/importable.cdc rename to runtime/sema/gen/testdata/importable/test.cdc diff --git a/runtime/sema/gen/testdata/importable.golden.go b/runtime/sema/gen/testdata/importable/test.golden.go similarity index 82% rename from runtime/sema/gen/testdata/importable.golden.go rename to runtime/sema/gen/testdata/importable/test.golden.go index 39496013d4..243be9b153 100644 --- a/runtime/sema/gen/testdata/importable.golden.go +++ b/runtime/sema/gen/testdata/importable/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/importable.cdc. DO NOT EDIT. +// Code generated from testdata/importable/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package importable + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/member_accessible/helper.go b/runtime/sema/gen/testdata/member_accessible/helper.go new file mode 100644 index 0000000000..2632d04b5c --- /dev/null +++ b/runtime/sema/gen/testdata/member_accessible/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 member_accessible + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/member_accessible.cdc b/runtime/sema/gen/testdata/member_accessible/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/member_accessible.cdc rename to runtime/sema/gen/testdata/member_accessible/test.cdc diff --git a/runtime/sema/gen/testdata/member_accessible.golden.go b/runtime/sema/gen/testdata/member_accessible/test.golden.go similarity index 81% rename from runtime/sema/gen/testdata/member_accessible.golden.go rename to runtime/sema/gen/testdata/member_accessible/test.golden.go index d3553ebafd..ec49013df0 100644 --- a/runtime/sema/gen/testdata/member_accessible.golden.go +++ b/runtime/sema/gen/testdata/member_accessible/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/member_accessible.cdc. DO NOT EDIT. +// Code generated from testdata/member_accessible/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package member_accessible + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/nested.cdc b/runtime/sema/gen/testdata/nested/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/nested.cdc rename to runtime/sema/gen/testdata/nested/test.cdc diff --git a/runtime/sema/gen/testdata/nested.golden.go b/runtime/sema/gen/testdata/nested/test.golden.go similarity index 65% rename from runtime/sema/gen/testdata/nested.golden.go rename to runtime/sema/gen/testdata/nested/test.golden.go index 73c94c99c1..d5a1058aa0 100644 --- a/runtime/sema/gen/testdata/nested.golden.go +++ b/runtime/sema/gen/testdata/nested/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/nested.cdc. DO NOT EDIT. +// Code generated from testdata/nested/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,18 +17,19 @@ * limitations under the License. */ -package sema +package nested import ( "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/sema" ) const FooTypeFooFunctionName = "foo" -var FooTypeFooFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, +var FooTypeFooFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -46,9 +47,9 @@ Bar const Foo_BarTypeBarFunctionName = "bar" -var Foo_BarTypeBarFunctionType = &FunctionType{ - ReturnTypeAnnotation: NewTypeAnnotation( - VoidType, +var Foo_BarTypeBarFunctionType = &sema.FunctionType{ + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, ), } @@ -58,8 +59,8 @@ bar const Foo_BarTypeName = "Bar" -var Foo_BarType = func() *CompositeType { - var t = &CompositeType{ +var Foo_BarType = func() *sema.CompositeType { + var t = &sema.CompositeType{ Identifier: Foo_BarTypeName, Kind: common.CompositeKindStructure, ImportableBuiltin: false, @@ -70,24 +71,24 @@ var Foo_BarType = func() *CompositeType { }() func init() { - var members = []*Member{ - NewUnmeteredFunctionMember( + var members = []*sema.Member{ + sema.NewUnmeteredFunctionMember( Foo_BarType, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), Foo_BarTypeBarFunctionName, Foo_BarTypeBarFunctionType, Foo_BarTypeBarFunctionDocString, ), } - Foo_BarType.Members = MembersAsMap(members) - Foo_BarType.Fields = MembersFieldNames(members) + Foo_BarType.Members = sema.MembersAsMap(members) + Foo_BarType.Fields = sema.MembersFieldNames(members) } const FooTypeName = "Foo" -var FooType = func() *CompositeType { - var t = &CompositeType{ +var FooType = func() *sema.CompositeType { + var t = &sema.CompositeType{ Identifier: FooTypeName, Kind: common.CompositeKindStructure, ImportableBuiltin: false, @@ -99,17 +100,17 @@ var FooType = func() *CompositeType { }() func init() { - var members = []*Member{ - NewUnmeteredFunctionMember( + var members = []*sema.Member{ + sema.NewUnmeteredFunctionMember( FooType, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), FooTypeFooFunctionName, FooTypeFooFunctionType, FooTypeFooFunctionDocString, ), - NewUnmeteredFieldMember( + sema.NewUnmeteredFieldMember( FooType, - PrimitiveAccess(ast.AccessAll), + sema.PrimitiveAccess(ast.AccessAll), ast.VariableKindConstant, FooTypeBarFieldName, FooTypeBarFieldType, @@ -117,6 +118,6 @@ func init() { ), } - FooType.Members = MembersAsMap(members) - FooType.Fields = MembersFieldNames(members) + FooType.Members = sema.MembersAsMap(members) + FooType.Fields = sema.MembersFieldNames(members) } diff --git a/runtime/sema/gen/testdata/simple_resource/helper.go b/runtime/sema/gen/testdata/simple_resource/helper.go new file mode 100644 index 0000000000..16de616169 --- /dev/null +++ b/runtime/sema/gen/testdata/simple_resource/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 simple_resource + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/simple-resource.cdc b/runtime/sema/gen/testdata/simple_resource/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/simple-resource.cdc rename to runtime/sema/gen/testdata/simple_resource/test.cdc diff --git a/runtime/sema/gen/testdata/simple-resource.golden.go b/runtime/sema/gen/testdata/simple_resource/test.golden.go similarity index 82% rename from runtime/sema/gen/testdata/simple-resource.golden.go rename to runtime/sema/gen/testdata/simple_resource/test.golden.go index 53ee6c24f7..a6876b92ce 100644 --- a/runtime/sema/gen/testdata/simple-resource.golden.go +++ b/runtime/sema/gen/testdata/simple_resource/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/simple-resource.cdc. DO NOT EDIT. +// Code generated from testdata/simple_resource/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package simple_resource + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: true, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/simple_struct/helper.go b/runtime/sema/gen/testdata/simple_struct/helper.go new file mode 100644 index 0000000000..b9cf6dd4da --- /dev/null +++ b/runtime/sema/gen/testdata/simple_struct/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 simple_struct + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/simple-struct.cdc b/runtime/sema/gen/testdata/simple_struct/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/simple-struct.cdc rename to runtime/sema/gen/testdata/simple_struct/test.cdc diff --git a/runtime/sema/gen/testdata/simple-struct.golden.go b/runtime/sema/gen/testdata/simple_struct/test.golden.go similarity index 82% rename from runtime/sema/gen/testdata/simple-struct.golden.go rename to runtime/sema/gen/testdata/simple_struct/test.golden.go index 0429d008f3..4606268f1d 100644 --- a/runtime/sema/gen/testdata/simple-struct.golden.go +++ b/runtime/sema/gen/testdata/simple_struct/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/simple-struct.cdc. DO NOT EDIT. +// Code generated from testdata/simple_struct/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package simple_struct + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/gen/testdata/storable/helper.go b/runtime/sema/gen/testdata/storable/helper.go new file mode 100644 index 0000000000..cd8334e96c --- /dev/null +++ b/runtime/sema/gen/testdata/storable/helper.go @@ -0,0 +1,23 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 storable + +import "github.com/onflow/cadence/runtime/sema" + +var TestTypeTag sema.TypeTag diff --git a/runtime/sema/gen/testdata/storable.cdc b/runtime/sema/gen/testdata/storable/test.cdc similarity index 100% rename from runtime/sema/gen/testdata/storable.cdc rename to runtime/sema/gen/testdata/storable/test.cdc diff --git a/runtime/sema/gen/testdata/storable.golden.go b/runtime/sema/gen/testdata/storable/test.golden.go similarity index 83% rename from runtime/sema/gen/testdata/storable.golden.go rename to runtime/sema/gen/testdata/storable/test.golden.go index c9c5526991..5a01604df9 100644 --- a/runtime/sema/gen/testdata/storable.golden.go +++ b/runtime/sema/gen/testdata/storable/test.golden.go @@ -1,4 +1,4 @@ -// Code generated from testdata/storable.cdc. DO NOT EDIT. +// Code generated from testdata/storable/test.cdc. DO NOT EDIT. /* * Cadence - The resource-oriented smart contract programming language * @@ -17,15 +17,17 @@ * limitations under the License. */ -package sema +package storable + +import "github.com/onflow/cadence/runtime/sema" const TestTypeName = "Test" -var TestType = &SimpleType{ +var TestType = &sema.SimpleType{ Name: TestTypeName, QualifiedName: TestTypeName, TypeID: TestTypeName, - tag: TestTypeTag, + TypeTag: TestTypeTag, IsResource: false, Storable: true, Equatable: false, diff --git a/runtime/sema/invalid_type.go b/runtime/sema/invalid_type.go index d0ce0787ec..409d50f5ab 100644 --- a/runtime/sema/invalid_type.go +++ b/runtime/sema/invalid_type.go @@ -25,7 +25,7 @@ var InvalidType = &SimpleType{ Name: "<>", QualifiedName: "<>", TypeID: "<>", - tag: InvalidTypeTag, + TypeTag: InvalidTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/meta_type.go b/runtime/sema/meta_type.go index 59d6c4281b..6ee455c1ab 100644 --- a/runtime/sema/meta_type.go +++ b/runtime/sema/meta_type.go @@ -37,7 +37,7 @@ var MetaType = &SimpleType{ Name: MetaTypeName, QualifiedName: MetaTypeName, TypeID: MetaTypeName, - tag: MetaTypeTag, + TypeTag: MetaTypeTag, IsResource: false, Storable: true, Equatable: true, diff --git a/runtime/sema/never_type.go b/runtime/sema/never_type.go index 1722259379..0d3fe642f5 100644 --- a/runtime/sema/never_type.go +++ b/runtime/sema/never_type.go @@ -23,7 +23,7 @@ var NeverType = &SimpleType{ Name: "Never", QualifiedName: "Never", TypeID: "Never", - tag: NeverTypeTag, + TypeTag: NeverTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/path_type.go b/runtime/sema/path_type.go index 41b19dd6f1..fa443cd17f 100644 --- a/runtime/sema/path_type.go +++ b/runtime/sema/path_type.go @@ -23,7 +23,7 @@ var PathType = &SimpleType{ Name: "Path", QualifiedName: "Path", TypeID: "Path", - tag: PathTypeTag, + TypeTag: PathTypeTag, IsResource: false, Storable: true, Equatable: true, @@ -43,7 +43,7 @@ var StoragePathType = &SimpleType{ Name: "StoragePath", QualifiedName: "StoragePath", TypeID: "StoragePath", - tag: StoragePathTypeTag, + TypeTag: StoragePathTypeTag, IsResource: false, Storable: true, Equatable: true, @@ -59,7 +59,7 @@ var CapabilityPathType = &SimpleType{ Name: "CapabilityPath", QualifiedName: "CapabilityPath", TypeID: "CapabilityPath", - tag: CapabilityPathTypeTag, + TypeTag: CapabilityPathTypeTag, IsResource: false, Storable: true, Equatable: true, @@ -79,7 +79,7 @@ var PublicPathType = &SimpleType{ Name: "PublicPath", QualifiedName: "PublicPath", TypeID: "PublicPath", - tag: PublicPathTypeTag, + TypeTag: PublicPathTypeTag, IsResource: false, Storable: true, Equatable: true, @@ -95,7 +95,7 @@ var PrivatePathType = &SimpleType{ Name: "PrivatePath", QualifiedName: "PrivatePath", TypeID: "PrivatePath", - tag: PrivatePathTypeTag, + TypeTag: PrivatePathTypeTag, IsResource: false, Storable: true, Equatable: true, diff --git a/runtime/sema/simple_type.go b/runtime/sema/simple_type.go index f137fdf61a..7e6affd690 100644 --- a/runtime/sema/simple_type.go +++ b/runtime/sema/simple_type.go @@ -42,7 +42,7 @@ type SimpleType struct { QualifiedName string TypeID TypeID Name string - tag TypeTag + TypeTag TypeTag memberResolversOnce sync.Once Importable bool Exportable bool @@ -60,7 +60,7 @@ var _ ContainerType = &SimpleType{} func (*SimpleType) IsType() {} func (t *SimpleType) Tag() TypeTag { - return t.tag + return t.TypeTag } func (t *SimpleType) String() string { diff --git a/runtime/sema/storage_capability_controller.gen.go b/runtime/sema/storage_capability_controller.gen.go index c74ed0974a..9ef52376db 100644 --- a/runtime/sema/storage_capability_controller.gen.go +++ b/runtime/sema/storage_capability_controller.gen.go @@ -134,7 +134,7 @@ var StorageCapabilityControllerType = &SimpleType{ Name: StorageCapabilityControllerTypeName, QualifiedName: StorageCapabilityControllerTypeName, TypeID: StorageCapabilityControllerTypeName, - tag: StorageCapabilityControllerTypeTag, + TypeTag: StorageCapabilityControllerTypeTag, IsResource: false, Storable: false, Equatable: false, diff --git a/runtime/sema/string_type.go b/runtime/sema/string_type.go index b4fa762599..6568c5b0a8 100644 --- a/runtime/sema/string_type.go +++ b/runtime/sema/string_type.go @@ -47,7 +47,7 @@ var StringType = &SimpleType{ Name: "String", QualifiedName: "String", TypeID: "String", - tag: StringTypeTag, + TypeTag: StringTypeTag, IsResource: false, Storable: true, Equatable: true, diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 20b942aede..afb3e44486 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4906,6 +4906,48 @@ func NewFunctionMember( } } +func NewUnmeteredConstructorMember( + containerType Type, + access Access, + identifier string, + functionType *FunctionType, + docString string, +) *Member { + return NewConstructorMember( + nil, + containerType, + access, + identifier, + functionType, + docString, + ) +} + +func NewConstructorMember( + memoryGauge common.MemoryGauge, + containerType Type, + access Access, + identifier string, + functionType *FunctionType, + docString string, +) *Member { + + return &Member{ + ContainerType: containerType, + Access: access, + Identifier: ast.NewIdentifier( + memoryGauge, + identifier, + ast.EmptyPosition, + ), + DeclarationKind: common.DeclarationKindInitializer, + VariableKind: ast.VariableKindConstant, + TypeAnnotation: NewTypeAnnotation(functionType), + ArgumentLabels: functionType.ArgumentLabels(), + DocString: docString, + } +} + func NewUnmeteredPublicConstantFieldMember( containerType Type, identifier string, diff --git a/runtime/sema/void_type.go b/runtime/sema/void_type.go index a35ab56d9d..4ebe233b58 100644 --- a/runtime/sema/void_type.go +++ b/runtime/sema/void_type.go @@ -23,7 +23,7 @@ var VoidType = &SimpleType{ Name: "Void", QualifiedName: "Void", TypeID: "Void", - tag: VoidTypeTag, + TypeTag: VoidTypeTag, IsResource: false, Storable: false, Equatable: true, diff --git a/runtime/stdlib/bls.gen.go b/runtime/stdlib/bls.gen.go index e88a5939fa..cde94eb341 100644 --- a/runtime/stdlib/bls.gen.go +++ b/runtime/stdlib/bls.gen.go @@ -35,7 +35,7 @@ var BLSTypeAggregateSignaturesFunctionType = &sema.FunctionType{ Identifier: "signatures", TypeAnnotation: sema.NewTypeAnnotation(&sema.VariableSizedType{ Type: &sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }, }), }, @@ -43,7 +43,7 @@ var BLSTypeAggregateSignaturesFunctionType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation( &sema.OptionalType{ Type: &sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }, }, ), @@ -69,13 +69,13 @@ var BLSTypeAggregatePublicKeysFunctionType = &sema.FunctionType{ Label: sema.ArgumentLabelNotRequired, Identifier: "keys", TypeAnnotation: sema.NewTypeAnnotation(&sema.VariableSizedType{ - Type: PublicKeyType, + Type: sema.PublicKeyType, }), }, }, ReturnTypeAnnotation: sema.NewTypeAnnotation( &sema.OptionalType{ - Type: PublicKeyType, + Type: sema.PublicKeyType, }, ), } diff --git a/runtime/stdlib/builtin.go b/runtime/stdlib/builtin.go index d462a5f83d..d292eb1bef 100644 --- a/runtime/stdlib/builtin.go +++ b/runtime/stdlib/builtin.go @@ -18,10 +18,6 @@ package stdlib -import "github.com/onflow/cadence/runtime/sema" - -var UInt8Type = sema.UInt8Type - type StandardLibraryHandler interface { Logger UnsafeRandomGenerator diff --git a/runtime/stdlib/flow.go b/runtime/stdlib/flow.go index f34cfd633a..47451caf56 100644 --- a/runtime/stdlib/flow.go +++ b/runtime/stdlib/flow.go @@ -193,7 +193,7 @@ var AccountEventCodeHashParameter = sema.Parameter{ var AccountEventPublicKeyParameterAsCompositeType = sema.Parameter{ Identifier: "publicKey", TypeAnnotation: sema.NewTypeAnnotation( - PublicKeyType, + sema.PublicKeyType, ), } diff --git a/runtime/stdlib/publickey.go b/runtime/stdlib/publickey.go index 5b02f4250d..ef27bebc3a 100644 --- a/runtime/stdlib/publickey.go +++ b/runtime/stdlib/publickey.go @@ -25,8 +25,6 @@ import ( "github.com/onflow/cadence/runtime/sema" ) -var PublicKeyType = sema.PublicKeyType - const publicKeyConstructorFunctionDocString = ` Constructs a new public key ` @@ -260,7 +258,7 @@ func newPublicKeyVerifySignatureFunction( inter.ExpectType( publicKeyValue, - PublicKeyType, + sema.PublicKeyType, locationRange, ) @@ -330,7 +328,7 @@ func newPublicKeyVerifyPoPFunction( inter.ExpectType( publicKeyValue, - PublicKeyType, + sema.PublicKeyType, locationRange, ) diff --git a/runtime/stdlib/rlp.gen.go b/runtime/stdlib/rlp.gen.go index 44aac52a78..1fdf0f7895 100644 --- a/runtime/stdlib/rlp.gen.go +++ b/runtime/stdlib/rlp.gen.go @@ -34,13 +34,13 @@ var RLPTypeDecodeStringFunctionType = &sema.FunctionType{ Label: sema.ArgumentLabelNotRequired, Identifier: "input", TypeAnnotation: sema.NewTypeAnnotation(&sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }), }, }, ReturnTypeAnnotation: sema.NewTypeAnnotation( &sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }, ), } @@ -61,14 +61,14 @@ var RLPTypeDecodeListFunctionType = &sema.FunctionType{ Label: sema.ArgumentLabelNotRequired, Identifier: "input", TypeAnnotation: sema.NewTypeAnnotation(&sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }), }, }, ReturnTypeAnnotation: sema.NewTypeAnnotation( &sema.VariableSizedType{ Type: &sema.VariableSizedType{ - Type: UInt8Type, + Type: sema.UInt8Type, }, }, ), From 58bf115c0ac83dc6a8ed596395405ce68e0e0026 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 22 Sep 2023 12:27:04 +0300 Subject: [PATCH 13/47] Replace panic with nil return in newInjectedCompositeFieldsHandler --- runtime/environment.go | 2 +- runtime/tests/interpreter/interpreter_test.go | 79 +++++++++++-------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/runtime/environment.go b/runtime/environment.go index 32a5f8b024..70dd083ed6 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -827,7 +827,7 @@ func (e *interpreterEnvironment) newInjectedCompositeFieldsHandler() interpreter case common.AddressLocation: address = location.Address default: - panic(errors.NewUnreachableError()) + return nil } addressValue := interpreter.NewAddressValue( diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index ebc35eab09..92dbf988a8 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -25,6 +25,7 @@ import ( "strings" "testing" + "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/runtime/activations" "github.com/onflow/atree" @@ -8603,42 +8604,58 @@ func TestInterpretContractAccountFieldUse(t *testing.T) { pub let address2 = Test.test() ` - addressValue := interpreter.AddressValue{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - } + t.Run("with custom handler", func(t *testing.T) { + addressValue := interpreter.AddressValue{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + } - inter, err := parseCheckAndInterpretWithOptions(t, code, - ParseCheckAndInterpretOptions{ - Config: &interpreter.Config{ - ContractValueHandler: makeContractValueHandler(nil, nil, nil), - InjectedCompositeFieldsHandler: func( - inter *interpreter.Interpreter, - _ common.Location, - _ string, - _ common.CompositeKind, - ) map[string]interpreter.Value { - return map[string]interpreter.Value{ - "account": newTestAuthAccountValue(inter, addressValue), - } + inter, err := parseCheckAndInterpretWithOptions(t, code, + ParseCheckAndInterpretOptions{ + Config: &interpreter.Config{ + ContractValueHandler: makeContractValueHandler(nil, nil, nil), + InjectedCompositeFieldsHandler: func( + inter *interpreter.Interpreter, + _ common.Location, + _ string, + _ common.CompositeKind, + ) map[string]interpreter.Value { + return map[string]interpreter.Value{ + "account": newTestAuthAccountValue(inter, addressValue), + } + }, }, }, - }, - ) - require.NoError(t, err) + ) + require.NoError(t, err) - AssertValuesEqual( - t, - inter, - addressValue, - inter.Globals.Get("address1").GetValue(), - ) + AssertValuesEqual( + t, + inter, + addressValue, + inter.Globals.Get("address1").GetValue(), + ) - AssertValuesEqual( - t, - inter, - addressValue, - inter.Globals.Get("address2").GetValue(), - ) + AssertValuesEqual( + t, + inter, + addressValue, + inter.Globals.Get("address2").GetValue(), + ) + }) + + t.Run("with default handler", func(t *testing.T) { + env := runtime.NewBaseInterpreterEnvironment(runtime.Config{}) + _, err := parseCheckAndInterpretWithOptions(t, code, + ParseCheckAndInterpretOptions{ + Config: &interpreter.Config{ + ContractValueHandler: makeContractValueHandler(nil, nil, nil), + InjectedCompositeFieldsHandler: env.InterpreterConfig.InjectedCompositeFieldsHandler, + }, + }, + ) + require.Error(t, err) + assert.ErrorContains(t, err, "error: member `account` is used before it has been initialized") + }) } func TestInterpretConformToImportedInterface(t *testing.T) { From 1e04b7af1c098a3deff37931ef33191644606a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 22 Sep 2023 10:04:59 -0700 Subject: [PATCH 14/47] initializer has no access modifier, but access to constructor is public --- runtime/sema/gen/main.go | 2 +- runtime/sema/gen/testdata/contract/test.golden.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/sema/gen/main.go b/runtime/sema/gen/main.go index 9238aec01c..b7778b0a97 100644 --- a/runtime/sema/gen/main.go +++ b/runtime/sema/gen/main.go @@ -1856,7 +1856,7 @@ func newDeclarationMember( if access == ast.AccessNotSpecified { switch declaration.DeclarationKind() { case common.DeclarationKindInitializer: - break + access = ast.AccessAll default: panic(fmt.Errorf( diff --git a/runtime/sema/gen/testdata/contract/test.golden.go b/runtime/sema/gen/testdata/contract/test.golden.go index 57a2fca534..1efdaeff66 100644 --- a/runtime/sema/gen/testdata/contract/test.golden.go +++ b/runtime/sema/gen/testdata/contract/test.golden.go @@ -81,7 +81,7 @@ func init() { var members = []*sema.Member{ sema.NewUnmeteredConstructorMember( TestType, - sema.PrimitiveAccess(ast.AccessNotSpecified), + sema.PrimitiveAccess(ast.AccessAll), Test_FooTypeName, Test_FooTypeConstructorType, Test_FooTypeConstructorDocString, From e7a7725aab0f4686611bb61dc965eabb6902b6e1 Mon Sep 17 00:00:00 2001 From: darkdrag00n Date: Sun, 24 Sep 2023 20:26:46 +0530 Subject: [PATCH 15/47] Remove unnecessary transfer call --- runtime/interpreter/value.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index b53445b696..e1a60855df 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -1429,26 +1429,14 @@ func (v *StringValue) Split(inter *Interpreter, locationRange LocationRange, sep } str := split[index] - strValue := NewStringValue( + index++ + return NewStringValue( inter, common.NewStringMemoryUsage(len(str)), func() string { return str }, ) - - index++ - - value := strValue.Transfer( - inter, - locationRange, - atree.Address{}, - true, - nil, - nil, - ) - - return value }, ) } From 3dadaa9029296aefccc0f4b80437cd345452fefc Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Thu, 14 Sep 2023 14:57:44 +0300 Subject: [PATCH 16/47] Refine API of the testing framework These changes will allow testing providers to unify unit & integration tests. --- runtime/stdlib/contracts/test.cdc | 19 +- runtime/stdlib/test-framework.go | 5 +- runtime/stdlib/test_contract.go | 48 ++++ runtime/stdlib/test_emulatorbackend.go | 77 +++++- runtime/stdlib/test_test.go | 340 ++++++++++++++++++++----- 5 files changed, 399 insertions(+), 90 deletions(-) diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index b6041f7b9e..458e138db7 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -27,6 +27,12 @@ pub contract Test { return self.backend.createAccount() } + /// Returns the account for the given address. + /// + pub fun getAccount(_ address: Address): Account { + return self.backend.getAccount(address) + } + /// Add a transaction to the current block. /// pub fun addTransaction(_ tx: Transaction) { @@ -77,14 +83,12 @@ pub contract Test { /// pub fun deployContract( name: String, - code: String, - account: Account, + path: String, arguments: [AnyStruct] ): Error? { return self.backend.deployContract( name: name, - code: code, - account: account, + path: path, arguments: arguments ) } @@ -297,6 +301,10 @@ pub contract Test { /// pub fun createAccount(): Account + /// Returns the account for the given address. + /// + pub fun getAccount(_ address: Address): Account + /// Add a transaction to the current block. /// pub fun addTransaction(_ tx: Transaction) @@ -315,8 +323,7 @@ pub contract Test { /// pub fun deployContract( name: String, - code: String, - account: Account, + path: String, arguments: [AnyStruct] ): Error? diff --git a/runtime/stdlib/test-framework.go b/runtime/stdlib/test-framework.go index 3e8d0523c2..facb02145c 100644 --- a/runtime/stdlib/test-framework.go +++ b/runtime/stdlib/test-framework.go @@ -43,6 +43,8 @@ type Blockchain interface { CreateAccount() (*Account, error) + GetAccount(interpreter.AddressValue) (*Account, error) + AddTransaction( inter *interpreter.Interpreter, code string, @@ -58,8 +60,7 @@ type Blockchain interface { DeployContract( inter *interpreter.Interpreter, name string, - code string, - account *Account, + path string, arguments []interpreter.Value, ) error diff --git a/runtime/stdlib/test_contract.go b/runtime/stdlib/test_contract.go index 2f3baf41e4..f4faa2b7c0 100644 --- a/runtime/stdlib/test_contract.go +++ b/runtime/stdlib/test_contract.go @@ -48,6 +48,14 @@ type TestContractType struct { expectFailureFunction interpreter.FunctionValue } +// 'Test.blockchain' public field + +const testTypeBlockchainFieldName = "blockchain" + +const testTypeBlockchainFieldDocString = ` +An emulator-backed blockchain. +` + // 'Test.assert' function const testTypeAssertFunctionDocString = ` @@ -1072,6 +1080,16 @@ func newTestContractType() *TestContractType { blockchainType := ty.blockchainType() + compositeType.Fields = []string{testTypeBlockchainFieldName} + blockchainField := sema.NewPublicConstantFieldMember( + nil, + compositeType, + testTypeBlockchainFieldName, + blockchainType, + testTypeBlockchainFieldDocString, + ) + compositeType.Members.Set(testTypeBlockchainFieldName, blockchainField) + // Test.assert() compositeType.Members.Set( testTypeAssertFunctionName, @@ -1368,5 +1386,35 @@ func (t *TestContractType) NewTestContract( compositeValue.Functions[testTypeBeLessThanFunctionName] = t.beLessThanFunction compositeValue.Functions[testExpectFailureFunctionName] = t.expectFailureFunction + // Create an `EmulatorBackend` + emulatorBackend := t.emulatorBackendType.newEmulatorBackend( + inter, + testFramework.NewEmulatorBackend(), + interpreter.EmptyLocationRange, + ) + + // Create a 'Blockchain' struct value, that wraps the emulator backend, + // by calling the constructor of 'Blockchain'. + blockchainConstructor := getNestedTypeConstructorValue( + compositeValue, + testBlockchainTypeName, + ) + blockchain, err := inter.InvokeExternally( + blockchainConstructor, + blockchainConstructor.Type, + []interpreter.Value{ + emulatorBackend, + }, + ) + if err != nil { + return nil, err + } + compositeValue.SetMember( + inter, + interpreter.EmptyLocationRange, + testTypeBlockchainFieldName, + blockchain, + ) + return compositeValue, nil } diff --git a/runtime/stdlib/test_emulatorbackend.go b/runtime/stdlib/test_emulatorbackend.go index aca8706e56..876e6c6858 100644 --- a/runtime/stdlib/test_emulatorbackend.go +++ b/runtime/stdlib/test_emulatorbackend.go @@ -20,6 +20,8 @@ package stdlib import ( + "fmt" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/errors" "github.com/onflow/cadence/runtime/interpreter" @@ -49,6 +51,7 @@ type testEmulatorBackendType struct { moveTimeFunctionType *sema.FunctionType createSnapshotFunctionType *sema.FunctionType loadSnapshotFunctionType *sema.FunctionType + getAccountFunctionType *sema.FunctionType } func newTestEmulatorBackendType( @@ -124,6 +127,11 @@ func newTestEmulatorBackendType( testEmulatorBackendTypeLoadSnapshotFunctionName, ) + getAccountFunctionType := interfaceFunctionType( + blockchainBackendInterfaceType, + testEmulatorBackendTypeGetAccountFunctionName, + ) + compositeType := &sema.CompositeType{ Identifier: testEmulatorBackendTypeName, Kind: common.CompositeKindStructure, @@ -218,6 +226,12 @@ func newTestEmulatorBackendType( loadSnapshotFunctionType, testEmulatorBackendTypeLoadSnapshotFunctionDocString, ), + sema.NewUnmeteredPublicFunctionMember( + compositeType, + testEmulatorBackendTypeGetAccountFunctionName, + getAccountFunctionType, + testEmulatorBackendTypeGetAccountFunctionDocString, + ), } compositeType.Members = sema.MembersAsMap(members) @@ -239,6 +253,7 @@ func newTestEmulatorBackendType( moveTimeFunctionType: moveTimeFunctionType, createSnapshotFunctionType: createSnapshotFunctionType, loadSnapshotFunctionType: loadSnapshotFunctionType, + getAccountFunctionType: getAccountFunctionType, } } @@ -348,6 +363,47 @@ func newTestAccountValue( return accountValue } +// 'EmulatorBackend.getAccount' function + +const testEmulatorBackendTypeGetAccountFunctionName = "getAccount" + +const testEmulatorBackendTypeGetAccountFunctionDocString = ` +Returns the account for the given address. +` + +func (t *testEmulatorBackendType) newGetAccountFunction( + blockchain Blockchain, +) *interpreter.HostFunctionValue { + return interpreter.NewUnmeteredHostFunctionValue( + t.getAccountFunctionType, + func(invocation interpreter.Invocation) interpreter.Value { + address, ok := invocation.Arguments[0].(interpreter.AddressValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + account, err := blockchain.GetAccount(address) + if err != nil { + msg := fmt.Sprintf("account with address: %s was not found", address) + panic(PanicError{ + Message: msg, + LocationRange: invocation.LocationRange, + }) + } + + inter := invocation.Interpreter + locationRange := invocation.LocationRange + + return newTestAccountValue( + blockchain, + inter, + locationRange, + account, + ) + }, + ) +} + // 'EmulatorBackend.addTransaction' function const testEmulatorBackendTypeAddTransactionFunctionName = "addTransaction" @@ -509,22 +565,14 @@ func (t *testEmulatorBackendType) newDeployContractFunction( panic(errors.NewUnreachableError()) } - // Contract code - code, ok := invocation.Arguments[1].(*interpreter.StringValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - // authorizer - accountValue, ok := invocation.Arguments[2].(interpreter.MemberAccessibleValue) + // Contract file path + path, ok := invocation.Arguments[1].(*interpreter.StringValue) if !ok { panic(errors.NewUnreachableError()) } - account := accountFromValue(inter, accountValue, invocation.LocationRange) - // Contract init arguments - args, err := arrayValueToSlice(inter, invocation.Arguments[3]) + args, err := arrayValueToSlice(inter, invocation.Arguments[2]) if err != nil { panic(err) } @@ -532,8 +580,7 @@ func (t *testEmulatorBackendType) newDeployContractFunction( err = blockchain.DeployContract( inter, name.Str, - code.Str, - account, + path.Str, args, ) @@ -878,6 +925,10 @@ func (t *testEmulatorBackendType) newEmulatorBackend( Name: testEmulatorBackendTypeLoadSnapshotFunctionName, Value: t.newLoadSnapshotFunction(blockchain), }, + { + Name: testEmulatorBackendTypeGetAccountFunctionName, + Value: t.newGetAccountFunction(blockchain), + }, } // TODO: Use SimpleCompositeValue diff --git a/runtime/stdlib/test_test.go b/runtime/stdlib/test_test.go index beaa3a2f68..17a3eb95bd 100644 --- a/runtime/stdlib/test_test.go +++ b/runtime/stdlib/test_test.go @@ -16,7 +16,8 @@ * limitations under the License. */ -package stdlib +// This is in order to avoid cyclic import errors with runtime package +package stdlib_test import ( "errors" @@ -26,6 +27,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/runtime/activations" "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" @@ -33,18 +35,24 @@ import ( "github.com/onflow/cadence/runtime/interpreter" "github.com/onflow/cadence/runtime/parser" "github.com/onflow/cadence/runtime/sema" + "github.com/onflow/cadence/runtime/stdlib" "github.com/onflow/cadence/runtime/tests/checker" "github.com/onflow/cadence/runtime/tests/utils" ) func newTestContractInterpreter(t *testing.T, code string) (*interpreter.Interpreter, error) { - return newTestContractInterpreterWithTestFramework(t, code, nil) + testFramework := &mockedTestFramework{ + newEmulatorBackend: func() stdlib.Blockchain { + return &mockedBlockchain{} + }, + } + return newTestContractInterpreterWithTestFramework(t, code, testFramework) } func newTestContractInterpreterWithTestFramework( t *testing.T, code string, - testFramework TestFramework, + testFramework stdlib.TestFramework, ) (*interpreter.Interpreter, error) { program, err := parser.ParseProgram( nil, @@ -54,8 +62,8 @@ func newTestContractInterpreterWithTestFramework( require.NoError(t, err) activation := sema.NewVariableActivation(sema.BaseValueActivation) - activation.DeclareValue(AssertFunction) - activation.DeclareValue(PanicFunction) + activation.DeclareValue(stdlib.AssertFunction) + activation.DeclareValue(stdlib.PanicFunction) checker, err := sema.NewChecker( program, @@ -72,15 +80,15 @@ func newTestContractInterpreterWithTestFramework( sema.Import, error, ) { - if importedLocation == TestContractLocation { + if importedLocation == stdlib.TestContractLocation { return sema.ElaborationImport{ - Elaboration: GetTestContractType().Checker.Elaboration, + Elaboration: stdlib.GetTestContractType().Checker.Elaboration, }, nil } return nil, errors.New("invalid import") }, - ContractValueHandler: TestCheckerContractValueHandler, + ContractValueHandler: stdlib.TestCheckerContractValueHandler, }, ) require.NoError(t, err) @@ -90,13 +98,13 @@ func newTestContractInterpreterWithTestFramework( return nil, err } - storage := newUnmeteredInMemoryStorage() + storage := interpreter.NewInMemoryStorage(nil) var uuid uint64 = 0 baseActivation := activations.NewActivation(nil, interpreter.BaseActivation) - interpreter.Declare(baseActivation, AssertFunction) - interpreter.Declare(baseActivation, PanicFunction) + interpreter.Declare(baseActivation, stdlib.AssertFunction) + interpreter.Declare(baseActivation, stdlib.PanicFunction) inter, err := interpreter.NewInterpreter( interpreter.ProgramFromChecker(checker), @@ -105,8 +113,8 @@ func newTestContractInterpreterWithTestFramework( Storage: storage, BaseActivation: baseActivation, ImportLocationHandler: func(inter *interpreter.Interpreter, location common.Location) interpreter.Import { - if location == TestContractLocation { - program := interpreter.ProgramFromChecker(GetTestContractType().Checker) + if location == stdlib.TestContractLocation { + program := interpreter.ProgramFromChecker(stdlib.GetTestContractType().Checker) subInterpreter, err := inter.NewSubInterpreter(program, location) if err != nil { panic(err) @@ -118,7 +126,7 @@ func newTestContractInterpreterWithTestFramework( return nil }, - ContractValueHandler: NewTestInterpreterContractValueHandler(testFramework), + ContractValueHandler: stdlib.NewTestInterpreterContractValueHandler(testFramework), UUIDHandler: func() (uint64, error) { uuid++ return uuid, nil @@ -690,7 +698,7 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("test") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, @@ -714,7 +722,7 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("test") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, @@ -749,7 +757,7 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("testNotEqual") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, @@ -792,7 +800,7 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("testNotEqual") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, @@ -827,7 +835,7 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("testNotEqual") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, @@ -862,11 +870,11 @@ func TestAssertEqual(t *testing.T) { _, err = inter.Invoke("testNotEqual") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) assert.ErrorContains( t, err, - "not equal: expected: {2: false, 1: true}, actual: {2: true, 1: true}", + "not equal: expected: {2: false, 1: true}, actual: {1: true, 2: true}", ) }) @@ -1721,7 +1729,7 @@ func TestTestExpect(t *testing.T) { _, err = inter.Invoke("test") require.Error(t, err) - assertionErr := &AssertionError{} + assertionErr := &stdlib.AssertionError{} assert.ErrorAs(t, err, assertionErr) assert.Equal(t, "given value is: \"this string\"", assertionErr.Message) assert.Equal(t, "test", assertionErr.LocationRange.Location.String()) @@ -1744,7 +1752,7 @@ func TestTestExpect(t *testing.T) { _, err = inter.Invoke("test") require.Error(t, err) - assert.ErrorAs(t, err, &AssertionError{}) + assert.ErrorAs(t, err, &stdlib.AssertionError{}) }) t.Run("with explicit types", func(t *testing.T) { @@ -2053,7 +2061,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain let events = blockchain.events() Test.expect(events, Test.beEmpty()) @@ -2063,7 +2071,7 @@ func TestBlockchain(t *testing.T) { eventsInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ events: func(inter *interpreter.Interpreter, eventType interpreter.StaticType) interpreter.Value { eventsInvoked = true @@ -2097,7 +2105,7 @@ func TestBlockchain(t *testing.T) { pub struct Foo {} pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain // 'Foo' is not an event-type. // But we just need to test the API, so it doesn't really matter. @@ -2112,7 +2120,7 @@ func TestBlockchain(t *testing.T) { eventsInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ events: func(inter *interpreter.Interpreter, eventType interpreter.StaticType) interpreter.Value { eventsInvoked = true @@ -2149,7 +2157,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.reset(to: 5) } ` @@ -2157,7 +2165,7 @@ func TestBlockchain(t *testing.T) { resetInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ reset: func(height uint64) { resetInvoked = true @@ -2183,7 +2191,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.reset(to: 5.5) } ` @@ -2191,7 +2199,7 @@ func TestBlockchain(t *testing.T) { resetInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ reset: func(height uint64) { resetInvoked = true @@ -2213,7 +2221,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveForward() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain // timeDelta is the representation of 35 days, // in the form of seconds. let timeDelta = Fix64(35 * 24 * 60 * 60) @@ -2224,7 +2232,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2250,7 +2258,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveBackward() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain // timeDelta is the representation of 35 days, // in the form of seconds. let timeDelta = Fix64(35 * 24 * 60 * 60) * -1.0 @@ -2261,7 +2269,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2287,7 +2295,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveTime() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.moveTime(by: 3000) } ` @@ -2295,7 +2303,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2310,14 +2318,14 @@ func TestBlockchain(t *testing.T) { assert.False(t, moveTimeInvoked) }) - t.Run("newEmulatorBackend", func(t *testing.T) { + t.Run("blockchain", func(t *testing.T) { t.Parallel() const script = ` import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain Test.assertEqual(Type(), blockchain.getType()) } ` @@ -2325,7 +2333,7 @@ func TestBlockchain(t *testing.T) { newEmulatorBackendInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { newEmulatorBackendInvoked = true return &mockedBlockchain{} }, @@ -2347,7 +2355,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.createSnapshot(name: "adminCreated") } ` @@ -2355,7 +2363,7 @@ func TestBlockchain(t *testing.T) { createSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { createSnapshotInvoked = true @@ -2383,7 +2391,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.createSnapshot(name: "adminCreated") } ` @@ -2391,7 +2399,7 @@ func TestBlockchain(t *testing.T) { createSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { createSnapshotInvoked = true @@ -2419,7 +2427,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.createSnapshot(name: "adminCreated") blockchain.loadSnapshot(name: "adminCreated") } @@ -2428,7 +2436,7 @@ func TestBlockchain(t *testing.T) { loadSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { assert.Equal(t, "adminCreated", name) @@ -2461,7 +2469,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.newEmulatorBlockchain() + let blockchain = Test.blockchain blockchain.createSnapshot(name: "adminCreated") blockchain.loadSnapshot(name: "contractDeployed") } @@ -2470,7 +2478,7 @@ func TestBlockchain(t *testing.T) { loadSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() Blockchain { + newEmulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { assert.Equal(t, "adminCreated", name) @@ -2496,17 +2504,203 @@ func TestBlockchain(t *testing.T) { assert.True(t, loadSnapshotInvoked) }) + t.Run("deployContract", func(t *testing.T) { + t.Parallel() + + const script = ` + import Test + + pub fun test() { + let blockchain = Test.blockchain + let err = blockchain.deployContract( + name: "FooContract", + path: "./contracts/FooContract.cdc", + arguments: ["Hey, there!"] + ) + + Test.expect(err, Test.beNil()) + } + ` + + deployContractInvoked := false + + testFramework := &mockedTestFramework{ + newEmulatorBackend: func() stdlib.Blockchain { + return &mockedBlockchain{ + deployContract: func( + inter *interpreter.Interpreter, + name string, + path string, + arguments []interpreter.Value, + ) error { + deployContractInvoked = true + assert.Equal(t, "FooContract", name) + assert.Equal(t, "./contracts/FooContract.cdc", path) + assert.Equal(t, 1, len(arguments)) + argument := arguments[0].(*interpreter.StringValue) + assert.Equal(t, "Hey, there!", argument.Str) + + return nil + }, + } + }, + } + + inter, err := newTestContractInterpreterWithTestFramework(t, script, testFramework) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.NoError(t, err) + + assert.True(t, deployContractInvoked) + }) + + t.Run("deployContract with failure", func(t *testing.T) { + t.Parallel() + + const script = ` + import Test + + pub fun test() { + let blockchain = Test.blockchain + let err = blockchain.deployContract( + name: "FooContract", + path: "./contracts/FooContract.cdc", + arguments: ["Hey, there!"] + ) + + Test.assertEqual( + "failed to deploy contract: FooContract", + err!.message + ) + } + ` + + deployContractInvoked := false + + testFramework := &mockedTestFramework{ + newEmulatorBackend: func() stdlib.Blockchain { + return &mockedBlockchain{ + deployContract: func( + inter *interpreter.Interpreter, + name string, + path string, + arguments []interpreter.Value, + ) error { + deployContractInvoked = true + + return fmt.Errorf("failed to deploy contract: %s", name) + }, + } + }, + } + + inter, err := newTestContractInterpreterWithTestFramework(t, script, testFramework) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.NoError(t, err) + + assert.True(t, deployContractInvoked) + }) + + t.Run("getAccount", func(t *testing.T) { + t.Parallel() + + const script = ` + import Test + + pub fun test() { + let blockchain = Test.blockchain + let account = blockchain.getAccount(0x0000000000000009) + } + ` + + getAccountInvoked := false + + testFramework := &mockedTestFramework{ + newEmulatorBackend: func() stdlib.Blockchain { + return &mockedBlockchain{ + getAccount: func(address interpreter.AddressValue) (*stdlib.Account, error) { + getAccountInvoked = true + assert.Equal(t, "0000000000000009", address.Hex()) + addr := common.Address(address) + + return &stdlib.Account{ + Address: addr, + PublicKey: &stdlib.PublicKey{ + PublicKey: []byte{1, 2, 3}, + SignAlgo: sema.SignatureAlgorithmECDSA_P256, + }, + }, nil + }, + stdlibHandler: func() stdlib.StandardLibraryHandler { + return runtime.NewBaseInterpreterEnvironment(runtime.Config{}) + }, + } + }, + } + + inter, err := newTestContractInterpreterWithTestFramework(t, script, testFramework) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.NoError(t, err) + + assert.True(t, getAccountInvoked) + }) + + t.Run("getAccount with failure", func(t *testing.T) { + t.Parallel() + + const script = ` + import Test + + pub fun test() { + let blockchain = Test.blockchain + let account = blockchain.getAccount(0x0000000000000009) + } + ` + + getAccountInvoked := false + + testFramework := &mockedTestFramework{ + newEmulatorBackend: func() stdlib.Blockchain { + return &mockedBlockchain{ + getAccount: func(address interpreter.AddressValue) (*stdlib.Account, error) { + getAccountInvoked = true + assert.Equal(t, "0000000000000009", address.Hex()) + + return nil, fmt.Errorf("failed to retrieve account with address: %s", address) + }, + stdlibHandler: func() stdlib.StandardLibraryHandler { + return runtime.NewBaseInterpreterEnvironment(runtime.Config{}) + }, + } + }, + } + + inter, err := newTestContractInterpreterWithTestFramework(t, script, testFramework) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.Error(t, err) + assert.ErrorContains(t, err, "account with address: 0x0000000000000009 was not found") + + assert.True(t, getAccountInvoked) + }) + // TODO: Add more tests for the remaining functions. } type mockedTestFramework struct { - newEmulatorBackend func() Blockchain + newEmulatorBackend func() stdlib.Blockchain readFile func(s string) (string, error) } -var _ TestFramework = &mockedTestFramework{} +var _ stdlib.TestFramework = &mockedTestFramework{} -func (m mockedTestFramework) NewEmulatorBackend() Blockchain { +func (m mockedTestFramework) NewEmulatorBackend() stdlib.Blockchain { if m.newEmulatorBackend == nil { panic("'NewEmulatorBackend' is not implemented") } @@ -2524,15 +2718,16 @@ func (m mockedTestFramework) ReadFile(fileName string) (string, error) { type mockedBlockchain struct { runScript func(inter *interpreter.Interpreter, code string, arguments []interpreter.Value) - createAccount func() (*Account, error) - addTransaction func(inter *interpreter.Interpreter, code string, authorizers []common.Address, signers []*Account, arguments []interpreter.Value) error - executeTransaction func() *TransactionResult + createAccount func() (*stdlib.Account, error) + getAccount func(interpreter.AddressValue) (*stdlib.Account, error) + addTransaction func(inter *interpreter.Interpreter, code string, authorizers []common.Address, signers []*stdlib.Account, arguments []interpreter.Value) error + executeTransaction func() *stdlib.TransactionResult commitBlock func() error - deployContract func(inter *interpreter.Interpreter, name string, code string, account *Account, arguments []interpreter.Value) error - useConfiguration func(configuration *Configuration) - stdlibHandler func() StandardLibraryHandler + deployContract func(inter *interpreter.Interpreter, name string, path string, arguments []interpreter.Value) error + useConfiguration func(configuration *stdlib.Configuration) + stdlibHandler func() stdlib.StandardLibraryHandler logs func() []string - serviceAccount func() (*Account, error) + serviceAccount func() (*stdlib.Account, error) events func(inter *interpreter.Interpreter, eventType interpreter.StaticType) interpreter.Value reset func(uint64) moveTime func(int64) @@ -2540,13 +2735,13 @@ type mockedBlockchain struct { loadSnapshot func(string) error } -var _ Blockchain = &mockedBlockchain{} +var _ stdlib.Blockchain = &mockedBlockchain{} func (m mockedBlockchain) RunScript( inter *interpreter.Interpreter, code string, arguments []interpreter.Value, -) *ScriptResult { +) *stdlib.ScriptResult { if m.runScript == nil { panic("'RunScript' is not implemented") } @@ -2554,7 +2749,7 @@ func (m mockedBlockchain) RunScript( return m.RunScript(inter, code, arguments) } -func (m mockedBlockchain) CreateAccount() (*Account, error) { +func (m mockedBlockchain) CreateAccount() (*stdlib.Account, error) { if m.createAccount == nil { panic("'CreateAccount' is not implemented") } @@ -2562,11 +2757,19 @@ func (m mockedBlockchain) CreateAccount() (*Account, error) { return m.createAccount() } +func (m mockedBlockchain) GetAccount(address interpreter.AddressValue) (*stdlib.Account, error) { + if m.getAccount == nil { + panic("'getAccount' is not implemented") + } + + return m.getAccount(address) +} + func (m mockedBlockchain) AddTransaction( inter *interpreter.Interpreter, code string, authorizers []common.Address, - signers []*Account, + signers []*stdlib.Account, arguments []interpreter.Value, ) error { if m.addTransaction == nil { @@ -2576,7 +2779,7 @@ func (m mockedBlockchain) AddTransaction( return m.addTransaction(inter, code, authorizers, signers, arguments) } -func (m mockedBlockchain) ExecuteNextTransaction() *TransactionResult { +func (m mockedBlockchain) ExecuteNextTransaction() *stdlib.TransactionResult { if m.executeTransaction == nil { panic("'ExecuteNextTransaction' is not implemented") } @@ -2595,18 +2798,17 @@ func (m mockedBlockchain) CommitBlock() error { func (m mockedBlockchain) DeployContract( inter *interpreter.Interpreter, name string, - code string, - account *Account, + path string, arguments []interpreter.Value, ) error { if m.deployContract == nil { panic("'DeployContract' is not implemented") } - return m.deployContract(inter, name, code, account, arguments) + return m.deployContract(inter, name, path, arguments) } -func (m mockedBlockchain) UseConfiguration(configuration *Configuration) { +func (m mockedBlockchain) UseConfiguration(configuration *stdlib.Configuration) { if m.useConfiguration == nil { panic("'UseConfiguration' is not implemented") } @@ -2614,7 +2816,7 @@ func (m mockedBlockchain) UseConfiguration(configuration *Configuration) { m.useConfiguration(configuration) } -func (m mockedBlockchain) StandardLibraryHandler() StandardLibraryHandler { +func (m mockedBlockchain) StandardLibraryHandler() stdlib.StandardLibraryHandler { if m.stdlibHandler == nil { panic("'StandardLibraryHandler' is not implemented") } @@ -2630,7 +2832,7 @@ func (m mockedBlockchain) Logs() []string { return m.logs() } -func (m mockedBlockchain) ServiceAccount() (*Account, error) { +func (m mockedBlockchain) ServiceAccount() (*stdlib.Account, error) { if m.serviceAccount == nil { panic("'ServiceAccount' is not implemented") } From 24d9c4bca06d59a16bf1b0cdef2d87a3ca01e21f Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 15 Sep 2023 14:54:35 +0300 Subject: [PATCH 17/47] Remove entirely the 'Test.Blockchain' struct --- runtime/stdlib/contracts/test.cdc | 263 +++++++++++++++--------------- runtime/stdlib/test_contract.go | 175 +++----------------- runtime/stdlib/test_test.go | 83 +++------- 3 files changed, 168 insertions(+), 353 deletions(-) diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index 458e138db7..04fe12aa36 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -2,164 +2,161 @@ /// pub contract Test { - /// Blockchain emulates a real network. + /// backend emulates a real network. /// - pub struct Blockchain { + pub let backend: AnyStruct{BlockchainBackend} - pub let backend: AnyStruct{BlockchainBackend} + init(backend: AnyStruct{BlockchainBackend}) { + self.backend = backend + } - init(backend: AnyStruct{BlockchainBackend}) { - self.backend = backend - } + /// Executes a script and returns the script return value and the status. + /// `returnValue` field of the result will be `nil` if the script failed. + /// + pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { + return self.backend.executeScript(script, arguments) + } - /// Executes a script and returns the script return value and the status. - /// `returnValue` field of the result will be `nil` if the script failed. - /// - pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { - return self.backend.executeScript(script, arguments) - } + /// Creates a signer account by submitting an account creation transaction. + /// The transaction is paid by the service account. + /// The returned account can be used to sign and authorize transactions. + /// + pub fun createAccount(): Account { + return self.backend.createAccount() + } - /// Creates a signer account by submitting an account creation transaction. - /// The transaction is paid by the service account. - /// The returned account can be used to sign and authorize transactions. - /// - pub fun createAccount(): Account { - return self.backend.createAccount() - } + /// Returns the account for the given address. + /// + pub fun getAccount(_ address: Address): Account { + return self.backend.getAccount(address) + } - /// Returns the account for the given address. - /// - pub fun getAccount(_ address: Address): Account { - return self.backend.getAccount(address) - } + /// Add a transaction to the current block. + /// + pub fun addTransaction(_ tx: Transaction) { + self.backend.addTransaction(tx) + } - /// Add a transaction to the current block. - /// - pub fun addTransaction(_ tx: Transaction) { - self.backend.addTransaction(tx) - } + /// Executes the next transaction in the block, if any. + /// Returns the result of the transaction, or nil if no transaction was scheduled. + /// + pub fun executeNextTransaction(): TransactionResult? { + return self.backend.executeNextTransaction() + } - /// Executes the next transaction in the block, if any. - /// Returns the result of the transaction, or nil if no transaction was scheduled. - /// - pub fun executeNextTransaction(): TransactionResult? { - return self.backend.executeNextTransaction() - } + /// Commit the current block. + /// Committing will fail if there are un-executed transactions in the block. + /// + pub fun commitBlock() { + self.backend.commitBlock() + } - /// Commit the current block. - /// Committing will fail if there are un-executed transactions in the block. - /// - pub fun commitBlock() { - self.backend.commitBlock() - } + /// Executes a given transaction and commit the current block. + /// + pub fun executeTransaction(_ tx: Transaction): TransactionResult { + self.addTransaction(tx) + let txResult = self.executeNextTransaction()! + self.commitBlock() + return txResult + } - /// Executes a given transaction and commit the current block. - /// - pub fun executeTransaction(_ tx: Transaction): TransactionResult { + /// Executes a given set of transactions and commit the current block. + /// + pub fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { + for tx in transactions { self.addTransaction(tx) - let txResult = self.executeNextTransaction()! - self.commitBlock() - return txResult } - /// Executes a given set of transactions and commit the current block. - /// - pub fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { - for tx in transactions { - self.addTransaction(tx) - } - - var results: [TransactionResult] = [] - for tx in transactions { - let txResult = self.executeNextTransaction()! - results.append(txResult) - } - - self.commitBlock() - return results + var results: [TransactionResult] = [] + for tx in transactions { + let txResult = self.executeNextTransaction()! + results.append(txResult) } - /// Deploys a given contract, and initilizes it with the arguments. - /// - pub fun deployContract( - name: String, - path: String, - arguments: [AnyStruct] - ): Error? { - return self.backend.deployContract( - name: name, - path: path, - arguments: arguments - ) - } + self.commitBlock() + return results + } - /// Set the configuration to be used by the blockchain. - /// Overrides any existing configuration. - /// - pub fun useConfiguration(_ configuration: Configuration) { - self.backend.useConfiguration(configuration) - } + /// Deploys a given contract, and initilizes it with the arguments. + /// + pub fun deployContract( + name: String, + path: String, + arguments: [AnyStruct] + ): Error? { + return self.backend.deployContract( + name: name, + path: path, + arguments: arguments + ) + } - /// Returns all the logs from the blockchain, up to the calling point. - /// - pub fun logs(): [String] { - return self.backend.logs() - } + /// Set the configuration to be used by the blockchain. + /// Overrides any existing configuration. + /// + pub fun useConfiguration(_ configuration: Configuration) { + self.backend.useConfiguration(configuration) + } - /// Returns the service account of the blockchain. Can be used to sign - /// transactions with this account. - /// - pub fun serviceAccount(): Account { - return self.backend.serviceAccount() - } + /// Returns all the logs from the blockchain, up to the calling point. + /// + pub fun logs(): [String] { + return self.backend.logs() + } - /// Returns all events emitted from the blockchain. - /// - pub fun events(): [AnyStruct] { - return self.backend.events(nil) - } + /// Returns the service account of the blockchain. Can be used to sign + /// transactions with this account. + /// + pub fun serviceAccount(): Account { + return self.backend.serviceAccount() + } - /// Returns all events emitted from the blockchain, - /// filtered by type. - /// - pub fun eventsOfType(_ type: Type): [AnyStruct] { - return self.backend.events(type) - } + /// Returns all events emitted from the blockchain. + /// + pub fun events(): [AnyStruct] { + return self.backend.events(nil) + } - /// Resets the state of the blockchain to the given height. - /// - pub fun reset(to height: UInt64) { - self.backend.reset(to: height) - } + /// Returns all events emitted from the blockchain, + /// filtered by type. + /// + pub fun eventsOfType(_ type: Type): [AnyStruct] { + return self.backend.events(type) + } - /// Moves the time of the blockchain by the given delta, - /// which should be passed in the form of seconds. - /// - pub fun moveTime(by delta: Fix64) { - self.backend.moveTime(by: delta) - } + /// Resets the state of the blockchain to the given height. + /// + pub fun reset(to height: UInt64) { + self.backend.reset(to: height) + } - /// Creates a snapshot of the blockchain, at the - /// current ledger state, with the given name. - /// - access(all) - fun createSnapshot(name: String) { - let err = self.backend.createSnapshot(name: name) - if err != nil { - panic(err!.message) - } + /// Moves the time of the blockchain by the given delta, + /// which should be passed in the form of seconds. + /// + pub fun moveTime(by delta: Fix64) { + self.backend.moveTime(by: delta) + } + + /// Creates a snapshot of the blockchain, at the + /// current ledger state, with the given name. + /// + access(all) + fun createSnapshot(name: String) { + let err = self.backend.createSnapshot(name: name) + if err != nil { + panic(err!.message) } + } - /// Loads a snapshot of the blockchain, with the - /// given name, and updates the current ledger - /// state. - /// - access(all) - fun loadSnapshot(name: String) { - let err = self.backend.loadSnapshot(name: name) - if err != nil { - panic(err!.message) - } + /// Loads a snapshot of the blockchain, with the + /// given name, and updates the current ledger + /// state. + /// + access(all) + fun loadSnapshot(name: String) { + let err = self.backend.loadSnapshot(name: name) + if err != nil { + panic(err!.message) } } diff --git a/runtime/stdlib/test_contract.go b/runtime/stdlib/test_contract.go index f4faa2b7c0..0cd3db214c 100644 --- a/runtime/stdlib/test_contract.go +++ b/runtime/stdlib/test_contract.go @@ -32,30 +32,21 @@ import ( ) type TestContractType struct { - Checker *sema.Checker - CompositeType *sema.CompositeType - InitializerTypes []sema.Type - emulatorBackendType *testEmulatorBackendType - newEmulatorBlockchainFunctionType *sema.FunctionType - expectFunction interpreter.FunctionValue - newMatcherFunction interpreter.FunctionValue - haveElementCountFunction interpreter.FunctionValue - beEmptyFunction interpreter.FunctionValue - equalFunction interpreter.FunctionValue - beGreaterThanFunction interpreter.FunctionValue - containFunction interpreter.FunctionValue - beLessThanFunction interpreter.FunctionValue - expectFailureFunction interpreter.FunctionValue + Checker *sema.Checker + CompositeType *sema.CompositeType + InitializerTypes []sema.Type + emulatorBackendType *testEmulatorBackendType + expectFunction interpreter.FunctionValue + newMatcherFunction interpreter.FunctionValue + haveElementCountFunction interpreter.FunctionValue + beEmptyFunction interpreter.FunctionValue + equalFunction interpreter.FunctionValue + beGreaterThanFunction interpreter.FunctionValue + containFunction interpreter.FunctionValue + beLessThanFunction interpreter.FunctionValue + expectFailureFunction interpreter.FunctionValue } -// 'Test.blockchain' public field - -const testTypeBlockchainFieldName = "blockchain" - -const testTypeBlockchainFieldDocString = ` -An emulator-backed blockchain. -` - // 'Test.assert' function const testTypeAssertFunctionDocString = ` @@ -388,65 +379,6 @@ func newTestTypeReadFileFunction(testFramework TestFramework) *interpreter.HostF ) } -// 'Test.newEmulatorBlockchain' function - -const testTypeNewEmulatorBlockchainFunctionDocString = ` -Creates a blockchain which is backed by a new emulator instance. -` - -const testTypeNewEmulatorBlockchainFunctionName = "newEmulatorBlockchain" - -const testBlockchainTypeName = "Blockchain" - -func newTestTypeNewEmulatorBlockchainFunctionType(blockchainType *sema.CompositeType) *sema.FunctionType { - return &sema.FunctionType{ - ReturnTypeAnnotation: sema.NewTypeAnnotation( - blockchainType, - ), - } -} - -func (t *TestContractType) newNewEmulatorBlockchainFunction( - testFramework TestFramework, -) *interpreter.HostFunctionValue { - return interpreter.NewUnmeteredHostFunctionValue( - t.newEmulatorBlockchainFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - inter := invocation.Interpreter - locationRange := invocation.LocationRange - - // Create an `EmulatorBackend` - emulatorBackend := t.emulatorBackendType.newEmulatorBackend( - inter, - testFramework.NewEmulatorBackend(), - locationRange, - ) - - // Create a 'Blockchain' struct value, that wraps the emulator backend, - // by calling the constructor of 'Blockchain'. - - blockchainConstructor := getNestedTypeConstructorValue( - *invocation.Self, - testBlockchainTypeName, - ) - - blockchain, err := inter.InvokeExternally( - blockchainConstructor, - blockchainConstructor.Type, - []interpreter.Value{ - emulatorBackend, - }, - ) - - if err != nil { - panic(err) - } - - return blockchain - }, - ) -} - // 'Test.NewMatcher' function. // Constructs a matcher that test only 'AnyStruct'. // Accepts test function that accepts subtype of 'AnyStruct'. @@ -1078,18 +1010,6 @@ func newTestContractType() *TestContractType { matcherType := ty.matcherType() matcherTestFunctionType := compositeFunctionType(matcherType, matcherTestFunctionName) - blockchainType := ty.blockchainType() - - compositeType.Fields = []string{testTypeBlockchainFieldName} - blockchainField := sema.NewPublicConstantFieldMember( - nil, - compositeType, - testTypeBlockchainFieldName, - blockchainType, - testTypeBlockchainFieldDocString, - ) - compositeType.Members.Set(testTypeBlockchainFieldName, blockchainField) - // Test.assert() compositeType.Members.Set( testTypeAssertFunctionName, @@ -1123,19 +1043,6 @@ func newTestContractType() *TestContractType { ), ) - // Test.newEmulatorBlockchain() - newEmulatorBlockchainFunctionType := newTestTypeNewEmulatorBlockchainFunctionType(blockchainType) - compositeType.Members.Set( - testTypeNewEmulatorBlockchainFunctionName, - sema.NewUnmeteredPublicFunctionMember( - compositeType, - testTypeNewEmulatorBlockchainFunctionName, - newEmulatorBlockchainFunctionType, - testTypeNewEmulatorBlockchainFunctionDocString, - ), - ) - ty.newEmulatorBlockchainFunctionType = newEmulatorBlockchainFunctionType - // Test.readFile() compositeType.Members.Set( testTypeReadFileFunctionName, @@ -1326,23 +1233,6 @@ func (t *TestContractType) matcherType() *sema.CompositeType { return matcherType } -func (t *TestContractType) blockchainType() *sema.CompositeType { - typ, ok := t.CompositeType.NestedTypes.Get(testBlockchainTypeName) - if !ok { - panic(typeNotFoundError(testContractTypeName, testBlockchainTypeName)) - } - - matcherType, ok := typ.(*sema.CompositeType) - if !ok || matcherType.Kind != common.CompositeKindStructure { - panic(errors.NewUnexpectedError( - "invalid type for '%s'. expected struct type", - testMatcherTypeName, - )) - } - - return matcherType -} - func (t *TestContractType) NewTestContract( inter *interpreter.Interpreter, testFramework TestFramework, @@ -1353,9 +1243,14 @@ func (t *TestContractType) NewTestContract( error, ) { initializerTypes := t.InitializerTypes + emulatorBackend := t.emulatorBackendType.newEmulatorBackend( + inter, + testFramework.NewEmulatorBackend(), + interpreter.EmptyLocationRange, + ) value, err := inter.InvokeFunctionValue( constructor, - nil, + []interpreter.Value{emulatorBackend}, initializerTypes, initializerTypes, invocationRange, @@ -1371,8 +1266,6 @@ func (t *TestContractType) NewTestContract( compositeValue.Functions[testTypeAssertEqualFunctionName] = testTypeAssertEqualFunction compositeValue.Functions[testTypeFailFunctionName] = testTypeFailFunction compositeValue.Functions[testTypeExpectFunctionName] = t.expectFunction - compositeValue.Functions[testTypeNewEmulatorBlockchainFunctionName] = - t.newNewEmulatorBlockchainFunction(testFramework) compositeValue.Functions[testTypeReadFileFunctionName] = newTestTypeReadFileFunction(testFramework) @@ -1386,35 +1279,5 @@ func (t *TestContractType) NewTestContract( compositeValue.Functions[testTypeBeLessThanFunctionName] = t.beLessThanFunction compositeValue.Functions[testExpectFailureFunctionName] = t.expectFailureFunction - // Create an `EmulatorBackend` - emulatorBackend := t.emulatorBackendType.newEmulatorBackend( - inter, - testFramework.NewEmulatorBackend(), - interpreter.EmptyLocationRange, - ) - - // Create a 'Blockchain' struct value, that wraps the emulator backend, - // by calling the constructor of 'Blockchain'. - blockchainConstructor := getNestedTypeConstructorValue( - compositeValue, - testBlockchainTypeName, - ) - blockchain, err := inter.InvokeExternally( - blockchainConstructor, - blockchainConstructor.Type, - []interpreter.Value{ - emulatorBackend, - }, - ) - if err != nil { - return nil, err - } - compositeValue.SetMember( - inter, - interpreter.EmptyLocationRange, - testTypeBlockchainFieldName, - blockchain, - ) - return compositeValue, nil } diff --git a/runtime/stdlib/test_test.go b/runtime/stdlib/test_test.go index 17a3eb95bd..a47bfbea94 100644 --- a/runtime/stdlib/test_test.go +++ b/runtime/stdlib/test_test.go @@ -874,7 +874,7 @@ func TestAssertEqual(t *testing.T) { assert.ErrorContains( t, err, - "not equal: expected: {2: false, 1: true}, actual: {1: true, 2: true}", + "not equal: expected: {1: true, 2: false}, actual: {2: true, 1: true}", ) }) @@ -2061,8 +2061,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - let events = blockchain.events() + let events = Test.events() Test.expect(events, Test.beEmpty()) } @@ -2105,13 +2104,11 @@ func TestBlockchain(t *testing.T) { pub struct Foo {} pub fun test() { - let blockchain = Test.blockchain - // 'Foo' is not an event-type. // But we just need to test the API, so it doesn't really matter. let typ = Type() - let events = blockchain.eventsOfType(typ) + let events = Test.eventsOfType(typ) Test.expect(events, Test.beEmpty()) } @@ -2157,8 +2154,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.reset(to: 5) + Test.reset(to: 5) } ` @@ -2191,8 +2187,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.reset(to: 5.5) + Test.reset(to: 5.5) } ` @@ -2221,11 +2216,10 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveForward() { - let blockchain = Test.blockchain // timeDelta is the representation of 35 days, // in the form of seconds. let timeDelta = Fix64(35 * 24 * 60 * 60) - blockchain.moveTime(by: timeDelta) + Test.moveTime(by: timeDelta) } ` @@ -2258,11 +2252,10 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveBackward() { - let blockchain = Test.blockchain // timeDelta is the representation of 35 days, // in the form of seconds. let timeDelta = Fix64(35 * 24 * 60 * 60) * -1.0 - blockchain.moveTime(by: timeDelta) + Test.moveTime(by: timeDelta) } ` @@ -2295,8 +2288,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun testMoveTime() { - let blockchain = Test.blockchain - blockchain.moveTime(by: 3000) + Test.moveTime(by: 3000) } ` @@ -2318,36 +2310,6 @@ func TestBlockchain(t *testing.T) { assert.False(t, moveTimeInvoked) }) - t.Run("blockchain", func(t *testing.T) { - t.Parallel() - - const script = ` - import Test - - pub fun test() { - let blockchain = Test.blockchain - Test.assertEqual(Type(), blockchain.getType()) - } - ` - - newEmulatorBackendInvoked := false - - testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { - newEmulatorBackendInvoked = true - return &mockedBlockchain{} - }, - } - - inter, err := newTestContractInterpreterWithTestFramework(t, script, testFramework) - require.NoError(t, err) - - _, err = inter.Invoke("test") - require.NoError(t, err) - - assert.True(t, newEmulatorBackendInvoked) - }) - t.Run("createSnapshot", func(t *testing.T) { t.Parallel() @@ -2355,8 +2317,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.createSnapshot(name: "adminCreated") + Test.createSnapshot(name: "adminCreated") } ` @@ -2391,8 +2352,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.createSnapshot(name: "adminCreated") + Test.createSnapshot(name: "adminCreated") } ` @@ -2427,9 +2387,8 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.createSnapshot(name: "adminCreated") - blockchain.loadSnapshot(name: "adminCreated") + Test.createSnapshot(name: "adminCreated") + Test.loadSnapshot(name: "adminCreated") } ` @@ -2469,9 +2428,8 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - blockchain.createSnapshot(name: "adminCreated") - blockchain.loadSnapshot(name: "contractDeployed") + Test.createSnapshot(name: "adminCreated") + Test.loadSnapshot(name: "contractDeployed") } ` @@ -2511,8 +2469,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - let err = blockchain.deployContract( + let err = Test.deployContract( name: "FooContract", path: "./contracts/FooContract.cdc", arguments: ["Hey, there!"] @@ -2562,8 +2519,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - let err = blockchain.deployContract( + let err = Test.deployContract( name: "FooContract", path: "./contracts/FooContract.cdc", arguments: ["Hey, there!"] @@ -2611,8 +2567,8 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - let account = blockchain.getAccount(0x0000000000000009) + let account = Test.getAccount(0x0000000000000009) + Test.assertEqual(0x0000000000000009 as Address, account.address) } ` @@ -2657,8 +2613,7 @@ func TestBlockchain(t *testing.T) { import Test pub fun test() { - let blockchain = Test.blockchain - let account = blockchain.getAccount(0x0000000000000009) + let account = Test.getAccount(0x0000000000000009) } ` From d39fa9eb8b1edecba066ea4c8d51a5768cc846a3 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 15 Sep 2023 16:16:01 +0300 Subject: [PATCH 18/47] Caching of initializeMemberResolvers seems to cause a bug For contracts that contain both a .cdc source file, with Cadence code, and with some functions being implemented natively, the GetMembers() does not return the natively implemented members. --- runtime/sema/type.go | 14 ++++++++++++-- runtime/stdlib/test_contract.go | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 9e2ab8b422..821b8550b4 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4262,7 +4262,11 @@ func (t *CompositeType) GetMembers() map[string]MemberResolver { } func (t *CompositeType) initializeMemberResolvers() { - t.memberResolversOnce.Do(func() { + t.memberResolversOnce.Do(t.initializerMemberResolversFunc()) +} + +func (t *CompositeType) initializerMemberResolversFunc() func() { + return func() { memberResolvers := MembersMapAsResolvers(t.Members) // Check conformances. @@ -4281,7 +4285,13 @@ func (t *CompositeType) initializeMemberResolvers() { }) t.memberResolvers = withBuiltinMembers(t, memberResolvers) - }) + } +} + +func (t *CompositeType) ResolveMembers() { + if t.Members.Len() != len(t.GetMembers()) { + t.initializerMemberResolversFunc()() + } } func (t *CompositeType) FieldPosition(name string, declaration ast.CompositeLikeDeclaration) ast.Position { diff --git a/runtime/stdlib/test_contract.go b/runtime/stdlib/test_contract.go index 0cd3db214c..36cb2980df 100644 --- a/runtime/stdlib/test_contract.go +++ b/runtime/stdlib/test_contract.go @@ -1193,6 +1193,7 @@ func newTestContractType() *TestContractType { ty.expectFailureFunction = newTestTypeExpectFailureFunction( expectFailureFunctionType, ) + compositeType.ResolveMembers() return ty } From b1b8bdd207de5d5f4d33119591589dcc4ca7200a Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Tue, 19 Sep 2023 12:02:49 +0300 Subject: [PATCH 19/47] Remove entirely the 'Test.useConfiguration' function --- runtime/stdlib/contracts/test.cdc | 12 ---- runtime/stdlib/test-framework.go | 6 -- runtime/stdlib/test.go | 2 - runtime/stdlib/test_emulatorbackend.go | 76 -------------------------- runtime/stdlib/test_test.go | 9 --- 5 files changed, 105 deletions(-) diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index 04fe12aa36..1f9972fb1e 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -91,13 +91,6 @@ pub contract Test { ) } - /// Set the configuration to be used by the blockchain. - /// Overrides any existing configuration. - /// - pub fun useConfiguration(_ configuration: Configuration) { - self.backend.useConfiguration(configuration) - } - /// Returns all the logs from the blockchain, up to the calling point. /// pub fun logs(): [String] { @@ -324,11 +317,6 @@ pub contract Test { arguments: [AnyStruct] ): Error? - /// Set the configuration to be used by the blockchain. - /// Overrides any existing configuration. - /// - pub fun useConfiguration(_ configuration: Configuration) - /// Returns all the logs from the blockchain, up to the calling point. /// pub fun logs(): [String] diff --git a/runtime/stdlib/test-framework.go b/runtime/stdlib/test-framework.go index facb02145c..c8b68cedc1 100644 --- a/runtime/stdlib/test-framework.go +++ b/runtime/stdlib/test-framework.go @@ -64,8 +64,6 @@ type Blockchain interface { arguments []interpreter.Value, ) error - UseConfiguration(configuration *Configuration) - StandardLibraryHandler() StandardLibraryHandler Logs() []string @@ -99,7 +97,3 @@ type Account struct { PublicKey *PublicKey Address common.Address } - -type Configuration struct { - Addresses map[string]common.Address -} diff --git a/runtime/stdlib/test.go b/runtime/stdlib/test.go index db3b08ff59..f4866afc23 100644 --- a/runtime/stdlib/test.go +++ b/runtime/stdlib/test.go @@ -48,8 +48,6 @@ const accountAddressFieldName = "address" const matcherTestFunctionName = "test" -const addressesFieldName = "addresses" - const TestContractLocation = common.IdentifierLocation(testContractTypeName) var testOnce sync.Once diff --git a/runtime/stdlib/test_emulatorbackend.go b/runtime/stdlib/test_emulatorbackend.go index 876e6c6858..1e087139ea 100644 --- a/runtime/stdlib/test_emulatorbackend.go +++ b/runtime/stdlib/test_emulatorbackend.go @@ -43,7 +43,6 @@ type testEmulatorBackendType struct { executeNextTransactionFunctionType *sema.FunctionType commitBlockFunctionType *sema.FunctionType deployContractFunctionType *sema.FunctionType - useConfigFunctionType *sema.FunctionType logsFunctionType *sema.FunctionType serviceAccountFunctionType *sema.FunctionType eventsFunctionType *sema.FunctionType @@ -87,11 +86,6 @@ func newTestEmulatorBackendType( testEmulatorBackendTypeDeployContractFunctionName, ) - useConfigFunctionType := interfaceFunctionType( - blockchainBackendInterfaceType, - testEmulatorBackendTypeUseConfigFunctionName, - ) - logsFunctionType := interfaceFunctionType( blockchainBackendInterfaceType, testEmulatorBackendTypeLogsFunctionName, @@ -178,12 +172,6 @@ func newTestEmulatorBackendType( deployContractFunctionType, testEmulatorBackendTypeDeployContractFunctionDocString, ), - sema.NewUnmeteredPublicFunctionMember( - compositeType, - testEmulatorBackendTypeUseConfigFunctionName, - useConfigFunctionType, - testEmulatorBackendTypeUseConfigFunctionDocString, - ), sema.NewUnmeteredPublicFunctionMember( compositeType, testEmulatorBackendTypeLogsFunctionName, @@ -245,7 +233,6 @@ func newTestEmulatorBackendType( executeNextTransactionFunctionType: executeNextTransactionFunctionType, commitBlockFunctionType: commitBlockFunctionType, deployContractFunctionType: deployContractFunctionType, - useConfigFunctionType: useConfigFunctionType, logsFunctionType: logsFunctionType, serviceAccountFunctionType: serviceAccountFunctionType, eventsFunctionType: eventsFunctionType, @@ -589,65 +576,6 @@ func (t *testEmulatorBackendType) newDeployContractFunction( ) } -// 'EmulatorBackend.useConfiguration' function - -const testEmulatorBackendTypeUseConfigFunctionName = "useConfiguration" - -const testEmulatorBackendTypeUseConfigFunctionDocString = ` -Set the configuration to be used by the blockchain. -Overrides any existing configuration. -` - -func (t *testEmulatorBackendType) newUseConfigFunction( - blockchain Blockchain, -) *interpreter.HostFunctionValue { - return interpreter.NewUnmeteredHostFunctionValue( - t.useConfigFunctionType, - func(invocation interpreter.Invocation) interpreter.Value { - inter := invocation.Interpreter - - // configurations - configsValue, ok := invocation.Arguments[0].(*interpreter.CompositeValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - addresses, ok := configsValue.GetMember( - inter, - invocation.LocationRange, - addressesFieldName, - ).(*interpreter.DictionaryValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - mapping := make(map[string]common.Address, addresses.Count()) - - addresses.Iterate(inter, func(locationValue, addressValue interpreter.Value) bool { - location, ok := locationValue.(*interpreter.StringValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - address, ok := addressValue.(interpreter.AddressValue) - if !ok { - panic(errors.NewUnreachableError()) - } - - mapping[location.Str] = common.Address(address) - - return true - }) - - blockchain.UseConfiguration(&Configuration{ - Addresses: mapping, - }) - - return interpreter.Void - }, - ) -} - // 'EmulatorBackend.logs' function const testEmulatorBackendTypeLogsFunctionName = "logs" @@ -893,10 +821,6 @@ func (t *testEmulatorBackendType) newEmulatorBackend( Name: testEmulatorBackendTypeDeployContractFunctionName, Value: t.newDeployContractFunction(blockchain), }, - { - Name: testEmulatorBackendTypeUseConfigFunctionName, - Value: t.newUseConfigFunction(blockchain), - }, { Name: testEmulatorBackendTypeLogsFunctionName, Value: t.newLogsFunction(blockchain), diff --git a/runtime/stdlib/test_test.go b/runtime/stdlib/test_test.go index a47bfbea94..734c3a66d7 100644 --- a/runtime/stdlib/test_test.go +++ b/runtime/stdlib/test_test.go @@ -2679,7 +2679,6 @@ type mockedBlockchain struct { executeTransaction func() *stdlib.TransactionResult commitBlock func() error deployContract func(inter *interpreter.Interpreter, name string, path string, arguments []interpreter.Value) error - useConfiguration func(configuration *stdlib.Configuration) stdlibHandler func() stdlib.StandardLibraryHandler logs func() []string serviceAccount func() (*stdlib.Account, error) @@ -2763,14 +2762,6 @@ func (m mockedBlockchain) DeployContract( return m.deployContract(inter, name, path, arguments) } -func (m mockedBlockchain) UseConfiguration(configuration *stdlib.Configuration) { - if m.useConfiguration == nil { - panic("'UseConfiguration' is not implemented") - } - - m.useConfiguration(configuration) -} - func (m mockedBlockchain) StandardLibraryHandler() stdlib.StandardLibraryHandler { if m.stdlibHandler == nil { panic("'StandardLibraryHandler' is not implemented") From 34f6ebea1c4e89e48a9ade63e4722cbbe6bbb2f3 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Fri, 22 Sep 2023 12:20:55 +0300 Subject: [PATCH 20/47] Remove left-over Test.Configuration struct --- runtime/stdlib/contracts/test.cdc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index 1f9972fb1e..b2e6ba9698 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -249,17 +249,6 @@ pub contract Test { } } - /// Configuration to be used by the blockchain. - /// Can be used to set the address mappings. - /// - pub struct Configuration { - pub let addresses: {String: Address} - - init(addresses: {String: Address}) { - self.addresses = addresses - } - } - /// Transaction that can be submitted and executed on the blockchain. /// pub struct Transaction { From 72bbfe1e5d4a5ed438762cfe05a6c7b1c1f731ef Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Mon, 25 Sep 2023 12:42:56 +0300 Subject: [PATCH 21/47] Use new access modifiers in Test contract --- runtime/stdlib/contracts/test.cdc | 160 ++++++++++++++++++------------ 1 file changed, 97 insertions(+), 63 deletions(-) diff --git a/runtime/stdlib/contracts/test.cdc b/runtime/stdlib/contracts/test.cdc index b2e6ba9698..8e7a39da7d 100644 --- a/runtime/stdlib/contracts/test.cdc +++ b/runtime/stdlib/contracts/test.cdc @@ -1,10 +1,10 @@ /// Test contract is the standard library that provides testing functionality in Cadence. /// -pub contract Test { +access(all) contract Test { /// backend emulates a real network. /// - pub let backend: AnyStruct{BlockchainBackend} + access(self) let backend: AnyStruct{BlockchainBackend} init(backend: AnyStruct{BlockchainBackend}) { self.backend = backend @@ -13,7 +13,8 @@ pub contract Test { /// Executes a script and returns the script return value and the status. /// `returnValue` field of the result will be `nil` if the script failed. /// - pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { + access(all) + fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult { return self.backend.executeScript(script, arguments) } @@ -21,39 +22,45 @@ pub contract Test { /// The transaction is paid by the service account. /// The returned account can be used to sign and authorize transactions. /// - pub fun createAccount(): Account { + access(all) + fun createAccount(): Account { return self.backend.createAccount() } /// Returns the account for the given address. /// - pub fun getAccount(_ address: Address): Account { + access(all) + fun getAccount(_ address: Address): Account { return self.backend.getAccount(address) } /// Add a transaction to the current block. /// - pub fun addTransaction(_ tx: Transaction) { + access(all) + fun addTransaction(_ tx: Transaction) { self.backend.addTransaction(tx) } /// Executes the next transaction in the block, if any. /// Returns the result of the transaction, or nil if no transaction was scheduled. /// - pub fun executeNextTransaction(): TransactionResult? { + access(all) + fun executeNextTransaction(): TransactionResult? { return self.backend.executeNextTransaction() } /// Commit the current block. /// Committing will fail if there are un-executed transactions in the block. /// - pub fun commitBlock() { + access(all) + fun commitBlock() { self.backend.commitBlock() } /// Executes a given transaction and commit the current block. /// - pub fun executeTransaction(_ tx: Transaction): TransactionResult { + access(all) + fun executeTransaction(_ tx: Transaction): TransactionResult { self.addTransaction(tx) let txResult = self.executeNextTransaction()! self.commitBlock() @@ -62,7 +69,8 @@ pub contract Test { /// Executes a given set of transactions and commit the current block. /// - pub fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { + access(all) + fun executeTransactions(_ transactions: [Transaction]): [TransactionResult] { for tx in transactions { self.addTransaction(tx) } @@ -79,7 +87,8 @@ pub contract Test { /// Deploys a given contract, and initilizes it with the arguments. /// - pub fun deployContract( + access(all) + fun deployContract( name: String, path: String, arguments: [AnyStruct] @@ -93,40 +102,46 @@ pub contract Test { /// Returns all the logs from the blockchain, up to the calling point. /// - pub fun logs(): [String] { + access(all) + fun logs(): [String] { return self.backend.logs() } /// Returns the service account of the blockchain. Can be used to sign /// transactions with this account. /// - pub fun serviceAccount(): Account { + access(all) + fun serviceAccount(): Account { return self.backend.serviceAccount() } /// Returns all events emitted from the blockchain. /// - pub fun events(): [AnyStruct] { + access(all) + fun events(): [AnyStruct] { return self.backend.events(nil) } /// Returns all events emitted from the blockchain, /// filtered by type. /// - pub fun eventsOfType(_ type: Type): [AnyStruct] { + access(all) + fun eventsOfType(_ type: Type): [AnyStruct] { return self.backend.events(type) } /// Resets the state of the blockchain to the given height. /// - pub fun reset(to height: UInt64) { + access(all) + fun reset(to height: UInt64) { self.backend.reset(to: height) } /// Moves the time of the blockchain by the given delta, /// which should be passed in the form of seconds. /// - pub fun moveTime(by delta: Fix64) { + access(all) + fun moveTime(by delta: Fix64) { self.backend.moveTime(by: delta) } @@ -153,18 +168,19 @@ pub contract Test { } } - pub struct Matcher { + access(all) struct Matcher { - pub let test: ((AnyStruct): Bool) + access(all) let test: ((AnyStruct): Bool) - pub init(test: ((AnyStruct): Bool)) { + init(test: ((AnyStruct): Bool)) { self.test = test } /// Combine this matcher with the given matcher. /// Returns a new matcher that succeeds if this and the given matcher succeed. /// - pub fun and(_ other: Matcher): Matcher { + access(all) + fun and(_ other: Matcher): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return self.test(value) && other.test(value) }) @@ -174,7 +190,8 @@ pub contract Test { /// Returns a new matcher that succeeds if this or the given matcher succeed. /// If this matcher succeeds, then the other matcher would not be tested. /// - pub fun or(_ other: Matcher): Matcher { + access(all) + fun or(_ other: Matcher): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return self.test(value) || other.test(value) }) @@ -183,29 +200,29 @@ pub contract Test { /// ResultStatus indicates status of a transaction or script execution. /// - pub enum ResultStatus: UInt8 { - pub case succeeded - pub case failed + access(all) enum ResultStatus: UInt8 { + access(all) case succeeded + access(all) case failed } /// Result is the interface to be implemented by the various execution /// operations, such as transactions and scripts. /// - pub struct interface Result { + access(all) struct interface Result { /// The result status of an executed operation. /// - pub let status: ResultStatus + access(all) let status: ResultStatus /// The optional error of an executed operation. /// - pub let error: Error? + access(all) let error: Error? } /// The result of a transaction execution. /// - pub struct TransactionResult: Result { - pub let status: ResultStatus - pub let error: Error? + access(all) struct TransactionResult: Result { + access(all) let status: ResultStatus + access(all) let error: Error? init(status: ResultStatus, error: Error?) { self.status = status @@ -215,10 +232,10 @@ pub contract Test { /// The result of a script execution. /// - pub struct ScriptResult: Result { - pub let status: ResultStatus - pub let returnValue: AnyStruct? - pub let error: Error? + access(all) struct ScriptResult: Result { + access(all) let status: ResultStatus + access(all) let returnValue: AnyStruct? + access(all) let error: Error? init(status: ResultStatus, returnValue: AnyStruct?, error: Error?) { self.status = status @@ -229,8 +246,8 @@ pub contract Test { // Error is returned if something has gone wrong. // - pub struct Error { - pub let message: String + access(all) struct Error { + access(all) let message: String init(_ message: String) { self.message = message @@ -239,9 +256,9 @@ pub contract Test { /// Account represents info about the account created on the blockchain. /// - pub struct Account { - pub let address: Address - pub let publicKey: PublicKey + access(all) struct Account { + access(all) let address: Address + access(all) let publicKey: PublicKey init(address: Address, publicKey: PublicKey) { self.address = address @@ -251,11 +268,11 @@ pub contract Test { /// Transaction that can be submitted and executed on the blockchain. /// - pub struct Transaction { - pub let code: String - pub let authorizers: [Address] - pub let signers: [Account] - pub let arguments: [AnyStruct] + access(all) struct Transaction { + access(all) let code: String + access(all) let authorizers: [Address] + access(all) let signers: [Account] + access(all) let arguments: [AnyStruct] init(code: String, authorizers: [Address], signers: [Account], arguments: [AnyStruct]) { self.code = code @@ -267,40 +284,47 @@ pub contract Test { /// BlockchainBackend is the interface to be implemented by the backend providers. /// - pub struct interface BlockchainBackend { + access(all) struct interface BlockchainBackend { /// Executes a script and returns the script return value and the status. /// `returnValue` field of the result will be `nil` if the script failed. /// - pub fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult + access(all) + fun executeScript(_ script: String, _ arguments: [AnyStruct]): ScriptResult /// Creates a signer account by submitting an account creation transaction. /// The transaction is paid by the service account. /// The returned account can be used to sign and authorize transactions. /// - pub fun createAccount(): Account + access(all) + fun createAccount(): Account /// Returns the account for the given address. /// - pub fun getAccount(_ address: Address): Account + access(all) + fun getAccount(_ address: Address): Account /// Add a transaction to the current block. /// - pub fun addTransaction(_ tx: Transaction) + access(all) + fun addTransaction(_ tx: Transaction) /// Executes the next transaction in the block, if any. /// Returns the result of the transaction, or nil if no transaction was scheduled. /// - pub fun executeNextTransaction(): TransactionResult? + access(all) + fun executeNextTransaction(): TransactionResult? /// Commit the current block. /// Committing will fail if there are un-executed transactions in the block. /// - pub fun commitBlock() + access(all) + fun commitBlock() /// Deploys a given contract, and initilizes it with the arguments. /// - pub fun deployContract( + access(all) + fun deployContract( name: String, path: String, arguments: [AnyStruct] @@ -308,26 +332,31 @@ pub contract Test { /// Returns all the logs from the blockchain, up to the calling point. /// - pub fun logs(): [String] + access(all) + fun logs(): [String] /// Returns the service account of the blockchain. Can be used to sign /// transactions with this account. /// - pub fun serviceAccount(): Account + access(all) + fun serviceAccount(): Account /// Returns all events emitted from the blockchain, optionally filtered /// by type. /// - pub fun events(_ type: Type?): [AnyStruct] + access(all) + fun events(_ type: Type?): [AnyStruct] /// Resets the state of the blockchain to the given height. /// - pub fun reset(to height: UInt64) + access(all) + fun reset(to height: UInt64) /// Moves the time of the blockchain by the given delta, /// which should be passed in the form of seconds. /// - pub fun moveTime(by delta: Fix64) + access(all) + fun moveTime(by delta: Fix64) /// Creates a snapshot of the blockchain, at the /// current ledger state, with the given name. @@ -345,7 +374,8 @@ pub contract Test { /// Returns a new matcher that negates the test of the given matcher. /// - pub fun not(_ matcher: Matcher): Matcher { + access(all) + fun not(_ matcher: Matcher): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return !matcher.test(value) }) @@ -355,7 +385,8 @@ pub contract Test { /// a ScriptResult or TransactionResult and the ResultStatus is succeeded. /// Returns false in any other case. /// - pub fun beSucceeded(): Matcher { + access(all) + fun beSucceeded(): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return (value as! {Result}).status == ResultStatus.succeeded }) @@ -365,7 +396,8 @@ pub contract Test { /// a ScriptResult or TransactionResult and the ResultStatus is failed. /// Returns false in any other case. /// - pub fun beFailed(): Matcher { + access(all) + fun beFailed(): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return (value as! {Result}).status == ResultStatus.failed }) @@ -373,7 +405,8 @@ pub contract Test { /// Returns a new matcher that checks if the given test value is nil. /// - pub fun beNil(): Matcher { + access(all) + fun beNil(): Matcher { return Matcher(test: fun (value: AnyStruct): Bool { return value == nil }) @@ -383,7 +416,8 @@ pub contract Test { /// a script or transaction, has failed and contains the given error /// message. /// - pub fun assertError(_ result: {Result}, errorMessage: String) { + access(all) + fun assertError(_ result: {Result}, errorMessage: String) { pre { result.status == ResultStatus.failed: "no error was found" } From 20a58ec3dbb9637bccb42422949a4661bda287d5 Mon Sep 17 00:00:00 2001 From: Ardit Marku Date: Mon, 25 Sep 2023 12:44:02 +0300 Subject: [PATCH 22/47] Rename TestFramework's NewEmulatorBackend function to EmulatorBackend --- runtime/stdlib/test-framework.go | 2 +- runtime/stdlib/test_contract.go | 2 +- runtime/stdlib/test_test.go | 42 ++++++++++++++++---------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/runtime/stdlib/test-framework.go b/runtime/stdlib/test-framework.go index c8b68cedc1..6496ee98fb 100644 --- a/runtime/stdlib/test-framework.go +++ b/runtime/stdlib/test-framework.go @@ -30,7 +30,7 @@ import ( // This is used as a way to inject test provider dependencies dynamically. type TestFramework interface { - NewEmulatorBackend() Blockchain + EmulatorBackend() Blockchain ReadFile(string) (string, error) } diff --git a/runtime/stdlib/test_contract.go b/runtime/stdlib/test_contract.go index 36cb2980df..3a7bcd12fb 100644 --- a/runtime/stdlib/test_contract.go +++ b/runtime/stdlib/test_contract.go @@ -1246,7 +1246,7 @@ func (t *TestContractType) NewTestContract( initializerTypes := t.InitializerTypes emulatorBackend := t.emulatorBackendType.newEmulatorBackend( inter, - testFramework.NewEmulatorBackend(), + testFramework.EmulatorBackend(), interpreter.EmptyLocationRange, ) value, err := inter.InvokeFunctionValue( diff --git a/runtime/stdlib/test_test.go b/runtime/stdlib/test_test.go index 734c3a66d7..de5545174a 100644 --- a/runtime/stdlib/test_test.go +++ b/runtime/stdlib/test_test.go @@ -42,7 +42,7 @@ import ( func newTestContractInterpreter(t *testing.T, code string) (*interpreter.Interpreter, error) { testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{} }, } @@ -2070,7 +2070,7 @@ func TestBlockchain(t *testing.T) { eventsInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ events: func(inter *interpreter.Interpreter, eventType interpreter.StaticType) interpreter.Value { eventsInvoked = true @@ -2117,7 +2117,7 @@ func TestBlockchain(t *testing.T) { eventsInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ events: func(inter *interpreter.Interpreter, eventType interpreter.StaticType) interpreter.Value { eventsInvoked = true @@ -2161,7 +2161,7 @@ func TestBlockchain(t *testing.T) { resetInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ reset: func(height uint64) { resetInvoked = true @@ -2194,7 +2194,7 @@ func TestBlockchain(t *testing.T) { resetInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ reset: func(height uint64) { resetInvoked = true @@ -2226,7 +2226,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2262,7 +2262,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2295,7 +2295,7 @@ func TestBlockchain(t *testing.T) { moveTimeInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ moveTime: func(timeDelta int64) { moveTimeInvoked = true @@ -2324,7 +2324,7 @@ func TestBlockchain(t *testing.T) { createSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { createSnapshotInvoked = true @@ -2359,7 +2359,7 @@ func TestBlockchain(t *testing.T) { createSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { createSnapshotInvoked = true @@ -2395,7 +2395,7 @@ func TestBlockchain(t *testing.T) { loadSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { assert.Equal(t, "adminCreated", name) @@ -2436,7 +2436,7 @@ func TestBlockchain(t *testing.T) { loadSnapshotInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ createSnapshot: func(name string) error { assert.Equal(t, "adminCreated", name) @@ -2482,7 +2482,7 @@ func TestBlockchain(t *testing.T) { deployContractInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ deployContract: func( inter *interpreter.Interpreter, @@ -2535,7 +2535,7 @@ func TestBlockchain(t *testing.T) { deployContractInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ deployContract: func( inter *interpreter.Interpreter, @@ -2575,7 +2575,7 @@ func TestBlockchain(t *testing.T) { getAccountInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ getAccount: func(address interpreter.AddressValue) (*stdlib.Account, error) { getAccountInvoked = true @@ -2620,7 +2620,7 @@ func TestBlockchain(t *testing.T) { getAccountInvoked := false testFramework := &mockedTestFramework{ - newEmulatorBackend: func() stdlib.Blockchain { + emulatorBackend: func() stdlib.Blockchain { return &mockedBlockchain{ getAccount: func(address interpreter.AddressValue) (*stdlib.Account, error) { getAccountInvoked = true @@ -2649,18 +2649,18 @@ func TestBlockchain(t *testing.T) { } type mockedTestFramework struct { - newEmulatorBackend func() stdlib.Blockchain - readFile func(s string) (string, error) + emulatorBackend func() stdlib.Blockchain + readFile func(s string) (string, error) } var _ stdlib.TestFramework = &mockedTestFramework{} -func (m mockedTestFramework) NewEmulatorBackend() stdlib.Blockchain { - if m.newEmulatorBackend == nil { +func (m mockedTestFramework) EmulatorBackend() stdlib.Blockchain { + if m.emulatorBackend == nil { panic("'NewEmulatorBackend' is not implemented") } - return m.newEmulatorBackend() + return m.emulatorBackend() } func (m mockedTestFramework) ReadFile(fileName string) (string, error) { From 9e8068e275f97ba97e1e5e361fa6a48bbb36fd3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Sep 2023 15:10:18 -0700 Subject: [PATCH 23/47] use kr/pretty instead of go-test/deep to prevent empty diffs --- go.mod | 17 +++++------ go.sum | 10 +++++-- runtime/tests/checker/utils.go | 13 ++++---- runtime/tests/utils/utils.go | 55 +++++++++++++++++----------------- tools/compare-parsing/main.go | 10 ++----- 5 files changed, 50 insertions(+), 55 deletions(-) diff --git a/go.mod b/go.mod index 6dfc1fb807..3a9ac1bf22 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,19 @@ go 1.20 require ( github.com/bits-and-blooms/bitset v1.5.0 + github.com/bytecodealliance/wasmtime-go/v7 v7.0.0 github.com/c-bata/go-prompt v0.2.6 + github.com/dave/dst v0.27.2 github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c - github.com/go-test/deep v1.1.0 + github.com/k0kubun/pp/v3 v3.2.0 + github.com/kr/pretty v0.3.1 github.com/leanovate/gopter v0.2.9 + github.com/logrusorgru/aurora/v4 v4.0.0 github.com/onflow/atree v0.6.0 github.com/rivo/uniseg v0.4.4 github.com/schollz/progressbar/v3 v3.13.1 github.com/stretchr/testify v1.8.2 + github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c github.com/tidwall/pretty v1.2.1 github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d go.opentelemetry.io/otel v1.14.0 @@ -23,14 +28,6 @@ require ( golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 ) -require ( - github.com/bytecodealliance/wasmtime-go/v7 v7.0.0 - github.com/dave/dst v0.27.2 - github.com/k0kubun/pp/v3 v3.2.0 - github.com/logrusorgru/aurora/v4 v4.0.0 - github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c -) - require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/circlehash v0.3.0 // indirect @@ -43,7 +40,9 @@ require ( github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/pkg/term v1.2.0-beta.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/assert v1.3.0 // indirect github.com/zeebo/blake3 v0.2.3 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.6.0 // indirect diff --git a/go.sum b/go.sum index 95f5ee6672..9dbb7f2d65 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,6 @@ github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c h1:5tm/Wbs9d9r github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/circlehash v0.3.0 h1:XKdvTtIJV9t7DDUtsf0RIpC1OcxZtPbmgIH7ekx28WA= github.com/fxamacker/circlehash v0.3.0/go.mod h1:3aq3OfVvsWtkWMb6A1owjOQFA+TLsD5FgJflnaQwtMM= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs= @@ -24,6 +22,8 @@ github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapd github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= @@ -54,6 +54,7 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/onflow/atree v0.6.0 h1:j7nQ2r8npznx4NX39zPpBYHmdy45f4xwoi+dm37Jk7c= github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVFi0tc= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -61,6 +62,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE= github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -81,8 +84,9 @@ github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d h1:5JInRQbk5UBX github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d/go.mod h1:Nlx5Y115XQvNcIdIy7dZXaNSUpzwBSge4/Ivk93/Yog= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= diff --git a/runtime/tests/checker/utils.go b/runtime/tests/checker/utils.go index d63c4a5f6d..dd20f5fe94 100644 --- a/runtime/tests/checker/utils.go +++ b/runtime/tests/checker/utils.go @@ -24,7 +24,8 @@ import ( "sync" "testing" - "github.com/go-test/deep" + gopretty "github.com/kr/pretty" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -35,10 +36,6 @@ import ( "github.com/onflow/cadence/runtime/tests/utils" ) -func init() { - deep.MaxDepth = 20 -} - func ParseAndCheck(t testing.TB, code string) (*sema.Checker, error) { return ParseAndCheckWithOptions(t, code, ParseAndCheckOptions{ // allow attachments is on by default for testing purposes @@ -159,9 +156,9 @@ func ParseAndCheckWithOptionsAndMemoryMetering( err = firstResult.err for otherResult := range results { - diff := deep.Equal(err, otherResult.err) - if diff != nil { - t.Error(diff) + diff := gopretty.Diff(err, otherResult.err) + if len(diff) > 0 { + t.Error(strings.Join(diff, "\n")) } } diff --git a/runtime/tests/utils/utils.go b/runtime/tests/utils/utils.go index 8835a83c6b..04a4476e44 100644 --- a/runtime/tests/utils/utils.go +++ b/runtime/tests/utils/utils.go @@ -24,7 +24,8 @@ import ( "strings" "testing" - "github.com/go-test/deep" + "github.com/k0kubun/pp/v3" + "github.com/kr/pretty" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -46,38 +47,36 @@ const ImportedLocation = common.StringLocation("imported") // // If the objects are not equal, this function prints a human-readable diff. func AssertEqualWithDiff(t *testing.T, expected, actual any) { - if !assert.Equal(t, expected, actual) { - // the maximum levels of a struct to recurse into - // this prevents infinite recursion from circular references - deep.MaxDepth = 100 - diff := deep.Equal(expected, actual) + // the maximum levels of a struct to recurse into + // this prevents infinite recursion from circular references + diff := pretty.Diff(expected, actual) - if len(diff) != 0 { - s := strings.Builder{} + if len(diff) != 0 { + s := strings.Builder{} - for i, d := range diff { - if i == 0 { - s.WriteString("diff : ") - } else { - s.WriteString(" ") - } - - s.WriteString(d) - s.WriteString("\n") + for i, d := range diff { + if i == 0 { + s.WriteString("diff : ") + } else { + s.WriteString(" ") } - t.Errorf( - "Not equal: \n"+ - "expected: %s\n"+ - "actual : %s\n\n"+ - "%s", - expected, - actual, - s.String(), - ) + s.WriteString(d) + s.WriteString("\n") } + + t.Errorf( + "Not equal: \n"+ + "expected: %s\n"+ + "actual : %s\n\n"+ + "%s", + pp.Sprint(expected), + pp.Sprint(actual), + s.String(), + ) } + } func AsInterfaceType(name string, kind common.CompositeKind) string { @@ -147,11 +146,11 @@ func ValuesAreEqual(inter *interpreter.Interpreter, expected, actual interpreter func AssertValuesEqual(t testing.TB, interpreter *interpreter.Interpreter, expected, actual interpreter.Value) bool { if !ValuesAreEqual(interpreter, expected, actual) { - diff := deep.Equal(expected, actual) + diff := pretty.Diff(expected, actual) var message string - if len(diff) != 0 { + if len(diff) > 0 { s := strings.Builder{} _, _ = fmt.Fprintf(&s, "Not equal: \n"+ diff --git a/tools/compare-parsing/main.go b/tools/compare-parsing/main.go index 9de50d73c7..36ea0cfab5 100644 --- a/tools/compare-parsing/main.go +++ b/tools/compare-parsing/main.go @@ -35,7 +35,7 @@ import ( "path" "strings" - "github.com/go-test/deep" + "github.com/kr/pretty" ) func main() { @@ -115,13 +115,9 @@ func compareParsing(directory string, location string, code string, parseOld str return } - // the maximum levels of a struct to recurse into - // this prevents infinite recursion from circular references - deep.MaxDepth = 100 + diff := pretty.Diff(res1, res2) - diff := deep.Equal(res1, res2) - - if len(diff) != 0 { + if len(diff) > 0 { var s strings.Builder for _, d := range diff { From 74e0b2d486eba26c7326247e41d72866910726c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 10:01:05 -0700 Subject: [PATCH 24/47] remove gocap --- .github/workflows/ci.yml | 3 --- Makefile | 6 ------ go.cap | 13 ------------- 3 files changed, 22 deletions(-) delete mode 100644 go.cap diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a5e483d72..238f823442 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,9 +73,6 @@ jobs: - name: Check license headers run: make check-headers - - name: Check capabilities of dependencies - run: make check-capabilities - lint-json: name: Lint JSON runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 327d437533..f822d9b20c 100644 --- a/Makefile +++ b/Makefile @@ -121,9 +121,3 @@ release: @(VERSIONED_FILES="version.go \ npm-packages/cadence-parser/package.json" \ bash ./bump-version.sh $(bump)) - -.PHONY: check-capabilities -check-capabilities: - go install github.com/cugu/gocap@v0.1.0 - go mod download - gocap check . diff --git a/go.cap b/go.cap deleted file mode 100644 index bb341c9fa6..0000000000 --- a/go.cap +++ /dev/null @@ -1,13 +0,0 @@ -github.com/onflow/cadence () - -github.com/davecgh/go-spew/spew (file) -github.com/klauspost/cpuid/v2 (file, runtime) -github.com/onflow/cadence/runtime/errors (runtime) -github.com/onflow/cadence/runtime/parser (file) -github.com/onflow/cadence/runtime/pretty (runtime) -github.com/stretchr/testify/assert (runtime, file, network) -github.com/stretchr/testify/require (network) -github.com/texttheater/golang-levenshtein/levenshtein (file) -github.com/zeebo/blake3/internal/consts (file) -golang.org/x/xerrors (runtime) -github.com/onflow/cadence/runtime/interpreter (runtime) From a03a45200ede2ee9ebeae0a8c56c049c649fe00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 11:49:46 -0700 Subject: [PATCH 25/47] fix lint --- runtime/stdlib/account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/stdlib/account.go b/runtime/stdlib/account.go index 17ae64b93f..f252312860 100644 --- a/runtime/stdlib/account.go +++ b/runtime/stdlib/account.go @@ -3765,7 +3765,7 @@ func newCapabilityControllerGetCapabilityFunction( capabilityID := controller.ControllerCapabilityID() borrowType := controller.CapabilityControllerBorrowType() - return func(inter *interpreter.Interpreter) *interpreter.CapabilityValue { + return func(inter *interpreter.Interpreter) *interpreter.CapabilityValue { return interpreter.NewCapabilityValue( inter, capabilityID, From 4d0836ee61c8c2aafd0f9b2e6633c251d8065147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 16:00:55 -0700 Subject: [PATCH 26/47] check native function declarations --- runtime/sema/check_function.go | 17 +++++- runtime/sema/errors.go | 17 ++++++ runtime/tests/checker/function_test.go | 76 ++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/runtime/sema/check_function.go b/runtime/sema/check_function.go index 8797b50f37..46d2d0392a 100644 --- a/runtime/sema/check_function.go +++ b/runtime/sema/check_function.go @@ -76,6 +76,21 @@ func (checker *Checker) visitFunctionDeclaration( declaration.Identifier, ) + functionBlock := declaration.FunctionBlock + + if declaration.IsNative() { + if !functionBlock.IsEmpty() { + checker.report(&NativeFunctionWithImplementationError{ + Range: ast.NewRangeFromPositioned( + checker.memoryGauge, + functionBlock, + ), + }) + } + + functionBlock = nil + } + // global functions were previously declared, see `declareFunctionDeclaration` functionType := checker.Elaboration.FunctionDeclarationFunctionType(declaration) @@ -93,7 +108,7 @@ func (checker *Checker) visitFunctionDeclaration( declaration.ParameterList, declaration.ReturnTypeAnnotation, functionType, - declaration.FunctionBlock, + functionBlock, options.mustExit, nil, options.checkResourceLoss, diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 958ab6009f..7d1d793c55 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -878,6 +878,23 @@ func (e *InvalidNativeModifierError) Error() string { return "invalid native modifier for declaration" } +// NativeFunctionWithImplementationError + +type NativeFunctionWithImplementationError struct { + ast.Range +} + +var _ SemanticError = &NativeFunctionWithImplementationError{} +var _ errors.UserError = &NativeFunctionWithImplementationError{} + +func (*NativeFunctionWithImplementationError) isSemanticError() {} + +func (*NativeFunctionWithImplementationError) IsUserError() {} + +func (e *NativeFunctionWithImplementationError) Error() string { + return "native function may not have an implementation" +} + // InvalidNameError type InvalidNameError struct { diff --git a/runtime/tests/checker/function_test.go b/runtime/tests/checker/function_test.go index 4ce60c282d..29a6066029 100644 --- a/runtime/tests/checker/function_test.go +++ b/runtime/tests/checker/function_test.go @@ -440,20 +440,74 @@ func TestCheckNativeFunctionDeclaration(t *testing.T) { t.Parallel() - _, err := ParseAndCheckWithOptions(t, - ` - native fun test() {} - `, - ParseAndCheckOptions{ - ParseOptions: parser.Config{ - NativeModifierEnabled: true, + t.Run("disabled", func(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheckWithOptions(t, + ` + native fun test(): Int {} + `, + ParseAndCheckOptions{ + ParseOptions: parser.Config{ + NativeModifierEnabled: true, + }, + Config: &sema.Config{ + AllowNativeDeclarations: false, + }, }, - }, - ) + ) - errs := RequireCheckerErrors(t, err, 1) + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.InvalidNativeModifierError{}, errs[0]) + }) + + t.Run("enabled, valid", func(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheckWithOptions(t, + ` + native fun test(): Int {} + `, + ParseAndCheckOptions{ + ParseOptions: parser.Config{ + NativeModifierEnabled: true, + }, + Config: &sema.Config{ + AllowNativeDeclarations: true, + }, + }, + ) + + require.NoError(t, err) + }) + + t.Run("enabled, invalid", func(t *testing.T) { - assert.IsType(t, &sema.InvalidNativeModifierError{}, errs[0]) + t.Parallel() + + _, err := ParseAndCheckWithOptions(t, + ` + native fun test(): Int { + return 1 + } + `, + ParseAndCheckOptions{ + ParseOptions: parser.Config{ + NativeModifierEnabled: true, + }, + Config: &sema.Config{ + AllowNativeDeclarations: true, + }, + }, + ) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.NativeFunctionWithImplementationError{}, errs[0]) + }) } func TestCheckResultVariable(t *testing.T) { From 5f185e0d3f54a6b0d037fa40818b5ce5c7ac287b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 16:20:00 -0700 Subject: [PATCH 27/47] improve error message Co-authored-by: Supun Setunga --- runtime/sema/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 7d1d793c55..5fc1424792 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -892,7 +892,7 @@ func (*NativeFunctionWithImplementationError) isSemanticError() {} func (*NativeFunctionWithImplementationError) IsUserError() {} func (e *NativeFunctionWithImplementationError) Error() string { - return "native function may not have an implementation" + return "native function must not have an implementation" } // InvalidNameError From d174f7be8598456f5c126c11ccb742b193208391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 16:24:54 -0700 Subject: [PATCH 28/47] add test case for declaring native function in composite --- runtime/tests/checker/function_test.go | 51 ++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/runtime/tests/checker/function_test.go b/runtime/tests/checker/function_test.go index 29a6066029..15aec78eea 100644 --- a/runtime/tests/checker/function_test.go +++ b/runtime/tests/checker/function_test.go @@ -24,6 +24,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/parser" "github.com/onflow/cadence/runtime/sema" ) @@ -508,6 +510,55 @@ func TestCheckNativeFunctionDeclaration(t *testing.T) { assert.IsType(t, &sema.NativeFunctionWithImplementationError{}, errs[0]) }) + + t.Run("enabled, composite", func(t *testing.T) { + + t.Parallel() + + checker, err := ParseAndCheckWithOptions(t, + ` + struct S { + native fun test(foo: String): Int {} + } + `, + ParseAndCheckOptions{ + ParseOptions: parser.Config{ + NativeModifierEnabled: true, + }, + Config: &sema.Config{ + AllowNativeDeclarations: true, + }, + }, + ) + require.NoError(t, err) + + sType := RequireGlobalType(t, checker.Elaboration, "S") + require.NotNil(t, sType) + + const testFunctionIdentifier = "test" + testMemberResolver, ok := sType.GetMembers()[testFunctionIdentifier] + require.True(t, ok) + + assert.Equal(t, + common.DeclarationKindFunction, + testMemberResolver.Kind, + ) + + member := testMemberResolver.Resolve(nil, testFunctionIdentifier, ast.EmptyRange, nil) + + assert.Equal(t, + sema.NewTypeAnnotation(&sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Identifier: "foo", + TypeAnnotation: sema.NewTypeAnnotation(sema.StringType), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.IntType), + }), + member.TypeAnnotation, + ) + }) } func TestCheckResultVariable(t *testing.T) { From d1f232e5b20644765214044aa5a5d98b70a83d6d Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 28 Sep 2023 13:15:03 -0400 Subject: [PATCH 29/47] properly access-check optional chaining with entitlements --- runtime/sema/check_member_expression.go | 2 + runtime/tests/checker/entitlements_test.go | 69 ++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/runtime/sema/check_member_expression.go b/runtime/sema/check_member_expression.go index 4d717c09ac..0ff70a37f5 100644 --- a/runtime/sema/check_member_expression.go +++ b/runtime/sema/check_member_expression.go @@ -419,6 +419,8 @@ func (checker *Checker) isReadableMember(accessedType Type, member *Member, resu } case EntitlementSetAccess: switch ty := accessedType.(type) { + case *OptionalType: + return checker.isReadableMember(ty.Type, member, resultingType, accessRange) case *ReferenceType: // when accessing a member on a reference, the read is allowed if // the member's access permits the reference's authorization diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index b97813af75..8c598cd14e 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7222,3 +7222,72 @@ func TestCheckEntitlementErrorReporting(t *testing.T) { ) }) } + +func TestCheckEntitlementOptionalChaining(t *testing.T) { + t.Run("optional chain function call", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` + entitlement X + + struct S { + access(X) fun foo() {} + } + + fun bar(r: &S?) { + r?.foo() + } + `) + + errs := RequireCheckerErrors(t, err, 1) + var invalidAccessErr *sema.InvalidAccessError + require.ErrorAs(t, errs[0], &invalidAccessErr) + }) + + t.Run("optional chain field access", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` + entitlement X + entitlement Y + + struct S { + access(X, Y) let foo: Int + init() { + self.foo = 0 + } + } + + fun bar(r: auth(X) &S?) { + r?.foo + } + `) + + errs := RequireCheckerErrors(t, err, 1) + var invalidAccessErr *sema.InvalidAccessError + require.ErrorAs(t, errs[0], &invalidAccessErr) + }) + + t.Run("optional chain mapping", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` + entitlement X + entitlement Y + + entitlement mapping E { + X -> Y + } + + struct S { + access(E) let foo: auth(E) &Int + init() { + self.foo = &0 as auth(Y) &Int + } + } + + fun bar(r: (auth(X) &S)?): (auth(Y) &Int)? { + return r?.foo + } + `) + + require.NoError(t, err) + }) +} From a28d5b6708cd7989beb663b5216ef4712bb9a100 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 28 Sep 2023 13:16:19 -0400 Subject: [PATCH 30/47] add test --- runtime/tests/checker/entitlements_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index 8c598cd14e..c43a02c0fc 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7266,6 +7266,27 @@ func TestCheckEntitlementOptionalChaining(t *testing.T) { require.ErrorAs(t, errs[0], &invalidAccessErr) }) + t.Run("optional chain non reference", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` + entitlement X + entitlement Y + + struct S { + access(X, Y) let foo: Int + init() { + self.foo = 0 + } + } + + fun bar(r: S?) { + r?.foo + } + `) + + require.NoError(t, err) + }) + t.Run("optional chain mapping", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` From 089768c5735ee1044514795243754274adc9caaf Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 3 Oct 2023 11:50:36 -0400 Subject: [PATCH 31/47] before statements require pure arguments --- runtime/sema/check_function.go | 5 +- runtime/tests/checker/conditions_test.go | 81 ++++++++++++++++++++++++ runtime/tests/checker/resources_test.go | 5 +- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/runtime/sema/check_function.go b/runtime/sema/check_function.go index 26c4ec7228..c84275e3af 100644 --- a/runtime/sema/check_function.go +++ b/runtime/sema/check_function.go @@ -344,7 +344,10 @@ func (checker *Checker) visitWithPostConditions(postConditions *ast.Conditions, checker.Elaboration.SetPostConditionsRewrite(postConditions, rewriteResult) - checker.visitStatements(rewriteResult.BeforeStatements) + // all condition blocks are `view` + checker.InNewPurityScope(true, func() { + checker.visitStatements(rewriteResult.BeforeStatements) + }) } body() diff --git a/runtime/tests/checker/conditions_test.go b/runtime/tests/checker/conditions_test.go index 8960d89fc1..b0d3b11398 100644 --- a/runtime/tests/checker/conditions_test.go +++ b/runtime/tests/checker/conditions_test.go @@ -1018,3 +1018,84 @@ func TestCheckRewrittenPostConditions(t *testing.T) { }) } + +func TestCheckBeforeConditions(t *testing.T) { + + t.Parallel() + + t.Run("function call", func(t *testing.T) { + + _, err := ParseAndCheck(t, ` + fun impure(): Int { + return 0 + } + + fun test() { + post { + before(impure()) > 0 + } + } + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.PurityError{}, errs[0]) + }) + + t.Run("view function call", func(t *testing.T) { + + _, err := ParseAndCheck(t, ` + view fun pure(): Int { + return 0 + } + + fun test() { + post { + before(pure()) > 0 + } + } + `) + + require.NoError(t, err) + }) + + t.Run("nested function call", func(t *testing.T) { + + _, err := ParseAndCheck(t, ` + view fun pure(): Int { + return 0 + } + + fun impure(): Int { + return 0 + } + + fun test() { + post { + before(before(impure())) > pure() + } + } + `) + + errs := RequireCheckerErrors(t, err, 1) + + assert.IsType(t, &sema.PurityError{}, errs[0]) + }) + + t.Run("nested pure function call", func(t *testing.T) { + + _, err := ParseAndCheck(t, ` + view fun pure(): Int { + return 0 + } + + fun test() { + post { + before(before(pure())) > 0 + } + } + `) + + require.NoError(t, err) + }) +} diff --git a/runtime/tests/checker/resources_test.go b/runtime/tests/checker/resources_test.go index f814147eee..db9726e67a 100644 --- a/runtime/tests/checker/resources_test.go +++ b/runtime/tests/checker/resources_test.go @@ -5673,9 +5673,10 @@ func TestCheckInvalidationInPostConditionBefore(t *testing.T) { } `) - errs := RequireCheckerErrors(t, err, 1) + errs := RequireCheckerErrors(t, err, 2) - assert.IsType(t, &sema.ResourceUseAfterInvalidationError{}, errs[0]) + assert.IsType(t, &sema.PurityError{}, errs[0]) + assert.IsType(t, &sema.ResourceUseAfterInvalidationError{}, errs[1]) } func TestCheckInvalidationInPostCondition(t *testing.T) { From bf4207b31747c8ad9a9c165ad8f7db14d2354784 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 3 Oct 2023 12:19:55 -0400 Subject: [PATCH 32/47] parallelize --- runtime/tests/checker/conditions_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/runtime/tests/checker/conditions_test.go b/runtime/tests/checker/conditions_test.go index b0d3b11398..d00d0a94ae 100644 --- a/runtime/tests/checker/conditions_test.go +++ b/runtime/tests/checker/conditions_test.go @@ -1025,6 +1025,8 @@ func TestCheckBeforeConditions(t *testing.T) { t.Run("function call", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` fun impure(): Int { return 0 @@ -1044,6 +1046,8 @@ func TestCheckBeforeConditions(t *testing.T) { t.Run("view function call", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` view fun pure(): Int { return 0 @@ -1061,6 +1065,8 @@ func TestCheckBeforeConditions(t *testing.T) { t.Run("nested function call", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` view fun pure(): Int { return 0 @@ -1084,6 +1090,8 @@ func TestCheckBeforeConditions(t *testing.T) { t.Run("nested pure function call", func(t *testing.T) { + t.Parallel() + _, err := ParseAndCheck(t, ` view fun pure(): Int { return 0 From 251f6e3854539b6056d17d2b4987edba1c84e274 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 4 Oct 2023 10:25:13 -0400 Subject: [PATCH 33/47] don't add relations to mappings if they fail --- runtime/sema/check_interface_declaration.go | 2 ++ runtime/tests/checker/entitlements_test.go | 28 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/runtime/sema/check_interface_declaration.go b/runtime/sema/check_interface_declaration.go index 51d798896b..45934ed77a 100644 --- a/runtime/sema/check_interface_declaration.go +++ b/runtime/sema/check_interface_declaration.go @@ -529,6 +529,7 @@ func (checker *Checker) declareEntitlementMappingType(declaration *ast.Entitleme checker.report(&InvalidNonEntitlementTypeInMapError{ Pos: association.Input.Identifier.Pos, }) + continue } output := checker.convertNominalType(association.Output) @@ -538,6 +539,7 @@ func (checker *Checker) declareEntitlementMappingType(declaration *ast.Entitleme checker.report(&InvalidNonEntitlementTypeInMapError{ Pos: association.Output.Identifier.Pos, }) + continue } entitlementRelations = append( diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index c43a02c0fc..3432237c3f 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7224,6 +7224,9 @@ func TestCheckEntitlementErrorReporting(t *testing.T) { } func TestCheckEntitlementOptionalChaining(t *testing.T) { + + t.Parallel() + t.Run("optional chain function call", func(t *testing.T) { t.Parallel() _, err := ParseAndCheck(t, ` @@ -7312,3 +7315,28 @@ func TestCheckEntitlementOptionalChaining(t *testing.T) { require.NoError(t, err) }) } + +func TestCheckEntitlementMissingInMap(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + access(all) entitlement X + access(all) entitlement mapping M { + X -> X + NonExistingEntitlement -> X + } + access(all) struct S { + access(M) var foo: auth(M) &Int + init() { + self.foo = &3 as auth(X) &Int + var selfRef = &self as auth(X) &S; + selfRef.foo; + } + } + `) + + errors := RequireCheckerErrors(t, err, 2) + require.IsType(t, errors[0], &sema.NotDeclaredError{}) + require.IsType(t, errors[1], &sema.InvalidNonEntitlementTypeInMapError{}) +} From 1be5126ee5c345ef317de432597f6e3c72c2a3bc Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 4 Oct 2023 10:26:34 -0400 Subject: [PATCH 34/47] other test --- runtime/tests/checker/entitlements_test.go | 37 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index 3432237c3f..dffec20bb2 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7320,7 +7320,11 @@ func TestCheckEntitlementMissingInMap(t *testing.T) { t.Parallel() - _, err := ParseAndCheck(t, ` + t.Run("missing type", func(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` access(all) entitlement X access(all) entitlement mapping M { X -> X @@ -7336,7 +7340,32 @@ func TestCheckEntitlementMissingInMap(t *testing.T) { } `) - errors := RequireCheckerErrors(t, err, 2) - require.IsType(t, errors[0], &sema.NotDeclaredError{}) - require.IsType(t, errors[1], &sema.InvalidNonEntitlementTypeInMapError{}) + errors := RequireCheckerErrors(t, err, 2) + require.IsType(t, errors[0], &sema.NotDeclaredError{}) + require.IsType(t, errors[1], &sema.InvalidNonEntitlementTypeInMapError{}) + }) + + t.Run("non entitlement type", func(t *testing.T) { + + t.Parallel() + + _, err := ParseAndCheck(t, ` + access(all) entitlement X + access(all) entitlement mapping M { + X -> X + Int -> X + } + access(all) struct S { + access(M) var foo: auth(M) &Int + init() { + self.foo = &3 as auth(X) &Int + var selfRef = &self as auth(X) &S; + selfRef.foo; + } + } + `) + + errors := RequireCheckerErrors(t, err, 1) + require.IsType(t, errors[0], &sema.InvalidNonEntitlementTypeInMapError{}) + }) } From 22d98e132502cc4d4dba751ac57a00cf71c07184 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 4 Oct 2023 13:56:57 -0400 Subject: [PATCH 35/47] add tests --- .../tests/interpreter/entitlements_test.go | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/runtime/tests/interpreter/entitlements_test.go b/runtime/tests/interpreter/entitlements_test.go index 42e7c57f60..fe32f2f133 100644 --- a/runtime/tests/interpreter/entitlements_test.go +++ b/runtime/tests/interpreter/entitlements_test.go @@ -3280,3 +3280,74 @@ func TestInterpretMappingInclude(t *testing.T) { ) }) } + +func TestInterpretMappingEscalation(t *testing.T) { + + t.Parallel() + + t.Run("escalate", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + entitlement X + entitlement Y + entitlement mapping M { + X -> Insert + Y -> Remove + } + struct S { + access(M) var member: auth(M) &[Int]? + init() { + self.member = nil; + } + access(all) fun grantRemovePrivileges(param: auth(Insert) &[Int]): Void{ + var selfRef = &self as auth(X) &S; + selfRef.member = param; + } + } + fun main(): Void { + var arr: [Int] = [123]; + var arrRef = &arr as auth(Insert) &[Int]; + let s = S() + s.grantRemovePrivileges(param: arrRef); + s.member?.removeLast() // Caught by checkMemberAccess type check + } + `) + + _, err := inter.Invoke("main") + assert.NoError(t, err) + }) + + t.Run("field assign", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + entitlement X + entitlement Y + entitlement mapping M { + X -> Insert + Y -> Remove + } + struct S { + access(M) var member: auth(M) &[Int]? + init() { + self.member = nil; + } + access(all) fun grantRemovePrivileges(sRef: auth(X) &S, param: auth(Insert) &[Int]): Void{ + sRef.member = param; + } + } + fun main(): Void { + var arr: [Int] = [123]; + var arrRef = &arr as auth(Insert) &[Int]; + let s = S() + s.grantRemovePrivileges(sRef: &s as auth(X) &S, param: arrRef); + s.member?.removeLast() // Caught by checkMemberAccess type check + } + `) + + _, err := inter.Invoke("main") + assert.NoError(t, err) + }) + +} From 16885b67a7c23193b6e549ed4eacd271b19b0f7c Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 4 Oct 2023 13:58:45 -0400 Subject: [PATCH 36/47] fix tests --- runtime/tests/checker/entitlements_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index dffec20bb2..3a997c54d5 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7334,15 +7334,15 @@ func TestCheckEntitlementMissingInMap(t *testing.T) { access(M) var foo: auth(M) &Int init() { self.foo = &3 as auth(X) &Int - var selfRef = &self as auth(X) &S; - selfRef.foo; + var selfRef = &self as auth(X) &S + selfRef.foo } } `) errors := RequireCheckerErrors(t, err, 2) - require.IsType(t, errors[0], &sema.NotDeclaredError{}) - require.IsType(t, errors[1], &sema.InvalidNonEntitlementTypeInMapError{}) + require.IsType(t, &sema.NotDeclaredError{}, errors[0]) + require.IsType(t, &sema.InvalidNonEntitlementTypeInMapError{}, errors[1]) }) t.Run("non entitlement type", func(t *testing.T) { @@ -7359,13 +7359,13 @@ func TestCheckEntitlementMissingInMap(t *testing.T) { access(M) var foo: auth(M) &Int init() { self.foo = &3 as auth(X) &Int - var selfRef = &self as auth(X) &S; - selfRef.foo; + var selfRef = &self as auth(X) &S + selfRef.foo } } `) errors := RequireCheckerErrors(t, err, 1) - require.IsType(t, errors[0], &sema.InvalidNonEntitlementTypeInMapError{}) + require.IsType(t, &sema.InvalidNonEntitlementTypeInMapError{}, errors[0]) }) } From 787fdbe4b4364ee7c4425cedf0dfa4616cab2b24 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 4 Oct 2023 15:06:53 -0400 Subject: [PATCH 37/47] require full entitlements to assign to a mapped field --- runtime/sema/check_member_expression.go | 22 ++++++ runtime/tests/checker/entitlements_test.go | 71 +++++++++++++++++++ .../tests/interpreter/entitlements_test.go | 71 ------------------- 3 files changed, 93 insertions(+), 71 deletions(-) diff --git a/runtime/sema/check_member_expression.go b/runtime/sema/check_member_expression.go index 0ff70a37f5..4d1d044a0d 100644 --- a/runtime/sema/check_member_expression.go +++ b/runtime/sema/check_member_expression.go @@ -455,6 +455,28 @@ func (checker *Checker) mapAccess( // pretend that the access succeeds to prevent a redundant access error report return true, UnauthorizedAccess } + // when we are in an assignment statement, + // we need full permissions to the map regardless of the input authorization of the reference + // Consider: + // + // entitlement X + // entitlement Y + // entitlement mapping M { + // X -> Insert + // Y -> Remove + // } + // struct S { + // access(M) var member: auth(M) &[T]? + // ... + // } + // + // If we were able to assign a `auth(Insert) &[T]` value to `ref.member` when `ref` has type `auth(X) &S` + // we could use this to then extract a `auth(Insert, Remove) &[T]` reference to that array by accessing `member` + // on an owned copy of `S`. As such, when in an assignment, we return the full codomain here as the "granted authorization" + // of the access expression, since the checker will later enforce that the incoming reference value is a subtype of that full codomain. + if checker.inAssignment { + return true, mappedAccess.Codomain() + } return true, grantedAccess case *OptionalType: diff --git a/runtime/tests/checker/entitlements_test.go b/runtime/tests/checker/entitlements_test.go index 3a997c54d5..727c0f613d 100644 --- a/runtime/tests/checker/entitlements_test.go +++ b/runtime/tests/checker/entitlements_test.go @@ -7369,3 +7369,74 @@ func TestCheckEntitlementMissingInMap(t *testing.T) { require.IsType(t, &sema.InvalidNonEntitlementTypeInMapError{}, errors[0]) }) } + +func TestInterpretMappingEscalation(t *testing.T) { + + t.Parallel() + + t.Run("escalate", func(t *testing.T) { + t.Parallel() + + _, err := ParseAndCheck(t, ` + entitlement X + entitlement Y + entitlement mapping M { + X -> Insert + Y -> Remove + } + struct S { + access(M) var member: auth(M) &[Int]? + init() { + self.member = nil; + } + access(all) fun grantRemovePrivileges(param: auth(Insert) &[Int]): Void{ + var selfRef = &self as auth(X) &S; + selfRef.member = param; + } + } + fun main(): Void { + var arr: [Int] = [123]; + var arrRef = &arr as auth(Insert) &[Int]; + let s = S() + s.grantRemovePrivileges(param: arrRef); + s.member?.removeLast() + } + `) + + errors := RequireCheckerErrors(t, err, 1) + require.IsType(t, &sema.TypeMismatchError{}, errors[0]) + }) + + t.Run("field assign", func(t *testing.T) { + t.Parallel() + + _, err := ParseAndCheck(t, ` + entitlement X + entitlement Y + entitlement mapping M { + X -> Insert + Y -> Remove + } + struct S { + access(M) var member: auth(M) &[Int]? + init() { + self.member = nil; + } + access(all) fun grantRemovePrivileges(sRef: auth(X) &S, param: auth(Insert) &[Int]): Void{ + sRef.member = param; + } + } + fun main(): Void { + var arr: [Int] = [123]; + var arrRef = &arr as auth(Insert) &[Int]; + let s = S() + s.grantRemovePrivileges(sRef: &s as auth(X) &S, param: arrRef); + s.member?.removeLast() + } + `) + + errors := RequireCheckerErrors(t, err, 1) + require.IsType(t, &sema.TypeMismatchError{}, errors[0]) + }) + +} diff --git a/runtime/tests/interpreter/entitlements_test.go b/runtime/tests/interpreter/entitlements_test.go index fe32f2f133..42e7c57f60 100644 --- a/runtime/tests/interpreter/entitlements_test.go +++ b/runtime/tests/interpreter/entitlements_test.go @@ -3280,74 +3280,3 @@ func TestInterpretMappingInclude(t *testing.T) { ) }) } - -func TestInterpretMappingEscalation(t *testing.T) { - - t.Parallel() - - t.Run("escalate", func(t *testing.T) { - t.Parallel() - - inter := parseCheckAndInterpret(t, ` - entitlement X - entitlement Y - entitlement mapping M { - X -> Insert - Y -> Remove - } - struct S { - access(M) var member: auth(M) &[Int]? - init() { - self.member = nil; - } - access(all) fun grantRemovePrivileges(param: auth(Insert) &[Int]): Void{ - var selfRef = &self as auth(X) &S; - selfRef.member = param; - } - } - fun main(): Void { - var arr: [Int] = [123]; - var arrRef = &arr as auth(Insert) &[Int]; - let s = S() - s.grantRemovePrivileges(param: arrRef); - s.member?.removeLast() // Caught by checkMemberAccess type check - } - `) - - _, err := inter.Invoke("main") - assert.NoError(t, err) - }) - - t.Run("field assign", func(t *testing.T) { - t.Parallel() - - inter := parseCheckAndInterpret(t, ` - entitlement X - entitlement Y - entitlement mapping M { - X -> Insert - Y -> Remove - } - struct S { - access(M) var member: auth(M) &[Int]? - init() { - self.member = nil; - } - access(all) fun grantRemovePrivileges(sRef: auth(X) &S, param: auth(Insert) &[Int]): Void{ - sRef.member = param; - } - } - fun main(): Void { - var arr: [Int] = [123]; - var arrRef = &arr as auth(Insert) &[Int]; - let s = S() - s.grantRemovePrivileges(sRef: &s as auth(X) &S, param: arrRef); - s.member?.removeLast() // Caught by checkMemberAccess type check - } - `) - - _, err := inter.Invoke("main") - assert.NoError(t, err) - }) - -} From 88f2e1d70c767a9f6217f80efa7fa48563dc16d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 1 Aug 2023 17:08:58 -0700 Subject: [PATCH 38/47] fix swapping in resource array: insert temporary placeholder --- runtime/interpreter/interpreter_expression.go | 28 +++-- runtime/interpreter/value.go | 3 + runtime/interpreter/value_placeholder.go | 104 ++++++++++++++++ runtime/tests/interpreter/interpreter_test.go | 112 ++++++++++++++++++ 4 files changed, 235 insertions(+), 12 deletions(-) create mode 100644 runtime/interpreter/value_placeholder.go diff --git a/runtime/interpreter/interpreter_expression.go b/runtime/interpreter/interpreter_expression.go index edb24e1d0c..70514e4687 100644 --- a/runtime/interpreter/interpreter_expression.go +++ b/runtime/interpreter/interpreter_expression.go @@ -138,21 +138,25 @@ func (interpreter *Interpreter) valueIndexExpressionGetterSetter(indexExpression isNestedResourceMove := elaboration.IsNestedResourceMoveExpression(indexExpression) + var get func(allowMissing bool) Value + + if isNestedResourceMove { + get = func(_ bool) Value { + value := target.RemoveKey(interpreter, locationRange, transferredIndexingValue) + target.InsertKey(interpreter, locationRange, transferredIndexingValue, placeholder) + return value + } + } else { + get = func(_ bool) Value { + return target.GetKey(interpreter, locationRange, transferredIndexingValue) + } + } + return getterSetter{ target: target, - get: func(_ bool) Value { - if isNestedResourceMove { - return target.RemoveKey(interpreter, locationRange, transferredIndexingValue) - } else { - return target.GetKey(interpreter, locationRange, transferredIndexingValue) - } - }, + get: get, set: func(value Value) { - if isNestedResourceMove { - target.InsertKey(interpreter, locationRange, transferredIndexingValue, value) - } else { - target.SetKey(interpreter, locationRange, transferredIndexingValue, value) - } + target.SetKey(interpreter, locationRange, transferredIndexingValue, value) }, } } diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 8a7aa890d2..4e34139977 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -18153,6 +18153,9 @@ func (v *DictionaryValue) SetKey( case NilValue: _ = v.Remove(interpreter, locationRange, keyValue) + case placeholderValue: + // NO-OP + default: panic(errors.NewUnreachableError()) } diff --git a/runtime/interpreter/value_placeholder.go b/runtime/interpreter/value_placeholder.go new file mode 100644 index 0000000000..24572a7620 --- /dev/null +++ b/runtime/interpreter/value_placeholder.go @@ -0,0 +1,104 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Dapper Labs, Inc. + * + * 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 + +import ( + "github.com/onflow/atree" + + "github.com/onflow/cadence/runtime/common" +) + +// placeholderValue +type placeholderValue struct{} + +var placeholder Value = placeholderValue{} + +var _ Value = placeholderValue{} + +func (placeholderValue) isValue() {} + +func (f placeholderValue) String() string { + return f.RecursiveString(SeenReferences{}) +} + +func (f placeholderValue) RecursiveString(_ SeenReferences) string { + return "" +} + +func (f placeholderValue) MeteredString(_ common.MemoryGauge, _ SeenReferences) string { + return "" +} + +func (f placeholderValue) Accept(_ *Interpreter, _ Visitor) { + // NO-OP +} + +func (f placeholderValue) Walk(_ *Interpreter, _ func(Value)) { + // NO-OP +} + +func (f placeholderValue) StaticType(_ *Interpreter) StaticType { + return PrimitiveStaticTypeNever +} + +func (placeholderValue) IsImportable(_ *Interpreter) bool { + return false +} + +func (f placeholderValue) ConformsToStaticType( + _ *Interpreter, + _ LocationRange, + _ TypeConformanceResults, +) bool { + return true +} + +func (f placeholderValue) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { + return NonStorable{Value: f}, nil +} + +func (placeholderValue) NeedsStoreTo(_ atree.Address) bool { + return false +} + +func (placeholderValue) IsResourceKinded(_ *Interpreter) bool { + return false +} + +func (f placeholderValue) Transfer( + interpreter *Interpreter, + _ LocationRange, + _ atree.Address, + remove bool, + storable atree.Storable, +) Value { + // TODO: actually not needed, value is not storable + if remove { + interpreter.RemoveReferencedSlab(storable) + } + return f +} + +func (f placeholderValue) Clone(_ *Interpreter) Value { + return f +} + +func (placeholderValue) DeepRemove(_ *Interpreter) { + // NO-OP +} diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 92dbf988a8..ec45874fbc 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -12011,3 +12011,115 @@ func TestInterpretConditionsWrapperFunctionType(t *testing.T) { require.NoError(t, err) }) } + +func TestInterpretSwapInSameArray(t *testing.T) { + + t.Parallel() + + t.Run("resources", func(t *testing.T) { + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + resource R { + let value: Int + + init(value: Int) { + self.value = value + } + } + + fun test(): [Int] { + let rs <- [ + <- create R(value: 0), + <- create R(value: 1), + <- create R(value: 2) + ] + + // We swap only '0' and '1' + rs[0] <-> rs[1] + + let values = [ + rs[0].value, + rs[1].value, + rs[2].value + ] + + destroy rs + + return values + } + `) + + value, err := inter.Invoke("test") + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(0), + interpreter.NewUnmeteredIntValueFromInt64(2), + ), + value, + ) + }) + + t.Run("structs", func(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + struct S { + let value: Int + + init(value: Int) { + self.value = value + } + } + + fun test(): [Int] { + let structs = [ + S(value: 0), + S(value: 1), + S(value: 2) + ] + + // We swap only '0' and '1' + structs[0] <-> structs[1] + + return [ + structs[0].value, + structs[1].value, + structs[2].value + ] + } + `) + + value, err := inter.Invoke("test") + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(0), + interpreter.NewUnmeteredIntValueFromInt64(2), + ), + value, + ) + }) +} From de1ec1f7cb6fec16e3f9f50ee8ac0dc28edc19d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 1 Aug 2023 17:13:40 -0700 Subject: [PATCH 39/47] add test case for same indices --- runtime/tests/interpreter/interpreter_test.go | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index ec45874fbc..8e6529abcc 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -12016,7 +12016,7 @@ func TestInterpretSwapInSameArray(t *testing.T) { t.Parallel() - t.Run("resources", func(t *testing.T) { + t.Run("resources, different indices", func(t *testing.T) { t.Parallel() inter := parseCheckAndInterpret(t, ` @@ -12071,6 +12071,62 @@ func TestInterpretSwapInSameArray(t *testing.T) { ) }) + t.Run("resources, same indices", func(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + resource R { + let value: Int + + init(value: Int) { + self.value = value + } + } + + fun test(): [Int] { + let rs <- [ + <- create R(value: 0), + <- create R(value: 1), + <- create R(value: 2) + ] + + // We swap only '1' + rs[1] <-> rs[1] + + let values = [ + rs[0].value, + rs[1].value, + rs[2].value + ] + + destroy rs + + return values + } + `) + + value, err := inter.Invoke("test") + require.NoError(t, err) + + AssertValuesEqual( + t, + inter, + interpreter.NewArrayValue( + inter, + interpreter.EmptyLocationRange, + interpreter.VariableSizedStaticType{ + Type: interpreter.PrimitiveStaticTypeInt, + }, + common.ZeroAddress, + interpreter.NewUnmeteredIntValueFromInt64(0), + interpreter.NewUnmeteredIntValueFromInt64(1), + interpreter.NewUnmeteredIntValueFromInt64(2), + ), + value, + ) + }) + t.Run("structs", func(t *testing.T) { t.Parallel() From 405464a6b9d696b93d6d7c0922178323e38b2d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 2 Aug 2023 13:44:06 -0700 Subject: [PATCH 40/47] add an explanation for the placeholder insertion --- runtime/interpreter/interpreter_expression.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/runtime/interpreter/interpreter_expression.go b/runtime/interpreter/interpreter_expression.go index 70514e4687..96420aa4cd 100644 --- a/runtime/interpreter/interpreter_expression.go +++ b/runtime/interpreter/interpreter_expression.go @@ -136,6 +136,29 @@ func (interpreter *Interpreter) valueIndexExpressionGetterSetter(indexExpression }, ) + // Normally, moves of nested resources (e.g `let r <- rs[0]`) are statically rejected. + // + // However, there are cases in which we do allow moves of nested resources: + // + // - In a swap statement (e.g. `rs[0] <-> rs[1]`) + // - In a variable declaration with two values/assignments (e.g. `let r <- rs["foo"] <- nil`) + // + // In both cases we know that a move of the nested resource is immediately followed by a replacement. + // This notion of an expression that moves a nested resource is tracked in the elaboration. + // + // When indexing is a move of a nested resource, we need to remove the key/value from the container. + // However, for some containers, like arrays, the removal influences other values in the container. + // In case of an array, the removal of an element shifts all following elements. + // + // A removal alone would thus result in subsequent code being executed incorrectly. + // For example, in the case where a swap operation through indexing is performed on the same array, + // e.g. `rs[0] <-> rs[1]`, once the first removal was performed, the second operates on a modified container. + // + // Prevent this problem by temporarily writing a placeholder value after the removal. + // Only perform the replacement with a placeholder in the case of a nested resource move. + // We know that in that case the get operation will be followed by a set operation, + // which will replace the temporary placeholder. + isNestedResourceMove := elaboration.IsNestedResourceMoveExpression(indexExpression) var get func(allowMissing bool) Value From f1a8ff118cff59e22425defd7bff209abeba461a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 2 Oct 2023 12:01:38 -0700 Subject: [PATCH 41/47] add new parameter --- runtime/interpreter/value_placeholder.go | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/interpreter/value_placeholder.go b/runtime/interpreter/value_placeholder.go index 24572a7620..6cc6184852 100644 --- a/runtime/interpreter/value_placeholder.go +++ b/runtime/interpreter/value_placeholder.go @@ -87,6 +87,7 @@ func (f placeholderValue) Transfer( _ atree.Address, remove bool, storable atree.Storable, + _ map[atree.StorageID]struct{}, ) Value { // TODO: actually not needed, value is not storable if remove { From c6e7139acc0cdf488a1ddc74164d711e45f4d532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 14:32:21 -0700 Subject: [PATCH 42/47] fix swap statement evaluation evaluate all parts (left target, left key, right target, right key), before getting and setting --- runtime/interpreter/interpreter_statement.go | 27 +++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/runtime/interpreter/interpreter_statement.go b/runtime/interpreter/interpreter_statement.go index 171748e389..dd6090c68c 100644 --- a/runtime/interpreter/interpreter_statement.go +++ b/runtime/interpreter/interpreter_statement.go @@ -153,8 +153,10 @@ func (interpreter *Interpreter) visitIfStatementWithVariableDeclaration( // If the resource was not moved ou of the container, // its contents get deleted. + getterSetter := interpreter.assignmentGetterSetter(declaration.Value) + const allowMissing = false - value := interpreter.assignmentGetterSetter(declaration.Value).get(allowMissing) + value := getterSetter.get(allowMissing) if value == nil { panic(errors.NewUnreachableError()) } @@ -498,8 +500,10 @@ func (interpreter *Interpreter) visitVariableDeclaration( // If the resource was not moved ou of the container, // its contents get deleted. + getterSetter := interpreter.assignmentGetterSetter(declaration.Value) + const allowMissing = false - result := interpreter.assignmentGetterSetter(declaration.Value).get(allowMissing) + result := getterSetter.get(allowMissing) if result == nil { panic(errors.NewUnreachableError()) } @@ -552,23 +556,32 @@ func (interpreter *Interpreter) VisitAssignmentStatement(assignment *ast.Assignm } func (interpreter *Interpreter) VisitSwapStatement(swap *ast.SwapStatement) StatementResult { + + // Get type information + swapStatementTypes := interpreter.Program.Elaboration.SwapStatementTypes(swap) leftType := swapStatementTypes.LeftType rightType := swapStatementTypes.RightType - const allowMissing = false + // Evaluate the left side (target and key) - // Evaluate the left expression leftGetterSetter := interpreter.assignmentGetterSetter(swap.Left) + + // Evaluate the right side (target and key) + + rightGetterSetter := interpreter.assignmentGetterSetter(swap.Right) + + // Get left and right values + + const allowMissing = false + leftValue := leftGetterSetter.get(allowMissing) interpreter.checkSwapValue(leftValue, swap.Left) - // Evaluate the right expression - rightGetterSetter := interpreter.assignmentGetterSetter(swap.Right) rightValue := rightGetterSetter.get(allowMissing) interpreter.checkSwapValue(rightValue, swap.Right) - // Set right value to left target + // Set right value to left target, // and left value to right target locationRange := LocationRange{ From 6748a7e82651bc018ec99fbf239936c3010e7c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Sep 2023 11:21:23 -0700 Subject: [PATCH 43/47] add tests --- runtime/tests/interpreter/interpreter_test.go | 310 +++++++++++++----- 1 file changed, 235 insertions(+), 75 deletions(-) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 8e6529abcc..595ae93000 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -73,6 +73,65 @@ func parseCheckAndInterpretWithOptions( return parseCheckAndInterpretWithOptionsAndMemoryMetering(t, code, options, nil) } +func parseCheckAndInterpretWithLogs( + tb testing.TB, + code string, +) ( + inter *interpreter.Interpreter, + getLogs func() []string, + err error, +) { + var logs []string + + logFunction := stdlib.NewStandardLibraryFunction( + "log", + &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Label: sema.ArgumentLabelNotRequired, + Identifier: "value", + TypeAnnotation: sema.NewTypeAnnotation(sema.AnyStructType), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation( + sema.VoidType, + ), + }, + ``, + func(invocation interpreter.Invocation) interpreter.Value { + message := invocation.Arguments[0].String() + logs = append(logs, message) + return interpreter.Void + }, + ) + + baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) + baseValueActivation.DeclareValue(logFunction) + + baseActivation := activations.NewActivation(nil, interpreter.BaseActivation) + interpreter.Declare(baseActivation, logFunction) + + result, err := parseCheckAndInterpretWithOptions( + tb, + code, + ParseCheckAndInterpretOptions{ + Config: &interpreter.Config{ + BaseActivation: baseActivation, + }, + CheckerConfig: &sema.Config{ + BaseValueActivation: baseValueActivation, + }, + HandleCheckerError: nil, + }, + ) + + getLogs = func() []string { + return logs + } + + return result, getLogs, err +} + func parseCheckAndInterpretWithMemoryMetering( t testing.TB, code string, @@ -9969,90 +10028,49 @@ func TestInterpretNestedDestroy(t *testing.T) { t.Parallel() - var logs []string - - logFunction := stdlib.NewStandardLibraryFunction( - "log", - &sema.FunctionType{ - Parameters: []sema.Parameter{ - { - Label: sema.ArgumentLabelNotRequired, - Identifier: "value", - TypeAnnotation: sema.NewTypeAnnotation(sema.AnyStructType), - }, - }, - ReturnTypeAnnotation: sema.NewTypeAnnotation( - sema.VoidType, - ), - }, - ``, - func(invocation interpreter.Invocation) interpreter.Value { - message := invocation.Arguments[0].String() - logs = append(logs, message) - return interpreter.Void - }, - ) - - baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation) - baseValueActivation.DeclareValue(logFunction) - - baseActivation := activations.NewActivation(nil, interpreter.BaseActivation) - interpreter.Declare(baseActivation, logFunction) - - inter, err := parseCheckAndInterpretWithOptions(t, - ` - resource B { - let id: Int + inter, getLogs, err := parseCheckAndInterpretWithLogs(t, ` + resource B { + let id: Int - init(_ id: Int){ - self.id = id - } + init(_ id: Int){ + self.id = id + } - destroy(){ - log("destroying B with id:") - log(self.id) - } + destroy(){ + log("destroying B with id:") + log(self.id) } + } - resource A { - let id: Int - let bs: @[B] + resource A { + let id: Int + let bs: @[B] - init(_ id: Int){ - self.id = id - self.bs <- [] - } + init(_ id: Int){ + self.id = id + self.bs <- [] + } - fun add(_ b: @B){ - self.bs.append(<-b) - } + fun add(_ b: @B){ + self.bs.append(<-b) + } - destroy() { - log("destroying A with id:") - log(self.id) - destroy self.bs - } + destroy() { + log("destroying A with id:") + log(self.id) + destroy self.bs } + } - fun test() { - let a <- create A(1) - a.add(<- create B(2)) - a.add(<- create B(3)) - a.add(<- create B(4)) + fun test() { + let a <- create A(1) + a.add(<- create B(2)) + a.add(<- create B(3)) + a.add(<- create B(4)) - destroy a - } - `, - ParseCheckAndInterpretOptions{ - Config: &interpreter.Config{ - BaseActivation: baseActivation, - }, - CheckerConfig: &sema.Config{ - BaseValueActivation: baseValueActivation, - }, - HandleCheckerError: nil, - }, - ) + destroy a + } + `) require.NoError(t, err) value, err := inter.Invoke("test") @@ -10076,7 +10094,7 @@ func TestInterpretNestedDestroy(t *testing.T) { `"destroying B with id:"`, "4", }, - logs, + getLogs(), ) } @@ -12179,3 +12197,145 @@ func TestInterpretSwapInSameArray(t *testing.T) { ) }) } + +func TestInterpretSwapDictionaryKeysWithSideEffects(t *testing.T) { + + t.Parallel() + + t.Run("simple", func(t *testing.T) { + t.Parallel() + + inter, getLogs, err := parseCheckAndInterpretWithLogs(t, ` + let xs: [{Int: String}] = [{2: "x"}, {3: "y"}] + + fun a(): Int { + log("a") + return 0 + } + + fun b(): Int { + log("b") + return 2 + } + + fun c(): Int { + log("c") + return 1 + } + + fun d(): Int { + log("d") + return 3 + } + + fun test() { + log(xs) + xs[a()][b()] <-> xs[c()][d()] + log(xs) + } + `) + + _, err = inter.Invoke("test") + require.NoError(t, err) + + assert.Equal(t, + []string{ + `[{2: "x"}, {3: "y"}]`, + `"a"`, + `"b"`, + `"c"`, + `"d"`, + `[{2: "y"}, {3: "x"}]`, + }, + getLogs(), + ) + + }) + + t.Run("resources", func(t *testing.T) { + t.Parallel() + + inter, getLogs, err := parseCheckAndInterpretWithLogs(t, ` + resource Resource { + var value: Int + + init(_ value: Int) { + log( + "Creating resource with UUID " + .concat(self.uuid.toString()) + .concat(" and value ") + .concat(value.toString()) + ) + self.value = value + } + + destroy() { + log( + "Destroying resource with UUID " + .concat(self.uuid.toString()) + .concat(" and value ") + .concat(self.value.toString()) + ) + } + } + + resource ResourceLoser { + var dict: @{Int: Resource} + var toBeLost: @Resource + + init(_ victim: @Resource) { + self.dict <- {1: <- create Resource(2)} + + self.toBeLost <- victim + + // Magic happens during the swap below. + self.dict[1] <-> self.dict[self.shenanigans()] + } + + fun shenanigans(): Int { + var d <- create Resource(3) + + self.toBeLost <-> d + + // This takes advantage of the fact that self.dict[1] has been + // temporarily removed at the point of the swap when this gets called + // We take advantage of this window of opportunity to + // insert the "to-be-lost" resource in its place. The swap implementation + // will blindly overwrite it. + var old <- self.dict.insert(key: 1, <- d) + + // "old" will be nil here thanks to the removal done by the swap + // implementation. We have to destroy it to please sema checker. + destroy old + + return 1 + } + + destroy() { + destroy self.dict + destroy self.toBeLost + } + } + + fun test() { + destroy <- create ResourceLoser(<- create Resource(1)) + } + `) + require.NoError(t, err) + + _, err = inter.Invoke("test") + require.NoError(t, err) + + assert.Equal(t, + []string{ + `"Creating resource with UUID 1 and value 1"`, + `"Creating resource with UUID 3 and value 2"`, + `"Creating resource with UUID 4 and value 3"`, + `"Destroying resource with UUID 3 and value 2"`, + `"Destroying resource with UUID 1 and value 1"`, + `"Destroying resource with UUID 4 and value 3"`, + }, + getLogs(), + ) + }) +} From 6c6f491a98ec355cd5f62fdee0104b82f0583e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 2 Oct 2023 12:43:55 -0700 Subject: [PATCH 44/47] lint --- runtime/tests/interpreter/interpreter_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 595ae93000..6f6157bab5 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -12234,6 +12234,7 @@ func TestInterpretSwapDictionaryKeysWithSideEffects(t *testing.T) { log(xs) } `) + require.NoError(t, err) _, err = inter.Invoke("test") require.NoError(t, err) From 96e74ddb652958d8ae1f82a49c77124baa3d7afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 2 Oct 2023 11:11:50 -0700 Subject: [PATCH 45/47] prevent re-deploy in same transaction --- runtime/contract_test.go | 24 ++++--- runtime/contract_update_test.go | 108 +++++++++++++++++++++++++++++++- runtime/environment.go | 4 ++ runtime/stdlib/account.go | 11 +++- runtime/storage.go | 11 ++++ 5 files changed, 142 insertions(+), 16 deletions(-) diff --git a/runtime/contract_test.go b/runtime/contract_test.go index 21d2d08540..f242fb59ac 100644 --- a/runtime/contract_test.go +++ b/runtime/contract_test.go @@ -307,6 +307,8 @@ func TestRuntimeContract(t *testing.T) { ) RequireError(t, err) + require.ErrorContains(t, err, "cannot overwrite existing contract") + // the deployed code should not have been updated, // and no events should have been emitted, // as the deployment should fail @@ -448,6 +450,8 @@ func TestRuntimeContract(t *testing.T) { } else { RequireError(t, err) + require.ErrorContains(t, err, "cannot overwrite existing contract") + require.Empty(t, deployedCode) require.Empty(t, events) require.Empty(t, loggedMessages) @@ -473,9 +477,11 @@ func TestRuntimeContract(t *testing.T) { Location: nextTransactionLocation(), }, ) - require.NoError(t, err) + RequireError(t, err) - require.Equal(t, []byte(tc.code2), deployedCode) + require.ErrorContains(t, err, "cannot overwrite existing contract") + + require.Empty(t, deployedCode) require.Equal(t, []string{ @@ -484,20 +490,18 @@ func TestRuntimeContract(t *testing.T) { `"Test"`, codeArrayString, `nil`, - `"Test"`, - code2ArrayString, - `"Test"`, - code2ArrayString, }, loggedMessages, ) - require.Len(t, events, 2) - assert.EqualValues(t, stdlib.AccountContractRemovedEventType.ID(), events[0].Type().ID()) - assert.EqualValues(t, stdlib.AccountContractAddedEventType.ID(), events[1].Type().ID()) + require.Len(t, events, 1) + assert.EqualValues(t, + stdlib.AccountContractRemovedEventType.ID(), + events[0].Type().ID(), + ) contractValueExists := getContractValueExists() - + // contract still exists (from previous transaction), if not interface if tc.isInterface { require.False(t, contractValueExists) } else { diff --git a/runtime/contract_update_test.go b/runtime/contract_update_test.go index 0bb7509449..b65ee3c662 100644 --- a/runtime/contract_update_test.go +++ b/runtime/contract_update_test.go @@ -29,7 +29,7 @@ import ( "github.com/onflow/cadence/encoding/json" "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/interpreter" - "github.com/onflow/cadence/runtime/tests/utils" + . "github.com/onflow/cadence/runtime/tests/utils" ) func TestContractUpdateWithDependencies(t *testing.T) { @@ -142,7 +142,7 @@ func TestContractUpdateWithDependencies(t *testing.T) { err := runtime.ExecuteTransaction( Script{ - Source: utils.DeploymentTransaction( + Source: DeploymentTransaction( "Foo", []byte(fooContractV1), ), @@ -163,7 +163,7 @@ func TestContractUpdateWithDependencies(t *testing.T) { err = runtime.ExecuteTransaction( Script{ - Source: utils.DeploymentTransaction( + Source: DeploymentTransaction( "Bar", []byte(barContractV1), ), @@ -235,3 +235,105 @@ func TestContractUpdateWithDependencies(t *testing.T) { ) require.NoError(t, err) } + +func TestRuntimeInvalidContractRedeploy(t *testing.T) { + + t.Parallel() + + foo1 := []byte(` + access(all) + contract Foo { + + access(all) + resource R { + + access(all) + var x: Int + + init() { + self.x = 0 + } + } + + access(all) + fun createR(): @R { + return <-create R() + } + } + `) + + foo2 := []byte(` + access(all) + contract Foo { + + access(all) + struct R { + access(all) + var x: Int + + init() { + self.x = 0 + } + } + } + `) + + tx := []byte(` + transaction(foo1: String, foo2: String) { + prepare(signer: AuthAccount) { + signer.contracts.add(name: "Foo", code: foo1.utf8) + signer.contracts.add(name: "Foo", code: foo2.utf8) + } + } + `) + + runtime := newTestInterpreterRuntime() + runtime.defaultConfig.AtreeValidationEnabled = false + + address := common.MustBytesToAddress([]byte{0x1}) + + var events []cadence.Event + + runtimeInterface := &testRuntimeInterface{ + storage: newTestLedger(nil, nil), + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil + }, + getAccountContractCode: func(location common.AddressLocation) ([]byte, error) { + return nil, nil + }, + resolveLocation: singleIdentifierLocationResolver(t), + updateAccountContractCode: func(location common.AddressLocation, code []byte) error { + // "delay" + return nil + }, + emitEvent: func(event cadence.Event) error { + events = append(events, event) + return nil + }, + decodeArgument: func(b []byte, t cadence.Type) (value cadence.Value, err error) { + return json.Decode(nil, b) + }, + } + + nextTransactionLocation := newTransactionLocationGenerator() + + // Deploy + + err := runtime.ExecuteTransaction( + Script{ + Source: tx, + Arguments: encodeArgs([]cadence.Value{ + cadence.String(foo1), + cadence.String(foo2), + }), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + RequireError(t, err) + + require.ErrorContains(t, err, "cannot overwrite existing contract") +} diff --git a/runtime/environment.go b/runtime/environment.go index daa4e5440f..df4b5e8f7b 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -340,6 +340,10 @@ func (e *interpreterEnvironment) RecordContractUpdate( e.storage.recordContractUpdate(location, contractValue) } +func (e *interpreterEnvironment) ContractUpdateRecorded(location common.AddressLocation) bool { + return e.storage.contractUpdateRecorded(location) +} + func (e *interpreterEnvironment) TemporarilyRecordCode(location common.AddressLocation, code []byte) { e.codesAndPrograms.setCode(location, code) } diff --git a/runtime/stdlib/account.go b/runtime/stdlib/account.go index 1577c34c9e..2437f40be7 100644 --- a/runtime/stdlib/account.go +++ b/runtime/stdlib/account.go @@ -1431,7 +1431,11 @@ type AccountContractAdditionHandler interface { ) (*interpreter.Program, error) // UpdateAccountContractCode updates the code associated with an account contract. UpdateAccountContractCode(location common.AddressLocation, code []byte) error - RecordContractUpdate(location common.AddressLocation, value *interpreter.CompositeValue) + RecordContractUpdate( + location common.AddressLocation, + value *interpreter.CompositeValue, + ) + ContractUpdateRecorded(location common.AddressLocation) bool InterpretContract( location common.AddressLocation, program *interpreter.Program, @@ -1514,9 +1518,10 @@ func newAuthAccountContractsChangeFunction( } else { // We are adding a new contract. - // Ensure that no contract/contract interface with the given name exists already + // Ensure that no contract/contract interface with the given name exists already, + // and no contract deploy or update was recorded before - if len(existingCode) > 0 { + if len(existingCode) > 0 || handler.ContractUpdateRecorded(location) { panic(errors.NewDefaultUserError( "cannot overwrite existing contract with name %q in account %s", contractName, diff --git a/runtime/storage.go b/runtime/storage.go index dd4618a747..965e3c6720 100644 --- a/runtime/storage.go +++ b/runtime/storage.go @@ -175,6 +175,17 @@ func (s *Storage) recordContractUpdate( s.contractUpdates.Set(key, contractValue) } +func (s *Storage) contractUpdateRecorded( + location common.AddressLocation, +) bool { + if s.contractUpdates == nil { + return false + } + + key := interpreter.NewStorageKey(s.memoryGauge, location.Address, location.Name) + return s.contractUpdates.Contains(key) +} + type ContractUpdate struct { ContractValue *interpreter.CompositeValue Key interpreter.StorageKey From c9089c8feac3f30486d75c3052e9973c3581b511 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Thu, 5 Oct 2023 10:04:00 -0400 Subject: [PATCH 46/47] set base during attachment iteration --- runtime/interpreter/interpreter_statement.go | 2 +- runtime/interpreter/value.go | 10 +++--- runtime/tests/interpreter/attachments_test.go | 34 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/runtime/interpreter/interpreter_statement.go b/runtime/interpreter/interpreter_statement.go index 59d249c796..5d7f4a6862 100644 --- a/runtime/interpreter/interpreter_statement.go +++ b/runtime/interpreter/interpreter_statement.go @@ -473,7 +473,7 @@ func (interpreter *Interpreter) VisitRemoveStatement(removeStatement *ast.Remove if attachment.IsResourceKinded(interpreter) { // this attachment is no longer attached to its base, but the `base` variable is still available in the destructor - attachment.setBaseValue(interpreter, base, attachmentBaseAuthorization(interpreter, attachment)) + attachment.setBaseValue(interpreter, base) attachment.Destroy(interpreter, locationRange) } diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index e1a60855df..a8c91a7d18 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -16513,7 +16513,7 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio // is a necessary pre-requisite for calling any members of the attachment. However, in // the case of a destructor, this is called implicitly, and thus must have its `base` // set manually - attachment.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, attachment)) + attachment.setBaseValue(interpreter, v) attachment.Destroy(interpreter, locationRange) }) @@ -17276,7 +17276,7 @@ func (v *CompositeValue) Transfer( if compositeValue, ok := value.(*CompositeValue); ok && compositeValue.Kind == common.CompositeKindAttachment { - compositeValue.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, compositeValue)) + compositeValue.setBaseValue(interpreter, v) } value = value.Transfer( @@ -17594,7 +17594,7 @@ func (v *CompositeValue) getBaseValue() *EphemeralReferenceValue { return v.base } -func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeValue, authorization Authorization) { +func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeValue) { attachmentType, ok := interpreter.MustSemaTypeOfValue(v).(*sema.CompositeType) if !ok { panic(errors.NewUnreachableError()) @@ -17608,6 +17608,7 @@ func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeV baseType = ty } + authorization := attachmentBaseAuthorization(interpreter, v) v.base = NewEphemeralReferenceValue(interpreter, authorization, base, baseType) interpreter.trackReferencedResourceKindedValue(base.StorageID(), base) } @@ -17762,6 +17763,7 @@ func (v *CompositeValue) forEachAttachment(interpreter *Interpreter, _ LocationR // attachments is added that takes a `fun (&Attachment): Void` callback, the `f` provided here // should convert the provided attachment value into a reference before passing it to the user // callback + attachment.setBaseValue(interpreter, v) f(attachment) } } @@ -17779,7 +17781,7 @@ func (v *CompositeValue) getTypeKey( } attachmentType := keyType.(*sema.CompositeType) // dynamically set the attachment's base to this composite, but with authorization based on the requested access on that attachment - attachment.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, attachment)) + attachment.setBaseValue(interpreter, v) // Map the entitlements of the accessing reference through the attachment's entitlement map to get the authorization of this reference attachmentReferenceAuth, err := attachmentReferenceAuthorization(interpreter, attachmentType, baseAccess) diff --git a/runtime/tests/interpreter/attachments_test.go b/runtime/tests/interpreter/attachments_test.go index 27d1b89818..6d6d4ccc92 100644 --- a/runtime/tests/interpreter/attachments_test.go +++ b/runtime/tests/interpreter/attachments_test.go @@ -2237,6 +2237,40 @@ func TestInterpretMutationDuringForEachAttachment(t *testing.T) { AssertValuesEqual(t, inter, interpreter.NewUnmeteredIntValueFromInt64(3), value) }) + + t.Run("callback", func(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + access(all) resource R { + let foo: Int + init() { + self.foo = 9 + } + } + access(all) attachment A for R { + access(all) fun touchBase(): Int { + var foo = base.foo + return foo + } + } + access(all) fun main(): Int { + var r <- attach A() to <- create R() + var id: Int = 0 + r.forEachAttachment(fun(a: &AnyResourceAttachment) { + id = (a as! &A).touchBase() + }); + destroy r + return id + } + `) + + value, err := inter.Invoke("main") + require.NoError(t, err) + + AssertValuesEqual(t, inter, interpreter.NewUnmeteredIntValueFromInt64(9), value) + }) } func TestInterpretBuiltinCompositeAttachment(t *testing.T) { From ce7bc999cb09592a2f024bad38e010e968c544cf Mon Sep 17 00:00:00 2001 From: turbolent Date: Thu, 5 Oct 2023 20:56:11 +0000 Subject: [PATCH 47/47] v0.42.0 --- npm-packages/cadence-parser/package.json | 2 +- version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-packages/cadence-parser/package.json b/npm-packages/cadence-parser/package.json index 4bc2b2b221..73b0b9de55 100644 --- a/npm-packages/cadence-parser/package.json +++ b/npm-packages/cadence-parser/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/cadence-parser", - "version": "0.41.1", + "version": "0.42.0", "description": "The Cadence parser", "homepage": "https://github.com/onflow/cadence", "repository": { diff --git a/version.go b/version.go index e9056ef2c4..9ee7be9668 100644 --- a/version.go +++ b/version.go @@ -21,4 +21,4 @@ package cadence -const Version = "v0.41.1" +const Version = "v0.42.0"