diff options
author | Damian Gryski <[email protected]> | 2023-06-16 12:19:53 -0700 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-07-02 11:47:08 +0200 |
commit | ef72c5bb4e544843badec2e2c63ed10a09c281e6 (patch) | |
tree | fa4de81ddede753917f48ca83e257b83a17aa88e /src/reflect | |
parent | 93cc03b15a6c5e4e9f21d5390084b3012acc54f5 (diff) | |
download | tinygo-ef72c5bb4e544843badec2e2c63ed10a09c281e6.tar.gz tinygo-ef72c5bb4e544843badec2e2c63ed10a09c281e6.zip |
reflect: fix iterating over maps with interface{} keys
Fixes #3794
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/value.go | 21 | ||||
-rw-r--r-- | src/reflect/value_test.go | 18 |
2 files changed, 30 insertions, 9 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index a5014329c..5ee7e5fc1 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -914,10 +914,11 @@ func (v Value) MapKeys() []Value { e := New(v.typecode.Elem()) keyType := v.typecode.key() - isKeyStoredAsInterface := keyType.Kind() != String && !keyType.isBinary() + keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0 + shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary() for hashmapNext(v.pointer(), it, k.value, e.value) { - if isKeyStoredAsInterface { + if shouldUnpackInterface { intf := *(*interface{})(k.value) v := ValueOf(intf) keys = append(keys, v) @@ -992,12 +993,14 @@ func (v Value) MapRange() *MapIter { } keyType := v.typecode.key() - isKeyStoredAsInterface := keyType.Kind() != String && !keyType.isBinary() + + keyTypeIsEmptyInterface := keyType.Kind() == Interface && keyType.NumMethod() == 0 + shouldUnpackInterface := !keyTypeIsEmptyInterface && keyType.Kind() != String && !keyType.isBinary() return &MapIter{ - m: v, - it: hashmapNewIterator(), - keyInterface: isKeyStoredAsInterface, + m: v, + it: hashmapNewIterator(), + unpackKeyInterface: shouldUnpackInterface, } } @@ -1007,8 +1010,8 @@ type MapIter struct { key Value val Value - valid bool - keyInterface bool + valid bool + unpackKeyInterface bool } func (it *MapIter) Key() Value { @@ -1016,7 +1019,7 @@ func (it *MapIter) Key() Value { panic("reflect.MapIter.Key called on invalid iterator") } - if it.keyInterface { + if it.unpackKeyInterface { intf := *(*interface{})(it.key.value) v := ValueOf(intf) return v diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index ef6eabcf2..305cf02e8 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -191,6 +191,24 @@ func TestTinyMap(t *testing.T) { if _, ok := utIterKey.Interface().(unmarshalerText); !ok { t.Errorf("Map keys via MapIter() have wrong type: %v", utIterKey.Type().String()) } + + { + m := map[any]any{1: 2} + rv := ValueOf(m) + iter := rv.MapRange() + + iter.Next() + k := iter.Key() + if k.Kind().String() != "interface" { + t.Errorf("map[any]any MapRange has wrong key type: %v", k.Kind().String()) + } + + keys := rv.MapKeys() + if k := keys[0]; k.Kind().String() != "interface" { + t.Errorf("map[any]any MapRange has wrong key type: %v", k.Kind().String()) + } + + } } // For an interface type, it returns the number of exported and unexported methods. |