mirror of
https://github.com/golang/go
synced 2024-11-26 04:17:59 -07:00
go/types: avoid endless recursion in the Comparable predicate
This is a port of CL 276374 from the dev.typeparams branch. Avoid an endless recursion in Comparable by tracking types that have already been considered. Fixes #43088 Change-Id: I927b29ac544df9bfb5c8c04699d57fafe6cfff73 Reviewed-on: https://go-review.googlesource.com/c/go/+/276552 Run-TryBot: Robert Findley <rfindley@google.com> Trust: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
f1980efb92
commit
89f465c2b5
@ -12,6 +12,7 @@ import (
|
|||||||
"go/ast"
|
"go/ast"
|
||||||
"go/importer"
|
"go/importer"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -523,3 +524,28 @@ func TestIssue34921(t *testing.T) {
|
|||||||
pkg = res // res is imported by the next package in this test
|
pkg = res // res is imported by the next package in this test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue43088(t *testing.T) {
|
||||||
|
// type T1 struct {
|
||||||
|
// _ T2
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// type T2 struct {
|
||||||
|
// _ struct {
|
||||||
|
// _ T2
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
n1 := NewTypeName(token.NoPos, nil, "T1", nil)
|
||||||
|
T1 := NewNamed(n1, nil, nil)
|
||||||
|
n2 := NewTypeName(token.NoPos, nil, "T2", nil)
|
||||||
|
T2 := NewNamed(n2, nil, nil)
|
||||||
|
s1 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
|
||||||
|
T1.SetUnderlying(s1)
|
||||||
|
s2 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
|
||||||
|
s3 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", s2, false)}, nil)
|
||||||
|
T2.SetUnderlying(s3)
|
||||||
|
|
||||||
|
// These calls must terminate (no endless recursion).
|
||||||
|
Comparable(T1)
|
||||||
|
Comparable(T2)
|
||||||
|
}
|
||||||
|
@ -79,6 +79,18 @@ func IsInterface(typ Type) bool {
|
|||||||
|
|
||||||
// Comparable reports whether values of type T are comparable.
|
// Comparable reports whether values of type T are comparable.
|
||||||
func Comparable(T Type) bool {
|
func Comparable(T Type) bool {
|
||||||
|
return comparable(T, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparable(T Type, seen map[Type]bool) bool {
|
||||||
|
if seen[T] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if seen == nil {
|
||||||
|
seen = make(map[Type]bool)
|
||||||
|
}
|
||||||
|
seen[T] = true
|
||||||
|
|
||||||
switch t := T.Underlying().(type) {
|
switch t := T.Underlying().(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
// assume invalid types to be comparable
|
// assume invalid types to be comparable
|
||||||
@ -88,13 +100,13 @@ func Comparable(T Type) bool {
|
|||||||
return true
|
return true
|
||||||
case *Struct:
|
case *Struct:
|
||||||
for _, f := range t.fields {
|
for _, f := range t.fields {
|
||||||
if !Comparable(f.typ) {
|
if !comparable(f.typ, seen) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case *Array:
|
case *Array:
|
||||||
return Comparable(t.elem)
|
return comparable(t.elem, seen)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user