fix(gnotypes): prevent init panic on Go 1.26+ from recursive builtin type stubs#57
fix(gnotypes): prevent init panic on Go 1.26+ from recursive builtin type stubs#57tbruyelle wants to merge 3 commits into
Conversation
…type stubs
Go 1.26's go/types now treats the self-referential predeclared type stubs in
builtin.gno (`type bool bool`, `type comparable interface{ comparable }`, ...)
as a fatal "invalid recursive type" error that aborts type resolution for the
whole file. This leaves ~23 builtin funcs -- including gno's cross, revive and
istypednil -- with a nil Type(), and isMethod's unchecked
fn.Type().(*types.Signature) then panics at package init. The panic kills the
gnopls binary on startup, so the language server never answers a single request
(definition, hover, ...) on any file.
On Go 1.24/1.25 the same recursive-type error was reported but non-fatal, so the
funcs still got their signatures -- hence the regression only surfaced after
building with the 1.26 toolchain.
- builtin.gno: drop the self-referential predeclared scalar type stubs and the
comparable stub. They are pure documentation: each is already provided by
types.Universe and skipped during registration, so removing them changes
nothing but lets the file type-check cleanly on all toolchains.
- builtin.go: harden isMethod and the builtin registration loop to log-and-skip
a nil signature instead of panicking, so a future toolchain change degrades
gracefully instead of taking down the whole server.
Verified on Go 1.26.4 and 1.25.0: gnotypes/resolver tests pass, builtins
register, `gnopls definition` on the realm builtin type and cross-package
imports resolve, and `gnopls check` on an interrealm-v2 realm is clean.
Add a `toolchain go1.26.4` directive so CI and `go install` build with the Go 1.26 toolchain that exposes the gnotypes init panic fixed in the previous commit. Without this, a machine with an older default toolchain could build a working binary while 1.26 users get a crash-on-startup server, and CI would stay green against the very version that breaks. The `go 1.25.0` minimum language version is left unchanged.
|
Tested on Go 1.26.4 and 1.25.10 — LGTM. Removing the recursive stubs fixes it at the source (repro'd: old file → 23 nil-typed funcs, this PR → 0), and the nil guards are solid. Two minor notes:
(ai agent) |
Apply the same defensive handling as isMethod to IsGnoBuiltin's obj.Type().(*types.Signature) assertion: an unresolved func signature now returns false instead of panicking. Addresses PR review feedback (the last unguarded instance of this pattern).
|
Thanks for the review!
Good catch — fixed in a follow-up commit (
I re-ran the actual
So for the real code path it is version-dependent. The subtlety: Your importer point is a real, related failure mode though: an importer that can't resolve |
|
this change finally makes me free from the eternal pain point |
Go 1.26's go/types now treats the self-referential predeclared type stubs in builtin.gno (
type bool bool,type comparable interface{ comparable }, ...) as a fatal "invalid recursive type" error that aborts type resolution for the whole file. This leaves ~23 builtin funcs -- including gno's cross, revive and istypednil -- with a nil Type(), and isMethod's unchecked fn.Type().(*types.Signature) then panics at package init. The panic kills the gnopls binary on startup, so the language server never answers a single request (definition, hover, ...) on any file.On Go 1.24/1.25 the same recursive-type error was reported but non-fatal, so the funcs still got their signatures -- hence the regression only surfaced after building with the 1.26 toolchain.
Verified on Go 1.26.4 and 1.25.0: gnotypes/resolver tests pass, builtins register,
gnopls definitionon the realm builtin type and cross-package imports resolve, andgnopls checkon an interrealm-v2 realm is clean.