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:
Alan Donovan 2013-05-31 16:36:03 -04:00
parent 838e9a8987
commit 1f2812fe9b
4 changed files with 46 additions and 5 deletions

View File

@ -20,7 +20,7 @@ type PackageInfo struct {
// Type-checker deductions.
types map[ast.Expr]types.Type // inferred types of 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
}
@ -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
// otherwise.
// Precondition: e belongs to the package's ASTs.
//
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
return info.constants[e]

View File

@ -132,6 +132,7 @@ var testdataTests = []string{
"coverage.go",
"mrvchain.go",
"boundmeth.go",
"ifaceprom.go",
}
func run(t *testing.T, dir, input string) bool {

35
ssa/interp/testdata/ifaceprom.go vendored Normal file
View 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)
}
}

View File

@ -314,11 +314,15 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
c.Call.Func = cand.concrete
c.Call.Args = append(c.Call.Args, v)
} 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
// 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:] {
c.Call.Args = append(c.Call.Args, arg)