Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: clarify assignability for non-constant untyped boolean values #15171

Open
momchil-velikov opened this issue Apr 7, 2016 · 1 comment

Comments

@momchil-velikov
Copy link
Contributor

commented Apr 7, 2016

Consider the initialization of c in the following example:

http://play.golang.org/p/iwCeX6lwkg

package main
var (
    a, b int
    c    bool = a > b
)
func main() {}

We have an untyped boolean value result of the comparison operator ("Comparison
operators compare two operands and yield an untyped boolean value.")

Regarding the declaration of c in the example, the specification says
(https://golang.org/ref/spec#Variable_declarations):

(1) If a list of expressions is given, the variables are initialized with the
expressions following the rule for assignments.
(2) Otherwise, each variable is initialized to its zero value.

(3) If a type is present, each variable is given that type.
(4) Otherwise, each variable is given the type of the corresponding
initialization value in the assignment. If that value is an untyped constant,
it is first converted to its default type; if it is an untyped boolean value,
it is first converted to type bool.

The example falls in the clauses (1) and (3). Clause (2) is not applicable,
because an initializer expression is given and (4) is not applicable, because a
type is present; in particular, the implicit conversion to bool in specified
by (4) does not take place.

Then, following (1) we consult the "rules for assignments"
(https://golang.org/ref/spec#Assignments)

In assignments, each value must be assignable to the type of the operand to
which it is assigned, with the following special cases:
(1) Any typed value may be assigned to the blank identifier.
(2) If an untyped constant is assigned to a variable of interface type or the
blank identifier, the constant is first converted to its default type.
(3) If an untyped boolean value is assigned to a variable of interface type or
the blank identifier, it is first converted to type bool.

The special case (1) is not applicable, because neither the assignments is to
the blank identifier, nor the assigned value is untyped.

The special case (2) is not applicable, because neither the assigned value is an
untyped constant (it's not a constant), nor it is assigned to a variable of an
interface type (the type is bool), nor to the blank identifier

The special case (3) is not applicable, because the untyped boolean value is not
assigned to a variable of an interface type, or the blank identifier.

Therefore, the initialization of c must be checked according to the
assignability criteria (https://golang.org/ref/spec#Assignability) :

A value x is assignable to a variable of type T ("x is assignable to T") in
any of these cases:
(1) x's type is identical to T.
(2) x's type V and T have identical underlying types and at least one of V or T is
not a named type.
(3) T is an interface type and x implements T.
(4) x is a bidirectional channel value, T is a channel type, x's type V and T have
identical element types, and at least one of V or T is not a named type.
(5) x is the predeclared identifier nil and T is a pointer, function, slice, map,
channel, or interface type.
(6) x is an untyped constant representable by a value of type T.

Clause (1) is not applicable because T is bool and the value is untyped
boolean.

Clause (2) is not applicable, because there is no way to derive an "underlying
type" (https://golang.org/ref/spec#Types) untyped boolean values.

Clause (3) is not applicable because bool is not an interface type.

Clause (4) is not applicable, because neither the expression's type, nor T is
a channel type.

Clause (5) it not applicable, because neither the expression if the nil, nor
T is one of the enumerated in the clause types.

Clause (6) is not applicable, because the expression is not an untyped constant.

In conclusion, I couldn't find a text the specification, which renders the above
example program as correct. Similar issues arise with initializations and
assignments involving the additional untyped boolean values, yielded by type
assertions, receive operators, or map index operators.

The compilers (go, gccgo and gotypes) all accept the example program.

It seems there's an omission in the specification. One possible way to fix it is
to add to the assignability criteria a clause, which specifies that an untyped
boolean value is assignable to T if the underlying type of T is bool.

@bradfitz bradfitz added this to the Unplanned milestone Apr 7, 2016

@griesemer

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2016

It may be sufficient to modify clause (6) (assignability) and replace constant with value.

Originally, untyped values were always constants. Untyped non-constant boolean values arrived later. We probably need to revisit the spec carefully in light of that.

Thanks for raising the point. Revisiting the spec carefully and clean up some of these open issues is on my list to do, but it's not urgent. We will get to it when we get to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.