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:
parent
f5ceeb94a8
commit
139160eb30
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user