x/tools/gopls: Hover: invalid nil entry in types.Defs map
Closed this issue ยท 15 comments
#!stacks
"runtime.sigpanic" && ("golang.hover:+170" || "golang.hover:+209" || "golang.hover:+216")
This stack zUGLQA was reported by telemetry:
if def, ok := pkg.TypesInfo().Defs[ident]; ok && ident.Pos() == def.Pos() {Looks like Defs[ident]=nil is an actual map entry. This is confirmed by #69362 (comment).
crash/crash
runtime.gopanic:+69
runtime.panicmem:=262
runtime.sigpanic:+19
golang.org/x/tools/gopls/internal/golang.hover:+170
golang.org/x/tools/gopls/internal/golang.Hover:+4
golang.org/x/tools/gopls/internal/server.(*server).Hover:+30
golang.org/x/tools/gopls/internal/protocol.serverDispatch:+335
golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.ServerHandler.func3:+5
golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.handshaker.func4:+52
golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2
golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3
runtime.goexit:+0
golang.org/x/tools/gopls@v0.16.1 go1.23.0 darwin/amd64 vscode (1)
Issue created by golang.org/x/tools/gopls/internal/telemetry/cmd/stacks.
Dups: ylB3Iw x2v5eg v95MAw r1YMdg
Related Issues and Documentation
- x/tools/gopls: Hover bug reported by telemetry #66857 (closed)
- x/tools/gopls: "type name %q without type spec" bug in Hover (via telemetry) #64241
- x/tools/gopls: Hover bug reported by telemetry #64237 (closed)
- x/tools/gopls: Hover bug reported by telemetry #64239 (closed)
- x/tools/gopls: Hover bug reported by telemetry [PE4R3g] #64244 (closed)
- x/tools/gopls: "type name %q without type spec" bug in Hover(reported by telemetry) #66314 (closed)
- x/tools/gopls: panic in hover #52211 (closed)
- x/tools/gopls: Highlight crash (reported by telemetry) #66091 (closed)
- x/tools/gopls: crash in work.Hover #60821 (closed)
- x/tools/gopls: hoverBuiltin bug reported by telemetry #64502 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
I can't explain this one. The only three calls to recordDef(id, nil) in the type checker are for:
package idswitch id := expr.(type) {}- the blank identifier in
_ = expr.
It can't be (1) because the Hover logic handled the package clause specially at L186. It can't be (2) because this would cause referencedObject to return a non-nil third result (selectedType), causing an early return. And it can't be (3) because that would cause referencedObject not to return a non-nil Object, Ident pair, leading to an early return.
Clearly there is a mistake in my logic. But where?
Agreed. I think the best we'll be able to do here is downgrade the panic into two or more bug reports that refine the panic.
This is not the first "can't happen" bug related to go/types...
Change https://go.dev/cl/627015 mentions this issue: gopls/internal/golang: refine crash report golang/go#69362
This stack ylB3Iw was reported by telemetry:
crash/crashruntime.gopanic:+69runtime.panicmem:=262runtime.sigpanic:+19golang.org/x/tools/gopls/internal/golang.hover:+209golang.org/x/tools/gopls/internal/golang.Hover:+4golang.org/x/tools/gopls/internal/server.(*server).Hover:+30golang.org/x/tools/gopls/internal/protocol.serverDispatch:+335golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.ServerHandler.func3:+5golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.handshaker.func4:+52golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3runtime.goexit:+0
golang.org/x/tools/gopls@v0.17.0-pre.2 go1.23.3 darwin/arm64 vscode (1)
This stack x2v5eg was reported by telemetry:
crash/crashruntime.gopanic:+69runtime.panicmem:=262runtime.sigpanic:+9golang.org/x/tools/gopls/internal/golang.hover:+209golang.org/x/tools/gopls/internal/golang.Hover:+4golang.org/x/tools/gopls/internal/server.(*server).Hover:+30golang.org/x/tools/gopls/internal/protocol.serverDispatch:+335golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.ServerHandler.func3:+5golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.handshaker.func4:+52golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3runtime.goexit:+0
golang.org/x/tools/gopls@v0.17.1 go1.23.3 windows/amd64 vscode (1)
golang.org/x/tools/gopls@v0.17.0 go1.23.2 windows/amd64 vscode (1)
Well, the new stack is clearly a lie! Bumping this to 0.18.1, when we can hopefully have accurate stacks.
I have a theory: of the three cases listed above, the type-switch one is the most plausible. In order to reach the assertion, we must have gotten the triple (ident != nil, obj != nil, selectedType == nil) from referencedObject. Of the three return statements in referencedObject, this implicates only the one after the call to typeSwitchImplicits, and means that typeSwitchImplicits must have returned (empty slice, nil Type). Looking at the return statements within typeSwitchImplicits, this implicates only the final one (the other two are unreachable due to preconditions of this call). So, we have a type switch with an empty Body.List, and there is missing type information for the operand of the type switch: switch x := y.(type) {}.
The question then becomes: what syntax could y be to cause the type checker not to record a type for it? This would likely be a type checker bug. I looked for recent "no type recorded for expr" bugs but didn't find anything promising.
Still, I think this implicates the behavior of the type checker on a certain input with at least two compilation errors.
Ah, blaming the "may be nil" comment on the TypeOf call brought me to #69092 (comment), which records that we decided types may always be nil and that we should be defensive. So perhaps the right thing to do here is to return types.Invalid if the TypeOf call fails; then hover will take the early return and not reach the Defs lookup.
@adonovan FWIW I tried to follow your lead, and it may be a dead end: types.Checker.expr always records a type (possibly invalid), and inside the type checker we call expr on the asserted expression before we record any implicits https://cs.opensource.google/go/go/+/master:src/go/types/stmt.go;l=740;drc=c9afcbade7308cf66b67b9ce080f10b621b17c6a
So we can't have implicits with no RHS type.
This stack v95MAw was reported by telemetry:
crash/crashruntime.gopanic:+69runtime.panicmem:=262runtime.sigpanic:+19golang.org/x/tools/gopls/internal/golang.hover:+216golang.org/x/tools/gopls/internal/golang.Hover:+4golang.org/x/tools/gopls/internal/server.(*server).Hover:+30golang.org/x/tools/gopls/internal/protocol.serverDispatch:+335golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.ServerHandler.func3:+5golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.handshaker.func4:+52golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3runtime.goexit:+0
golang.org/x/tools/gopls@v0.18.0-pre.2 go1.24.0 linux/amd64 vscode (2)
The most recent stack shows definitively that the types.Defs map contains a nil value.
I repro'ed!
switch x := y.(type) { // y is undefined!
case int:
}
Test+fix incoming.
Change https://go.dev/cl/652015 mentions this issue: gopls/internal/golang: fix crash when hovering over implicit
This stack r1YMdg was reported by telemetry:
crash/crashruntime.gopanic:+69runtime.panicmem:=262runtime.sigpanic:+9golang.org/x/tools/gopls/internal/golang.hover:+216golang.org/x/tools/gopls/internal/golang.Hover:+4golang.org/x/tools/gopls/internal/server.(*server).Hover:+30golang.org/x/tools/gopls/internal/protocol.serverDispatch:+335golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.ServerHandler.func3:+5golang.org/x/tools/gopls/internal/lsprpc.(*streamServer).ServeStream.handshaker.func4:+52golang.org/x/tools/gopls/internal/protocol.Handlers.MustReplyHandler.func1:+2golang.org/x/tools/gopls/internal/protocol.Handlers.AsyncHandler.func2.2:+3runtime.goexit:+0
golang.org/x/tools/gopls@v0.18.1 go1.24.0 windows/amd64 vscode (7)
golang.org/x/tools/gopls@v0.18.1 go1.23.6 windows/amd64 vscode (1)