From 7b679617f3bb532fe65d8e83365b9f1f41b01b00 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 11 Feb 2021 11:54:46 -0500 Subject: [PATCH] [dev.typeparams] go/types: conversions to type parameters are not constant 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 Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check.go | 4 +++- src/go/types/examples/types.go2 | 17 +++++++++++++++++ src/go/types/predicates.go | 9 +++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/go/types/check.go b/src/go/types/check.go index 57c6a2e7b89..4cc3024de99 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -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} diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2 index 4dba4f0e57d..20abefbe05d 100644 --- a/src/go/types/examples/types.go2 +++ b/src/go/types/examples/types.go2 @@ -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) +} + diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 7a99c1ff997..0ff8fcbbf71 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -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 {