From: Robert Griesemer Date: Tue, 28 Feb 2023 17:43:36 +0000 (-0800) Subject: go/types, types2: handle unbound type parameters in switch (cleanup) X-Git-Tag: go1.21rc1~1399 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=052a36ccbe698b5f2be9ac097fc2403428f200d5;p=gostls13.git go/types, types2: handle unbound type parameters in switch (cleanup) This simply moves the special handling for unbound type parameters into the switch (which already looks for type parameters). Change-Id: I2d6d22f3fdffc443065c3681a442288cd1d375ef Reviewed-on: https://go-review.googlesource.com/c/go/+/472115 TryBot-Result: Gopher Robot Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 7bd7493c7d..23362bf766 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -341,50 +341,20 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { return true } + // x != y if we get here + assert(x != y) + // If we get here and x or y is a type parameter, they are unbound // (not recorded with the unifier). - // By definition, a valid type argument must be in the type set of - // the respective type constraint. Therefore, the type argument's - // underlying type must be in the set of underlying types of that - // constraint. If there is a single such underlying type, it's the - // constraint's core type. It must match the type argument's under- - // lying type, irrespective of whether the actual type argument, - // which may be a defined type, is actually in the type set (that - // will be determined at instantiation time). - // Thus, if we have the core type of an unbound type parameter, - // we know the structure of the possible types satisfying such - // parameters. Use that core type for further unification - // (see go.dev/issue/50755 for a test case). - if enableCoreTypeUnification { - // swap x and y as needed - // (the earlier swap checks for _recorded_ type parameters only) - if isTypeParam(y) { - if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) - } - x, y = y, x - } - if isTypeParam(x) { - // When considering the type parameter for unification - // we look at the core type. - // Because the core type is always an underlying type, - // unification will take care of matching against a - // defined or literal type automatically. - // If y is also an unbound type parameter, we will end - // up here again with x and y swapped, so we don't - // need to take care of that case separately. - if cx := coreType(x); cx != nil { - if traceInference { - u.tracef("core %s ≡ %s", x, y) - } - return u.nify(cx, y, p) - } + // Ensure that if we have at least one type parameter, it is in x + // (the earlier swap checks for _recorded_ type parameters only). + if isTypeParam(y) { + if traceInference { + u.tracef("%s ≡ %s (swap)", y, x) } + x, y = y, x } - // x != y if we reach here - assert(x != y) - switch x := x.(type) { case *Basic: // Basic types are singletons except for the rune and byte @@ -559,7 +529,37 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } case *TypeParam: - // nothing to do - we know x != y + // x must be an unbound type parameter (see comment above). + if debug { + assert(u.asTypeParam(x) == nil) + } + // By definition, a valid type argument must be in the type set of + // the respective type constraint. Therefore, the type argument's + // underlying type must be in the set of underlying types of that + // constraint. If there is a single such underlying type, it's the + // constraint's core type. It must match the type argument's under- + // lying type, irrespective of whether the actual type argument, + // which may be a defined type, is actually in the type set (that + // will be determined at instantiation time). + // Thus, if we have the core type of an unbound type parameter, + // we know the structure of the possible types satisfying such + // parameters. Use that core type for further unification + // (see go.dev/issue/50755 for a test case). + if enableCoreTypeUnification { + // Because the core type is always an underlying type, + // unification will take care of matching against a + // defined or literal type automatically. + // If y is also an unbound type parameter, we will end + // up here again with x and y swapped, so we don't + // need to take care of that case separately. + if cx := coreType(x); cx != nil { + if traceInference { + u.tracef("core %s ≡ %s", x, y) + } + return u.nify(cx, y, p) + } + } + // x != y and there's nothing to do 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 b41b7af96a..89af7745b4 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -343,50 +343,20 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { return true } + // x != y if we get here + assert(x != y) + // If we get here and x or y is a type parameter, they are unbound // (not recorded with the unifier). - // By definition, a valid type argument must be in the type set of - // the respective type constraint. Therefore, the type argument's - // underlying type must be in the set of underlying types of that - // constraint. If there is a single such underlying type, it's the - // constraint's core type. It must match the type argument's under- - // lying type, irrespective of whether the actual type argument, - // which may be a defined type, is actually in the type set (that - // will be determined at instantiation time). - // Thus, if we have the core type of an unbound type parameter, - // we know the structure of the possible types satisfying such - // parameters. Use that core type for further unification - // (see go.dev/issue/50755 for a test case). - if enableCoreTypeUnification { - // swap x and y as needed - // (the earlier swap checks for _recorded_ type parameters only) - if isTypeParam(y) { - if traceInference { - u.tracef("%s ≡ %s (swap)", y, x) - } - x, y = y, x - } - if isTypeParam(x) { - // When considering the type parameter for unification - // we look at the core type. - // Because the core type is always an underlying type, - // unification will take care of matching against a - // defined or literal type automatically. - // If y is also an unbound type parameter, we will end - // up here again with x and y swapped, so we don't - // need to take care of that case separately. - if cx := coreType(x); cx != nil { - if traceInference { - u.tracef("core %s ≡ %s", x, y) - } - return u.nify(cx, y, p) - } + // Ensure that if we have at least one type parameter, it is in x + // (the earlier swap checks for _recorded_ type parameters only). + if isTypeParam(y) { + if traceInference { + u.tracef("%s ≡ %s (swap)", y, x) } + x, y = y, x } - // x != y if we reach here - assert(x != y) - switch x := x.(type) { case *Basic: // Basic types are singletons except for the rune and byte @@ -561,7 +531,37 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) { } case *TypeParam: - // nothing to do - we know x != y + // x must be an unbound type parameter (see comment above). + if debug { + assert(u.asTypeParam(x) == nil) + } + // By definition, a valid type argument must be in the type set of + // the respective type constraint. Therefore, the type argument's + // underlying type must be in the set of underlying types of that + // constraint. If there is a single such underlying type, it's the + // constraint's core type. It must match the type argument's under- + // lying type, irrespective of whether the actual type argument, + // which may be a defined type, is actually in the type set (that + // will be determined at instantiation time). + // Thus, if we have the core type of an unbound type parameter, + // we know the structure of the possible types satisfying such + // parameters. Use that core type for further unification + // (see go.dev/issue/50755 for a test case). + if enableCoreTypeUnification { + // Because the core type is always an underlying type, + // unification will take care of matching against a + // defined or literal type automatically. + // If y is also an unbound type parameter, we will end + // up here again with x and y swapped, so we don't + // need to take care of that case separately. + if cx := coreType(x); cx != nil { + if traceInference { + u.tracef("core %s ≡ %s", x, y) + } + return u.nify(cx, y, p) + } + } + // x != y and there's nothing to do case nil: // avoid a crash in case of nil type