Skip to content

Commit 0fee806

Browse files
authored
Go 1.11.1 support (version bump to GopherJS 1.11-2). (gopherjs#865)
Go 1.11.1 has been released recently. It includes some changes to the reflect package, including: - golang/go@a2f1c8e - golang/go@3afa9df - golang/go@58c9bd9 The second commit makes some changes to internal reflect code that makes GopherJS reflect overrides no longer compatible, causing the package to no longer build: $ gopherjs build reflect /usr/local/go/src/reflect/value.go:673:60: cannot use t (variable of type *rtype) as *funcType value in argument to funcLayout /usr/local/go/src/reflect/value.go:336:21: cannot use methodReceiver(op, v, int(v.flag) >> flagMethodShift) (value of type *rtype) as *funcType value in assignment Specifically, the type of return value t of function methodReceiver was changed from *rtype to *funcType in commit golang/go@3afa9df. This change updates the native reflect override for methodReceiver function and Value.call method accordingly. Maintain backwards compatibility with Go 1.11(.0) by creating a custom go1.11.1 release tag (to be applied whenever Go version is 1.11.1 or greater) and using it to select the appropriate overrides for the reflect package for Go 1.11.1 and Go 1.11(.0). This way, GopherJS 1.11-2 will function with Go 1.11.1 and Go 1.11(.0) versions, rather than only with Go 1.11.1. Regenerate natives with: go generate ./compiler/natives Use Go 1.11.1 in CI. Bump GopherJS version to GopherJS 1.11-2. Fixes gopherjs#862.
1 parent bf5fc7d commit 0fee806

File tree

7 files changed

+340
-164
lines changed

7 files changed

+340
-164
lines changed

build/build.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,14 @@ func parseAndAugment(bctx *build.Context, pkg *build.Package, isTest bool, fileS
312312
return natives.FS.Open(name)
313313
},
314314
}
315+
316+
// reflect needs to tell Go 1.11 apart from Go 1.11.1 for https://github.com/gopherjs/gopherjs/issues/862,
317+
// so provide it with the custom go1.11.1 build tag whenever we're on Go 1.11.1 or later.
318+
// TODO: Remove this ad hoc special behavior in GopherJS 1.12.
319+
if runtime.Version() != "go1.11" {
320+
nativesContext.ReleaseTags = append(nativesContext.ReleaseTags, "go1.11.1")
321+
}
322+
315323
if nativesPkg, err := nativesContext.Import(importPath, "", 0); err == nil {
316324
names := nativesPkg.GoFiles
317325
if isTest {

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ machine:
66

77
dependencies:
88
pre:
9-
- cd /usr/local && sudo rm -rf go && curl https://storage.googleapis.com/golang/go1.11.linux-amd64.tar.gz | sudo tar -xz && sudo chmod a+w go/src/path/filepath
9+
- cd /usr/local && sudo rm -rf go && curl https://storage.googleapis.com/golang/go1.11.1.linux-amd64.tar.gz | sudo tar -xz && sudo chmod a+w go/src/path/filepath
1010
post:
1111
- mv ./gopherjs $HOME/bin
1212
- npm install --global node-gyp

compiler/natives/fs_vfsdata.go

Lines changed: 46 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/natives/src/reflect/reflect.go

Lines changed: 0 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -647,39 +647,6 @@ func Copy(dst, src Value) int {
647647
return js.Global.Call("$copySlice", dstVal, srcVal).Int()
648648
}
649649

650-
func methodReceiver(op string, v Value, i int) (_, t *rtype, fn unsafe.Pointer) {
651-
var prop string
652-
if v.typ.Kind() == Interface {
653-
tt := (*interfaceType)(unsafe.Pointer(v.typ))
654-
if i < 0 || i >= len(tt.methods) {
655-
panic("reflect: internal error: invalid method index")
656-
}
657-
m := &tt.methods[i]
658-
if !tt.nameOff(m.name).isExported() {
659-
panic("reflect: " + op + " of unexported method")
660-
}
661-
t = tt.typeOff(m.typ)
662-
prop = tt.nameOff(m.name).name()
663-
} else {
664-
ms := v.typ.exportedMethods()
665-
if uint(i) >= uint(len(ms)) {
666-
panic("reflect: internal error: invalid method index")
667-
}
668-
m := ms[i]
669-
if !v.typ.nameOff(m.name).isExported() {
670-
panic("reflect: " + op + " of unexported method")
671-
}
672-
t = v.typ.typeOff(m.mtyp)
673-
prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
674-
}
675-
rcvr := v.object()
676-
if isWrapped(v.typ) {
677-
rcvr = jsType(v.typ).New(rcvr)
678-
}
679-
fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
680-
return
681-
}
682-
683650
func valueInterface(v Value, safe bool) interface{} {
684651
if v.flag == 0 {
685652
panic(&ValueError{"reflect.Value.Interface", 0})
@@ -847,105 +814,6 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
847814

848815
var callHelper = js.Global.Get("$call").Interface().(func(...interface{}) *js.Object)
849816

850-
func (v Value) call(op string, in []Value) []Value {
851-
var (
852-
t *rtype
853-
fn unsafe.Pointer
854-
rcvr *js.Object
855-
)
856-
if v.flag&flagMethod != 0 {
857-
_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
858-
rcvr = v.object()
859-
if isWrapped(v.typ) {
860-
rcvr = jsType(v.typ).New(rcvr)
861-
}
862-
} else {
863-
t = v.typ
864-
fn = unsafe.Pointer(v.object().Unsafe())
865-
rcvr = js.Undefined
866-
}
867-
868-
if fn == nil {
869-
panic("reflect.Value.Call: call of nil function")
870-
}
871-
872-
isSlice := op == "CallSlice"
873-
n := t.NumIn()
874-
if isSlice {
875-
if !t.IsVariadic() {
876-
panic("reflect: CallSlice of non-variadic function")
877-
}
878-
if len(in) < n {
879-
panic("reflect: CallSlice with too few input arguments")
880-
}
881-
if len(in) > n {
882-
panic("reflect: CallSlice with too many input arguments")
883-
}
884-
} else {
885-
if t.IsVariadic() {
886-
n--
887-
}
888-
if len(in) < n {
889-
panic("reflect: Call with too few input arguments")
890-
}
891-
if !t.IsVariadic() && len(in) > n {
892-
panic("reflect: Call with too many input arguments")
893-
}
894-
}
895-
for _, x := range in {
896-
if x.Kind() == Invalid {
897-
panic("reflect: " + op + " using zero Value argument")
898-
}
899-
}
900-
for i := 0; i < n; i++ {
901-
if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
902-
panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
903-
}
904-
}
905-
if !isSlice && t.IsVariadic() {
906-
// prepare slice for remaining values
907-
m := len(in) - n
908-
slice := MakeSlice(t.In(n), m, m)
909-
elem := t.In(n).Elem()
910-
for i := 0; i < m; i++ {
911-
x := in[n+i]
912-
if xt := x.Type(); !xt.AssignableTo(elem) {
913-
panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
914-
}
915-
slice.Index(i).Set(x)
916-
}
917-
origIn := in
918-
in = make([]Value, n+1)
919-
copy(in[:n], origIn)
920-
in[n] = slice
921-
}
922-
923-
nin := len(in)
924-
if nin != t.NumIn() {
925-
panic("reflect.Value.Call: wrong argument count")
926-
}
927-
nout := t.NumOut()
928-
929-
argsArray := js.Global.Get("Array").New(t.NumIn())
930-
for i, arg := range in {
931-
argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
932-
}
933-
results := callHelper(js.InternalObject(fn), rcvr, argsArray)
934-
935-
switch nout {
936-
case 0:
937-
return nil
938-
case 1:
939-
return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
940-
default:
941-
ret := make([]Value, nout)
942-
for i := range ret {
943-
ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
944-
}
945-
return ret
946-
}
947-
}
948-
949817
func (v Value) Cap() int {
950818
k := v.kind()
951819
switch k {
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// +build js
2+
// +build !go1.11.1
3+
4+
package reflect
5+
6+
import (
7+
"unsafe"
8+
9+
"github.com/gopherjs/gopherjs/js"
10+
)
11+
12+
func methodReceiver(op string, v Value, i int) (_, t *rtype, fn unsafe.Pointer) {
13+
var prop string
14+
if v.typ.Kind() == Interface {
15+
tt := (*interfaceType)(unsafe.Pointer(v.typ))
16+
if i < 0 || i >= len(tt.methods) {
17+
panic("reflect: internal error: invalid method index")
18+
}
19+
m := &tt.methods[i]
20+
if !tt.nameOff(m.name).isExported() {
21+
panic("reflect: " + op + " of unexported method")
22+
}
23+
t = tt.typeOff(m.typ)
24+
prop = tt.nameOff(m.name).name()
25+
} else {
26+
ms := v.typ.exportedMethods()
27+
if uint(i) >= uint(len(ms)) {
28+
panic("reflect: internal error: invalid method index")
29+
}
30+
m := ms[i]
31+
if !v.typ.nameOff(m.name).isExported() {
32+
panic("reflect: " + op + " of unexported method")
33+
}
34+
t = v.typ.typeOff(m.mtyp)
35+
prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
36+
}
37+
rcvr := v.object()
38+
if isWrapped(v.typ) {
39+
rcvr = jsType(v.typ).New(rcvr)
40+
}
41+
fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
42+
return
43+
}
44+
45+
func (v Value) call(op string, in []Value) []Value {
46+
var (
47+
t *rtype
48+
fn unsafe.Pointer
49+
rcvr *js.Object
50+
)
51+
if v.flag&flagMethod != 0 {
52+
_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
53+
rcvr = v.object()
54+
if isWrapped(v.typ) {
55+
rcvr = jsType(v.typ).New(rcvr)
56+
}
57+
} else {
58+
t = v.typ
59+
fn = unsafe.Pointer(v.object().Unsafe())
60+
rcvr = js.Undefined
61+
}
62+
63+
if fn == nil {
64+
panic("reflect.Value.Call: call of nil function")
65+
}
66+
67+
isSlice := op == "CallSlice"
68+
n := t.NumIn()
69+
if isSlice {
70+
if !t.IsVariadic() {
71+
panic("reflect: CallSlice of non-variadic function")
72+
}
73+
if len(in) < n {
74+
panic("reflect: CallSlice with too few input arguments")
75+
}
76+
if len(in) > n {
77+
panic("reflect: CallSlice with too many input arguments")
78+
}
79+
} else {
80+
if t.IsVariadic() {
81+
n--
82+
}
83+
if len(in) < n {
84+
panic("reflect: Call with too few input arguments")
85+
}
86+
if !t.IsVariadic() && len(in) > n {
87+
panic("reflect: Call with too many input arguments")
88+
}
89+
}
90+
for _, x := range in {
91+
if x.Kind() == Invalid {
92+
panic("reflect: " + op + " using zero Value argument")
93+
}
94+
}
95+
for i := 0; i < n; i++ {
96+
if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
97+
panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
98+
}
99+
}
100+
if !isSlice && t.IsVariadic() {
101+
// prepare slice for remaining values
102+
m := len(in) - n
103+
slice := MakeSlice(t.In(n), m, m)
104+
elem := t.In(n).Elem()
105+
for i := 0; i < m; i++ {
106+
x := in[n+i]
107+
if xt := x.Type(); !xt.AssignableTo(elem) {
108+
panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
109+
}
110+
slice.Index(i).Set(x)
111+
}
112+
origIn := in
113+
in = make([]Value, n+1)
114+
copy(in[:n], origIn)
115+
in[n] = slice
116+
}
117+
118+
nin := len(in)
119+
if nin != t.NumIn() {
120+
panic("reflect.Value.Call: wrong argument count")
121+
}
122+
nout := t.NumOut()
123+
124+
argsArray := js.Global.Get("Array").New(t.NumIn())
125+
for i, arg := range in {
126+
argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
127+
}
128+
results := callHelper(js.InternalObject(fn), rcvr, argsArray)
129+
130+
switch nout {
131+
case 0:
132+
return nil
133+
case 1:
134+
return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
135+
default:
136+
ret := make([]Value, nout)
137+
for i := range ret {
138+
ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
139+
}
140+
return ret
141+
}
142+
}

0 commit comments

Comments
 (0)