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 type elision rules for composite literals #17954

Closed
griesemer opened this issue Nov 17, 2016 · 6 comments
Closed

spec: clarify type elision rules for composite literals #17954

griesemer opened this issue Nov 17, 2016 · 6 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@griesemer
Copy link
Contributor

griesemer commented Nov 17, 2016

Per the spec ( https://golang.org/ref/spec#Composite_literals ):

"Within a composite literal of array, slice, or map type T, elements or map keys that are themselves composite literals may elide the respective literal type if it is identical to the element or key type of T. Similarly, elements or keys that are addresses of composite literals may elide the &T when the element or key type is *T."

Given this paragraph, it's not obviously clear if the following code should be permitted:

type T *struct {
  s string
}

var _ = []T{
  { "foo" },
}

Here, the element type is a named type T that happens to be a *S. From the phrasing in the spec, it's not obvious whether the rule also applies in this case, or not (it doesn't explicitly say whether the underlying type is meant or not).

The gc and gccgo compilers accept the code above, go/types does not.

In contrast, the code below is also accepted by go/types (and clearly satisfies the spec rule).

var _ = []*struct {
  s string
}{
  { "foo" },
}
@griesemer griesemer added this to the Go1.8Maybe milestone Nov 17, 2016
@griesemer griesemer self-assigned this Nov 17, 2016
@rsc
Copy link
Contributor

rsc commented Nov 17, 2016

The two compilers agreeing suggests that this should (continue to) be accepted. Is there a test for this behavior that led to the compilers agreeing? If so, that would even more strongly push in that direction.

If past behavior does not determine the answer, then looking at the spec itself, there are many places in the spec that talk about 'a type T' meaning "your type here" and not meaning only named types. Otherwise there is no way to talk about "any type". The text quoted seems to be talking about arbitrary types, not only named types (it never mentions names), in which case the answer is that yes the example is OK. That is, if you think of the example as being a shortening of:

type X *struct {
  s string
}

var _ = []X{
  &struct{s string}{ "foo" },
}

(I changed the type name to avoid 'T'), then "elements ... that are addresses of composite literals may elide the &T when the element ... type is *T" seems to be satisfied. The element type X is *T for T = struct{s string}.

@quentinmit quentinmit added the NeedsFix The path to resolution is known, but the work has not been done. label Nov 17, 2016
@gopherbot
Copy link

CL https://golang.org/cl/33358 mentions this issue.

@griesemer griesemer assigned alandonovan and unassigned alandonovan Nov 17, 2016
@griesemer
Copy link
Contributor Author

I would like to agree with this (and I already have an easy fix for this for go/types: https://go-review.googlesource.com/33358). But it's not that simple. Given

type Point  struct{x, y int}
type PPoint *Point

this is valid

[]*Point{{1.5, -3.5}, {0, 0}}    // same as []*Point{&Point{1.5, -3.5}, &Point{0, 0}}

Note that &Point{...} creates a value of type *Point which is identical to the element type *Point of the composite literal type []*Point.

If we allow the same rule for PPoint, we arrive at

[]PPoint{{1.5, -3.5}, {0, 0}}    // "same" as []PPoint{&?{1.5, -3.5}, &?{0, 0}}

What should the type marked with ? be? The obvious choice seems Point as above, which would create an element of type *Point. However, *Point is not identical to the element type PPoint of the composite literal type []PPoint, only assignment-compatible.

More to the point (no pun intended), we can't actually write down the element type of PPoint: There's no way to write a type T such that &T is identical to PPoint. (Fundamentally, this goes all the way back to the rule that a type declaration introduces a new, and different, type.)

The spec says very clearly:

"Within a composite literal of array, slice, or map type T, elements or map keys that are themselves composite literals may elide the respective literal type if it is identical to the element or key type of T."

In this example, the element types are not identical. Thus, I argue that gc and gccgo are incorrect.

(We may not be able to change this at this point, but then the spec has to be adjusted.)

@ianlancetaylor
Copy link
Contributor

ianlancetaylor commented Nov 17, 2016

But the sentence you are quoting is not the relevant one. Here T is a meta-syntactic variable, and clearly the second clause does not apply--the type of the elements is not, and can not be, type PPoint. For a pointer type, it's the second sentence that governs: "Similarly, elements or keys that are addresses of composite literals may elide the &T when the element or key type is *T." Here the element type is *PPoint, so we are permitted to elide the &T. It is true that there is no T we could properly write there, but, good news! We can elide it. So at least so far I am with Russ in thinking that this is OK.

@griesemer
Copy link
Contributor Author

griesemer commented Nov 18, 2016

@ianlancetaylor Fair point, I quoted the wrong sentence. The element type is PPoint (rather than *PPoint as you said, though). I guess we could write PPoint(&Point{x, y}) and thus elide the PPoint(&Point ... ) part.

I still think we're a bit on shaky ground here, but we probably should just update the spec.

gopherbot pushed a commit that referenced this issue Nov 18, 2016
…ls with elided types

Match behavior of gc and gccgo.

For #17954.

Change-Id: I3f065e56d0a623bd7642c1438d0cab94d23fa2ae
Reviewed-on: https://go-review.googlesource.com/33358
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
@gopherbot
Copy link

CL https://golang.org/cl/33361 mentions this issue.

@golang golang locked and limited conversation to collaborators Nov 18, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

6 participants