Commit e54662dc authored by Robert Griesemer's avatar Robert Griesemer

go/types: look at underlying type of element type of composite literals with elided types

Match behavior of gc and gccgo.

For #17954.

Change-Id: I3f065e56d0a623bd7642c1438d0cab94d23fa2ae
Reviewed-on: https://go-review.googlesource.com/33358Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent b21743c6
...@@ -1015,32 +1015,38 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { ...@@ -1015,32 +1015,38 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
} }
case *ast.CompositeLit: case *ast.CompositeLit:
typ := hint var typ, base Type
openArray := false
if e.Type != nil { switch {
case e.Type != nil:
// composite literal type present - use it
// [...]T array types may only appear with composite literals. // [...]T array types may only appear with composite literals.
// Check for them here so we don't have to handle ... in general. // Check for them here so we don't have to handle ... in general.
typ = nil
if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil { if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil { if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
// We have an "open" [...]T array type. // We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1) // Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal. // and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elem: check.typ(atyp.Elt)} typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
openArray = true base = typ
break
} }
} }
if typ == nil { typ = check.typ(e.Type)
typ = check.typ(e.Type) base = typ
}
} case hint != nil:
if typ == nil { // no composite literal type present - use hint (element type of enclosing type)
typ = hint
base, _ = deref(typ.Underlying()) // *T implies &T{}
default:
// TODO(gri) provide better error messages depending on context // TODO(gri) provide better error messages depending on context
check.error(e.Pos(), "missing type in composite literal") check.error(e.Pos(), "missing type in composite literal")
goto Error goto Error
} }
switch typ, _ := deref(typ); utyp := typ.Underlying().(type) { switch utyp := base.Underlying().(type) {
case *Struct: case *Struct:
if len(e.Elts) == 0 { if len(e.Elts) == 0 {
break break
...@@ -1109,7 +1115,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { ...@@ -1109,7 +1115,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// If we have an "open" [...]T array, set the length now that we know it // If we have an "open" [...]T array, set the length now that we know it
// and record the type for [...] (usually done by check.typExpr which is // and record the type for [...] (usually done by check.typExpr which is
// not called for [...]). // not called for [...]).
if openArray { if utyp.len < 0 {
utyp.len = n utyp.len = n
check.recordTypeAndValue(e.Type, typexpr, utyp, nil) check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
} }
......
...@@ -324,6 +324,22 @@ func slice_literals() { ...@@ -324,6 +324,22 @@ func slice_literals() {
// recursively so // recursively so
_ = [][]T{{}, []T{{}}, {{1, 2, 3}}} _ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
// issue 17954
type T0 *struct { s string }
_ = []T0{{}}
_ = []T0{{"foo"}}
type T1 *struct{ int }
_ = []T1{}
_ = []T1{{0}, {1}, {2}}
type T2 T1
_ = []T2{}
_ = []T2{{0}, {1}, {2}}
_ = map[T0]T2{}
_ = map[T0]T2{{}: {}}
} }
const index2 int = 2 const index2 int = 2
...@@ -393,6 +409,14 @@ func map_literals() { ...@@ -393,6 +409,14 @@ func map_literals() {
type Point struct { x, y float32 } type Point struct { x, y float32 }
_ = map[string]Point{"orig": {0, 0}} _ = map[string]Point{"orig": {0, 0}}
_ = map[*Point]string{{0, 0}: "orig"} _ = map[*Point]string{{0, 0}: "orig"}
// issue 17954
type T0 *struct{ s string }
type T1 *struct{ int }
type T2 T1
_ = map[T0]T2{}
_ = map[T0]T2{{}: {}}
} }
var key2 string = "bar" var key2 string = "bar"
......
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