diff options
| author | Rob Findley <rfindley@anthropic.com> | 2026-04-12 21:21:36 +0000 |
|---|---|---|
| committer | Robert Findley <rfindley@anthropic.com> | 2026-04-13 15:16:46 -0700 |
| commit | 3d4ee07f7f1c6c4870677d9530e1c4bdef2c5e0a (patch) | |
| tree | 8f2defdd8d68c1fe3c05c13349a82248aec75196 | |
| parent | 356b87fa7bbba02debea59d2d03e1eca1750ccb6 (diff) | |
| download | go-3d4ee07f7f1c6c4870677d9530e1c4bdef2c5e0a.tar.xz | |
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 <gri@google.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
| -rw-r--r-- | src/cmd/compile/internal/types2/unify.go | 4 | ||||
| -rw-r--r-- | src/go/types/unify.go | 4 | ||||
| -rw-r--r-- | 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 |
