golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.89k stars 17.52k forks source link

go/types, cmd/compile/internal/types2: type parameter inference fails for constraints that succeed individually #66751

Open firelizzard18 opened 5 months ago

firelizzard18 commented 5 months ago

Go version

go version go1.22.1 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/firelizzard/.cache/go-build'
GOENV='/home/firelizzard/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/firelizzard/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/firelizzard/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.1'
GCCGO='/usr/bin/gccgo'
GOAMD64='v1'
AR='ar'
CC='x86_64-pc-linux-gnu-gcc'
CXX='x86_64-pc-linux-gnu-g++'
CGO_ENABLED='1'
GOMOD='/home/firelizzard/src/yaegi/go-script/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 -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3476193043=/tmp/go-build -gno-record-gcc-switches'

What did you do?

https://go.dev/play/p/fVSkvTEgYx_1

package main

type ptrTo[A any] interface{ ~*A }
type hasFoo[A any] interface{ foo(A) }
type both[A, B any] interface {
    ptrTo[A]
    hasFoo[B]
}

type fooer[A any] struct{}

func (f *fooer[A]) foo(A) {}

func withPtr[A ptrTo[B], B any]()       {}
func withFoo[A hasFoo[B], B any]()      {}
func withBoth[A both[B, C], B, C any]() {}

func main() {
    withPtr[*fooer[int]]()  // Ok
    withFoo[*fooer[int]]()  // Ok
    withBoth[*fooer[int]]() // Error: cannot infer C
}

What did you see happen?

Inference succeeds on all three calls.

What did you expect to see?

Inference succeeds on the first two but fails on the third. If inference of B for withPtr or withFoo failed, it would make sense. But inference succeeds on both of those so it's surprising and confusing that it fails for withBoth.

findleyr commented 5 months ago

CC @griesemer

Garciat commented 4 months ago

I ran into an inference issue that is very similar to OP's issue:

type X struct {}
func (x X) M() int { return 42 }

func CallM1[T interface{M() R}, R any](t T) R {
    return t.M()
}

func CallM2[T interface{X; M() R}, R any](t T) R {
    return t.M()
}

func main() {
    CallM1(X{}) // OK
    CallM2(X{}) // cannot infer R
}

I wasn't expecting CallM2 to fail inference on R because of the added T=X constraint.