From 50f4ebbdd30f53272b5f42ab66c50939eade0a0e Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 11 Aug 2021 11:45:11 -0400 Subject: [PATCH] cmd/compile/internal/types2: define Identical for instances Instantiation of parameterized types may occur in other packages, so we need an intrinsic notion of type identity for instances. Add the natural definition: two instances are identical if their bases and type arguments are identical. Type unification was already considering type arguments, but has some inaccurate logic with respect to objects. This will be addressed in a follow-up CL. Change-Id: Ib2ce67c05de65eb302ee588cc40c89c60018da50 Reviewed-on: https://go-review.googlesource.com/c/go/+/341856 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/api_test.go | 25 +++++++++++++++++++ src/cmd/compile/internal/types2/predicates.go | 22 ++++++++++++++++ src/cmd/compile/internal/types2/unify.go | 5 ---- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index dfa4de1175..be05d06fd0 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -1879,3 +1879,28 @@ 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) { + f, err := parseSrc("", src) + if err != nil { + t.Fatal(err) + } + name := f.PkgName.Value + pkg, err := conf.Check(name, []*syntax.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/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 070a0b3932..3c883e1ab5 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -304,6 +304,28 @@ 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 len(xargs) != len(yargs) { + return false + } + + if len(xargs) > 0 { + // Instances are identical if their original type and type arguments + // are identical. + if !Identical(x.orig, y.orig) { + return false + } + for i, xa := range xargs { + if !Identical(xa, yargs[i]) { + 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/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 28f9cf751c..710fc51b53 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -426,11 +426,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.48.1