Permalink
Browse files

Go 1.11.1 support (version bump to GopherJS 1.11-2). (#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 #862.
  • Loading branch information...
dmitshur committed Oct 4, 2018
1 parent bf5fc7d commit 0fee806ad4970060e8f97d37a50fc58572426195
View
@@ -312,6 +312,14 @@ func parseAndAugment(bctx *build.Context, pkg *build.Package, isTest bool, fileS
return natives.FS.Open(name)
},
}
// reflect needs to tell Go 1.11 apart from Go 1.11.1 for https://github.com/gopherjs/gopherjs/issues/862,
// so provide it with the custom go1.11.1 build tag whenever we're on Go 1.11.1 or later.
// TODO: Remove this ad hoc special behavior in GopherJS 1.12.
if runtime.Version() != "go1.11" {
nativesContext.ReleaseTags = append(nativesContext.ReleaseTags, "go1.11.1")
}
if nativesPkg, err := nativesContext.Import(importPath, "", 0); err == nil {
names := nativesPkg.GoFiles
if isTest {
View
@@ -6,7 +6,7 @@ machine:
dependencies:
pre:
- 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
- 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
post:
- mv ./gopherjs $HOME/bin
- npm install --global node-gyp

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -647,39 +647,6 @@ func Copy(dst, src Value) int {
return js.Global.Call("$copySlice", dstVal, srcVal).Int()
}
func methodReceiver(op string, v Value, i int) (_, t *rtype, fn unsafe.Pointer) {
var prop string
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
if i < 0 || i >= len(tt.methods) {
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
if !tt.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
t = tt.typeOff(m.typ)
prop = tt.nameOff(m.name).name()
} else {
ms := v.typ.exportedMethods()
if uint(i) >= uint(len(ms)) {
panic("reflect: internal error: invalid method index")
}
m := ms[i]
if !v.typ.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
t = v.typ.typeOff(m.mtyp)
prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
}
rcvr := v.object()
if isWrapped(v.typ) {
rcvr = jsType(v.typ).New(rcvr)
}
fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
return
}
func valueInterface(v Value, safe bool) interface{} {
if v.flag == 0 {
panic(&ValueError{"reflect.Value.Interface", 0})
@@ -847,105 +814,6 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
var callHelper = js.Global.Get("$call").Interface().(func(...interface{}) *js.Object)
func (v Value) call(op string, in []Value) []Value {
var (
t *rtype
fn unsafe.Pointer
rcvr *js.Object
)
if v.flag&flagMethod != 0 {
_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
rcvr = v.object()
if isWrapped(v.typ) {
rcvr = jsType(v.typ).New(rcvr)
}
} else {
t = v.typ
fn = unsafe.Pointer(v.object().Unsafe())
rcvr = js.Undefined
}
if fn == nil {
panic("reflect.Value.Call: call of nil function")
}
isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice {
if !t.IsVariadic() {
panic("reflect: CallSlice of non-variadic function")
}
if len(in) < n {
panic("reflect: CallSlice with too few input arguments")
}
if len(in) > n {
panic("reflect: CallSlice with too many input arguments")
}
} else {
if t.IsVariadic() {
n--
}
if len(in) < n {
panic("reflect: Call with too few input arguments")
}
if !t.IsVariadic() && len(in) > n {
panic("reflect: Call with too many input arguments")
}
}
for _, x := range in {
if x.Kind() == Invalid {
panic("reflect: " + op + " using zero Value argument")
}
}
for i := 0; i < n; i++ {
if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
}
}
if !isSlice && t.IsVariadic() {
// prepare slice for remaining values
m := len(in) - n
slice := MakeSlice(t.In(n), m, m)
elem := t.In(n).Elem()
for i := 0; i < m; i++ {
x := in[n+i]
if xt := x.Type(); !xt.AssignableTo(elem) {
panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
}
slice.Index(i).Set(x)
}
origIn := in
in = make([]Value, n+1)
copy(in[:n], origIn)
in[n] = slice
}
nin := len(in)
if nin != t.NumIn() {
panic("reflect.Value.Call: wrong argument count")
}
nout := t.NumOut()
argsArray := js.Global.Get("Array").New(t.NumIn())
for i, arg := range in {
argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
}
results := callHelper(js.InternalObject(fn), rcvr, argsArray)
switch nout {
case 0:
return nil
case 1:
return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
default:
ret := make([]Value, nout)
for i := range ret {
ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
}
return ret
}
}
func (v Value) Cap() int {
k := v.kind()
switch k {
@@ -0,0 +1,142 @@
// +build js
// +build !go1.11.1
package reflect
import (
"unsafe"
"github.com/gopherjs/gopherjs/js"
)
func methodReceiver(op string, v Value, i int) (_, t *rtype, fn unsafe.Pointer) {
var prop string
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
if i < 0 || i >= len(tt.methods) {
panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
if !tt.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
t = tt.typeOff(m.typ)
prop = tt.nameOff(m.name).name()
} else {
ms := v.typ.exportedMethods()
if uint(i) >= uint(len(ms)) {
panic("reflect: internal error: invalid method index")
}
m := ms[i]
if !v.typ.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
t = v.typ.typeOff(m.mtyp)
prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
}
rcvr := v.object()
if isWrapped(v.typ) {
rcvr = jsType(v.typ).New(rcvr)
}
fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
return
}
func (v Value) call(op string, in []Value) []Value {
var (
t *rtype
fn unsafe.Pointer
rcvr *js.Object
)
if v.flag&flagMethod != 0 {
_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
rcvr = v.object()
if isWrapped(v.typ) {
rcvr = jsType(v.typ).New(rcvr)
}
} else {
t = v.typ
fn = unsafe.Pointer(v.object().Unsafe())
rcvr = js.Undefined
}
if fn == nil {
panic("reflect.Value.Call: call of nil function")
}
isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice {
if !t.IsVariadic() {
panic("reflect: CallSlice of non-variadic function")
}
if len(in) < n {
panic("reflect: CallSlice with too few input arguments")
}
if len(in) > n {
panic("reflect: CallSlice with too many input arguments")
}
} else {
if t.IsVariadic() {
n--
}
if len(in) < n {
panic("reflect: Call with too few input arguments")
}
if !t.IsVariadic() && len(in) > n {
panic("reflect: Call with too many input arguments")
}
}
for _, x := range in {
if x.Kind() == Invalid {
panic("reflect: " + op + " using zero Value argument")
}
}
for i := 0; i < n; i++ {
if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
}
}
if !isSlice && t.IsVariadic() {
// prepare slice for remaining values
m := len(in) - n
slice := MakeSlice(t.In(n), m, m)
elem := t.In(n).Elem()
for i := 0; i < m; i++ {
x := in[n+i]
if xt := x.Type(); !xt.AssignableTo(elem) {
panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
}
slice.Index(i).Set(x)
}
origIn := in
in = make([]Value, n+1)
copy(in[:n], origIn)
in[n] = slice
}
nin := len(in)
if nin != t.NumIn() {
panic("reflect.Value.Call: wrong argument count")
}
nout := t.NumOut()
argsArray := js.Global.Get("Array").New(t.NumIn())
for i, arg := range in {
argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
}
results := callHelper(js.InternalObject(fn), rcvr, argsArray)
switch nout {
case 0:
return nil
case 1:
return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
default:
ret := make([]Value, nout)
for i := range ret {
ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
}
return ret
}
}
Oops, something went wrong.

0 comments on commit 0fee806

Please sign in to comment.