From 3d4ee07f7f1c6c4870677d9530e1c4bdef2c5e0a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Sun, 12 Apr 2026 21:21:36 +0000 Subject: go/types, types2: fail interface inference against generic methods When unifying an interface against a concrete type, interface inference looks up each interface method on the concrete type and unifies the signatures. If the concrete method is generic, the *Signature unify case (which ignores type parameter lists) would unify the method's own type parameter into the inference variable, leading to errors mentioning a leaked P and recording the wrong type in Info. A generic method never satisfies an interface method, so fail the unification at the lookup site instead. Change-Id: Id01eefcde492399cb94f4452f5627c4edbd22a1c Reviewed-on: https://go-review.googlesource.com/c/go/+/766160 Reviewed-by: Robert Griesemer Reviewed-by: Mark Freeman LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/cmd/compile/internal/types2/unify.go | 4 +++- src/go/types/unify.go | 4 +++- src/internal/types/testdata/spec/methods.go | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 7250d82478..9e90c5fc7d 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -534,10 +534,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // the non-interface type, otherwise unification fails. if xi != nil { // All xi methods must exist in y and corresponding signatures must unify. + // A generic method never satisfies an interface method, so fail rather + // than unify ym's own type parameter into an inference variable. xmethods := xi.typeSet().methods for _, xm := range xmethods { obj, _, _ := LookupFieldOrMethod(y, false, xm.pkg, xm.name) - if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, exact, p) { + if ym, _ := obj.(*Func); ym == nil || ym.Signature().TypeParams().Len() > 0 || !u.nify(xm.typ, ym.typ, exact, p) { return false } } diff --git a/src/go/types/unify.go b/src/go/types/unify.go index bf072c09d9..070f9d4482 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -537,10 +537,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // the non-interface type, otherwise unification fails. if xi != nil { // All xi methods must exist in y and corresponding signatures must unify. + // A generic method never satisfies an interface method, so fail rather + // than unify ym's own type parameter into an inference variable. xmethods := xi.typeSet().methods for _, xm := range xmethods { obj, _, _ := LookupFieldOrMethod(y, false, xm.pkg, xm.name) - if ym, _ := obj.(*Func); ym == nil || !u.nify(xm.typ, ym.typ, exact, p) { + if ym, _ := obj.(*Func); ym == nil || ym.Signature().TypeParams().Len() > 0 || !u.nify(xm.typ, ym.typ, exact, p) { return false } } diff --git a/src/internal/types/testdata/spec/methods.go b/src/internal/types/testdata/spec/methods.go index f7eeee5865..532910b1ab 100644 --- a/src/internal/types/testdata/spec/methods.go +++ b/src/internal/types/testdata/spec/methods.go @@ -77,6 +77,14 @@ func (V) m[_ any]() {} var _ J = V /* ERROR "wrong type for method m)\n\t\thave m[_ any]()\n\t\twant m()" */ {} +// In particular, interface inference must not unify a generic method's +// own type parameter into an inference variable. +func need[X any](I[X]) {} + +func _() { + need(T /* ERROR "type T of T{} does not match I[X] (cannot infer X)" */ {}) +} + // Test case from parser smoke test. type List[E any] []E -- cgit v1.3