Skip to content

Commit 73958a0

Browse files
authored
Merge pull request #1308 from Workiva/updateGo1.20
[go1.20] Pull master into go1.20
2 parents fc3ec56 + 7f7a196 commit 73958a0

File tree

5 files changed

+154
-4
lines changed

5 files changed

+154
-4
lines changed

build/build.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke
174174
overrides := make(map[string]overrideInfo)
175175
for _, file := range overlayFiles {
176176
augmentOverlayFile(file, overrides)
177-
pruneImports(file)
178177
}
179178
delete(overrides, "init")
180179

compiler/expressions.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
387387
switch basic.Kind() {
388388
case types.Int32, types.Int:
389389
return fc.formatParenExpr("$imul(%e, %e)", e.X, e.Y)
390-
case types.Uint32, types.Uintptr:
390+
case types.Uint32, types.Uint, types.Uintptr:
391391
return fc.formatParenExpr("$imul(%e, %e) >>> 0", e.X, e.Y)
392392
}
393393
return fc.fixNumber(fc.formatExpr("%e * %e", e.X, e.Y), basic)
@@ -1131,8 +1131,6 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
11311131
return fc.fixNumber(fc.formatParenExpr("%1l + ((%1h >> 31) * 4294967296)", expr), t)
11321132
}
11331133
return fc.fixNumber(fc.formatExpr("%s.$low", fc.translateExpr(expr)), t)
1134-
case isFloat(basicExprType):
1135-
return fc.formatParenExpr("%e >> 0", expr)
11361134
case types.Identical(exprType, types.Typ[types.UnsafePointer]):
11371135
return fc.translateExpr(expr)
11381136
default:

compiler/prelude/jsmapping.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ var $internalize = (v, t, recv, seen, makeWrapper) => {
236236
case $kindFloat64:
237237
return parseFloat(v);
238238
case $kindArray:
239+
if (v === null || v === undefined) {
240+
$throwRuntimeError("cannot internalize "+v+" as a "+t.string);
241+
}
239242
if (v.length !== t.len) {
240243
$throwRuntimeError("got array with wrong size from JavaScript native");
241244
}
@@ -331,6 +334,9 @@ var $internalize = (v, t, recv, seen, makeWrapper) => {
331334
return $internalize(v, t.elem, makeWrapper);
332335
}
333336
case $kindSlice:
337+
if (v == null) {
338+
return t.zero();
339+
}
334340
return new t($mapArray(v, e => { return $internalize(e, t.elem, makeWrapper); }));
335341
case $kindString:
336342
v = String(v);

tests/js_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,45 @@ func TestExternalize(t *testing.T) {
830830
}
831831
}
832832

833+
func TestInternalizeSlice(t *testing.T) {
834+
tests := []struct {
835+
name string
836+
init []int
837+
want string
838+
}{
839+
{
840+
name: `nil slice`,
841+
init: []int(nil),
842+
want: `[]int(nil)`,
843+
},
844+
{
845+
name: `empty slice`,
846+
init: []int{},
847+
want: `[]int{}`,
848+
},
849+
{
850+
name: `non-empty slice`,
851+
init: []int{42, 53, 64},
852+
want: `[]int{42, 53, 64}`,
853+
},
854+
}
855+
856+
for _, tt := range tests {
857+
t.Run(tt.name, func(t *testing.T) {
858+
b := struct {
859+
*js.Object
860+
V []int `js:"V"` // V is externalized
861+
}{Object: js.Global.Get("Object").New()}
862+
b.V = tt.init
863+
864+
result := fmt.Sprintf(`%#v`, b.V) // internalize b.V
865+
if result != tt.want {
866+
t.Errorf(`Unexpected result %q != %q`, result, tt.want)
867+
}
868+
})
869+
}
870+
}
871+
833872
func TestInternalizeExternalizeNull(t *testing.T) {
834873
type S struct {
835874
*js.Object

tests/numeric_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package tests
22

33
import (
4+
"fmt"
5+
"math/bits"
46
"math/rand"
57
"runtime"
68
"testing"
79
"testing/quick"
10+
11+
"github.com/gopherjs/gopherjs/js"
812
)
913

1014
// naiveMul64 performs 64-bit multiplication without using the multiplication
@@ -93,3 +97,107 @@ func BenchmarkMul64(b *testing.B) {
9397
}
9498
})
9599
}
100+
101+
func TestIssue733(t *testing.T) {
102+
if runtime.GOOS != "js" {
103+
t.Skip("test uses GopherJS-specific features")
104+
}
105+
106+
t.Run("sign", func(t *testing.T) {
107+
f := float64(-1)
108+
i := uint32(f)
109+
underlying := js.InternalObject(i).Float() // Get the raw JS number behind i.
110+
if want := float64(4294967295); underlying != want {
111+
t.Errorf("Got: uint32(float64(%v)) = %v. Want: %v.", f, underlying, want)
112+
}
113+
})
114+
t.Run("truncation", func(t *testing.T) {
115+
f := float64(300)
116+
i := uint8(f)
117+
underlying := js.InternalObject(i).Float() // Get the raw JS number behind i.
118+
if want := float64(44); underlying != want {
119+
t.Errorf("Got: uint32(float64(%v)) = %v. Want: %v.", f, underlying, want)
120+
}
121+
})
122+
}
123+
124+
// Test_32BitEnvironment tests that GopherJS behaves correctly
125+
// as a 32-bit environment for integers. To simulate a 32 bit environment
126+
// we have to use `$imul` instead of `*` to get the correct result.
127+
func Test_32BitEnvironment(t *testing.T) {
128+
if bits.UintSize != 32 {
129+
t.Skip(`test is only relevant for 32-bit environment`)
130+
}
131+
132+
tests := []struct {
133+
x, y, exp uint64
134+
}{
135+
{
136+
x: 65535, // x = 2^16 - 1
137+
y: 65535, // same as x
138+
exp: 4294836225, // x² works since it doesn't overflow 32 bits.
139+
},
140+
{
141+
x: 134217729, // x = 2^27 + 1, x < 2^32 and x > sqrt(2^53), so x² overflows 53 bits.
142+
y: 134217729, // same as x
143+
exp: 268435457, // x² mod 2^32 = (2^27 + 1)² mod 2^32 = (2^54 + 2^28 + 1) mod 2^32 = 2^28 + 1
144+
// In pure JS, `x * x >>> 0`, would result in 268,435,456 because it lost the least significant bit
145+
// prior to being truncated, where in a real 32 bit environment, it would be 268,435,457 since
146+
// the rollover removed the most significant bit and doesn't affect the least significant bit.
147+
},
148+
{
149+
x: 4294967295, // x = 2^32 - 1 another case where x² overflows 53 bits causing a loss of precision.
150+
y: 4294967295, // same as x
151+
exp: 1, // x² mod 2^32 = (2^32 - 1)² mod 2^32 = (2^64 - 2^33 + 1) mod 2^32 = 1
152+
// In pure JS, `x * x >>> 0`, would result in 0 because it lost the least significant bits.
153+
},
154+
{
155+
x: 4294967295, // x = 2^32 - 1
156+
y: 3221225473, // y = 2^31 + 2^30 + 1
157+
exp: 1073741823, // 2^32 - 1.
158+
// In pure JS, `x * y >>> 0`, would result in 1,073,741,824.
159+
},
160+
{
161+
x: 4294967295, // x = 2^32 - 1
162+
y: 134217729, // y = 2^27 + 1
163+
exp: 4160749567, // In pure JS, `x * y >>> 0`, would result in 4,160,749,568.
164+
},
165+
}
166+
167+
for i, test := range tests {
168+
t.Run(fmt.Sprintf(`#%d/uint32`, i), func(t *testing.T) {
169+
x, y, exp := uint32(test.x), uint32(test.y), uint32(test.exp)
170+
if got := x * y; got != exp {
171+
t.Errorf("got: %d\nwant: %d.", got, exp)
172+
}
173+
})
174+
175+
t.Run(fmt.Sprintf(`#%d/uintptr`, i), func(t *testing.T) {
176+
x, y, exp := uintptr(test.x), uintptr(test.y), uintptr(test.exp)
177+
if got := x * y; got != exp {
178+
t.Errorf("got: %d\nwant: %d.", got, exp)
179+
}
180+
})
181+
182+
t.Run(fmt.Sprintf(`#%d/uint`, i), func(t *testing.T) {
183+
x, y, exp := uint(test.x), uint(test.y), uint(test.exp)
184+
if got := x * y; got != exp {
185+
t.Errorf("got: %d\nwant: %d.", got, exp)
186+
}
187+
})
188+
189+
t.Run(fmt.Sprintf(`#%d/int32`, i), func(t *testing.T) {
190+
x, y, exp := int32(test.x), int32(test.y), int32(test.exp)
191+
if got := x * y; got != exp {
192+
t.Errorf("got: %d\nwant: %d.", got, exp)
193+
}
194+
})
195+
196+
t.Run(fmt.Sprintf(`#%d/int`, i), func(t *testing.T) {
197+
x, y, exp := int(test.x), int(test.y), int(test.exp)
198+
if got := x * y; got != exp {
199+
t.Errorf("got: %d\nwant: %d.", got, exp)
200+
}
201+
})
202+
}
203+
}

0 commit comments

Comments
 (0)