Commit 9690d245 authored by griesemer's avatar griesemer Committed by Robert Griesemer

spec: clarify context type for certain non-constant shifts

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/60230Reviewed-by: default avatarRuss Cox <rsc@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent ec359643
<!--{
"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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment