aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Findley <rfindley@anthropic.com>2026-04-12 21:21:36 +0000
committerRobert Findley <rfindley@anthropic.com>2026-04-13 15:16:46 -0700
commit3d4ee07f7f1c6c4870677d9530e1c4bdef2c5e0a (patch)
tree8f2defdd8d68c1fe3c05c13349a82248aec75196
parent356b87fa7bbba02debea59d2d03e1eca1750ccb6 (diff)
downloadgo-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.go4
-rw-r--r--src/go/types/unify.go4
-rw-r--r--src/internal/types/testdata/spec/methods.go8
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