Skip to content

Commit 73df10d

Browse files
committed
Support builtin make() for type parameters.
Slice, channel and map types' constructors now have a .make() method that implements the builtin for the corresponding type. The compiler simply calls the builtin without a need to introspect the type.
1 parent 29a46a5 commit 73df10d

File tree

3 files changed

+99
-19
lines changed

3 files changed

+99
-19
lines changed

compiler/expressions.go

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,26 +1049,16 @@ func (fc *funcContext) translateBuiltin(name string, sig *types.Signature, args
10491049
return fc.formatExpr("$newDataPointer(%e, %s)", fc.zeroValue(t.Elem()), fc.typeName(t))
10501050
}
10511051
case "make":
1052-
switch argType := fc.pkgCtx.TypeOf(args[0]).Underlying().(type) {
1053-
case *types.Slice:
1054-
t := fc.typeName(fc.pkgCtx.TypeOf(args[0]))
1055-
if len(args) == 3 {
1056-
return fc.formatExpr("$makeSlice(%s, %f, %f)", t, args[1], args[2])
1057-
}
1058-
return fc.formatExpr("$makeSlice(%s, %f)", t, args[1])
1059-
case *types.Map:
1060-
if len(args) == 2 && fc.pkgCtx.Types[args[1]].Value == nil {
1061-
return fc.formatExpr(`((%1f < 0 || %1f > 2147483647) ? $throwRuntimeError("makemap: size out of range") : new $global.Map())`, args[1])
1062-
}
1063-
return fc.formatExpr("new $global.Map()")
1064-
case *types.Chan:
1065-
length := "0"
1066-
if len(args) == 2 {
1067-
length = fc.formatExpr("%f", args[1]).String()
1068-
}
1069-
return fc.formatExpr("new $Chan(%s, %s)", fc.typeName(fc.pkgCtx.TypeOf(args[0]).Underlying().(*types.Chan).Elem()), length)
1052+
typeName := fc.typeName(fc.pkgCtx.TypeOf(args[0]))
1053+
switch len(args) {
1054+
case 1:
1055+
return fc.formatExpr("%s.$make()", typeName)
1056+
case 2:
1057+
return fc.formatExpr("%s.$make(%f)", typeName, args[1])
1058+
case 3:
1059+
return fc.formatExpr("%s.$make(%f, %f)", typeName, args[1], args[2])
10701060
default:
1071-
panic(fmt.Sprintf("Unhandled make type: %T\n", argType))
1061+
panic(fmt.Errorf("builtin make(): invalid number of arguments: %d", len(args)))
10721062
}
10731063
case "len":
10741064
switch argType := fc.pkgCtx.TypeOf(args[0]).Underlying().(type) {

compiler/prelude/types.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
175175
typ.sendOnly = sendOnly;
176176
typ.recvOnly = recvOnly;
177177
};
178+
typ.$make = (bufsize) => new $Chan(typ.elem, bufsize ? bufsize : 0);
178179
break;
179180

180181
case $kindFunc:
@@ -210,6 +211,11 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
210211
typ.elem = elem;
211212
typ.comparable = false;
212213
};
214+
typ.$make = (size) => {
215+
if (size === undefined) { size = 0; }
216+
if (size < 0 || size > 2147483647) { $throwRuntimeError("makemap: size out of range"); }
217+
return new $global.Map();
218+
};
213219
break;
214220

215221
case $kindPtr:
@@ -250,6 +256,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
250256
typ.nativeArray = $nativeArray(elem.kind);
251257
typ.nil = new typ([]);
252258
};
259+
typ.$make = (size, capacity) => $makeSlice(typ, size, capacity);
253260
break;
254261

255262
case $kindStruct:

tests/typeparams/builtins_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package typeparams_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
func TestMake(t *testing.T) {
9+
t.Run("slice", func(t *testing.T) {
10+
tests := []struct {
11+
slice []int
12+
wantStr string
13+
wantLen int
14+
wantCap int
15+
}{{
16+
slice: make([]int, 1),
17+
wantStr: "[]int{0}",
18+
wantLen: 1,
19+
wantCap: 1,
20+
}, {
21+
slice: make([]int, 1, 2),
22+
wantStr: "[]int{0}",
23+
wantLen: 1,
24+
wantCap: 2,
25+
}}
26+
27+
for i, test := range tests {
28+
t.Run(fmt.Sprint(i), func(t *testing.T) {
29+
if got := fmt.Sprintf("%#v", test.slice); got != test.wantStr {
30+
t.Errorf("Got: fmt.Sprint(%v) = %q. Want: %q.", test.slice, got, test.wantStr)
31+
}
32+
if got := len(test.slice); got != test.wantLen {
33+
t.Errorf("Got: len(%v) = %d. Want: %d.", test.slice, got, test.wantLen)
34+
}
35+
if got := cap(test.slice); got != test.wantCap {
36+
t.Errorf("Got: cap(%v) = %d. Want: %d.", test.slice, got, test.wantCap)
37+
}
38+
})
39+
}
40+
})
41+
42+
t.Run("map", func(t *testing.T) {
43+
tests := []map[int]int{
44+
make(map[int]int),
45+
make(map[int]int, 1),
46+
}
47+
48+
for i, test := range tests {
49+
t.Run(fmt.Sprint(i), func(t *testing.T) {
50+
want := "map[int]int{}"
51+
got := fmt.Sprintf("%#v", test)
52+
if want != got {
53+
t.Errorf("Got: fmt.Sprint(%v) = %q. Want: %q.", test, got, want)
54+
}
55+
})
56+
}
57+
})
58+
59+
t.Run("chan", func(t *testing.T) {
60+
tests := []struct {
61+
ch chan int
62+
wantCap int
63+
}{{
64+
ch: make(chan int),
65+
wantCap: 0,
66+
}, {
67+
ch: make(chan int, 1),
68+
wantCap: 1,
69+
}}
70+
71+
for i, test := range tests {
72+
t.Run(fmt.Sprint(i), func(t *testing.T) {
73+
wantStr := "chan int"
74+
if got := fmt.Sprintf("%T", test.ch); got != wantStr {
75+
t.Errorf("Got: fmt.Sprint(%v) = %q. Want: %q.", test.ch, got, wantStr)
76+
}
77+
if got := cap(test.ch); got != test.wantCap {
78+
t.Errorf("Got: cap(%v) = %d. Want: %d.", test.ch, got, test.wantCap)
79+
}
80+
})
81+
}
82+
})
83+
}

0 commit comments

Comments
 (0)