Skip to content

Commit da2f549

Browse files
committed
Propsed fix for struct and array vals in interface-typed variables
1 parent 2b1d432 commit da2f549

File tree

4 files changed

+107
-3
lines changed

4 files changed

+107
-3
lines changed

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ test:
1818
- go tool vet *.go # Go package in root directory.
1919
- for d in */; do echo $d; done | grep -v tests/ | grep -v third_party/ | xargs go tool vet # All subdirectories except "tests", "third_party".
2020
- >
21-
gopherjs test --short --minify
21+
gopherjs test --minify
2222
github.com/gopherjs/gopherjs/tests
2323
github.com/gopherjs/gopherjs/tests/main
2424
github.com/gopherjs/gopherjs/js

compiler/expressions.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,12 @@ func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType typ
11131113

11141114
exprType := c.p.TypeOf(expr)
11151115
if types.Identical(exprType, desiredType) {
1116-
return c.translateExpr(expr)
1116+
switch exprType.Underlying().(type) {
1117+
case *types.Interface:
1118+
return c.formatExpr("$copyIntf(%e)", expr)
1119+
default:
1120+
return c.translateExpr(expr)
1121+
}
11171122
}
11181123

11191124
basicExprType, isBasicExpr := exprType.Underlying().(*types.Basic)
@@ -1130,11 +1135,14 @@ func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType typ
11301135
// wrap JS object into js.Object struct when converting to interface
11311136
return c.formatExpr("new $jsObjectPtr(%e)", expr)
11321137
}
1138+
if _, isArray := exprType.Underlying().(*types.Array); isArray {
1139+
return c.formatExpr("new %1s($clone(%e, %1s))", c.typeName(exprType), expr)
1140+
}
11331141
if isWrapped(exprType) {
11341142
return c.formatExpr("new %s(%e)", c.typeName(exprType), expr)
11351143
}
11361144
if _, isStruct := exprType.Underlying().(*types.Struct); isStruct {
1137-
return c.formatExpr("new %1e.constructor.elem(%1e)", expr)
1145+
return c.formatExpr("new %1e.constructor.elem($clone(%1e, %s))", expr, c.typeName(exprType))
11381146
}
11391147
}
11401148

compiler/prelude/prelude.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ var $clone = function(src, type) {
293293
return clone;
294294
};
295295
296+
var $copyIntf = function(src) {
297+
if (src.constructor.copy) {
298+
return new src.constructor($clone(src.$val, src.constructor));
299+
}
300+
301+
return src;
302+
};
303+
296304
var $pointerOfStructConversion = function(obj, type) {
297305
if(obj.$proxies === undefined) {
298306
obj.$proxies = {};

tests/interface_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package tests
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type Struct struct {
9+
Name string
10+
}
11+
12+
func (s Struct) SetName(n string) {
13+
s.Name = n
14+
}
15+
16+
type SetName interface {
17+
SetName(n string)
18+
}
19+
20+
func TestAssignStructValInterface(t *testing.T) {
21+
s := Struct{
22+
Name: "Rob",
23+
}
24+
25+
var i1 interface{} = s
26+
var i2 interface{} = i1
27+
28+
s.Name = "Pike"
29+
30+
ss := fmt.Sprintf("%#v", s)
31+
i1s := fmt.Sprintf("%#v", i1)
32+
i2s := fmt.Sprintf("%#v", i2)
33+
34+
if exp := "tests.Struct{Name:\"Pike\"}"; ss != exp {
35+
t.Fatalf("ss should have been %q; got %q", exp, ss)
36+
}
37+
38+
iexp := "tests.Struct{Name:\"Rob\"}"
39+
40+
if i1s != iexp {
41+
t.Fatalf("is should have been %q; got %q", iexp, i1s)
42+
}
43+
44+
if i2s != iexp {
45+
t.Fatalf("is should have been %q; got %q", iexp, i2s)
46+
}
47+
}
48+
49+
func TestStructValIntfMethodCall(t *testing.T) {
50+
var i SetName = Struct{
51+
Name: "Rob",
52+
}
53+
54+
i.SetName("Pike")
55+
56+
is := fmt.Sprintf("%#v", i)
57+
58+
if exp := "tests.Struct{Name:\"Rob\"}"; is != exp {
59+
t.Fatalf("is should have been %q; got %q", exp, is)
60+
}
61+
}
62+
63+
func TestAssignArrayInterface(t *testing.T) {
64+
a := [2]int{1, 2}
65+
66+
var i1 interface{} = a
67+
var i2 interface{} = i1
68+
69+
a[0] = 0
70+
71+
as := fmt.Sprintf("%#v", a)
72+
i1s := fmt.Sprintf("%#v", i1)
73+
i2s := fmt.Sprintf("%#v", i2)
74+
75+
if exp := "[2]int{0, 2}"; as != exp {
76+
t.Fatalf("ss should have been %q; got %q", exp, as)
77+
}
78+
79+
iexp := "[2]int{1, 2}"
80+
81+
if i1s != iexp {
82+
t.Fatalf("is should have been %q; got %q", iexp, i1s)
83+
}
84+
85+
if i2s != iexp {
86+
t.Fatalf("is should have been %q; got %q", iexp, i2s)
87+
}
88+
}

0 commit comments

Comments
 (0)