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

Improve new static type-based dynamic type checking #1576

Merged
merged 1 commit into from
Apr 13, 2022
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
4 changes: 2 additions & 2 deletions runtime/convertTypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,8 @@ func ImportType(t cadence.Type) interpreter.StaticType {
return importInterfaceType(t.(cadence.InterfaceType))
case cadence.ReferenceType:
return interpreter.ReferenceStaticType{
Authorized: t.Authorized,
Type: ImportType(t.Type),
Authorized: t.Authorized,
BorrowedType: ImportType(t.Type),
}
case cadence.RestrictedType:
restrictions := make([]interpreter.InterfaceStaticType, 0, len(t.Restrictions))
Expand Down
4 changes: 2 additions & 2 deletions runtime/convertValues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,8 +1069,8 @@ func TestImportRuntimeType(t *testing.T) {
Type: cadence.IntType{},
},
expected: interpreter.ReferenceStaticType{
Authorized: false,
Type: interpreter.PrimitiveStaticTypeInt,
Authorized: false,
BorrowedType: interpreter.PrimitiveStaticTypeInt,
},
},
{
Expand Down
4 changes: 2 additions & 2 deletions runtime/interpreter/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1337,8 +1337,8 @@ func decodeReferenceStaticType(dec *cbor.StreamDecoder) (StaticType, error) {
}

return ReferenceStaticType{
Authorized: authorized,
Type: staticType,
Authorized: authorized,
BorrowedType: staticType,
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/interpreter/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ func (t ReferenceStaticType) Encode(e *cbor.StreamEncoder) error {
return err
}
// Encode type at array index encodedReferenceStaticTypeTypeFieldKey
return EncodeStaticType(e, t.Type)
return EncodeStaticType(e, t.BorrowedType)
}

// NOTE: NEVER change, only add/increment; ensure uint64
Expand Down
8 changes: 4 additions & 4 deletions runtime/interpreter/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3405,8 +3405,8 @@ func TestEncodeDecodeLinkValue(t *testing.T) {
value := LinkValue{
TargetPath: publicPathValue,
Type: ReferenceStaticType{
Authorized: true,
Type: PrimitiveStaticTypeBool,
Authorized: true,
BorrowedType: PrimitiveStaticTypeBool,
},
}

Expand Down Expand Up @@ -3439,8 +3439,8 @@ func TestEncodeDecodeLinkValue(t *testing.T) {
value := LinkValue{
TargetPath: publicPathValue,
Type: ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeBool,
Authorized: false,
BorrowedType: PrimitiveStaticTypeBool,
},
}

Expand Down
27 changes: 13 additions & 14 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3293,8 +3293,8 @@ var runtimeTypeConstructors = []runtimeTypeConstructor{

return TypeValue{
Type: ReferenceStaticType{
Authorized: bool(authorizedValue),
Type: typeValue.Type,
Authorized: bool(authorizedValue),
BorrowedType: typeValue.Type,
},
}
},
Expand Down Expand Up @@ -3678,30 +3678,32 @@ func (interpreter *Interpreter) IsSubTypeOfSemaType(subType StaticType, superTyp
return true
}

switch staticType := subType.(type) {
switch subType := subType.(type) {
case OptionalStaticType:
if typedSuperType, ok := superType.(*sema.OptionalType); ok {
return interpreter.IsSubTypeOfSemaType(staticType.Type, typedSuperType.Type)
if superType, ok := superType.(*sema.OptionalType); ok {
return interpreter.IsSubTypeOfSemaType(subType.Type, superType.Type)
}

switch superType {
case sema.AnyStructType, sema.AnyResourceType:
return interpreter.IsSubTypeOfSemaType(staticType.Type, superType)
return interpreter.IsSubTypeOfSemaType(subType.Type, superType)
}

case ReferenceStaticType:
if typedSuperType, ok := superType.(*sema.ReferenceType); ok {
if superType, ok := superType.(*sema.ReferenceType); ok {

// First, check that the static type of the referenced value
// is a subtype of the super type

if staticType.InnerType != nil && !interpreter.IsSubTypeOfSemaType(staticType.InnerType, typedSuperType.Type) {
if subType.ReferencedType == nil ||
!interpreter.IsSubTypeOfSemaType(subType.ReferencedType, superType.Type) {

return false
}

// If the reference value is authorized it may be downcasted

authorized := staticType.Authorized
authorized := subType.Authorized

if authorized {
return true
Expand All @@ -3710,17 +3712,14 @@ func (interpreter *Interpreter) IsSubTypeOfSemaType(subType StaticType, superTyp
// If the reference value is not authorized,
// it may not be down-casted

var borrowType sema.Type
if staticType.Type != nil {
borrowType = interpreter.MustConvertStaticToSemaType(staticType.Type)
}
borrowType := interpreter.MustConvertStaticToSemaType(subType.BorrowedType)

return sema.IsSubType(
&sema.ReferenceType{
Authorized: authorized,
Type: borrowType,
},
typedSuperType,
superType,
)
}

Expand Down
20 changes: 10 additions & 10 deletions runtime/interpreter/statictype.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,9 @@ outer:
// ReferenceStaticType

type ReferenceStaticType struct {
Authorized bool
Type StaticType
InnerType StaticType
Authorized bool
BorrowedType StaticType
ReferencedType StaticType
}

var _ StaticType = ReferenceStaticType{}
Expand All @@ -294,7 +294,7 @@ func (t ReferenceStaticType) String() string {
auth = "auth "
}

return fmt.Sprintf("%s&%s", auth, t.Type)
return fmt.Sprintf("%s&%s", auth, t.BorrowedType)
}

func (t ReferenceStaticType) Equal(other StaticType) bool {
Expand All @@ -304,7 +304,7 @@ func (t ReferenceStaticType) Equal(other StaticType) bool {
}

return t.Authorized == otherReferenceType.Authorized &&
t.Type.Equal(otherReferenceType.Type)
t.BorrowedType.Equal(otherReferenceType.BorrowedType)
}

// CapabilityStaticType
Expand Down Expand Up @@ -378,7 +378,7 @@ func ConvertSemaToStaticType(t sema.Type) StaticType {
}

case *sema.ReferenceType:
return ConvertSemaReferenceTyoeToStaticReferenceType(t)
return ConvertSemaReferenceTypeToStaticReferenceType(t)

case *sema.CapabilityType:
result := CapabilityStaticType{}
Expand Down Expand Up @@ -425,10 +425,10 @@ func ConvertSemaDictionaryTypeToStaticDictionaryType(t *sema.DictionaryType) Dic
}
}

func ConvertSemaReferenceTyoeToStaticReferenceType(t *sema.ReferenceType) ReferenceStaticType {
func ConvertSemaReferenceTypeToStaticReferenceType(t *sema.ReferenceType) ReferenceStaticType {
return ReferenceStaticType{
Authorized: t.Authorized,
Type: ConvertSemaToStaticType(t.Type),
Authorized: t.Authorized,
BorrowedType: ConvertSemaToStaticType(t.Type),
}
}

Expand Down Expand Up @@ -498,7 +498,7 @@ func ConvertStaticToSemaType(
}, err

case ReferenceStaticType:
ty, err := ConvertStaticToSemaType(t.Type, getInterface, getComposite)
ty, err := ConvertStaticToSemaType(t.BorrowedType, getInterface, getComposite)
return &sema.ReferenceType{
Authorized: t.Authorized,
Type: ty,
Expand Down
30 changes: 15 additions & 15 deletions runtime/interpreter/statictype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestCapabilityStaticType_Equal(t *testing.T) {
BorrowType: PrimitiveStaticTypeString,
}.Equal(
ReferenceStaticType{
Type: PrimitiveStaticTypeString,
BorrowedType: PrimitiveStaticTypeString,
},
),
)
Expand All @@ -106,12 +106,12 @@ func TestReferenceStaticType_Equal(t *testing.T) {

require.True(t,
ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeString,
Authorized: false,
BorrowedType: PrimitiveStaticTypeString,
}.Equal(
ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeString,
Authorized: false,
BorrowedType: PrimitiveStaticTypeString,
},
),
)
Expand All @@ -123,12 +123,12 @@ func TestReferenceStaticType_Equal(t *testing.T) {

require.False(t,
ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeInt,
Authorized: false,
BorrowedType: PrimitiveStaticTypeInt,
}.Equal(
ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeString,
Authorized: false,
BorrowedType: PrimitiveStaticTypeString,
},
),
)
Expand All @@ -140,12 +140,12 @@ func TestReferenceStaticType_Equal(t *testing.T) {

require.False(t,
ReferenceStaticType{
Authorized: false,
Type: PrimitiveStaticTypeInt,
Authorized: false,
BorrowedType: PrimitiveStaticTypeInt,
}.Equal(
ReferenceStaticType{
Authorized: true,
Type: PrimitiveStaticTypeInt,
Authorized: true,
BorrowedType: PrimitiveStaticTypeInt,
},
),
)
Expand All @@ -157,7 +157,7 @@ func TestReferenceStaticType_Equal(t *testing.T) {

require.False(t,
ReferenceStaticType{
Type: PrimitiveStaticTypeString,
BorrowedType: PrimitiveStaticTypeString,
}.Equal(
CapabilityStaticType{
BorrowType: PrimitiveStaticTypeString,
Expand Down Expand Up @@ -936,7 +936,7 @@ func TestRestrictedStaticType_Equal(t *testing.T) {
},
}).Equal(
ReferenceStaticType{
Type: PrimitiveStaticTypeInt,
BorrowedType: PrimitiveStaticTypeInt,
},
),
)
Expand Down
42 changes: 16 additions & 26 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ import (
type TypeConformanceResults map[typeConformanceResultEntry]bool

type typeConformanceResultEntry struct {
EphemeralReferenceValue *EphemeralReferenceValue
EphemeralReferenceDynamicType ReferenceStaticType
EphemeralReferenceValue *EphemeralReferenceValue
EphemeralReferenceType ReferenceStaticType
}

// SeenReferences is a set of seen references.
Expand Down Expand Up @@ -14236,20 +14236,15 @@ func (v *StorageReferenceValue) DynamicType(interpreter *Interpreter, seenRefere
}

func (v *StorageReferenceValue) StaticType(inter *Interpreter) StaticType {
var borrowedType StaticType
if v.BorrowedType != nil {
borrowedType = ConvertSemaToStaticType(v.BorrowedType)
}

referencedValue, err := v.dereference(inter, ReturnEmptyLocationRange)
if err != nil {
panic(err)
}

return ReferenceStaticType{
Authorized: v.Authorized,
Type: borrowedType,
InnerType: (*referencedValue).StaticType(inter),
Authorized: v.Authorized,
BorrowedType: ConvertSemaToStaticType(v.BorrowedType),
ReferencedType: (*referencedValue).StaticType(inter),
}
}

Expand Down Expand Up @@ -14455,11 +14450,11 @@ func (v *StorageReferenceValue) ConformsToStaticType(
return false
}

if refType.Type == nil {
if refType.BorrowedType == nil {
if v.BorrowedType != nil {
return false
}
} else if !refType.Type.Equal(ConvertSemaToStaticType(v.BorrowedType)) {
} else if !refType.BorrowedType.Equal(ConvertSemaToStaticType(v.BorrowedType)) {
return false
}

Expand All @@ -14471,7 +14466,7 @@ func (v *StorageReferenceValue) ConformsToStaticType(
return (*referencedValue).ConformsToStaticType(
interpreter,
getLocationRange,
refType.InnerType,
refType.ReferencedType,
results,
)
}
Expand Down Expand Up @@ -14580,20 +14575,15 @@ func (v *EphemeralReferenceValue) DynamicType(interpreter *Interpreter, seenRefe
}

func (v *EphemeralReferenceValue) StaticType(inter *Interpreter) StaticType {
var borrowedType StaticType
if v.BorrowedType != nil {
borrowedType = ConvertSemaToStaticType(v.BorrowedType)
}

referencedValue := v.ReferencedValue(inter, ReturnEmptyLocationRange)
if referencedValue == nil {
panic(DereferenceError{})
}

return ReferenceStaticType{
Authorized: v.Authorized,
Type: borrowedType,
InnerType: (*referencedValue).StaticType(inter),
Authorized: v.Authorized,
BorrowedType: ConvertSemaToStaticType(v.BorrowedType),
ReferencedType: (*referencedValue).StaticType(inter),
}
}

Expand Down Expand Up @@ -14789,11 +14779,11 @@ func (v *EphemeralReferenceValue) ConformsToStaticType(
return false
}

if refType.Type == nil {
if refType.BorrowedType == nil {
if v.BorrowedType != nil {
return false
}
} else if !refType.Type.Equal(ConvertSemaToStaticType(v.BorrowedType)) {
} else if !refType.BorrowedType.Equal(ConvertSemaToStaticType(v.BorrowedType)) {
return false
}

Expand All @@ -14803,8 +14793,8 @@ func (v *EphemeralReferenceValue) ConformsToStaticType(
}

entry := typeConformanceResultEntry{
EphemeralReferenceValue: v,
EphemeralReferenceDynamicType: refType,
EphemeralReferenceValue: v,
EphemeralReferenceType: refType,
}

if result, contains := results[entry]; contains {
Expand All @@ -14818,7 +14808,7 @@ func (v *EphemeralReferenceValue) ConformsToStaticType(
result := (*referencedValue).ConformsToStaticType(
interpreter,
getLocationRange,
refType.InnerType,
refType.ReferencedType,
results,
)

Expand Down
Loading