mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
go.tools/ssa: fix bug in makeBridgeMethod for promoted interfaces.
The method index was hard-coded to zero, which works some of the time. Apparently I just forgot to implement the method-table lookup... Added regression test. R=gri CC=golang-dev https://golang.org/cl/9916043
This commit is contained in:
parent
838e9a8987
commit
1f2812fe9b
@ -20,7 +20,7 @@ type PackageInfo struct {
|
|||||||
// Type-checker deductions.
|
// Type-checker deductions.
|
||||||
types map[ast.Expr]types.Type // inferred types of expressions
|
types map[ast.Expr]types.Type // inferred types of expressions
|
||||||
constants map[ast.Expr]exact.Value // values of constant expressions
|
constants map[ast.Expr]exact.Value // values of constant expressions
|
||||||
idents map[*ast.Ident]types.Object // resoved objects for named entities
|
idents map[*ast.Ident]types.Object // resolved objects for named entities
|
||||||
typecases map[*ast.CaseClause]*types.Var // implicit vars for single-type typecases
|
typecases map[*ast.CaseClause]*types.Var // implicit vars for single-type typecases
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +47,7 @@ func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
|
|||||||
|
|
||||||
// ValueOf returns the value of expression e if it is a constant, nil
|
// ValueOf returns the value of expression e if it is a constant, nil
|
||||||
// otherwise.
|
// otherwise.
|
||||||
|
// Precondition: e belongs to the package's ASTs.
|
||||||
//
|
//
|
||||||
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
|
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
|
||||||
return info.constants[e]
|
return info.constants[e]
|
||||||
|
@ -132,6 +132,7 @@ var testdataTests = []string{
|
|||||||
"coverage.go",
|
"coverage.go",
|
||||||
"mrvchain.go",
|
"mrvchain.go",
|
||||||
"boundmeth.go",
|
"boundmeth.go",
|
||||||
|
"ifaceprom.go",
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(t *testing.T, dir, input string) bool {
|
func run(t *testing.T, dir, input string) bool {
|
||||||
|
35
ssa/interp/testdata/ifaceprom.go
vendored
Normal file
35
ssa/interp/testdata/ifaceprom.go
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Test of promotion of methods of an interface embedded within a
|
||||||
|
// struct. In particular, this test excercises that the correct
|
||||||
|
// method is called.
|
||||||
|
|
||||||
|
type I interface {
|
||||||
|
one() int
|
||||||
|
two() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
I
|
||||||
|
}
|
||||||
|
|
||||||
|
type impl struct{}
|
||||||
|
|
||||||
|
func (impl) one() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (impl) two() string {
|
||||||
|
return "two"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var s S
|
||||||
|
s.I = impl{}
|
||||||
|
if one := s.one(); one != 1 {
|
||||||
|
panic(one)
|
||||||
|
}
|
||||||
|
if two := s.two(); two != "two" {
|
||||||
|
panic(two)
|
||||||
|
}
|
||||||
|
}
|
@ -314,11 +314,15 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
|
|||||||
c.Call.Func = cand.concrete
|
c.Call.Func = cand.concrete
|
||||||
c.Call.Args = append(c.Call.Args, v)
|
c.Call.Args = append(c.Call.Args, v)
|
||||||
} else {
|
} else {
|
||||||
|
c.Call.Method = -1
|
||||||
|
iface := v.Type().Underlying().(*types.Interface)
|
||||||
|
for i, n := 0, iface.NumMethods(); i < n; i++ {
|
||||||
|
if iface.Method(i) == cand.method {
|
||||||
|
c.Call.Method = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
c.Call.Recv = v
|
c.Call.Recv = v
|
||||||
// TODO(adonovan): fix: this looks wrong! Need to
|
|
||||||
// find method index within
|
|
||||||
// v.Type().Underlying().(*types.Interface).Methods()
|
|
||||||
c.Call.Method = 0
|
|
||||||
}
|
}
|
||||||
for _, arg := range fn.Params[1:] {
|
for _, arg := range fn.Params[1:] {
|
||||||
c.Call.Args = append(c.Call.Args, arg)
|
c.Call.Args = append(c.Call.Args, arg)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user