summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/reflect/all_test.go85
-rw-r--r--src/reflect/value.go11
2 files changed, 91 insertions, 5 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 964d8c6e95..dbee822cea 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -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
}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 79a7c6a204..f0db434009 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -560,11 +560,6 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
}
for i, typ := range ftyp.out() {
v := out[i]
- if v.typ != typ {
- panic("reflect: function created by MakeFunc using " + funcName(f) +
- " returned wrong type: have " +
- out[i].typ.String() + " for " + typ.String())
- }
if v.flag&flagRO != 0 {
panic("reflect: function created by MakeFunc using " + funcName(f) +
" returned value obtained from unexported field")
@@ -574,6 +569,12 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
continue
}
addr := add(ptr, off, "typ.size > 0")
+
+ // Convert v to type typ if v is assignable to a variable
+ // of type t in the language spec.
+ // See issue 28761.
+ v = v.assignTo("reflect.MakeFunc", typ, addr)
+
// We are writing to stack. No write barrier.
if v.flag&flagIndir != 0 {
memmove(addr, v.ptr, typ.size)