From b40831b115e46e9de719bddccf2d27d7d4940756 Mon Sep 17 00:00:00 2001 From: griesemer Date: Mon, 21 Aug 2017 15:47:51 +0200 Subject: [PATCH] spec: explicitly define notion of "representability" (clarification) Throughout the spec we use the notion of a constant x being representable by a value of type T. While intuitively clear, at least for floating-point and complex constants types, the concept was not well-defined. In the section on Conversions there was an extra rule for floating-point types only and it missed the case of floating-point values overflowing to an infinity after rounding. Since the concept is important to Go, and a compiler most certainly will have a function to test "representability", it seems warranted to define the term explicitly in the spec. This change introduces a new entry "Representability" under the section on "Properties of types and values", and defines the term explicitly, together with examples. The phrase used is "representable by" rather than "representable as" because the former use is prevalent in the spec. Additionally, it clarifies that a floating-point constant that overflows to an infinity after rounding is never representable by a value of a floating-point type, even though infinities are valid values of IEEE floating point types. This is required because there are not infinite value constants in the language (like there is also no -0.0) and representability also matters for constant conversions. This is not a language change, and type-checkers have been following this rule before. The change also introduces links throughout the spec to the new section as appropriate and removes duplicate text and examples elsewhere (Constants and Conversions sections), leading to simplifications in the relevant paragraphs. Fixes #15389. Change-Id: I8be0e071552df0f18998ef4c5ef521f64ffe8c44 Reviewed-on: https://go-review.googlesource.com/57530 Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor Reviewed-by: Matthew Dempsky --- doc/go_spec.html | 117 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index a2ad56b4f9..74fccd7125 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -577,11 +577,7 @@ or conversion, or implicitly when used in a assignment or as an operand in an expression. It is an error if the constant value -cannot be represented as a value of the respective type. -For instance, 3.0 can be given any integer or any -floating-point type, while 2147483648.0 (equal to 1<<31) -can be given the types float32, float64, or uint32 but -not int32 or string. +cannot be represented as a value of the respective type.

@@ -861,7 +857,8 @@ ElementType = Type .

The length is part of the array's type; it must evaluate to a -non-negative constant representable by a value +non-negative constant +representable by a value of type int. The length of array a can be discovered using the built-in function len. @@ -1514,7 +1511,7 @@ are different because B0 is different from []string.

A value x is assignable to a variable of type T -("x is assignable to T") in any of these cases: +("x is assignable to T") if one of the following conditions applies:

    @@ -1540,12 +1537,68 @@ and at least one of V or T is not a defined type. is a pointer, function, slice, map, channel, or interface type.
  • -x is an untyped constant representable +x is an untyped constant +representable by a value of type T.
+

Representability

+ +

+A constant x is representable +by a value of type T if one of the following conditions applies: +

+ +
    +
  • +x is in the set of values determined by T. +
  • + +
  • +T is a floating-point type and x can be rounded to T's +precision without overflow. Rounding uses IEEE 754 round-to-even rules but with an IEEE +negative zero further simplified to an unsigned zero. Note that constant values never result +in an IEEE negative zero, NaN, or infinity. +
  • + +
  • +T is a complex type, and x's +components real(x) and imag(x) +are representable by values of T's component type (float32 or +float64). +
  • +
+ +
+x                   T           x is representable by a value of T because
+
+'a'                 byte        97 is in the set of byte values
+97                  rune        rune is an alias for int32, and 97 is in the set of 32-bit integers
+"foo"               string      "foo" is in the set of string values
+1024                int16       1024 is in the set of 16-bit integers
+42.0                byte        42 is in the set of unsigned 8-bit integers
+1e10                uint64      10000000000 is in the set of unsigned 64-bit integers
+2.718281828459045   float32     2.718281828459045 rounds to 2.7182817 which is in the set of float32 values
+-1e-1000            float64     -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0
+0i                  int         0 is an integer value
+(42 + 0i)           float32     42.0 (with zero imaginary part) is in the set of float32 values
+
+ +
+x                   T           x is not representable by a value of T because
+
+0                   bool        0 is not in the set of boolean values
+'a'                 string      'a' is a rune, it is not in the set of string values
+1024                byte        1024 is not in the set of unsigned 8-bit integers
+-1                  uint16      -1 is not in the set of unsigned 16-bit integers
+1.1                 int         1.1 is not an integer value
+42i                 float32     (0 + 42i) is not in the set of float32 values
+1e1000              float64     1e1000 overflows to IEEE +Inf after rounding
+
+ +

Blocks

@@ -2348,7 +2401,8 @@ For array and slice literals the following rules apply: its position in the array.

  • An element with a key uses the key as its index. The - key must be a non-negative constant representable by + key must be a non-negative constant + representable by a value of type int; and if it is typed it must be of integer type.
  • @@ -2925,7 +2979,8 @@ If a is not a map: it is in range if 0 <= x < len(a), otherwise it is out of range
  • a constant index must be non-negative - and representable by a value of type int + and representable by a value + of type int
  • @@ -3075,7 +3130,8 @@ For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length. -A constant index must be non-negative and representable by a value of type +A constant index must be non-negative and +representable by a value of type int; for arrays or constant strings, constant indices must also be in range. If both indices are constant, they must satisfy low <= high. If the indices are out of range at run time, a run-time panic occurs. @@ -3135,7 +3191,8 @@ If the sliced operand is an array, it must be addre

    The indices are in range if 0 <= low <= high <= max <= cap(a), otherwise they are out of range. -A constant index must be non-negative and representable by a value of type +A constant index must be non-negative and +representable by a value of type int; for arrays, constant indices must also be in range. If multiple indices are constant, the constants that are present must be in range relative to each other. @@ -3384,7 +3441,8 @@ to the type of the other operand.

    The right operand in a shift expression must have unsigned integer type -or be an untyped constant representable by a value of type uint. +or be an untyped constant representable by a +value of type uint. If the left operand of a non-constant shift expression is an untyped constant, it is first converted to the type it would assume if the shift expression were replaced by its left operand alone. @@ -3877,30 +3935,14 @@ func() int(x) // x is converted to func() int (unambiguous)

    A constant value x can be converted to -type T in any of these cases: +type T if x is representable +by a value of T. +As a special case, an integer constant x can be converted to a +string type using the +same rule +as for non-constant x.

    -
      -
    • - x is representable by a value of type T. -
    • -
    • - x is a floating-point constant, - T is a floating-point type, - and x is representable by a value - of type T after rounding using - IEEE 754 round-to-even rules, but with an IEEE -0.0 - further rounded to an unsigned 0.0. - The constant T(x) is the rounded value. -
    • -
    • - x is an integer constant and T is a - string type. - The same rule - as for non-constant x applies in this case. -
    • -
    -

    Converting a constant yields a typed constant as result.

    @@ -4187,7 +4229,8 @@ The divisor of a constant division or remainder operation must not be zero:

    -The values of typed constants must always be accurately representable as values +The values of typed constants must always be accurately +representable by values of the constant type. The following constant expressions are illegal:

    @@ -5683,7 +5726,7 @@ make(T, n) channel buffered channel of type T, buffer size n

    The size arguments n and m must be of integer type or untyped. A constant size argument must be non-negative and -representable by a value of type int. +representable by a value of type int. If both n and m are provided and are constant, then n must be no larger than m. If n is negative or larger than m at run time,