1
0
mirror of https://github.com/golang/go synced 2024-10-01 22:18:32 -06:00

reflect: fix interface to interface conversion in Call

Call is meant to mirror the language semantics, which allow:

	var r io.ReadWriter
	f := func(io.Reader){}
	f(r)

even though the conversion from io.ReadWriter to io.Reader is
being applied to a nil interface. This is different from an explicit
conversion:

	_ = r.(io.Reader)
	f(r.(io.Reader))

Both of those lines panic, but the implicit conversion does not.

By using E2I, which is the implementation of the explicit conversion,
the reflect.Call equivalent of f(r) was inadvertently panicking.
Avoid the panic.

Fixes #22143.

Change-Id: I6b2f5b808e0cd3b89ae8bc75881e307bf1c25558
Reviewed-on: https://go-review.googlesource.com/80736
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Russ Cox 2017-11-29 14:44:43 -05:00
parent f22cf7131a
commit eafa29bdce
2 changed files with 15 additions and 0 deletions

View File

@ -1631,6 +1631,15 @@ func TestFunc(t *testing.T) {
}
}
func TestCallConvert(t *testing.T) {
v := ValueOf(new(io.ReadWriter)).Elem()
f := ValueOf(func(r io.Reader) io.Reader { return r })
out := f.Call([]Value{v})
if len(out) != 1 || out[0].Type() != TypeOf(new(io.Reader)).Elem() || !out[0].IsNil() {
t.Errorf("expected [nil], got %v", out)
}
}
type emptyStruct struct{}
type nonEmptyStruct struct {

View File

@ -2197,6 +2197,12 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
if target == nil {
target = unsafe_New(dst)
}
if v.Kind() == Interface && v.IsNil() {
// A nil ReadWriter passed to nil Reader is OK,
// but using ifaceE2I below will panic.
// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.
return Value{dst, nil, flag(Interface)}
}
x := valueInterface(v, false)
if dst.NumMethod() == 0 {
*(*interface{})(target) = x