Skip to content

Commit 1a1138d

Browse files
committed
Fix method calls for interfaces
1 parent 68aa569 commit 1a1138d

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

checker/checker.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -393,15 +393,19 @@ func (v *visitor) MemberNode(node *ast.MemberNode) (reflect.Type, info) {
393393
// First, check methods defined on base type itself,
394394
// independent of which type it is. Without dereferencing.
395395
if m, ok := base.MethodByName(name.Value); ok {
396-
node.Method = true
397-
node.MethodIndex = m.Index
398-
node.Name = name.Value
399396
if base.Kind() == reflect.Interface {
400397
// In case of interface type method will not have a receiver,
401398
// and to prevent checker decreasing numbers of in arguments
402399
// return method type as not method (second argument is false).
400+
401+
// Also, we can not use m.Index here, because it will be
402+
// different indexes for different types which implement
403+
// the same interface.
403404
return m.Type, info{}
404405
} else {
406+
node.Method = true
407+
node.MethodIndex = m.Index
408+
node.Name = name.Value
405409
return m.Type, info{method: true}
406410
}
407411
}

expr_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -1811,6 +1811,48 @@ func TestEval_nil_in_maps(t *testing.T) {
18111811
})
18121812
}
18131813

1814+
type Bar interface {
1815+
Bar() int
1816+
}
1817+
type Foo interface {
1818+
Foo() Bar
1819+
}
1820+
1821+
type FooImpl struct{}
1822+
1823+
func (f FooImpl) Foo() Bar {
1824+
return BarImpl{}
1825+
}
1826+
1827+
type BarImpl struct{}
1828+
1829+
// Aba is a special method that is not part of the Bar interface,
1830+
// but is used to test that the correct method is called. "Aba" name
1831+
// is chosen to be before "Bar" in the alphabet.
1832+
func (b BarImpl) Aba() bool {
1833+
return true
1834+
}
1835+
1836+
func (b BarImpl) Bar() int {
1837+
return 42
1838+
}
1839+
1840+
func TestEval_interface_method(t *testing.T) {
1841+
require.True(t, BarImpl{}.Aba())
1842+
require.True(t, BarImpl{}.Bar() == 42)
1843+
1844+
env := map[string]interface{}{
1845+
"var": FooImpl{},
1846+
}
1847+
p, err := expr.Compile(`var.Foo().Bar()`, expr.Env(env))
1848+
1849+
assert.NoError(t, err)
1850+
1851+
out, err := expr.Run(p, env)
1852+
assert.NoError(t, err)
1853+
assert.Equal(t, 42, out)
1854+
}
1855+
18141856
// Mock types
18151857

18161858
type mockEnv struct {

0 commit comments

Comments
 (0)