From 15270476fd25f69f0f9fa745a66a0d72b3fff719 Mon Sep 17 00:00:00 2001 From: Alfonso Garcia-Caro Date: Wed, 24 Nov 2021 00:22:48 +0900 Subject: [PATCH] Fix #2614 #2615 --- build.fsx | 1 + src/Fable.Transforms/Replacements.fs | 18 ++++++++++++++++-- src/fable-library/Int32.ts | 11 +++++++++++ src/fable-library/Long.ts | 11 +++++++++++ tests/Main/ArithmeticTests.fs | 22 ++++++++++++++++++++++ tests/Main/CharTests.fs | 4 ++++ 6 files changed, 65 insertions(+), 2 deletions(-) diff --git a/build.fsx b/build.fsx index 9202250a53..a1a9f90cb1 100644 --- a/build.fsx +++ b/build.fsx @@ -547,6 +547,7 @@ match BUILD_ARGS_LOWER with | "test-integration"::_ -> testIntegration() | "quicktest"::_ -> buildLibraryIfNotExists() + removeDirRecursive "src/quicktest/fable_modules" run "dotnet watch --project src/Fable.Cli run -- watch --cwd ../quicktest --exclude Fable.Core --noCache --runScript" | "run"::_ -> diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index a7ef2edd85..86ed2d5556 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -605,7 +605,10 @@ let toInt com (ctx: Context) r targetType (args: Expr list) = | JsNumber UInt32 -> emitJsExpr None (Number UInt32) [arg] "$0 >>> 0" | _ -> failwithf "Unexpected non-integer type %A" typeTo match sourceType, targetType with - | Char, _ -> Helper.InstanceCall(args.Head, "charCodeAt", targetType, [makeIntConst 0]) + | Char, _ -> + match targetType, args with + | Number kind, Value(CharConstant c, r)::_ -> Value(NumberConstant(float c, kind), r) + | _ -> Helper.InstanceCall(args.Head, "charCodeAt", targetType, [makeIntConst 0]) | String, _ -> stringToInt com ctx r targetType args | Builtin BclBigInt, _ -> Helper.LibCall(com, "BigInt", castBigIntMethod targetType, targetType, args) | NumberExt typeFrom, NumberExt typeTo -> @@ -696,7 +699,12 @@ let applyOp (com: ICompiler) (ctx: Context) r t opName (args: Expr list) argType Operation(Logical(op, left, right), Boolean, r) let nativeOp opName argTypes args = match opName, args with - | Operators.addition, [left; right] -> binOp BinaryPlus left right + | Operators.addition, [left; right] -> + match argTypes with + | Char::_ -> + let toUInt16 e = toInt com ctx None (Number UInt16) [e] + Operation(Binary(BinaryPlus, toUInt16 left, toUInt16 right), Number UInt16, r) |> toChar + | _ -> binOp BinaryPlus left right | Operators.subtraction, [left; right] -> binOp BinaryMinus left right | Operators.multiply, [left; right] -> binOp BinaryMultiply left right | (Operators.division | Operators.divideByInt), [left; right] -> @@ -1622,6 +1630,12 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o | "Sign", _ -> let args = toFloat com ctx r t args |> List.singleton Helper.LibCall(com, "Util", "sign", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | "DivRem", _ -> + let modName = + match i.SignatureArgTypes with + | Builtin (BclInt64)::_ -> "Long" + | _ -> "Int32" + Helper.LibCall(com, modName, "divRem", t, args, i.SignatureArgTypes, ?loc=r) |> Some // Numbers | ("Infinity"|"InfinitySingle"), _ -> Helper.GlobalIdent("Number", "POSITIVE_INFINITY", t, ?loc=r) |> Some diff --git a/src/fable-library/Int32.ts b/src/fable-library/Int32.ts index cc79dfa16d..dc45fe967c 100644 --- a/src/fable-library/Int32.ts +++ b/src/fable-library/Int32.ts @@ -132,3 +132,14 @@ export function op_UnaryNegation_Int16(x: number) { export function op_UnaryNegation_Int32(x: number) { return x === -2147483648 ? x : -x; } + +export function divRem(x: number, y: number, out?: FSharpRef) { + const div = ~~(x / y); + const rem = x % y; + if (out != null) { + out.contents = rem; + return div; + } else { + return [div, rem]; + } +} diff --git a/src/fable-library/Long.ts b/src/fable-library/Long.ts index 2a99dc86fc..366517c645 100644 --- a/src/fable-library/Long.ts +++ b/src/fable-library/Long.ts @@ -143,3 +143,14 @@ export function ticksToUnixEpochMilliseconds(ticks: Long) { // } // }; // } + +export function divRem(x: Long, y: Long, out?: FSharpRef) { + const div = op_Division(x, y); + const rem = op_Modulus(x, y); + if (out != null) { + out.contents = rem; + return div; + } else { + return [div, rem]; + } +} diff --git a/tests/Main/ArithmeticTests.fs b/tests/Main/ArithmeticTests.fs index 0dc47d1e12..3c55617b60 100644 --- a/tests/Main/ArithmeticTests.fs +++ b/tests/Main/ArithmeticTests.fs @@ -56,6 +56,28 @@ let tests = testCase "Infix modulo can be generated" <| fun () -> 4 % 3 |> equal 1 + testCase "Math.DivRem works with ints" <| fun () -> + Math.DivRem(5, 2) |> equal (2, 1) + Math.DivRem(4, 2) |> equal (2, 0) + + testCase "Math.DivRem works with ints and ref" <| fun () -> + let rem = ref -1 + Math.DivRem(5, 2, rem) |> equal 2 + rem.Value |> equal 1 + Math.DivRem(4, 2, rem) |> equal 2 + rem.Value |> equal 0 + + testCase "Math.DivRem works with longs" <| fun () -> + Math.DivRem(5L, 2L) |> equal (2L, 1L) + Math.DivRem(4L, 2L) |> equal (2L, 0L) + + testCase "Math.DivRem works with longs and ref" <| fun () -> + let rem = ref -1L + Math.DivRem(5L, 2L, rem) |> equal 2L + rem.Value |> equal 1 + Math.DivRem(4L, 2L, rem) |> equal 2L + rem.Value |> equal 0 + testCase "Evaluation order is preserved by generated code" <| fun () -> (4 - 2) * 2 + 1 |> equal 5 diff --git a/tests/Main/CharTests.fs b/tests/Main/CharTests.fs index f45e31a0f2..c0fdfddda9 100644 --- a/tests/Main/CharTests.fs +++ b/tests/Main/CharTests.fs @@ -214,4 +214,8 @@ let tests = |> failwithf "Unexpected result '%c'" with | _ -> () + + testCase "Char addition works" <| fun _ -> + 'A' + 'B' |> int |> equal 131 + 'A' + char 7 |> int |> equal 72 ] \ No newline at end of file