Go version
go version go1.25-20250711-RC00 REDACTED +6ebb5f56d9 X:fieldtrack,boringcrypto linux/amd64
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=''
GOAMD64='v3'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='REDACTED'
GOCACHEPROG=''
GODEBUG=''
GOENV='REDACTED'
GOEXE=''
GOEXPERIMENT='fieldtrack,boringcrypto'
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build889680920=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='REDACTED'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='REDACTED'
GOPRIVATE=''
GOPROXY=''
GOROOT='REDACTED'
GOSUMDB=''
GOTELEMETRY='local'
GOTELEMETRYDIR='REDACTED'
GOTMPDIR=''
GOTOOLCHAIN=''
GOTOOLDIR='REDACTED'
GOVCS=''
GOVERSION='go1.25-20250711-RC00 REDACTED +6ebb5f56d9 X:fieldtrack,boringcrypto'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
We use //go:nointerface within a project, and we encountered the following issue:
package missing_method_repro_test
import "testing"
type Fooer interface {
Foo() string
}
type FooImpl struct{}
//go:nointerface
func (FooImpl) Foo() string { return "foo" }
func toInterface[T Fooer](fooer T) Fooer {
return fooer
}
func TestFooer(t *testing.T) {
var iface Fooer = toInterface(FooImpl{})
if iface == nil {
t.Errorf("iface = nil, want non-nil")
}
if iface.Foo == nil {
t.Errorf("iface.Foo = nil, want non-nil")
}
iface.Foo() // panics with nil pointer dereference
}
What did you see happen?
So even though a method is marked as nointerface, it's valid to pass this to function with the interface as a type constraint (and calling the method actually works). It looks like it's also valid to pass this value to an interface (because it passes assignability rules in the generic). And while the interface method even returns non-nil, calling the mehtod results in a nil pointer dereference. Please note that the following workaround works:
type dispatch func() string
func (d dispatch) Foo() string {
return d()
}
func toInterface[T Fooer](fooer T) Fooer {
return dispatch(fooer.Foo)
}
What did you expect to see?
Since the manual dispatch approach works, I guess the compiler could just figure out how to do this kind of dispatching itself.
Comment From: cherrymui
So even though a method is marked as nointerface, it's valid to pass this to function with the interface as a type constraint
I think this should not be allowed. A type constraint is an interface. So if a type does not satisfy a regular interface, it should also not satisfy the same interface as a type constraint.
cc @golang/compiler @mrkfrmn
Comment From: zoltanhalassy
I think this should not be allowed.
I don't mind personally, but please note that code exists out there right now, which relies on the generic loophole. I don't know what's the procedure around that. Disallowing it will cause compilation failures for existing code from that change though.
Comment From: cherrymui
Thanks for the note. We should analyze the internal usage and have a migration plan. Let's continue this on the internal channel. Would you mind filing an issue internally? Thanks.
Comment From: gabyhelp
Related Issues
- gccgo: nointerface on exported inlined method causes bad type descriptor #30862 (closed)
- go/types, types2: Syntax (interface vs nil struct) This example breaks the concept of passing nil values to interface #54470 (closed)
- nil empty interface conversion to generic type panics #57839 (closed)
- No compilation error on assigning pointer to interface to an interface #26641 (closed)
- affected/package: interfaces with generics #50313 (closed)
- cmd/compile: `//go:nointerface` mishandled for promoted methods with -G=3 #47928 (closed)
- cmd/compiler: generics code loses nil-ness of interface in sub-call #69162 (closed)
- not `nil` return value, when return `nil` struct which implements `interface`. #19803 (closed)
- Nil-ness of a pointer is lost when converted to an interface #42306 (closed)
- gccgo: assert in "implements_interface", types.cc:9098 with inlinable function #33219 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)