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"