go/types: implement Identical for *Union types

This aligns with the API proposal (#47916).

Change-Id: I732e5b107e729718ed37e053ad3f434993a97ecd
Reviewed-on: https://go-review.googlesource.com/c/go/+/349413
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Robert Findley 2021-09-12 14:33:04 -04:00
parent cb4e1de021
commit 0bb40b08c4
2 changed files with 51 additions and 0 deletions

View File

@ -1621,6 +1621,48 @@ func TestIdentical_issue15173(t *testing.T) {
}
}
func TestIdenticalUnions(t *testing.T) {
tname := NewTypeName(token.NoPos, nil, "myInt", nil)
myInt := NewNamed(tname, Typ[Int], nil)
tmap := map[string]*Term{
"int": NewTerm(false, Typ[Int]),
"~int": NewTerm(true, Typ[Int]),
"string": NewTerm(false, Typ[String]),
"~string": NewTerm(true, Typ[String]),
"myInt": NewTerm(false, myInt),
}
makeUnion := func(s string) *Union {
parts := strings.Split(s, "|")
var terms []*Term
for _, p := range parts {
term := tmap[p]
if term == nil {
t.Fatalf("missing term %q", p)
}
terms = append(terms, term)
}
return NewUnion(terms)
}
for _, test := range []struct {
x, y string
want bool
}{
// These tests are just sanity checks. The tests for type sets and
// interfaces provide much more test coverage.
{"int|~int", "~int", true},
{"myInt|~int", "~int", true},
{"int|string", "string|int", true},
{"int|int|string", "string|int", true},
{"myInt|string", "int|string", false},
} {
x := makeUnion(test.x)
y := makeUnion(test.y)
if got := Identical(x, y); got != test.want {
t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
}
}
}
func TestIssue15305(t *testing.T) {
const src = "package p; func f() int16; var _ = f(undef)"
fset := token.NewFileSet()

View File

@ -6,6 +6,8 @@
package types
import "go/token"
// isNamed reports whether typ has a name.
// isNamed may be called with types that are not fully set up.
func isNamed(typ Type) bool {
@ -225,6 +227,13 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
identical(x.results, y.results, cmpTags, p)
}
case *Union:
if y, _ := y.(*Union); y != nil {
xset := computeUnionTypeSet(nil, token.NoPos, x)
yset := computeUnionTypeSet(nil, token.NoPos, y)
return xset.terms.equal(yset.terms)
}
case *Interface:
// Two interface types are identical if they describe the same type sets.
// With the existing implementation restriction, this simplifies to: