1
0
mirror of https://github.com/golang/go synced 2024-11-23 15:30:05 -07:00

go/types, types2: clean up defined type identity check/unification

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>
This commit is contained in:
Robert Griesemer 2023-03-07 19:01:38 -08:00 committed by Gopher Robot
parent 269bdcd568
commit 7042ea62da
5 changed files with 63 additions and 60 deletions

View 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.

View 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:

View 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.

View 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:

View File

@ -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]{})
}