Skip to content

Commit

Permalink
Merge pull request #3089 from onflow/bastian/3088-allow-contract-inte…
Browse files Browse the repository at this point in the history
…rfaces-in-intersection-types
  • Loading branch information
turbolent authored Feb 12, 2024
2 parents eebd43c + e7de6ad commit 1f7a1f6
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 26 deletions.
11 changes: 7 additions & 4 deletions runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -982,11 +982,15 @@ func CheckIntersectionType(
// the type is ambiguous.

report(func(t *ast.IntersectionType) error {
return &AmbiguousIntersectionTypeError{Range: ast.NewRangeFromPositioned(memoryGauge, t)}
return &AmbiguousIntersectionTypeError{
Range: ast.NewRangeFromPositioned(memoryGauge, t),
}
})
return InvalidType

case common.CompositeKindResource, common.CompositeKindStructure:
case common.CompositeKindResource,
common.CompositeKindStructure,
common.CompositeKindContract:
break

default:
Expand All @@ -1011,8 +1015,7 @@ func (checker *Checker) convertIntersectionType(t *ast.IntersectionType) Type {
if ok {
intersectedCompositeKind = intersectedInterfaceType.CompositeKind
}
if !ok || (intersectedCompositeKind != common.CompositeKindResource &&
intersectedCompositeKind != common.CompositeKindStructure) {
if !ok || !intersectedCompositeKind.SupportsInterfaces() {

if !intersectedResult.IsInvalidType() {
checker.report(&InvalidIntersectedTypeError{
Expand Down
23 changes: 1 addition & 22 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3616,7 +3616,7 @@ func (*InvalidIntersectedTypeError) IsUserError() {}

func (e *InvalidIntersectedTypeError) Error() string {
return fmt.Sprintf(
"cannot restrict using non-resource/structure interface type: `%s`",
"cannot restrict using non-resource/structure/contract interface type: `%s`",
e.Type.QualifiedString(),
)
}
Expand Down Expand Up @@ -3665,27 +3665,6 @@ func (e *InvalidIntersectionTypeDuplicateError) Error() string {
)
}

// InvalidNonConformanceIntersectionError

type InvalidNonConformanceIntersectionError struct {
Type *InterfaceType
ast.Range
}

var _ SemanticError = &InvalidNonConformanceIntersectionError{}
var _ errors.UserError = &InvalidNonConformanceIntersectionError{}

func (*InvalidNonConformanceIntersectionError) isSemanticError() {}

func (*InvalidNonConformanceIntersectionError) IsUserError() {}

func (e *InvalidNonConformanceIntersectionError) Error() string {
return fmt.Sprintf(
"intersection type does not conform to restricting type: `%s`",
e.Type.QualifiedString(),
)
}

// IntersectionMemberClashError

type IntersectionMemberClashError struct {
Expand Down
103 changes: 103 additions & 0 deletions runtime/tests/checker/intersection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,109 @@ func TestCheckIntersectionType(t *testing.T) {

assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[0])
})

t.Run("contract interface", func(t *testing.T) {

_, err := ParseAndCheck(t, `
contract interface CI {}
fun test (_ c: {CI}) {}
`)

require.NoError(t, err)
})

t.Run("contract", func(t *testing.T) {

_, err := ParseAndCheck(t, `
contract C {}
fun test (_ c: {C}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})

t.Run("enum", func(t *testing.T) {

_, err := ParseAndCheck(t, `
enum E: UInt8 {}
fun test (_ e: {E}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})

t.Run("event", func(t *testing.T) {

_, err := ParseAndCheck(t, `
event E()
fun test (_ e: {E}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})

t.Run("attachment", func(t *testing.T) {

_, err := ParseAndCheck(t, `
resource R {}
attachment A for R {}
fun test (_ a: {A}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})

t.Run("entitlement", func(t *testing.T) {

_, err := ParseAndCheck(t, `
entitlement E
fun test (_ e: {E}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})

t.Run("entitlement mapping", func(t *testing.T) {

_, err := ParseAndCheck(t, `
entitlement mapping M {}
fun test (_ m: {M}) {}
`)

errs := RequireCheckerErrors(t, err, 2)

assert.IsType(t, &sema.InvalidIntersectedTypeError{}, errs[0])
// Checker is not able to infer valid composite kind based on intersection's types
assert.IsType(t, &sema.AmbiguousIntersectionTypeError{}, errs[1])
})
}

func TestCheckIntersectionTypeMemberAccess(t *testing.T) {
Expand Down

0 comments on commit 1f7a1f6

Please sign in to comment.