Go version

go version go1.25rc2 linux/arm64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='0'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='off'
GOCACHEPROG=''
GODEBUG=''
GOENV=''
GOEXE=''
GOEXPERIMENT='jsonv2'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build532612676=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/tie/kek/bar/go.mod'
GOMODCACHE=''
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH=''
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/tie/sdk/go1.25rc2'
GOSUMDB='sum.golang.org'
GOTELEMETRY='off'
GOTELEMETRYDIR=''
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/tie/sdk/go1.25rc2/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='go1.25rc2'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

See https://go.dev/play/p/Jy3vpt28nU3?v=gotip

I’ve defined a type alias in an internal package for a type with a method that is usually inlined (e.g. encoding/json/jsontext.Token.String).

What did you see happen?

Go compiler does not inline the method and instead allocates the result on the heap when a type is defined as a type alias.

GOEXPERIMENT=jsonv2 go1.25rc2 run  -gcflags=-m . |& sort
Allocations: 1
# example
example/main.go:15:32: inlining call to jsontext.NewDecoder
example/main.go:15:32: inlining call to jsontext.NewDecoder
example/main.go:15:32: new(jsontext.Decoder) escapes to heap
example/main.go:15:48: &bytes.Buffer{...} escapes to heap
example/main.go:15:48: inlining call to bytes.NewBuffer
example/main.go:15:56: ([]byte)("\"circle\"") escapes to heap
example/main.go:22:12: ... argument does not escape
example/main.go:24:12: inlining call to checkToken
example/main.go:24:12: "unreachable" escapes to heap
example/main.go:27:12: ... argument does not escape
example/main.go:27:12: inlining call to fmt.Printf
example/main.go:27:47: after.Mallocs - before.Mallocs escapes to heap
example/main.go:30:17: token does not escape
example/main.go:30:6: can inline checkToken
example/main.go:35:9: "unreachable" escapes to heap

What did you expect to see?

Same as an implementation without type aliases, jsontext.Token.String is inlined and the result does not escape.

@@ -8,7 +8,7 @@
        "log"
        "runtime"

-       "example/jsontext"
+       "encoding/json/jsontext"
 )

 func main() {
  Allocations: 0
  # example
  example/main.go:13:32: inlining call to jsontext.NewDecoder
  example/main.go:13:32: new(jsontext.Decoder) escapes to heap
  example/main.go:13:48: &bytes.Buffer{...} escapes to heap
  example/main.go:13:48: inlining call to bytes.NewBuffer
  example/main.go:13:56: ([]byte)("\"circle\"") escapes to heap
  example/main.go:18:33: inlining call to jsontext.(*Decoder).ReadToken
  example/main.go:20:12: ... argument does not escape
  example/main.go:25:12: ... argument does not escape
  example/main.go:25:12: inlining call to fmt.Printf
  example/main.go:25:47: after.Mallocs - before.Mallocs escapes to heap
  example/main.go:28:17: token does not escape
+ example/main.go:29:28: inlining call to jsontext.Token.String
+ example/main.go:29:28: string(jsontext.b) does not escape
  example/main.go:33:9: "unreachable" escapes to heap

Comment From: tie

~~Oops, accidentally typed Command+Enter. I’ll update the issue in a few minutes.~~ Done.

Comment From: gabyhelp

Related Issues

Related Code Changes

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: tie

Seems to be the same issue as #71598

Comment From: Jorropo

Adding _ "encoding/json/jsontext" fixes it.