Skip to content

Commit

Permalink
Find common interface for composite types
Browse files Browse the repository at this point in the history
  • Loading branch information
SupunS committed Jun 24, 2021
1 parent 03496eb commit b6c5c9b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 7 deletions.
83 changes: 76 additions & 7 deletions runtime/sema/type_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,21 +369,34 @@ func findCommonSupperType(joinedTypeTag TypeTag, types ...Type) Type {
return BlockType
case deployedContractMask:
return DeployedContractType
case pathTypeMask:
return PathType
case capabilityPathTypeMask:
return CapabilityPathType
case privatePathTypeMask:
return PrivatePathType
case publicPathTypeMask:
return PublicPathType
case storagePathTypeMask:
return StoragePathType

case compositeTypeMask:
// We reach here if all are composite types.
// Therefore check for member types, and decide the
// common supertype based on the member types.
var prevType Type
for _, typ := range types {
if prevType == nil {
prevType = typ
continue
}

if !typ.Equal(prevType) {
return commonSuperTypeOfComposites(types)
}
}

return prevType

// All derived types goes here.
case arrayTypeMask,
dictionaryTypeMask,
compositeTypeMask,
referenceTypeMask,
optionalTypeMask,
genericTypeMask,
Expand All @@ -396,7 +409,7 @@ func findCommonSupperType(joinedTypeTag TypeTag, types ...Type) Type {
// We reach here if all types belongs to same kind.
// e.g: All are arrays, all are dictionaries, etc.
// Therefore check for member types, and decide the
// common suprtype based on the member types.
// common supertype based on the member types.
var prevType Type
for _, typ := range types {
if prevType == nil {
Expand Down Expand Up @@ -465,15 +478,71 @@ func commonSuperTypeOfHeterogeneousTypes(types []Type) Type {
isResource := typ.IsResourceType()
hasResources = hasResources || isResource
hasStructs = hasStructs || !isResource

if hasResources && hasStructs {
return NeverType
}
}

if hasResources {
if hasStructs {
return AnyResourceType
}

return AnyStructType
}

func commonSuperTypeOfComposites(types []Type) Type {
var hasStructs, hasResources bool

commonInterfaces := map[string]bool{}
commonInterfacesList := make([]*InterfaceType, 0)

hasCommonInterface := true

for i, typ := range types {
isResource := typ.IsResourceType()
hasResources = hasResources || isResource
hasStructs = hasStructs || !isResource

if hasResources && hasStructs {
// If the types has both structs and resources,
// then there's no common super type.
return NeverType
}

if hasCommonInterface {
compositeType := typ.(*CompositeType)

if i == 0 {
for _, interfaceType := range compositeType.ExplicitInterfaceConformances {
commonInterfaces[interfaceType.QualifiedIdentifier()] = true
commonInterfacesList = append(commonInterfacesList, interfaceType)
}
} else {
intersection := map[string]bool{}
commonInterfacesList = make([]*InterfaceType, 0)

for _, interfaceType := range compositeType.ExplicitInterfaceConformances {
if _, ok := commonInterfaces[interfaceType.QualifiedIdentifier()]; ok {
intersection[interfaceType.QualifiedIdentifier()] = true
commonInterfacesList = append(commonInterfacesList, interfaceType)
}
}

commonInterfaces = intersection
}

if len(commonInterfaces) == 0 {
hasCommonInterface = false
}
}
}

if hasCommonInterface {
return commonInterfacesList[0]
}

if hasResources {
return AnyResourceType
}

Expand Down
60 changes: 60 additions & 0 deletions runtime/sema/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,40 @@ func TestCommonSuperType(t *testing.T) {
})

t.Run("Structs & Resources", func(t *testing.T) {

testLocation := common.StringLocation("test")

interfaceType1 := &InterfaceType{
Location: testLocation,
Identifier: "I1",
CompositeKind: common.CompositeKindStructure,
Members: NewStringMemberOrderedMap(),
}

interfaceType2 := &InterfaceType{
Location: testLocation,
Identifier: "I2",
CompositeKind: common.CompositeKindStructure,
Members: NewStringMemberOrderedMap(),
}

interfaceType3 := &InterfaceType{
Location: testLocation,
Identifier: "I3",
CompositeKind: common.CompositeKindStructure,
Members: NewStringMemberOrderedMap(),
}

newCompositeWithInterfaces := func(name string, interfaces ...*InterfaceType) *CompositeType {
return &CompositeType{
Location: testLocation,
Identifier: name,
Kind: common.CompositeKindStructure,
ExplicitInterfaceConformances: interfaces,
Members: NewStringMemberOrderedMap(),
}
}

tests := []testCase{
{
name: "all anyStructs",
Expand Down Expand Up @@ -936,6 +970,32 @@ func TestCommonSuperType(t *testing.T) {
},
expectedSuperType: AnyStructType,
},
{
name: "common interface",
types: []Type{
newCompositeWithInterfaces("Foo", interfaceType1, interfaceType2),
newCompositeWithInterfaces("Bar", interfaceType2, interfaceType3),
newCompositeWithInterfaces("Baz", interfaceType1, interfaceType2, interfaceType3),
},
expectedSuperType: interfaceType2,
},
{
name: "multiple common interfaces",
types: []Type{
newCompositeWithInterfaces("Foo", interfaceType1, interfaceType2),
newCompositeWithInterfaces("Baz", interfaceType1, interfaceType2, interfaceType3),
},
expectedSuperType: interfaceType1,
},
{
name: "no common interfaces",
types: []Type{
newCompositeWithInterfaces("Foo", interfaceType1),
newCompositeWithInterfaces("Baz", interfaceType2),
newCompositeWithInterfaces("Baz", interfaceType3),
},
expectedSuperType: AnyStructType,
},
}

testLeastCommonSuperType(t, tests)
Expand Down

0 comments on commit b6c5c9b

Please sign in to comment.