reflect: add PtrTo, add Value.Addr (old Addr is now UnsafeAddr)
This change makes it possible to take the address of a
struct field or slice element in order to call a method that
requires a pointer receiver.
Existing code that uses the Value.Addr method will have
to change (as gob does in this CL) to call UnsafeAddr instead.
R=r, rog
CC=golang-dev
https://golang.org/cl/4239052
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 3675be6..7a97ea1 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -1093,6 +1093,18 @@
t.Errorf("Value Method returned %d; want 250", i)
}
+ // Curried method of pointer.
+ i = NewValue(&p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Value Method returned %d; want 250", i)
+ }
+
+ // Curried method of pointer to value.
+ i = NewValue(p).Addr().Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Value Method returned %d; want 250", i)
+ }
+
// Curried method of interface value.
// Have to wrap interface value in a struct to get at it.
// Passing it to NewValue directly would
@@ -1390,3 +1402,66 @@
t.Errorf("f(o) = %d, want 2", v)
}
}
+
+func TestPtrTo(t *testing.T) {
+ var i int
+
+ typ := Typeof(i)
+ for i = 0; i < 100; i++ {
+ typ = PtrTo(typ)
+ }
+ for i = 0; i < 100; i++ {
+ typ = typ.(*PtrType).Elem()
+ }
+ if typ != Typeof(i) {
+ t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, Typeof(i))
+ }
+}
+
+func TestAddr(t *testing.T) {
+ var p struct {
+ X, Y int
+ }
+
+ v := NewValue(&p)
+ v = v.(*PtrValue).Elem()
+ v = v.Addr()
+ v = v.(*PtrValue).Elem()
+ v = v.(*StructValue).Field(0)
+ v.(*IntValue).Set(2)
+ if p.X != 2 {
+ t.Errorf("Addr.Elem.Set failed to set value")
+ }
+
+ // Again but take address of the NewValue value.
+ // Exercises generation of PtrTypes not present in the binary.
+ v = NewValue(&p)
+ v = v.Addr()
+ v = v.(*PtrValue).Elem()
+ v = v.(*PtrValue).Elem()
+ v = v.Addr()
+ v = v.(*PtrValue).Elem()
+ v = v.(*StructValue).Field(0)
+ v.(*IntValue).Set(3)
+ if p.X != 3 {
+ t.Errorf("Addr.Elem.Set failed to set value")
+ }
+
+ // Starting without pointer we should get changed value
+ // in interface.
+ v = NewValue(p)
+ v0 := v
+ v = v.Addr()
+ v = v.(*PtrValue).Elem()
+ v = v.(*StructValue).Field(0)
+ v.(*IntValue).Set(4)
+ if p.X != 3 { // should be unchanged from last time
+ t.Errorf("somehow value Set changed original p")
+ }
+ p = v0.Interface().(struct {
+ X, Y int
+ })
+ if p.X != 4 {
+ t.Errorf("Addr.Elem.Set valued to set value in top value")
+ }
+}