Skip to content

Commit 6cf535a

Browse files
committed
[dev.go2go] go/types: avoid endless recursion when computing operational types
The operational type for a type parameter T constrained by interface { type T } is the top type, not itself. The latter can lead to infinite recursions. Fix suggested by @tdakkota. Fixes #39680. Change-Id: I8a6a6c503f09294b9276965f1d9e05c5d22ec912 Reviewed-on: https://go-review.googlesource.com/c/go/+/238863 Reviewed-by: Robert Griesemer <[email protected]>
1 parent b302b5f commit 6cf535a

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

src/go/types/check_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ var tests = [][]string{
127127
// Should just traverse that directory.
128128
{"fixedbugs/issue39664.go2"},
129129
{"fixedbugs/issue39693.go2"},
130+
{"fixedbugs/issue39680.go2"},
130131
}
131132

132133
var fset = token.NewFileSet()

src/go/types/fixedbugs/issue39680.go2

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
import "fmt"
8+
9+
// Minimal test case.
10+
func _(type T interface{type T})(x T) T{
11+
return x
12+
}
13+
14+
// Test case from issue.
15+
type constr(type T) interface {
16+
type T
17+
}
18+
19+
func Print(type T constr(T))(s []T) {
20+
for _, v := range s {
21+
fmt.Print(v)
22+
}
23+
}
24+
25+
func f() {
26+
Print([]string{"Hello, ", "playground\n"})
27+
}

src/go/types/type.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,10 +839,17 @@ func (t *TypeParam) Bound() *Interface {
839839
// as the underlying type (as returned by Under). For
840840
// Type parameters, the operational type is determined
841841
// by the corresponding type bound's type list. The
842-
// result may be the bottom or top type.
842+
// result may be the bottom or top type, but it is never
843+
// the incoming type parameter.
843844
func optype(typ Type) Type {
844845
if t := typ.TypeParam(); t != nil {
845-
if u := t.Bound().allTypes; u != nil {
846+
// If the optype is typ, return the top type as we have
847+
// no information. It also prevents infinite recursion
848+
// via the TypeParam converter methods. This can happen
849+
// for a type parameter list of the form:
850+
// (type T interface { type T }).
851+
// See also issue #39680.
852+
if u := t.Bound().allTypes; u != nil && u != typ {
846853
return u
847854
}
848855
return theTop

0 commit comments

Comments
 (0)