Skip to content

Commit bfa92fe

Browse files
committed
Implement cap() builtin for type params.
Similar to len(), to maintain performance when used in loops I've kept compile-time specializations for when the exact type is known. Otherwise, a type-specific implementation is called at runtime.
1 parent 11065e6 commit bfa92fe

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

compiler/expressions.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,13 @@ func (fc *funcContext) translateBuiltin(name string, sig *types.Signature, args
10841084
return fc.formatExpr("%e.$capacity", args[0])
10851085
case *types.Pointer:
10861086
return fc.formatExpr("(%e, %d)", args[0], argType.Elem().(*types.Array).Len())
1087-
// capacity of array is constant
1087+
case *types.Array:
1088+
// This should never happen™
1089+
panic(fmt.Errorf("array capacity should have been inlined as constant"))
1090+
case *types.Interface: // *types.TypeParam has interface as underlying type.
1091+
return fc.formatExpr("%s.$cap(%e)", fc.typeName(fc.pkgCtx.TypeOf(args[0])), args[0])
10881092
default:
1089-
panic(fmt.Sprintf("Unhandled cap type: %T\n", argType))
1093+
panic(fmt.Errorf("unhandled cap type: %T", argType))
10901094
}
10911095
case "panic":
10921096
return fc.formatExpr("$panic(%s)", fc.translateImplicitConversion(args[0], types.NewInterface(nil, nil)))

compiler/prelude/types.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
165165
Object.defineProperty(typ.ptr.nil, "nilCheck", { get: $throwNilPointerError });
166166
};
167167
typ.$len = (v) => typ.len;
168+
typ.$cap = (v) => typ.len;
168169
break;
169170

170171
case $kindChan:
@@ -179,6 +180,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
179180
};
180181
typ.$make = (bufsize) => new $Chan(typ.elem, bufsize ? bufsize : 0);
181182
typ.$len = (v) => v.$buffer.length;
183+
typ.$cap = (v) => v.$capacity;
182184
break;
183185

184186
case $kindFunc:
@@ -241,6 +243,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
241243
typ.nil = new typ($throwNilPointerError, $throwNilPointerError);
242244
};
243245
typ.$len = (v) => typ.elem.$len(typ.wrapped ? v : v.$get());
246+
typ.$cap = (v) => typ.elem.$cap(typ.wrapped ? v : v.$get());
244247
break;
245248

246249
case $kindSlice:
@@ -263,6 +266,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
263266
};
264267
typ.$make = (size, capacity) => $makeSlice(typ, size, capacity);
265268
typ.$len = (v) => v.$length;
269+
typ.$cap = (v) => v.$capacity;
266270
break;
267271

268272
case $kindStruct:

tests/typeparams/builtins_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,42 @@ func TestLen(t *testing.T) {
124124
})
125125
}
126126
}
127+
128+
func _cap[T []int | *[3]int | [3]int | chan int](x T) int {
129+
return cap(x)
130+
}
131+
132+
func TestCap(t *testing.T) {
133+
ch := make(chan int, 2)
134+
ch <- 1
135+
136+
tests := []struct {
137+
desc string
138+
got int
139+
want int
140+
}{{
141+
desc: "[]int",
142+
got: _cap([]int{1, 2, 3}),
143+
want: 3,
144+
}, {
145+
desc: "*[3]int",
146+
got: _cap(&[3]int{1}),
147+
want: 3,
148+
}, {
149+
desc: "[3]int",
150+
got: _cap([3]int{1}),
151+
want: 3,
152+
}, {
153+
desc: "chan int",
154+
got: _cap(ch),
155+
want: 2,
156+
}}
157+
158+
for _, test := range tests {
159+
t.Run(test.desc, func(t *testing.T) {
160+
if test.got != test.want {
161+
t.Errorf("Got: len() = %d. Want: %d.", test.got, test.want)
162+
}
163+
})
164+
}
165+
}

0 commit comments

Comments
 (0)