aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeddy Wing2024-03-09 18:45:48 +0100
committerTeddy Wing2024-03-09 18:45:48 +0100
commitbf64f32a1a8099ee45d66796b5f60f9ae10a2436 (patch)
treeae287d874195f7ed127155aa5cac873f3abc8005
parent160d3bef43b386e6a3db8990ad78c3177c56fc3a (diff)
downloadgocapturedrefrace-bf64f32a1a8099ee45d66796b5f60f9ae10a2436.tar.bz2
Debug broken behaviour caused by Go 1.22
The Go 1.22 release notes mention in passing: > The start position (Pos) of the lexical environment block (Scope) that > represents a function body has changed: it used to start at the > opening curly brace of the function body, but now starts at the > function's func token. (https://go.dev/doc/go1.22#go/types) That looked like what was causing the breakage in Capturedrefrace. I started by trying to compare the differences between Go 1.21 and Go 1.22: $ go install golang.org/dl/go1.22.0@latest $ go1.22.0 download $ go install golang.org/dl/go1.21.8@latest $ go1.21.8 download $ go1.22.0 test === RUN Test analysistest.go:522: gocapturedrefrace/testdata/simple.go:29:10: unexpected diagnostic: captured reference copied in goroutine closure analysistest.go:522: gocapturedrefrace/testdata/simple.go:57:10: unexpected diagnostic: captured reference s in goroutine closure --- FAIL: Test (0.40s) FAIL exit status 1 FAIL gopkg.teddywing.com/capturedrefrace 0.410s $ go1.21.8 test -v === RUN Test --- PASS: Test (0.38s) PASS ok gopkg.teddywing.com/capturedrefrace 0.389s Printing different AST values showed differences, but it was difficult to see what was going on. What was clear was that the problem came from the `if funcScope != scope` line. Since it was clear the problem came from the Go standard library rather than the golang.org/x/tools package, I tried bisecting Go (with some guidance from https://scribe.rip/@fzambia/bisecting-go-performance-degradation-4d4a7ee83a63): $ git clone https://github.com/golang/go.git $ git checkout go1.22.0 $ git bisect start $ git bisect good go1.21.8 $ git bisect bad $ cd src/ $ ./make.bash ... And in this repository: $ /tmp/go/bin/go test -v That turned up this commit: https://github.com/golang/go/commit/a27a525d1b4df74989ac9f6ad10394391fe3eb88. Now I know what's causing the problem, and that the change isn't likely to be reverted because the issues it references describe it as a bug. Next, I'll have to work out how to work around the change in the analyzer.
-rw-r--r--capturedrefrace.go13
1 files changed, 13 insertions, 0 deletions
diff --git a/capturedrefrace.go b/capturedrefrace.go
index c0bc646..52f7c34 100644
--- a/capturedrefrace.go
+++ b/capturedrefrace.go
@@ -51,6 +51,7 @@
package capturedrefrace
import (
+ "fmt"
"go/ast"
"go/token"
"go/types"
@@ -179,6 +180,8 @@ func checkClosure(pass *analysis.Pass, funcLit *ast.FuncLit) {
ast.Inspect(
funcLit,
func(node ast.Node) bool {
+ // fmt.Printf("node: %#v\n", node)
+
ident, ok := node.(*ast.Ident)
if !ok {
return true
@@ -197,6 +200,7 @@ func checkClosure(pass *analysis.Pass, funcLit *ast.FuncLit) {
// Find out whether `ident` was defined in an outer scope.
scope, scopeObj := funcScope.LookupParent(ident.Name, ident.NamePos)
+ // fmt.Printf("ident: %#v\n\t%#v\n\t%#v\n", ident, scope, scopeObj)
// Identifier is local to the closure.
if scope == nil && scopeObj == nil {
@@ -215,6 +219,15 @@ func checkClosure(pass *analysis.Pass, funcLit *ast.FuncLit) {
return true
}
+ if ident.Name == "copied" {
+ fmt.Printf("identifier: %#v, obj: %#v, decl: %#v\n", ident, ident.Obj, ident.Obj.Decl)
+ fmt.Printf("scope: %#v\n", scope)
+ fmt.Printf("funcScope: %#v\n", funcScope)
+ fmt.Println()
+ }
+
+ // TODO: Broken by golang/go a27a525d1b4df74989ac9f6ad10394391fe3eb88
+ // Test with golang.org/x/tools@v0.15.0
// Identifier was defined in a different scope.
if funcScope != scope {
pass.Reportf(