From 0bb40b08c4884952d7facce3135ff9e50847763f Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Sun, 12 Sep 2021 14:33:04 -0400 Subject: 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 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/api_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ src/go/types/predicates.go | 9 +++++++++ 2 files changed, 51 insertions(+) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 49c054bd7d..4472748685 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -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() diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 9aa565b68a..a5d4be9bcc 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -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: -- cgit v1.2.3-54-g00ecf