It is not a bug. The spec says
<https://golang.org/ref/spec#Constant_expressions>:

If the left operand of a *constant *shift expression is an untyped
> constant, the result is an integer constant; otherwise it is a constant of
> the same type as the left operand, which must be of integer type.



Any other operation on untyped constants results in an untyped constant of
> the same kind


(emphasis mine). Given that a is not a constant, 1<<a is not a constant
shift expression. Therefore, it's "any other operation" and is given a type
from context. The way this happens is described in Operators
<https://golang.org/ref/spec#Operators>:

The right operand in a shift expression must have integer type 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
> implicitly converted to the type it would assume if the shift expression
> were replaced by its left operand alone.


Therefore, the untyped constant 1 in float64(1<<a) is given the type it
would assume in float64(1). I don't think it is surprising, that that type
is float64. Though arguably, there is a difference between "float64(1) is a
float64 constant" and "the 1 in float64(1) is given the type float64".

There's the section on conversions <https://golang.org/ref/spec#Conversions>,
which says:

A constant value x can be converted to type T if x is representable by a
> value of T.


That seems to read as "1 stays an untyped constant and is then converted".
On the other hand, the section on constants
<https://golang.org/ref/spec#Constants> says:

A constant may be given a type explicitly by a constant declaration or
> conversion, […]


This says that the untyped constant is given a type, which seems to imply
that "1 is given the type float64 by the conversion".

So, it can be argued that the spec is insufficiently clear here.
Personally, I tend to think that the behavior is reasonably clear - at
least the part where float64(1) gives 1 the type float64. We generally
accept that an untyped constant is given the type of the context it appears
in. So it does take a while to chase down why it behaves this way, but it's
in the spec.

But either way: If anything, this is a bug in the spec, not a bug in the
implementation. At this point (more than ten years after Go 1), if
something requires as subtle a reading of the spec as this, it's the
implementation that is right, unless implementations disagree.

On Thu, Jun 3, 2021 at 11:21 AM Brian Candler <b.cand...@pobox.com> wrote:

> Weird.  It simplifies to this: https://play.golang.org/p/OsOhRMC6kBu
>
> On Thursday, 3 June 2021 at 10:08:22 UTC+1 Jamil Djadala wrote:
>
>>
>> https://groups.google.com/g/golang-nuts
>>
>> package main
>>
>> import (
>>     "fmt"
>> )
>>
>> func main() {
>>     const aa int = 0
>>     var a int
>>     fmt.Println(float64(1<<aa), a)
>>     fmt.Println(float64(1<<a), a) // ./prog.go:11:21: invalid operation:
>> 1 << a (shift of type float64)
>> }
>> ./prog.go:11:21: invalid operation: 1 << a (shift of type float64)
>>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/87ee9f5f-6db2-48e8-86cc-de0b88511a65n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/87ee9f5f-6db2-48e8-86cc-de0b88511a65n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHs_0BXEHbUGhnZ8bcKyQU-iQ%2BaoL5SA9%2BDtiFju2%2Bxbw%40mail.gmail.com.

Reply via email to