]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: clean up defined type identity check/unification
authorRobert Griesemer <gri@golang.org>
Wed, 8 Mar 2023 03:01:38 +0000 (19:01 -0800)
committerGopher Robot <gobot@golang.org>
Thu, 9 Mar 2023 20:32:29 +0000 (20:32 +0000)
Factor out check for identical origin.
Match unification code with type identity check.
Add a test case for #53692.

Change-Id: I1238b28297a5ac549e99261c8a085dd46f3dd65f
Reviewed-on: https://go-review.googlesource.com/c/go/+/474197
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Robert Griesemer <gri@google.com>

src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/unify.go
src/go/types/predicates.go
src/go/types/unify.go
src/internal/types/testdata/fixedbugs/issue53692.go [new file with mode: 0644]

index c92c1dc292cf6b39e1f0f04adb4d320310ae9ece..4f8441467e5c90cfba1fc27af1fd2945362f7a03 100644 (file)
@@ -433,33 +433,23 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
 
        case *Named:
                // Two named types are identical if their type names originate
-               // in the same type declaration.
+               // in the same type declaration; if they are instantiated they
+               // must have identical type argument lists.
                if y, ok := y.(*Named); ok {
+                       // check type arguments before origins to match unifier
+                       // (for correct source code we need to do all checks so
+                       // order doesn't matter)
                        xargs := x.TypeArgs().list()
                        yargs := y.TypeArgs().list()
-
                        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.Origin(), y.Origin()) {
+                       for i, xarg := range xargs {
+                               if !Identical(xarg, yargs[i]) {
                                        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.
-                       return x.obj == y.obj
+                       return indenticalOrigin(x, y)
                }
 
        case *TypeParam:
@@ -475,6 +465,12 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
        return false
 }
 
+// identicalOrigin reports whether x and y originated in the same declaration.
+func indenticalOrigin(x, y *Named) bool {
+       // TODO(gri) is this correct?
+       return x.Origin().obj == y.Origin().obj
+}
+
 // identicalInstance reports if two type instantiations are identical.
 // Instantiations are identical if their origin and type arguments are
 // identical.
index 23362bf76651b0da1073cb9f102e02d0df1aeaf3..a5ccc6eb41cdcc2b62ff53e48cf49acba1d2a6af 100644 (file)
@@ -506,26 +506,24 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                }
 
        case *Named:
-               // TODO(gri) This code differs now from the parallel code in Checker.identical. Investigate.
+               // Two named types are identical if their type names originate
+               // in the same type declaration; if they are instantiated they
+               // must have identical type argument lists.
                if y, ok := y.(*Named); ok {
+                       // check type arguments before origins so they unify
+                       // even if the origins don't match; for better error
+                       // messages (see go.dev/issue/53692)
                        xargs := x.TypeArgs().list()
                        yargs := y.TypeArgs().list()
-
                        if len(xargs) != len(yargs) {
                                return false
                        }
-
-                       // TODO(gri) This is not always correct: two types may have the same names
-                       //           in the same package if one of them is nested in a function.
-                       //           Extremely unlikely but we need an always correct solution.
-                       if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
-                               for i, x := range xargs {
-                                       if !u.nify(x, yargs[i], p) {
-                                               return false
-                                       }
+                       for i, xarg := range xargs {
+                               if !u.nify(xarg, yargs[i], p) {
+                                       return false
                                }
-                               return true
                        }
+                       return indenticalOrigin(x, y)
                }
 
        case *TypeParam:
index cf02a8cab536b819c5f2012604a62aba129fcda0..e09e774f2a74bca1764993e217cf61c04a0dcebc 100644 (file)
@@ -435,33 +435,23 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
 
        case *Named:
                // Two named types are identical if their type names originate
-               // in the same type declaration.
+               // in the same type declaration; if they are instantiated they
+               // must have identical type argument lists.
                if y, ok := y.(*Named); ok {
+                       // check type arguments before origins to match unifier
+                       // (for correct source code we need to do all checks so
+                       // order doesn't matter)
                        xargs := x.TypeArgs().list()
                        yargs := y.TypeArgs().list()
-
                        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.Origin(), y.Origin()) {
+                       for i, xarg := range xargs {
+                               if !Identical(xarg, yargs[i]) {
                                        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.
-                       return x.obj == y.obj
+                       return indenticalOrigin(x, y)
                }
 
        case *TypeParam:
@@ -477,6 +467,12 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
        return false
 }
 
+// identicalOrigin reports whether x and y originated in the same declaration.
+func indenticalOrigin(x, y *Named) bool {
+       // TODO(gri) is this correct?
+       return x.Origin().obj == y.Origin().obj
+}
+
 // identicalInstance reports if two type instantiations are identical.
 // Instantiations are identical if their origin and type arguments are
 // identical.
index 89af7745b43e73f11ca6a17b1f6e8b02f2dd6f9b..107e569380579a6b1a78c923bcc42ea748385e51 100644 (file)
@@ -508,26 +508,24 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
                }
 
        case *Named:
-               // TODO(gri) This code differs now from the parallel code in Checker.identical. Investigate.
+               // Two named types are identical if their type names originate
+               // in the same type declaration; if they are instantiated they
+               // must have identical type argument lists.
                if y, ok := y.(*Named); ok {
+                       // check type arguments before origins so they unify
+                       // even if the origins don't match; for better error
+                       // messages (see go.dev/issue/53692)
                        xargs := x.TypeArgs().list()
                        yargs := y.TypeArgs().list()
-
                        if len(xargs) != len(yargs) {
                                return false
                        }
-
-                       // TODO(gri) This is not always correct: two types may have the same names
-                       //           in the same package if one of them is nested in a function.
-                       //           Extremely unlikely but we need an always correct solution.
-                       if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
-                               for i, x := range xargs {
-                                       if !u.nify(x, yargs[i], p) {
-                                               return false
-                                       }
+                       for i, xarg := range xargs {
+                               if !u.nify(xarg, yargs[i], p) {
+                                       return false
                                }
-                               return true
                        }
+                       return indenticalOrigin(x, y)
                }
 
        case *TypeParam:
diff --git a/src/internal/types/testdata/fixedbugs/issue53692.go b/src/internal/types/testdata/fixedbugs/issue53692.go
new file mode 100644 (file)
index 0000000..a7bd572
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type Cache[K comparable, V any] interface{}
+
+type LRU[K comparable, V any] struct{}
+
+func WithLocking2[K comparable, V any](Cache[K, V]) {}
+
+func _() {
+       WithLocking2[string](LRU /* ERROR "type LRU[string, int] of LRU[string, int]{} does not match inferred type Cache[string, int] for Cache[string, V]" */ [string, int]{})
+}