From 139160eb30b34ebb289c36fcbc97df5952b56dc9 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 1 Mar 2013 12:51:19 -0500 Subject: [PATCH] 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 --- src/pkg/exp/ssa/builder.go | 1 - src/pkg/exp/ssa/emit.go | 8 ++++++- src/pkg/exp/ssa/promote.go | 43 +++++++++++++++----------------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/pkg/exp/ssa/builder.go b/src/pkg/exp/ssa/builder.go index 0e62104e2e..79f7285761 100644 --- a/src/pkg/exp/ssa/builder.go +++ b/src/pkg/exp/ssa/builder.go @@ -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" diff --git a/src/pkg/exp/ssa/emit.go b/src/pkg/exp/ssa/emit.go index 1246306fb7..16661f3bd3 100644 --- a/src/pkg/exp/ssa/emit.go +++ b/src/pkg/exp/ssa/emit.go @@ -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 { diff --git a/src/pkg/exp/ssa/promote.go b/src/pkg/exp/ssa/promote.go index 0b206eab33..91d4491c14 100644 --- a/src/pkg/exp/ssa/promote.go +++ b/src/pkg/exp/ssa/promote.go @@ -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