Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: recursive generic interface instantiation error #65362

Open
carmichaeljr opened this issue Jan 30, 2024 · 5 comments
Open

cmd/compile: recursive generic interface instantiation error #65362

carmichaeljr opened this issue Jan 30, 2024 · 5 comments
Assignees
Labels
generics Issue is related to generics NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@carmichaeljr
Copy link

Go version

go version go1.21.6 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/jcarmichael/.cache/go-build'
GOENV='/home/jcarmichael/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/jcarmichael/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/jcarmichael/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.6'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/mnt/c/Users/Lenovo/Documents/Programming/util/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-build1952531264=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I wrote the code shown below and in the following playground link: https://go.dev/play/p/d8XxoEklO6D

package main

import "fmt"

type Comparisons[OI any, OIR any, K any, V any] interface {
	Difference(other OIR) OI
}

// An interface that only allows read operations on a vector.
type ReadVector[V any] interface {
	Comparisons[Vector[V], ReadVector[V], int, V]
}

// An interface that only allows write operations on a vector.
type WriteVector[V any] interface {
	otherMethods()
}

// An interface that represents a vector with no restrictions on reading or
// writing.
type Vector[V any] interface {
	ReadVector[V]
	WriteVector[V]
}

type VectorImpl[T any] struct{}

func (v *VectorImpl[T]) otherMethods() {}
func (v *VectorImpl[T]) Difference(other ReadVector[T]) Vector[T] {
	rv := VectorImpl[T]{}
	return &rv
}

func main() {
	v := VectorImpl[int]{}
	v2 := VectorImpl[int]{}
	var v2Interface Vector[int] = &v2
	fmt.Println(v.Difference(v2Interface))
}

What did you see happen?

The compiler produced the following error:

./prog.go:38:27: cannot use v2Interface (type ReadVector[int]) as type ReadVector[go.shape.int] in argument to (*VectorImpl[go.shape.int]).Difference:
	ReadVector[int] does not implement ReadVector[go.shape.int] (wrong type for Difference method)
		have Difference(ReadVector[int]) Vector[int]
		want Difference(ReadVector[go.shape.int]) go.shape.interface { main.otherMethods() }

Go build failed.

What did you expect to see?

I expected the program to compile and print the empty Vector[int] structure value.

Of note is if you change the second generic parameter on line 11 to Vector[int] as well as the corresponding type on the Difference method on line then the compiler successfully finishes, and the program works as intended.

I am not sure if this is relevant, but the compiler error does not list the difference method on the Vector return type of the Difference method in the error it produces. It prints this:

want Difference(ReadVector[go.shape.int]) go.shape.interface { main.otherMethods() }

when I think it should print something like this (formatting added for readability):

want Difference(ReadVector[go.shape.int]) go.shape.interface { 
    main.otherMethods() 
    main.Difference(
        ReadVector[go.shape.int]
    ) go.shape.interface{ main.otherMethods(); ReadVector[go.shape.int]} 
}

I am guessing on the syntax of the output shown above, I am just saying what would make sense to see based on what I am already seeing, I am sure the correct output is different.

I am not sure what the rules are regarding recursive interface type definitions as shown in the example, and the issue is only compounded by the added generics.

@carmichaeljr carmichaeljr changed the title Generic Interface Instantiation Error Recursive Generic Interface Instantiation Error Jan 30, 2024
@mknyszek mknyszek changed the title Recursive Generic Interface Instantiation Error cmd/compile: recursive generic interface instantiation error Jan 30, 2024
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jan 30, 2024
@mknyszek mknyszek added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. generics Issue is related to generics and removed compiler/runtime Issues related to the Go compiler and/or runtime. labels Jan 30, 2024
@mknyszek mknyszek added this to the Backlog milestone Jan 30, 2024
@mknyszek
Copy link
Contributor

CC @golang/compiler, and perhaps @griesemer specifically?

@griesemer griesemer self-assigned this Jan 30, 2024
@griesemer griesemer modified the milestones: Backlog, Go1.23 Jan 30, 2024
@griesemer
Copy link
Contributor

The type checker is happy with this code. Looks like a problem in the backend (backend type checker). Here's a simplified repro (playground), at tip:

package main

type Vector[V any] interface {
	ReadVector[V]
}

type ReadVector[V any] interface {
	Comparisons[ReadVector[V], Vector[V]]
}

type Comparisons[RV, V any] interface {
	Diff(RV) V
}

type VectorImpl[V any] struct{}

func (*VectorImpl[V]) Diff(ReadVector[V]) (_ Vector[V]) {
	return
}

func main() {
	var v1 VectorImpl[int]
	var v2 Vector[int]
	_ = v1.Diff(v2)
}

resulting in:

./prog.go:24:14: cannot use v2 (type ReadVector[int]) as type ReadVector[go.shape.int] in argument to (*VectorImpl[go.shape.int]).Diff:
	ReadVector[int] does not implement ReadVector[go.shape.int] (wrong type for Diff method)
		have Diff(ReadVector[int]) Vector[int]
		want Diff(ReadVector[go.shape.int]) go.shape.interface {}

@mdempsky, @randall77 any insights?

@griesemer griesemer removed their assignment Jan 30, 2024
@mdempsky mdempsky self-assigned this Jan 30, 2024
@mdempsky
Copy link
Member

The code looks reasonable, and I don't immediately see why it would be failing. I'd guess it's an error during runtime dictionary construction. (Cc @cuonglm because he's good at debugging these issues too.)

@cuonglm
Copy link
Member

cuonglm commented Jan 31, 2024

@mdempsky I think this is a bad interaction when shapifying recursive instantiated type argument ReadVector[go.shape.int] vs instantiated type argument Vector[go.shape.int].

Because ReadVector is recursive interface type, we end up shapifying the type argument as ReadVector[go.shape.int], while Vector[go.shape.int] is shapifying to its underlying type go.shape.interface {}, causing the mismatch in interface method signature.

Probably we should shapifying an interface type as-is if it is fully instantiated and already has shape?


types2 does not have this problem, because there's no shapifying there.

@gopherbot
Copy link

Change https://go.dev/cl/559656 mentions this issue: cmd/compile: fix recursive generic interface instantiation

@cuonglm cuonglm self-assigned this Feb 2, 2024
@cuonglm cuonglm added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Feb 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
generics Issue is related to generics NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

6 participants