Skip to content

Commit ad99d88

Browse files
committed
cmd/compile/internal/types2: avoid infinite expansion for invalid recursive generic types
The algorithm for detecting invalid recursive types that expand indefinitely suffered from the exact problem is was intended to detect: if the indefinite expansion is happening through type parameters, the algorithm ended up in an infinite sequence of instantiations. (This is only a problem for generic types). Changed the algorithm to always only consider the "original" uninstantiated types. This avoids the problem but it will also not detect some invalid recursive generic types anymore. That requires a more sophisticated type flow analysis. Opened #48962 to track. Addressed with help from @findleyr. For #48951. Change-Id: Ie29cea8f810dae55153dbb1b17c9390cd823c2d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/355732 Trust: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 24e798e commit ad99d88

File tree

5 files changed

+43
-11
lines changed

5 files changed

+43
-11
lines changed

src/cmd/compile/internal/types2/decl.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,16 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
330330
}
331331

332332
case *Named:
333-
t.resolve(check.conf.Context)
333+
// If t is parameterized, we should be considering the instantiated (expanded)
334+
// form of t, but in general we can't with this algorithm: if t is an invalid
335+
// type it may be so because it infinitely expands through a type parameter.
336+
// Instantiating such a type would lead to an infinite sequence of instantiations.
337+
// In general, we need "type flow analysis" to recognize those cases.
338+
// Example: type A[T any] struct{ x A[*T] } (issue #48951)
339+
// In this algorithm we always only consider the orginal, uninstantiated type.
340+
// This won't recognize some invalid cases with parameterized types, but it
341+
// will terminate.
342+
t = t.orig
334343

335344
// don't touch the type if it is from a different package or the Universe scope
336345
// (doing so would lead to a race condition - was issue #35049)
@@ -359,7 +368,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
359368
check.cycleError(path[i:])
360369
t.info = invalid
361370
t.underlying = Typ[Invalid]
362-
return t.info
371+
return invalid
363372
}
364373
}
365374
panic("cycle start not found")

src/cmd/compile/internal/types2/testdata/check/issues.go2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ type List3[TElem any] struct {
145145
}
146146

147147
// Infinite generic type declarations must lead to an error.
148-
type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
149-
type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
148+
type inf1 /* ERROR illegal cycle */ [T any] struct{ _ inf1[T] }
149+
type inf2 /* ERROR illegal cycle */ [T any] struct{ inf2[T] }
150150

151151
// The implementation of conversions T(x) between integers and floating-point
152152
// numbers checks that both T and x have either integer or floating-point

src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ func main7() { var _ foo7 = x7[int]{} }
3737
// func main8() {}
3838

3939
// crash 9
40-
type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] }
41-
func _() { var _ = new(foo9 /* ERROR illegal cycle */ [int]) }
40+
type foo9 /* ERROR illegal cycle */ [A any] interface { foo9[A] }
41+
func _() { var _ = new(foo9[int]) }
4242

4343
// crash 12
4444
var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len /* ERROR must be called */ /* ERROR must be called */ )]c /* ERROR undeclared */ /* ERROR undeclared */

src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// license that can be found in the LICENSE file.
44

55
// Check "infinite expansion" cycle errors across instantiated types.
6+
// We can't detect these errors anymore at the moment. See #48962 for
7+
// details.
68

79
package p
810

@@ -11,19 +13,19 @@ type E1[P any] *P
1113
type E2[P any] struct{ _ P }
1214
type E3[P any] struct{ _ *P }
1315

14-
type T0 /* ERROR illegal cycle */ struct {
16+
type T0 /* illegal cycle */ struct {
1517
_ E0[T0]
1618
}
1719

18-
type T0_ /* ERROR illegal cycle */ struct {
20+
type T0_ /* illegal cycle */ struct {
1921
E0[T0_]
2022
}
2123

2224
type T1 struct {
2325
_ E1[T1]
2426
}
2527

26-
type T2 /* ERROR illegal cycle */ struct {
28+
type T2 /* illegal cycle */ struct {
2729
_ E2[T2]
2830
}
2931

@@ -33,15 +35,15 @@ type T3 struct {
3335

3436
// some more complex cases
3537

36-
type T4 /* ERROR illegal cycle */ struct {
38+
type T4 /* illegal cycle */ struct {
3739
_ E0[E2[T4]]
3840
}
3941

4042
type T5 struct {
4143
_ E0[E2[E0[E1[E2[[10]T5]]]]]
4244
}
4345

44-
type T6 /* ERROR illegal cycle */ struct {
46+
type T6 /* illegal cycle */ struct {
4547
_ E0[[10]E2[E0[E2[E2[T6]]]]]
4648
}
4749

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
type (
8+
A1 /* ERROR illegal cycle */ [P any] [10]A1[P]
9+
A2 /* ERROR illegal cycle */ [P any] [10]A2[*P]
10+
A3[P any] [10]*A3[P]
11+
12+
L1[P any] []L1[P]
13+
14+
S1 /* ERROR illegal cycle */ [P any] struct{ f S1[P] }
15+
S2 /* ERROR illegal cycle */ [P any] struct{ f S2[*P] } // like example in issue
16+
S3[P any] struct{ f *S3[P] }
17+
18+
I1 /* ERROR illegal cycle */ [P any] interface{ I1[P] }
19+
I2 /* ERROR illegal cycle */ [P any] interface{ I2[*P] }
20+
I3[P any] interface{ *I3 /* ERROR interface contains type constraints */ [P] }
21+
)

0 commit comments

Comments
 (0)