diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index c463b61c57b896..4b215f120c963b 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -5019,6 +5019,17 @@ func TestStructOfWithInterface(t *testing.T) { }) } +func TestStructOfTooManyFields(t *testing.T) { + // Bug Fix: #25402 - this should not panic + tt := StructOf([]StructField{ + {Name: "Time", Type: TypeOf(time.Time{}), Anonymous: true}, + }) + + if _, present := tt.MethodByName("After"); !present { + t.Errorf("Expected method `After` to be found") + } +} + func TestChanOf(t *testing.T) { // check construction and use of type not in binary type T string diff --git a/src/reflect/type.go b/src/reflect/type.go index a04234ca692825..5bbab79fc0775d 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1889,6 +1889,8 @@ func MapOf(key, elem Type) Type { return ti.(Type) } +// TODO(crawshaw): as these funcTypeFixedN structs have no methods, +// they could be defined at runtime using the StructOf function. type funcTypeFixed4 struct { funcType args [4]*rtype @@ -2278,42 +2280,6 @@ type structTypeUncommon struct { u uncommonType } -// A *rtype representing a struct is followed directly in memory by an -// array of method objects representing the methods attached to the -// struct. To get the same layout for a run time generated type, we -// need an array directly following the uncommonType memory. The types -// structTypeFixed4, ...structTypeFixedN are used to do this. -// -// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN. - -// TODO(crawshaw): as these structTypeFixedN and funcTypeFixedN structs -// have no methods, they could be defined at runtime using the StructOf -// function. - -type structTypeFixed4 struct { - structType - u uncommonType - m [4]method -} - -type structTypeFixed8 struct { - structType - u uncommonType - m [8]method -} - -type structTypeFixed16 struct { - structType - u uncommonType - m [16]method -} - -type structTypeFixed32 struct { - structType - u uncommonType - m [32]method -} - // isLetter reports whether a given 'rune' is classified as a Letter. func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) @@ -2571,33 +2537,26 @@ func StructOf(fields []StructField) Type { var typ *structType var ut *uncommonType - switch { - case len(methods) == 0: + if len(methods) == 0 { t := new(structTypeUncommon) typ = &t.structType ut = &t.u - case len(methods) <= 4: - t := new(structTypeFixed4) - typ = &t.structType - ut = &t.u - copy(t.m[:], methods) - case len(methods) <= 8: - t := new(structTypeFixed8) - typ = &t.structType - ut = &t.u - copy(t.m[:], methods) - case len(methods) <= 16: - t := new(structTypeFixed16) - typ = &t.structType - ut = &t.u - copy(t.m[:], methods) - case len(methods) <= 32: - t := new(structTypeFixed32) - typ = &t.structType - ut = &t.u - copy(t.m[:], methods) - default: - panic("reflect.StructOf: too many methods") + } else { + // A *rtype representing a struct is followed directly in memory by an + // array of method objects representing the methods attached to the + // struct. To get the same layout for a run time generated type, we + // need an array directly following the uncommonType memory. + // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN. + tt := New(StructOf([]StructField{ + {Name: "S", Type: TypeOf(structType{})}, + {Name: "U", Type: TypeOf(uncommonType{})}, + {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))}, + })) + + typ = (*structType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) + ut = (*uncommonType)(unsafe.Pointer(tt.Elem().Field(1).UnsafeAddr())) + + copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods) } // TODO(sbinet): Once we allow embedding multiple types, // methods will need to be sorted like the compiler does.