Skip to content

Commit 7f348c7

Browse files
committed
internal/versions: updates the meaning of FileVersions.
For Go >=1.22, FileVersions returns an unknown [invalid] Future version when the file versions would be invalid. This better matches go/types. For Go <=1.21, FileVersions returns either the runtime.Version() or the Future version. Adds AtLeast and Before for doing comparisons with Future. Updates golang/go#65612 Fixes golang/go#66007 Change-Id: I93ff1681b0f9117765614a20d82642749597307c Reviewed-on: https://go-review.googlesource.com/c/tools/+/567635 Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 38b0e9b commit 7f348c7

File tree

17 files changed

+274
-25
lines changed

17 files changed

+274
-25
lines changed

go/analysis/passes/loopclosure/loopclosure.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
5555
switch n := n.(type) {
5656
case *ast.File:
5757
// Only traverse the file if its goversion is strictly before go1.22.
58-
goversion := versions.Lang(versions.FileVersions(pass.TypesInfo, n))
59-
// goversion is empty for older go versions (or the version is invalid).
60-
return goversion == "" || versions.Compare(goversion, "go1.22") < 0
58+
goversion := versions.FileVersion(pass.TypesInfo, n)
59+
return versions.Before(goversion, versions.Go1_22)
6160
case *ast.RangeStmt:
6261
body = n.Body
6362
addVar(n.Key)

go/analysis/passes/loopclosure/loopclosure_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import (
1717
)
1818

1919
func Test(t *testing.T) {
20+
// legacy loopclosure test expectations are incorrect > 1.21.
21+
testenv.SkipAfterGo1Point(t, 21)
22+
2023
testdata := analysistest.TestData()
2124
analysistest.Run(t, testdata, loopclosure.Analyzer,
2225
"a", "golang.org/...", "subtests", "typeparams")

go/analysis/passes/loopclosure/testdata/src/a/a.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This file contains tests for the loopclosure checker.
5+
// This file contains legacy tests for the loopclosure checker.
6+
// Legacy expectations are incorrect after go1.22.
67

78
package testdata
89

go/analysis/passes/loopclosure/testdata/src/subtests/subtest.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This file contains tests that the loopclosure analyzer detects leaked
5+
// This file contains legacy tests that the loopclosure analyzer detects leaked
66
// references via parallel subtests.
7+
// Legacy expectations are incorrect after go1.22.
78

89
package subtests
910

go/analysis/passes/loopclosure/testdata/src/typeparams/typeparams.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This file contains tests for the loopclosure checker.
5+
// This file contains legacy tests for the loopclosure checker for GoVersion <go1.22.
6+
// Expectations are incorrect after go1.22.
67

78
//go:build go1.18
89

@@ -45,16 +46,16 @@ type T[P any] struct {
4546
a P
4647
}
4748

48-
func (t T[P]) Go(func() error) { }
49+
func (t T[P]) Go(func() error) {}
4950

5051
func _(g T[errgroup.Group]) {
5152
var s []int
5253
for i, v := range s {
5354
// "T.a" is method "(*...errgroup.Group).Go".
5455
g.a.Go(func() error {
55-
print(i) // want "loop variable i captured by func literal"
56-
print(v) // want "loop variable v captured by func literal"
56+
print(i) // want "loop variable i captured by func literal"
57+
print(v) // want "loop variable v captured by func literal"
5758
return nil
5859
})
5960
}
60-
}
61+
}

go/ssa/builder.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,8 +1747,7 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) {
17471747
// Use forStmtGo122 instead if it applies.
17481748
if s.Init != nil {
17491749
if assign, ok := s.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE {
1750-
afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0
1751-
if afterGo122 {
1750+
if versions.AtLeast(fn.goversion, versions.Go1_22) {
17521751
b.forStmtGo122(fn, s, label)
17531752
return
17541753
}
@@ -2243,7 +2242,7 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
22432242
}
22442243
}
22452244

2246-
afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0
2245+
afterGo122 := versions.AtLeast(fn.goversion, versions.Go1_22)
22472246
if s.Tok == token.DEFINE && !afterGo122 {
22482247
// pre-go1.22: If iteration variables are defined (:=), this
22492248
// occurs once outside the loop.

go/ssa/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
245245
if len(files) > 0 {
246246
// Go source package.
247247
for _, file := range files {
248-
goversion := versions.Lang(versions.FileVersions(p.info, file))
248+
goversion := versions.Lang(versions.FileVersion(p.info, file))
249249
for _, decl := range file.Decls {
250250
membersFromDecl(p, decl, goversion)
251251
}

internal/versions/features.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package versions
6+
7+
// This file contains predicates for working with file versions to
8+
// decide when a tool should consider a language feature enabled.
9+
10+
// GoVersions that features in x/tools can be gated to.
11+
const (
12+
Go1_18 = "go1.18"
13+
Go1_19 = "go1.19"
14+
Go1_20 = "go1.20"
15+
Go1_21 = "go1.21"
16+
Go1_22 = "go1.22"
17+
)
18+
19+
// Future is an invalid unknown Go version sometime in the future.
20+
// Do not use directly with Compare.
21+
const Future = ""
22+
23+
// AtLeast reports whether the file version v comes after a Go release.
24+
//
25+
// Use this predicate to enable a behavior once a certain Go release
26+
// has happened (and stays enabled in the future).
27+
func AtLeast(v, release string) bool {
28+
if v == Future {
29+
return true // an unknown future version is always after y.
30+
}
31+
return Compare(Lang(v), Lang(release)) >= 0
32+
}
33+
34+
// Before reports whether the file version v is strictly before a Go release.
35+
//
36+
// Use this predicate to disable a behavior once a certain Go release
37+
// has happened (and stays enabled in the future).
38+
func Before(v, release string) bool {
39+
if v == Future {
40+
return false // an unknown future version happens after y.
41+
}
42+
return Compare(Lang(v), Lang(release)) < 0
43+
}

internal/versions/toolchain.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package versions
6+
7+
// toolchain is maximum version (<1.22) that the go toolchain used
8+
// to build the current tool is known to support.
9+
//
10+
// When a tool is built with >=1.22, the value of toolchain is unused.
11+
//
12+
// x/tools does not support building with go <1.18. So we take this
13+
// as the minimum possible maximum.
14+
var toolchain string = Go1_18

internal/versions/toolchain_go119.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.19
6+
// +build go1.19
7+
8+
package versions
9+
10+
func init() {
11+
if Compare(toolchain, Go1_19) < 0 {
12+
toolchain = Go1_19
13+
}
14+
}

0 commit comments

Comments
 (0)