Skip to content

Commit

Permalink
Merge pull request #2674 from onflow/sainati/interface-inheritance-ne…
Browse files Browse the repository at this point in the history
…sted

Fix interface inheritance for nested interfaces
  • Loading branch information
dsainati1 authored Jul 22, 2023
2 parents c59c3be + 29ccac3 commit 52fd154
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 10 deletions.
6 changes: 6 additions & 0 deletions runtime/sema/check_composite_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,12 @@ func (checker *Checker) declareCompositeLikeMembersAndValue(
DocString: nestedCompositeDeclaration.DeclarationDocString(),
})
}
for _, nestedInterfaceDeclaration := range members.Interfaces() {
// resolve conformances
nestedInterfaceType := checker.Elaboration.InterfaceDeclarationType(nestedInterfaceDeclaration)
nestedInterfaceType.ExplicitInterfaceConformances =
checker.explicitInterfaceConformances(nestedInterfaceDeclaration, nestedInterfaceType)
}
for _, nestedCompositeDeclaration := range nestedComposites {
declareNestedComposite(nestedCompositeDeclaration)
}
Expand Down
5 changes: 5 additions & 0 deletions runtime/sema/check_interface_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ func (checker *Checker) declareInterfaceMembers(declaration *ast.InterfaceDeclar
// Declare nested declarations' members

for _, nestedInterfaceDeclaration := range declaration.Members.Interfaces() {
// resolve conformances
nestedInterfaceType := checker.Elaboration.InterfaceDeclarationType(nestedInterfaceDeclaration)
nestedInterfaceType.ExplicitInterfaceConformances =
checker.explicitInterfaceConformances(nestedInterfaceDeclaration, nestedInterfaceType)

checker.declareInterfaceMembers(nestedInterfaceDeclaration)
}

Expand Down
18 changes: 8 additions & 10 deletions runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,16 +373,7 @@ func (checker *Checker) CheckProgram(program *ast.Program) {
// Therefore, this is done in two steps.

for _, declaration := range program.InterfaceDeclarations() {
checker.declareInterfaceType(declaration)
}

for _, declaration := range program.InterfaceDeclarations() {
interfaceType := checker.Elaboration.InterfaceDeclarationType(declaration)

// Resolve conformances
interfaceType.ExplicitInterfaceConformances =
checker.explicitInterfaceConformances(declaration, interfaceType)

interfaceType := checker.declareInterfaceType(declaration)
VisitThisAndNested(interfaceType, registerInElaboration)
}

Expand All @@ -395,6 +386,13 @@ func (checker *Checker) CheckProgram(program *ast.Program) {
VisitThisAndNested(compositeType, registerInElaboration)
}

// Resolve conformances
for _, declaration := range program.InterfaceDeclarations() {
interfaceType := checker.Elaboration.InterfaceDeclarationType(declaration)
interfaceType.ExplicitInterfaceConformances =
checker.explicitInterfaceConformances(declaration, interfaceType)
}

for _, declaration := range program.AttachmentDeclarations() {
compositeType := checker.declareAttachmentType(declaration)

Expand Down
197 changes: 197 additions & 0 deletions runtime/tests/checker/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4393,3 +4393,200 @@ func TestCheckInheritedInterfacesSubtyping(t *testing.T) {
require.NoError(t, err)
})
}

func TestNestedInterfaceInheritance(t *testing.T) {

t.Parallel()

t.Run("mixed top level", func(t *testing.T) {

_, err := ParseAndCheck(t,
`
resource interface Y: C.X {}
contract C {
resource interface X {}
}
`,
)

require.NoError(t, err)
})

t.Run("mixed top level interface", func(t *testing.T) {

_, err := ParseAndCheck(t,
`
resource interface Y: C.X {}
contract interface C {
resource interface X {}
}
`,
)

require.NoError(t, err)
})

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

_, err := ParseAndCheck(t,
`
contract C {
resource interface TopInterface {}
resource interface MiddleInterface: TopInterface {}
resource ConcreteResource: MiddleInterface {}
fun createR(): @{TopInterface} {
return <-create ConcreteResource()
}
}
`,
)

require.NoError(t, err)
})

t.Run("all in one contract reverse order", func(t *testing.T) {

_, err := ParseAndCheck(t,
`
contract C {
resource ConcreteResource: MiddleInterface {}
resource interface MiddleInterface: TopInterface {}
resource interface TopInterface {}
fun createR(): @{TopInterface} {
return <-create ConcreteResource()
}
}
`,
)

require.NoError(t, err)
})

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

_, err := ParseAndCheck(t,
`
contract interface C {
resource interface TopInterface {}
resource interface MiddleInterface: TopInterface {}
fun createR(m: @{MiddleInterface}): @{TopInterface} {
return <-m
}
}
`,
)

require.NoError(t, err)
})

t.Run("all in one contract interface reverse order", func(t *testing.T) {

_, err := ParseAndCheck(t,
`
contract interface C {
resource interface MiddleInterface: TopInterface {}
resource interface TopInterface {}
fun createR(m: @{MiddleInterface}): @{TopInterface} {
return <-m
}
}
`,
)

require.NoError(t, err)
})

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

_, err := ParseAndCheck(t,
`
contract interface CI {
resource interface TopInterface {}
resource interface MiddleInterface: TopInterface {}
}
contract C {
resource ConcreteResource: CI.MiddleInterface {}
fun createR(): @{CI.TopInterface} {
return <-create ConcreteResource()
}
}
`,
)

require.NoError(t, err)
})

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

_, err := ParseAndCheck(t,
`
contract C {
resource ConcreteResource: CI.MiddleInterface {}
fun createR(): @{CI.TopInterface} {
return <-create ConcreteResource()
}
}
contract interface CI {
resource interface MiddleInterface: TopInterface {}
resource interface TopInterface {}
}
`,
)

require.NoError(t, err)
})

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

_, err := ParseAndCheck(t,
`
contract C {
resource ConcreteResource: CI.MiddleInterface {}
fun createR(): @{C1.TopInterface} {
return <-create ConcreteResource()
}
}
contract interface CI {
resource interface MiddleInterface: C1.TopInterface {}
}
contract C1 {
resource interface TopInterface {}
}
`,
)

require.NoError(t, err)
})

t.Run("mixed with top levels", func(t *testing.T) {

_, err := ParseAndCheck(t,
`
contract C {
resource ConcreteResource: CI.MiddleInterface {}
fun createR(): @{SuperTopInterface} {
return <-create ConcreteResource()
}
}
contract C1 {
resource interface TopInterface: SuperTopInterface {}
}
contract interface CI {
resource interface MiddleInterface: C1.TopInterface {}
}
resource interface SuperTopInterface {}
`,
)

require.NoError(t, err)
})

}
34 changes: 34 additions & 0 deletions runtime/tests/interpreter/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -883,3 +883,37 @@ func TestInterpretInterfaceFunctionConditionsInheritance(t *testing.T) {
assert.Equal(t, []string{"A", "D", "F", "E", "C", "B"}, logs)
})
}

func TestRuntimeNestedInterfaceCast(t *testing.T) {

t.Parallel()

inter, err := parseCheckAndInterpretWithOptions(t, `
access(all) contract C {
access(all) resource interface TopInterface {}
access(all) resource interface MiddleInterface: TopInterface {}
access(all) resource ConcreteResource: MiddleInterface {}
access(all) fun createMiddleInterface(): @{MiddleInterface} {
return <-create ConcreteResource()
}
}
access(all) fun main() {
let x <- C.createMiddleInterface()
let y <- x as! @{C.TopInterface}
destroy y
}
`,
ParseCheckAndInterpretOptions{
CheckerConfig: &sema.Config{},
Config: &interpreter.Config{
ContractValueHandler: makeContractValueHandler(nil, nil, nil),
},
},
)
require.NoError(t, err)

_, err = inter.Invoke("main")
require.NoError(t, err)
}

0 comments on commit 52fd154

Please sign in to comment.