From 56a919f17f660af192855c1f7e9ede4876fefe9c Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Mon, 16 Aug 2021 13:15:47 -0400 Subject: [PATCH] go/types: define Identical for instances This is a port of CL 341856 to go/types. It is adjusted to use the NumTArgs/TArg API of go/types, which has not yet been ported to types2. Change-Id: I6faeec027f4ae08634267001f473263703e80c5b Reviewed-on: https://go-review.googlesource.com/c/go/+/342478 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/go/types/api_test.go | 26 ++++++++++++++++++++++++++ src/go/types/predicates.go | 24 ++++++++++++++++++++++++ src/go/types/unify.go | 5 ----- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 52c9e5afe8..1631215d15 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -1861,3 +1861,29 @@ func TestInstantiate(t *testing.T) { t.Fatalf("unexpected result type: %s points to %s", res, p) } } + +func TestInstanceIdentity(t *testing.T) { + imports := make(testImporter) + conf := Config{Importer: imports} + makePkg := func(src string) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + name := f.Name.Name + pkg, err := conf.Check(name, fset, []*ast.File{f}, nil) + if err != nil { + t.Fatal(err) + } + imports[name] = pkg + } + makePkg(genericPkg + `lib; type T[P any] struct{}`) + makePkg(genericPkg + `a; import "generic_lib"; var A generic_lib.T[int]`) + makePkg(genericPkg + `b; import "generic_lib"; var B generic_lib.T[int]`) + a := imports["generic_a"].Scope().Lookup("A") + b := imports["generic_b"].Scope().Lookup("B") + if !Identical(a.Type(), b.Type()) { + t.Errorf("mismatching types: a.A: %s, b.B: %s", a.Type(), b.Type()) + } +} diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index bd9e53d2bb..0945dac722 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -304,6 +304,30 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Named); ok { x.expand(nil) y.expand(nil) + + // xargs := x.TArgs() + // yargs := y.TArgs() + + if x.NumTArgs() != y.NumTArgs() { + return false + } + + if nargs := x.NumTArgs(); nargs > 0 { + // Instances are identical if their original type and type arguments + // are identical. + if !Identical(x.orig, y.orig) { + return false + } + for i := 0; i < nargs; i++ { + xa := x.TArg(i) + ya := y.TArg(i) + if !Identical(xa, ya) { + return false + } + } + return true + } + // TODO(gri) Why is x == y not sufficient? And if it is, // we can just return false here because x == y // is caught in the very beginning of this function. diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 20cada2e69..de87466fe8 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -423,11 +423,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool { } case *Named: - // Two named types are identical if their type names originate - // in the same type declaration. - // if y, ok := y.(*Named); ok { - // return x.obj == y.obj - // } if y, ok := y.(*Named); ok { x.expand(nil) y.expand(nil) -- 2.50.0