Skip to content

Commit

Permalink
go/types, types2: clean up defined type identity check/unification
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Auto-Submit: Robert Griesemer <[email protected]>
  • Loading branch information
griesemer authored and gopherbot committed Mar 9, 2023
1 parent 269bdcd commit 7042ea6
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 60 deletions.
32 changes: 14 additions & 18 deletions src/cmd/compile/internal/types2/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand Down
22 changes: 10 additions & 12 deletions src/cmd/compile/internal/types2/unify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
32 changes: 14 additions & 18 deletions src/go/types/predicates.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 10 additions & 12 deletions src/go/types/unify.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/internal/types/testdata/fixedbugs/issue53692.go
Original file line number Diff line number Diff line change
@@ -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]{})
}

0 comments on commit 7042ea6

Please sign in to comment.