func (check *Checker) conversion(x *operand, T Type) {
constArg := x.mode == constant_
- var ok bool
- var cause string
- switch {
- case constArg && isConstType(T):
- // constant conversion (T cannot be a type parameter)
+ constConvertibleTo := func(T Type, val *constant.Value) bool {
switch t := asBasic(T); {
- case representableConst(x.val, check, t, &x.val):
- ok = true
+ case t == nil:
+ // nothing to do
+ case representableConst(x.val, check, t, val):
+ return true
case isInteger(x.typ) && isString(t):
codepoint := unicode.ReplacementChar
if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
codepoint = rune(i)
}
- x.val = constant.MakeString(string(codepoint))
- ok = true
+ if val != nil {
+ *val = constant.MakeString(string(codepoint))
+ }
+ return true
}
+ return false
+ }
+
+ var ok bool
+ var cause string
+ switch {
+ case constArg && isConstType(T):
+ // constant conversion
+ ok = constConvertibleTo(T, &x.val)
+ case constArg && isTypeParam(T):
+ // x is convertible to T if it is convertible
+ // to each specific type in the type set of T.
+ // If T's type set is empty, or if it doesn't
+ // have specific types, constant x cannot be
+ // converted.
+ ok = under(T).(*TypeParam).underIs(func(u Type) bool {
+ // t is nil if there are no specific type terms
+ // TODO(gri) add a cause in case of failure
+ return u != nil && constConvertibleTo(u, nil)
+ })
+ x.mode = value // type parameters are not constants
case x.convertibleTo(check, T, &cause):
// non-constant conversion
- x.mode = value
ok = true
+ x.mode = value
}
if !ok {
return nil, nil, _InvalidUntypedConversion
}
case *TypeParam:
+ // TODO(gri) review this code - doesn't look quite right
ok := t.underIs(func(t Type) bool {
target, _, _ := check.implicitTypeAndValue(x, t)
return target != nil
return asInterface(typ) != nil
}
+// isTypeParam reports whether typ is a type parameter.
+func isTypeParam(typ Type) bool {
+ _, ok := under(typ).(*TypeParam)
+ return ok
+}
+
// Comparable reports whether values of type T are comparable.
func Comparable(T Type) bool {
return comparable(T, nil)
--- /dev/null
+// Copyright 2021 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 integer interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+func Add1024[T integer](s []T) {
+ for i, v := range s {
+ s[i] = v + 1024 // ERROR cannot convert 1024 \(untyped int constant\) to T
+ }
+}
+
+func f[T interface{ int8 }]() {
+ println(T(1024 /* ERROR cannot convert 1024 \(untyped int value\) to T */))
+}
--- /dev/null
+// Copyright 2021 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
+
+func _[
+ T0 any,
+ T1 []int,
+ T2 ~float64 | ~complex128 | chan int,
+]() {
+ // TODO(rfindley): the types2 error here is clearer.
+ _ = T0(nil /* ERROR cannot convert nil \(untyped nil value\) to T0 */ )
+ _ = T1(1 /* ERROR cannot convert 1 .* to T1 */ )
+ _ = T2(2 /* ERROR cannot convert 2 .* to T2 */ )
+}
+
+// test case from issue
+func f[T interface{[]int}]() {
+ _ = T(1 /* ERROR cannot convert */ )
+}
import "unsafe"
+// constant conversions
+
+func _[T ~byte]() T { return 255 }
+func _[T ~byte]() T { return 256 /* ERROR cannot use 256 .* as T value */ }
+
+func _[T ~byte]() {
+ const _ = T /* ERROR T\(0\) .* is not constant */ (0)
+ var _ T = 255
+ var _ T = 256 // ERROR cannot use 256 .* as T value
+}
+
+func _[T ~string]() T { return T('a') }
+func _[T ~int | ~string]() T { return T('a') }
+func _[T ~byte | ~int | ~string]() T { return T(256 /* ERROR cannot convert 256 .* to T */ ) }
+
+// implicit conversions never convert to string
+func _[T ~string]() {
+ var _ string = 0 // ERROR cannot use .* as string value
+ var _ T = 0 // ERROR cannot use .* as T value
+}
+
// "x is assignable to T"
// - tested via assignability tests