Skip to content

Commit 87d5f6b

Browse files
reflect: make StructOf panic for methods that don't work
When StructOf is used with an anonymous field that has methods, and that anonymous field is not the first field, the methods we generate are incorrect because they do not offset to the field as required. If we encounter that case, panic rather than doing the wrong thing. Fixes #20824 Updates #15924 Change-Id: I3b0901ddbc6d58af5f7e84660b5e3085a431035d Reviewed-on: https://go-review.googlesource.com/47035 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 792f9c9 commit 87d5f6b

File tree

2 files changed

+69
-32
lines changed

2 files changed

+69
-32
lines changed

src/reflect/all_test.go

+56-30
Original file line numberDiff line numberDiff line change
@@ -4686,41 +4686,67 @@ func TestStructOfWithInterface(t *testing.T) {
46864686
}
46874687

46884688
for i, table := range tests {
4689-
rt := StructOf(
4690-
[]StructField{
4691-
{
4692-
Name: table.name,
4693-
Anonymous: true,
4694-
PkgPath: "",
4695-
Type: table.typ,
4696-
},
4697-
},
4698-
)
4699-
rv := New(rt).Elem()
4700-
rv.Field(0).Set(table.val)
4689+
for j := 0; j < 2; j++ {
4690+
var fields []StructField
4691+
if j == 1 {
4692+
fields = append(fields, StructField{
4693+
Name: "Dummy",
4694+
PkgPath: "",
4695+
Type: TypeOf(int(0)),
4696+
})
4697+
}
4698+
fields = append(fields, StructField{
4699+
Name: table.name,
4700+
Anonymous: true,
4701+
PkgPath: "",
4702+
Type: table.typ,
4703+
})
47014704

4702-
if _, ok := rv.Interface().(Iface); ok != table.impl {
4703-
if table.impl {
4704-
t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ)
4705-
} else {
4706-
t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ)
4705+
// We currently do not correctly implement methods
4706+
// for anonymous fields other than the first.
4707+
// Therefore, for now, we expect those methods
4708+
// to not exist. See issues 15924 and 20824.
4709+
// When those issues are fixed, this test of panic
4710+
// should be removed.
4711+
if j == 1 && table.impl {
4712+
func() {
4713+
defer func() {
4714+
if err := recover(); err == nil {
4715+
t.Errorf("test-%d-%d did not panic", i, j)
4716+
}
4717+
}()
4718+
_ = StructOf(fields)
4719+
}()
4720+
continue
47074721
}
4708-
continue
4709-
}
47104722

4711-
if !table.impl {
4712-
continue
4713-
}
4723+
rt := StructOf(fields)
4724+
rv := New(rt).Elem()
4725+
rv.Field(j).Set(table.val)
47144726

4715-
v := rv.Interface().(Iface).Get()
4716-
if v != want {
4717-
t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, v, want)
4718-
}
4727+
if _, ok := rv.Interface().(Iface); ok != table.impl {
4728+
if table.impl {
4729+
t.Errorf("test-%d-%d: type=%v fails to implement Iface.\n", i, j, table.typ)
4730+
} else {
4731+
t.Errorf("test-%d-%d: type=%v should NOT implement Iface\n", i, j, table.typ)
4732+
}
4733+
continue
4734+
}
47194735

4720-
fct := rv.MethodByName("Get")
4721-
out := fct.Call(nil)
4722-
if !DeepEqual(out[0].Interface(), want) {
4723-
t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, out[0].Interface(), want)
4736+
if !table.impl {
4737+
continue
4738+
}
4739+
4740+
v := rv.Interface().(Iface).Get()
4741+
if v != want {
4742+
t.Errorf("test-%d-%d: x.Get()=%v. want=%v\n", i, j, v, want)
4743+
}
4744+
4745+
fct := rv.MethodByName("Get")
4746+
out := fct.Call(nil)
4747+
if !DeepEqual(out[0].Interface(), want) {
4748+
t.Errorf("test-%d-%d: x.Get()=%v. want=%v\n", i, j, out[0].Interface(), want)
4749+
}
47244750
}
47254751
}
47264752
}

src/reflect/type.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -2434,7 +2434,7 @@ func StructOf(fields []StructField) Type {
24342434
ift := (*interfaceType)(unsafe.Pointer(ft))
24352435
for im, m := range ift.methods {
24362436
if ift.nameOff(m.name).pkgPath() != "" {
2437-
// TODO(sbinet)
2437+
// TODO(sbinet). Issue 15924.
24382438
panic("reflect: embedded interface with unexported method(s) not implemented")
24392439
}
24402440

@@ -2492,10 +2492,15 @@ func StructOf(fields []StructField) Type {
24922492
case Ptr:
24932493
ptr := (*ptrType)(unsafe.Pointer(ft))
24942494
if unt := ptr.uncommon(); unt != nil {
2495+
if i > 0 && unt.mcount > 0 {
2496+
// Issue 15924.
2497+
panic("reflect: embedded type with methods not implemented if type is not first field")
2498+
}
24952499
for _, m := range unt.methods() {
24962500
mname := ptr.nameOff(m.name)
24972501
if mname.pkgPath() != "" {
2498-
// TODO(sbinet)
2502+
// TODO(sbinet).
2503+
// Issue 15924.
24992504
panic("reflect: embedded interface with unexported method(s) not implemented")
25002505
}
25012506
methods = append(methods, method{
@@ -2511,6 +2516,7 @@ func StructOf(fields []StructField) Type {
25112516
mname := ptr.nameOff(m.name)
25122517
if mname.pkgPath() != "" {
25132518
// TODO(sbinet)
2519+
// Issue 15924.
25142520
panic("reflect: embedded interface with unexported method(s) not implemented")
25152521
}
25162522
methods = append(methods, method{
@@ -2523,10 +2529,15 @@ func StructOf(fields []StructField) Type {
25232529
}
25242530
default:
25252531
if unt := ft.uncommon(); unt != nil {
2532+
if i > 0 && unt.mcount > 0 {
2533+
// Issue 15924.
2534+
panic("reflect: embedded type with methods not implemented if type is not first field")
2535+
}
25262536
for _, m := range unt.methods() {
25272537
mname := ft.nameOff(m.name)
25282538
if mname.pkgPath() != "" {
25292539
// TODO(sbinet)
2540+
// Issue 15924.
25302541
panic("reflect: embedded interface with unexported method(s) not implemented")
25312542
}
25322543
methods = append(methods, method{

0 commit comments

Comments
 (0)