diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 3f40a99b0744b..320e12d4d60c5 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -597,34 +597,43 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { if m, _ := obj.(*Func); m != nil { // check.dump("### found method %s", m) check.objDecl(m, nil) - // If m has a parameterized receiver type, infer the type parameter - // values from the actual receiver provided and then substitute the - // type parameters in the signature accordingly. + // If m has a parameterized receiver type, infer the type arguments + // from the actual receiver provided and then substitute the type + // parameters accordingly. // TODO(gri) factor this code out sig := m.typ.(*Signature) if len(sig.rparams) > 0 { - //check.dump("### recv typ = %s", x.typ) + // For inference to work, we must use the receiver type + // matching the receiver in the actual method declaration. + // If the method is embedded, the matching receiver is the + // embedded struct or interface that declared the method. + // Traverse the embedding to find that type (issue #44688). + recv := x.typ + for i := 0; i < len(index)-1; i++ { + // The embedded type is always a struct or a pointer to + // a struct except for the last one (which we don't need). + recv = asStruct(derefStructPtr(recv)).Field(index[i]).typ + } + //check.dump("### recv = %s", recv) //check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams) // The method may have a pointer receiver, but the actually provided receiver // may be a (hopefully addressable) non-pointer value, or vice versa. Here we // only care about inferring receiver type parameters; to make the inference // work, match up pointer-ness of receiver and argument. - arg := x - if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) { - copy := *arg + if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(recv) { if ptrRecv { - copy.typ = NewPointer(arg.typ) + recv = NewPointer(recv) } else { - copy.typ = arg.typ.(*Pointer).base + recv = recv.(*Pointer).base } - arg = © } - targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg}) + arg := operand{mode: variable, expr: x.expr, typ: recv} + targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{&arg}) //check.dump("### inferred targs = %s", targs) if failed >= 0 { // We may reach here if there were other errors (see issue #40056). // check.infer will report a follow-up error. - // TODO(gri) avoid the follow-up error or provide better explanation. + // TODO(gri) avoid the follow-up error as it is confusing (there's no inference in the source code) goto Error } // Don't modify m. Instead - for now - make a copy of m and use that instead. diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 new file mode 100644 index 0000000000000..512bfcc9223c8 --- /dev/null +++ b/src/cmd/compile/internal/types2/fixedbugs/issue44688.go2 @@ -0,0 +1,83 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package P + +type A1[T any] struct{} + +func (*A1[T]) m1(T) {} + +type A2[T any] interface { + m2(T) +} + +type B1[T any] struct { + filler int + *A1[T] + A2[T] +} + +type B2[T any] interface { + A2[T] +} + +type C[T any] struct { + filler1 int + filler2 int + B1[T] +} + +type D[T any] struct { + filler1 int + filler2 int + filler3 int + C[T] +} + +func _() { + // calling embedded methods + var b1 B1[string] + + b1.A1.m1("") + b1.m1("") + + b1.A2.m2("") + b1.m2("") + + var b2 B2[string] + b2.m2("") + + // a deeper nesting + var d D[string] + d.m1("") + d.m2("") + + // calling method expressions + m1x := B1[string].m1 + m1x(b1, "") + m2x := B2[string].m2 + m2x(b2, "") + + // calling method values + m1v := b1.m1 + m1v("") + m2v := b1.m2 + m2v("") + b2v := b2.m2 + b2v("") +} + +// actual test case from issue + +type A[T any] struct{} + +func (*A[T]) f(T) {} + +type B[T any] struct{ A[T] } + +func _() { + var b B[string] + b.A.f("") + b.f("") +} diff --git a/src/cmd/compile/internal/types2/selection.go b/src/cmd/compile/internal/types2/selection.go index 67d1aa7e1df61..02c0fc690252c 100644 --- a/src/cmd/compile/internal/types2/selection.go +++ b/src/cmd/compile/internal/types2/selection.go @@ -51,8 +51,8 @@ func (s *Selection) Kind() SelectionKind { return s.kind } // Recv returns the type of x in x.f. func (s *Selection) Recv() Type { return s.recv } -// Work-around for bug where a (*instance) shows up in a final type. -// TODO(gri): fix this bug. +// Work-around for a compiler issue where an (*instance) escapes. +// TODO(gri): Is this still needed? func (s *Selection) TArgs() []Type { r := s.recv if p := asPointer(r); p != nil {