i := timp(0)
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
- ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
+ bad(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
bad(func() { call(v.Field(0).Method(1)) }) // .t0.w
bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
- ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
- ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
- ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
- ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
+ ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
+ ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
+ ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
+ bad(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
}
}
+
+func TestIssue22031(t *testing.T) {
+ type s []struct{ C int }
+
+ type t1 struct{ s }
+ type t2 struct{ f s }
+
+ tests := []Value{
+ ValueOf(t1{s{{}}}).Field(0).Index(0).Field(0),
+ ValueOf(t2{s{{}}}).Field(0).Index(0).Field(0),
+ }
+
+ for i, test := range tests {
+ if test.CanSet() {
+ t.Errorf("%d: CanSet: got true, want false", i)
+ }
+ }
+}
return Kind(f & flagKindMask)
}
+func (f flag) ro() flag {
+ if f&flagRO != 0 {
+ return flagStickyRO
+ }
+ return 0
+}
+
// pointer returns the underlying pointer represented by v.
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
func (v Value) pointer() unsafe.Pointer {
if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)}
+ return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)}
}
// Bool returns v's underlying value.
}
x := unpackEface(eface)
if x.flag != 0 {
- x.flag |= v.flag & flagRO
+ x.flag |= v.flag.ro()
}
return x
case Ptr:
// In the latter case, we must be doing Index(0), so offset = 0,
// so v.ptr + offset is still okay.
val := unsafe.Pointer(uintptr(v.ptr) + offset)
- fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array
+ fl := v.flag&(flagIndir|flagAddr) | v.flag.ro() | flag(typ.Kind()) // bits same as overall array
return Value{typ, val, fl}
case Slice:
tt := (*sliceType)(unsafe.Pointer(v.typ))
typ := tt.elem
val := arrayAt(s.Data, i, typ.size)
- fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
+ fl := flagAddr | flagIndir | v.flag.ro() | flag(typ.Kind())
return Value{typ, val, fl}
case String:
panic("reflect: string index out of range")
}
p := arrayAt(s.Data, i, 1)
- fl := v.flag&flagRO | flag(Uint8) | flagIndir
+ fl := v.flag.ro() | flag(Uint8) | flagIndir
return Value{uint8Type, p, fl}
}
panic(&ValueError{"reflect.Value.Index", v.kind()})
return Value{}
}
typ := tt.elem
- fl := (v.flag | key.flag) & flagRO
+ fl := (v.flag | key.flag).ro()
fl |= flag(typ.Kind())
if ifaceIndir(typ) {
// Copy result so future changes to the map
tt := (*mapType)(unsafe.Pointer(v.typ))
keyType := tt.key
- fl := v.flag&flagRO | flag(keyType.Kind())
+ fl := v.flag.ro() | flag(keyType.Kind())
m := v.pointer()
mlen := int(0)
s.Data = base
}
- fl := v.flag&flagRO | flagIndir | flag(Slice)
+ fl := v.flag.ro() | flagIndir | flag(Slice)
return Value{typ.common(), unsafe.Pointer(&x), fl}
}
s.Data = base
}
- fl := v.flag&flagRO | flagIndir | flag(Slice)
+ fl := v.flag.ro() | flagIndir | flag(Slice)
return Value{typ.common(), unsafe.Pointer(&x), fl}
}
case directlyAssignable(dst, v.typ):
// Overwrite type so that they match.
// Same memory layout, so no harm done.
- fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl := v.flag&(flagAddr|flagIndir) | v.flag.ro()
fl |= flag(dst.Kind())
return Value{dst, v.ptr, fl}
// convertOp: intXX -> [u]intXX
func cvtInt(v Value, t Type) Value {
- return makeInt(v.flag&flagRO, uint64(v.Int()), t)
+ return makeInt(v.flag.ro(), uint64(v.Int()), t)
}
// convertOp: uintXX -> [u]intXX
func cvtUint(v Value, t Type) Value {
- return makeInt(v.flag&flagRO, v.Uint(), t)
+ return makeInt(v.flag.ro(), v.Uint(), t)
}
// convertOp: floatXX -> intXX
func cvtFloatInt(v Value, t Type) Value {
- return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t)
+ return makeInt(v.flag.ro(), uint64(int64(v.Float())), t)
}
// convertOp: floatXX -> uintXX
func cvtFloatUint(v Value, t Type) Value {
- return makeInt(v.flag&flagRO, uint64(v.Float()), t)
+ return makeInt(v.flag.ro(), uint64(v.Float()), t)
}
// convertOp: intXX -> floatXX
func cvtIntFloat(v Value, t Type) Value {
- return makeFloat(v.flag&flagRO, float64(v.Int()), t)
+ return makeFloat(v.flag.ro(), float64(v.Int()), t)
}
// convertOp: uintXX -> floatXX
func cvtUintFloat(v Value, t Type) Value {
- return makeFloat(v.flag&flagRO, float64(v.Uint()), t)
+ return makeFloat(v.flag.ro(), float64(v.Uint()), t)
}
// convertOp: floatXX -> floatXX
func cvtFloat(v Value, t Type) Value {
- return makeFloat(v.flag&flagRO, v.Float(), t)
+ return makeFloat(v.flag.ro(), v.Float(), t)
}
// convertOp: complexXX -> complexXX
func cvtComplex(v Value, t Type) Value {
- return makeComplex(v.flag&flagRO, v.Complex(), t)
+ return makeComplex(v.flag.ro(), v.Complex(), t)
}
// convertOp: intXX -> string
func cvtIntString(v Value, t Type) Value {
- return makeString(v.flag&flagRO, string(v.Int()), t)
+ return makeString(v.flag.ro(), string(v.Int()), t)
}
// convertOp: uintXX -> string
func cvtUintString(v Value, t Type) Value {
- return makeString(v.flag&flagRO, string(v.Uint()), t)
+ return makeString(v.flag.ro(), string(v.Uint()), t)
}
// convertOp: []byte -> string
func cvtBytesString(v Value, t Type) Value {
- return makeString(v.flag&flagRO, string(v.Bytes()), t)
+ return makeString(v.flag.ro(), string(v.Bytes()), t)
}
// convertOp: string -> []byte
func cvtStringBytes(v Value, t Type) Value {
- return makeBytes(v.flag&flagRO, []byte(v.String()), t)
+ return makeBytes(v.flag.ro(), []byte(v.String()), t)
}
// convertOp: []rune -> string
func cvtRunesString(v Value, t Type) Value {
- return makeString(v.flag&flagRO, string(v.runes()), t)
+ return makeString(v.flag.ro(), string(v.runes()), t)
}
// convertOp: string -> []rune
func cvtStringRunes(v Value, t Type) Value {
- return makeRunes(v.flag&flagRO, []rune(v.String()), t)
+ return makeRunes(v.flag.ro(), []rune(v.String()), t)
}
// convertOp: direct copy
ptr = c
f &^= flagAddr
}
- return Value{t, ptr, v.flag&flagRO | f} // v.flag&flagRO|f == f?
+ return Value{t, ptr, v.flag.ro() | f} // v.flag.ro()|f == f?
}
// convertOp: concrete -> interface
} else {
ifaceE2I(typ.(*rtype), x, target)
}
- return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)}
+ return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)}
}
// convertOp: interface -> interface
func cvtI2I(v Value, typ Type) Value {
if v.IsNil() {
ret := Zero(typ)
- ret.flag |= v.flag & flagRO
+ ret.flag |= v.flag.ro()
return ret
}
return cvtT2I(v.Elem(), typ)