diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go index c6ae9c5f03..73d24f7515 100644 --- a/src/go/types/conversions.go +++ b/src/go/types/conversions.go @@ -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 } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 311376df6e..f5d7001dfc 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -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. diff --git a/src/go/types/testdata/issues.go2 b/src/go/types/testdata/issues.go2 index eeeed730b2..31d1004da9 100644 --- a/src/go/types/testdata/issues.go2 +++ b/src/go/types/testdata/issues.go2 @@ -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) +} \ No newline at end of file