From f0e9ed6cbc1fbddcc0f886285d061bc91e2cb785 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 5 Jul 2026 23:03:56 -0700 Subject: [PATCH] reflect: add missing iterator methods --- src/reflect/iter.go | 25 ++++++++++++++++++ src/reflect/iter_test.go | 39 ++++++++++++++++++++++++++++ src/reflect/type.go | 56 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/src/reflect/iter.go b/src/reflect/iter.go index 2c6af42f0f..3748568955 100644 --- a/src/reflect/iter.go +++ b/src/reflect/iter.go @@ -8,6 +8,31 @@ import ( "iter" ) +// Fields returns an iterator over each StructField of v along with its Value. +func (v Value) Fields() iter.Seq2[StructField, Value] { + if v.Kind() != Struct { + panic(&ValueError{Method: "reflect.Value.Fields", Kind: v.Kind()}) + } + return func(yield func(StructField, Value) bool) { + for i, n := 0, v.NumField(); i < n; i++ { + if !yield(v.Type().Field(i), v.Field(i)) { + return + } + } + } +} + +// Methods returns an iterator over each Method of v along with its Value. +func (v Value) Methods() iter.Seq2[Method, Value] { + return func(yield func(Method, Value) bool) { + for i, n := 0, v.NumMethod(); i < n; i++ { + if !yield(v.Type().Method(i), v.Method(i)) { + return + } + } + } +} + func rangeNum[T int8 | int16 | int32 | int64 | int | uint8 | uint16 | uint32 | uint64 | uint | uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] { diff --git a/src/reflect/iter_test.go b/src/reflect/iter_test.go index fdcc83fc9e..5c2cd9e58d 100644 --- a/src/reflect/iter_test.go +++ b/src/reflect/iter_test.go @@ -383,6 +383,45 @@ func TestValueSeq2(t *testing.T) { } } +func TestValueFields(t *testing.T) { + type T struct { + First int + Second string + Third bool + } + v := ValueOf(T{First: 10, Second: "visible", Third: true}) + + names := []string{"First", "Second", "Third"} + values := []any{10, "visible", true} + var count int + for field, value := range v.Fields() { + if field.Name != names[count] { + t.Fatalf("field %d name = %q, want %q", count, field.Name, names[count]) + } + if field.Index[0] != count { + t.Fatalf("field %d index = %v, want [%d]", count, field.Index, count) + } + if got := value.Interface(); got != values[count] { + t.Fatalf("field %d value = %v, want %v", count, got, values[count]) + } + count++ + } + if count != len(names) { + t.Fatalf("field count = %d, want %d", count, len(names)) + } + + count = 0 + for field := range v.Type().Fields() { + if field.Name != names[count] { + t.Fatalf("type field %d name = %q, want %q", count, field.Name, names[count]) + } + count++ + } + if count != len(names) { + t.Fatalf("type field count = %d, want %d", count, len(names)) + } +} + // methodIter is a type from which we can derive a method // value that is an iter.Seq. type methodIter struct{} diff --git a/src/reflect/type.go b/src/reflect/type.go index 777db1a81e..f40863ee89 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -65,6 +65,7 @@ package reflect import ( "internal/reflectlite" + "iter" "unsafe" ) @@ -265,6 +266,10 @@ type Type interface { // It panics if i is not in the range [0, NumField()). Field(i int) StructField + // Fields returns an iterator over each struct field for struct type t. + // It panics if the type's Kind is not Struct. + Fields() iter.Seq[StructField] + // FieldByIndex returns the nested field corresponding // to the index sequence. It is equivalent to calling Field // successively for each index i. @@ -294,6 +299,10 @@ type Type interface { // It panics if i is not in the range [0, NumIn()). In(i int) Type + // Ins returns an iterator over each input parameter of function type t. + // It panics if the type's Kind is not Func. + Ins() iter.Seq[Type] + // Key returns a map type's key type. // It panics if the type's Kind is not Map. Key() Type @@ -319,6 +328,10 @@ type Type interface { // It panics if i is not in the range [0, NumOut()). Out(i int) Type + // Outs returns an iterator over each output parameter of function type t. + // It panics if the type's Kind is not Func. + Outs() iter.Seq[Type] + // OverflowComplex reports whether the complex128 x cannot be represented by type t. // It panics if t's Kind is not Complex64 or Complex128. OverflowComplex(x complex128) bool @@ -340,6 +353,9 @@ type Type interface { // CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2]. CanSeq2() bool + + // Methods returns an iterator over each method in the type's method set. + Methods() iter.Seq[Method] } type rawType struct { @@ -414,6 +430,16 @@ func (t *rawType) Field(i int) StructField { return toStructField(f) } +func (t *rawType) Fields() iter.Seq[StructField] { + return func(yield func(StructField) bool) { + for i, n := 0, t.NumField(); i < n; i++ { + if !yield(t.Field(i)) { + return + } + } + } +} + func (t *rawType) FieldByIndex(index []int) StructField { f := t.RawType.FieldByIndex(index) return toStructField(f) @@ -437,6 +463,16 @@ func (t *rawType) In(i int) Type { panic("unimplemented: (reflect.Type).In()") } +func (t *rawType) Ins() iter.Seq[Type] { + return func(yield func(Type) bool) { + for i, n := 0, t.NumIn(); i < n; i++ { + if !yield(t.In(i)) { + return + } + } + } +} + func (t *rawType) IsVariadic() bool { panic("unimplemented: (reflect.Type).IsVariadic()") } @@ -453,6 +489,16 @@ func (t *rawType) MethodByName(name string) (Method, bool) { panic("unimplemented: (reflect.Type).MethodByName()") } +func (t *rawType) Methods() iter.Seq[Method] { + return func(yield func(Method) bool) { + for i, n := 0, t.NumMethod(); i < n; i++ { + if !yield(t.Method(i)) { + return + } + } + } +} + func (t *rawType) NumIn() int { panic("unimplemented: (reflect.Type).NumIn()") } @@ -465,6 +511,16 @@ func (t *rawType) Out(i int) Type { panic("unimplemented: (reflect.Type).Out()") } +func (t *rawType) Outs() iter.Seq[Type] { + return func(yield func(Type) bool) { + for i, n := 0, t.NumOut(); i < n; i++ { + if !yield(t.Out(i)) { + return + } + } + } +} + // A StructField describes a single field in a struct. // This must be kept in sync with [reflectlite.StructField]. type StructField struct {