Skip to content

Commit

Permalink
compiler: fix handling of struct, array and interface values.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
myitcv committed Apr 1, 2018
1 parent 82b3220 commit 7a694bb
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 4 deletions.
17 changes: 14 additions & 3 deletions compiler/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,11 @@ func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {

_, isPointer := recvType.Underlying().(*types.Pointer)
methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type()

if _, isInterface := methodsRecvType.Underlying().(*types.Interface); isInterface {
return c.formatExpr("$copyInterfaceVal(%e)", x)
}

_, pointerExpected := methodsRecvType.(*types.Pointer)
if !isPointer && pointerExpected {
recvType = types.NewPointer(recvType)
Expand All @@ -825,6 +830,7 @@ func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {
if isWrapped(recvType) {
recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv)
}

return recv
}

Expand Down Expand Up @@ -1130,12 +1136,17 @@ func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType typ
// wrap JS object into js.Object struct when converting to interface
return c.formatExpr("new $jsObjectPtr(%e)", expr)
}

switch exprType.Underlying().(type) {
case *types.Array:
return c.formatExpr("new %1s($clone(%e, %1s))", c.typeName(exprType), expr)
case *types.Struct:
return c.formatExpr("new %1e.constructor.elem($clone(%1e, %s))", expr, c.typeName(exprType))
}

if isWrapped(exprType) {
return c.formatExpr("new %s(%e)", c.typeName(exprType), expr)
}
if _, isStruct := exprType.Underlying().(*types.Struct); isStruct {
return c.formatExpr("new %1e.constructor.elem(%1e)", expr)
}
}

return c.translateExpr(expr)
Expand Down

0 comments on commit 7a694bb

Please sign in to comment.