Skip to content
Merged
8 changes: 5 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ jobs:
docker:
- image: ubuntu:18.04
environment:
SOURCE_MAP_SUPPORT: false
SOURCE_MAP_SUPPORT: true
GO111MODULE: "off" # Until issue #855 is fixed, we operate in GOPATH mode.
working_directory: ~/go/src/github.com/gopherjs/gopherjs
steps:
- run: apt-get update && apt-get install -y sudo curl git python make g++
- checkout
- run: git clone https://github.com/creationix/nvm $HOME/.nvm && cd $HOME/.nvm && git checkout v0.33.9 && echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV && echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
- run: nvm install 10.0.0 && nvm alias default 10.0.0
- run: echo export "NODE_PATH='$(npm root --global)'" >> $BASH_ENV # Make nodejs able to require globally installed modules from any working path.
- run: env
- run: cd /usr/local && sudo rm -rf go && curl https://storage.googleapis.com/golang/go1.16.linux-amd64.tar.gz | sudo tar -xz
- run: echo 'export PATH="$PATH:/usr/local/go/bin:$HOME/go/bin"' >> $BASH_ENV
- run: go get -t -d -v ./...
- run: go install -v
- run: npm install # Install our (dev) dependencies from package.json.
- run: npm install --global source-map-support # Required by standard library tests.
- run: npm install --global node-gyp@5.1.1
- run: cd node-syscall && node-gyp rebuild && mkdir -p ~/.node_libraries && cp build/Release/syscall.node ~/.node_libraries/syscall.node

- run: cd node-syscall && node-gyp rebuild && mkdir -p $NODE_PATH && cp build/Release/syscall.node $NODE_PATH/syscall.node
- run: go generate github.com/gopherjs/gopherjs/compiler/prelude
- run: diff -u <(echo -n) <(git status --porcelain)
- run: diff -u <(echo -n) <(gofmt -d .)
Expand Down
2 changes: 1 addition & 1 deletion compiler/gopherjspkg/fs_vfsdata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 17 additions & 17 deletions compiler/natives/fs_vfsdata.go

Large diffs are not rendered by default.

9 changes: 0 additions & 9 deletions compiler/natives/src/internal/reflectlite/reflectlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,6 @@ func newTypeOff(t *rtype) typeOff {
return typeOff(i)
}

// addReflectOff adds a pointer to the reflection lookup map in the runtime.
// It returns a new ID that can be used as a typeOff or textOff, and will
// be resolved correctly. Implemented in the runtime package.
func addReflectOff(ptr unsafe.Pointer) int32 {
i := len(typeOffList)
typeOffList = append(typeOffList, (*rtype)(ptr))
return int32(i)
}

func internalStr(strObj *js.Object) string {
var c struct{ str string }
js.InternalObject(c).Set("str", strObj) // get string without internalizing
Expand Down
157 changes: 114 additions & 43 deletions compiler/natives/src/reflect/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,15 @@ func newTypeOff(t *rtype) typeOff {
return typeOff(i)
}

// addReflectOff adds a pointer to the reflection lookup map in the runtime.
// It returns a new ID that can be used as a typeOff or textOff, and will
// be resolved correctly. Implemented in the runtime package.
func addReflectOff(ptr unsafe.Pointer) int32 {
i := len(typeOffList)
typeOffList = append(typeOffList, (*rtype)(ptr))
return int32(i)
}

func internalStr(strObj *js.Object) string {
var c struct{ str string }
js.InternalObject(c).Set("str", strObj) // get string without internalizing
Expand Down Expand Up @@ -380,44 +389,95 @@ func SliceOf(t Type) Type {
return reflectType(js.Global.Call("$sliceType", jsType(t)))
}

// func StructOf(fields []StructField) Type {
// jsFields := make([]*js.Object, len(fields))
// fset := map[string]struct{}{}
// for i, f := range fields {
// if f.Type == nil {
// panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
// }

// name := f.Name
// if name == "" {
// // Embedded field
// if f.Type.Kind() == Ptr {
// // Embedded ** and *interface{} are illegal
// elem := f.Type.Elem()
// if k := elem.Kind(); k == Ptr || k == Interface {
// panic("reflect.StructOf: illegal anonymous field type " + f.Type.String())
// }
// name = elem.String()
// } else {
// name = f.Type.String()
// }
// }

// if _, dup := fset[name]; dup {
// panic("reflect.StructOf: duplicate field " + name)
// }
// fset[name] = struct{}{}

// jsf := js.Global.Get("Object").New()
// jsf.Set("prop", name)
// jsf.Set("name", name)
// jsf.Set("exported", true)
// jsf.Set("typ", jsType(f.Type))
// jsf.Set("tag", f.Tag)
// jsFields[i] = jsf
// }
// return reflectType(js.Global.Call("$structType", "", jsFields))
// }
func StructOf(fields []StructField) Type {
var (
jsFields = make([]*js.Object, len(fields))
fset = map[string]struct{}{}
pkgpath string
hasGCProg bool
)
for i, field := range fields {
if field.Name == "" {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
}
if !isValidFieldName(field.Name) {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name")
}
if field.Type == nil {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
}
f, fpkgpath := runtimeStructField(field)
ft := f.typ
if ft.kind&kindGCProg != 0 {
hasGCProg = true
}
if fpkgpath != "" {
if pkgpath == "" {
pkgpath = fpkgpath
} else if pkgpath != fpkgpath {
panic("reflect.Struct: fields with different PkgPath " + pkgpath + " and " + fpkgpath)
}
}
name := field.Name
if f.embedded() {
// Embedded field
if field.Type.Kind() == Ptr {
// Embedded ** and *interface{} are illegal
elem := field.Type.Elem()
if k := elem.Kind(); k == Ptr || k == Interface {
panic("reflect.StructOf: illegal anonymous field type " + field.Type.String())
}
}
switch field.Type.Kind() {
case Interface:
case Ptr:
ptr := (*ptrType)(unsafe.Pointer(ft))
if unt := ptr.uncommon(); unt != nil {
if i > 0 && unt.mcount > 0 {
// Issue 15924.
panic("reflect: embedded type with methods not implemented if type is not first field")
}
if len(fields) > 1 {
panic("reflect: embedded type with methods not implemented if there is more than one field")
}
}
default:
if unt := ft.uncommon(); unt != nil {
if i > 0 && unt.mcount > 0 {
// Issue 15924.
panic("reflect: embedded type with methods not implemented if type is not first field")
}
if len(fields) > 1 && ft.kind&kindDirectIface != 0 {
panic("reflect: embedded type with methods not implemented for non-pointer type")
}
}
}
}

if _, dup := fset[name]; dup {
panic("reflect.StructOf: duplicate field " + name)
}
fset[name] = struct{}{}
// To be consistent with Compiler's behavior we need to avoid externalizing
// the "name" property. The line below is effectively an inverse of the
// internalStr() function.
jsf := js.InternalObject(struct{ name string }{name})
// The rest is set through the js.Object() interface, which the compiler will
// externalize for us.
jsf.Set("prop", name)
jsf.Set("exported", f.name.isExported())
jsf.Set("typ", jsType(field.Type))
jsf.Set("tag", field.Tag)
jsf.Set("embedded", field.Anonymous)
jsFields[i] = jsf
}
_ = hasGCProg
typ := js.Global.Call("$structType", "", jsFields)
if pkgpath != "" {
typ.Set("pkgPath", pkgpath)
}
return reflectType(typ)
}

func Zero(typ Type) Value {
return makeValue(typ, jsType(typ).Call("zero"), 0)
Expand Down Expand Up @@ -467,12 +527,27 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
ftyp := (*funcType)(unsafe.Pointer(t))

fv := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} {
// Convert raw JS arguments into []Value the user-supplied function expects.
args := make([]Value, ftyp.NumIn())
for i := range args {
argType := ftyp.In(i).common()
args[i] = makeValue(argType, arguments[i], 0)
}

// Call the user-supplied function.
resultsSlice := fn(args)

// Verify that returned value types are compatible with the function type specified by the caller.
if want, got := ftyp.NumOut(), len(resultsSlice); want != got {
panic("reflect: expected " + strconv.Itoa(want) + " return values, got " + strconv.Itoa(got))
}
for i, rtyp := range ftyp.out() {
if !resultsSlice[i].Type().AssignableTo(rtyp) {
panic("reflect: " + strconv.Itoa(i) + " return value type is not compatible with the function declaration")
}
}

// Rearrange return values according to the expected function signature.
switch ftyp.NumOut() {
case 0:
return nil
Expand Down Expand Up @@ -591,7 +666,7 @@ func mapiterkey(it unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(js.Global.Call("$newDataPointer", kv.Get("k"), jsType(PtrTo(iter.t.Key()))).Unsafe())
}

func mapitervalue(it unsafe.Pointer) unsafe.Pointer {
func mapiterelem(it unsafe.Pointer) unsafe.Pointer {
iter := (*mapIter)(it)
var kv *js.Object
if iter.last != nil {
Expand Down Expand Up @@ -748,10 +823,6 @@ func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) {
js.InternalObject(dst).Call("$set", js.InternalObject(src))
}

func methodName() string {
return "?FIXME?"
}

func makeMethodValue(op string, v Value) Value {
if v.flag&flagMethod == 0 {
panic("reflect: internal error: invalid use of makePartialFunc")
Expand Down
55 changes: 25 additions & 30 deletions compiler/natives/src/reflect/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,40 +59,20 @@ func TestSelectOnInvalid(t *testing.T) {
})
}

func TestStructOfFieldName(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOf(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfExportRules(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfGC(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfAlg(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfGenericAlg(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfDirectIface(t *testing.T) {
t.Skip("StructOf")
t.Skip("reflect.Value.InterfaceData is not supported by GopherJS.")
}

func TestStructOfWithInterface(t *testing.T) {
t.Skip("StructOf")
}

func TestStructOfTooManyFields(t *testing.T) {
t.Skip("StructOf")
// TODO(nevkontakte) Most of this test actually passes, but there is something
// about embedding fields with methods that can or can't be stored in an
// interface value directly that GopherJS does differently from upstream. As
// a result, GopherJS's implementation of StructOf() doesn't panic where
// upstream does. It seems to be a result of our implementation not propagating
// the kindDirectIface flag in struct types created by StructOf(), but at this
// point I wasn't able to figure out what that flag actually means in the
// GopherJS context or how it maps onto our own reflection implementation.
t.Skip("GopherJS doesn't support storing types directly in interfaces.")
}

var deepEqualTests = []DeepEqualTest{
Expand Down Expand Up @@ -187,3 +167,18 @@ func init() {
// TODO: This is a failure in 1.11, try to determine the cause and fix.
typeTests = append(typeTests[:31], typeTests[32:]...) // skip test case #31
}

func TestConvertNaNs(t *testing.T) {
// This test is exactly the same as the upstream, except it uses a "quiet NaN"
// value instead of "signalling NaN". JavaScript appears to coerce all NaNs
// into quiet ones, but for the purpose of this test either is fine.

const qnan uint32 = 0x7fc00001 // Originally: 0x7f800001.
type myFloat32 float32
x := V(myFloat32(math.Float32frombits(qnan)))
y := x.Convert(reflect.TypeOf(float32(0)))
z := y.Interface().(float32)
if got := math.Float32bits(z); got != qnan {
t.Errorf("quiet nan conversion got %x, want %x", got, qnan)
}
}
Loading