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:
parent
269bdcd568
commit
7042ea62da
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
15
src/internal/types/testdata/fixedbugs/issue53692.go
vendored
Normal file
15
src/internal/types/testdata/fixedbugs/issue53692.go
vendored
Normal 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]{})
|
||||
}
|
Loading…
Reference in New Issue
Block a user