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: generic code behaves differently from non-generic code #59827

Open
go101 opened this issue Apr 25, 2023 · 6 comments
Open

cmd/compile: generic code behaves differently from non-generic code #59827

go101 opened this issue Apr 25, 2023 · 6 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@go101
Copy link

go101 commented Apr 25, 2023

What version of Go are you using (go version)?

$ go version
go version go1.20.3 linux/amd64

Does this issue reproduce with the latest release?

Yes

What did you do?

package main

type I interface {
	M(int)
	P()
}

type V int

func (v V) P()       { println(v) }
func (v *V) M(n int) { *v = V(n) }

type S struct{ *V }

func F[T I](x T) {
	defer x.P()
	x.M(9)
}

func G(x *S) {
	defer x.P()
	x.M(9)
}

func main() {
	{
		var s = S{V: new(V)}
		F(&s) // 9
	}
	{
		var s = S{V: new(V)}
		G(&s) // 0
	}
}

What did you expect to see?

Same behavior.

What did you see instead?

Different behavior.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Apr 25, 2023
@cuonglm
Copy link
Member

cuonglm commented Apr 25, 2023

It's not generic vs non-generic, but concrete type vs interface type. Change F to get in an interface, it also prints 9:

func F(x I) {
	defer x.P()
	x.M(9)
}

AFAICT, this behavior is right. According to the spec:

For a value x of type I where I is an interface type, x.f denotes the actual method with name f of the dynamic value of x.

@go101
Copy link
Author

go101 commented Apr 25, 2023

But &s is not an interface. That is the problem.

@ianlancetaylor
Copy link
Contributor

May be related to #52025.

CC @randall77 @mdempsky

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Apr 25, 2023
@dmitshur dmitshur added this to the Backlog milestone Apr 25, 2023
@go101
Copy link
Author

go101 commented Apr 26, 2023

@dmitshur I think this should be a new problem, instead of a backlog problem.

@mdempsky
Copy link
Member

As @cuonglm points out, the generic code using type parameters behaves the same as how interface calls work. Ack that this differs from how the same code would work when specialized to execute with a single, concrete type argument.

I think this is a spec ambiguity issue. The semantics around promoted methods, interface method calls, method values, and defer statements are still fuzzy, IMO.

@go101
Copy link
Author

go101 commented Apr 27, 2023

It looks this specified problem is more about the inconsistency between interface method value and non-interface method value evaluation:

package main

type I interface {M(int); P()}

type V int
func (v *V) M(n int) {*v = V(n)}
func (v V) P() {print(v)}

func F(x *V) {defer x.P(); x.M(7)}

func G[T I](x T) {defer x.P(); x.M(7)}

func H(x I) {defer x.P(); x.M(7)}

func main() {
	F(new(V)) // 0
	G(new(V)) // 7
	H(new(V)) // 7
}

It really breaks many people's expectations to view type parameters always as interfaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

6 participants