Skip to content

Commit

Permalink
Merge pull request #2686 from onflow/sainati/inherited-member
Browse files Browse the repository at this point in the history
Fix interface member inheritance
  • Loading branch information
dsainati1 authored Aug 1, 2023
2 parents 3de2d1a + 88806df commit 22597d4
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
10 changes: 10 additions & 0 deletions runtime/sema/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -4951,6 +4951,16 @@ func (t *InterfaceType) initializeMemberResolvers() {
t.memberResolversOnce.Do(func() {
members := MembersMapAsResolvers(t.Members)

// add any inherited members from up the inheritance chain
for _, conformance := range t.EffectiveInterfaceConformances() {
for name, member := range conformance.InterfaceType.GetMembers() { //nolint:maprange
if _, ok := members[name]; !ok {
members[name] = member
}
}

}

t.memberResolvers = withBuiltinMembers(t, members)
})
}
Expand Down
66 changes: 66 additions & 0 deletions runtime/tests/checker/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4095,6 +4095,72 @@ func TestCheckInterfaceTypeDefinitionInheritance(t *testing.T) {

}

func TestInheritedInterfaceMembers(t *testing.T) {
t.Parallel()

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

t.Parallel()

_, err := ParseAndCheck(t, `
resource interface A {
let foo: String
}
resource interface B: A {}
resource C: B {
let foo: String
init() {
self.foo = ""
}
}
fun test() {
let c: @{B} <- create C()
c.foo
destroy c
}
`)

require.NoError(t, err)
})

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

t.Parallel()

_, err := ParseAndCheck(t, `
resource interface A {
fun foo ()
}
resource interface B: A {}
fun test(c: @{B}) {
c.foo()
destroy c
}
`)

require.NoError(t, err)
})

t.Run("doubly inherited interface function", func(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
resource interface A {
fun foo ()
}
resource interface B: A {}
resource interface C: B {}
fun test(c: @{C}) {
c.foo()
destroy c
}
`)

require.NoError(t, err)
})
}

func TestCheckInterfaceEventsInheritance(t *testing.T) {

t.Parallel()
Expand Down
34 changes: 34 additions & 0 deletions runtime/tests/interpreter/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,40 @@ func TestInterpretInterfaceDefaultImplementation(t *testing.T) {
array.Get(inter, interpreter.EmptyLocationRange, 1),
)
})

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

t.Parallel()

inter := parseCheckAndInterpret(t, `
struct interface I {
fun test(): Int {
return 3
}
}
struct interface J: I {}
struct S: J {}
fun foo(_ s: {J}): Int {
return s.test()
}
fun main(): Int {
return foo(S())
}
`)

value, err := inter.Invoke("main")
require.NoError(t, err)

assert.Equal(t,
interpreter.NewUnmeteredIntValueFromInt64(3),
value,
)
})
}

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

0 comments on commit 22597d4

Please sign in to comment.