Go version

go version go1.23.0 darwin/arm64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/varun/Library/Caches/go-build'
GOENV='/Users/varun/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/varun/.asdf/installs/golang/1.23.0/packages/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/varun/.asdf/installs/golang/1.23.0/packages'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/varun/.asdf/installs/golang/1.23.0/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/varun/.asdf/installs/golang/1.23.0/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.0'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/varun/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/varun/Code/play/go/underpanic/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/tr/gylnxkts3bn0gyhhlrv8z9_m0000gn/T/go-build2694439591=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

Minimal example: https://github.com/varungandhi-src/underpanic

I had some code using using APIs like String on *types.Named, as well as functions like types.NewMethodSet.

I upgraded that from Go 1.22.4 to Go 1.23.0

What did you see happen?

go/types.(*Named).under(0x140001a6850)
        /Users/varun/.asdf/installs/golang/1.23.0/go/src/go/types/named.go:548 +0x38c
go/types.under({0x1007ca020, 0x140001a6850})
        /Users/varun/.asdf/installs/golang/1.23.0/go/src/go/types/under.go:16 +0x2c
go/types.writeObject(0x14000467890, {0x1007cdb38, 0x140001a4780}, 0x0)
        /Users/varun/.asdf/installs/golang/1.23.0/go/src/go/types/object.go:576 +0x734
go/types.ObjectString({0x1007cdb38, 0x140001a4780}, 0x0)
        /Users/varun/.asdf/installs/golang/1.23.0/go/src/go/types/object.go:613 +0x44
go/types.(*TypeName).String(...)
        /Users/varun/.asdf/installs/golang/1.23.0/go/src/go/types/object.go:619
main.main()
        /Users/varun/Code/play/go/underpanic/main.go:33 +0x164

What did you expect to see?

Functions like NewMethodSet and methods like String should continue to work in the presence of CGo.

Comment From: gabyhelp

Related Issues and Documentation

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

Comment From: ianlancetaylor

CC @griesemer @findleyr

Comment From: adonovan

Many thanks for the very helpful bug report. The input program that reproduces the problem can be reduced to the following, which does not use cgo:

package main

type (
    T struct{}
    U = T
    S U
)

Loading it using this reduced main program:

package main

import (
    "go/types"
    "log"

    "golang.org/x/tools/go/packages"
)

func main() {
    cfg := &packages.Config{Mode: packages.NeedTypes}
    pkgs, err := packages.Load(cfg, ".")
    if err != nil {
        log.Fatal(err)
    }
    obj := pkgs[0].Types.Scope().Lookup("S").(*types.TypeName)
    _ = obj.String() // panics
}

produces the same crash:

processing type: type golang.org/x/tools/issue68877.T struct{}
panic: Named.check == nil but type is incomplete

goroutine 1 [running]:
go/types.(*Named).under(0x140000c0b60)
    /Users/adonovan/w/goroot/src/go/types/named.go:548 +0x38c
go/types.under({0x1029e9bc0, 0x140000c0b60})
    /Users/adonovan/w/goroot/src/go/types/under.go:16 +0x2c
go/types.writeObject(0x140002910b0, {0x1029ed7d8, 0x140005304b0}, 0x0)
    /Users/adonovan/w/goroot/src/go/types/object.go:576 +0x734
go/types.ObjectString({0x1029ed7d8, 0x140005304b0}, 0x0)
    /Users/adonovan/w/goroot/src/go/types/object.go:613 +0x44
go/types.(*TypeName).String(...)
    /Users/adonovan/w/goroot/src/go/types/object.go:619
main.main()
    /Users/adonovan/w/xtools/issue68877/main.go:33 +0x164
exit status 2

Comment From: adonovan

Reducing again to eliminate packages.Load:

func TestIssue68877(t *testing.T) {
    setGotypesalias(t, true)
    const src = `package main

type (
    T struct{}
    U = T
    S U
)`

    pkg := mustTypecheck(src, nil, nil)
    S := pkg.Scope().Lookup("S").(*TypeName)
    _ = S.String()
}

Comment From: griesemer

cc: @timothy-king for visibility

Comment From: griesemer

Analysis so far: The underlying problem (no pun intended) is that Named.Underlying may end up calling Unalias which may return a Named type which is not the actual underlying type. We can follow that chain to the end which addresses this particular issue ~but causes other tests to loop endlessly, for not yet fully understood reasons~.

The endless seem to be caused by invalid code (alias cycles). Should have a tentative CL later today.

Comment From: gopherbot

Change https://go.dev/cl/605757 mentions this issue: go/types, types2: fix Named.Underlying in the presence of Alias types

Comment From: griesemer

Gopherbot, please create a backport issue for Go 1.23.

Comment From: callthingsoff

Gopherbot, please create a backport issue for Go 1.23.

We need ‘@‘ the bot.

Comment From: findleyr

@gopherbot, please create a backport issue for Go 1.23: this is a regression in the type checker when run with GODEBUG=gotypesalias=1, the new default.

Comment From: gopherbot

Backport issue(s) opened: #68894 (for 1.23).

Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases.

Comment From: gopherbot

Change https://go.dev/cl/605977 mentions this issue: go/types, types2: Named.cleanup must also handle *Alias types