Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix migration of built-in types #3205

Merged
merged 6 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions migrations/statictypes/statictype_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,18 @@ func (m *StaticTypeMigration) maybeConvertStaticType(staticType, parentType inte
convertedType = compositeTypeConverter(staticType)
}

// Convert built-in types in composite type form to primitive type
if convertedType == nil && staticType.Location == nil {
primitiveStaticType := interpreter.PrimitiveStaticTypeFromTypeID(staticType.TypeID)
if primitiveStaticType != interpreter.PrimitiveStaticTypeUnknown {
convertedPrimitiveStaticType := m.maybeConvertStaticType(primitiveStaticType, parentType)
if convertedPrimitiveStaticType != nil {
return convertedPrimitiveStaticType
}
return primitiveStaticType
}
}

// Interface types need to be placed in intersection types.
// If the composite type was converted to an interface type,
// and if the parent type is not an intersection type,
Expand Down
123 changes: 123 additions & 0 deletions migrations/statictypes/statictype_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,84 @@ func TestStaticTypeMigration(t *testing.T) {
)
})

t.Run("TypeValue with reference to AuthAccount (as primitive)", func(t *testing.T) {
t.Parallel()

staticTypeMigration := NewStaticTypeMigration()

actual := migrate(t,
staticTypeMigration,
interpreter.NewUnmeteredTypeValue(
interpreter.NewDictionaryStaticType(nil,
interpreter.PrimitiveStaticTypeAddress,
interpreter.NewCapabilityStaticType(nil,
interpreter.NewReferenceStaticType(
nil,
interpreter.UnauthorizedAccess,
interpreter.PrimitiveStaticTypeAuthAccount, //nolint:staticcheck
),
),
),
),
true,
)
assert.Equal(t,
interpreter.NewUnmeteredTypeValue(
interpreter.NewDictionaryStaticType(nil,
interpreter.PrimitiveStaticTypeAddress,
interpreter.NewCapabilityStaticType(nil,
// NOTE: NOT reference to reference type
authAccountReferenceType,
),
),
),
actual,
)
})

t.Run("TypeValue with reference to AuthAccount (as composite)", func(t *testing.T) {
t.Parallel()

staticTypeMigration := NewStaticTypeMigration()

authAccountTypeID := interpreter.PrimitiveStaticTypeAuthAccount.ID() //nolint:staticcheck

actual := migrate(t,
staticTypeMigration,
interpreter.NewUnmeteredTypeValue(
interpreter.NewDictionaryStaticType(nil,
interpreter.PrimitiveStaticTypeAddress,
interpreter.NewCapabilityStaticType(nil,
interpreter.NewReferenceStaticType(
nil,
interpreter.UnauthorizedAccess,
// NOTE: AuthAccount as composite type
interpreter.NewCompositeStaticType(
nil,
nil,
string(authAccountTypeID),
authAccountTypeID,
),
),
),
),
),
true,
)
assert.Equal(t,
interpreter.NewUnmeteredTypeValue(
interpreter.NewDictionaryStaticType(nil,
interpreter.PrimitiveStaticTypeAddress,
interpreter.NewCapabilityStaticType(nil,
// NOTE: NOT reference to reference type
authAccountReferenceType,
),
),
),
actual,
)
})

t.Run("PathCapabilityValue with nil borrow type", func(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -718,6 +796,51 @@ func TestStaticTypeMigration(t *testing.T) {

assert.Equal(t, expected, actual)
})

t.Run(
"composite types of (non-deprecated) built-in types are converted to primitive static types",
func(t *testing.T) {
t.Parallel()

test := func(t *testing.T, ty interpreter.PrimitiveStaticType) {

typeID := ty.ID()

t.Run(string(typeID), func(t *testing.T) {
t.Parallel()

staticTypeMigration := NewStaticTypeMigration()

actual := migrate(t,
staticTypeMigration,
interpreter.NewUnmeteredTypeValue(
// NOTE: AuthAccount as composite type
interpreter.NewCompositeStaticType(
nil,
nil,
string(typeID),
typeID,
),
),
true,
)
assert.Equal(t,
interpreter.NewUnmeteredTypeValue(ty),
actual,
)
})
}

for ty := interpreter.PrimitiveStaticTypeUnknown + 1; ty < interpreter.PrimitiveStaticType_Count; ty++ {
if !ty.IsDefined() || ty.IsDeprecated() { //nolint:staticcheck
continue
}

test(t, ty)
}
},
)

}

func TestMigratingNestedContainers(t *testing.T) {
Expand Down
71 changes: 71 additions & 0 deletions runtime/interpreter/primitivestatictype.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@
PrimitiveStaticTypeAccountKey:
// These types are deprecated, and only exist for migration purposes
return UnknownElementSize

case PrimitiveStaticTypeUnknown:
case PrimitiveStaticType_Count:
}

panic(errors.NewUnexpectedError("missing case for %s", t))
Expand Down Expand Up @@ -422,6 +425,35 @@
}

func (t PrimitiveStaticType) ID() TypeID {

// Handle deprecated types specially, because they do not have a sema type equivalent anymore
switch t {
turbolent marked this conversation as resolved.
Show resolved Hide resolved
case PrimitiveStaticTypeAuthAccount: //nolint:staticcheck
return "AuthAccount"
case PrimitiveStaticTypePublicAccount: //nolint:staticcheck
return "PublicAccount"
case PrimitiveStaticTypeAuthAccountContracts: //nolint:staticcheck
return "AuthAccount.Contracts"
case PrimitiveStaticTypePublicAccountContracts: //nolint:staticcheck
return "PublicAccount.Contracts"
case PrimitiveStaticTypeAuthAccountKeys: //nolint:staticcheck
return "AuthAccount.Keys"
case PrimitiveStaticTypePublicAccountKeys: //nolint:staticcheck
return "PublicAccount.Keys"
case PrimitiveStaticTypeAuthAccountInbox: //nolint:staticcheck
return "AuthAccount.Inbox"
case PrimitiveStaticTypeAuthAccountStorageCapabilities: //nolint:staticcheck
return "AuthAccount.StorageCapabilities"
case PrimitiveStaticTypeAuthAccountAccountCapabilities: //nolint:staticcheck
return "AuthAccount.AccountCapabilities"
case PrimitiveStaticTypeAuthAccountCapabilities: //nolint:staticcheck
return "AuthAccount.Capabilities"
case PrimitiveStaticTypePublicAccountCapabilities: //nolint:staticcheck
return "PublicAccount.Capabilities"
case PrimitiveStaticTypeAccountKey: //nolint:staticcheck
return "AccountKey"
}

return t.SemaType().ID()
}

Expand Down Expand Up @@ -654,6 +686,21 @@
case PrimitiveStaticTypePublicAccount: //nolint:staticcheck
// deprecated, but needed for migration purposes
return sema.AccountReferenceType

case PrimitiveStaticTypeAuthAccountContracts:
case PrimitiveStaticTypePublicAccountContracts:
case PrimitiveStaticTypeAuthAccountKeys:
case PrimitiveStaticTypePublicAccountKeys:
case PrimitiveStaticTypeAccountKey:
case PrimitiveStaticTypeAuthAccountInbox:
case PrimitiveStaticTypeAuthAccountStorageCapabilities:
case PrimitiveStaticTypeAuthAccountAccountCapabilities:
case PrimitiveStaticTypeAuthAccountCapabilities:
case PrimitiveStaticTypePublicAccountCapabilities:
panic(errors.NewUnexpectedError("cannot convert deprecated type %s", t))

Check warning on line 700 in runtime/interpreter/primitivestatictype.go

View check run for this annotation

Codecov / codecov/patch

runtime/interpreter/primitivestatictype.go#L699-L700

Added lines #L699 - L700 were not covered by tests

case PrimitiveStaticTypeUnknown:
case PrimitiveStaticType_Count:
}

if t.IsDeprecated() {
Expand Down Expand Up @@ -919,3 +966,27 @@

return NewPrimitiveStaticType(memoryGauge, typ)
}

var primitiveStaticTypesByTypeID = map[TypeID]PrimitiveStaticType{}

func init() {
// Check all defined primitive static types,
// and construct a type ID to primitive static type mapping
for ty := PrimitiveStaticTypeUnknown + 1; ty < PrimitiveStaticType_Count; ty++ {
if !ty.IsDefined() {
continue
}

_ = ty.elementSize()

primitiveStaticTypesByTypeID[ty.ID()] = ty
}
}

func PrimitiveStaticTypeFromTypeID(typeID TypeID) PrimitiveStaticType {
ty, ok := primitiveStaticTypesByTypeID[typeID]
if !ok {
return PrimitiveStaticTypeUnknown
}
return ty
}
Loading