golang / go

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

cmd/compile: generics with method values not working #45817

Closed randall77 closed 3 years ago

randall77 commented 3 years ago
package main

type s[T any] struct {
    a T
}
func (x s[T]) f() T {
    return x.a
}
func main() {
    x := s[int]{a:7}
    f := x.f
    f()
}
% ../bin/go run -gcflags=-G=3 ~/gowork/tmp6.go
# command-line-arguments
../../../gowork/tmp6.go:11:4: cannot use s[int].f (type func(s[int]) int) as type func() int in assignment

This should work, I think. It looks like it got the type of f correct, which means := worked. But then later it decided the RHS was a different type...

I think this might be happening during stenciling. Beforehand, the RHS of the assignment is

.   .   .   FUNCINST tc(1) FUNC-func() int # tmp6.go:11 FUNC-func() int
.   .   .   .   CALLPART tc(1) FUNC-method(s[T₂]) func() T₂ # tmp6.go:11 main.s[T₂].f FUNC-method(s[T₂]) func() T₂
.   .   .   .   .   NAME-main.x tc(1) Class:PAUTO Offset:0 OnStack main.s[int] # tmp6.go:10

afterward, the RHS is

.   .   .   NAME-main.s[int].f tc(1) Class:PFUNC Offset:0 FUNC-func(s[int]) int # tmp6.go:6

The former looks superficially ok, but I'm not entirely sure as I don't really understand what method types are. The latter definitely looks like a problem.

Adding -l to the command line makes the compiler crash :(

@griesemer @findleyr @mdempsky @danscales

mdempsky commented 3 years ago

Method types are just function types with the receiver parameter still in place. As far as expression typing goes, you can generally just ignore the receiver part: method(A) func(B) C is identical to func(B) C within the Go type system.

Off hand, I think they only show up in ODOTMETH, ODOTINTER, and OCALLPART. But even there, we could probably change them to use the bare function signatures if desirable. (We used to rely on these nodes referencing the exact *types.Type of the function, so we could get back to the corresponding *ir.Name/*ir.Func. But that's no longer necessary since we added ir.SelectorExpr.Selection.)

Method expressions will instead have a new type like func(B, C) anyway.

danscales commented 3 years ago

Thanks for the example. Method values are definitely an untested area. I think I already have another example of method values not working when I tried an adjusted version of ./cmd/compile/internal/types2/fixedbugs/issue44688.go2.

FYI, the other big areas that are not handled correctly yet related to generic functions/types are: embedded fields & interfaces and type aliases.

I eventually plan to go through all of ./cmd/compile/internal/types2/fixedbugs, but it will be easier once we have basic export/import working.

gopherbot commented 3 years ago

Change https://golang.org/cl/318089 mentions this issue: cmd/compile: fix use of method values with stenciled methods

gopherbot commented 3 years ago

Change https://golang.org/cl/319589 mentions this issue: cmd/compile: fix use of method values with stenciled methods

danscales commented 3 years ago

Fixed by https://golang.org/cl/319589. I guess the issue wasn't closed automatically, because the CL was checked in on dev.typeparams? But I think we can close this issue, since we're doing all the testing/dev on dev.typeparams.