go/types, types2: permit type cycles through type parameter lists

Issue #49439 was about a deadlock during type inference inside
a type parameter list of a recursive constraint. As a remedy
we disallowed recursive type parameter lists.

In the meantime we have removed support for type inference for
type arguments to generic types; the Go 1.18 generic release
didn't support it.

As a consequence, the fix for #49439, CL 361922, is probably
not needed anymore: cycles through type parameter lists are ok.

Fixes #68162.
For #49439.

Change-Id: Ie9deb3274914d428e8e45071cee5e68abf8afe9c
Reviewed-on: https://go-review.googlesource.com/c/go/+/711420
Commit-Queue: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Bypass: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2025-10-13 12:47:42 -07:00
parent 9fdd6904da
commit 1abc6b0204
14 changed files with 64 additions and 31 deletions

View file

@ -302,6 +302,12 @@ loop:
}
}
// Cycles through type parameter lists are ok (go.dev/issue/68162).
// TODO(gri) if we are happy with this this, remove this flag and simplify code.
if tparCycle {
return true
}
check.cycleError(cycle, firstInSrc(cycle))
return false
}

View file

@ -303,6 +303,12 @@ loop:
}
}
// Cycles through type parameter lists are ok (go.dev/issue/68162).
// TODO(gri) if we are happy with this this, remove this flag and simplify code.
if tparCycle {
return true
}
check.cycleError(cycle, firstInSrc(cycle))
return false
}

View file

@ -4,7 +4,7 @@
package p
type Builder /* ERROR "invalid recursive type" */ [T interface{ struct{ Builder[T] } }] struct{}
type Builder[T ~struct{ Builder[T] }] struct{}
type myBuilder struct {
Builder[myBuilder]
}

View file

@ -7,16 +7,16 @@
package p
// test case 1
type T /* ERROR "invalid recursive type" */ [U interface{ M() T[U] }] int
type T[U interface{ M() T[U] }] int
type X int
func (X) M() T[X] { return 0 }
// test case 2
type A /* ERROR "invalid recursive type" */ [T interface{ A[T] }] interface{}
type A[T interface{ A[T] }] interface{}
// test case 3
type A2 /* ERROR "invalid recursive type" */ [U interface{ A2[U] }] interface{ M() A2[U] }
type A2[U interface{ A2[U] }] interface{ M() A2[U] }
type I interface{ A2[I]; M() A2[I] }

View file

@ -7,17 +7,16 @@
package p
// test case 1
type T /* ERROR "invalid recursive type" */ [U interface{ M() T[U] }] int
type T[U interface{ M() T[U] }] int
type X int
func (X) M() T[X] { return 0 }
// test case 2
type A /* ERROR "invalid recursive type" */ [T interface{ A[T] }] interface{}
type A[T interface{ A[T] }] interface{}
// test case 3
// TODO(gri) should report error only once
type A2 /* ERROR "invalid recursive type" */ /* ERROR "invalid recursive type" */ [U interface{ A2[U] }] interface{ M() A2[U] }
type A2[U interface{ A2[U] }] interface{ M() A2[U] }
type I interface{ A2[I]; M() A2[I] }

View file

@ -6,16 +6,16 @@ package p
// parameterized types with self-recursive constraints
type (
T1 /* ERROR "invalid recursive type" */ [P T1[P]] interface{}
T2 /* ERROR "invalid recursive type" */ [P, Q T2[P, Q]] interface{}
T1[P T1[P]] interface{}
T2[P, Q T2[P, Q]] interface{}
T3[P T2[P, Q], Q interface{ ~string }] interface{}
T4a /* ERROR "invalid recursive type" */ [P T4a[P]] interface{ ~int }
T4b /* ERROR "invalid recursive type" */ [P T4b[int]] interface{ ~int }
T4c /* ERROR "invalid recursive type" */ [P T4c[string]] interface{ ~int }
T4a[P T4a[P]] interface{ ~int }
T4b[P T4b[int]] interface{ ~int }
T4c[P T4c[string /* ERROR "string does not satisfy T4c[string]" */]] interface{ ~int }
// mutually recursive constraints
T5 /* ERROR "invalid recursive type" */ [P T6[P]] interface{ int }
T5[P T6[P]] interface{ int }
T6[P T5[P]] interface{ int }
)
@ -28,6 +28,6 @@ var (
// test case from issue
type Eq /* ERROR "invalid recursive type" */ [a Eq[a]] interface {
type Eq[a Eq[a]] interface {
Equal(that a) bool
}

View file

@ -4,7 +4,7 @@
package p
type T /* ERROR "invalid recursive type" */ [U interface{ M() T[U, int] }] int
type T[U interface{ M() T /* ERROR "too many type arguments for type T" */ [U, int] }] int
type X int

View file

@ -6,21 +6,21 @@ package p
import "unsafe"
type T0 /* ERROR "invalid recursive type" */ [P T0[P]] struct{}
type T0[P T0[P]] struct{}
type T1 /* ERROR "invalid recursive type" */ [P T2[P]] struct{}
type T2[P T1[P]] struct{}
type T1[P T2[P /* ERROR "P does not satisfy T1[P]" */]] struct{}
type T2[P T1[P /* ERROR "P does not satisfy T2[P]" */]] struct{}
type T3 /* ERROR "invalid recursive type" */ [P interface{ ~struct{ f T3[int] } }] struct{}
type T3[P interface{ ~struct{ f T3[int /* ERROR "int does not satisfy" */ ] } }] struct{}
// valid cycle in M
type N[P M[P]] struct{}
type M[Q any] struct { F *M[Q] }
type M[Q any] struct{ F *M[Q] }
// "crazy" case
type TC[P [unsafe.Sizeof(func() {
type T [P [unsafe.Sizeof(func(){})]byte] struct{}
type T[P [unsafe.Sizeof(func() {})]byte] struct{}
})]byte] struct{}
// test case from issue
type X /* ERROR "invalid recursive type" */ [T any, PT X[T]] interface{}
type X[T any, PT X /* ERROR "not enough type arguments for type X" */ [T]] interface{}

View file

@ -0,0 +1,24 @@
// Copyright 2024 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 main
type N[B N[B]] interface {
Add(B) B
}
func Add[P N[P]](x, y P) P {
return x.Add(y)
}
type MyInt int
func (x MyInt) Add(y MyInt) MyInt {
return x + y
}
func main() {
var x, y MyInt = 2, 3
println(Add(x, y))
}

View file

@ -1,4 +1,4 @@
// errorcheck
// compile
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@ -6,7 +6,7 @@
package p
type T[U interface{ M() T[U] }] int // ERROR "invalid recursive type: T refers to itself"
type T[U interface{ M() T[U] }] int
type X int

View file

@ -4,4 +4,4 @@
package a
type T[U interface{ M() int }] int
type T[U interface{ M() T[U] }] int

View file

@ -8,6 +8,4 @@ import "./a"
type X int
func (X) M() int { return 0 }
type _ a.T[X]
func (X) M() a.T[X] { return 0 }

View file

@ -4,7 +4,7 @@
package a
type I[T any] interface {
type I[T I[T]] interface {
F() T
}

View file

@ -4,6 +4,6 @@
package a
type I[T any] interface {
type I[T I[T]] interface {
F() T
}