1
0
mirror of https://github.com/golang/go synced 2024-11-12 05:30:21 -07:00

exp/ssa: fix bug in bridge method

Bridge methods for embedded interfaces were
passing the interface twice: once as receiver,
once as first param.
Covered by $GOROOT/test/ddd.go.

Also:
- invent names ("arg%d") for parameters if missing.
- refactoring: move common code for bridge methods into
  createParams and emitTailCall.

R=gri
CC=golang-dev
https://golang.org/cl/7437047
This commit is contained in:
Alan Donovan 2013-03-01 12:51:19 -05:00
parent f5ceeb94a8
commit 139160eb30
3 changed files with 24 additions and 28 deletions

View File

@ -23,7 +23,6 @@ package ssa
// TODO(adonovan):
// - fix: support f(g()) where g has multiple result parameters.
// - fix: multiple labels on same statement.
import (
"fmt"

View File

@ -221,11 +221,17 @@ func emitExtract(f *Function, tuple Value, index int, typ types.Type) Value {
return f.emit(e)
}
// emitTailCall emits to f a function call in tail position.
// emitTailCall emits to f a function call in tail position,
// passing on all but the first formal parameter to f as actual
// values in the call. Intended for delegating bridge methods.
// Precondition: f does/will not use deferred procedure calls.
// Postcondition: f.currentBlock is nil.
//
func emitTailCall(f *Function, call *Call) {
for _, arg := range f.Params[1:] {
call.Args = append(call.Args, arg)
}
call.Type_ = &types.Result{Values: f.Signature.Results}
tuple := f.emit(call)
var ret Ret
switch {

View File

@ -272,13 +272,7 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
}
fn.start(nil)
fn.addSpilledParam(sig.Recv)
var last *Parameter
for _, p := range fn.Signature.Params {
last = fn.addParam(p.Name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
createParams(fn)
// Each bridge method performs a sequence of selections,
// then tailcalls the promoted method.
@ -315,22 +309,30 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
fn.Pos = c.Func.(*Function).Pos // TODO(adonovan): fix: wrong.
c.Pos = fn.Pos // TODO(adonovan): fix: wrong.
c.Args = append(c.Args, v)
for _, arg := range fn.Params[1:] {
c.Args = append(c.Args, arg)
}
} else {
c.Recv = v
c.Method = 0
for _, arg := range fn.Params {
c.Args = append(c.Args, arg)
}
}
c.Type_ = &types.Result{Values: sig.Results}
emitTailCall(fn, &c)
fn.finish()
return fn
}
// createParams creates parameters for bridge method fn based on its Signature.
func createParams(fn *Function) {
var last *Parameter
for i, p := range fn.Signature.Params {
name := p.Name
if name == "" {
name = fmt.Sprintf("arg%d", i)
}
last = fn.addParam(name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
}
// Thunks for standalone interface methods ----------------------------------------
// makeImethodThunk returns a synthetic thunk function permitting an
@ -373,21 +375,10 @@ func makeImethodThunk(prog *Program, typ types.Type, id Id) *Function {
// TODO(adonovan): set fn.Pos to location of interface method ast.Field.
fn.start(nil)
fn.addParam("recv", typ)
var last *Parameter
for _, p := range fn.Signature.Params {
last = fn.addParam(p.Name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
createParams(fn)
var c Call
c.Method = index
c.Recv = fn.Params[0]
for _, arg := range fn.Params[1:] {
c.Args = append(c.Args, arg)
}
c.Type_ = &types.Result{Values: sig.Results}
emitTailCall(fn, &c)
fn.finish()
return fn