Go version
go version go1.26.0 darwin/arm64
Output of go env in your module/workspace:
AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE='on'
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/pkolak/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/pkolak/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/9f/3zyyhrh945q002gvclld4bg00000gp/T/go-build2148103633=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/pkolak/go/pkg/mod'
GONOPROXY=''
GONOSUMDB='github.com/nike-*'
GOOS='darwin'
GOPATH='/Users/pkolak/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/pkolak/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.darwin-arm64'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/pkolak/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/pkolak/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.0.darwin-arm64/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.26.0'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
I defined a generic interface Getter[T] and a generic function Evaluate[T] that accepts a Getter[T] parameter. I then created a concrete type SomeInt whose pointer receiver implements Getter[int].
Minimal reproducer:
package main
type Getter[T any] interface {
Get() T
}
func Evaluate[T any](getter Getter[T]) T {
return getter.Get()
}
var someInt = Evaluate(&SomeInt{}) // ERROR: cannot infer T
type SomeInt struct{}
func (i *SomeInt) Get() int {
return 10
}
func main() {
_ = someInt
}
Playground: https://go.dev/play/p/mp1G_OFCoui
What did you see happen?
When calling Evaluate(&SomeInt{}) in a package-level variable initializer, the compiler fails to infer the type parameter T, even though *SomeInt unambiguously implements Getter[int]. The behavior depends on where in the file the var declaration is placed relative to the type and method declarations:
| Case |
Declaration position |
Evaluate(&SomeInt{}) |
Evaluate[int](&SomeInt{}) |
| 1 |
Before type declaration |
❌ cannot infer T |
✅ Succeeds |
| 2 |
After type declaration, before method |
❌ cannot infer T |
✅ Succeeds |
| 3 |
Inside init() function |
✅ Succeeds |
✅ Succeeds |
| 4 |
After method declaration |
✅ Succeeds |
✅ Succeeds |
What did you expect to see?
I expected the compiler to successfully infer the type parameter T as int in the call Evaluate(&SomeInt{}) when used in a package-level variable initializer, regardless of where in the file the var declaration appears relative to the type and method declarations.
Since *SomeInt unambiguously implements Getter[int] (it has a single method Get() int matching the interface), the compiler has all the information needed to deduce T = int. This inference already works correctly in all of the following contexts:
- Inside function bodies (
main(), init(), or any other function)
- At package level only if the
var is placed after the method declaration in source order
- When the type parameter is provided explicitly (
Evaluate[int](&SomeInt{})) — works everywhere
Therefore, the expected behavior is that all four cases below should compile without error:
// Case 1 — Before type declaration
var someInt = Evaluate(&SomeInt{}) // should infer T = int ✅
type SomeInt struct{}
// Case 2 — After type declaration, before method
var someInt = Evaluate(&SomeInt{}) // should infer T = int ✅
func (i *SomeInt) Get() int { return 10 }
// Case 3 — Inside init()
func init() {
someInt = Evaluate(&SomeInt{}) // should infer T = int ✅
}
// Case 4 — After method declaration
var someInt = Evaluate(&SomeInt{}) // should infer T = int ✅
According to the Go specification section on Package initialization:
Dependency analysis does not rely on the actual values of the variables, only on lexical references to them in the source, analyzed transitively.
This means the compiler is expected to resolve all package-level references — including type and method declarations — transitively across the entire package, without regard to their position in the source file. Since *SomeInt and its Get() int method are declared in the same package, the compiler should recognize that *SomeInt satisfies Getter[int] and infer T = int at any point in the file. The current behavior — where inference fails in Cases 1 & 2 but succeeds in Case 4 — indicates that the type inference pass is incorrectly sensitive to source ordering, contradicting the specification's guarantee of order-independent dependency analysis.
Go version
go version go1.26.0 darwin/arm64
Output of
go envin your module/workspace:What did you do?
I defined a generic interface
Getter[T]and a generic functionEvaluate[T]that accepts aGetter[T]parameter. I then created a concrete typeSomeIntwhose pointer receiver implementsGetter[int].Minimal reproducer:
Playground: https://go.dev/play/p/mp1G_OFCoui
What did you see happen?
When calling
Evaluate(&SomeInt{})in a package-level variable initializer, the compiler fails to infer the type parameterT, even though*SomeIntunambiguously implementsGetter[int]. The behavior depends on where in the file thevardeclaration is placed relative to the type and method declarations:Evaluate(&SomeInt{})Evaluate[int](&SomeInt{})cannot infer Tcannot infer Tinit()functionWhat did you expect to see?
I expected the compiler to successfully infer the type parameter
Tasintin the callEvaluate(&SomeInt{})when used in a package-level variable initializer, regardless of where in the file thevardeclaration appears relative to the type and method declarations.Since
*SomeIntunambiguously implementsGetter[int](it has a single methodGet() intmatching the interface), the compiler has all the information needed to deduceT = int. This inference already works correctly in all of the following contexts:main(),init(), or any other function)varis placed after the method declaration in source orderEvaluate[int](&SomeInt{})) — works everywhereTherefore, the expected behavior is that all four cases below should compile without error:
According to the Go specification section on Package initialization:
This means the compiler is expected to resolve all package-level references — including type and method declarations — transitively across the entire package, without regard to their position in the source file. Since
*SomeIntand itsGet() intmethod are declared in the same package, the compiler should recognize that*SomeIntsatisfiesGetter[int]and inferT = intat any point in the file. The current behavior — where inference fails in Cases 1 & 2 but succeeds in Case 4 — indicates that the type inference pass is incorrectly sensitive to source ordering, contradicting the specification's guarantee of order-independent dependency analysis.