Skip to content

Commit daae650

Browse files
authored
Merge pull request #1043 from gopherjs/wip-go1.17
Go 1.17 support
2 parents eee08aa + 7fa979d commit daae650

File tree

122 files changed

+1615
-481
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+1615
-481
lines changed

.std_test_pkg_exclusions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ go/internal/gccgoimporter
77
go/internal/gcimporter
88
go/internal/srcimporter
99
go/types
10+
internal/abi
1011
internal/syscall/unix
1112
internal/syscall/windows
1213
internal/syscall/windows/registry

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ GopherJS compiles Go code ([golang.org](https://golang.org/)) to pure JavaScript
99

1010
### What's new?
1111

12+
- 2021-09-19: Go 1.17 support is available!
13+
- 2021-08-23: Go Modules are now fully supported.
1214
- 2021-06-19: Complete `syscall/js` package implementation compatible with the upstream Go 1.16.
1315
- 2021-04-04: **Go 1.16 is now officially supported!** 🎉 🎉 🎉
1416

@@ -22,7 +24,7 @@ Nearly everything, including Goroutines ([compatibility documentation](https://g
2224

2325
### Installation and Usage
2426

25-
GopherJS [requires Go 1.16 or newer](https://github.com/gopherjs/gopherjs/blob/master/doc/compatibility.md#go-version-compatibility). If you need an older Go
27+
GopherJS [requires Go 1.17 or newer](https://github.com/gopherjs/gopherjs/blob/master/doc/compatibility.md#go-version-compatibility). If you need an older Go
2628
version, you can use an [older Gopher release](https://github.com/gopherjs/gopherjs/releases).
2729

2830
Get or update GopherJS and dependencies with:
@@ -31,12 +33,12 @@ Get or update GopherJS and dependencies with:
3133
go get -u github.com/gopherjs/gopherjs
3234
```
3335

34-
If your local Go distribution as reported by `go version` is newer than Go 1.16, then you need to set the `GOPHERJS_GOROOT` environment variable to a directory that contains a Go 1.16 distribution. For example:
36+
If your local Go distribution as reported by `go version` is newer than Go 1.17, then you need to set the `GOPHERJS_GOROOT` environment variable to a directory that contains a Go 1.17 distribution. For example:
3537

3638
```
37-
go get golang.org/dl/go1.16.3
38-
go1.16.3 download
39-
export GOPHERJS_GOROOT="$(go1.16.3 env GOROOT)" # Also add this line to your .profile or equivalent.
39+
go get golang.org/dl/go1.17.1
40+
go1.17.1 download
41+
export GOPHERJS_GOROOT="$(go1.17.1 env GOROOT)" # Also add this line to your .profile or equivalent.
4042
```
4143

4244
Now you can use `gopherjs build [package]`, `gopherjs build [files]` or `gopherjs install [package]` which behave similar to the `go` tool. For `main` packages, these commands create a `.js` file and `.js.map` source map in the current directory or in `$GOPATH/bin`. The generated JavaScript file can be used as usual in a website. Use `gopherjs help [command]` to get a list of possible command line flags, e.g. for minification and automatically watching for changes.

build/build.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,11 @@ func (s *Session) InstallSuffix() string {
509509
return ""
510510
}
511511

512+
// GoRelease returns Go release version this session is building with.
513+
func (s *Session) GoRelease() string {
514+
return compiler.GoRelease(s.options.GOROOT)
515+
}
516+
512517
func (s *Session) BuildDir(packagePath string, importPath string, pkgObj string) error {
513518
if s.Watcher != nil {
514519
s.Watcher.Add(packagePath)
@@ -778,7 +783,7 @@ func (s *Session) WriteCommandPackage(archive *compiler.Archive, pkgObj string)
778783
if err != nil {
779784
return err
780785
}
781-
return compiler.WriteProgramCode(deps, sourceMapFilter)
786+
return compiler.WriteProgramCode(deps, sourceMapFilter, s.GoRelease())
782787
}
783788

784789
func NewMappingCallback(m *sourcemap.Map, goroot, gopath string, localMap bool) func(generatedLine, generatedColumn int, originalPos token.Position) {

build/cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
// cachePath is the base path for GopherJS's own build cache.
1212
//
1313
// It serves a similar function to the Go build cache, but is a lot more
14-
// simlistic and therefore not compatible with Go. We use this cache directory
14+
// simplistic and therefore not compatible with Go. We use this cache directory
1515
// to store build artifacts for packages loaded from a module, for which PkgObj
1616
// provided by go/build points inside the module source tree, which can cause
1717
// inconvenience with version control, etc.
@@ -28,7 +28,7 @@ var cachePath = func() string {
2828
// returned by go/build.
2929
func cachedPath(orig string) string {
3030
if orig == "" {
31-
panic(fmt.Errorf("CachedPath() must not be used with an empty string"))
31+
panic("CachedPath() must not be used with an empty string")
3232
}
3333
sum := fmt.Sprintf("%x", sha256.Sum256([]byte(orig)))
3434
return filepath.Join(cachePath, sum[0:2], sum)

build/versionhack/versionhack.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
// However, it naively assumes that the go tool version in the PATH matches the
1111
// version that was used to build GopherJS and disables module support whenever
1212
// ReleaseTags in the context are set to anything other than the default. This,
13-
// unfortunately, isn't very helpful since gopherjs may be build by a Go version
13+
// unfortunately, isn't very helpful since gopherjs may be built by a Go version
1414
// other than the PATH's default.
1515
//
16-
// Luckily, even if go tool version is mismatches, it's only used for discovery
16+
// Luckily, even if go tool version is mismatched, it's only used for discovery
1717
// of the package locations, and go/build evaluates build constraints on its own
1818
// with ReleaseTags we've passed.
1919
//
@@ -37,6 +37,10 @@ import (
3737
//go:linkname releaseTags go/build.defaultReleaseTags
3838
var releaseTags []string
3939

40+
//go:linkname toolTags go/build.defaultToolTags
41+
var toolTags []string
42+
4043
func init() {
4144
releaseTags = build.Default.ReleaseTags[:compiler.GoVersion]
45+
toolTags = []string{}
4246
}

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ workflows:
4848
parameters:
4949
go_version:
5050
type: string
51-
default: "1.16.7"
51+
default: "1.17.1"
5252
nvm_version:
5353
type: string
5454
default: "0.38.0"

compiler/compiler.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ type dceInfo struct {
173173
methodFilter string
174174
}
175175

176-
func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter) error {
176+
func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter, goVersion string) error {
177177
mainPkg := pkgs[len(pkgs)-1]
178178
minify := mainPkg.Minified
179179

@@ -242,6 +242,10 @@ func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter) error {
242242
if _, err := w.Write([]byte("\"use strict\";\n(function() {\n\n")); err != nil {
243243
return err
244244
}
245+
if _, err := w.Write([]byte(fmt.Sprintf("var $goVersion = %q;\n", goVersion))); err != nil {
246+
return err
247+
}
248+
245249
preludeJS := prelude.Prelude
246250
if minify {
247251
preludeJS = prelude.Minified
@@ -260,10 +264,9 @@ func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter) error {
260264
}
261265
}
262266

263-
if _, err := w.Write([]byte("$synthesizeMethods();\n$initAllLinknames();var $mainPkg = $packages[\"" + string(mainPkg.ImportPath) + "\"];\n$packages[\"runtime\"].$init();\n$go($mainPkg.$init, []);\n$flushConsole();\n\n}).call(this);\n")); err != nil {
267+
if _, err := w.Write([]byte("$synthesizeMethods();\n$initAllLinknames();\nvar $mainPkg = $packages[\"" + string(mainPkg.ImportPath) + "\"];\n$packages[\"runtime\"].$init();\n$go($mainPkg.$init, []);\n$flushConsole();\n\n}).call(this);\n")); err != nil {
264268
return err
265269
}
266-
267270
return nil
268271
}
269272

compiler/expressions.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
199199

200200
switch t.Underlying().(type) {
201201
case *types.Struct, *types.Array:
202+
// JavaScript's pass-by-reference semantics makes passing array's or
203+
// struct's object semantically equivalent to passing a pointer
204+
// TODO(nevkontakte): Evaluate if performance gain justifies complexity
205+
// introduced by the special case.
202206
return fc.translateExpr(e.X)
203207
}
204208

@@ -426,10 +430,6 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
426430
return fc.formatExpr("$equal(%e, %e, %s)", e.X, e.Y, fc.typeName(t))
427431
case *types.Interface:
428432
return fc.formatExpr("$interfaceIsEqual(%s, %s)", fc.translateImplicitConversion(e.X, t), fc.translateImplicitConversion(e.Y, t))
429-
case *types.Pointer:
430-
if _, ok := u.Elem().Underlying().(*types.Array); ok {
431-
return fc.formatExpr("$equal(%s, %s, %s)", fc.translateImplicitConversion(e.X, t), fc.translateImplicitConversion(e.Y, t), fc.typeName(u.Elem()))
432-
}
433433
case *types.Basic:
434434
if isBoolean(u) {
435435
if b, ok := analysis.BoolValue(e.X, fc.pkgCtx.Info.Info); ok && b {
@@ -450,11 +450,22 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
450450

451451
case *ast.IndexExpr:
452452
switch t := fc.pkgCtx.TypeOf(e.X).Underlying().(type) {
453-
case *types.Array, *types.Pointer:
453+
case *types.Pointer:
454+
if _, ok := t.Elem().Underlying().(*types.Array); !ok {
455+
// Should never happen in type-checked code.
456+
panic(fmt.Errorf("non-array pointers can't be used with index expression"))
457+
}
458+
// Rewrite arrPtr[i] → (*arrPtr)[i] to concentrate array dereferencing
459+
// logic in one place.
460+
x := &ast.StarExpr{
461+
Star: e.X.Pos(),
462+
X: e.X,
463+
}
464+
astutil.SetType(fc.pkgCtx.Info.Info, t.Elem(), x)
465+
e.X = x
466+
return fc.translateExpr(e)
467+
case *types.Array:
454468
pattern := rangeCheck("%1e[%2f]", fc.pkgCtx.Types[e.Index].Value != nil, true)
455-
if _, ok := t.(*types.Pointer); ok { // check pointer for nix (attribute getter causes a panic)
456-
pattern = `(%1e.nilCheck, ` + pattern + `)`
457-
}
458469
return fc.formatExpr(pattern, e.X, e.Index)
459470
case *types.Slice:
460471
return fc.formatExpr(rangeCheck("%1e.$array[%1e.$offset + %2f]", fc.pkgCtx.Types[e.Index].Value != nil, false), e.X, e.Index)
@@ -823,6 +834,7 @@ func (fc *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {
823834

824835
recv := fc.translateImplicitConversionWithCloning(x, methodsRecvType)
825836
if isWrapped(recvType) {
837+
// Wrap JS-native value to have access to the Go type's methods.
826838
recv = fc.formatExpr("new %s(%s)", fc.typeName(methodsRecvType), recv)
827839
}
828840
return recv
@@ -1031,7 +1043,7 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
10311043
case t.Kind() == types.UnsafePointer:
10321044
if unary, isUnary := expr.(*ast.UnaryExpr); isUnary && unary.Op == token.AND {
10331045
if indexExpr, isIndexExpr := unary.X.(*ast.IndexExpr); isIndexExpr {
1034-
return fc.formatExpr("$sliceToArray(%s)", fc.translateConversionToSlice(indexExpr.X, types.NewSlice(types.Typ[types.Uint8])))
1046+
return fc.formatExpr("$sliceToNativeArray(%s)", fc.translateConversionToSlice(indexExpr.X, types.NewSlice(types.Typ[types.Uint8])))
10351047
}
10361048
if ident, isIdent := unary.X.(*ast.Ident); isIdent && ident.Name == "_zero" {
10371049
return fc.formatExpr("new Uint8Array(0)")
@@ -1075,8 +1087,12 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
10751087
break
10761088
}
10771089

1078-
switch u := t.Elem().Underlying().(type) {
1090+
switch ptrElType := t.Elem().Underlying().(type) {
10791091
case *types.Array: // (*[N]T)(expr) — converting expr to a pointer to an array.
1092+
if _, ok := exprType.Underlying().(*types.Slice); ok {
1093+
return fc.formatExpr("$sliceToGoArray(%e, %s)", expr, fc.typeName(desiredType))
1094+
}
1095+
// TODO(nevkontakte): Is this just for aliased types (e.g. `type a [4]byte`)?
10801096
return fc.translateExpr(expr)
10811097
case *types.Struct: // (*StructT)(expr) — converting expr to a pointer to a struct.
10821098
if fc.pkgCtx.Pkg.Path() == "syscall" && types.Identical(exprType, types.Typ[types.UnsafePointer]) {
@@ -1086,7 +1102,7 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
10861102
// indeed pointing at a byte array.
10871103
array := fc.newVariable("_array")
10881104
target := fc.newVariable("_struct")
1089-
return fc.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, fc.zeroValue(t.Elem()), fc.loadStruct(array, target, u), target)
1105+
return fc.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, fc.zeroValue(t.Elem()), fc.loadStruct(array, target, ptrElType), target)
10901106
}
10911107
// Convert between structs of different types but identical layouts,
10921108
// for example:
@@ -1152,7 +1168,7 @@ func (fc *funcContext) translateImplicitConversion(expr ast.Expr, desiredType ty
11521168

11531169
switch desiredType.Underlying().(type) {
11541170
case *types.Slice:
1155-
return fc.formatExpr("$subslice(new %1s(%2e.$array), %2e.$offset, %2e.$offset + %2e.$length)", fc.typeName(desiredType), expr)
1171+
return fc.formatExpr("$convertSliceType(%1e, %2s)", expr, fc.typeName(desiredType))
11561172

11571173
case *types.Interface:
11581174
if typesutil.IsJsObject(exprType) {

compiler/gopherjspkg/doc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
package gopherjspkg
1111

1212
//go:generate vfsgendev -source="github.com/gopherjs/gopherjs/compiler/gopherjspkg".FS -tag=gopherjsdev
13+
//go:generate gofmt -w -s fs_vfsdata.go

compiler/gopherjspkg/fs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build gopherjsdev
12
// +build gopherjsdev
23

34
package gopherjspkg

0 commit comments

Comments
 (0)