]> Cypherpunks repositories - gostls13.git/commitdiff
spec: clarify context type for certain non-constant shifts
authorgriesemer <gri@golang.org>
Wed, 30 Aug 2017 13:10:12 +0000 (15:10 +0200)
committerRobert Griesemer <gri@golang.org>
Fri, 1 Sep 2017 15:46:24 +0000 (15:46 +0000)
The spec is not conclusive about whether a non-constant shift of
certain untyped constant left operands is valid when the shift
expression appears as an index in an index or slice expression,
or as a size in a `make` function call.

Despite identical spec rules in all these cases, cmd/compile accepts

make([]byte, 1.0 << s)

but pronounces an error for

a[1.0 << s]

(go/types accepts both).

This change clarifies the spec by explicitly stating that an
untyped constant left operand in a non-constant shift (1.0 in
the above examples) will be given type `int` in these contexts.

A separate issue #21693 addresses the cmd/compile bug.

Fixes #14844.

Change-Id: I4b52125e487a607fae377fcbed55463cdce9836c
Reviewed-on: https://go-review.googlesource.com/60230
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
doc/go_spec.html

index 80de0f45a6d20fb33e6b1bc36048211a6f45894f..ba0a4757460002265552f0a4793236b8257c9c5d 100644 (file)
@@ -1,6 +1,6 @@
 <!--{
        "Title": "The Go Programming Language Specification",
-       "Subtitle": "Version of August 30, 2017",
+       "Subtitle": "Version of September 1, 2017",
        "Path": "/ref/spec"
 }-->
 
@@ -2975,12 +2975,12 @@ The following rules apply:
 If <code>a</code> is not a map:
 </p>
 <ul>
-       <li>the index <code>x</code> must be of integer type or untyped;
-           it is <i>in range</i> if <code>0 &lt;= x &lt; len(a)</code>,
+       <li>the index <code>x</code> must be of integer type or an untyped constant</li>
+       <li>a constant index must be non-negative and
+           <a href="#Representability">representable</a> by a value of type <code>int</code></li>
+       <li>a constant index that is untyped is given type <code>int</code></li>
+       <li>the index <code>x</code> is <i>in range</i> if <code>0 &lt;= x &lt; len(a)</code>,
            otherwise it is <i>out of range</i></li>
-       <li>a <a href="#Constants">constant</a> index must be non-negative
-           and <a href="#Representability">representable</a> by a value
-           of type <code>int</code></li>
 </ul>
 
 <p>
@@ -3450,18 +3450,20 @@ replaced by its left operand alone.
 
 <pre>
 var s uint = 33
-var i = 1&lt;&lt;s           // 1 has type int
-var j int32 = 1&lt;&lt;s     // 1 has type int32; j == 0
-var k = uint64(1&lt;&lt;s)   // 1 has type uint64; k == 1&lt;&lt;33
-var m int = 1.0&lt;&lt;s     // 1.0 has type int; m == 0 if ints are 32bits in size
-var n = 1.0&lt;&lt;s == j    // 1.0 has type int32; n == true
-var o = 1&lt;&lt;s == 2&lt;&lt;s   // 1 and 2 have type int; o == true if ints are 32bits in size
-var p = 1&lt;&lt;s == 1&lt;&lt;33  // illegal if ints are 32bits in size: 1 has type int, but 1&lt;&lt;33 overflows int
-var u = 1.0&lt;&lt;s         // illegal: 1.0 has type float64, cannot shift
-var u1 = 1.0&lt;&lt;s != 0   // illegal: 1.0 has type float64, cannot shift
-var u2 = 1&lt;&lt;s != 1.0   // illegal: 1 has type float64, cannot shift
-var v float32 = 1&lt;&lt;s   // illegal: 1 has type float32, cannot shift
-var w int64 = 1.0&lt;&lt;33  // 1.0&lt;&lt;33 is a constant shift expression
+var i = 1&lt;&lt;s                  // 1 has type int
+var j int32 = 1&lt;&lt;s            // 1 has type int32; j == 0
+var k = uint64(1&lt;&lt;s)          // 1 has type uint64; k == 1&lt;&lt;33
+var m int = 1.0&lt;&lt;s            // 1.0 has type int; m == 0 if ints are 32bits in size
+var n = 1.0&lt;&lt;s == j           // 1.0 has type int32; n == true
+var o = 1&lt;&lt;s == 2&lt;&lt;s          // 1 and 2 have type int; o == true if ints are 32bits in size
+var p = 1&lt;&lt;s == 1&lt;&lt;33         // illegal if ints are 32bits in size: 1 has type int, but 1&lt;&lt;33 overflows int
+var u = 1.0&lt;&lt;s                // illegal: 1.0 has type float64, cannot shift
+var u1 = 1.0&lt;&lt;s != 0          // illegal: 1.0 has type float64, cannot shift
+var u2 = 1&lt;&lt;s != 1.0          // illegal: 1 has type float64, cannot shift
+var v float32 = 1&lt;&lt;s          // illegal: 1 has type float32, cannot shift
+var w int64 = 1.0&lt;&lt;33         // 1.0&lt;&lt;33 is a constant shift expression
+var x = a[1.0&lt;&lt;s]             // 1.0 has type int; x == a[0] if ints are 32bits in size
+var a = make([]byte, 1.0&lt;&lt;s)  // 1.0 has type int; len(a) == 0 if ints are 32bits in size
 </pre>
 
 
@@ -5724,9 +5726,10 @@ make(T, n)       channel    buffered channel of type T, buffer size n
 
 
 <p>
-The size arguments <code>n</code> and <code>m</code> must be of integer type or untyped.
-A <a href="#Constants">constant</a> size argument must be non-negative and
-<a href="#Representability">representable</a> by a value of type <code>int</code>.
+Each of the size arguments <code>n</code> and <code>m</code> must be of integer type
+or an untyped <a href="#Constants">constant</a>.
+A constant size argument must be non-negative and <a href="#Representability">representable</a>
+by a value of type <code>int</code>; if it is an untyped constant it is given type <code>int</code>.
 If both <code>n</code> and <code>m</code> are provided and are constant, then
 <code>n</code> must be no larger than <code>m</code>.
 If <code>n</code> is negative or larger than <code>m</code> at run time,