From 35a4d1b3bc37b09d56cf045f845be1dfb282c44f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 23 Feb 2023 20:47:17 -0800 Subject: [PATCH] go/types, types2: simplify unification when x == y (pointer identity) Because we rename type parameters to avoid problems with self-recursive function calls, there's no need anymore for special (and hard to follow) logic for pointer-identical types. If they are identical, we have a match. Simplify the code accordingly. Change-Id: I2e1838a43e90fa4abfae3ab9e4f7da6463508966 Reviewed-on: https://go-review.googlesource.com/c/go/+/471018 Reviewed-by: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: Robert Findley Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/unify.go | 28 ++++++++++++------------ src/go/types/unify.go | 28 ++++++++++++------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 365767b2e8..7bd7493c7d 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -231,10 +231,6 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { return list } -func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool { - return x == y || u.nify(x, y, p) -} - // nify implements the core unification algorithm which is an // adapted version of Checker.identical. For changes to that // code the corresponding changes should be made here. @@ -251,6 +247,11 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { u.depth-- }() + // nothing to do if x == y + if x == y { + return true + } + // Stop gap for cases where unification fails. if u.depth > unificationDepthLimit { if traceInference { @@ -298,6 +299,10 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { // Per the spec, a defined type cannot have an underlying type // that is a type parameter. assert(!isTypeParam(y)) + // x and y may be identical now + if x == y { + return true + } } // Cases where at least one of x or y is a type parameter recorded with u. @@ -313,13 +318,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { return true } // both x and y have an inferred type - they must match - return u.nifyEq(u.at(px), u.at(py), p) + return u.nify(u.at(px), u.at(py), p) case px != nil: // x is a type parameter, y is not if x := u.at(px); x != nil { // x has an inferred type which must match y - if u.nifyEq(x, y, p) { + if u.nify(x, y, p) { // If we have a match, possibly through underlying types, // and y is a defined type, make sure we record that type // for type parameter x, which may have until now only @@ -377,10 +382,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } } - // For type unification, do not shortcut (x == y) for identical - // types. Instead keep comparing them element-wise to unify the - // matching (and equal type parameter types). A simple test case - // where this matters is: func f[P any](a P) { f(a) } . + // x != y if we reach here + assert(x != y) switch x := x.(type) { case *Basic: @@ -556,10 +559,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } case *TypeParam: - // Two type parameters (which are not part of the type parameters of the - // enclosing type as those are handled in the beginning of this function) - // are identical if they originate in the same declaration. - return x == y + // nothing to do - we know x != y case nil: // avoid a crash in case of nil type diff --git a/src/go/types/unify.go b/src/go/types/unify.go index dcbe26e42b..b41b7af96a 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -233,10 +233,6 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { return list } -func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool { - return x == y || u.nify(x, y, p) -} - // nify implements the core unification algorithm which is an // adapted version of Checker.identical. For changes to that // code the corresponding changes should be made here. @@ -253,6 +249,11 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { u.depth-- }() + // nothing to do if x == y + if x == y { + return true + } + // Stop gap for cases where unification fails. if u.depth > unificationDepthLimit { if traceInference { @@ -300,6 +301,10 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { // Per the spec, a defined type cannot have an underlying type // that is a type parameter. assert(!isTypeParam(y)) + // x and y may be identical now + if x == y { + return true + } } // Cases where at least one of x or y is a type parameter recorded with u. @@ -315,13 +320,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { return true } // both x and y have an inferred type - they must match - return u.nifyEq(u.at(px), u.at(py), p) + return u.nify(u.at(px), u.at(py), p) case px != nil: // x is a type parameter, y is not if x := u.at(px); x != nil { // x has an inferred type which must match y - if u.nifyEq(x, y, p) { + if u.nify(x, y, p) { // If we have a match, possibly through underlying types, // and y is a defined type, make sure we record that type // for type parameter x, which may have until now only @@ -379,10 +384,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } } - // For type unification, do not shortcut (x == y) for identical - // types. Instead keep comparing them element-wise to unify the - // matching (and equal type parameter types). A simple test case - // where this matters is: func f[P any](a P) { f(a) } . + // x != y if we reach here + assert(x != y) switch x := x.(type) { case *Basic: @@ -558,10 +561,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } case *TypeParam: - // Two type parameters (which are not part of the type parameters of the - // enclosing type as those are handled in the beginning of this function) - // are identical if they originate in the same declaration. - return x == y + // nothing to do - we know x != y case nil: // avoid a crash in case of nil type -- 2.50.0