Skip to content

Commit 83092a4

Browse files
reflect: prevent additional StructOf embedded method cases
The current implementation does not generate wrappers for methods of embedded non-interface types. We can only skip the wrapper if kindDirectIface of the generated struct type matches kindDirectIface of the embedded type. Panic if that is not the case. It would be better to actually generate wrappers, but that can be done later. Updates #15924 Fixes #24782 Change-Id: I01f5c76d9a07f44e1b04861bfe9f9916a04e65ca Reviewed-on: https://go-review.googlesource.com/121316 Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent d144dd7 commit 83092a4

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

src/reflect/all_test.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4817,13 +4817,29 @@ func (i StructI) Get() int { return int(i) }
48174817

48184818
type StructIPtr int
48194819

4820-
func (i *StructIPtr) Get() int { return int(*i) }
4820+
func (i *StructIPtr) Get() int { return int(*i) }
4821+
func (i *StructIPtr) Set(v int) { *(*int)(i) = v }
4822+
4823+
type SettableStruct struct {
4824+
SettableField int
4825+
}
4826+
4827+
func (p *SettableStruct) Set(v int) { p.SettableField = v }
4828+
4829+
type SettablePointer struct {
4830+
SettableField *int
4831+
}
4832+
4833+
func (p *SettablePointer) Set(v int) { *p.SettableField = v }
48214834

48224835
func TestStructOfWithInterface(t *testing.T) {
48234836
const want = 42
48244837
type Iface interface {
48254838
Get() int
48264839
}
4840+
type IfaceSet interface {
4841+
Set(int)
4842+
}
48274843
tests := []struct {
48284844
name string
48294845
typ Type
@@ -4931,6 +4947,76 @@ func TestStructOfWithInterface(t *testing.T) {
49314947
}
49324948
}
49334949
}
4950+
4951+
// Test an embedded nil pointer with pointer methods.
4952+
fields := []StructField{{
4953+
Name: "StructIPtr",
4954+
Anonymous: true,
4955+
Type: PtrTo(TypeOf(StructIPtr(want))),
4956+
}}
4957+
rt := StructOf(fields)
4958+
rv := New(rt).Elem()
4959+
// This should panic since the pointer is nil.
4960+
shouldPanic(func() {
4961+
rv.Interface().(IfaceSet).Set(want)
4962+
})
4963+
4964+
// Test an embedded nil pointer to a struct with pointer methods.
4965+
4966+
fields = []StructField{{
4967+
Name: "SettableStruct",
4968+
Anonymous: true,
4969+
Type: PtrTo(TypeOf(SettableStruct{})),
4970+
}}
4971+
rt = StructOf(fields)
4972+
rv = New(rt).Elem()
4973+
// This should panic since the pointer is nil.
4974+
shouldPanic(func() {
4975+
rv.Interface().(IfaceSet).Set(want)
4976+
})
4977+
4978+
// The behavior is different if there is a second field,
4979+
// since now an interface value holds a pointer to the struct
4980+
// rather than just holding a copy of the struct.
4981+
fields = []StructField{
4982+
{
4983+
Name: "SettableStruct",
4984+
Anonymous: true,
4985+
Type: PtrTo(TypeOf(SettableStruct{})),
4986+
},
4987+
{
4988+
Name: "EmptyStruct",
4989+
Anonymous: true,
4990+
Type: StructOf(nil),
4991+
},
4992+
}
4993+
// With the current implementation this is expected to panic.
4994+
// Ideally it should work and we should be able to see a panic
4995+
// if we call the Set method.
4996+
shouldPanic(func() {
4997+
StructOf(fields)
4998+
})
4999+
5000+
// Embed a field that can be stored directly in an interface,
5001+
// with a second field.
5002+
fields = []StructField{
5003+
{
5004+
Name: "SettablePointer",
5005+
Anonymous: true,
5006+
Type: TypeOf(SettablePointer{}),
5007+
},
5008+
{
5009+
Name: "EmptyStruct",
5010+
Anonymous: true,
5011+
Type: StructOf(nil),
5012+
},
5013+
}
5014+
// With the current implementation this is expected to panic.
5015+
// Ideally it should work and we should be able to call the
5016+
// Set and Get methods.
5017+
shouldPanic(func() {
5018+
StructOf(fields)
5019+
})
49345020
}
49355021

49365022
func TestChanOf(t *testing.T) {

src/reflect/type.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,9 @@ func StructOf(fields []StructField) Type {
24672467
// Issue 15924.
24682468
panic("reflect: embedded type with methods not implemented if type is not first field")
24692469
}
2470+
if len(fields) > 1 {
2471+
panic("reflect: embedded type with methods not implemented if there is more than one field")
2472+
}
24702473
for _, m := range unt.methods() {
24712474
mname := ptr.nameOff(m.name)
24722475
if mname.pkgPath() != "" {
@@ -2504,6 +2507,9 @@ func StructOf(fields []StructField) Type {
25042507
// Issue 15924.
25052508
panic("reflect: embedded type with methods not implemented if type is not first field")
25062509
}
2510+
if len(fields) > 1 && ft.kind&kindDirectIface != 0 {
2511+
panic("reflect: embedded type with methods not implemented for non-pointer type")
2512+
}
25072513
for _, m := range unt.methods() {
25082514
mname := ft.nameOff(m.name)
25092515
if mname.pkgPath() != "" {

0 commit comments

Comments
 (0)