diff options
author | Teddy Wing | 2024-03-09 18:45:48 +0100 |
---|---|---|
committer | Teddy Wing | 2024-03-09 18:45:48 +0100 |
commit | bf64f32a1a8099ee45d66796b5f60f9ae10a2436 (patch) | |
tree | ae287d874195f7ed127155aa5cac873f3abc8005 | |
parent | 160d3bef43b386e6a3db8990ad78c3177c56fc3a (diff) | |
download | gocapturedrefrace-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.go | 13 |
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( |