diff --git a/.github/workflows/compatibility-check-template.yml b/.github/workflows/compatibility-check-template.yml index d406cc9db7..85879a62d3 100644 --- a/.github/workflows/compatibility-check-template.yml +++ b/.github/workflows/compatibility-check-template.yml @@ -113,6 +113,5 @@ jobs: # Check Diff - name: Check diff - working-directory: ./tools/compatibility-check run: | - go run ./cmd/check_diff/main.go ../../tmp/output-old.txt ../../tmp/output-new.txt + diff -u --color ./tmp/output-old.txt ./tmp/output-new.txt diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..e1e9f669d4 --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +Bastian Müller +Bastian Müller diff --git a/go.mod b/go.mod index 871f5a0563..b17a06a98c 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c github.com/go-test/deep v1.1.0 github.com/leanovate/gopter v0.2.9 - github.com/onflow/atree v0.6.1-0.20230629205511-5b7b45a566a9 + github.com/onflow/atree v0.6.1-0.20230629202201-116c95986e54 github.com/rivo/uniseg v0.4.4 github.com/schollz/progressbar/v3 v3.13.1 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 84e854a294..c126efb53f 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3px github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/onflow/atree v0.6.1-0.20230629205511-5b7b45a566a9 h1:mffWKRKGrBq5NhCWplOox33eW+gf2lcgjvdI8aeCjGk= -github.com/onflow/atree v0.6.1-0.20230629205511-5b7b45a566a9/go.mod h1:7YNAyCd5JENq+NzH+fR1ABUZVzbSq9dkt0+5fZH3L2A= +github.com/onflow/atree v0.6.1-0.20230629202201-116c95986e54 h1:sYpk0UK7vHH907N3c/OIjrUq2PKtU7CcTi2O9YvKIYs= +github.com/onflow/atree v0.6.1-0.20230629202201-116c95986e54/go.mod h1:7YNAyCd5JENq+NzH+fR1ABUZVzbSq9dkt0+5fZH3L2A= 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= diff --git a/runtime/ast/access.go b/runtime/ast/access.go index 014ff7e290..5105375114 100644 --- a/runtime/ast/access.go +++ b/runtime/ast/access.go @@ -21,6 +21,7 @@ package ast import ( "encoding/json" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/errors" ) @@ -58,9 +59,12 @@ var BasicAccesses = []Access{ AccessPublicSettable, } -var AllAccesses = append(BasicAccesses[:], - AccessContract, - AccessAccount, +var AllAccesses = common.Concat( + BasicAccesses, + []Access{ + AccessContract, + AccessAccount, + }, ) func (a Access) Keyword() string { diff --git a/runtime/common/concat.go b/runtime/common/concat.go new file mode 100644 index 0000000000..40034c3025 --- /dev/null +++ b/runtime/common/concat.go @@ -0,0 +1,36 @@ +/* + * 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 common + +func Concat[T any](slices ...[]T) []T { + var length int + + for _, slice := range slices { + length += len(slice) + } + + result := make([]T, length) + + var offset int + for _, slice := range slices { + offset += copy(result[offset:], slice) + } + + return result +} diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 3791f68676..d463ef1c5f 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -239,7 +239,7 @@ type Storage interface { CheckHealth() error } -type ReferencedResourceKindedValues map[atree.StorageID]map[ReferenceTrackedResourceKindedValue]struct{} +type ReferencedResourceKindedValues map[atree.ID]map[ReferenceTrackedResourceKindedValue]struct{} type Interpreter struct { Location common.Location @@ -5100,12 +5100,12 @@ func (interpreter *Interpreter) ValidateAtreeValue(value atree.Value) { func (interpreter *Interpreter) maybeTrackReferencedResourceKindedValue(value Value) { if value, ok := value.(ReferenceTrackedResourceKindedValue); ok { - interpreter.trackReferencedResourceKindedValue(value.StorageID(), value) + interpreter.trackReferencedResourceKindedValue(value.ID(), value) } } func (interpreter *Interpreter) trackReferencedResourceKindedValue( - id atree.StorageID, + id atree.ID, value ReferenceTrackedResourceKindedValue, ) { values := interpreter.SharedState.referencedResourceKindedValues[id] @@ -5117,20 +5117,20 @@ func (interpreter *Interpreter) trackReferencedResourceKindedValue( } func (interpreter *Interpreter) updateReferencedResource( - currentStorageID atree.StorageID, - newStorageID atree.StorageID, + currentID atree.ID, + newID atree.ID, updateFunc func(value ReferenceTrackedResourceKindedValue), ) { - values := interpreter.SharedState.referencedResourceKindedValues[currentStorageID] + values := interpreter.SharedState.referencedResourceKindedValues[currentID] if values == nil { return } for value := range values { //nolint:maprange updateFunc(value) } - if newStorageID != currentStorageID { - interpreter.SharedState.referencedResourceKindedValues[newStorageID] = values - interpreter.SharedState.referencedResourceKindedValues[currentStorageID] = nil + if newID != currentID { + interpreter.SharedState.referencedResourceKindedValues[newID] = values + interpreter.SharedState.referencedResourceKindedValues[currentID] = nil } } @@ -5377,8 +5377,8 @@ func (interpreter *Interpreter) idCapabilityCheckFunction( ) } -func (interpreter *Interpreter) validateMutation(storageID atree.StorageID, locationRange LocationRange) { - _, present := interpreter.SharedState.containerValueIteration[storageID] +func (interpreter *Interpreter) validateMutation(id atree.ID, locationRange LocationRange) { + _, present := interpreter.SharedState.containerValueIteration[id] if !present { return } @@ -5387,32 +5387,32 @@ func (interpreter *Interpreter) validateMutation(storageID atree.StorageID, loca }) } -func (interpreter *Interpreter) withMutationPrevention(storageID atree.StorageID, f func()) { - oldIteration, present := interpreter.SharedState.containerValueIteration[storageID] - interpreter.SharedState.containerValueIteration[storageID] = struct{}{} +func (interpreter *Interpreter) withMutationPrevention(id atree.ID, f func()) { + oldIteration, present := interpreter.SharedState.containerValueIteration[id] + interpreter.SharedState.containerValueIteration[id] = struct{}{} f() if !present { - delete(interpreter.SharedState.containerValueIteration, storageID) + delete(interpreter.SharedState.containerValueIteration, id) } else { - interpreter.SharedState.containerValueIteration[storageID] = oldIteration + interpreter.SharedState.containerValueIteration[id] = oldIteration } } func (interpreter *Interpreter) withResourceDestruction( - storageID atree.StorageID, + id atree.ID, locationRange LocationRange, f func(), ) { - _, exists := interpreter.SharedState.destroyedResources[storageID] + _, exists := interpreter.SharedState.destroyedResources[id] if exists { panic(DestroyedResourceError{ LocationRange: locationRange, }) } - interpreter.SharedState.destroyedResources[storageID] = struct{}{} + interpreter.SharedState.destroyedResources[id] = struct{}{} f() } diff --git a/runtime/interpreter/interpreter_expression.go b/runtime/interpreter/interpreter_expression.go index fc49fd6ed3..60fff757a6 100644 --- a/runtime/interpreter/interpreter_expression.go +++ b/runtime/interpreter/interpreter_expression.go @@ -937,7 +937,7 @@ func (interpreter *Interpreter) visitInvocationExpressionWithImplicitArgument(in if boundFunction, ok := function.(BoundFunctionValue); ok && boundFunction.Self != nil { self := *boundFunction.Self if resource, ok := self.(ReferenceTrackedResourceKindedValue); ok { - storageID := resource.StorageID() + storageID := resource.ID() interpreter.trackReferencedResourceKindedValue(storageID, resource) } } @@ -1290,7 +1290,7 @@ func (interpreter *Interpreter) VisitAttachExpression(attachExpression *ast.Atta base, interpreter.MustSemaTypeOfValue(base).(*sema.CompositeType), ) - interpreter.trackReferencedResourceKindedValue(base.StorageID(), base) + interpreter.trackReferencedResourceKindedValue(base.ID(), base) attachment, ok := interpreter.visitInvocationExpressionWithImplicitArgument( attachExpression.Attachment, @@ -1302,7 +1302,7 @@ func (interpreter *Interpreter) VisitAttachExpression(attachExpression *ast.Atta } // Because `self` in attachments is a reference, we need to track the attachment if it's a resource - interpreter.trackReferencedResourceKindedValue(attachment.StorageID(), attachment) + interpreter.trackReferencedResourceKindedValue(attachment.ID(), attachment) base = base.Transfer( interpreter, diff --git a/runtime/interpreter/sharedstate.go b/runtime/interpreter/sharedstate.go index f250ce3f58..02800016cd 100644 --- a/runtime/interpreter/sharedstate.go +++ b/runtime/interpreter/sharedstate.go @@ -43,8 +43,8 @@ type SharedState struct { storageMutatedDuringIteration bool CapabilityControllerIterations map[AddressPath]int MutationDuringCapabilityControllerIteration bool - containerValueIteration map[atree.StorageID]struct{} - destroyedResources map[atree.StorageID]struct{} + containerValueIteration map[atree.ID]struct{} + destroyedResources map[atree.ID]struct{} } func NewSharedState(config *Config) *SharedState { @@ -59,11 +59,11 @@ func NewSharedState(config *Config) *SharedState { }, inStorageIteration: false, storageMutatedDuringIteration: false, - referencedResourceKindedValues: map[atree.StorageID]map[ReferenceTrackedResourceKindedValue]struct{}{}, + referencedResourceKindedValues: map[atree.ID]map[ReferenceTrackedResourceKindedValue]struct{}{}, resourceVariables: map[ResourceKindedValue]*Variable{}, CapabilityControllerIterations: map[AddressPath]int{}, - containerValueIteration: map[atree.StorageID]struct{}{}, - destroyedResources: map[atree.StorageID]struct{}{}, + containerValueIteration: map[atree.ID]struct{}{}, + destroyedResources: map[atree.ID]struct{}{}, } } diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index fd85c90010..a4d6bbfbd7 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -217,7 +217,7 @@ func maybeDestroy(interpreter *Interpreter, locationRange LocationRange, value V type ReferenceTrackedResourceKindedValue interface { ResourceKindedValue IsReferenceTrackedResourceKindedValue() - StorageID() atree.StorageID + ID() atree.ID } // ContractValue is the value of a contract. @@ -1717,7 +1717,7 @@ func (v *ArrayValue) Iterate(interpreter *Interpreter, f func(element Value) (re } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.StorageID(), iterate) + interpreter.withMutationPrevention(v.ID(), iterate) } else { iterate() } @@ -1784,10 +1784,10 @@ func (v *ArrayValue) Destroy(interpreter *Interpreter, locationRange LocationRan }() } - storageID := v.StorageID() + id := v.ID() interpreter.withResourceDestruction( - storageID, + id, locationRange, func() { v.Walk(interpreter, func(element Value) { @@ -1803,8 +1803,8 @@ func (v *ArrayValue) Destroy(interpreter *Interpreter, locationRange LocationRan } interpreter.updateReferencedResource( - storageID, - storageID, + id, + id, func(value ReferenceTrackedResourceKindedValue) { arrayValue, ok := value.(*ArrayValue) if !ok { @@ -1948,7 +1948,7 @@ func (v *ArrayValue) SetKey(interpreter *Interpreter, locationRange LocationRang func (v *ArrayValue) Set(interpreter *Interpreter, locationRange LocationRange, index int, element Value) { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Set function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2022,7 +2022,7 @@ func (v *ArrayValue) MeteredString(memoryGauge common.MemoryGauge, seenReference func (v *ArrayValue) Append(interpreter *Interpreter, locationRange LocationRange, element Value) { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) // length increases by 1 dataSlabs, metaDataSlabs := common.AdditionalAtreeMemoryUsage( @@ -2070,7 +2070,7 @@ func (v *ArrayValue) InsertKey(interpreter *Interpreter, locationRange LocationR func (v *ArrayValue) Insert(interpreter *Interpreter, locationRange LocationRange, index int, element Value) { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Insert function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2125,7 +2125,7 @@ func (v *ArrayValue) RemoveKey(interpreter *Interpreter, locationRange LocationR func (v *ArrayValue) Remove(interpreter *Interpreter, locationRange LocationRange, index int) Value { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) // We only need to check the lower bound before converting from `int` (signed) to `uint64` (unsigned). // atree's Array.Remove function will check the upper bound and report an atree.IndexOutOfBoundsError @@ -2540,8 +2540,12 @@ func (v *ArrayValue) Equal(interpreter *Interpreter, locationRange LocationRange return true } -func (v *ArrayValue) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { - return atree.StorageIDStorable(v.StorageID()), nil +func (v *ArrayValue) Storable( + storage atree.SlabStorage, + address atree.Address, + maxInlineSize uint64, +) (atree.Storable, error) { + return v.array.Storable(storage, address, maxInlineSize) } func (v *ArrayValue) IsReferenceTrackedResourceKindedValue() {} @@ -2582,12 +2586,11 @@ func (v *ArrayValue) Transfer( }() } - currentStorageID := v.StorageID() - currentAddress := currentStorageID.Address + currentID := v.ID() array := v.array - needsStoreTo := address != currentAddress + needsStoreTo := v.NeedsStoreTo(address) isResourceKinded := v.IsResourceKinded(interpreter) if needsStoreTo || !isResourceKinded { @@ -2652,11 +2655,11 @@ func (v *ArrayValue) Transfer( res = v } - newStorageID := array.StorageID() + newID := array.ID() interpreter.updateReferencedResource( - currentStorageID, - newStorageID, + currentID, + newID, func(value ReferenceTrackedResourceKindedValue) { arrayValue, ok := value.(*ArrayValue) if !ok { @@ -2694,7 +2697,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() @@ -2760,8 +2763,16 @@ func (v *ArrayValue) StorageID() atree.StorageID { return v.array.StorageID() } +func (v *ArrayValue) StorageAddress() atree.Address { + return v.array.Address() +} + +func (v *ArrayValue) ID() atree.ID { + return v.array.ID() +} + func (v *ArrayValue) GetOwner() common.Address { - return common.Address(v.StorageID().Address) + return common.Address(v.StorageAddress()) } func (v *ArrayValue) SemaType(interpreter *Interpreter) sema.ArrayType { @@ -2773,7 +2784,7 @@ func (v *ArrayValue) SemaType(interpreter *Interpreter) sema.ArrayType { } func (v *ArrayValue) NeedsStoreTo(address atree.Address) bool { - return address != v.StorageID().Address + return address != v.StorageAddress() } func (v *ArrayValue) IsResourceKinded(interpreter *Interpreter) bool { @@ -2921,11 +2932,7 @@ func getNumberValueMember(interpreter *Interpreter, v NumberValue, name string, case sema.NumericTypeSaturatingAddFunctionName: return NewHostFunctionValue( interpreter, - &sema.FunctionType{ - ReturnTypeAnnotation: sema.NewTypeAnnotation( - typ, - ), - }, + sema.SaturatingArithmeticTypeFunctionTypes[typ], func(invocation Invocation) Value { other, ok := invocation.Arguments[0].(NumberValue) if !ok { @@ -2942,11 +2949,7 @@ func getNumberValueMember(interpreter *Interpreter, v NumberValue, name string, case sema.NumericTypeSaturatingSubtractFunctionName: return NewHostFunctionValue( interpreter, - &sema.FunctionType{ - ReturnTypeAnnotation: sema.NewTypeAnnotation( - typ, - ), - }, + sema.SaturatingArithmeticTypeFunctionTypes[typ], func(invocation Invocation) Value { other, ok := invocation.Arguments[0].(NumberValue) if !ok { @@ -2963,11 +2966,7 @@ func getNumberValueMember(interpreter *Interpreter, v NumberValue, name string, case sema.NumericTypeSaturatingMultiplyFunctionName: return NewHostFunctionValue( interpreter, - &sema.FunctionType{ - ReturnTypeAnnotation: sema.NewTypeAnnotation( - typ, - ), - }, + sema.SaturatingArithmeticTypeFunctionTypes[typ], func(invocation Invocation) Value { other, ok := invocation.Arguments[0].(NumberValue) if !ok { @@ -2984,11 +2983,7 @@ func getNumberValueMember(interpreter *Interpreter, v NumberValue, name string, case sema.NumericTypeSaturatingDivideFunctionName: return NewHostFunctionValue( interpreter, - &sema.FunctionType{ - ReturnTypeAnnotation: sema.NewTypeAnnotation( - typ, - ), - }, + sema.SaturatingArithmeticTypeFunctionTypes[typ], func(invocation Invocation) Value { other, ok := invocation.Arguments[0].(NumberValue) if !ok { @@ -15373,10 +15368,10 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio }() } - storageID := v.StorageID() + id := v.ID() interpreter.withResourceDestruction( - storageID, + id, locationRange, func() { // if this type has attachments, destroy all of them before invoking the destructor @@ -15428,8 +15423,8 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio } interpreter.updateReferencedResource( - storageID, - storageID, + id, + id, func(value ReferenceTrackedResourceKindedValue) { compositeValue, ok := value.(*CompositeValue) if !ok { @@ -15583,7 +15578,7 @@ func (v *CompositeValue) InitializeFunctions(interpreter *Interpreter) { } func (v *CompositeValue) OwnerValue(interpreter *Interpreter, locationRange LocationRange) OptionalValue { - address := v.StorageID().Address + address := v.StorageAddress() if address == (atree.Address{}) { return NilOptionalValue @@ -15695,7 +15690,7 @@ func (v *CompositeValue) SetMember( }() } - address := v.StorageID().Address + address := v.StorageAddress() value = value.Transfer( interpreter, @@ -16022,16 +16017,20 @@ func (v *CompositeValue) IsStorable() bool { return v.Location != nil } -func (v *CompositeValue) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { +func (v *CompositeValue) Storable( + storage atree.SlabStorage, + address atree.Address, + maxInlineSize uint64, +) (atree.Storable, error) { if !v.IsStorable() { return NonStorable{Value: v}, nil } - return atree.StorageIDStorable(v.StorageID()), nil + return v.dictionary.Storable(storage, address, maxInlineSize) } func (v *CompositeValue) NeedsStoreTo(address atree.Address) bool { - return address != v.StorageID().Address + return address != v.StorageAddress() } func (v *CompositeValue) IsResourceKinded(interpreter *Interpreter) bool { @@ -16082,12 +16081,12 @@ func (v *CompositeValue) Transfer( }() } - currentStorageID := v.StorageID() - currentAddress := currentStorageID.Address + currentID := v.ID() + currentAddress := v.StorageAddress() dictionary := v.dictionary - needsStoreTo := address != currentAddress + needsStoreTo := v.NeedsStoreTo(address) isResourceKinded := v.IsResourceKinded(interpreter) if needsStoreTo && v.Kind == common.CompositeKindContract { @@ -16175,11 +16174,11 @@ func (v *CompositeValue) Transfer( res = v } - newStorageID := dictionary.StorageID() + newID := dictionary.ID() interpreter.updateReferencedResource( - currentStorageID, - newStorageID, + currentID, + newID, func(value ReferenceTrackedResourceKindedValue) { compositeValue, ok := value.(*CompositeValue) if !ok { @@ -16250,7 +16249,7 @@ func (v *CompositeValue) Clone(interpreter *Interpreter) Value { dictionary, err := atree.NewMapFromBatchData( config.Storage, - v.StorageID().Address, + v.StorageAddress(), atree.NewDefaultDigesterBuilder(), v.dictionary.Type(), StringAtreeValueComparator, @@ -16337,7 +16336,7 @@ func (v *CompositeValue) DeepRemove(interpreter *Interpreter) { } func (v *CompositeValue) GetOwner() common.Address { - return common.Address(v.StorageID().Address) + return common.Address(v.StorageAddress()) } // ForEachField iterates over all field-name field-value pairs of the composite value. @@ -16360,6 +16359,14 @@ func (v *CompositeValue) StorageID() atree.StorageID { return v.dictionary.StorageID() } +func (v *CompositeValue) StorageAddress() atree.Address { + return v.dictionary.Address() +} + +func (v *CompositeValue) ID() atree.ID { + return v.dictionary.ID() +} + func (v *CompositeValue) RemoveField( interpreter *Interpreter, _ LocationRange, @@ -16447,7 +16454,7 @@ func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeV // the base reference can only be borrowed with the declared type of the attachment's base v.base = NewEphemeralReferenceValue(interpreter, false, base, baseType) - interpreter.trackReferencedResourceKindedValue(base.StorageID(), base) + interpreter.trackReferencedResourceKindedValue(base.ID(), base) } func attachmentMemberName(ty sema.Type) string { @@ -16477,7 +16484,7 @@ func attachmentBaseAndSelfValues( base = v.getBaseValue(interpreter, locationRange) // in attachment functions, self is a reference value self = NewEphemeralReferenceValue(interpreter, false, v, interpreter.MustSemaTypeOfValue(v)) - interpreter.trackReferencedResourceKindedValue(v.StorageID(), v) + interpreter.trackReferencedResourceKindedValue(v.ID(), v) return } @@ -16528,7 +16535,7 @@ func (v *CompositeValue) GetTypeKey( attachment.setBaseValue(interpreter, v) attachmentRef := NewEphemeralReferenceValue(interpreter, false, attachment, ty) - interpreter.trackReferencedResourceKindedValue(attachment.StorageID(), attachment) + interpreter.trackReferencedResourceKindedValue(attachment.ID(), attachment) return NewSomeValueNonCopying(interpreter, attachmentRef) } @@ -16737,7 +16744,7 @@ func (v *DictionaryValue) Iterate(interpreter *Interpreter, f func(key, value Va } } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.StorageID(), iterate) + interpreter.withMutationPrevention(v.ID(), iterate) } else { iterate() } @@ -16835,10 +16842,10 @@ func (v *DictionaryValue) Destroy(interpreter *Interpreter, locationRange Locati }() } - storageID := v.StorageID() + id := v.ID() interpreter.withResourceDestruction( - storageID, + id, locationRange, func() { v.Iterate(interpreter, func(key, value Value) (resume bool) { @@ -16858,8 +16865,8 @@ func (v *DictionaryValue) Destroy(interpreter *Interpreter, locationRange Locati } interpreter.updateReferencedResource( - storageID, - storageID, + id, + id, func(value ReferenceTrackedResourceKindedValue) { dictionaryValue, ok := value.(*DictionaryValue) if !ok { @@ -16914,7 +16921,7 @@ func (v *DictionaryValue) ForEachKey( } if v.IsResourceKinded(interpreter) { - interpreter.withMutationPrevention(v.StorageID(), iterate) + interpreter.withMutationPrevention(v.ID(), iterate) } else { iterate() } @@ -16986,7 +16993,7 @@ func (v *DictionaryValue) SetKey( keyValue Value, value Value, ) { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) config := interpreter.SharedState.Config @@ -17270,7 +17277,7 @@ func (v *DictionaryValue) Remove( keyValue Value, ) OptionalValue { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) valueComparator := newValueComparator(interpreter, locationRange) hashInputProvider := newHashInputProvider(interpreter, locationRange) @@ -17327,7 +17334,7 @@ func (v *DictionaryValue) Insert( keyValue, value Value, ) OptionalValue { - interpreter.validateMutation(v.StorageID(), locationRange) + interpreter.validateMutation(v.ID(), locationRange) // length increases by 1 dataSlabs, metaDataSlabs := common.AdditionalAtreeMemoryUsage(v.dictionary.Count(), v.elementSize, false) @@ -17531,8 +17538,12 @@ func (v *DictionaryValue) Equal(interpreter *Interpreter, locationRange Location } } -func (v *DictionaryValue) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { - return atree.StorageIDStorable(v.StorageID()), nil +func (v *DictionaryValue) Storable( + storage atree.SlabStorage, + address atree.Address, + maxInlineSize uint64, +) (atree.Storable, error) { + return v.dictionary.Storable(storage, address, maxInlineSize) } func (v *DictionaryValue) IsReferenceTrackedResourceKindedValue() {} @@ -17576,12 +17587,10 @@ func (v *DictionaryValue) Transfer( }() } - currentStorageID := v.StorageID() - currentAddress := currentStorageID.Address - + currentID := v.ID() dictionary := v.dictionary - needsStoreTo := address != currentAddress + needsStoreTo := v.NeedsStoreTo(address) isResourceKinded := v.IsResourceKinded(interpreter) if needsStoreTo || !isResourceKinded { @@ -17661,11 +17670,11 @@ func (v *DictionaryValue) Transfer( res = v } - newStorageID := dictionary.StorageID() + newID := dictionary.ID() interpreter.updateReferencedResource( - currentStorageID, - newStorageID, + currentID, + newID, func(value ReferenceTrackedResourceKindedValue) { dictionaryValue, ok := value.(*DictionaryValue) if !ok { @@ -17703,7 +17712,7 @@ func (v *DictionaryValue) Clone(interpreter *Interpreter) Value { dictionary, err := atree.NewMapFromBatchData( config.Storage, - v.StorageID().Address, + v.StorageAddress(), atree.NewDefaultDigesterBuilder(), v.dictionary.Type(), valueComparator, @@ -17781,13 +17790,21 @@ func (v *DictionaryValue) DeepRemove(interpreter *Interpreter) { } func (v *DictionaryValue) GetOwner() common.Address { - return common.Address(v.StorageID().Address) + return common.Address(v.StorageAddress()) } func (v *DictionaryValue) StorageID() atree.StorageID { return v.dictionary.StorageID() } +func (v *DictionaryValue) StorageAddress() atree.Address { + return v.dictionary.Address() +} + +func (v *DictionaryValue) ID() atree.ID { + return v.dictionary.ID() +} + func (v *DictionaryValue) SemaType(interpreter *Interpreter) *sema.DictionaryType { if v.semaType == nil { // this function will panic already if this conversion fails @@ -17797,7 +17814,7 @@ func (v *DictionaryValue) SemaType(interpreter *Interpreter) *sema.DictionaryTyp } func (v *DictionaryValue) NeedsStoreTo(address atree.Address) bool { - return address != v.StorageID().Address + return address != v.StorageAddress() } func (v *DictionaryValue) IsResourceKinded(interpreter *Interpreter) bool { diff --git a/runtime/literal_test.go b/runtime/literal_test.go index 19e1e4b94b..b0f80e8d4e 100644 --- a/runtime/literal_test.go +++ b/runtime/literal_test.go @@ -643,10 +643,12 @@ func TestParseLiteral(t *testing.T) { ) } - for _, signedIntegerType := range append( - sema.AllSignedIntegerTypes[:], - sema.IntegerType, - sema.SignedIntegerType, + for _, signedIntegerType := range common.Concat( + sema.AllSignedIntegerTypes, + []sema.Type{ + sema.IntegerType, + sema.SignedIntegerType, + }, ) { t.Run( diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 2e158dfb56..e2746a10f0 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -913,9 +913,10 @@ const numericTypeSaturatingDivideFunctionDocString = ` self / other, saturating at the numeric bounds instead of overflowing. ` -func addSaturatingArithmeticFunctions(t SaturatingArithmeticType, members map[string]MemberResolver) { +var SaturatingArithmeticTypeFunctionTypes = map[Type]*FunctionType{} - arithmeticFunctionType := &FunctionType{ +func registerSaturatingArithmeticType(t Type) { + SaturatingArithmeticTypeFunctionTypes[t] = &FunctionType{ Parameters: []Parameter{ { Label: ArgumentLabelNotRequired, @@ -925,13 +926,21 @@ func addSaturatingArithmeticFunctions(t SaturatingArithmeticType, members map[st }, ReturnTypeAnnotation: NewTypeAnnotation(t), } +} + +func addSaturatingArithmeticFunctions(t SaturatingArithmeticType, members map[string]MemberResolver) { addArithmeticFunction := func(name string, docString string) { members[name] = MemberResolver{ Kind: common.DeclarationKindFunction, - Resolve: func(memoryGauge common.MemoryGauge, identifier string, targetRange ast.Range, report func(error)) *Member { + Resolve: func(memoryGauge common.MemoryGauge, _ string, _ ast.Range, _ func(error)) *Member { return NewPublicFunctionMember( - memoryGauge, t, name, arithmeticFunctionType, docString) + memoryGauge, + t, + name, + SaturatingArithmeticTypeFunctionTypes[t], + docString, + ) }, } } @@ -965,20 +974,24 @@ func addSaturatingArithmeticFunctions(t SaturatingArithmeticType, members map[st } } +type SaturatingArithmeticSupport struct { + Add bool + Subtract bool + Multiply bool + Divide bool +} + // NumericType represent all the types in the integer range // and non-fractional ranged types. type NumericType struct { - minInt *big.Int - maxInt *big.Int - memberResolvers map[string]MemberResolver - name string - tag TypeTag - memberResolversOnce sync.Once - supportsSaturatingAdd bool - supportsSaturatingSubtract bool - supportsSaturatingMultiply bool - supportsSaturatingDivide bool - isSuperType bool + minInt *big.Int + maxInt *big.Int + memberResolvers map[string]MemberResolver + name string + tag TypeTag + memberResolversOnce sync.Once + saturatingArithmetic SaturatingArithmeticSupport + isSuperType bool } var _ Type = &NumericType{} @@ -1004,40 +1017,28 @@ func (t *NumericType) WithIntRange(min *big.Int, max *big.Int) *NumericType { return t } -func (t *NumericType) WithSaturatingAdd() *NumericType { - t.supportsSaturatingAdd = true - return t -} +func (t *NumericType) WithSaturatingFunctions(saturatingArithmetic SaturatingArithmeticSupport) *NumericType { + t.saturatingArithmetic = saturatingArithmetic -func (t *NumericType) WithSaturatingSubtract() *NumericType { - t.supportsSaturatingSubtract = true - return t -} + registerSaturatingArithmeticType(t) -func (t *NumericType) WithSaturatingMultiply() *NumericType { - t.supportsSaturatingMultiply = true - return t -} - -func (t *NumericType) WithSaturatingDivide() *NumericType { - t.supportsSaturatingDivide = true return t } func (t *NumericType) SupportsSaturatingAdd() bool { - return t.supportsSaturatingAdd + return t.saturatingArithmetic.Add } func (t *NumericType) SupportsSaturatingSubtract() bool { - return t.supportsSaturatingSubtract + return t.saturatingArithmetic.Subtract } func (t *NumericType) SupportsSaturatingMultiply() bool { - return t.supportsSaturatingMultiply + return t.saturatingArithmetic.Multiply } func (t *NumericType) SupportsSaturatingDivide() bool { - return t.supportsSaturatingDivide + return t.saturatingArithmetic.Divide } func (*NumericType) IsType() {} @@ -1143,20 +1144,17 @@ func (t *NumericType) IsSuperType() bool { // FixedPointNumericType represents all the types in the fixed-point range. type FixedPointNumericType struct { - maxFractional *big.Int - minFractional *big.Int - memberResolvers map[string]MemberResolver - minInt *big.Int - maxInt *big.Int - name string - tag TypeTag - scale uint - memberResolversOnce sync.Once - supportsSaturatingAdd bool - supportsSaturatingDivide bool - supportsSaturatingMultiply bool - supportsSaturatingSubtract bool - isSuperType bool + maxFractional *big.Int + minFractional *big.Int + memberResolvers map[string]MemberResolver + minInt *big.Int + maxInt *big.Int + name string + tag TypeTag + scale uint + memberResolversOnce sync.Once + saturatingArithmetic SaturatingArithmeticSupport + isSuperType bool } var _ Type = &FixedPointNumericType{} @@ -1200,40 +1198,28 @@ func (t *FixedPointNumericType) WithScale(scale uint) *FixedPointNumericType { return t } -func (t *FixedPointNumericType) WithSaturatingAdd() *FixedPointNumericType { - t.supportsSaturatingAdd = true - return t -} +func (t *FixedPointNumericType) WithSaturatingFunctions(saturatingArithmetic SaturatingArithmeticSupport) *FixedPointNumericType { + t.saturatingArithmetic = saturatingArithmetic -func (t *FixedPointNumericType) WithSaturatingSubtract() *FixedPointNumericType { - t.supportsSaturatingSubtract = true - return t -} - -func (t *FixedPointNumericType) WithSaturatingMultiply() *FixedPointNumericType { - t.supportsSaturatingMultiply = true - return t -} + registerSaturatingArithmeticType(t) -func (t *FixedPointNumericType) WithSaturatingDivide() *FixedPointNumericType { - t.supportsSaturatingDivide = true return t } func (t *FixedPointNumericType) SupportsSaturatingAdd() bool { - return t.supportsSaturatingAdd + return t.saturatingArithmetic.Add } func (t *FixedPointNumericType) SupportsSaturatingSubtract() bool { - return t.supportsSaturatingSubtract + return t.saturatingArithmetic.Subtract } func (t *FixedPointNumericType) SupportsSaturatingMultiply() bool { - return t.supportsSaturatingMultiply + return t.saturatingArithmetic.Multiply } func (t *FixedPointNumericType) SupportsSaturatingDivide() bool { - return t.supportsSaturatingDivide + return t.saturatingArithmetic.Divide } func (*FixedPointNumericType) IsType() {} @@ -1381,115 +1367,141 @@ var ( Int8Type = NewNumericType(Int8TypeName). WithTag(Int8TypeTag). WithIntRange(Int8TypeMinInt, Int8TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // Int16Type represents the 16-bit signed integer type `Int16` Int16Type = NewNumericType(Int16TypeName). WithTag(Int16TypeTag). WithIntRange(Int16TypeMinInt, Int16TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // Int32Type represents the 32-bit signed integer type `Int32` Int32Type = NewNumericType(Int32TypeName). WithTag(Int32TypeTag). WithIntRange(Int32TypeMinInt, Int32TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // Int64Type represents the 64-bit signed integer type `Int64` Int64Type = NewNumericType(Int64TypeName). WithTag(Int64TypeTag). WithIntRange(Int64TypeMinInt, Int64TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // Int128Type represents the 128-bit signed integer type `Int128` Int128Type = NewNumericType(Int128TypeName). WithTag(Int128TypeTag). WithIntRange(Int128TypeMinIntBig, Int128TypeMaxIntBig). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // Int256Type represents the 256-bit signed integer type `Int256` Int256Type = NewNumericType(Int256TypeName). WithTag(Int256TypeTag). WithIntRange(Int256TypeMinIntBig, Int256TypeMaxIntBig). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // UIntType represents the arbitrary-precision unsigned integer type `UInt` UIntType = NewNumericType(UIntTypeName). WithTag(UIntTypeTag). WithIntRange(UIntTypeMin, nil). - WithSaturatingSubtract() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Subtract: true, + }) // UInt8Type represents the 8-bit unsigned integer type `UInt8` // which checks for overflow and underflow UInt8Type = NewNumericType(UInt8TypeName). WithTag(UInt8TypeTag). WithIntRange(UInt8TypeMinInt, UInt8TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // UInt16Type represents the 16-bit unsigned integer type `UInt16` // which checks for overflow and underflow UInt16Type = NewNumericType(UInt16TypeName). WithTag(UInt16TypeTag). WithIntRange(UInt16TypeMinInt, UInt16TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // UInt32Type represents the 32-bit unsigned integer type `UInt32` // which checks for overflow and underflow UInt32Type = NewNumericType(UInt32TypeName). WithTag(UInt32TypeTag). WithIntRange(UInt32TypeMinInt, UInt32TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // UInt64Type represents the 64-bit unsigned integer type `UInt64` // which checks for overflow and underflow UInt64Type = NewNumericType(UInt64TypeName). WithTag(UInt64TypeTag). WithIntRange(UInt64TypeMinInt, UInt64TypeMaxInt). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // UInt128Type represents the 128-bit unsigned integer type `UInt128` // which checks for overflow and underflow UInt128Type = NewNumericType(UInt128TypeName). WithTag(UInt128TypeTag). WithIntRange(UInt128TypeMinIntBig, UInt128TypeMaxIntBig). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // UInt256Type represents the 256-bit unsigned integer type `UInt256` // which checks for overflow and underflow UInt256Type = NewNumericType(UInt256TypeName). WithTag(UInt256TypeTag). WithIntRange(UInt256TypeMinIntBig, UInt256TypeMaxIntBig). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) // Word8Type represents the 8-bit unsigned integer type `Word8` // which does NOT check for overflow and underflow @@ -1544,10 +1556,12 @@ var ( WithIntRange(Fix64TypeMinIntBig, Fix64TypeMaxIntBig). WithFractionalRange(Fix64TypeMinFractionalBig, Fix64TypeMaxFractionalBig). WithScale(Fix64Scale). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply(). - WithSaturatingDivide() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + Divide: true, + }) // UFix64Type represents the 64-bit unsigned decimal fixed-point type `UFix64` // which has a scale of 1E9, and checks for overflow and underflow @@ -1556,9 +1570,11 @@ var ( WithIntRange(UFix64TypeMinIntBig, UFix64TypeMaxIntBig). WithFractionalRange(UFix64TypeMinFractionalBig, UFix64TypeMaxFractionalBig). WithScale(Fix64Scale). - WithSaturatingAdd(). - WithSaturatingSubtract(). - WithSaturatingMultiply() + WithSaturatingFunctions(SaturatingArithmeticSupport{ + Add: true, + Subtract: true, + Multiply: true, + }) ) // Numeric type ranges @@ -3124,37 +3140,37 @@ var BaseTypeActivation = NewVariableActivation(nil) func init() { - types := AllNumberTypes[:] - - types = append( - types, - MetaType, - VoidType, - AnyStructType, - AnyStructAttachmentType, - AnyResourceType, - AnyResourceAttachmentType, - NeverType, - BoolType, - CharacterType, - StringType, - TheAddressType, - AuthAccountType, - PublicAccountType, - PathType, - StoragePathType, - CapabilityPathType, - PrivatePathType, - PublicPathType, - &CapabilityType{}, - DeployedContractType, - BlockType, - AccountKeyType, - PublicKeyType, - SignatureAlgorithmType, - HashAlgorithmType, - StorageCapabilityControllerType, - AccountCapabilityControllerType, + types := common.Concat( + AllNumberTypes, + []Type{ + MetaType, + VoidType, + AnyStructType, + AnyStructAttachmentType, + AnyResourceType, + AnyResourceAttachmentType, + NeverType, + BoolType, + CharacterType, + StringType, + TheAddressType, + AuthAccountType, + PublicAccountType, + PathType, + StoragePathType, + CapabilityPathType, + PrivatePathType, + PublicPathType, + &CapabilityType{}, + DeployedContractType, + BlockType, + AccountKeyType, + PublicKeyType, + SignatureAlgorithmType, + HashAlgorithmType, + StorageCapabilityControllerType, + AccountCapabilityControllerType, + }, ) for _, ty := range types { @@ -3202,13 +3218,13 @@ var AllUnsignedFixedPointTypes = []Type{ UFix64Type, } -var AllFixedPointTypes = append( - append( - AllUnsignedFixedPointTypes[:], - AllSignedFixedPointTypes..., - ), - FixedPointType, - SignedFixedPointType, +var AllFixedPointTypes = common.Concat( + AllUnsignedFixedPointTypes, + AllSignedFixedPointTypes, + []Type{ + FixedPointType, + SignedFixedPointType, + }, ) var AllSignedIntegerTypes = []Type{ @@ -3239,22 +3255,22 @@ var AllUnsignedIntegerTypes = []Type{ Word256Type, } -var AllIntegerTypes = append( - append( - AllUnsignedIntegerTypes[:], - AllSignedIntegerTypes..., - ), - IntegerType, - SignedIntegerType, +var AllIntegerTypes = common.Concat( + AllUnsignedIntegerTypes, + AllSignedIntegerTypes, + []Type{ + IntegerType, + SignedIntegerType, + }, ) -var AllNumberTypes = append( - append( - AllIntegerTypes[:], - AllFixedPointTypes..., - ), - NumberType, - SignedNumberType, +var AllNumberTypes = common.Concat( + AllIntegerTypes, + AllFixedPointTypes, + []Type{ + NumberType, + SignedNumberType, + }, ) const NumberTypeMinFieldName = "min" @@ -3794,6 +3810,15 @@ func (t *CompositeType) ID() TypeID { return t.cachedIdentifiers.TypeID } +// clearCachedIdentifiers clears cachedIdentifiers. +// This function currently is only used in tests. +func (t *CompositeType) clearCachedIdentifiers() { + t.cachedIdentifiersLock.Lock() + defer t.cachedIdentifiersLock.Unlock() + + t.cachedIdentifiers = nil +} + func (t *CompositeType) initializeIdentifiers() { t.cachedIdentifiersLock.Lock() defer t.cachedIdentifiersLock.Unlock() @@ -4382,6 +4407,15 @@ func (t *InterfaceType) checkIdentifiersCached() { } } +// clearCachedIdentifiers clears cachedIdentifiers. +// This function currently is only used in tests. +func (t *InterfaceType) clearCachedIdentifiers() { + t.cachedIdentifiersLock.Lock() + defer t.cachedIdentifiersLock.Unlock() + + t.cachedIdentifiers = nil +} + func (t *InterfaceType) GetCompositeKind() common.CompositeKind { return t.CompositeKind } diff --git a/runtime/sema/type_test.go b/runtime/sema/type_test.go index 0e27d87bba..3233d9c323 100644 --- a/runtime/sema/type_test.go +++ b/runtime/sema/type_test.go @@ -631,23 +631,23 @@ func TestIdentifierCacheUpdate(t *testing.T) { t.Parallel() code := ` - pub contract interface Test { + contract interface Test { - pub struct interface NestedInterface { - pub fun test(): Bool - } - - pub struct Nested: NestedInterface {} + struct interface NestedInterface { + pub fun test(): Bool } - pub contract TestImpl { + struct Nested: NestedInterface {} + } - pub struct Nested { - pub fun test(): Bool { - return true - } + contract TestImpl { + + struct Nested { + fun test(): Bool { + return true } } + } ` program, err := parser.ParseProgram(nil, []byte(code), parser.Config{}) @@ -658,7 +658,7 @@ func TestIdentifierCacheUpdate(t *testing.T) { common.StringLocation("test"), nil, &Config{ - AccessCheckMode: AccessCheckModeStrict, + AccessCheckMode: AccessCheckModeNotSpecifiedUnrestricted, }, ) require.NoError(t, err) @@ -666,8 +666,10 @@ func TestIdentifierCacheUpdate(t *testing.T) { err = checker.Check() require.NoError(t, err) + var typeIDs []common.TypeID + checker.typeActivations.ForEachVariableDeclaredInAndBelow( - 0, + checker.valueActivations.Depth(), func(_ string, value *Variable) { typ := value.Type @@ -690,7 +692,7 @@ func TestIdentifierCacheUpdate(t *testing.T) { cachedID := semaType.ID() // clear cached identifiers for one level - semaType.cachedIdentifiers = nil + semaType.clearCachedIdentifiers() recalculatedQualifiedID := semaType.QualifiedIdentifier() recalculatedID := semaType.ID() @@ -698,6 +700,8 @@ func TestIdentifierCacheUpdate(t *testing.T) { assert.Equal(t, recalculatedQualifiedID, cachedQualifiedID) assert.Equal(t, recalculatedID, cachedID) + typeIDs = append(typeIDs, recalculatedID) + // Recursively check for nested types checkNestedTypes(semaType.NestedTypes) @@ -706,7 +710,7 @@ func TestIdentifierCacheUpdate(t *testing.T) { cachedID := semaType.ID() // clear cached identifiers for one level - semaType.cachedIdentifiers = nil + semaType.clearCachedIdentifiers() recalculatedQualifiedID := semaType.QualifiedIdentifier() recalculatedID := semaType.ID() @@ -714,13 +718,28 @@ func TestIdentifierCacheUpdate(t *testing.T) { assert.Equal(t, recalculatedQualifiedID, cachedQualifiedID) assert.Equal(t, recalculatedID, cachedID) + typeIDs = append(typeIDs, recalculatedID) + // Recursively check for nested types checkNestedTypes(semaType.NestedTypes) } } checkIdentifiers(t, typ) - }) + }, + ) + + assert.Equal(t, + []common.TypeID{ + "S.test.Test", + "S.test.Test.NestedInterface", + "S.test.Test.Nested", + "S.test.TestImpl", + "S.test.TestImpl.Nested", + }, + typeIDs, + ) + } func TestCommonSuperType(t *testing.T) { diff --git a/runtime/tests/checker/builtinfunctions_test.go b/runtime/tests/checker/builtinfunctions_test.go index 4d38f49938..bf8c135c41 100644 --- a/runtime/tests/checker/builtinfunctions_test.go +++ b/runtime/tests/checker/builtinfunctions_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/sema" ) @@ -32,9 +33,11 @@ func TestCheckToString(t *testing.T) { t.Parallel() - for _, numberOrAddressType := range append( - sema.AllNumberTypes[:], - sema.TheAddressType, + for _, numberOrAddressType := range common.Concat( + sema.AllNumberTypes, + []sema.Type{ + sema.TheAddressType, + }, ) { ty := numberOrAddressType diff --git a/runtime/tests/checker/events_test.go b/runtime/tests/checker/events_test.go index 4ad1b2b798..2dc3b87258 100644 --- a/runtime/tests/checker/events_test.go +++ b/runtime/tests/checker/events_test.go @@ -107,7 +107,8 @@ func TestCheckEventDeclaration(t *testing.T) { t.Parallel() - validTypes := append( + validTypes := common.Concat( + sema.AllNumberTypes, []sema.Type{ sema.StringType, sema.CharacterType, @@ -120,7 +121,6 @@ func TestCheckEventDeclaration(t *testing.T) { sema.PrivatePathType, sema.CapabilityPathType, }, - sema.AllNumberTypes..., ) tests := validTypes[:] diff --git a/runtime/tests/checker/integer_test.go b/runtime/tests/checker/integer_test.go index 1079c2e3f0..c07a7b6163 100644 --- a/runtime/tests/checker/integer_test.go +++ b/runtime/tests/checker/integer_test.go @@ -26,12 +26,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/sema" ) -var allIntegerTypesAndAddressType = append( - sema.AllIntegerTypes[:], - sema.TheAddressType, +var allIntegerTypesAndAddressType = common.Concat( + sema.AllIntegerTypes, + []sema.Type{ + sema.TheAddressType, + }, ) func TestCheckIntegerLiteralTypeConversionInVariableDeclaration(t *testing.T) { diff --git a/runtime/tests/checker/operations_test.go b/runtime/tests/checker/operations_test.go index 7c4766b4a2..8f9f9d3091 100644 --- a/runtime/tests/checker/operations_test.go +++ b/runtime/tests/checker/operations_test.go @@ -426,9 +426,9 @@ func TestCheckSaturatedArithmeticFunctions(t *testing.T) { }, } - for _, ty := range append( - sema.AllSignedIntegerTypes[:], - sema.AllSignedFixedPointTypes..., + for _, ty := range common.Concat( + sema.AllSignedIntegerTypes, + sema.AllSignedFixedPointTypes, ) { if ty == sema.IntType { @@ -444,9 +444,9 @@ func TestCheckSaturatedArithmeticFunctions(t *testing.T) { }) } - for _, ty := range append( - sema.AllUnsignedIntegerTypes[:], - sema.AllUnsignedFixedPointTypes..., + for _, ty := range common.Concat( + sema.AllUnsignedIntegerTypes, + sema.AllUnsignedFixedPointTypes, ) { if ty == sema.UIntType || strings.HasPrefix(ty.String(), "Word") { diff --git a/runtime/tests/interpreter/arithmetic_test.go b/runtime/tests/interpreter/arithmetic_test.go index d05273f1be..d108ca90b1 100644 --- a/runtime/tests/interpreter/arithmetic_test.go +++ b/runtime/tests/interpreter/arithmetic_test.go @@ -26,6 +26,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/interpreter" "github.com/onflow/cadence/runtime/sema" . "github.com/onflow/cadence/runtime/tests/utils" @@ -723,9 +724,9 @@ func TestInterpretSaturatedArithmeticFunctions(t *testing.T) { // Verify all test cases exist - for _, ty := range append( - sema.AllSignedIntegerTypes[:], - sema.AllSignedFixedPointTypes..., + for _, ty := range common.Concat( + sema.AllSignedIntegerTypes, + sema.AllSignedFixedPointTypes, ) { testCase, ok := testCases[ty] @@ -749,9 +750,9 @@ func TestInterpretSaturatedArithmeticFunctions(t *testing.T) { } } - for _, ty := range append( - sema.AllUnsignedIntegerTypes[:], - sema.AllUnsignedFixedPointTypes..., + for _, ty := range common.Concat( + sema.AllUnsignedIntegerTypes, + sema.AllUnsignedFixedPointTypes, ) { if strings.HasPrefix(ty.String(), "Word") { diff --git a/tools/compatibility-check/cmd/check_diff/main.go b/tools/compatibility-check/cmd/check_diff/main.go deleted file mode 100644 index c1e7188e60..0000000000 --- a/tools/compatibility-check/cmd/check_diff/main.go +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 ( - "fmt" - "os" - - "github.com/rs/zerolog/log" - - "github.com/sergi/go-diff/diffmatchpatch" -) - -func main() { - if len(os.Args) < 2 { - log.Error().Msg("not enough arguments. Usage: old_checking_results new_checking_results") - return - } - - oldResultsPath := os.Args[1] - newResultsPath := os.Args[2] - - oldResultsFile, err := os.ReadFile(oldResultsPath) - if err != nil { - log.Err(err).Msgf("failed to open file: %s", oldResultsPath) - return - } - - newResultsFile, err := os.ReadFile(newResultsPath) - if err != nil { - log.Err(err).Msgf("failed to open file: %s", newResultsPath) - return - } - - compareBytes(oldResultsFile, newResultsFile) -} - -func compareBytes(old, new []byte) { - dmp := diffmatchpatch.New() - - diffs := dmp.DiffMain(string(old), string(new), false) - - changes := make([]diffmatchpatch.Diff, 0) - - // Filter out only the diff chunks with changes. - // No need to print the equal chunks. - for _, diff := range diffs { - if diff.Type == diffmatchpatch.DiffEqual { - continue - } - changes = append(changes, diff) - } - - fmt.Println(dmp.DiffPrettyText(changes)) - - if len(changes) > 0 { - log.Fatal().Msg("found differences") - } -} diff --git a/tools/compatibility-check/go.mod b/tools/compatibility-check/go.mod index e9d3b6135c..9cb961cde1 100644 --- a/tools/compatibility-check/go.mod +++ b/tools/compatibility-check/go.mod @@ -5,7 +5,6 @@ go 1.19 require ( github.com/onflow/cadence v0.31.2-0.20230207221811-9eb6e7fe4121 github.com/rs/zerolog v1.26.1 - github.com/sergi/go-diff v1.2.0 github.com/stretchr/testify v1.7.3 ) @@ -15,6 +14,7 @@ require ( github.com/fxamacker/cbor/v2 v2.4.1-0.20220515183430-ad2eae63303f // indirect github.com/fxamacker/circlehash v0.3.0 // indirect github.com/klauspost/cpuid/v2 v2.0.14 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect github.com/onflow/atree v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tools/compatibility-check/go.sum b/tools/compatibility-check/go.sum index cbc3f58844..765ad9dce2 100644 --- a/tools/compatibility-check/go.sum +++ b/tools/compatibility-check/go.sum @@ -1,6 +1,7 @@ github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk= github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -14,11 +15,10 @@ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8= github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= @@ -26,20 +26,20 @@ github.com/onflow/atree v0.4.0 h1:+TbNisavAkukAKhgQ4plWnvR9o5+SkwPIsi3jaeAqKs= github.com/onflow/atree v0.4.0/go.mod h1:7Qe1xaW0YewvouLXrugzMFUYXNoRQ8MT/UsVAWx1Ndo= github.com/onflow/cadence v0.31.2-0.20230207221811-9eb6e7fe4121 h1:pOJOFoX1fEwoXyzhU9Q8VtGUlZUnMCj4LcuOJdBnLgk= github.com/onflow/cadence v0.31.2-0.20230207221811-9eb6e7fe4121/go.mod h1:hhktaaXlJmxnfLgH2HG0cftcUWScdfjO/CTZkzaom/g= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.1-0.20211004051800-57c86be7915a h1:s7GrsqeorVkFR1vGmQ6WVL9nup0eyQCC+YVUeSQLH/Q= github.com/rivo/uniseg v0.2.1-0.20211004051800-57c86be7915a/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +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/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.3 h1:dAm0YRdRQlWojc3CrCRgPBzG5f941d0zvAKu7qY4e+I= github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -98,9 +98,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=