Skip to content

Commit ac13918

Browse files
committed
Implement bitwise shift left operator for type parameters.
1 parent f4c0904 commit ac13918

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

compiler/expressions.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ func (fc *funcContext) translateBinaryExpr(e *ast.BinaryExpr) *expression {
704704
return fc.formatExpr("%s.xor(%e, %e)", fc.typeName(t), e.X, e.Y)
705705
case token.AND_NOT:
706706
return fc.formatExpr("%s.andNot(%e, %e)", fc.typeName(t), e.X, e.Y)
707+
case token.SHL:
708+
return fc.formatExpr("%s.shl(%e, $flatten64(%e, %s))", fc.typeName(t), e.X, e.Y, fc.typeName(t2))
707709
}
708710
}
709711

compiler/prelude/numeric.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ var $floatKey = f => {
3030
return String(f);
3131
};
3232

33-
var $flatten64 = x => {
33+
var $flatten64 = (x, typ) => {
34+
if (typ && typ.kind != $kindInt64 && typ.kind != $kindUint64) {
35+
return x; // Not a 64-bit number, no need to flatten.
36+
}
3437
return x.$high * 4294967296 + x.$low;
3538
};
3639

compiler/prelude/types.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
429429
typ.or = (x, y) => (x | y);
430430
typ.xor = (x, y) => $truncateNumber(x ^ y, typ);
431431
typ.andNot = (x, y) => $truncateNumber(x & ~y, typ);
432+
typ.shl = (x, y) => (y < 32) ? $truncateNumber(x << y, typ) : 0;
432433
break;
433434
case $kindUint8:
434435
case $kindUint16:
@@ -441,6 +442,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
441442
typ.or = (x, y) => (x | y) >>> 0;
442443
typ.xor = (x, y) => $truncateNumber(x ^ y, typ);
443444
typ.andNot = (x, y) => $truncateNumber(x & ~y, typ);
445+
typ.shl = (x, y) => (y < 32) ? $truncateNumber(x << y, typ) : 0;
444446
break;
445447
case $kindUint:
446448
case $kindUint32:
@@ -454,6 +456,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
454456
typ.or = (x, y) => (x | y) >>> 0;
455457
typ.xor = (x, y) => $truncateNumber(x ^ y, typ);
456458
typ.andNot = (x, y) => $truncateNumber(x & ~y, typ);
459+
typ.shl = (x, y) => (y < 32) ? $truncateNumber(x << y, typ) : 0;
457460
break;
458461
case $kindInt:
459462
case $kindInt32:
@@ -466,6 +469,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
466469
typ.or = (x, y) => (x | y);
467470
typ.xor = (x, y) => $truncateNumber(x ^ y, typ);
468471
typ.andNot = (x, y) => $truncateNumber(x & ~y, typ);
472+
typ.shl = (x, y) => (y < 32) ? $truncateNumber(x << y, typ) : 0;
469473
break;
470474
case $kindInt64:
471475
case $kindUint64:
@@ -478,6 +482,7 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
478482
typ.or = (x, y) => new typ(x.$high | y.$high, (x.$low | y.$low) >>> 0);
479483
typ.xor = (x, y) => new typ(x.$high ^ y.$high, (x.$low ^ y.$low) >>> 0);
480484
typ.andNot = (x, y) => new typ(x.$high & ~y.$high, (x.$low & ~y.$low) >>> 0);
485+
typ.shl = (x, y) => $shiftLeft64(x, y);
481486
break;
482487
case $kindFloat32:
483488
case $kindFloat64:

tests/typeparams/arithmetics_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package typeparams_test
33
import (
44
"fmt"
55
"go/token"
6+
"math/bits"
67
"testing"
78

89
"golang.org/x/exp/constraints"
@@ -368,3 +369,42 @@ func TestBitwiseAndNot(t *testing.T) {
368369
t.Run(test.String(), test.Run)
369370
}
370371
}
372+
373+
func leftShift[T constraints.Integer](x, y T) T {
374+
return x << y
375+
}
376+
377+
func leftShiftTC[T constraints.Integer](x, y, want T) *testCase[T] {
378+
return &testCase[T]{
379+
op: leftShift[T],
380+
opName: token.SHL,
381+
x: x,
382+
y: y,
383+
want: want,
384+
}
385+
}
386+
387+
func TestBitwiseShitLeft(t *testing.T) {
388+
tests := []testCaseI{
389+
leftShiftTC[int8](0x48, 1, -0x70),
390+
leftShiftTC[int16](0x4008, 1, -0x7ff0),
391+
leftShiftTC[int32](0x40000008, 1, -0x7ffffff0),
392+
leftShiftTC[uint8](0x88, 1, 0x10),
393+
leftShiftTC[uint16](0x8008, 1, 0x0010),
394+
leftShiftTC[uint32](0x80000008, 1, 0x00000010),
395+
leftShiftTC[int64](0x4000000000000008, 1, -0x7ffffffffffffff0),
396+
leftShiftTC[uint64](0x8000000000000008, 1, 0x0000000000000010),
397+
}
398+
399+
if bits.UintSize == 32 {
400+
tests = append(tests,
401+
leftShiftTC[int](0x40000008, 1, -0x7ffffff0),
402+
leftShiftTC[uint](0x80000008, 1, 0x00000010),
403+
leftShiftTC[uintptr](0x80000008, 1, 0x00000010),
404+
)
405+
}
406+
407+
for _, test := range tests {
408+
t.Run(test.String(), test.Run)
409+
}
410+
}

0 commit comments

Comments
 (0)