From 63c655095e804186c9accd939bac62b88bf81b71 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Mon, 7 Aug 2023 13:16:48 -0400 Subject: [PATCH 1/7] basic conversion of values --- runtime/interpreter/interpreter.go | 47 +++++++++ runtime/interpreter/value_test.go | 158 +++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index ddc18c2a05..72b2458b28 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -5022,6 +5022,53 @@ func (interpreter *Interpreter) MustConvertStaticAuthorizationToSemaAccess(auth return access } +func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { + semaType := interpreter.MustSemaTypeOfValue(v) + entitledType := sema.ConvertToEntitledType(interpreter, semaType) + + switch v := v.(type) { + case *EphemeralReferenceValue: + entitledReferenceType := entitledType.(*sema.ReferenceType) + staticAuthorization := ConvertSemaAccesstoStaticAuthorization(interpreter, entitledReferenceType.Authorization) + v.Authorization = staticAuthorization + v.BorrowedType = entitledReferenceType.Type + interpreter.ConvertValueToEntitlements(v.Value) + case *StorageReferenceValue: + entitledReferenceType := entitledType.(*sema.ReferenceType) + staticAuthorization := ConvertSemaAccesstoStaticAuthorization(interpreter, entitledReferenceType.Authorization) + v.Authorization = staticAuthorization + v.BorrowedType = entitledReferenceType.Type + // TODO: how to convert stored value + // interpreter.convertValueToEntitlements(v.Value) + case *SomeValue: + interpreter.ConvertValueToEntitlements(v.value) + case *CompositeValue: + // convert all the fields of this composite value to entitlements + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + case *ArrayValue: + entitledArrayType := entitledType.(sema.ArrayType) + v.semaType = entitledArrayType + v.Type = ConvertSemaArrayTypeToStaticArrayType(interpreter, entitledArrayType) + // convert all the elements of this array value to entitlements + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + case *DictionaryValue: + entitledDictionaryType := entitledType.(*sema.DictionaryType) + v.semaType = entitledDictionaryType + v.Type = ConvertSemaDictionaryTypeToStaticDictionaryType(interpreter, entitledDictionaryType) + // convert all the elements of this array value to entitlements + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + // capabilities should just have their borrow type updated; + // we will update their underlying value when the capability is borrowed + case *PathCapabilityValue: + entitledCapabilityValue := entitledType.(*sema.CapabilityType) + v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) + case *IDCapabilityValue: + entitledCapabilityValue := entitledType.(*sema.CapabilityType) + v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) + } + +} + func (interpreter *Interpreter) getElaboration(location common.Location) *sema.Elaboration { // Ensure the program for this location is loaded, diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 5d332d1fad..1678b17753 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -4533,3 +4533,161 @@ func TestValue_ConformsToStaticType(t *testing.T) { }) } + +func TestConvertToEntitledValue(t *testing.T) { + t.Parallel() + + var uuid uint64 + + storage := newUnmeteredInMemoryStorage() + + code := ` + access(all) entitlement E + access(all) entitlement F + access(all) entitlement G + + access(all) entitlement mapping M { + E -> F + F -> G + } + + access(all) struct S { + access(E) let eField: Int + access(F) let fField: String + init() { + self.eField = 0 + self.fField = "" + } + } + + access(all) resource R { + access(E, G) let egField: Int + init() { + self.egField = 0 + } + } + + access(all) resource Nested { + access(E | F) let efField: @R + init() { + self.efField <- create R() + } + destroy() { + destroy self.efField + } + } + + access(all) fun makeS(): S { + return S() + } + + access(all) fun makeR(): @R { + return <- create R() + } + + access(all) fun makeNested(): @Nested { + return <- create Nested() + } + ` + checker, err := checkerUtils.ParseAndCheckWithOptions(t, + code, + checkerUtils.ParseAndCheckOptions{}, + ) + + require.NoError(t, err) + + inter, err := NewInterpreter( + ProgramFromChecker(checker), + checker.Location, + &Config{ + Storage: storage, + UUIDHandler: func() (uint64, error) { + uuid++ + return uuid, nil + }, + }, + ) + + require.NoError(t, err) + + err = inter.Interpret() + require.NoError(t, err) + + rValue, err := inter.Invoke("makeR") + require.NoError(t, err) + sValue, err := inter.Invoke("makeS") + require.NoError(t, err) + nestedValue, err := inter.Invoke("makeNested") + require.NoError(t, err) + + tests := []struct { + Input Value + Output Value + Name string + }{ + { + Input: rValue, + Output: rValue, + Name: "R", + }, + { + Input: sValue, + Output: sValue, + Name: "S", + }, + { + Input: nestedValue, + Output: nestedValue, + Name: "Nested", + }, + { + Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, sValue, inter.MustSemaTypeOfValue(sValue)), + Output: NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + sValue, + inter.MustSemaTypeOfValue(sValue), + ), + Name: "&S", + }, + { + Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, rValue, inter.MustSemaTypeOfValue(rValue)), + Output: NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.G"}, + sema.Conjunction, + ), + rValue, + inter.MustSemaTypeOfValue(rValue), + ), + Name: "&R", + }, + { + Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, nestedValue, inter.MustSemaTypeOfValue(nestedValue)), + Output: NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + nestedValue, + inter.MustSemaTypeOfValue(nestedValue), + ), + Name: "&Nested", + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + inter.ConvertValueToEntitlements(test.Input) + require.Equal(t, test.Input, test.Output) + }) + } +} From 079195517bf91d9921ff929b22d781cbc4d9dc69 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Mon, 7 Aug 2023 14:18:06 -0400 Subject: [PATCH 2/7] tests for arrays and dicts of references --- runtime/interpreter/value_test.go | 124 +++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 1678b17753..66b809ce95 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -4541,6 +4541,8 @@ func TestConvertToEntitledValue(t *testing.T) { storage := newUnmeteredInMemoryStorage() + testAddress := common.MustBytesToAddress([]byte{0x1}) + code := ` access(all) entitlement E access(all) entitlement F @@ -4654,6 +4656,67 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "&S", }, + { + Input: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, NewReferenceStaticType(inter, UnauthorizedAccess, sValue.StaticType(inter))), + testAddress, + NewEphemeralReferenceValue(inter, UnauthorizedAccess, sValue, inter.MustSemaTypeOfValue(sValue)), + ), + Output: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType( + inter, + NewReferenceStaticType(inter, + UnauthorizedAccess, + sValue.StaticType(inter), + ), + ), + testAddress, + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + sValue, + inter.MustSemaTypeOfValue(sValue), + ), + ), + Name: "[&S]", + }, + { + Input: NewDictionaryValue( + inter, + EmptyLocationRange, + NewDictionaryStaticType(inter, PrimitiveStaticTypeInt, NewReferenceStaticType(inter, UnauthorizedAccess, sValue.StaticType(inter))), + NewIntValueFromInt64(inter, 0), + NewEphemeralReferenceValue(inter, UnauthorizedAccess, sValue, inter.MustSemaTypeOfValue(sValue)), + ), + Output: NewDictionaryValue( + inter, + EmptyLocationRange, + NewDictionaryStaticType(inter, PrimitiveStaticTypeInt, NewReferenceStaticType(inter, + UnauthorizedAccess, + sValue.StaticType(inter), + )), + NewIntValueFromInt64(inter, 0), + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + sValue, + inter.MustSemaTypeOfValue(sValue), + ), + ), + Name: "{Int: &S}", + }, { Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, rValue, inter.MustSemaTypeOfValue(rValue)), Output: NewEphemeralReferenceValue( @@ -4668,6 +4731,32 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "&R", }, + { + Input: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, NewReferenceStaticType(inter, UnauthorizedAccess, rValue.StaticType(inter))), + testAddress, + NewEphemeralReferenceValue(inter, UnauthorizedAccess, rValue, inter.MustSemaTypeOfValue(rValue)), + ), + Output: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, NewReferenceStaticType(inter, UnauthorizedAccess, rValue.StaticType(inter))), + testAddress, + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.G"}, + sema.Conjunction, + ), + rValue, + inter.MustSemaTypeOfValue(rValue), + ), + ), + Name: "[&R]", + }, { Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, nestedValue, inter.MustSemaTypeOfValue(nestedValue)), Output: NewEphemeralReferenceValue( @@ -4682,12 +4771,45 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "&Nested", }, + { + Input: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, NewReferenceStaticType(inter, UnauthorizedAccess, nestedValue.StaticType(inter))), + testAddress, + NewEphemeralReferenceValue(inter, UnauthorizedAccess, nestedValue, inter.MustSemaTypeOfValue(nestedValue)), + ), + Output: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, NewReferenceStaticType(inter, UnauthorizedAccess, nestedValue.StaticType(inter))), + testAddress, + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + nestedValue, + inter.MustSemaTypeOfValue(nestedValue), + ), + ), + Name: "[&Nested]", + }, + + // TODO: after mutability entitlements, add tests for references to arrays and dictionaries } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { inter.ConvertValueToEntitlements(test.Input) - require.Equal(t, test.Input, test.Output) + switch input := test.Input.(type) { + case EquatableValue: + require.True(t, input.Equal(inter, EmptyLocationRange, test.Output)) + default: + require.Equal(t, test.Input, test.Output) + } }) } } From 1c0e20d3d685be4237db6907a6eea66fe758f5fe Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 8 Aug 2023 13:38:23 -0400 Subject: [PATCH 3/7] add test for capability values --- runtime/interpreter/value_test.go | 47 ++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 66b809ce95..972d42643c 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -4797,7 +4797,52 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "[&Nested]", }, - + { + Input: NewIDCapabilityValue( + inter, + 0, + NewAddressValue(inter, testAddress), + NewReferenceStaticType(inter, UnauthorizedAccess, sValue.StaticType(inter)), + ), + Output: NewIDCapabilityValue( + inter, + 0, + NewAddressValue(inter, testAddress), + NewReferenceStaticType( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + sValue.StaticType(inter), + ), + ), + Name: "Capability<&S>", + }, + { + Input: NewIDCapabilityValue( + inter, + 0, + NewAddressValue(inter, testAddress), + NewReferenceStaticType(inter, UnauthorizedAccess, rValue.StaticType(inter)), + ), + Output: NewIDCapabilityValue( + inter, + 0, + NewAddressValue(inter, testAddress), + NewReferenceStaticType( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.G"}, + sema.Conjunction, + ), + rValue.StaticType(inter), + ), + ), + Name: "Capability<&R>", + }, // TODO: after mutability entitlements, add tests for references to arrays and dictionaries } From b031af972511c199b0f368807d4cb09508500852 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Tue, 8 Aug 2023 14:26:11 -0400 Subject: [PATCH 4/7] convert runtime type values --- runtime/interpreter/interpreter.go | 30 ++++++++++++++++++++++++------ runtime/interpreter/value_test.go | 20 ++++++++++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 72b2458b28..bad850ae3a 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -5022,7 +5022,10 @@ func (interpreter *Interpreter) MustConvertStaticAuthorizationToSemaAccess(auth return access } -func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { +// Converts the input value into a version compatible with the new entitlements feature, +// with the same members/operations accessible on any references as would have been accessible in the past. +// Modifies the input `v` in place, and also returns a copy of the value +func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { semaType := interpreter.MustSemaTypeOfValue(v) entitledType := sema.ConvertToEntitledType(interpreter, semaType) @@ -5038,25 +5041,24 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { staticAuthorization := ConvertSemaAccesstoStaticAuthorization(interpreter, entitledReferenceType.Authorization) v.Authorization = staticAuthorization v.BorrowedType = entitledReferenceType.Type - // TODO: how to convert stored value - // interpreter.convertValueToEntitlements(v.Value) + // stored value is not converted; instead we will convert it upon load case *SomeValue: interpreter.ConvertValueToEntitlements(v.value) case *CompositeValue: // convert all the fields of this composite value to entitlements - v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) case *ArrayValue: entitledArrayType := entitledType.(sema.ArrayType) v.semaType = entitledArrayType v.Type = ConvertSemaArrayTypeToStaticArrayType(interpreter, entitledArrayType) // convert all the elements of this array value to entitlements - v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) case *DictionaryValue: entitledDictionaryType := entitledType.(*sema.DictionaryType) v.semaType = entitledDictionaryType v.Type = ConvertSemaDictionaryTypeToStaticDictionaryType(interpreter, entitledDictionaryType) // convert all the elements of this array value to entitlements - v.Walk(interpreter, interpreter.ConvertValueToEntitlements) + v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) // capabilities should just have their borrow type updated; // we will update their underlying value when the capability is borrowed case *PathCapabilityValue: @@ -5065,8 +5067,24 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { case *IDCapabilityValue: entitledCapabilityValue := entitledType.(*sema.CapabilityType) v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) + case TypeValue: + if v.Type == nil { + return v + } + // convert the static type of the value + return NewTypeValue( + interpreter, + ConvertSemaToStaticType( + interpreter, + sema.ConvertToEntitledType( + interpreter, + interpreter.MustConvertStaticToSemaType(v.Type), + ), + ), + ) } + return v } func (interpreter *Interpreter) getElaboration(location common.Location) *sema.Elaboration { diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 972d42643c..d8767d8961 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -4846,14 +4846,26 @@ func TestConvertToEntitledValue(t *testing.T) { // TODO: after mutability entitlements, add tests for references to arrays and dictionaries } + for _, test := range tests { + var runtimeTypeTest struct { + Input Value + Output Value + Name string + } + runtimeTypeTest.Input = NewTypeValue(nil, test.Input.StaticType(inter)) + runtimeTypeTest.Output = NewTypeValue(nil, test.Output.StaticType(inter)) + runtimeTypeTest.Name = "runtime type " + test.Name + + tests = append(tests, runtimeTypeTest) + } + for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - inter.ConvertValueToEntitlements(test.Input) - switch input := test.Input.(type) { + switch output := inter.ConvertValueToEntitlements(test.Input).(type) { case EquatableValue: - require.True(t, input.Equal(inter, EmptyLocationRange, test.Output)) + require.True(t, output.Equal(inter, EmptyLocationRange, test.Output)) default: - require.Equal(t, test.Input, test.Output) + require.Equal(t, output, test.Output) } }) } From bfed26b2973d49593700497ccd0efae848e726ca Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 9 Aug 2023 11:50:06 -0400 Subject: [PATCH 5/7] make TypeValue a pointer type --- runtime/convertValues.go | 6 +- runtime/convertValues_test.go | 6 +- runtime/interpreter/decode.go | 2 +- runtime/interpreter/encoding_test.go | 8 +- runtime/interpreter/interpreter.go | 26 +++-- runtime/interpreter/value.go | 66 +++++------ runtime/interpreter/value_test.go | 104 ++++++++++++++++-- runtime/interpreter/visitor.go | 6 +- runtime/stdlib/test_emulatorbackend.go | 2 +- runtime/tests/interpreter/account_test.go | 4 +- runtime/tests/interpreter/attachments_test.go | 4 +- runtime/tests/interpreter/interpreter_test.go | 14 +-- runtime/tests/interpreter/metatype_test.go | 30 ++--- runtime/tests/interpreter/runtimetype_test.go | 70 ++++++------ runtime/tests/interpreter/string_test.go | 8 +- 15 files changed, 221 insertions(+), 135 deletions(-) diff --git a/runtime/convertValues.go b/runtime/convertValues.go index 82a2caa0c7..3c0a7ecdb2 100644 --- a/runtime/convertValues.go +++ b/runtime/convertValues.go @@ -231,7 +231,7 @@ func exportValueWithInterpreter( return exportAccountLinkValue(inter), nil case interpreter.PathValue: return exportPathValue(inter, v) - case interpreter.TypeValue: + case *interpreter.TypeValue: return exportTypeValue(v, inter), nil case *interpreter.IDCapabilityValue: return exportIDCapabilityValue(v, inter) @@ -634,7 +634,7 @@ func exportPathValue(gauge common.MemoryGauge, v interpreter.PathValue) (cadence ) } -func exportTypeValue(v interpreter.TypeValue, inter *interpreter.Interpreter) cadence.TypeValue { +func exportTypeValue(v *interpreter.TypeValue, inter *interpreter.Interpreter) cadence.TypeValue { var typ sema.Type if v.Type != nil { typ = inter.MustConvertStaticToSemaType(v.Type) @@ -1130,7 +1130,7 @@ func (i valueImporter) importPathValue(v cadence.Path) interpreter.PathValue { ) } -func (i valueImporter) importTypeValue(v cadence.Type) (interpreter.TypeValue, error) { +func (i valueImporter) importTypeValue(v cadence.Type) (*interpreter.TypeValue, error) { inter := i.inter typ := ImportType(inter, v) diff --git a/runtime/convertValues_test.go b/runtime/convertValues_test.go index 4db6b7e620..62e8ae4a06 100644 --- a/runtime/convertValues_test.go +++ b/runtime/convertValues_test.go @@ -889,7 +889,7 @@ func TestImportValue(t *testing.T) { { label: "Type()", value: cadence.NewTypeValue(cadence.IntType{}), - expected: interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeInt}, + expected: &interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeInt}, }, } { test(tt) @@ -2070,7 +2070,7 @@ func TestExportTypeValue(t *testing.T) { t.Parallel() - value := interpreter.TypeValue{ + value := &interpreter.TypeValue{ Type: nil, } actual, err := exportValueWithInterpreter( @@ -2117,7 +2117,7 @@ func TestExportTypeValue(t *testing.T) { inter := newTestInterpreter(t) inter.Program = interpreter.ProgramFromChecker(checker) - ty := interpreter.TypeValue{ + ty := &interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ Types: []interpreter.InterfaceStaticType{ { diff --git a/runtime/interpreter/decode.go b/runtime/interpreter/decode.go index 5c8647ec58..55f4a9fd6d 100644 --- a/runtime/interpreter/decode.go +++ b/runtime/interpreter/decode.go @@ -1330,7 +1330,7 @@ func (d StorableDecoder) decodePublishedValue() (*PublishedValue, error) { return NewPublishedValue(d.memoryGauge, addressValue, capabilityValue), nil } -func (d StorableDecoder) decodeType() (TypeValue, error) { +func (d StorableDecoder) decodeType() (*TypeValue, error) { const expectedLength = encodedTypeValueTypeLength arraySize, err := d.decoder.DecodeArrayHead() diff --git a/runtime/interpreter/encoding_test.go b/runtime/interpreter/encoding_test.go index 3d57ba229e..75567e76f7 100644 --- a/runtime/interpreter/encoding_test.go +++ b/runtime/interpreter/encoding_test.go @@ -4383,7 +4383,7 @@ func TestEncodeDecodeTypeValue(t *testing.T) { t.Parallel() - value := TypeValue{ + value := &TypeValue{ Type: ConvertSemaToPrimitiveStaticType(nil, sema.BoolType), } @@ -4410,7 +4410,7 @@ func TestEncodeDecodeTypeValue(t *testing.T) { t.Parallel() - value := TypeValue{ + value := &TypeValue{ Type: ConvertSemaToPrimitiveStaticType(nil, sema.IntType), } @@ -4437,7 +4437,7 @@ func TestEncodeDecodeTypeValue(t *testing.T) { t.Parallel() - value := TypeValue{ + value := &TypeValue{ Type: nil, } @@ -4468,7 +4468,7 @@ func TestEncodeDecodeTypeValue(t *testing.T) { maxInlineElementSize := atree.MaxInlineArrayElementSize identifier := strings.Repeat("x", int(maxInlineElementSize+1)) - expected := TypeValue{ + expected := &TypeValue{ Type: NewCompositeStaticTypeComputeTypeID( nil, common.AddressLocation{}, diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index bad850ae3a..079eaf49f7 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -3442,12 +3442,12 @@ func init() { } func dictionaryTypeFunction(invocation Invocation) Value { - keyTypeValue, ok := invocation.Arguments[0].(TypeValue) + keyTypeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } - valueTypeValue, ok := invocation.Arguments[1].(TypeValue) + valueTypeValue, ok := invocation.Arguments[1].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3480,7 +3480,7 @@ func referenceTypeFunction(invocation Invocation) Value { panic(errors.NewUnreachableError()) } - typeValue, ok := invocation.Arguments[1].(TypeValue) + typeValue, ok := invocation.Arguments[1].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3577,7 +3577,7 @@ func functionTypeFunction(invocation Invocation) Value { panic(errors.NewUnreachableError()) } - typeValue, ok := invocation.Arguments[1].(TypeValue) + typeValue, ok := invocation.Arguments[1].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3589,7 +3589,7 @@ func functionTypeFunction(invocation Invocation) Value { if parameterCount > 0 { parameterTypes = make([]sema.Parameter, 0, parameterCount) parameters.Iterate(interpreter, func(param Value) bool { - semaType := interpreter.MustConvertStaticToSemaType(param.(TypeValue).Type) + semaType := interpreter.MustConvertStaticToSemaType(param.(*TypeValue).Type) parameterTypes = append( parameterTypes, sema.Parameter{ @@ -3768,7 +3768,7 @@ var runtimeTypeConstructors = []runtimeTypeConstructor{ converter: NewUnmeteredHostFunctionValue( sema.OptionalTypeFunctionType, func(invocation Invocation) Value { - typeValue, ok := invocation.Arguments[0].(TypeValue) + typeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3788,7 +3788,7 @@ var runtimeTypeConstructors = []runtimeTypeConstructor{ converter: NewUnmeteredHostFunctionValue( sema.VariableSizedArrayTypeFunctionType, func(invocation Invocation) Value { - typeValue, ok := invocation.Arguments[0].(TypeValue) + typeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3809,7 +3809,7 @@ var runtimeTypeConstructors = []runtimeTypeConstructor{ converter: NewUnmeteredHostFunctionValue( sema.ConstantSizedArrayTypeFunctionType, func(invocation Invocation) Value { - typeValue, ok := invocation.Arguments[0].(TypeValue) + typeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -3835,7 +3835,7 @@ var runtimeTypeConstructors = []runtimeTypeConstructor{ converter: NewUnmeteredHostFunctionValue( sema.CapabilityTypeFunctionType, func(invocation Invocation) Value { - typeValue, ok := invocation.Arguments[0].(TypeValue) + typeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -5043,7 +5043,9 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { v.BorrowedType = entitledReferenceType.Type // stored value is not converted; instead we will convert it upon load case *SomeValue: - interpreter.ConvertValueToEntitlements(v.value) + v.value = interpreter.ConvertValueToEntitlements(v.value) + // reset the storable, to be recomputed on next access + v.valueStorable = nil case *CompositeValue: // convert all the fields of this composite value to entitlements v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) @@ -5067,7 +5069,7 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { case *IDCapabilityValue: entitledCapabilityValue := entitledType.(*sema.CapabilityType) v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) - case TypeValue: + case *TypeValue: if v.Type == nil { return v } @@ -5330,7 +5332,7 @@ func (interpreter *Interpreter) isInstanceFunction(self Value) *HostFunctionValu interpreter := invocation.Interpreter firstArgument := invocation.Arguments[0] - typeValue, ok := firstArgument.(TypeValue) + typeValue, ok := firstArgument.(*TypeValue) if !ok { panic(errors.NewUnreachableError()) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 8e9715da6b..535d11c7b9 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -303,44 +303,44 @@ type TypeValue struct { Type StaticType } -var EmptyTypeValue = TypeValue{} +var EmptyTypeValue = &TypeValue{} -var _ Value = TypeValue{} -var _ atree.Storable = TypeValue{} -var _ EquatableValue = TypeValue{} -var _ MemberAccessibleValue = TypeValue{} +var _ Value = &TypeValue{} +var _ atree.Storable = &TypeValue{} +var _ EquatableValue = &TypeValue{} +var _ MemberAccessibleValue = &TypeValue{} -func NewUnmeteredTypeValue(t StaticType) TypeValue { - return TypeValue{Type: t} +func NewUnmeteredTypeValue(t StaticType) *TypeValue { + return &TypeValue{Type: t} } func NewTypeValue( memoryGauge common.MemoryGauge, staticType StaticType, -) TypeValue { +) *TypeValue { common.UseMemory(memoryGauge, common.TypeValueMemoryUsage) return NewUnmeteredTypeValue(staticType) } -func (TypeValue) isValue() {} +func (*TypeValue) isValue() {} -func (v TypeValue) Accept(interpreter *Interpreter, visitor Visitor) { +func (v *TypeValue) Accept(interpreter *Interpreter, visitor Visitor) { visitor.VisitTypeValue(interpreter, v) } -func (TypeValue) Walk(_ *Interpreter, _ func(Value)) { +func (*TypeValue) Walk(_ *Interpreter, _ func(Value)) { // NO-OP } -func (TypeValue) StaticType(interpreter *Interpreter) StaticType { +func (*TypeValue) StaticType(interpreter *Interpreter) StaticType { return NewPrimitiveStaticType(interpreter, PrimitiveStaticTypeMetaType) } -func (TypeValue) IsImportable(_ *Interpreter) bool { +func (*TypeValue) IsImportable(_ *Interpreter) bool { return sema.MetaType.Importable } -func (v TypeValue) String() string { +func (v *TypeValue) String() string { var typeString string staticType := v.Type if staticType != nil { @@ -350,11 +350,11 @@ func (v TypeValue) String() string { return format.TypeValue(typeString) } -func (v TypeValue) RecursiveString(_ SeenReferences) string { +func (v *TypeValue) RecursiveString(_ SeenReferences) string { return v.String() } -func (v TypeValue) MeteredString(memoryGauge common.MemoryGauge, _ SeenReferences) string { +func (v *TypeValue) MeteredString(memoryGauge common.MemoryGauge, _ SeenReferences) string { common.UseMemory(memoryGauge, common.TypeValueStringMemoryUsage) var typeString string @@ -365,8 +365,8 @@ func (v TypeValue) MeteredString(memoryGauge common.MemoryGauge, _ SeenReference return format.TypeValue(typeString) } -func (v TypeValue) Equal(_ *Interpreter, _ LocationRange, other Value) bool { - otherTypeValue, ok := other.(TypeValue) +func (v *TypeValue) Equal(_ *Interpreter, _ LocationRange, other Value) bool { + otherTypeValue, ok := other.(*TypeValue) if !ok { return false } @@ -383,7 +383,7 @@ func (v TypeValue) Equal(_ *Interpreter, _ LocationRange, other Value) bool { return staticType.Equal(otherStaticType) } -func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name string) Value { +func (v *TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name string) Value { switch name { case sema.MetaTypeIdentifierFieldName: var typeID string @@ -407,7 +407,7 @@ func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name str interpreter := invocation.Interpreter staticType := v.Type - otherTypeValue, ok := invocation.Arguments[0].(TypeValue) + otherTypeValue, ok := invocation.Arguments[0].(*TypeValue) if !ok { panic(errors.NewUnreachableError()) } @@ -430,17 +430,17 @@ func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name str return nil } -func (TypeValue) RemoveMember(_ *Interpreter, _ LocationRange, _ string) Value { +func (*TypeValue) RemoveMember(_ *Interpreter, _ LocationRange, _ string) Value { // Types have no removable members (fields / functions) panic(errors.NewUnreachableError()) } -func (TypeValue) SetMember(_ *Interpreter, _ LocationRange, _ string, _ Value) bool { +func (*TypeValue) SetMember(_ *Interpreter, _ LocationRange, _ string, _ Value) bool { // Types have no settable members (fields / functions) panic(errors.NewUnreachableError()) } -func (v TypeValue) ConformsToStaticType( +func (v *TypeValue) ConformsToStaticType( _ *Interpreter, _ LocationRange, _ TypeConformanceResults, @@ -448,7 +448,7 @@ func (v TypeValue) ConformsToStaticType( return true } -func (v TypeValue) Storable( +func (v *TypeValue) Storable( storage atree.SlabStorage, address atree.Address, maxInlineSize uint64, @@ -461,15 +461,15 @@ func (v TypeValue) Storable( ) } -func (TypeValue) NeedsStoreTo(_ atree.Address) bool { +func (*TypeValue) NeedsStoreTo(_ atree.Address) bool { return false } -func (TypeValue) IsResourceKinded(_ *Interpreter) bool { +func (*TypeValue) IsResourceKinded(_ *Interpreter) bool { return false } -func (v TypeValue) Transfer( +func (v *TypeValue) Transfer( interpreter *Interpreter, _ LocationRange, _ atree.Address, @@ -483,30 +483,30 @@ func (v TypeValue) Transfer( return v } -func (v TypeValue) Clone(_ *Interpreter) Value { +func (v *TypeValue) Clone(_ *Interpreter) Value { return v } -func (TypeValue) DeepRemove(_ *Interpreter) { +func (*TypeValue) DeepRemove(_ *Interpreter) { // NO-OP } -func (v TypeValue) ByteSize() uint32 { +func (v *TypeValue) ByteSize() uint32 { return mustStorableSize(v) } -func (v TypeValue) StoredValue(_ atree.SlabStorage) (atree.Value, error) { +func (v *TypeValue) StoredValue(_ atree.SlabStorage) (atree.Value, error) { return v, nil } -func (TypeValue) ChildStorables() []atree.Storable { +func (*TypeValue) ChildStorables() []atree.Storable { return nil } // HashInput returns a byte slice containing: // - HashInputTypeType (1 byte) // - type id (n bytes) -func (v TypeValue) HashInput(interpreter *Interpreter, _ LocationRange, scratch []byte) []byte { +func (v *TypeValue) HashInput(interpreter *Interpreter, _ LocationRange, scratch []byte) []byte { typeID := interpreter.MustConvertStaticToSemaType(v.Type).ID() length := 1 + len(typeID) diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index d8767d8961..6cd05e056b 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -2329,12 +2329,12 @@ func TestTypeValue_Equal(t *testing.T) { inter := newTestInterpreter(t) require.True(t, - TypeValue{ + (&TypeValue{ Type: PrimitiveStaticTypeString, - }.Equal( + }).Equal( inter, EmptyLocationRange, - TypeValue{ + &TypeValue{ Type: PrimitiveStaticTypeString, }, ), @@ -2348,12 +2348,12 @@ func TestTypeValue_Equal(t *testing.T) { inter := newTestInterpreter(t) require.False(t, - TypeValue{ + (&TypeValue{ Type: PrimitiveStaticTypeString, - }.Equal( + }).Equal( inter, EmptyLocationRange, - TypeValue{ + &TypeValue{ Type: PrimitiveStaticTypeInt, }, ), @@ -2367,9 +2367,9 @@ func TestTypeValue_Equal(t *testing.T) { inter := newTestInterpreter(t) require.False(t, - TypeValue{ + (&TypeValue{ Type: PrimitiveStaticTypeString, - }.Equal( + }).Equal( inter, EmptyLocationRange, NewUnmeteredStringValue("String"), @@ -4688,6 +4688,43 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "[&S]", }, + { + Input: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, PrimitiveStaticTypeMetaType), + testAddress, + NewTypeValue( + inter, + NewEphemeralReferenceValue( + inter, + UnauthorizedAccess, + sValue, + inter.MustSemaTypeOfValue(sValue), + ).StaticType(inter), + ), + ), + Output: NewArrayValue( + inter, + EmptyLocationRange, + NewVariableSizedStaticType(inter, PrimitiveStaticTypeMetaType), + testAddress, + NewTypeValue( + inter, + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), + sValue, + inter.MustSemaTypeOfValue(sValue), + ).StaticType(inter), + ), + ), + Name: "[Type]", + }, { Input: NewDictionaryValue( inter, @@ -4717,6 +4754,40 @@ func TestConvertToEntitledValue(t *testing.T) { ), Name: "{Int: &S}", }, + { + Input: NewDictionaryValue( + inter, + EmptyLocationRange, + NewDictionaryStaticType(inter, PrimitiveStaticTypeInt, PrimitiveStaticTypeMetaType), + NewIntValueFromInt64(inter, 0), + NewTypeValue( + inter, + NewEphemeralReferenceValue( + inter, + UnauthorizedAccess, + sValue, + inter.MustSemaTypeOfValue(sValue), + ).StaticType(inter), + ), + ), + Output: NewDictionaryValue( + inter, + EmptyLocationRange, + NewDictionaryStaticType(inter, PrimitiveStaticTypeInt, PrimitiveStaticTypeMetaType), + NewIntValueFromInt64(inter, 0), + NewTypeValue(inter, + NewEphemeralReferenceValue( + inter, + NewEntitlementSetAuthorization( + inter, + []common.TypeID{"S.test.E", "S.test.F"}, + sema.Conjunction, + ), sValue, inter.MustSemaTypeOfValue(sValue), + ).StaticType(inter), + ), + ), + Name: "{Int: Type}", + }, { Input: NewEphemeralReferenceValue(inter, UnauthorizedAccess, rValue, inter.MustSemaTypeOfValue(rValue)), Output: NewEphemeralReferenceValue( @@ -4852,13 +4923,26 @@ func TestConvertToEntitledValue(t *testing.T) { Output Value Name string } - runtimeTypeTest.Input = NewTypeValue(nil, test.Input.StaticType(inter)) - runtimeTypeTest.Output = NewTypeValue(nil, test.Output.StaticType(inter)) + runtimeTypeTest.Input = NewTypeValue(inter, test.Input.Clone(inter).StaticType(inter)) + runtimeTypeTest.Output = NewTypeValue(inter, test.Output.Clone(inter).StaticType(inter)) runtimeTypeTest.Name = "runtime type " + test.Name tests = append(tests, runtimeTypeTest) } + for _, test := range tests { + var optionalValueTest struct { + Input Value + Output Value + Name string + } + optionalValueTest.Input = NewSomeValueNonCopying(inter, test.Input.Clone(inter)) + optionalValueTest.Output = NewSomeValueNonCopying(inter, test.Output.Clone(inter)) + optionalValueTest.Name = "optional " + test.Name + + tests = append(tests, optionalValueTest) + } + for _, test := range tests { t.Run(test.Name, func(t *testing.T) { switch output := inter.ConvertValueToEntitlements(test.Input).(type) { diff --git a/runtime/interpreter/visitor.go b/runtime/interpreter/visitor.go index 587a899865..c760d4a2aa 100644 --- a/runtime/interpreter/visitor.go +++ b/runtime/interpreter/visitor.go @@ -20,7 +20,7 @@ package interpreter type Visitor interface { VisitSimpleCompositeValue(interpreter *Interpreter, value *SimpleCompositeValue) - VisitTypeValue(interpreter *Interpreter, value TypeValue) + VisitTypeValue(interpreter *Interpreter, value *TypeValue) VisitVoidValue(interpreter *Interpreter, value VoidValue) VisitBoolValue(interpreter *Interpreter, value BoolValue) VisitStringValue(interpreter *Interpreter, value *StringValue) @@ -71,7 +71,7 @@ type Visitor interface { type EmptyVisitor struct { SimpleCompositeValueVisitor func(interpreter *Interpreter, value *SimpleCompositeValue) - TypeValueVisitor func(interpreter *Interpreter, value TypeValue) + TypeValueVisitor func(interpreter *Interpreter, value *TypeValue) VoidValueVisitor func(interpreter *Interpreter, value VoidValue) BoolValueVisitor func(interpreter *Interpreter, value BoolValue) CharacterValueVisitor func(interpreter *Interpreter, value CharacterValue) @@ -129,7 +129,7 @@ func (v EmptyVisitor) VisitSimpleCompositeValue(interpreter *Interpreter, value v.SimpleCompositeValueVisitor(interpreter, value) } -func (v EmptyVisitor) VisitTypeValue(interpreter *Interpreter, value TypeValue) { +func (v EmptyVisitor) VisitTypeValue(interpreter *Interpreter, value *TypeValue) { if v.TypeValueVisitor == nil { return } diff --git a/runtime/stdlib/test_emulatorbackend.go b/runtime/stdlib/test_emulatorbackend.go index 86e9db2038..46af82c6b8 100644 --- a/runtime/stdlib/test_emulatorbackend.go +++ b/runtime/stdlib/test_emulatorbackend.go @@ -646,7 +646,7 @@ func (t *testEmulatorBackendType) newEventsFunction( // Do nothing case *interpreter.SomeValue: innerValue := value.InnerValue(invocation.Interpreter, invocation.LocationRange) - typeValue, ok := innerValue.(interpreter.TypeValue) + typeValue, ok := innerValue.(*interpreter.TypeValue) if !ok { panic(errors.NewUnreachableError()) } diff --git a/runtime/tests/interpreter/account_test.go b/runtime/tests/interpreter/account_test.go index c301e9c9a2..ca84f2c75e 100644 --- a/runtime/tests/interpreter/account_test.go +++ b/runtime/tests/interpreter/account_test.go @@ -327,7 +327,7 @@ func TestInterpretAuthAccount_type(t *testing.T) { require.NoError(t, err) require.Equal(t, interpreter.NewUnmeteredSomeValueNonCopying( - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ Location: TestLocation, QualifiedIdentifier: "R", @@ -350,7 +350,7 @@ func TestInterpretAuthAccount_type(t *testing.T) { require.NoError(t, err) require.Equal(t, interpreter.NewUnmeteredSomeValueNonCopying( - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ Location: TestLocation, QualifiedIdentifier: "S", diff --git a/runtime/tests/interpreter/attachments_test.go b/runtime/tests/interpreter/attachments_test.go index bc9cde98d1..596005a72d 100644 --- a/runtime/tests/interpreter/attachments_test.go +++ b/runtime/tests/interpreter/attachments_test.go @@ -1835,8 +1835,8 @@ func TestInterpretAttachmentsRuntimeType(t *testing.T) { a, err := inter.Invoke("test") require.NoError(t, err) - require.IsType(t, interpreter.TypeValue{}, a) - require.Equal(t, "S.test.A", a.(interpreter.TypeValue).Type.String()) + require.IsType(t, &interpreter.TypeValue{}, a) + require.Equal(t, "S.test.A", a.(*interpreter.TypeValue).Type.String()) }) } diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index a24e7873ef..48966efe28 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -9986,8 +9986,8 @@ func TestHostFunctionStaticType(t *testing.T) { value.StaticType(inter), ) - require.IsType(t, interpreter.TypeValue{}, value) - typeValue := value.(interpreter.TypeValue) + require.IsType(t, &interpreter.TypeValue{}, value) + typeValue := value.(*interpreter.TypeValue) assert.Equal(t, interpreter.PrimitiveStaticTypeInt8, typeValue.Type) }) @@ -10043,7 +10043,7 @@ func TestInterpretArrayTypeInference(t *testing.T) { AssertValuesEqual( t, inter, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeAnyStruct, }, @@ -10068,7 +10068,7 @@ func TestInterpretArrayTypeInference(t *testing.T) { AssertValuesEqual( t, inter, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, }, @@ -10425,7 +10425,7 @@ func TestInterpretCastingBoxing(t *testing.T) { require.Equal( t, interpreter.NewUnmeteredSomeValueNonCopying( - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.PrimitiveStaticTypeInt, }, ), @@ -10447,7 +10447,7 @@ func TestInterpretCastingBoxing(t *testing.T) { require.Equal( t, interpreter.NewUnmeteredSomeValueNonCopying( - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.PrimitiveStaticTypeInt, }, ), @@ -10469,7 +10469,7 @@ func TestInterpretCastingBoxing(t *testing.T) { require.Equal( t, interpreter.NewUnmeteredSomeValueNonCopying( - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.PrimitiveStaticTypeInt, }, ), diff --git a/runtime/tests/interpreter/metatype_test.go b/runtime/tests/interpreter/metatype_test.go index 8534f1c927..3975e315d6 100644 --- a/runtime/tests/interpreter/metatype_test.go +++ b/runtime/tests/interpreter/metatype_test.go @@ -124,7 +124,7 @@ func TestInterpretMetaTypeEquality(t *testing.T) { valueDeclaration := stdlib.StandardLibraryValue{ Name: "unknownType", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -167,7 +167,7 @@ func TestInterpretMetaTypeEquality(t *testing.T) { { Name: "unknownType1", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -175,7 +175,7 @@ func TestInterpretMetaTypeEquality(t *testing.T) { { Name: "unknownType2", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -264,7 +264,7 @@ func TestInterpretMetaTypeIdentifier(t *testing.T) { { Name: "unknownType", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -397,7 +397,7 @@ func TestInterpretIsInstance(t *testing.T) { valueDeclaration := stdlib.StandardLibraryValue{ Name: "unknownType", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -537,7 +537,7 @@ func TestInterpretIsSubtype(t *testing.T) { valueDeclaration := stdlib.StandardLibraryValue{ Name: "unknownType", Type: sema.MetaType, - Value: interpreter.TypeValue{ + Value: &interpreter.TypeValue{ Type: nil, }, Kind: common.DeclarationKindConstant, @@ -585,7 +585,7 @@ func TestInterpretGetType(t *testing.T) { return "abc".getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.PrimitiveStaticTypeString, }, }, @@ -596,7 +596,7 @@ func TestInterpretGetType(t *testing.T) { return (1).getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.PrimitiveStaticTypeInt, }, }, @@ -612,7 +612,7 @@ func TestInterpretGetType(t *testing.T) { return res } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.NewCompositeStaticTypeComputeTypeID(nil, TestLocation, "R"), }, }, @@ -630,7 +630,7 @@ func TestInterpretGetType(t *testing.T) { return optRef.getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.ReferenceStaticType{ Authorization: interpreter.NewEntitlementSetAuthorization(nil, []common.TypeID{"S.test.X"}, sema.Conjunction), @@ -653,7 +653,7 @@ func TestInterpretGetType(t *testing.T) { return optRef.getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.ReferenceStaticType{ // Reference was converted @@ -677,7 +677,7 @@ func TestInterpretGetType(t *testing.T) { return optRef.getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.ReferenceStaticType{ Authorization: interpreter.NewEntitlementSetAuthorization(nil, []common.TypeID{"S.test.X"}, sema.Conjunction), @@ -703,7 +703,7 @@ func TestInterpretGetType(t *testing.T) { return optRef.getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.ReferenceStaticType{ // Reference was converted @@ -730,7 +730,7 @@ func TestInterpretGetType(t *testing.T) { return optRef.getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.ReferenceStaticType{ Authorization: interpreter.NewEntitlementSetAuthorization(nil, []common.TypeID{"S.test.X"}, sema.Conjunction), @@ -746,7 +746,7 @@ func TestInterpretGetType(t *testing.T) { return [1, 3].getType() } `, - result: interpreter.TypeValue{ + result: &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, }, diff --git a/runtime/tests/interpreter/runtimetype_test.go b/runtime/tests/interpreter/runtimetype_test.go index 18a9c4862e..cc43d2066c 100644 --- a/runtime/tests/interpreter/runtimetype_test.go +++ b/runtime/tests/interpreter/runtimetype_test.go @@ -45,7 +45,7 @@ func TestInterpretOptionalType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.PrimitiveStaticTypeString, }, @@ -54,7 +54,7 @@ func TestInterpretOptionalType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.PrimitiveStaticTypeInt, }, @@ -63,7 +63,7 @@ func TestInterpretOptionalType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.CompositeStaticType{ Location: utils.TestLocation, @@ -76,7 +76,7 @@ func TestInterpretOptionalType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.OptionalStaticType{ Type: interpreter.OptionalStaticType{ Type: interpreter.PrimitiveStaticTypeString, @@ -108,7 +108,7 @@ func TestInterpretVariableSizedArrayType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeString, }, @@ -117,7 +117,7 @@ func TestInterpretVariableSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, }, @@ -126,7 +126,7 @@ func TestInterpretVariableSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.CompositeStaticType{ Location: utils.TestLocation, @@ -139,7 +139,7 @@ func TestInterpretVariableSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.VariableSizedStaticType{ Type: interpreter.PrimitiveStaticTypeString, @@ -170,7 +170,7 @@ func TestInterpretConstantSizedArrayType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ConstantSizedStaticType{ Type: interpreter.PrimitiveStaticTypeString, Size: int64(10), @@ -180,7 +180,7 @@ func TestInterpretConstantSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ConstantSizedStaticType{ Type: interpreter.PrimitiveStaticTypeInt, Size: int64(5), @@ -190,7 +190,7 @@ func TestInterpretConstantSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ConstantSizedStaticType{ Type: interpreter.CompositeStaticType{ Location: utils.TestLocation, @@ -204,7 +204,7 @@ func TestInterpretConstantSizedArrayType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ConstantSizedStaticType{ Type: interpreter.ConstantSizedStaticType{ Type: interpreter.PrimitiveStaticTypeString, @@ -240,7 +240,7 @@ func TestInterpretDictionaryType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.DictionaryStaticType{ KeyType: interpreter.PrimitiveStaticTypeString, ValueType: interpreter.PrimitiveStaticTypeInt, @@ -250,7 +250,7 @@ func TestInterpretDictionaryType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.DictionaryStaticType{ KeyType: interpreter.PrimitiveStaticTypeInt, ValueType: interpreter.PrimitiveStaticTypeString, @@ -260,7 +260,7 @@ func TestInterpretDictionaryType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.DictionaryStaticType{ ValueType: interpreter.CompositeStaticType{ Location: utils.TestLocation, @@ -274,7 +274,7 @@ func TestInterpretDictionaryType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.DictionaryStaticType{ ValueType: interpreter.DictionaryStaticType{ KeyType: interpreter.PrimitiveStaticTypeString, @@ -320,7 +320,7 @@ func TestInterpretCompositeType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ QualifiedIdentifier: "R", Location: utils.TestLocation, @@ -331,7 +331,7 @@ func TestInterpretCompositeType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ QualifiedIdentifier: "S", Location: utils.TestLocation, @@ -357,7 +357,7 @@ func TestInterpretCompositeType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ QualifiedIdentifier: "F", Location: utils.TestLocation, @@ -368,7 +368,7 @@ func TestInterpretCompositeType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ QualifiedIdentifier: "PublicKey", Location: nil, @@ -379,7 +379,7 @@ func TestInterpretCompositeType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CompositeStaticType{ QualifiedIdentifier: "HashAlgorithm", Location: nil, @@ -406,7 +406,7 @@ func TestInterpretInterfaceType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.InterfaceStaticType{ QualifiedIdentifier: "R", Location: utils.TestLocation, @@ -416,7 +416,7 @@ func TestInterpretInterfaceType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.InterfaceStaticType{ QualifiedIdentifier: "S", Location: utils.TestLocation, @@ -449,7 +449,7 @@ func TestInterpretFunctionType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.FunctionStaticType{ Type: &sema.FunctionType{ Parameters: []sema.Parameter{ @@ -465,7 +465,7 @@ func TestInterpretFunctionType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.FunctionStaticType{ Type: &sema.FunctionType{ Parameters: []sema.Parameter{ @@ -480,7 +480,7 @@ func TestInterpretFunctionType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.FunctionStaticType{ Type: &sema.FunctionType{ ReturnTypeAnnotation: sema.StringTypeAnnotation, @@ -513,7 +513,7 @@ func TestInterpretReferenceType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ReferenceStaticType{ ReferencedType: interpreter.CompositeStaticType{ QualifiedIdentifier: "R", @@ -527,7 +527,7 @@ func TestInterpretReferenceType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ReferenceStaticType{ ReferencedType: interpreter.PrimitiveStaticTypeString, Authorization: interpreter.UnauthorizedAccess, @@ -537,7 +537,7 @@ func TestInterpretReferenceType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.ReferenceStaticType{ ReferencedType: interpreter.CompositeStaticType{ QualifiedIdentifier: "S", @@ -590,7 +590,7 @@ func TestInterpretIntersectionType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ Types: []interpreter.InterfaceStaticType{ { @@ -609,7 +609,7 @@ func TestInterpretIntersectionType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ Types: []interpreter.InterfaceStaticType{ { @@ -628,7 +628,7 @@ func TestInterpretIntersectionType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: &interpreter.IntersectionStaticType{ Types: []interpreter.InterfaceStaticType{ { @@ -677,7 +677,7 @@ func TestInterpretCapabilityType(t *testing.T) { `) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CapabilityStaticType{ BorrowType: interpreter.ReferenceStaticType{ ReferencedType: interpreter.PrimitiveStaticTypeString, @@ -689,7 +689,7 @@ func TestInterpretCapabilityType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CapabilityStaticType{ BorrowType: interpreter.ReferenceStaticType{ ReferencedType: interpreter.PrimitiveStaticTypeInt, @@ -701,7 +701,7 @@ func TestInterpretCapabilityType(t *testing.T) { ) assert.Equal(t, - interpreter.TypeValue{ + &interpreter.TypeValue{ Type: interpreter.CapabilityStaticType{ BorrowType: interpreter.ReferenceStaticType{ ReferencedType: interpreter.CompositeStaticType{ diff --git a/runtime/tests/interpreter/string_test.go b/runtime/tests/interpreter/string_test.go index 44d3f0ee16..826b02f5eb 100644 --- a/runtime/tests/interpreter/string_test.go +++ b/runtime/tests/interpreter/string_test.go @@ -342,7 +342,7 @@ func TestInterpretStringAccess(t *testing.T) { require.NoError(t, err) require.Equal(t, - interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeCharacter}, + &interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeCharacter}, result, ) } @@ -362,7 +362,7 @@ func TestInterpretCharacterLiteralType(t *testing.T) { require.NoError(t, err) require.Equal(t, - interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeCharacter}, + &interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeCharacter}, result, ) } @@ -382,7 +382,7 @@ func TestInterpretOneCharacterStringLiteralType(t *testing.T) { require.NoError(t, err) require.Equal(t, - interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeString}, + &interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeString}, result, ) } @@ -402,7 +402,7 @@ func TestInterpretCharacterLiteralTypeNoAnnotation(t *testing.T) { require.NoError(t, err) require.Equal(t, - interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeString}, + &interpreter.TypeValue{Type: interpreter.PrimitiveStaticTypeString}, result, ) } From bb650486581336c41d78e8c0a8ab5a5fd28cddef Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 9 Aug 2023 11:54:11 -0400 Subject: [PATCH 6/7] fix tests --- runtime/interpreter/interpreter.go | 25 ++++++++++--------------- runtime/interpreter/value_test.go | 7 ++++--- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 079eaf49f7..eb58ae9ac1 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -5024,8 +5024,8 @@ func (interpreter *Interpreter) MustConvertStaticAuthorizationToSemaAccess(auth // Converts the input value into a version compatible with the new entitlements feature, // with the same members/operations accessible on any references as would have been accessible in the past. -// Modifies the input `v` in place, and also returns a copy of the value -func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { +// Modifies the input `v` in place +func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { semaType := interpreter.MustSemaTypeOfValue(v) entitledType := sema.ConvertToEntitledType(interpreter, semaType) @@ -5043,24 +5043,24 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { v.BorrowedType = entitledReferenceType.Type // stored value is not converted; instead we will convert it upon load case *SomeValue: - v.value = interpreter.ConvertValueToEntitlements(v.value) + interpreter.ConvertValueToEntitlements(v.value) // reset the storable, to be recomputed on next access v.valueStorable = nil case *CompositeValue: // convert all the fields of this composite value to entitlements - v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) case *ArrayValue: entitledArrayType := entitledType.(sema.ArrayType) v.semaType = entitledArrayType v.Type = ConvertSemaArrayTypeToStaticArrayType(interpreter, entitledArrayType) // convert all the elements of this array value to entitlements - v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) case *DictionaryValue: entitledDictionaryType := entitledType.(*sema.DictionaryType) v.semaType = entitledDictionaryType v.Type = ConvertSemaDictionaryTypeToStaticDictionaryType(interpreter, entitledDictionaryType) // convert all the elements of this array value to entitlements - v.Walk(interpreter, func(v Value) { interpreter.ConvertValueToEntitlements(v) }) + v.Walk(interpreter, interpreter.ConvertValueToEntitlements) // capabilities should just have their borrow type updated; // we will update their underlying value when the capability is borrowed case *PathCapabilityValue: @@ -5071,22 +5071,17 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) Value { v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) case *TypeValue: if v.Type == nil { - return v + return } // convert the static type of the value - return NewTypeValue( + v.Type = ConvertSemaToStaticType( interpreter, - ConvertSemaToStaticType( + sema.ConvertToEntitledType( interpreter, - sema.ConvertToEntitledType( - interpreter, - interpreter.MustConvertStaticToSemaType(v.Type), - ), + interpreter.MustConvertStaticToSemaType(v.Type), ), ) } - - return v } func (interpreter *Interpreter) getElaboration(location common.Location) *sema.Elaboration { diff --git a/runtime/interpreter/value_test.go b/runtime/interpreter/value_test.go index 6cd05e056b..113ca7e7de 100644 --- a/runtime/interpreter/value_test.go +++ b/runtime/interpreter/value_test.go @@ -4945,11 +4945,12 @@ func TestConvertToEntitledValue(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - switch output := inter.ConvertValueToEntitlements(test.Input).(type) { + inter.ConvertValueToEntitlements(test.Input) + switch input := test.Input.(type) { case EquatableValue: - require.True(t, output.Equal(inter, EmptyLocationRange, test.Output)) + require.True(t, input.Equal(inter, EmptyLocationRange, test.Output)) default: - require.Equal(t, output, test.Output) + require.Equal(t, input, test.Output) } }) } From fa700044f42d6f9df7a3421a96dc12524659df07 Mon Sep 17 00:00:00 2001 From: Daniel Sainati Date: Wed, 9 Aug 2023 13:42:25 -0400 Subject: [PATCH 7/7] removed old capability value --- runtime/interpreter/interpreter.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 7ae4511983..ef394a4395 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -4565,9 +4565,6 @@ func (interpreter *Interpreter) ConvertValueToEntitlements(v Value) { v.Walk(interpreter, interpreter.ConvertValueToEntitlements) // capabilities should just have their borrow type updated; // we will update their underlying value when the capability is borrowed - case *PathCapabilityValue: - entitledCapabilityValue := entitledType.(*sema.CapabilityType) - v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType) case *IDCapabilityValue: entitledCapabilityValue := entitledType.(*sema.CapabilityType) v.BorrowType = ConvertSemaToStaticType(interpreter, entitledCapabilityValue.BorrowType)