]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] go/types: conversions to type parameters are not constant
authorRob Findley <rfindley@google.com>
Thu, 11 Feb 2021 16:54:46 +0000 (11:54 -0500)
committerRobert Findley <rfindley@google.com>
Thu, 18 Feb 2021 14:58:11 +0000 (14:58 +0000)
This is a port of CL 290471 to go/types. However, this change preserves
the existing check for constant types in recordTypeAndValue, which uses
is(..., isConstType) rather than the isConstType predicate. In types2,
this code path is not hit with type parameters because convertUntyped
walks the type list in order before calling updateExprType with the type
parameter, at which point the expression type would have already been
recorded as the first element of the type list -- probably something
that should be corrected.

Longer term, I believe we actually could allow const type parameters if
the optype is a sum of constant types.

Change-Id: Iaa91ffa740b5f08a5696bd96918a866bffd7aef6
Reviewed-on: https://go-review.googlesource.com/c/go/+/291323
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/check.go
src/go/types/examples/types.go2
src/go/types/predicates.go

index 57c6a2e7b89ff059a31acccf2fc64dee5540ec6c..4cc3024de990713ed6c3d10abddbecb1732e214e 100644 (file)
@@ -340,7 +340,9 @@ func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type,
        }
        if mode == constant_ {
                assert(val != nil)
-               assert(typ == Typ[Invalid] || isConstType(typ))
+               // We check is(typ, IsConstType) here as constant expressions may be
+               // recorded as type parameters.
+               assert(typ == Typ[Invalid] || is(typ, IsConstType))
        }
        if m := check.Types; m != nil {
                m[x] = TypeAndValue{mode, typ, val}
index 4dba4f0e57d3161eb7a3b50919da9db9d499ac17..20abefbe05d646ac1387b6edd0f066ed507a8045 100644 (file)
@@ -267,3 +267,20 @@ func _() {
        var _ comparable /* ERROR comparable */
        var _ C /* ERROR comparable */
 }
+
+// Type parameters are never const types, i.e., it's
+// not possible to declare a constant of type parameter type.
+// (If a type list contains just a single const type, we could
+// allow it, but such type lists don't make much sense in the
+// first place.)
+func _[T interface { type int, float64 }]() {
+       // not valid
+       const _ = T /* ERROR not constant */ (0)
+       const _ T /* ERROR invalid constant type T */ = 1
+
+       // valid
+       var _ = T(0)
+       var _ T = 1
+       _ = T(0)
+}
+
index 7a99c1ff99750b5288ea3cb1cb9752b41a50eca2..0ff8fcbbf71ddf0a12f22b42d439c9bd87b507f7 100644 (file)
@@ -73,8 +73,13 @@ func isUntyped(typ Type) bool {
        return !isTyped(typ)
 }
 
-func isOrdered(typ Type) bool   { return is(typ, IsOrdered) }
-func isConstType(typ Type) bool { return is(typ, IsConstType) }
+func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
+
+func isConstType(typ Type) bool {
+       // Type parameters are never const types.
+       t, _ := under(typ).(*Basic)
+       return t != nil && t.info&IsConstType != 0
+}
 
 // IsInterface reports whether typ is an interface type.
 func IsInterface(typ Type) bool {