Skip to content

Commit aa9b527

Browse files
committed
reflect: Fix test failures introduced in Go 1.18.
- Avoid use of unsafe in TestNestedMethods and TestEmbeddedMethods. - Skip TestNotInHeapDeref and TestMethodCallValueCodePtr, which concern low-level GC and heap details, inapplicable to GopherJS. - Skip TestIssue50208 until generics are supported. - Add a hack into methodNameSkip() to make method names match what the tests expect. gopherjs#1085 would be a better long-term solution. - Stub out verifyNotInHeapPtr(), which is also not applicable to GopherJS.
1 parent d8f1734 commit aa9b527

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

compiler/natives/src/reflect/reflect.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package reflect
55

66
import (
77
"errors"
8+
"runtime"
89
"strconv"
910
"unsafe"
1011

@@ -1725,3 +1726,35 @@ func deepValueEqualJs(v1, v2 Value, visited [][2]unsafe.Pointer) bool {
17251726

17261727
return js.Global.Call("$interfaceIsEqual", js.InternalObject(valueInterface(v1, false)), js.InternalObject(valueInterface(v2, false))).Bool()
17271728
}
1729+
1730+
func methodNameSkip() string {
1731+
pc, _, _, _ := runtime.Caller(3)
1732+
f := runtime.FuncForPC(pc)
1733+
if f == nil {
1734+
return "unknown method"
1735+
}
1736+
// Function name extracted from the call stack can be different from vanilla
1737+
// Go. Here we try to fix stuff like "Object.$packages.reflect.Q.ptr.SetIterKey"
1738+
// into "Value.SetIterKey".
1739+
// This workaround may become obsolete after https://github.com/gopherjs/gopherjs/issues/1085
1740+
// is resolved.
1741+
name := f.Name()
1742+
idx := len(name) - 1
1743+
for idx > 0 {
1744+
if name[idx] == '.' {
1745+
break
1746+
}
1747+
idx--
1748+
}
1749+
if idx < 0 {
1750+
return name
1751+
}
1752+
return "Value" + name[idx:]
1753+
}
1754+
1755+
func verifyNotInHeapPtr(p uintptr) bool {
1756+
// Go runtime uses this method to make sure that a uintptr won't crash GC if
1757+
// interpreted as a heap pointer. This is not relevant for GopherJS, so we can
1758+
// always return true.
1759+
return true
1760+
}

compiler/natives/src/reflect/reflect_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,77 @@ func TestMapIterSet(t *testing.T) {
214214
// Upstream test also tests allocations made by the iterator. GopherJS doesn't
215215
// support runtime.ReadMemStats(), so we leave that part out.
216216
}
217+
218+
type inner struct {
219+
x int
220+
}
221+
222+
type outer struct {
223+
y int
224+
inner
225+
}
226+
227+
func (*inner) M() int { return 1 }
228+
func (*outer) M() int { return 2 }
229+
230+
func TestNestedMethods(t *testing.T) {
231+
// This test is similar to the upstream, but avoids using the unsupported
232+
// Value.UnsafePointer() method.
233+
typ := TypeOf((*outer)(nil))
234+
args := []Value{
235+
ValueOf((*outer)(nil)), // nil receiver
236+
}
237+
if typ.NumMethod() != 1 {
238+
t.Errorf("Wrong method table for outer, found methods:")
239+
for i := 0; i < typ.NumMethod(); i++ {
240+
m := typ.Method(i)
241+
t.Errorf("\t%d: %s\n", i, m.Name)
242+
}
243+
}
244+
if got := typ.Method(0).Func.Call(args)[0]; got.Int() != 2 {
245+
t.Errorf("Wrong method table for outer, expected return value 2, got: %v", got)
246+
}
247+
if got := ValueOf((*outer).M).Call(args)[0]; got.Int() != 2 {
248+
t.Errorf("Wrong method table for outer, expected return value 2, got: %v", got)
249+
}
250+
}
251+
252+
func TestEmbeddedMethods(t *testing.T) {
253+
// This test is similar to the upstream, but avoids using the unsupported
254+
// Value.UnsafePointer() method.
255+
typ := TypeOf((*OuterInt)(nil))
256+
if typ.NumMethod() != 1 {
257+
t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
258+
for i := 0; i < typ.NumMethod(); i++ {
259+
m := typ.Method(i)
260+
t.Errorf("\t%d: %s %p\n", i, m.Name, m.Func.UnsafePointer())
261+
}
262+
}
263+
264+
i := &InnerInt{3}
265+
if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 {
266+
t.Errorf("i.M() = %d, want 3", v)
267+
}
268+
269+
o := &OuterInt{1, InnerInt{2}}
270+
if v := ValueOf(o).Method(0).Call(nil)[0].Int(); v != 2 {
271+
t.Errorf("i.M() = %d, want 2", v)
272+
}
273+
274+
f := (*OuterInt).M
275+
if v := f(o); v != 2 {
276+
t.Errorf("f(o) = %d, want 2", v)
277+
}
278+
}
279+
280+
func TestNotInHeapDeref(t *testing.T) {
281+
t.Skip("GopherJS doesn't support //go:notinheap")
282+
}
283+
284+
func TestMethodCallValueCodePtr(t *testing.T) {
285+
t.Skip("methodValueCallCodePtr() is not applicable in GopherJS")
286+
}
287+
288+
func TestIssue50208(t *testing.T) {
289+
t.Skip("This test required generics, which are not yet supported: https://github.com/gopherjs/gopherjs/issues/1013")
290+
}

0 commit comments

Comments
 (0)