diff mbox

libgo patch committed: Fix reflection of variadic methods

Message ID mcrmw9dp2wj.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 3, 2014, 3:51 p.m. UTC
This patch from Michael Hudson-Doyle fixes PR 61877 which is about using
reflection to get a variadic method value.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r 9a88882ca32c libgo/go/reflect/all_test.go
--- a/libgo/go/reflect/all_test.go	Fri Oct 03 08:13:20 2014 -0700
+++ b/libgo/go/reflect/all_test.go	Fri Oct 03 08:50:04 2014 -0700
@@ -1543,7 +1543,17 @@ 
 	fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
 	ValueOf(&fn).Elem().Set(fv)
 
-	r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+	r := fn(1, 2, 3)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
+
+	r = fn(1, []int{2, 3}...)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
+
+	r = fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
 	if r[0] != 2 || r[1] != 3 {
 		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
 	}
@@ -1552,6 +1562,17 @@ 
 	if r[0] != 2 || r[1] != 3 {
 		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
 	}
+
+	f := fv.Interface().(func(int, ...int) []int)
+
+	r = f(1, 2, 3)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
+	r = f(1, []int{2, 3}...)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
 }
 
 type Point struct {
@@ -1569,6 +1590,24 @@ 
 	return p.x*p.x*scale + p.y*p.y*scale
 }
 
+// This will be index 2.
+func (p Point) GCMethod(k int) int {
+	runtime.GC()
+	return k + p.x
+}
+
+// This will be index 3.
+func (p Point) TotalDist(points ...Point) int {
+	tot := 0
+	for _, q := range points {
+		dx := q.x - p.x
+		dy := q.y - p.y
+		tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test.
+
+	}
+	return tot
+}
+
 func TestMethod(t *testing.T) {
 	// Non-curried method of type.
 	p := Point{3, 4}
@@ -1751,6 +1790,37 @@ 
 	}
 }
 
+func TestVariadicMethodValue(t *testing.T) {
+	p := Point{3, 4}
+	points := []Point{{20, 21}, {22, 23}, {24, 25}}
+	want := int64(p.TotalDist(points[0], points[1], points[2]))
+
+	// Curried method of value.
+	tfunc := TypeOf((func(...Point) int)(nil))
+	v := ValueOf(p).Method(3)
+	if tt := v.Type(); tt != tfunc {
+		t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc)
+	}
+	i := ValueOf(v.Interface()).Call([]Value{ValueOf(points[0]), ValueOf(points[1]), ValueOf(points[2])})[0].Int()
+	if i != want {
+		t.Errorf("Variadic Method returned %d; want %d", i, want)
+	}
+	i = ValueOf(v.Interface()).CallSlice([]Value{ValueOf(points)})[0].Int()
+	if i != want {
+		t.Errorf("Variadic Method CallSlice returned %d; want %d", i, want)
+	}
+
+	f := v.Interface().(func(...Point) int)
+	i = int64(f(points[0], points[1], points[2]))
+	if i != want {
+		t.Errorf("Variadic Method Interface returned %d; want %d", i, want)
+	}
+	i = int64(f(points...))
+	if i != want {
+		t.Errorf("Variadic Method Interface Slice returned %d; want %d", i, want)
+	}
+}
+
 // Reflect version of $GOROOT/test/method5.go
 
 // Concrete types implementing M method.
@@ -3718,11 +3788,6 @@ 
 	f.Call([]Value{})
 }
 
-func (p Point) GCMethod(k int) int {
-	runtime.GC()
-	return k + p.x
-}
-
 func TestReflectMethodTraceback(t *testing.T) {
 	p := Point{3, 4}
 	m := ValueOf(p).MethodByName("GCMethod")
diff -r 9a88882ca32c libgo/go/reflect/makefunc.go
--- a/libgo/go/reflect/makefunc.go	Fri Oct 03 08:13:20 2014 -0700
+++ b/libgo/go/reflect/makefunc.go	Fri Oct 03 08:50:04 2014 -0700
@@ -117,29 +117,21 @@ 
 	ftyp := (*funcType)(unsafe.Pointer(t))
 	method := int(v.flag) >> flagMethodShift
 
-	var code uintptr
-	var ffi *ffiData
+	fv := &makeFuncImpl{
+		typ:    ftyp,
+		method: method,
+		rcvr:   rcvr,
+	}
+
 	switch runtime.GOARCH {
 	case "amd64", "386":
 		// Indirect Go func value (dummy) to obtain actual
 		// code address. (A Go func value is a pointer to a C
 		// function pointer. http://golang.org/s/go11func.)
 		dummy := makeFuncStub
-		code = **(**uintptr)(unsafe.Pointer(&dummy))
+		fv.code = **(**uintptr)(unsafe.Pointer(&dummy))
 	default:
-		code, ffi = makeFuncFFI(ftyp,
-			func(in []Value) []Value {
-				m := rcvr.Method(method)
-				return m.Call(in)
-			})
-	}
-
-	fv := &makeFuncImpl{
-		code:   code,
-		typ:    ftyp,
-		method: method,
-		rcvr:   rcvr,
-		ffi:    ffi,
+		fv.code, fv.ffi = makeFuncFFI(ftyp, fv.call)
 	}
 
 	return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
@@ -160,28 +152,21 @@ 
 	t := typ.common()
 	ftyp := (*funcType)(unsafe.Pointer(t))
 
-	var code uintptr
-	var ffi *ffiData
+	impl := &makeFuncImpl{
+		typ:    ftyp,
+		method: -2,
+		rcvr:   v,
+	}
+
 	switch runtime.GOARCH {
 	case "amd64", "386":
 		// Indirect Go func value (dummy) to obtain actual
 		// code address. (A Go func value is a pointer to a C
 		// function pointer. http://golang.org/s/go11func.)
 		dummy := makeFuncStub
-		code = **(**uintptr)(unsafe.Pointer(&dummy))
+		impl.code = **(**uintptr)(unsafe.Pointer(&dummy))
 	default:
-		code, ffi = makeFuncFFI(ftyp,
-			func(in []Value) []Value {
-				return v.Call(in)
-			})
-	}
-
-	impl := &makeFuncImpl{
-		code:   code,
-		typ:    ftyp,
-		method: -2,
-		rcvr:   v,
-		ffi:    ffi,
+		impl.code, impl.ffi = makeFuncFFI(ftyp, impl.call)
 	}
 
 	return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
@@ -192,9 +177,17 @@ 
 	if c.method == -1 {
 		return c.fn(in)
 	} else if c.method == -2 {
-		return c.rcvr.Call(in)
+		if c.typ.IsVariadic() {
+			return c.rcvr.CallSlice(in)
+		} else {
+			return c.rcvr.Call(in)
+		}
 	} else {
 		m := c.rcvr.Method(c.method)
-		return m.Call(in)
+		if c.typ.IsVariadic() {
+			return m.CallSlice(in)
+		} else {
+			return m.Call(in)
+		}
 	}
 }