loader: make sure Go version is plumbed through
This fixes the new loop variable behavior in Go 1.22. Specifically: * The compiler (actually, the x/tools/go/ssa package) now correctly picks up the Go version. * If a module doesn't specify the Go version, the current Go version (from the `go` tool and standard library) is used. This fixes `go run`. * The tests in testdata/ that use a separate directory are now actually run in that directory. This makes it possible to use a go.mod file there. * There is a test to make sure old Go modules still work with the old Go behavior, even on a newer Go version.
Этот коммит содержится в:
родитель
38a80b45d3
коммит
57f49af726
10 изменённых файлов: 78 добавлений и 10 удалений
|
@ -23,6 +23,7 @@ type Options struct {
|
||||||
GOOS string // environment variable
|
GOOS string // environment variable
|
||||||
GOARCH string // environment variable
|
GOARCH string // environment variable
|
||||||
GOARM string // environment variable (only used with GOARCH=arm)
|
GOARM string // environment variable (only used with GOARCH=arm)
|
||||||
|
Directory string // working dir, leave it unset to use the current working dir
|
||||||
Target string
|
Target string
|
||||||
Opt string
|
Opt string
|
||||||
GC string
|
GC string
|
||||||
|
@ -48,7 +49,6 @@ type Options struct {
|
||||||
Programmer string
|
Programmer string
|
||||||
OpenOCDCommands []string
|
OpenOCDCommands []string
|
||||||
LLVMFeatures string
|
LLVMFeatures string
|
||||||
Directory string
|
|
||||||
PrintJSON bool
|
PrintJSON bool
|
||||||
Monitor bool
|
Monitor bool
|
||||||
BaudRate int
|
BaudRate int
|
||||||
|
|
|
@ -27,6 +27,8 @@ import (
|
||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var initFileVersions = func(info *types.Info) {}
|
||||||
|
|
||||||
// Program holds all packages and some metadata about the program as a whole.
|
// Program holds all packages and some metadata about the program as a whole.
|
||||||
type Program struct {
|
type Program struct {
|
||||||
config *compileopts.Config
|
config *compileopts.Config
|
||||||
|
@ -383,7 +385,19 @@ func (p *Package) Check() error {
|
||||||
// errors out on language features not supported in that particular
|
// errors out on language features not supported in that particular
|
||||||
// version.
|
// version.
|
||||||
checker.GoVersion = "go" + p.Module.GoVersion
|
checker.GoVersion = "go" + p.Module.GoVersion
|
||||||
|
} else {
|
||||||
|
// Version is not known, so use the currently installed Go version.
|
||||||
|
// This is needed for `tinygo run` for example.
|
||||||
|
// Normally we'd use goenv.GorootVersionString(), but for compatibility
|
||||||
|
// with Go 1.20 and below we need a version in the form of "go1.12" (no
|
||||||
|
// patch version).
|
||||||
|
major, minor, err := goenv.GetGorootVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
initFileVersions(&p.info)
|
||||||
|
|
||||||
// Do typechecking of the package.
|
// Do typechecking of the package.
|
||||||
packageName := p.ImportPath
|
packageName := p.ImportPath
|
||||||
|
|
17
loader/loader_go122.go
Обычный файл
17
loader/loader_go122.go
Обычный файл
|
@ -0,0 +1,17 @@
|
||||||
|
//go:build go1.22
|
||||||
|
|
||||||
|
// types.Info.FileVersions was added in Go 1.22, so we can only initialize it
|
||||||
|
// when built with Go 1.22.
|
||||||
|
|
||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initFileVersions = func(info *types.Info) {
|
||||||
|
info.FileVersions = make(map[*ast.File]string)
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ func TestBuild(t *testing.T) {
|
||||||
"json.go",
|
"json.go",
|
||||||
"map.go",
|
"map.go",
|
||||||
"math.go",
|
"math.go",
|
||||||
|
"oldgo/",
|
||||||
"print.go",
|
"print.go",
|
||||||
"reflect.go",
|
"reflect.go",
|
||||||
"slice.go",
|
"slice.go",
|
||||||
|
@ -91,7 +92,7 @@ func TestBuild(t *testing.T) {
|
||||||
tests = append(tests, "go1.21.go")
|
tests = append(tests, "go1.21.go")
|
||||||
}
|
}
|
||||||
if minor >= 22 {
|
if minor >= 22 {
|
||||||
tests = append(tests, "go1.22.go")
|
tests = append(tests, "go1.22/")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *testTarget != "" {
|
if *testTarget != "" {
|
||||||
|
@ -336,8 +337,11 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||||
path := TESTDATA + "/" + name
|
path := TESTDATA + "/" + name
|
||||||
// Get the expected output for this test.
|
// Get the expected output for this test.
|
||||||
txtpath := path[:len(path)-3] + ".txt"
|
txtpath := path[:len(path)-3] + ".txt"
|
||||||
|
pkgName := "./" + path
|
||||||
if path[len(path)-1] == '/' {
|
if path[len(path)-1] == '/' {
|
||||||
txtpath = path + "out.txt"
|
txtpath = path + "out.txt"
|
||||||
|
options.Directory = path
|
||||||
|
pkgName = "."
|
||||||
}
|
}
|
||||||
expected, err := os.ReadFile(txtpath)
|
expected, err := os.ReadFile(txtpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -351,7 +355,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||||
|
|
||||||
// Build the test binary.
|
// Build the test binary.
|
||||||
stdout := &bytes.Buffer{}
|
stdout := &bytes.Buffer{}
|
||||||
_, err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
3
testdata/go1.22/go.mod
предоставленный
Обычный файл
3
testdata/go1.22/go.mod
предоставленный
Обычный файл
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/tinygo-org/tinygo/testdata/go1.22
|
||||||
|
|
||||||
|
go 1.22
|
10
testdata/go1.22.go → testdata/go1.22/main.go
предоставленный
10
testdata/go1.22.go → testdata/go1.22/main.go
предоставленный
|
@ -19,15 +19,13 @@ func testLoopVar() {
|
||||||
f = func() int { return i }
|
f = func() int { return i }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Prints 1 in Go 1.21, or 0 in Go 1.22.
|
// Variable n is 1 in Go 1.21, or 0 in Go 1.22.
|
||||||
// TODO: this still prints Go 1.21 even in Go 1.22. We probably need to
|
|
||||||
// specify the Go version somewhere.
|
|
||||||
n := f()
|
n := f()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
println("behaves like Go 1.22")
|
println("loops behave like Go 1.22")
|
||||||
} else if n == 1 {
|
} else if n == 1 {
|
||||||
println("behaves like Go 1.21")
|
println("loops behave like Go 1.21")
|
||||||
} else {
|
} else {
|
||||||
println("unknown behavior")
|
println("unknown loop behavior")
|
||||||
}
|
}
|
||||||
}
|
}
|
2
testdata/go1.22.txt → testdata/go1.22/out.txt
предоставленный
2
testdata/go1.22.txt → testdata/go1.22/out.txt
предоставленный
|
@ -9,4 +9,4 @@
|
||||||
2
|
2
|
||||||
1
|
1
|
||||||
go1.22 has lift-off!
|
go1.22 has lift-off!
|
||||||
behaves like Go 1.21
|
loops behave like Go 1.22
|
5
testdata/oldgo/go.mod
предоставленный
Обычный файл
5
testdata/oldgo/go.mod
предоставленный
Обычный файл
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/tinygo-org/tinygo/testdata/oldgo
|
||||||
|
|
||||||
|
// Go version doesn't matter much, as long as it's old.
|
||||||
|
|
||||||
|
go 1.15
|
26
testdata/oldgo/main.go
предоставленный
Обычный файл
26
testdata/oldgo/main.go
предоставленный
Обычный файл
|
@ -0,0 +1,26 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This package verifies that the Go language version is correctly picked up
|
||||||
|
// from the go.mod file.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
testLoopVar()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLoopVar() {
|
||||||
|
var f func() int
|
||||||
|
for i := 0; i < 1; i++ {
|
||||||
|
if i == 0 {
|
||||||
|
f = func() int { return i }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Variable n is 1 in Go 1.21, or 0 in Go 1.22.
|
||||||
|
n := f()
|
||||||
|
if n == 0 {
|
||||||
|
println("loops behave like Go 1.22")
|
||||||
|
} else if n == 1 {
|
||||||
|
println("loops behave like Go 1.21")
|
||||||
|
} else {
|
||||||
|
println("unknown loop behavior")
|
||||||
|
}
|
||||||
|
}
|
1
testdata/oldgo/out.txt
предоставленный
Обычный файл
1
testdata/oldgo/out.txt
предоставленный
Обычный файл
|
@ -0,0 +1 @@
|
||||||
|
loops behave like Go 1.21
|
Загрузка…
Создание таблицы
Сослаться в новой задаче