mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: MakeFunc: allow assignment conversions on values returned from the wrapped function
Instead of requiring exact type match, allow assignment conversions (those conversions allowed in the language spec without a cast) on the returned values. Particularly useful when the type being returned is an interface type, but the Value actually returned is a concrete value implementing that type (as it is tricky to return a Value which has interface type). RELNOTE=y Fixes #28761 Change-Id: I69eef07ca51690b2086dfa1eb549db5e4724c657 Reviewed-on: https://go-review.googlesource.com/c/go/+/174531 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
bf35b7c8b1
commit
fe83731651
2 changed files with 91 additions and 5 deletions
|
|
@ -1934,6 +1934,91 @@ func TestMakeFuncVariadic(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Dummy type that implements io.WriteCloser
|
||||
type WC struct {
|
||||
}
|
||||
|
||||
func (w *WC) Write(p []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (w *WC) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMakeFuncValidReturnAssignments(t *testing.T) {
|
||||
// reflect.Values returned from the wrapped function should be assignment-converted
|
||||
// to the types returned by the result of MakeFunc.
|
||||
|
||||
// Concrete types should be promotable to interfaces they implement.
|
||||
var f func() error
|
||||
f = MakeFunc(TypeOf(f), func([]Value) []Value {
|
||||
return []Value{ValueOf(io.EOF)}
|
||||
}).Interface().(func() error)
|
||||
f()
|
||||
|
||||
// Super-interfaces should be promotable to simpler interfaces.
|
||||
var g func() io.Writer
|
||||
g = MakeFunc(TypeOf(g), func([]Value) []Value {
|
||||
var w io.WriteCloser = &WC{}
|
||||
return []Value{ValueOf(&w).Elem()}
|
||||
}).Interface().(func() io.Writer)
|
||||
g()
|
||||
|
||||
// Channels should be promotable to directional channels.
|
||||
var h func() <-chan int
|
||||
h = MakeFunc(TypeOf(h), func([]Value) []Value {
|
||||
return []Value{ValueOf(make(chan int))}
|
||||
}).Interface().(func() <-chan int)
|
||||
h()
|
||||
|
||||
// Unnamed types should be promotable to named types.
|
||||
type T struct{ a, b, c int }
|
||||
var i func() T
|
||||
i = MakeFunc(TypeOf(i), func([]Value) []Value {
|
||||
return []Value{ValueOf(struct{ a, b, c int }{a: 1, b: 2, c: 3})}
|
||||
}).Interface().(func() T)
|
||||
i()
|
||||
}
|
||||
|
||||
func TestMakeFuncInvalidReturnAssignments(t *testing.T) {
|
||||
// Type doesn't implement the required interface.
|
||||
shouldPanic(func() {
|
||||
var f func() error
|
||||
f = MakeFunc(TypeOf(f), func([]Value) []Value {
|
||||
return []Value{ValueOf(int(7))}
|
||||
}).Interface().(func() error)
|
||||
f()
|
||||
})
|
||||
// Assigning to an interface with additional methods.
|
||||
shouldPanic(func() {
|
||||
var f func() io.ReadWriteCloser
|
||||
f = MakeFunc(TypeOf(f), func([]Value) []Value {
|
||||
var w io.WriteCloser = &WC{}
|
||||
return []Value{ValueOf(&w).Elem()}
|
||||
}).Interface().(func() io.ReadWriteCloser)
|
||||
f()
|
||||
})
|
||||
// Directional channels can't be assigned to bidirectional ones.
|
||||
shouldPanic(func() {
|
||||
var f func() chan int
|
||||
f = MakeFunc(TypeOf(f), func([]Value) []Value {
|
||||
var c <-chan int = make(chan int)
|
||||
return []Value{ValueOf(c)}
|
||||
}).Interface().(func() chan int)
|
||||
f()
|
||||
})
|
||||
// Two named types which are otherwise identical.
|
||||
shouldPanic(func() {
|
||||
type T struct{ a, b, c int }
|
||||
type U struct{ a, b, c int }
|
||||
var f func() T
|
||||
f = MakeFunc(TypeOf(f), func([]Value) []Value {
|
||||
return []Value{ValueOf(U{a: 1, b: 2, c: 3})}
|
||||
}).Interface().(func() T)
|
||||
f()
|
||||
})
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
x, y int
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue