Skip to content

Commit

Permalink
fix: func reflect impl for named functions, updated tests
Browse files Browse the repository at this point in the history
Co-authored-by: Ethan Lewis <[email protected]>
  • Loading branch information
jeff1010322 and elewis787 committed Nov 1, 2024
1 parent ee7dde4 commit b848853
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/reflect/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3312,6 +3312,8 @@ func TestMethodPkgPath(t *testing.T) {
}
}
*/

func TestVariadicType(t *testing.T) {
// Test example from Type documentation.
var f func(x int, y ...float64)
Expand All @@ -3335,6 +3337,8 @@ func TestVariadicType(t *testing.T) {
t.Error(s)
}

/*
type inner struct {
x int
}
Expand Down
57 changes: 45 additions & 12 deletions src/reflect/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,14 +608,22 @@ func (t *rawType) String() string {
s += " }"
return s
case Func:
isVariadic := t.IsVariadic()

f := "func("
for i := 0; i < t.NumIn(); i++ {
if i > 0 {
f += ", "
}
f += t.In(i).String()

input := t.In(i).String()
if isVariadic && i == t.NumIn()-1 {
f += "..."
input = input[2:]
}
f += input
}

f += ") "

var rets string
Expand Down Expand Up @@ -1069,21 +1077,36 @@ func (t *rawType) ConvertibleTo(u Type) bool {
}

func (t *rawType) IsVariadic() bool {
// need to test if bool mapped to int set by compiler
if t.isNamed() {
named := (*namedType)(unsafe.Pointer(t))
t = named.elem
}

if t.Kind() != Func {
panic("reflect: IsVariadic of non-func type")
}

return (*funcType)(unsafe.Pointer(t)).variadic
}

func (t *rawType) NumIn() int {
if t.isNamed() {
named := (*namedType)(unsafe.Pointer(t))
return int((*funcType)(unsafe.Pointer(named.elem)).inCount)
}

if t.Kind() != Func {
panic("reflect: NumIn of non-func type")
}
return int((*funcType)(unsafe.Pointer(t)).inCount)
}

func (t *rawType) NumOut() int {
if t.isNamed() {
named := (*namedType)(unsafe.Pointer(t))
return int((*funcType)(unsafe.Pointer(named.elem)).outCount)
}

if t.Kind() != Func {
panic("reflect: NumOut of non-func type")
}
Expand Down Expand Up @@ -1163,33 +1186,43 @@ func addChecked(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
}

func (t *rawType) In(i int) Type {
if t.isNamed() {
named := (*namedType)(unsafe.Pointer(t))
t = named.elem
}

if t.Kind() != Func {
panic(errTypeField)
}
descriptor := (*funcType)(unsafe.Pointer(t.underlying()))
if uint(i) >= uint(descriptor.inCount) {
fType := (*funcType)(unsafe.Pointer(t))
if uint(i) >= uint(fType.inCount) {
panic("reflect: field index out of range")
}

pointer := (unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
return (*rawType)(*(**rawType)(pointer))
pointer := (unsafe.Add(unsafe.Pointer(&fType.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
return (*(**rawType)(pointer))
}

func (t *rawType) Out(i int) Type {
if t.isNamed() {
named := (*namedType)(unsafe.Pointer(t))
t = named.elem
}

if t.Kind() != Func {
panic(errTypeField)
}

descriptor := (*funcType)(unsafe.Pointer(t.underlying()))
if uint(i) >= uint(descriptor.outCount) {
fType := (*funcType)(unsafe.Pointer(t))

if uint(i) >= uint(fType.outCount) {
panic("reflect: field index out of range")
}

// Shift the index by the number of input parameters.
i = i + int((*funcType)(unsafe.Pointer(t)).inCount)

pointer := (unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
return (*rawType)(*(**rawType)(pointer))
i = i + int(fType.inCount)
pointer := (unsafe.Add(unsafe.Pointer(&fType.fields[0]), uintptr(i)*unsafe.Sizeof(unsafe.Pointer(nil))))
return (*(**rawType)(pointer))
}

// OverflowComplex reports whether the complex128 x cannot be represented by type t.
Expand Down
2 changes: 2 additions & 0 deletions src/reflect/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func TestTypeFor(t *testing.T) {
type (
mystring string
myiface interface{}
myfunc func()
)

testcases := []struct {
Expand All @@ -25,6 +26,7 @@ func TestTypeFor(t *testing.T) {
{new(mystring), reflect.TypeFor[mystring]()},
{new(any), reflect.TypeFor[any]()},
{new(myiface), reflect.TypeFor[myiface]()},
{new(myfunc), reflect.TypeFor[myfunc]()},
}
for _, tc := range testcases {
want := reflect.ValueOf(tc.wantFrom).Elem().Type()
Expand Down
53 changes: 53 additions & 0 deletions src/reflect/value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,59 @@ func TestTinyStruct(t *testing.T) {
}
}

func TestTinyFunc(t *testing.T) {
type barStruct struct {
QuxString string
BazInt int
}

type foobar func(bar barStruct, x int, v ...string) string

var fb foobar

reffb := TypeOf(fb)

numIn := reffb.NumIn()
if want := 3; numIn != want {
t.Errorf("NumIn=%v, want %v", numIn, want)
}

numOut := reffb.NumOut()
if want := 1; numOut != want {
t.Errorf("NumOut=%v, want %v", numOut, want)
}

in0 := reffb.In(0)
if want := TypeOf(barStruct{}); in0 != want {
t.Errorf("In(0)=%v, want %v", in0, want)
}

in1 := reffb.In(1)
if want := TypeOf(0); in1 != want {
t.Errorf("In(1)=%v, want %v", in1, want)
}

in2 := reffb.In(2)
if want := TypeOf([]string{}); in2 != want {
t.Errorf("In(2)=%v, want %v", in2, want)
}

out0 := reffb.Out(0)
if want := TypeOf(""); out0 != want {
t.Errorf("Out(0)=%v, want %v", out0, want)
}

isVariadic := reffb.IsVariadic()
if want := true; isVariadic != want {
t.Errorf("IsVariadic=%v, want %v", isVariadic, want)
}

if got, want := reffb.String(), "reflect_test.foobar"; got != want {
t.Errorf("Value.String()=%v, want %v", got, want)
}

}

func TestTinyZero(t *testing.T) {
s := "hello, world"
sptr := &s
Expand Down

0 comments on commit b848853

Please sign in to comment.