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/33358
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index e1d92ee..f76da17 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -1015,32 +1015,38 @@
}
case *ast.CompositeLit:
- typ := hint
- openArray := false
- if e.Type != nil {
+ var typ, base Type
+
+ switch {
+ case e.Type != nil:
+ // composite literal type present - use it
// [...]T array types may only appear with composite literals.
// 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 ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
// We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
- openArray = true
+ base = typ
+ break
}
}
- if typ == nil {
- typ = check.typ(e.Type)
- }
- }
- if typ == nil {
+ typ = check.typ(e.Type)
+ base = typ
+
+ case hint != 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
check.error(e.Pos(), "missing type in composite literal")
goto Error
}
- switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+ switch utyp := base.Underlying().(type) {
case *Struct:
if len(e.Elts) == 0 {
break
@@ -1109,7 +1115,7 @@
// 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
// not called for [...]).
- if openArray {
+ if utyp.len < 0 {
utyp.len = n
check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index 53c03e7..ab1a9f6 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -324,6 +324,22 @@
// recursively so
_ = [][]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
@@ -393,6 +409,14 @@
type Point struct { x, y float32 }
_ = map[string]Point{"orig": {0, 0}}
_ = 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"