go/types: fix numeric conversions between type parameter types

The implementation of conversions T(x) between integers and floating-point
numbers checks that both T and x have either integer or floating-point
type. When the type of T or x is a type parameter, the respective simple
predicate disjunction in the implementation was wrong because if a type list
contains both an integer and a floating-point type, the type parameter is
neither an integer or a floating-point number.

Change-Id: I007aa956007ab1a0228e0ee2fca05804686b404c
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/759562
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2020-06-01 22:49:28 -07:00
parent 716d51681b
commit 0fa4f81317
3 changed files with 21 additions and 1 deletions

View File

@ -104,7 +104,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
}
// "x's type and T are both integer or floating point types"
if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
return true
}

View File

@ -46,6 +46,12 @@ func isComplex(typ Type) bool { return is(typ, IsComplex) }
func isNumeric(typ Type) bool { return is(typ, IsNumeric) }
func isString(typ Type) bool { return is(typ, IsString) }
// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
// produce the expected result because a type list that contains both an integer
// and a floating-point type is neither (all) integers, nor (all) floats.
// Use isIntegerOrFloat instead.
func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
// isTyped reports whether typ is typed; i.e., not an untyped
// constant or boolean. isTyped may be called with types that
// are not fully set up.

View File

@ -232,3 +232,17 @@ type List3(type TElem) struct {
// Infinite generic type declarations must lead to an error.
type inf1(type T) struct{ _ inf1 /* ERROR illegal cycle */ (T) }
type inf2(type T) struct{ (inf2 /* ERROR illegal cycle */ (T)) }
// The implementation of conversions T(x) between integers and floating-point
// numbers checks that both T and x have either integer or floating-point
// type. When the type of T or x is a type parameter, the respective simple
// predicate disjunction in the implementation was wrong because if a type list
// contains both an integer and a floating-point type, the type parameter is
// neither an integer or a floating-point number.
func convert(type T1, T2 interface{type int, uint, float32})(v T1) T2 {
return T2(v)
}
func _() {
convert(int, uint)(5)
}