Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/types: panic when checking method on generic struct called from package-level function #57522

Closed
sethp opened this issue Dec 30, 2022 · 8 comments
Assignees
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@sethp
Copy link

sethp commented Dec 30, 2022

gopls version

Build info
----------
golang.org/x/tools/gopls v0.11.0
    golang.org/x/tools/gopls@v0.11.0 h1:/nvKHdTtePQmrv9XN3gIUN9MOdUrKzO/dcqgbG6x8EY=
    github.com/BurntSushi/toml@v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
    github.com/google/go-cmp@v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
    github.com/sergi/go-diff@v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
    golang.org/x/exp@v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
    golang.org/x/exp/typeparams@v0.0.0-20221031165847-c99f073a8326 h1:fl8k2zg28yA23264d82M4dp+YlJ3ngDcpuB1bewkQi4=
    golang.org/x/mod@v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
    golang.org/x/sync@v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
    golang.org/x/sys@v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
    golang.org/x/text@v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
    golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8 h1:7/HkGkN/2ktghBCSRRgp31wAww4syfsW52tj7yirjWk=
    golang.org/x/vuln@v0.0.0-20221109205719-3af8368ee4fe h1:qptQiQwEpETwDiz85LKtChqif9xhVkAm8Nhxs0xnTww=
    honnef.co/go/tools@v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
    mvdan.cc/gofumpt@v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
    mvdan.cc/xurls/v2@v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
go: go1.19.4

go env

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/seth/.cache/go-build"
GOENV="/home/seth/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/seth/Code/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/seth/Code"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.19.4"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3205916473=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Typing away in my editor (VSCode, though I don't think it matters), I made a couple of mistakes in a file containing some generics: trying to add a []string formal parameter to a method, I typed []STR (because caps lock was on), and then made a second error in placing my cursor to start removing characters and ended up with a parameter type of [STR. This caused gopls to go into a tight crash loop.

Whittling it down, I found this example produces a panic at the same location:

$ gopls check <(cat <<'EOF'
package p

type S[T any] struct{}

var V = S[any]{}

func (fs *S[T]) M([STR) {}

func M() {
	V.M()
}
EOF
)

The names of things don't seem to matter, besides the match between the method M and package func M. I thought this was the case, but I just tried with func F() { V.M() } and that also crashed.

What did you expect to see?

Some sort of error like: "mismatched [" I suppose? I'm not really sure what gopls check looks like when it's working as intended.

What did you see instead?

The immediate crash described above and below.

Editor and settings

I don't think it's relevant, since it's reproducible for me with a bare gopls invocation in an empty directory not part of any project, but I'm happy to provide these if it'd be helpful.

Logs

The full stdio output from running the gopls check ... above that I see is:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x5beb50]

goroutine 222 [running]:
go/types.(*Checker).handleBailout(0xc0004d21c0, 0xc0007bf5e8)
        /usr/lib/go/src/go/types/check.go:302 +0x8b
panic({0xd64c60, 0x160c0e0})
        /usr/lib/go/src/runtime/panic.go:884 +0x212
go/types.(*Named).expandMethod(0xc0004fccb0, 0xc0004fccb0?)
        /usr/lib/go/src/go/types/named.go:386 +0xb0
go/types.(*Named).Method(0xc0004fccb0, 0x0)
        /usr/lib/go/src/go/types/named.go:357 +0x1a9
go/types.(*Named).lookupMethod(0xc0004fccb0, 0xc0007b5890?, {0x15db2e8, 0x1}, 0x49?)
        /usr/lib/go/src/go/types/named.go:569 +0xa5
go/types.lookupFieldOrMethod({0x10dcdd0?, 0xc0004fccb0?}, 0x1, 0x10df408?, {0x15db2e8, 0x1}, 0x0?)
        /usr/lib/go/src/go/types/lookup.go:137 +0x605
go/types.LookupFieldOrMethod({0x10dcdd0?, 0xc0004fccb0?}, 0x8?, 0xc0007b0dc0?, {0x15db2e8?, 0x1?})
        /usr/lib/go/src/go/types/lookup.go:66 +0xc5
go/types.(*Checker).selector(0xc0004d21c0, 0xc00016a7c0, 0xc0000132a8, 0x0)
        /usr/lib/go/src/go/types/call.go:544 +0x1e5
go/types.(*Checker).typInternal(0xc0004d21c0, {0x10df6a8?, 0xc0000132a8?}, 0x0)
        /usr/lib/go/src/go/types/typexpr.go:258 +0x37d
go/types.(*Checker).definedType(0xc0007be948?, {0x10df6a8?, 0xc0000132a8}, 0xd596c0?)
        /usr/lib/go/src/go/types/typexpr.go:180 +0x37
go/types.(*Checker).varType(0xe32ee0?, {0x10df6a8, 0xc0000132a8})
        /usr/lib/go/src/go/types/typexpr.go:145 +0x2a
go/types.(*Checker).collectParams(0xc0004d21c0, 0xc0007c0960, 0xc0007b4a80, 0x1)
        /usr/lib/go/src/go/types/signature.go:281 +0x227
go/types.(*Checker).funcType(0xc0004d21c0, 0xc00016a780, 0x0, 0xc0007b0e00)
        /usr/lib/go/src/go/types/signature.go:184 +0x394
go/types.(*Checker).typInternal(0xc0004d21c0, {0x10df378?, 0xc0007b0e00?}, 0x0)
        /usr/lib/go/src/go/types/typexpr.go:323 +0x28a
go/types.(*Checker).definedType(0xc0007beef0?, {0x10df378?, 0xc0007b0e00}, 0xd596c0?)
        /usr/lib/go/src/go/types/typexpr.go:180 +0x37
go/types.(*Checker).varType(0xe32ee0?, {0x10df378, 0xc0007b0e00})
        /usr/lib/go/src/go/types/typexpr.go:145 +0x2a
go/types.(*Checker).collectParams(0xc0004d21c0, 0xc0007c07e0, 0xc0007b4ae0, 0x1)
        /usr/lib/go/src/go/types/signature.go:281 +0x227
go/types.(*Checker).funcType(0xc0004d21c0, 0xc00016a500, 0xc0007b49f0, 0xc0007b0e20)
        /usr/lib/go/src/go/types/signature.go:184 +0x394
go/types.(*Checker).funcDecl(0xc0004d21c0, 0xc0007c0660, 0xc0007c06c0)
        /usr/lib/go/src/go/types/decl.go:809 +0xd9
go/types.(*Checker).objDecl(0xc0004d21c0, {0x10e9138, 0xc0007c0660}, 0xc0007bf4f8?)
        /usr/lib/go/src/go/types/decl.go:201 +0x676
go/types.(*Checker).packageObjects(0xc0004d21c0)
        /usr/lib/go/src/go/types/resolver.go:658 +0x285
go/types.(*Checker).checkFiles(0xc0004d21c0, {0xc00011a848?, 0xc00016ecd0?, 0x1?})
        /usr/lib/go/src/go/types/check.go:332 +0xbf
go/types.(*Checker).Files(...)
        /usr/lib/go/src/go/types/check.go:307
golang.org/x/tools/gopls/internal/lsp/cache.doTypeCheck({0x10e0998, 0xc00043e600}, 0xc0003cedc0, {0xc0004871a0, 0x1, 0x0?}, {0xc0004871b0, 0x1, 0x1}, 0xc000659ba0, ...)
        /home/seth/Code/pkg/mod/golang.org/x/tools/gopls@v0.11.0/internal/lsp/cache/check.go:572 +0xa09
golang.org/x/tools/gopls/internal/lsp/cache.typeCheckImpl({0x10e0998?, 0xc00043e600}, 0xc0003cedc0, {0xc0004871a0, 0x1, 0x1}, {0xc0004871b0, 0x1, 0x1}, 0xc000659ba0, ...)
        /home/seth/Code/pkg/mod/golang.org/x/tools/gopls@v0.11.0/internal/lsp/cache/check.go:332 +0x345
golang.org/x/tools/gopls/internal/lsp/cache.(*snapshot).buildPackageHandle.func1({0x10e0998?, 0xc00043e600?}, {0xe4e3c0?, 0xc0003cedc0?})
        /home/seth/Code/pkg/mod/golang.org/x/tools/gopls@v0.11.0/internal/lsp/cache/check.go:145 +0x96
golang.org/x/tools/internal/memoize.(*Promise).run.func2.1()
        /home/seth/Code/pkg/mod/golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8/internal/memoize/memoize.go:187 +0xa9
runtime/trace.WithRegion({0x10e0998?, 0xc00043e600?}, {0xc00012fe30, 0x22}, 0xc00069a790)
        /usr/lib/go/src/runtime/trace/annotation.go:141 +0xe3
golang.org/x/tools/internal/memoize.(*Promise).run.func2()
        /home/seth/Code/pkg/mod/golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8/internal/memoize/memoize.go:180 +0x145
created by golang.org/x/tools/internal/memoize.(*Promise).run
        /home/seth/Code/pkg/mod/golang.org/x/tools@v0.3.1-0.20221213193459-ca17b2c27ca8/internal/memoize/memoize.go:179 +0x1ea
@gopherbot gopherbot added Tools This label describes issues relating to any tools in the x/tools repository. gopls Issues related to the Go language server, gopls. labels Dec 30, 2022
@gopherbot gopherbot added this to the Unreleased milestone Dec 30, 2022
@sethp sethp changed the title x/tools/gopls: SIGSEGV when checking method on generic struct with matching package-level name x/tools/gopls: SIGSEGV when checking method on generic struct called from package-level function Dec 30, 2022
@suzmue suzmue modified the milestones: Unreleased, gopls/v0.12.0 Dec 30, 2022
@jamalc jamalc assigned adonovan, jamalc and findleyr and unassigned adonovan and jamalc Jan 5, 2023
@findleyr
Copy link
Contributor

findleyr commented Jan 5, 2023

CC @griesemer

Thanks for the detailed report! This looks like a type-checker bug. (gri: I'll take a look)

@findleyr
Copy link
Contributor

findleyr commented Jan 5, 2023

Minimal reproducer:

type S[T any] struct{}

type V = S[any]

func (fs *S[T]) M(x V.M) {}

The (invalid) selector causes evaluation of the method set of S before it is fully set up.

@findleyr
Copy link
Contributor

findleyr commented Jan 5, 2023

I think the easiest fix is to avoid the lookup entirely in types.Checker.selector when checking a selector in a typexpr context. This is not difficult to implement, but several error messages change (for example, in some cases we no longer detect invalid cycles).

@findleyr
Copy link
Contributor

More reproducers / related panics:

type S[T any] V.M
type V = S[any]
type X[T any] int
func (X[T]) M(x [X[int].M]int) {}

Selectors and array lengths are two places where we evaluate expressions while checking type declarations, and therefore are vectors for this type of crasher.

This needs a more systematic fix. Not sure if this can be done for 1.20, though perhaps we should land the selector fix.

@gopherbot
Copy link

Change https://go.dev/cl/461577 mentions this issue: go/types, types2: don't look up fields or methods when expecting a type

@findleyr
Copy link
Contributor

I think we can avoid most (but not all) instances of this type of crash with the CL above, which we should consider for 1.20. I have ideas for a more comprehensive fix for 1.21.

@findleyr findleyr changed the title x/tools/gopls: SIGSEGV when checking method on generic struct called from package-level function go/types: panic when checking method on generic struct called from package-level function Jan 11, 2023
@findleyr findleyr modified the milestones: gopls/v0.12.0, Go1.20 Jan 11, 2023
gopherbot pushed a commit that referenced this issue Jan 11, 2023
As we have seen many times, the type checker must be careful to avoid
accessing named type information before the type is fully set up. We
need a more systematic solution to this problem, but for now avoid one
case that causes a crash: checking a selector expression on an
incomplete type when a type expression is expected.

For #57522

Change-Id: I7ed31b859cca263276e3a0647d1f1b49670023a9
Reviewed-on: https://go-review.googlesource.com/c/go/+/461577
Run-TryBot: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
@findleyr findleyr modified the milestones: Go1.20, Go1.21 Jan 18, 2023
@findleyr
Copy link
Contributor

Moving this to 1.21 for the follow-up.

@findleyr
Copy link
Contributor

@griesemer has been thinking about more general controls for lazy expansion; in the meantime this particular crash is fixed, so I will close this issue.

@golang golang locked and limited conversation to collaborators Apr 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

6 participants