From 4f6746f066f3f0102ba47408ef28293384aeeb92 Mon Sep 17 00:00:00 2001 From: Nevkontakte Date: Mon, 6 May 2024 18:56:26 +0100 Subject: [PATCH] Fix float64 to uint{8,16,32} conversion. Before this change, GopherJS compiler emitted `(f >> 0)` expression to convert a float64 `f` to any non-64-bit unsigned integer type. This is incorrect, because `>>` is a signed bitshift operator in JS, so the returned value remained signed. Moreover, it did not take into account to bit size of the target type. By removing the switch cause, we make the compiler fall through to the default clause where `fc.fixNumber()` actually does the right thing, taking the target into account. Fixes #733. --- compiler/expressions.go | 2 -- tests/numeric_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/compiler/expressions.go b/compiler/expressions.go index 2768e3d2a..11b2840ba 100644 --- a/compiler/expressions.go +++ b/compiler/expressions.go @@ -1128,8 +1128,6 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type return fc.fixNumber(fc.formatParenExpr("%1l + ((%1h >> 31) * 4294967296)", expr), t) } return fc.fixNumber(fc.formatExpr("%s.$low", fc.translateExpr(expr)), t) - case isFloat(basicExprType): - return fc.formatParenExpr("%e >> 0", expr) case types.Identical(exprType, types.Typ[types.UnsafePointer]): return fc.translateExpr(expr) default: diff --git a/tests/numeric_test.go b/tests/numeric_test.go index df06db584..4eaa678c0 100644 --- a/tests/numeric_test.go +++ b/tests/numeric_test.go @@ -5,6 +5,8 @@ import ( "runtime" "testing" "testing/quick" + + "github.com/gopherjs/gopherjs/js" ) // naiveMul64 performs 64-bit multiplication without using the multiplication @@ -93,3 +95,26 @@ func BenchmarkMul64(b *testing.B) { } }) } + +func TestIssue733(t *testing.T) { + if runtime.GOOS != "js" { + t.Skip("test uses GopherJS-specific features") + } + + t.Run("sign", func(t *testing.T) { + f := float64(-1) + i := uint32(f) + underlying := js.InternalObject(i).Float() // Get the raw JS number behind i. + if want := float64(4294967295); underlying != want { + t.Errorf("Got: uint32(float64(%v)) = %v. Want: %v.", f, underlying, want) + } + }) + t.Run("truncation", func(t *testing.T) { + f := float64(300) + i := uint8(f) + underlying := js.InternalObject(i).Float() // Get the raw JS number behind i. + if want := float64(44); underlying != want { + t.Errorf("Got: uint32(float64(%v)) = %v. Want: %v.", f, underlying, want) + } + }) +}