chore: simplify and modernize for Go 1.27 - #2627
Open
dunglas wants to merge 7 commits into
Open
Conversation
Go 1.27 adds the slicesbackward, embedlit and unsafefuncs analyzers and renames waitgroup to waitgroupgo. The two extgen parsers are left untouched: embedlit rewrites their composite literals into a shape that reads worse than the original.
go fix does not analyze files that import "C", so the root package never received the transformations applied everywhere else. splitRemoteAddr now uses strings.CutLast, new in Go 1.27. Its not-found return value is exactly what the old else branch assigned, so the branch is gone. The manual unsafe.Pointer/uintptr arithmetic becomes unsafe.Add. The old form is only valid inside a single expression and silently breaks if a later refactor splits the line.
Drops the throwaway target values the errors.As calls had to allocate.
Eleven copies of the same register-or-panic block, each allocating an AlreadyRegisteredError to match against.
The package has no C preamble and calls nothing in C, but the bare import "C" still forced it through cgo.
synctest.Wait returns once every subscriber goroutine is durably blocked, so the subscriber count is exact instead of polled for up to a second. Covers the WaitForStateWithTimeout give-up path too, including that it drops its subscriber. The bubble's fake clock makes its one second timeout fire instantly.
Uses the goroutineleak profile, generally available since Go 1.27, to catch a thread, scaling ticker or watcher goroutine that outlives Shutdown with nothing left to wake it. The count is compared against a baseline rather than zero because tests share a process. Profile.Count only reports the previous detection cycle, so the profile has to be written first to trigger one.
AlliBalliBaba
approved these changes
Aug 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the Go 1.27 upgrade in a411024, applying what the new release makes available.
Modernizers
go fixgainedslicesbackward,embedlitandunsafefuncs, and renamedwaitgrouptowaitgroupgo. Applied across both modules, with two exceptions:embedlitrewrites their composite literals into a shape that reads worse than the original.go fixskips files that import"C", so the root package never got the transformations applied everywhere else. Those are done by hand in a separate commit.Standard library
splitRemoteAddrusesstrings.CutLast, new in 1.27. Its not-found return is exactly what the oldelsebranch assigned, so the branch disappears.unsafe.Pointer/uintptrarithmetic intypes.goandfrankenphp.gobecomesunsafe.Add. The old form is only valid inside a single expression and silently breaks if a later refactor splits the line.errors.Asbecomeserrors.AsType, dropping the throwaway target values.metrics.gocollapse into onemustRegisterhelper.Tests
internal/statemoves totesting/synctest.synctest.Waitreturns once every subscriber goroutine is durably blocked, so the subscriber count is exact rather than polled for up to a second. This also makes theWaitForStateWithTimeoutgive-up path worth covering, since the bubble's fake clock fires its one second timeout instantly.The other timing tests stay as they are.
regularRequestChanis a package global that live PHP thread goroutines receive from, so a bubbled sender can have its send stolen by an out-of-bubble thread, and PHP threads are C threads, which never count as durably blocked. Bubbling them would buy flakiness, not determinism.A new test uses the
goroutineleakprofile, GA in 1.27, to catch a thread, scaling ticker or watcher goroutine that outlivesShutdownwith nothing left to wake it. Currently reports zero leaks across a fullInit/Shutdowncycle./debug/pprof/goroutineleakneeds no code to expose:net/http/pprof.Indexdispatches profiles by name, so it is already live on the admin endpoint. Verified against a running server. It reports one leaked goroutine there, but the same one appears with nophp_serverconfigured at all, so it is Caddy/runtime baseline rather than ours.Drive-by
internal/statehad a bareimport "C"with no C preamble and no calls into C, which forced a pure Go package through cgo. Removed.No action needed
encoding/json/v2backingencoding/jsonand the size-specialized allocator are both in the 1.27 baseline and active automatically. The stricter jsonv2 defaults ship only with an explicitencoding/json/v2import, so v1 semantics are unchanged: duplicate keys still accepted, invalid UTF-8 still replaced rather than rejected.