Skip to content

Commit 4bc831c

Browse files
committed
compiler: fix handling of struct, array and interface values.
As outlined in #661, the compiler fails to generate code to copy a struct/array value for an assignment when the target's underlying type is an interface type, whether for explicit variable assignments, implicit function/method parameters etc. Instead, taking the example of explicit variable assignment, the interface variable is assigned a value that contains the same pointer to the source struct/array val (we're in Javascript world, so everything is a pointer). This means that changes to the struct/array value via the source variable are, incorrectly, visible via the target variable. #661 gives a simple example. There is a further issue when interface values are assigned to interface-typed variables: struct/array values are not copied when they should be. Fixes #661.
1 parent 558a913 commit 4bc831c

File tree

3 files changed

+111
-4
lines changed

3 files changed

+111
-4
lines changed

compiler/expressions.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,11 @@ func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {
812812

813813
_, isPointer := recvType.Underlying().(*types.Pointer)
814814
methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type()
815+
816+
if _, isInterface := methodsRecvType.Underlying().(*types.Interface); isInterface {
817+
return c.formatExpr("$copyInterfaceVal(%e)", x)
818+
}
819+
815820
_, pointerExpected := methodsRecvType.(*types.Pointer)
816821
if !isPointer && pointerExpected {
817822
recvType = types.NewPointer(recvType)
@@ -825,6 +830,7 @@ func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {
825830
if isWrapped(recvType) {
826831
recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv)
827832
}
833+
828834
return recv
829835
}
830836

@@ -1130,12 +1136,17 @@ func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType typ
11301136
// wrap JS object into js.Object struct when converting to interface
11311137
return c.formatExpr("new $jsObjectPtr(%e)", expr)
11321138
}
1139+
1140+
switch exprType.Underlying().(type) {
1141+
case *types.Array:
1142+
return c.formatExpr("new %1s($clone(%e, %1s))", c.typeName(exprType), expr)
1143+
case *types.Struct:
1144+
return c.formatExpr("new %1e.constructor.elem($clone(%1e, %s))", expr, c.typeName(exprType))
1145+
}
1146+
11331147
if isWrapped(exprType) {
11341148
return c.formatExpr("new %s(%e)", c.typeName(exprType), expr)
11351149
}
1136-
if _, isStruct := exprType.Underlying().(*types.Struct); isStruct {
1137-
return c.formatExpr("new %1e.constructor.elem(%1e)", expr)
1138-
}
11391150
}
11401151

11411152
return c.translateExpr(expr)

0 commit comments

Comments
 (0)