Skip to content

Commit b848853

Browse files
fix: func reflect impl for named functions, updated tests
Co-authored-by: Ethan Lewis <[email protected]>
1 parent ee7dde4 commit b848853

File tree

4 files changed

+104
-12
lines changed

4 files changed

+104
-12
lines changed

src/reflect/all_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,6 +3312,8 @@ func TestMethodPkgPath(t *testing.T) {
33123312
}
33133313
}
33143314
3315+
*/
3316+
33153317
func TestVariadicType(t *testing.T) {
33163318
// Test example from Type documentation.
33173319
var f func(x int, y ...float64)
@@ -3335,6 +3337,8 @@ func TestVariadicType(t *testing.T) {
33353337
t.Error(s)
33363338
}
33373339

3340+
/*
3341+
33383342
type inner struct {
33393343
x int
33403344
}

src/reflect/type.go

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -608,14 +608,22 @@ func (t *rawType) String() string {
608608
s += " }"
609609
return s
610610
case Func:
611+
isVariadic := t.IsVariadic()
611612

612613
f := "func("
613614
for i := 0; i < t.NumIn(); i++ {
614615
if i > 0 {
615616
f += ", "
616617
}
617-
f += t.In(i).String()
618+
619+
input := t.In(i).String()
620+
if isVariadic && i == t.NumIn()-1 {
621+
f += "..."
622+
input = input[2:]
623+
}
624+
f += input
618625
}
626+
619627
f += ") "
620628

621629
var rets string
@@ -1069,21 +1077,36 @@ func (t *rawType) ConvertibleTo(u Type) bool {
10691077
}
10701078

10711079
func (t *rawType) IsVariadic() bool {
1072-
// need to test if bool mapped to int set by compiler
1080+
if t.isNamed() {
1081+
named := (*namedType)(unsafe.Pointer(t))
1082+
t = named.elem
1083+
}
1084+
10731085
if t.Kind() != Func {
10741086
panic("reflect: IsVariadic of non-func type")
10751087
}
1088+
10761089
return (*funcType)(unsafe.Pointer(t)).variadic
10771090
}
10781091

10791092
func (t *rawType) NumIn() int {
1093+
if t.isNamed() {
1094+
named := (*namedType)(unsafe.Pointer(t))
1095+
return int((*funcType)(unsafe.Pointer(named.elem)).inCount)
1096+
}
1097+
10801098
if t.Kind() != Func {
10811099
panic("reflect: NumIn of non-func type")
10821100
}
10831101
return int((*funcType)(unsafe.Pointer(t)).inCount)
10841102
}
10851103

10861104
func (t *rawType) NumOut() int {
1105+
if t.isNamed() {
1106+
named := (*namedType)(unsafe.Pointer(t))
1107+
return int((*funcType)(unsafe.Pointer(named.elem)).outCount)
1108+
}
1109+
10871110
if t.Kind() != Func {
10881111
panic("reflect: NumOut of non-func type")
10891112
}
@@ -1163,33 +1186,43 @@ func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
11631186
}
11641187

11651188
func (t *rawType) In(i int) Type {
1189+
if t.isNamed() {
1190+
named := (*namedType)(unsafe.Pointer(t))
1191+
t = named.elem
1192+
}
1193+
11661194
if t.Kind() != Func {
11671195
panic(errTypeField)
11681196
}
1169-
descriptor := (*funcType)(unsafe.Pointer(t.underlying()))
1170-
if uint(i) >= uint(descriptor.inCount) {
1197+
fType := (*funcType)(unsafe.Pointer(t))
1198+
if uint(i) >= uint(fType.inCount) {
11711199
panic("reflect: field index out of range")
11721200
}
11731201

1174-
pointer := (unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
1175-
return (*rawType)(*(**rawType)(pointer))
1202+
pointer := (unsafe.Add(unsafe.Pointer(&fType.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
1203+
return (*(**rawType)(pointer))
11761204
}
11771205

11781206
func (t *rawType) Out(i int) Type {
1207+
if t.isNamed() {
1208+
named := (*namedType)(unsafe.Pointer(t))
1209+
t = named.elem
1210+
}
1211+
11791212
if t.Kind() != Func {
11801213
panic(errTypeField)
11811214
}
11821215

1183-
descriptor := (*funcType)(unsafe.Pointer(t.underlying()))
1184-
if uint(i) >= uint(descriptor.outCount) {
1216+
fType := (*funcType)(unsafe.Pointer(t))
1217+
1218+
if uint(i) >= uint(fType.outCount) {
11851219
panic("reflect: field index out of range")
11861220
}
11871221

11881222
// Shift the index by the number of input parameters.
1189-
i = i + int((*funcType)(unsafe.Pointer(t)).inCount)
1190-
1191-
pointer := (unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
1192-
return (*rawType)(*(**rawType)(pointer))
1223+
i = i + int(fType.inCount)
1224+
pointer := (unsafe.Add(unsafe.Pointer(&fType.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
1225+
return (*(**rawType)(pointer))
11931226
}
11941227

11951228
// OverflowComplex reports whether the complex128 x cannot be represented by type t.

src/reflect/type_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func TestTypeFor(t *testing.T) {
1313
type (
1414
mystring string
1515
myiface interface{}
16+
myfunc func()
1617
)
1718

1819
testcases := []struct {
@@ -25,6 +26,7 @@ func TestTypeFor(t *testing.T) {
2526
{new(mystring), reflect.TypeFor[mystring]()},
2627
{new(any), reflect.TypeFor[any]()},
2728
{new(myiface), reflect.TypeFor[myiface]()},
29+
{new(myfunc), reflect.TypeFor[myfunc]()},
2830
}
2931
for _, tc := range testcases {
3032
want := reflect.ValueOf(tc.wantFrom).Elem().Type()

src/reflect/value_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,59 @@ func TestTinyStruct(t *testing.T) {
487487
}
488488
}
489489

490+
func TestTinyFunc(t *testing.T) {
491+
type barStruct struct {
492+
QuxString string
493+
BazInt int
494+
}
495+
496+
type foobar func(bar barStruct, x int, v ...string) string
497+
498+
var fb foobar
499+
500+
reffb := TypeOf(fb)
501+
502+
numIn := reffb.NumIn()
503+
if want := 3; numIn != want {
504+
t.Errorf("NumIn=%v, want %v", numIn, want)
505+
}
506+
507+
numOut := reffb.NumOut()
508+
if want := 1; numOut != want {
509+
t.Errorf("NumOut=%v, want %v", numOut, want)
510+
}
511+
512+
in0 := reffb.In(0)
513+
if want := TypeOf(barStruct{}); in0 != want {
514+
t.Errorf("In(0)=%v, want %v", in0, want)
515+
}
516+
517+
in1 := reffb.In(1)
518+
if want := TypeOf(0); in1 != want {
519+
t.Errorf("In(1)=%v, want %v", in1, want)
520+
}
521+
522+
in2 := reffb.In(2)
523+
if want := TypeOf([]string{}); in2 != want {
524+
t.Errorf("In(2)=%v, want %v", in2, want)
525+
}
526+
527+
out0 := reffb.Out(0)
528+
if want := TypeOf(""); out0 != want {
529+
t.Errorf("Out(0)=%v, want %v", out0, want)
530+
}
531+
532+
isVariadic := reffb.IsVariadic()
533+
if want := true; isVariadic != want {
534+
t.Errorf("IsVariadic=%v, want %v", isVariadic, want)
535+
}
536+
537+
if got, want := reffb.String(), "reflect_test.foobar"; got != want {
538+
t.Errorf("Value.String()=%v, want %v", got, want)
539+
}
540+
541+
}
542+
490543
func TestTinyZero(t *testing.T) {
491544
s := "hello, world"
492545
sptr := &s

0 commit comments

Comments
 (0)