Skip to content

Commit aa25f6c

Browse files
authored
Merge pull request gopherjs#1208 from nevkontakte/composite-lit
Fix compiler panic when handling composite literals representing named pointer types.
2 parents c3dcfaf + 6e3de82 commit aa25f6c

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

Diff for: compiler/expressions.go

+29-3
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,34 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
100100

101101
switch e := expr.(type) {
102102
case *ast.CompositeLit:
103-
if ptrType, isPointer := exprType.(*types.Pointer); isPointer {
104-
exprType = ptrType.Elem()
103+
if ptrType, isPointer := exprType.Underlying().(*types.Pointer); isPointer {
104+
// Go automatically treats `[]*T{{}}` as `[]*T{&T{}}`, in which case the
105+
// inner composite literal `{}` would has a pointer type. To make sure the
106+
// type conversion is handled correctly, we generate the explicit AST for
107+
// this.
108+
var rewritten ast.Expr = fc.setType(&ast.UnaryExpr{
109+
OpPos: e.Pos(),
110+
Op: token.AND,
111+
X: fc.setType(&ast.CompositeLit{
112+
Elts: e.Elts,
113+
}, ptrType.Elem()),
114+
}, ptrType)
115+
116+
if exprType, ok := exprType.(*types.Named); ok {
117+
// Handle a special case when the pointer type is named, e.g.:
118+
// type PS *S
119+
// _ = []PS{{}}
120+
// In that case the value corresponding to the inner literal `{}` is
121+
// initialized as `&S{}` and then converted to `PS`: `[]PS{PS(&S{})}`.
122+
typeCast := fc.setType(&ast.CallExpr{
123+
Fun: fc.newTypeIdent(exprType.String(), exprType.Obj()),
124+
Lparen: e.Lbrace,
125+
Args: []ast.Expr{rewritten},
126+
Rparen: e.Rbrace,
127+
}, exprType)
128+
rewritten = typeCast
129+
}
130+
return fc.translateExpr(rewritten)
105131
}
106132

107133
collectIndexedElements := func(elementType types.Type) []string {
@@ -173,7 +199,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
173199
}
174200
return fc.formatExpr("new %s.ptr(%s)", fc.typeName(exprType), strings.Join(elements, ", "))
175201
default:
176-
panic(fmt.Sprintf("Unhandled CompositeLit type: %T\n", t))
202+
panic(fmt.Sprintf("Unhandled CompositeLit type: %[1]T %[1]v\n", t))
177203
}
178204

179205
case *ast.FuncLit:

Diff for: compiler/utils.go

+6
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ func (fc *funcContext) newIdent(name string, t types.Type) *ast.Ident {
282282
return ident
283283
}
284284

285+
func (fc *funcContext) newTypeIdent(name string, obj types.Object) *ast.Ident {
286+
ident := ast.NewIdent(name)
287+
fc.pkgCtx.Info.Uses[ident] = obj
288+
return ident
289+
}
290+
285291
func (fc *funcContext) setType(e ast.Expr, t types.Type) ast.Expr {
286292
fc.pkgCtx.Types[e] = types.TypeAndValue{Type: t}
287293
return e

Diff for: tests/misc_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -920,3 +920,18 @@ func TestAssignImplicitConversion(t *testing.T) {
920920
}
921921
})
922922
}
923+
924+
func TestCompositeLiterals(t *testing.T) {
925+
type S struct{}
926+
type SP *S
927+
928+
s1 := []*S{{}}
929+
if got := reflect.TypeOf(s1[0]); got.String() != "*tests.S" {
930+
t.Errorf("Got: reflect.TypeOf(s1[0]) = %v. Want: *tests.S", got)
931+
}
932+
933+
s2 := []SP{{}}
934+
if got := reflect.TypeOf(s2[0]); got.String() != "tests.SP" {
935+
t.Errorf("Got: reflect.TypeOf(s2[0]) = %v. Want: tests.SP", got)
936+
}
937+
}

0 commit comments

Comments
 (0)