diff --git a/backend/src/Builtins/Builtins.Pure/Libs/Int128.fs b/backend/src/Builtins/Builtins.Pure/Libs/Int128.fs index e3950a9b6c..d396451e9d 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/Int128.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/Int128.fs @@ -94,15 +94,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt128 ""; Param.make "b" TInt128 "" ] returnType = TInt128 - description = "Adds two 128-bit signed integers together" + description = "Adds two 128-bit signed integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DInt128 a; DInt128 b ] -> - try - let result = System.Int128.op_CheckedAddition (a, b) - Ply(DInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -114,15 +109,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt128 ""; Param.make "b" TInt128 "" ] returnType = TInt128 - description = "Subtracts two 128-bit signed integers" + description = "Subtracts two 128-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt128 a; DInt128 b ] -> - try - let result = System.Int128.op_CheckedSubtraction (a, b) - Ply(DInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -135,15 +125,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt128 ""; Param.make "b" TInt128 "" ] returnType = TInt128 - description = "Multiplies two 128-bit signed integers" + description = "Multiplies two 128-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt128 a; DInt128 b ] -> - try - let result = System.Int128.op_CheckedMultiply (a, b) - Ply(DInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -162,14 +147,13 @@ let fns () : List = fn = (function | _, vm, _, [ DInt128 a; DInt128 b ] -> - try - let result = System.Int128.op_Division (a, b) - Ply(DInt128(result)) - with - | :? System.DivideByZeroException -> + if b = System.Int128.Zero then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID - | :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + elif a = System.Int128.MinValue && b = System.Int128.NegativeOne then + // wraps back to MinValue (the division itself would throw) + Ply(DInt128 System.Int128.MinValue) + else + Ply(DInt128(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -184,12 +168,7 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt128 a ] -> - try - let result = System.Int128.op_CheckedUnaryNegation a - Ply(DInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt128 a ] -> Ply(DInt128(-a)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/Int16.fs b/backend/src/Builtins/Builtins.Pure/Libs/Int16.fs index db32c0cc28..9d08bec2d3 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/Int16.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/Int16.fs @@ -95,15 +95,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt16 ""; Param.make "b" TInt16 "" ] returnType = TInt16 - description = "Adds two 16-bit signed integers together" + description = "Adds two 16-bit signed integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DInt16 a; DInt16 b ] -> - try - let result = Checked.(+) a b - Ply(DInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -115,15 +110,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt16 ""; Param.make "b" TInt16 "" ] returnType = TInt16 - description = "Subtracts two 16-bit signed integers" + description = "Subtracts two 16-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt16 a; DInt16 b ] -> - try - let result = Checked.(-) a b - Ply(DInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -135,15 +125,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt16 ""; Param.make "b" TInt16 "" ] returnType = TInt16 - description = "multiplies two 16-bit signed integers" + description = "Multiplies two 16-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt16 a; DInt16 b ] -> - try - let result = Checked.(*) a b - Ply(DInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -158,17 +143,19 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function | _, vm, _, [ DInt16 number; DInt16 exp ] -> - (try - if exp < 0s then - RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID - else - (bigint number) ** (int exp) |> int16 |> DInt16 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + if exp < 0s then + RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID + else + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 16) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + let r = if r >= m / bigint 2 then r - m else r + int16 r |> DInt16 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -186,15 +173,9 @@ let fns () : List = | _, vm, _, [ DInt16 a; DInt16 b ] -> if b = 0s then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID - else if a = int16 System.Int16.MinValue && b = -1s then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID else - let result = a / b - if result < System.Int16.MinValue || result > System.Int16.MaxValue then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DInt16(int16 result)) - + // -32768s / -1s divides in int32 then narrows, wrapping instead of throwing + Ply(DInt16(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -209,13 +190,7 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt16 a ] -> - if a = System.Int16.MinValue then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - let result = -a - Ply(DInt16 result) - + | _, _, _, [ DInt16 a ] -> Ply(DInt16(-a)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/Int32.fs b/backend/src/Builtins/Builtins.Pure/Libs/Int32.fs index 3e75afebbe..fa749a99e2 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/Int32.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/Int32.fs @@ -95,14 +95,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt32 ""; Param.make "b" TInt32 "" ] returnType = TInt32 - description = "Adds two 32-bit signed integers together" + description = "Adds two 32-bit signed integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DInt32 a; DInt32 b ] -> - try - DInt32(Checked.(+) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -114,14 +110,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt32 ""; Param.make "b" TInt32 "" ] returnType = TInt32 - description = "Subtracts two 32-bit signed integers" + description = "Subtracts two 32-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt32 a; DInt32 b ] -> - try - DInt32(Checked.(-) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -133,14 +125,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt32 ""; Param.make "b" TInt32 "" ] returnType = TInt32 - description = "Multiplies two 32-bit signed integers" + description = "Multiplies two 32-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt32 a; DInt32 b ] -> - try - DInt32(Checked.(*) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -155,17 +143,19 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function | _, vm, _, [ DInt32 number; DInt32 exp ] -> - (try - if exp < 0 then - RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID - else - (bigint number) ** (int exp) |> int32 |> DInt32 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + if exp < 0 then + RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID + else + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 32) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + let r = if r >= m / bigint 2 then r - m else r + int32 r |> DInt32 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -184,7 +174,8 @@ let fns () : List = if b = 0 then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else if a = System.Int32.MinValue && b = -1 then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + // wraps back to MinValue (the division itself would throw) + Ply(DInt32 System.Int32.MinValue) else Ply(DInt32(a / b)) | _ -> incorrectArgs ()) @@ -201,11 +192,7 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt32 a ] -> - if a = System.Int32.MinValue then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DInt32(-a)) + | _, _, _, [ DInt32 a ] -> Ply(DInt32(-a)) | _ -> incorrectArgs ()) sqlSpec = NotQueryable previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/Int64.fs b/backend/src/Builtins/Builtins.Pure/Libs/Int64.fs index 1f69466956..92b8235d4e 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/Int64.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/Int64.fs @@ -137,15 +137,14 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt64 ""; Param.make "b" TInt64 "" ] returnType = TInt64 - description = "Adds two integers together" + description = "Adds two integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DInt64 a; DInt64 b ] -> - try - DInt64(Checked.(+) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a + b)) | _ -> incorrectArgs ()) + // CLEANUP: SQL pushdown for Int64 arithmetic does not match runtime + // overflow semantics. Runtime evaluation wraps, but SQLite promotes + // overflowing integer arithmetic to REAL for these add/sub/mul/div/pow specs. sqlSpec = SqlBinOp "+" previewable = Pure capabilities = LibExecution.Capabilities.noCaps @@ -156,14 +155,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt64 ""; Param.make "b" TInt64 "" ] returnType = TInt64 - description = "Subtracts two integers" + description = "Subtracts two integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt64 a; DInt64 b ] -> - try - DInt64(Checked.(-) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a - b)) | _ -> incorrectArgs ()) sqlSpec = SqlBinOp "-" previewable = Pure @@ -175,14 +170,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt64 ""; Param.make "b" TInt64 "" ] returnType = TInt64 - description = "Multiplies two integers" + description = "Multiplies two integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt64 a; DInt64 b ] -> - try - DInt64(Checked.(*) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a * b)) | _ -> incorrectArgs ()) sqlSpec = SqlBinOp "*" previewable = Pure @@ -197,32 +188,20 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function | _, vm, _, [ DInt64 number; DInt64 exp ] -> if exp < 0L then RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID - elif exp > int64 System.Int32.MaxValue then - // `bigint ** int` needs an Int32 exponent; an exponent this large - // overflows Int64 unless the base is trivial. (Without this guard - // `int exp` silently truncates to a bogus — possibly negative — - // Int32, and `bigint ** negative` throws an uncaught exception.) - match number with - | 0L -> Ply(DInt64 0L) - | 1L -> Ply(DInt64 1L) - | -1L -> Ply(DInt64(if exp % 2L = 0L then 1L else -1L)) - | _ -> RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - elif exp > 63L && (number > 1L || number < -1L) then - // Avoid constructing enormous bigints that can never fit in Int64. - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID else - // `int64` narrowing throws OverflowException when the result - // exceeds Int64 range. - try - (bigint number) ** (int exp) |> int64 |> DInt64 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + // wrap on overflow via modular exponentiation, which stays cheap + // even for huge exponents (no enormous bigint is built) + let m = System.Numerics.BigInteger.Pow(bigint 2, 64) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + let r = if r >= m / bigint 2 then r - m else r + int64 r |> DInt64 |> Ply | _ -> incorrectArgs ()) sqlSpec = SqlFunction "POWER" previewable = Pure @@ -241,7 +220,8 @@ let fns () : List = if b = 0L then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else if a = System.Int64.MinValue && b = -1L then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + // wraps back to MinValue (the division itself would throw) + Ply(DInt64 System.Int64.MinValue) else Ply(DInt64(a / b)) | _ -> incorrectArgs ()) @@ -258,11 +238,7 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt64 a ] -> - if a = System.Int64.MinValue then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DInt64(-a)) + | _, _, _, [ DInt64 a ] -> Ply(DInt64(-a)) | _ -> incorrectArgs ()) sqlSpec = NotQueryable previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/Int8.fs b/backend/src/Builtins/Builtins.Pure/Libs/Int8.fs index ba470c2a89..28a0256754 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/Int8.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/Int8.fs @@ -95,14 +95,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt8 ""; Param.make "b" TInt8 "" ] returnType = TInt8 - description = "Adds two 8-bit signed integers together" + description = "Adds two 8-bit signed integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - try - DInt8(Checked.(+) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -114,14 +110,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt8 ""; Param.make "b" TInt8 "" ] returnType = TInt8 - description = "Subtracts two 8-bit signed integers" + description = "Subtracts two 8-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - try - DInt8(Checked.(-) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -133,14 +125,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TInt8 ""; Param.make "b" TInt8 "" ] returnType = TInt8 - description = "Multiplies two 8-bit signed integers" + description = "Multiplies two 8-bit signed integers, wrapping on overflow" fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - try - DInt8(Checked.(*) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -155,17 +143,19 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function | _, vm, _, [ DInt8 number; DInt8 exp ] -> - (try - if exp < 0y then - RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID - else - (bigint number) ** (int exp) |> int8 |> DInt8 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + if exp < 0y then + RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID + else + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 8) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + let r = if r >= m / bigint 2 then r - m else r + int8 r |> DInt8 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -181,14 +171,11 @@ let fns () : List = fn = (function | _, vm, _, [ DInt8 a; DInt8 b ] -> - if b = int8 0 then + if b = 0y then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else - let result = int a / int b - if result < -128 || result > 127 then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DInt8(int8 result)) + // widen to int32 so -128y / -1y wraps on narrowing instead of throwing + Ply(DInt8(int8 (int a / int b))) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -203,12 +190,7 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt8 a ] -> - let result = -(int a) - if result < -128 || result > 127 then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DInt8(int8 result)) + | _, _, _, [ DInt8 a ] -> Ply(DInt8(-a)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/NoModule.fs b/backend/src/Builtins/Builtins.Pure/Libs/NoModule.fs index 436e6f6f71..460cafba83 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/NoModule.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/NoModule.fs @@ -194,21 +194,29 @@ let private zeroModulus (vm : VMState) : 'a = let private negativeModulus (vm : VMState) : 'a = RTE.Ints.NegativeModulus |> RTE.Int |> raiseRTE vm.threadID +let private negativeExponent (vm : VMState) : 'a = + RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID + let private outOfRange (vm : VMState) : 'a = RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID -let private negativeExponent (vm : VMState) : 'a = - RTE.Ints.NegativeExponent |> RTE.Int |> raiseRTE vm.threadID +// Fixed-width integer arithmetic wraps around on overflow (e.g. +// `127y + 1y == -128y`), so `+`, `-`, `*` use F#'s unchecked operators and +// `negate`/`divide` let `MinValue` wrap to itself rather than raising. + +/// `number ^ exp` wrapped into a signed `bits`-wide integer. +/// Uses modular exponentiation so huge exponents stay cheap. +let private powSigned (bits : int) (number : bigint) (exp : bigint) : bigint = + let m = System.Numerics.BigInteger.Pow(bigint 2, bits) + let r = System.Numerics.BigInteger.ModPow(number, exp, m) + let r = ((r % m) + m) % m + if r >= m / bigint 2 then r - m else r -/// Runs an integer computation that may overflow, converting the .NET -/// OverflowException into a clean `OutOfRange` RTE. Used by `/` and `^`, where -/// overflow is still an error (`+`, `-`, `*` wrap instead): `Int64.MinValue / -1L` -/// and oversized `^` results would otherwise escape as an uncaught exception. -let private overflowChecked (vm : VMState) (f : unit -> Dval) : Ply = - try - Ply(f ()) - with :? System.OverflowException -> - outOfRange vm +/// `number ^ exp` wrapped into an unsigned `bits`-wide integer. +let private powUnsigned (bits : int) (number : bigint) (exp : bigint) : bigint = + let m = System.Numerics.BigInteger.Pow(bigint 2, bits) + let r = System.Numerics.BigInteger.ModPow(number, exp, m) + ((r % m) + m) % m let fns () : List = @@ -248,36 +256,29 @@ let fns () : List = returnType = varA description = "Adds two numbers of the same numeric type. Fixed-width integer overflow - raises a runtime error; the arbitrary-precision Int grows instead of - overflowing; float arithmetic follows IEEE (overflow to infinity)." + wraps around; the arbitrary-precision Int grows + instead of overflowing; float arithmetic follows IEEE (overflow to + infinity)." fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - overflowChecked vm (fun () -> DInt8(Checked.(+) a b)) - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - overflowChecked vm (fun () -> DUInt8(Checked.(+) a b)) - | _, vm, _, [ DInt16 a; DInt16 b ] -> - overflowChecked vm (fun () -> DInt16(Checked.(+) a b)) - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - overflowChecked vm (fun () -> DUInt16(Checked.(+) a b)) - | _, vm, _, [ DInt32 a; DInt32 b ] -> - overflowChecked vm (fun () -> DInt32(Checked.(+) a b)) - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - overflowChecked vm (fun () -> DUInt32(Checked.(+) a b)) - | _, vm, _, [ DInt64 a; DInt64 b ] -> - overflowChecked vm (fun () -> DInt64(Checked.(+) a b)) - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - overflowChecked vm (fun () -> DUInt64(Checked.(+) a b)) - | _, vm, _, [ DInt128 a; DInt128 b ] -> - overflowChecked vm (fun () -> - DInt128(System.Int128.op_CheckedAddition (a, b))) - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - overflowChecked vm (fun () -> - DUInt128(System.UInt128.op_CheckedAddition (a, b))) + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a + b)) + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a + b)) + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a + b)) + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a + b)) + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a + b)) + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a + b)) + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a + b)) + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a + b)) + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a + b)) + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a + b)) | _, _, _, [ DInt a; DInt b ] -> Ply(DInt(DarkInt.add a b)) | _, _, _, [ DFloat a; DFloat b ] -> Ply(DFloat(a + b)) | _, vm, _, [ a; b ] -> numericTypeError vm a b | _ -> incorrectArgs ()) + // CLEANUP: SQL pushdown for fixed-width integer arithmetic does not match + // runtime overflow semantics. Runtime evaluation wraps, but SQLite promotes + // overflowing integer arithmetic to REAL for these add/sub/mul/div/pow specs. + // DInt is arbitrary-precision, so it has no wrap behavior to preserve. sqlSpec = SqlBinOp "+" previewable = Pure capabilities = LibExecution.Capabilities.noCaps @@ -290,33 +291,21 @@ let fns () : List = returnType = varA description = "Subtracts two numbers of the same numeric type. Fixed-width integer - overflow raises a runtime error; the arbitrary-precision Int grows - instead of overflowing; float arithmetic follows IEEE (overflow to - infinity)." + overflow wraps around; the arbitrary-precision Int + grows instead of overflowing; float arithmetic follows IEEE (overflow + to infinity)." fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - overflowChecked vm (fun () -> DInt8(Checked.(-) a b)) - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - overflowChecked vm (fun () -> DUInt8(Checked.(-) a b)) - | _, vm, _, [ DInt16 a; DInt16 b ] -> - overflowChecked vm (fun () -> DInt16(Checked.(-) a b)) - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - overflowChecked vm (fun () -> DUInt16(Checked.(-) a b)) - | _, vm, _, [ DInt32 a; DInt32 b ] -> - overflowChecked vm (fun () -> DInt32(Checked.(-) a b)) - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - overflowChecked vm (fun () -> DUInt32(Checked.(-) a b)) - | _, vm, _, [ DInt64 a; DInt64 b ] -> - overflowChecked vm (fun () -> DInt64(Checked.(-) a b)) - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - overflowChecked vm (fun () -> DUInt64(Checked.(-) a b)) - | _, vm, _, [ DInt128 a; DInt128 b ] -> - overflowChecked vm (fun () -> - DInt128(System.Int128.op_CheckedSubtraction (a, b))) - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - overflowChecked vm (fun () -> - DUInt128(System.UInt128.op_CheckedSubtraction (a, b))) + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a - b)) + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a - b)) + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a - b)) + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a - b)) + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a - b)) + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a - b)) + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a - b)) + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a - b)) + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a - b)) + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a - b)) | _, _, _, [ DInt a; DInt b ] -> Ply(DInt(DarkInt.subtract a b)) | _, _, _, [ DFloat a; DFloat b ] -> Ply(DFloat(a - b)) | _, vm, _, [ a; b ] -> numericTypeError vm a b @@ -333,33 +322,21 @@ let fns () : List = returnType = varA description = "Multiplies two numbers of the same numeric type. Fixed-width integer - overflow raises a runtime error; the arbitrary-precision Int grows - instead of overflowing; float arithmetic follows IEEE (overflow to - infinity)." + overflow wraps around; the arbitrary-precision Int + grows instead of overflowing; float arithmetic follows IEEE (overflow + to infinity)." fn = (function - | _, vm, _, [ DInt8 a; DInt8 b ] -> - overflowChecked vm (fun () -> DInt8(Checked.(*) a b)) - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - overflowChecked vm (fun () -> DUInt8(Checked.(*) a b)) - | _, vm, _, [ DInt16 a; DInt16 b ] -> - overflowChecked vm (fun () -> DInt16(Checked.(*) a b)) - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - overflowChecked vm (fun () -> DUInt16(Checked.(*) a b)) - | _, vm, _, [ DInt32 a; DInt32 b ] -> - overflowChecked vm (fun () -> DInt32(Checked.(*) a b)) - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - overflowChecked vm (fun () -> DUInt32(Checked.(*) a b)) - | _, vm, _, [ DInt64 a; DInt64 b ] -> - overflowChecked vm (fun () -> DInt64(Checked.(*) a b)) - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - overflowChecked vm (fun () -> DUInt64(Checked.(*) a b)) - | _, vm, _, [ DInt128 a; DInt128 b ] -> - overflowChecked vm (fun () -> - DInt128(System.Int128.op_CheckedMultiply (a, b))) - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - overflowChecked vm (fun () -> - DUInt128(System.UInt128.op_CheckedMultiply (a, b))) + | _, _, _, [ DInt8 a; DInt8 b ] -> Ply(DInt8(a * b)) + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a * b)) + | _, _, _, [ DInt16 a; DInt16 b ] -> Ply(DInt16(a * b)) + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a * b)) + | _, _, _, [ DInt32 a; DInt32 b ] -> Ply(DInt32(a * b)) + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a * b)) + | _, _, _, [ DInt64 a; DInt64 b ] -> Ply(DInt64(a * b)) + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a * b)) + | _, _, _, [ DInt128 a; DInt128 b ] -> Ply(DInt128(a * b)) + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a * b)) | _, _, _, [ DInt a; DInt b ] -> Ply(DInt(DarkInt.multiply a b)) | _, _, _, [ DFloat a; DFloat b ] -> Ply(DFloat(a * b)) | _, vm, _, [ a; b ] -> numericTypeError vm a b @@ -377,45 +354,48 @@ let fns () : List = description = "Divides two numbers of the same numeric type. Integer types use integer division; dividing an integer by zero raises a runtime error. Signed - integer overflow (e.g. {{Int64.MinValue / -1}}) also raises a runtime - error." + integer overflow (e.g. {{Int64.MinValue / -1}}) wraps around to + {{MinValue}}." fn = // Unsigned division can't overflow. Signed division overflows only on - // `MinValue / -1`. For Int32/Int64/Int128 that throws (caught by - // `overflowChecked`); for the narrow Int8/Int16 it silently wraps - // (division happens in Int32 space), so those need an explicit guard. + // `MinValue / -1`, whose wrapped result is `MinValue` itself. For the + // narrow Int8/Int16 the division happens in Int32 space and narrows + // back, wrapping naturally; for Int32/Int64/Int128 the hardware/runtime + // would throw, so we return `MinValue` explicitly. (function | _, vm, _, [ DInt8 a; DInt8 b ] -> - if b = 0y then divideByZero vm - elif a = System.SByte.MinValue && b = -1y then outOfRange vm - else Ply(DInt8(a / b)) + if b = 0y then divideByZero vm else Ply(DInt8(a / b)) | _, vm, _, [ DUInt8 a; DUInt8 b ] -> if b = 0uy then divideByZero vm else Ply(DUInt8(a / b)) | _, vm, _, [ DInt16 a; DInt16 b ] -> - if b = 0s then divideByZero vm - elif a = System.Int16.MinValue && b = -1s then outOfRange vm - else Ply(DInt16(a / b)) + if b = 0s then divideByZero vm else Ply(DInt16(a / b)) | _, vm, _, [ DUInt16 a; DUInt16 b ] -> if b = 0us then divideByZero vm else Ply(DUInt16(a / b)) | _, vm, _, [ DInt32 a; DInt32 b ] -> if b = 0l then divideByZero vm + elif a = System.Int32.MinValue && b = -1l then + Ply(DInt32 System.Int32.MinValue) else - overflowChecked vm (fun () -> DInt32(a / b)) + Ply(DInt32(a / b)) | _, vm, _, [ DUInt32 a; DUInt32 b ] -> if b = 0ul then divideByZero vm else Ply(DUInt32(a / b)) | _, vm, _, [ DInt64 a; DInt64 b ] -> if b = 0L then divideByZero vm + elif a = System.Int64.MinValue && b = -1L then + Ply(DInt64 System.Int64.MinValue) else - overflowChecked vm (fun () -> DInt64(a / b)) + Ply(DInt64(a / b)) | _, vm, _, [ DUInt64 a; DUInt64 b ] -> if b = 0UL then divideByZero vm else Ply(DUInt64(a / b)) | _, vm, _, [ DInt128 a; DInt128 b ] -> if b = System.Int128.Zero then divideByZero vm + elif a = System.Int128.MinValue && b = System.Int128.NegativeOne then + Ply(DInt128 System.Int128.MinValue) else - overflowChecked vm (fun () -> DInt128(a / b)) + Ply(DInt128(a / b)) | _, vm, _, [ DUInt128 a; DUInt128 b ] -> if b = System.UInt128.Zero then divideByZero vm else Ply(DUInt128(a / b)) | _, vm, _, [ DInt a; DInt b ] -> @@ -522,66 +502,41 @@ let fns () : List = "Raises a number to the power of another number of the same type. Supported for every integer type and Float (not Int128/UInt128). Integer exponents must be non-negative. Fixed-width integer overflow - raises a runtime error; the arbitrary-precision Int grows instead." + wraps around; the arbitrary-precision Int grows + instead." fn = + // Fixed-width powers wrap, so they use modular exponentiation + // (`powSigned`/`powUnsigned`) — this stays cheap even for huge + // exponents instead of building an enormous bigint. (function | _, vm, _, [ DInt8 number; DInt8 exp ] -> if exp < 0y then negativeExponent vm else - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> int8 |> DInt8) - | _, vm, _, [ DUInt8 number; DUInt8 exp ] -> - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> uint8 |> DUInt8) + Ply(DInt8(int8 (powSigned 8 (bigint number) (bigint exp)))) + | _, _, _, [ DUInt8 number; DUInt8 exp ] -> + Ply(DUInt8(uint8 (powUnsigned 8 (bigint number) (bigint exp)))) | _, vm, _, [ DInt16 number; DInt16 exp ] -> if exp < 0s then negativeExponent vm else - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> int16 |> DInt16) - | _, vm, _, [ DUInt16 number; DUInt16 exp ] -> - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> uint16 |> DUInt16) + Ply(DInt16(int16 (powSigned 16 (bigint number) (bigint exp)))) + | _, _, _, [ DUInt16 number; DUInt16 exp ] -> + Ply(DUInt16(uint16 (powUnsigned 16 (bigint number) (bigint exp)))) | _, vm, _, [ DInt32 number; DInt32 exp ] -> if exp < 0l then negativeExponent vm else - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> int32 |> DInt32) - | _, vm, _, [ DUInt32 number; DUInt32 exp ] -> - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> uint32 |> DUInt32) - | _, vm, _, [ DUInt64 number; DUInt64 exp ] -> - if exp > uint64 System.Int32.MaxValue then - match number with - | 0UL -> Ply(DUInt64 0UL) - | 1UL -> Ply(DUInt64 1UL) - | _ -> outOfRange vm - elif exp > 63UL && number > 1UL then - outOfRange vm - else - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> uint64 |> DUInt64) + Ply(DInt32(int32 (powSigned 32 (bigint number) (bigint exp)))) + | _, _, _, [ DUInt32 number; DUInt32 exp ] -> + Ply(DUInt32(uint32 (powUnsigned 32 (bigint number) (bigint exp)))) + | _, _, _, [ DUInt64 number; DUInt64 exp ] -> + Ply(DUInt64(uint64 (powUnsigned 64 (bigint number) (bigint exp)))) | _, vm, _, [ DInt64 number; DInt64 exp ] -> if exp < 0L then negativeExponent vm - elif exp > int64 System.Int32.MaxValue then - // `bigint ** int` needs an Int32 exponent; an exponent this large - // overflows Int64 unless the base is trivial. - match number with - | 0L -> Ply(DInt64 0L) - | 1L -> Ply(DInt64 1L) - | -1L -> Ply(DInt64(if exp % 2L = 0L then 1L else -1L)) - | _ -> outOfRange vm - elif exp > 63L && (number > 1L || number < -1L) then - // Avoid constructing enormous bigints that can never fit in Int64. - outOfRange vm else - // `int64` narrowing throws OverflowException when the result - // exceeds Int64 range. - overflowChecked vm (fun () -> - (bigint number) ** (int exp) |> int64 |> DInt64) + Ply(DInt64(int64 (powSigned 64 (bigint number) (bigint exp)))) | _, vm, _, [ DInt number; DInt exp ] -> let number = DarkInt.toBigInt number let exp = DarkInt.toBigInt exp @@ -616,7 +571,7 @@ let fns () : List = // Unary negation (`-x`). Supported for signed integer types and Float; - // negating the minimum signed value overflows and raises. + // negating the minimum signed value wraps back to itself. { name = fn "negate" 0 typeParams = [] parameters = [ Param.make "a" varA "" ] @@ -624,21 +579,11 @@ let fns () : List = description = "Returns the negation of , {{-a}}" fn = (function - | _, vm, _, [ DInt8 a ] -> - let result = -(int a) - if result < -128 || result > 127 then - outOfRange vm - else - Ply(DInt8(int8 result)) - | _, vm, _, [ DInt16 a ] -> - if a = System.Int16.MinValue then outOfRange vm else Ply(DInt16(-a)) - | _, vm, _, [ DInt32 a ] -> - if a = System.Int32.MinValue then outOfRange vm else Ply(DInt32(-a)) - | _, vm, _, [ DInt64 a ] -> - if a = System.Int64.MinValue then outOfRange vm else Ply(DInt64(-a)) - | _, vm, _, [ DInt128 a ] -> - overflowChecked vm (fun () -> - DInt128(System.Int128.op_CheckedUnaryNegation a)) + | _, _, _, [ DInt8 a ] -> Ply(DInt8(-a)) + | _, _, _, [ DInt16 a ] -> Ply(DInt16(-a)) + | _, _, _, [ DInt32 a ] -> Ply(DInt32(-a)) + | _, _, _, [ DInt64 a ] -> Ply(DInt64(-a)) + | _, _, _, [ DInt128 a ] -> Ply(DInt128(-a)) | _, _, _, [ DInt a ] -> Ply(DInt(DarkInt.negate a)) | _, _, _, [ DFloat a ] -> Ply(DFloat(-a)) | _, vm, _, [ a ] -> numericTypeError vm a a diff --git a/backend/src/Builtins/Builtins.Pure/Libs/UInt128.fs b/backend/src/Builtins/Builtins.Pure/Libs/UInt128.fs index f68202d17c..a83d8478f8 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/UInt128.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/UInt128.fs @@ -58,15 +58,11 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt128 ""; Param.make "b" TUInt128 "" ] returnType = TUInt128 - description = "Adds two 128-bit unsigned integers together" + description = + "Adds two 128-bit unsigned integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - try - let result = System.UInt128.op_CheckedAddition (a, b) - Ply(DUInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -78,15 +74,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt128 ""; Param.make "b" TUInt128 "" ] returnType = TUInt128 - description = "Subtracts two 128-bit unsigned integers" + description = "Subtracts two 128-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - try - let result = System.UInt128.op_CheckedSubtraction (a, b) - Ply(DUInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -99,15 +90,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt128 ""; Param.make "b" TUInt128 "" ] returnType = TUInt128 - description = "Multiplies two 128-bit unsigned integers" + description = "Multiplies two 128-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - try - let result = System.UInt128.op_CheckedMultiply (a, b) - Ply(DUInt128(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt128 a; DUInt128 b ] -> Ply(DUInt128(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -126,14 +112,10 @@ let fns () : List = fn = (function | _, vm, _, [ DUInt128 a; DUInt128 b ] -> - try - let result = System.UInt128.op_Division (a, b) - Ply(DUInt128(result)) - with - | :? System.DivideByZeroException -> + if b = System.UInt128.Zero then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID - | :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + else + Ply(DUInt128(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/UInt16.fs b/backend/src/Builtins/Builtins.Pure/Libs/UInt16.fs index e95df21170..b63b540a66 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/UInt16.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/UInt16.fs @@ -59,16 +59,11 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt16 ""; Param.make "b" TUInt16 "" ] returnType = TUInt16 - description = "Adds two 16-bit unsigned integers together" + description = + "Adds two 16-bit unsigned integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - try - let result = Checked.(+) a b - Ply(DUInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -80,16 +75,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt16 ""; Param.make "b" TUInt16 "" ] returnType = TUInt16 - description = "Subtracts two 16-bit unsigned integers" + description = "Subtracts two 16-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - try - let result = Checked.(-) a b - Ply(DUInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -101,16 +90,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt16 ""; Param.make "b" TUInt16 "" ] returnType = TUInt16 - description = "Multiplies two 16-bit unsigned integers" + description = "Multiplies two 16-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt16 a; DUInt16 b ] -> - try - let result = Checked.(*) a b - Ply(DUInt16(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - + | _, _, _, [ DUInt16 a; DUInt16 b ] -> Ply(DUInt16(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -125,14 +108,15 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function - | _, vm, _, [ DUInt16 number; DUInt16 exp ] -> - (try - (bigint number) ** (int exp) |> uint16 |> DUInt16 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + | _, _, _, [ DUInt16 number; DUInt16 exp ] -> + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 16) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + uint16 r |> DUInt16 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -151,14 +135,7 @@ let fns () : List = if b = 0us then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else - let result = a / b - if - result < System.UInt16.MinValue || result > System.UInt16.MaxValue - then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DUInt16(uint16 result)) - + Ply(DUInt16(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/UInt32.fs b/backend/src/Builtins/Builtins.Pure/Libs/UInt32.fs index 43595e9698..56c280e16b 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/UInt32.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/UInt32.fs @@ -59,15 +59,11 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt32 ""; Param.make "b" TUInt32 "" ] returnType = TUInt32 - description = "Adds two 32-bit unsigned integers together" + description = + "Adds two 32-bit unsigned integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - try - let result = Checked.(+) a b - Ply(DUInt32(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -79,15 +75,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt32 ""; Param.make "b" TUInt32 "" ] returnType = TUInt32 - description = "Subtracts two 32-bit unsigned integers" + description = "Subtracts two 32-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - try - let result = Checked.(-) a b - Ply(DUInt32(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -99,15 +90,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt32 ""; Param.make "b" TUInt32 "" ] returnType = TUInt32 - description = "Multiplies two 32-bit unsigned integers" + description = "Multiplies two 32-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt32 a; DUInt32 b ] -> - try - let result = Checked.(*) a b - Ply(DUInt32(result)) - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt32 a; DUInt32 b ] -> Ply(DUInt32(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -122,14 +108,15 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function - | _, vm, _, [ DUInt32 number; DUInt32 exp ] -> - (try - (bigint number) ** (int exp) |> uint32 |> DUInt32 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + | _, _, _, [ DUInt32 number; DUInt32 exp ] -> + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 32) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + uint32 r |> DUInt32 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -148,14 +135,7 @@ let fns () : List = if b = 0ul then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else - let result = a / b - if - result < System.UInt32.MinValue || result > System.UInt32.MaxValue - then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DUInt32(uint32 result)) - + Ply(DUInt32(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/UInt64.fs b/backend/src/Builtins/Builtins.Pure/Libs/UInt64.fs index 8b228ce289..4fb8c9a79f 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/UInt64.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/UInt64.fs @@ -58,14 +58,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt64 ""; Param.make "b" TUInt64 "" ] returnType = TUInt64 - description = "Adds 64-bit unsigned integers together" + description = "Adds 64-bit unsigned integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - try - DUInt64(Checked.(+) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -77,14 +73,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt64 ""; Param.make "b" TUInt64 "" ] returnType = TUInt64 - description = "Subtracts 64-bit unsigned integers" + description = "Subtracts 64-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - try - DUInt64(Checked.(-) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -96,14 +88,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt64 ""; Param.make "b" TUInt64 "" ] returnType = TUInt64 - description = "Multiplies 64-bit unsigned integers" + description = "Multiplies 64-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt64 a; DUInt64 b ] -> - try - DUInt64(Checked.(*) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt64 a; DUInt64 b ] -> Ply(DUInt64(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -118,29 +106,16 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function - | _, vm, _, [ DUInt64 number; DUInt64 exp ] -> - if exp > uint64 System.Int32.MaxValue then - // `bigint ** int` needs an Int32 exponent; an exponent this large - // overflows UInt64 unless the base is trivial. (Without this guard - // `int exp` silently truncates to a bogus — possibly negative — - // Int32, and `bigint ** negative` throws an uncaught exception.) - match number with - | 0UL -> Ply(DUInt64 0UL) - | 1UL -> Ply(DUInt64 1UL) - | _ -> RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - elif exp > 63UL && number > 1UL then - // Avoid constructing enormous bigints that can never fit in UInt64. - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - // `uint64` narrowing throws OverflowException when the result - // exceeds UInt64 range. - try - (bigint number) ** (int exp) |> uint64 |> DUInt64 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt64 number; DUInt64 exp ] -> + // wrap on overflow via modular exponentiation, which stays cheap even + // for huge exponents (no enormous bigint is built) + let m = System.Numerics.BigInteger.Pow(bigint 2, 64) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + uint64 r |> DUInt64 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -159,13 +134,7 @@ let fns () : List = if b = 0UL then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else - let result = a / b - if - result < System.UInt64.MinValue || result > System.UInt64.MaxValue - then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DUInt64(result)) + Ply(DUInt64(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/Builtins/Builtins.Pure/Libs/UInt8.fs b/backend/src/Builtins/Builtins.Pure/Libs/UInt8.fs index 91b622578c..22e9a47b3f 100644 --- a/backend/src/Builtins/Builtins.Pure/Libs/UInt8.fs +++ b/backend/src/Builtins/Builtins.Pure/Libs/UInt8.fs @@ -59,14 +59,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt8 ""; Param.make "b" TUInt8 "" ] returnType = TUInt8 - description = "Adds two 8-bit unsigned integers together" + description = "Adds two 8-bit unsigned integers together, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - try - DUInt8(Checked.(+) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a + b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -78,14 +74,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt8 ""; Param.make "b" TUInt8 "" ] returnType = TUInt8 - description = "Subtracts two 8-bit unsigned integers" + description = "Subtracts two 8-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - try - DUInt8(Checked.(-) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a - b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -97,14 +89,10 @@ let fns () : List = typeParams = [] parameters = [ Param.make "a" TUInt8 ""; Param.make "b" TUInt8 "" ] returnType = TUInt8 - description = "Multiplies two 8-bit unsigned integers" + description = "Multiplies two 8-bit unsigned integers, wrapping on overflow" fn = (function - | _, vm, _, [ DUInt8 a; DUInt8 b ] -> - try - DUInt8(Checked.(*) a b) |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID + | _, _, _, [ DUInt8 a; DUInt8 b ] -> Ply(DUInt8(a * b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -119,14 +107,15 @@ let fns () : List = description = "Raise to the power of . must to be positive. - Return value wrapped in a {{Result}} " + Overflow wraps around." fn = (function - | _, vm, _, [ DUInt8 number; DUInt8 exp ] -> - (try - (bigint number) ** (int exp) |> uint8 |> DUInt8 |> Ply - with :? System.OverflowException -> - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID) + | _, _, _, [ DUInt8 number; DUInt8 exp ] -> + // wrap on overflow via modular exponentiation + let m = System.Numerics.BigInteger.Pow(bigint 2, 8) + let r = System.Numerics.BigInteger.ModPow(bigint number, bigint exp, m) + let r = ((r % m) + m) % m + uint8 r |> DUInt8 |> Ply | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure @@ -145,11 +134,7 @@ let fns () : List = if b = 0uy then RTE.Ints.DivideByZeroError |> RTE.Int |> raiseRTE vm.threadID else - let result = int a / int b - if result < 0 || result > 255 then - RTE.Ints.OutOfRange |> RTE.Int |> raiseRTE vm.threadID - else - Ply(DUInt8(uint8 result)) + Ply(DUInt8(a / b)) | _ -> incorrectArgs ()) sqlSpec = NotYetImplemented previewable = Pure diff --git a/backend/src/LibExecution/RTQueryCompiler.fs b/backend/src/LibExecution/RTQueryCompiler.fs index ae8d789005..7e83ca8931 100644 --- a/backend/src/LibExecution/RTQueryCompiler.fs +++ b/backend/src/LibExecution/RTQueryCompiler.fs @@ -215,12 +215,28 @@ let rec symbolicToSql | RT.DInt64 n -> Ok(string n, state) // The arbitrary-precision `Int` is deliberately NOT queryable yet: SQLite has // no native bignum, so emitting it as a number would let values past 2^63 be - // compared as lossy floats (silently wrong). Reject loudly instead — use a - // sized type like `Int64` for indexed numeric fields. (A future order- - // preserving encoded projection will make `Int` queryable.) + // compared as lossy floats. Return a compile error instead — use a sized + // type like `Int64` for indexed numeric fields. (A future order-preserving + // encoded projection will make `Int` queryable.) | RT.DInt _ -> Error "The arbitrary-precision Int type is not yet queryable in DB.query. Use a sized integer type (e.g. Int64) for fields you filter or sort on." + // Only Int64 is currently serialized as a SQL number. Other fixed-width ints + // would be serialized as JSON-string parameters, which do not compare equal + // to the stored numeric values. Return a compile error until those types have + // SQL numeric serialization. UInt64/Int128/UInt128 also need a representation + // that preserves values past 2^63. + | RT.DInt8 _ + | RT.DUInt8 _ + | RT.DInt16 _ + | RT.DUInt16 _ + | RT.DInt32 _ + | RT.DUInt32 _ + | RT.DUInt64 _ + | RT.DInt128 _ + | RT.DUInt128 _ -> + Error + "Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." | RT.DFloat f -> Ok(string f, state) | RT.DString _ -> // Use a parameter to prevent SQL injection diff --git a/backend/testfiles/execution/cloud/db.dark b/backend/testfiles/execution/cloud/db.dark index 945349ac20..e29b043e39 100644 --- a/backend/testfiles/execution/cloud/db.dark +++ b/backend/testfiles/execution/cloud/db.dark @@ -29,6 +29,22 @@ type IntFields = { big: Int; sized: Int64 } [] type IntFieldsDB = IntFields +// One field per non-Int64 fixed-width int type, for asserting that querying +// them rejects loudly (rather than silently returning nothing). +type SizedInts = + { i8: Int8 + u8: UInt8 + i16: Int16 + u16: UInt16 + i32: Int32 + u32: UInt32 + u64: UInt64 + i128: Int128 + u128: UInt128 } + +[] +type SizedIntsDB = SizedInts + // simple data stores of Enums // , and Records containing Enums @@ -766,6 +782,19 @@ module FindAll = (Stdlib.DB.query IntFieldsDB (fun p -> p.big > 5I)) = sqlerror="The arbitrary-precision Int type is not yet queryable in DB.query. Use a sized integer type (e.g. Int64) for fields you filter or sort on." (Stdlib.DB.query IntFieldsDB (fun p -> p.sized > 5L)) = [] + // non-Int64 fixed-width ints also reject loudly: only Int64 is wired through + // as a real SQL number, so the rest would silently match nothing. Fail clearly + // instead. (One per type; equality and arithmetic both go through the literal.) + (Stdlib.DB.query SizedIntsDB (fun p -> p.i8 == 5y)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.u8 == 5uy)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.i16 == 5s)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.u16 == 5us)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.i32 == 5l)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.u32 + 1ul == 6ul)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.u64 == 5UL)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.i128 == 5Q)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + (Stdlib.DB.query SizedIntsDB (fun p -> p.u128 == 5Z)) = sqlerror="Only Int64 integer fields are queryable in DB.query for now. Use Int64 for fields you filter or sort on." + // storage is untouched: a >Int64 value round-trips through set/get fine // (it's only numeric *querying* that's restricted) (let _ = Stdlib.DB.set (IntFields { big = 9223372036854775808I; sized = 5L }) "k" IntFieldsDB diff --git a/backend/testfiles/execution/language/apply/einfix.dark b/backend/testfiles/execution/language/apply/einfix.dark index 09895ae62f..addd8937de 100644 --- a/backend/testfiles/execution/language/apply/einfix.dark +++ b/backend/testfiles/execution/language/apply/einfix.dark @@ -25,19 +25,19 @@ Stdlib.Int64.add_v0 5L 3L = 8L 5L + true = error="Cannot perform numeric operation on Int64 and Bool" 1L + 2.0 = error="Cannot perform numeric operation on Int64 and Float" -// Integer +,-,* overflow raises a runtime error (consistent with /, %, ^) -127y + 1y = error="Encountered out-of-range value for type of Int" -0uy - 1uy = error="Encountered out-of-range value for type of Int" -9223372036854775807L + 1L = error="Encountered out-of-range value for type of Int" -2L * 9223372036854775807L = error="Encountered out-of-range value for type of Int" -170141183460469231731687303715884105727Q + 1Q = error="Encountered out-of-range value for type of Int" -340282366920938463463374607431768211455Z + 1Z = error="Encountered out-of-range value for type of Int" -// Signed integer division overflow (MinValue / -1) raises rather than crashing -// or (for narrow widths) silently wrapping --9223372036854775808L / -1L = error="Encountered out-of-range value for type of Int" --128y / -1y = error="Encountered out-of-range value for type of Int" -2L ^ 64L = error="Encountered out-of-range value for type of Int" -(-9223372036854775808L) ^ 64L = error="Encountered out-of-range value for type of Int" +// Integer +,-,* overflow wraps around (two's complement) +127y + 1y = -128y +0uy - 1uy = 255uy +9223372036854775807L + 1L = -9223372036854775808L +2L * 9223372036854775807L = -2L +170141183460469231731687303715884105727Q + 1Q = -170141183460469231731687303715884105728Q +340282366920938463463374607431768211455Z + 1Z = 0Z +// Signed integer division overflow (MinValue / -1) wraps back to MinValue +-9223372036854775808L / -1L = -9223372036854775808L +-128y / -1y = -128y +// Power overflow wraps around (two's complement) +2L ^ 64L = 0L +(-9223372036854775808L) ^ 64L = 0L // Integer division by zero raises a clean RTE 10L / 0L = error="Cannot divide by 0" // Float overflow follows IEEE (infinity), not an error @@ -53,4 +53,4 @@ Stdlib.Int64.add_v0 5L 3L = 8L -(Stdlib.Float.add_v0 1.0 1.5) = -2.5 5L + (Builtin.testRuntimeError "error") = error="Uncaught exception: error" (Builtin.testRuntimeError "error") + 5L = error="Uncaught exception: error" -(Builtin.testRuntimeError "one") + (Builtin.testRuntimeError "two") = error="Uncaught exception: one" \ No newline at end of file +(Builtin.testRuntimeError "one") + (Builtin.testRuntimeError "two") = error="Uncaught exception: one" diff --git a/backend/testfiles/execution/stdlib/ints/int128.dark b/backend/testfiles/execution/stdlib/ints/int128.dark index 2e985c33ca..d4aa0c2124 100644 --- a/backend/testfiles/execution/stdlib/ints/int128.dark +++ b/backend/testfiles/execution/stdlib/ints/int128.dark @@ -1,7 +1,7 @@ Stdlib.Int128.absoluteValue_v0 -5Q = 5Q Stdlib.Int128.absoluteValue_v0 5Q = 5Q -Stdlib.Int128.absoluteValue_v0 -170141183460469231731687303715884105728Q = error="Encountered out-of-range value for type of Int" +Stdlib.Int128.absoluteValue_v0 -170141183460469231731687303715884105728Q = -170141183460469231731687303715884105728Q Stdlib.Int128.max_v0 5Q 6Q = 6Q Stdlib.Int128.max_v0 10Q 1Q = 10Q Stdlib.Int128.max_v0 -5Q 6Q = 6Q @@ -35,7 +35,7 @@ Stdlib.Int128.negate_v0 5Q = -5Q Stdlib.Int128.negate_v0 0Q = 0Q Stdlib.Int128.negate_v0 -0Q = 0Q -Stdlib.Int128.negate_v0 -170141183460469231731687303715884105728Q = error="Encountered out-of-range value for type of Int" +Stdlib.Int128.negate_v0 -170141183460469231731687303715884105728Q = -170141183460469231731687303715884105728Q Stdlib.Int128.remainder_v0 15Q 6Q = Stdlib.Result.Result.Ok 3Q Stdlib.Int128.remainder_v0 20Q 8Q = Stdlib.Result.Result.Ok 4Q Stdlib.Int128.remainder_v0 -20Q 8Q = Stdlib.Result.Result.Ok -4Q @@ -50,14 +50,14 @@ Stdlib.Int128.add_v0 -55Q 55Q = 0Q Stdlib.Int128.add_v0 55Q 55Q = 110Q Stdlib.Int128.add_v0 9223372036854775807Q 2Q = 9223372036854775809Q -Stdlib.Int128.add_v0 170141183460469231731687303715884105726Q 4Q = error="Encountered out-of-range value for type of Int" +Stdlib.Int128.add_v0 170141183460469231731687303715884105726Q 4Q = -170141183460469231731687303715884105726Q Stdlib.Int128.subtract_v0 10Q 9Q = 1Q Stdlib.Int128.subtract_v0 88Q 9Q = 79Q Stdlib.Int128.subtract_v0 0Q 1Q = -1Q Stdlib.Int128.subtract_v0 1Q 0Q = 1Q Stdlib.Int128.subtract_v0 -55Q -55Q = 0Q -Stdlib.Int128.subtract_v0 -55Q 170141183460469231731687303715884105726Q = error="Encountered out-of-range value for type of Int" +Stdlib.Int128.subtract_v0 -55Q 170141183460469231731687303715884105726Q = 170141183460469231731687303715884105675Q Stdlib.Int128.multiply_v0 8Q 8Q = 64Q Stdlib.Int128.multiply_v0 1Q 0Q = 0Q @@ -67,7 +67,7 @@ Stdlib.Int128.divide_v0 -8Q 5Q = -1Q Stdlib.Int128.divide_v0 0Q 1Q = 0Q Stdlib.Int128.divide_v0 1Q 0Q = error="Cannot divide by 0" -Stdlib.Int128.divide_v0 -170141183460469231731687303715884105728Q -1Q = error="Encountered out-of-range value for type of Int" +Stdlib.Int128.divide_v0 -170141183460469231731687303715884105728Q -1Q = -170141183460469231731687303715884105728Q Stdlib.Int128.greaterThan_v0 20Q 1Q = true Stdlib.Int128.greaterThan_v0 20Q 170141183460469231731687303715884105727Q = false @@ -218,4 +218,4 @@ Stdlib.Int128.shiftRight 8Q 2Q = 2Q Stdlib.Int128.shiftRight 0Q 5Q = 0Q Stdlib.Int128.shiftRight 1Q 0Q = 1Q Stdlib.Int128.shiftRight (-1Q) 1Q = -1Q -Stdlib.Int128.shiftRight 40Q 3Q = 5Q \ No newline at end of file +Stdlib.Int128.shiftRight 40Q 3Q = 5Q diff --git a/backend/testfiles/execution/stdlib/ints/int16.dark b/backend/testfiles/execution/stdlib/ints/int16.dark index 9753cdf24e..286e9767de 100644 --- a/backend/testfiles/execution/stdlib/ints/int16.dark +++ b/backend/testfiles/execution/stdlib/ints/int16.dark @@ -1,6 +1,6 @@ Stdlib.Int16.absoluteValue_v0 -5s = 5s Stdlib.Int16.absoluteValue_v0 5s = 5s -Stdlib.Int16.absoluteValue_v0 -32768s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.absoluteValue_v0 -32768s = -32768s Stdlib.Int16.clamp_v0 -5s -2s 5s = -2s Stdlib.Int16.clamp_v0 -3s -2s 1s = -2s Stdlib.Int16.clamp_v0 -5s 1s 1s = 1s @@ -32,17 +32,17 @@ Stdlib.Int16.add_v0 1s 0s = 1s Stdlib.Int16.add_v0 -55s 55s = 0s Stdlib.Int16.add_v0 30000s 2767s = 32767s Stdlib.Int16.add_v0 -30000s -2768s = -32768s -Stdlib.Int16.add_v0 -30000s -2769s = error="Encountered out-of-range value for type of Int" -Stdlib.Int16.add_v0 30000s 2768s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.add_v0 -30000s -2769s = 32767s +Stdlib.Int16.add_v0 30000s 2768s = -32768s Stdlib.Int16.subtract_v0 10s 9s = 1s Stdlib.Int16.subtract_v0 88s 9s = 79s Stdlib.Int16.subtract_v0 0s 1s = -1s Stdlib.Int16.subtract_v0 1s 0s = 1s Stdlib.Int16.subtract_v0 -55s -55s = 0s -Stdlib.Int16.subtract_v0 -2769s 30000s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.subtract_v0 -2769s 30000s = 32767s Stdlib.Int16.multiply_v0 8s 8s = 64s Stdlib.Int16.multiply_v0 1s 0s = 0s -Stdlib.Int16.multiply_v0 5145s 5145s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.multiply_v0 5145s 5145s = -5519s Stdlib.Int16.power_v0 2s 3s = 8s Stdlib.Int16.power_v0 0s 1s = 0s Stdlib.Int16.power_v0 1s 0s = 1s @@ -51,15 +51,15 @@ Stdlib.Int16.power_v0 -2s 5s = -32s Stdlib.Int16.power_v0 -1s 5s = -1s Stdlib.Int16.power_v0 -1s 6s = 1s Stdlib.Int16.power_v0 1s 32767s = 1s -Stdlib.Int16.power_v0 2s 15s = error="Encountered out-of-range value for type of Int" -Stdlib.Int16.power_v0 120s 20s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.power_v0 2s 15s = -32768s +Stdlib.Int16.power_v0 120s 20s = 0s Stdlib.Int16.power_v0 2s -3s = error="Cannot raise integer to a negative exponent" Stdlib.Int16.divide_v0 10s 5s = 2s Stdlib.Int16.divide_v0 17s 3s = 5s Stdlib.Int16.divide_v0 -8s 5s = -1s Stdlib.Int16.divide_v0 0s 1s = 0s Stdlib.Int16.divide_v0 1s 0s = error="Cannot divide by 0" -Stdlib.Int16.divide_v0 -32768s -1s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.divide_v0 -32768s -1s = -32768s Stdlib.Int16.divide_v0 -32768s 1s = -32768s @@ -67,7 +67,7 @@ Stdlib.Int16.negate_v0 -5s = 5s Stdlib.Int16.negate_v0 5s = -5s Stdlib.Int16.negate_v0 0s = 0s Stdlib.Int16.negate_v0 -0s = 0s -Stdlib.Int16.negate_v0 -32768s = error="Encountered out-of-range value for type of Int" +Stdlib.Int16.negate_v0 -32768s = -32768s Stdlib.Int16.greaterThan_v0 20s 1s = true Stdlib.Int16.greaterThan_v0 20s 130s = false @@ -259,4 +259,4 @@ Stdlib.Int16.shiftRight 0s 5s = 0s Stdlib.Int16.shiftRight 1s 0s = 1s Stdlib.Int16.shiftRight 16384s 14s = 1s Stdlib.Int16.shiftRight (-1s) 1s = -1s -Stdlib.Int16.shiftRight 40s 3s = 5s \ No newline at end of file +Stdlib.Int16.shiftRight 40s 3s = 5s diff --git a/backend/testfiles/execution/stdlib/ints/int32.dark b/backend/testfiles/execution/stdlib/ints/int32.dark index 4d570b39e2..200426af54 100644 --- a/backend/testfiles/execution/stdlib/ints/int32.dark +++ b/backend/testfiles/execution/stdlib/ints/int32.dark @@ -1,6 +1,6 @@ Stdlib.Int32.absoluteValue_v0 -5l = 5l Stdlib.Int32.absoluteValue_v0 5l = 5l -Stdlib.Int32.absoluteValue_v0 (-2147483648l) = error="Encountered out-of-range value for type of Int" +Stdlib.Int32.absoluteValue_v0 (-2147483648l) = -2147483648l Stdlib.Int32.max_v0 5l 6l = 6l Stdlib.Int32.max_v0 10l 1l = 10l @@ -34,7 +34,7 @@ Stdlib.Int32.negate_v0 -5l = 5l Stdlib.Int32.negate_v0 5l = -5l Stdlib.Int32.negate_v0 0l = 0l Stdlib.Int32.negate_v0 -0l = 0l -Stdlib.Int32.negate_v0 (-2147483648l) = error="Encountered out-of-range value for type of Int" +Stdlib.Int32.negate_v0 (-2147483648l) = -2147483648l Stdlib.Int32.remainder_v0 15l 6l = Stdlib.Result.Result.Ok 3l Stdlib.Int32.remainder_v0 20l 8l = Stdlib.Result.Result.Ok 4l @@ -58,8 +58,8 @@ Stdlib.Int32.power_v0 -2l 5l = -32l Stdlib.Int32.power_v0 -1l 5l = -1l Stdlib.Int32.power_v0 -1l 6l = 1l Stdlib.Int32.power_v0 1l 2147483647l = 1l -Stdlib.Int32.power_v0 2l 31l = error="Encountered out-of-range value for type of Int" -Stdlib.Int32.power_v0 120l 20l = error="Encountered out-of-range value for type of Int" +Stdlib.Int32.power_v0 2l 31l = -2147483648l +Stdlib.Int32.power_v0 120l 20l = 0l Stdlib.Int32.power_v0 2l -3l = error="Cannot raise integer to a negative exponent" Stdlib.Int32.greaterThan_v0 20l 1l = true @@ -103,9 +103,9 @@ Stdlib.Int32.add_v0 -55l 55l = 0l Stdlib.Int32.add_v0 2147483646l 1l = 2147483647l // Overflow tests -Stdlib.Int32.add_v0 2147483647l 1l = error="Encountered out-of-range value for type of Int" -Stdlib.Int32.add_v0 55l 2147483647l = error="Encountered out-of-range value for type of Int" -Stdlib.Int32.add_v0 -2147483648l -1l = error="Encountered out-of-range value for type of Int" +Stdlib.Int32.add_v0 2147483647l 1l = -2147483648l +Stdlib.Int32.add_v0 55l 2147483647l = -2147483594l +Stdlib.Int32.add_v0 -2147483648l -1l = 2147483647l Stdlib.Int32.subtract_v0 10l 9l = 1l @@ -123,7 +123,7 @@ Stdlib.Int32.divide_v0 -8l 5l = -1l Stdlib.Int32.divide_v0 0l 1l = 0l Stdlib.Int32.divide_v0 1l 0l = error="Cannot divide by 0" -Stdlib.Int32.divide_v0 (-2147483648l) -1l = error="Encountered out-of-range value for type of Int" +Stdlib.Int32.divide_v0 (-2147483648l) -1l = -2147483648l (Stdlib.List.range_v0 1L 5L) |> Stdlib.List.map_v0 (fun x -> Stdlib.Int32.random 1l 2l) |> Stdlib.List.map_v0 (fun x -> @@ -287,4 +287,4 @@ Stdlib.Int32.shiftRight 0l 5l = 0l Stdlib.Int32.shiftRight 1l 0l = 1l Stdlib.Int32.shiftRight 1073741824l 30l = 1l Stdlib.Int32.shiftRight (-1l) 1l = -1l -Stdlib.Int32.shiftRight 40l 3l = 5l \ No newline at end of file +Stdlib.Int32.shiftRight 40l 3l = 5l diff --git a/backend/testfiles/execution/stdlib/ints/int64.dark b/backend/testfiles/execution/stdlib/ints/int64.dark index 05dcc4d869..f002bbc737 100644 --- a/backend/testfiles/execution/stdlib/ints/int64.dark +++ b/backend/testfiles/execution/stdlib/ints/int64.dark @@ -1,6 +1,6 @@ Stdlib.Int64.absoluteValue_v0 -5L = 5L Stdlib.Int64.absoluteValue_v0 5L = 5L -Stdlib.Int64.absoluteValue_v0 (-9223372036854775808L) = error="Encountered out-of-range value for type of Int" +Stdlib.Int64.absoluteValue_v0 (-9223372036854775808L) = -9223372036854775808L Stdlib.Int64.max_v0 5L 6L = 6L Stdlib.Int64.max_v0 10L 1L = 10L @@ -34,7 +34,7 @@ Stdlib.Int64.negate_v0 -5L = 5L Stdlib.Int64.negate_v0 5L = -5L Stdlib.Int64.negate_v0 0L = 0L Stdlib.Int64.negate_v0 -0L = 0L -Stdlib.Int64.negate_v0 (-9223372036854775808L) = error="Encountered out-of-range value for type of Int" +Stdlib.Int64.negate_v0 (-9223372036854775808L) = -9223372036854775808L Stdlib.Int64.remainder_v0 15L 6L = Stdlib.Result.Result.Ok 3L Stdlib.Int64.remainder_v0 20L 8L = Stdlib.Result.Result.Ok 4L @@ -94,14 +94,14 @@ Stdlib.Int64.power_v0 0L 0L = 1L Stdlib.Int64.power_v0 1L 0L = 1L Stdlib.Int64.power_v0 1000L 0L = 1L Stdlib.Int64.power_v0 -8L 5L = -32768L -Stdlib.Int64.power_v0 200L 20L = error="Encountered out-of-range value for type of Int" +Stdlib.Int64.power_v0 200L 20L = 1152921504606846976L Stdlib.Int64.power_v0 200L 7L = 12800000000000000L Stdlib.Int64.power_v0 1L 2147483649L = 1L Stdlib.Int64.power_v0 -1L 2147483649L = -1L -// Non-trivial base with an out-of-Int32-range exponent overflows rather than -// crashing on the internal `bigint ** (int exp)` narrowing. -Stdlib.Int64.power_v0 2L 2147483649L = error="Encountered out-of-range value for type of Int" -Stdlib.Int64.power_v0 2L 64L = error="Encountered out-of-range value for type of Int" +// Non-trivial base with a huge (out-of-Int32-range) exponent wraps via modular +// exponentiation, which stays cheap instead of building an enormous bigint. +Stdlib.Int64.power_v0 2L 2147483649L = 0L +Stdlib.Int64.power_v0 2L 64L = 0L Stdlib.Int64.power_v0 2L -3L = error="Cannot raise integer to a negative exponent" 5L ^ 2L = 25L -8L ^ 5L = -32768L @@ -173,9 +173,9 @@ Stdlib.Int64.add_v0 -55L 55L = 0L Stdlib.Int64.add_v0 9223372036854775806L 1L = 9223372036854775807L // Overflow tests -Stdlib.Int64.add_v0 9223372036854775807L 1L = error="Encountered out-of-range value for type of Int" -Stdlib.Int64.add_v0 55L 9223372036854775807L = error="Encountered out-of-range value for type of Int" -Stdlib.Int64.add_v0 (-9223372036854775808L) (-1L) = error="Encountered out-of-range value for type of Int" +Stdlib.Int64.add_v0 9223372036854775807L 1L = -9223372036854775808L +Stdlib.Int64.add_v0 55L 9223372036854775807L = -9223372036854775754L +Stdlib.Int64.add_v0 (-9223372036854775808L) (-1L) = 9223372036854775807L -2000L + 1950L = -50L -1993L + 2000L = 7L @@ -205,7 +205,7 @@ Stdlib.Int64.divide_v0 -8L 5L = -1L Stdlib.Int64.divide_v0 0L 1L = 0L Stdlib.Int64.divide_v0 1L 0L = error="Cannot divide by 0" -Stdlib.Int64.divide_v0 (-9223372036854775808L) -1L = error="Encountered out-of-range value for type of Int" +Stdlib.Int64.divide_v0 (-9223372036854775808L) -1L = -9223372036854775808L (Stdlib.List.range_v0 1L 5L) |> Stdlib.List.map_v0 (fun x -> Stdlib.Int64.random 1L 2L) |> Stdlib.List.map_v0 (fun x -> (x >= 1L) && (x <= 2L)) = [ true; true; true; true; true ] @@ -364,4 +364,4 @@ Stdlib.Int64.shiftRight 0L 5L = 0L Stdlib.Int64.shiftRight 1L 0L = 1L Stdlib.Int64.shiftRight 4611686018427387904L 62L = 1L Stdlib.Int64.shiftRight (-1L) 1L = -1L -Stdlib.Int64.shiftRight 40L 3L = 5L \ No newline at end of file +Stdlib.Int64.shiftRight 40L 3L = 5L diff --git a/backend/testfiles/execution/stdlib/ints/int8.dark b/backend/testfiles/execution/stdlib/ints/int8.dark index fd2ef226a2..3f5e491a77 100644 --- a/backend/testfiles/execution/stdlib/ints/int8.dark +++ b/backend/testfiles/execution/stdlib/ints/int8.dark @@ -1,7 +1,7 @@ Stdlib.Int8.absoluteValue_v0 -5y = 5y Stdlib.Int8.absoluteValue_v0 5y = 5y -Stdlib.Int8.absoluteValue_v0 -128y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.absoluteValue_v0 -128y = -128y Stdlib.Int8.max_v0 5y 6y = 6y Stdlib.Int8.max_v0 10y 1y = 10y Stdlib.Int8.max_v0 -5y 6y = 6y @@ -30,7 +30,7 @@ Stdlib.Int8.negate_v0 -5y = 5y Stdlib.Int8.negate_v0 5y = -5y Stdlib.Int8.negate_v0 0y = 0y Stdlib.Int8.negate_v0 -0y = 0y -Stdlib.Int8.negate_v0 -128y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.negate_v0 -128y = -128y Stdlib.Int8.remainder_v0 15y 6y = Stdlib.Result.Result.Ok 3y Stdlib.Int8.remainder_v0 20y 8y = Stdlib.Result.Result.Ok 4y Stdlib.Int8.remainder_v0 -20y 8y = Stdlib.Result.Result.Ok -4y @@ -45,21 +45,21 @@ Stdlib.Int8.add_v0 1y 0y = 1y Stdlib.Int8.add_v0 -55y 55y = 0y Stdlib.Int8.add_v0 55y 55y = 110y Stdlib.Int8.add_v0 Darklang.Test.Values.int8Value 5y = 10y -Stdlib.Int8.add_v0 127y 1y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.add_v0 -128y -1y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.add_v0 -100y -30y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.add_v0 100y 30y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.add_v0 127y 1y = -128y +Stdlib.Int8.add_v0 -128y -1y = 127y +Stdlib.Int8.add_v0 -100y -30y = 126y +Stdlib.Int8.add_v0 100y 30y = -126y Stdlib.Int8.subtract_v0 10y 9y = 1y Stdlib.Int8.subtract_v0 88y 9y = 79y Stdlib.Int8.subtract_v0 0y 1y = -1y Stdlib.Int8.subtract_v0 1y 0y = 1y Stdlib.Int8.subtract_v0 -55y -55y = 0y -Stdlib.Int8.subtract_v0 -2y 127y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.subtract_v0 -55y 100y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.subtract_v0 -2y 127y = 127y +Stdlib.Int8.subtract_v0 -55y 100y = 101y Stdlib.Int8.multiply_v0 8y 8y = 64y Stdlib.Int8.multiply_v0 1y 0y = 0y -Stdlib.Int8.multiply_v0 64y 2y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.multiply_v0 -128y -1y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.multiply_v0 64y 2y = -128y +Stdlib.Int8.multiply_v0 -128y -1y = -128y Stdlib.Int8.power_v0 2y 3y = 8y Stdlib.Int8.power_v0 0y 1y = 0y Stdlib.Int8.power_v0 1y 0y = 1y @@ -68,15 +68,15 @@ Stdlib.Int8.power_v0 -2y 5y = -32y Stdlib.Int8.power_v0 -1y 5y = -1y Stdlib.Int8.power_v0 -1y 6y = 1y Stdlib.Int8.power_v0 1y 127y = 1y -Stdlib.Int8.power_v0 3y 5y = error="Encountered out-of-range value for type of Int" -Stdlib.Int8.power_v0 120y 20y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.power_v0 3y 5y = -13y +Stdlib.Int8.power_v0 120y 20y = 0y Stdlib.Int8.power_v0 2y -3y = error="Cannot raise integer to a negative exponent" Stdlib.Int8.divide_v0 10y 5y = 2y Stdlib.Int8.divide_v0 17y 3y = 5y Stdlib.Int8.divide_v0 -8y 5y = -1y Stdlib.Int8.divide_v0 0y 1y = 0y Stdlib.Int8.divide_v0 1y 0y = error="Cannot divide by 0" -Stdlib.Int8.divide_v0 -128y -1y = error="Encountered out-of-range value for type of Int" +Stdlib.Int8.divide_v0 -128y -1y = -128y Stdlib.Int8.greaterThan_v0 20y 1y = true Stdlib.Int8.greaterThan_v0 20y 127y = false @@ -291,4 +291,4 @@ Stdlib.Int8.shiftRight 0y 5y = 0y Stdlib.Int8.shiftRight 1y 0y = 1y Stdlib.Int8.shiftRight 64y 6y = 1y Stdlib.Int8.shiftRight (-1y) 1y = -1y -Stdlib.Int8.shiftRight 40y 3y = 5y \ No newline at end of file +Stdlib.Int8.shiftRight 40y 3y = 5y diff --git a/backend/testfiles/execution/stdlib/ints/uint128.dark b/backend/testfiles/execution/stdlib/ints/uint128.dark index 7afd9ebf6a..d8c1004a21 100644 --- a/backend/testfiles/execution/stdlib/ints/uint128.dark +++ b/backend/testfiles/execution/stdlib/ints/uint128.dark @@ -19,7 +19,7 @@ Stdlib.UInt128.add_v0 9223372036854775807Z 2Z = 9223372036854775809Z Stdlib.UInt128.add_v0 170141183460469231731687303715884105726Z 4Z = 170141183460469231731687303715884105730Z -Stdlib.UInt128.add_v0 340282366920938463463374607431768211455Z 1Z = error="Encountered out-of-range value for type of Int" +Stdlib.UInt128.add_v0 340282366920938463463374607431768211455Z 1Z = 0Z Stdlib.UInt128.subtract_v0 10Z 9Z = 1Z Stdlib.UInt128.subtract_v0 88Z 9Z = 79Z Stdlib.UInt128.subtract_v0 1Z 0Z = 1Z @@ -27,7 +27,7 @@ Stdlib.UInt128.subtract_v0 1Z 0Z = 1Z Stdlib.UInt128.multiply_v0 8Z 8Z = 64Z Stdlib.UInt128.multiply_v0 1Z 0Z = 0Z -Stdlib.UInt128.multiply_v0 340282366920938463463374607431768211455Z 2Z = error="Encountered out-of-range value for type of Int" +Stdlib.UInt128.multiply_v0 340282366920938463463374607431768211455Z 2Z = 340282366920938463463374607431768211454Z Stdlib.UInt128.divide_v0 10Z 5Z = 2Z Stdlib.UInt128.divide_v0 17Z 3Z = 5Z Stdlib.UInt128.divide_v0 0Z 1Z = 0Z @@ -141,4 +141,4 @@ Stdlib.UInt128.shiftLeft 5Z 3Z = 40Z Stdlib.UInt128.shiftRight 8Z 2Z = 2Z Stdlib.UInt128.shiftRight 0Z 5Z = 0Z Stdlib.UInt128.shiftRight 1Z 0Z = 1Z -Stdlib.UInt128.shiftRight 40Z 3Z = 5Z \ No newline at end of file +Stdlib.UInt128.shiftRight 40Z 3Z = 5Z diff --git a/backend/testfiles/execution/stdlib/ints/uint16.dark b/backend/testfiles/execution/stdlib/ints/uint16.dark index ea57f603b4..d9ecfb5c20 100644 --- a/backend/testfiles/execution/stdlib/ints/uint16.dark +++ b/backend/testfiles/execution/stdlib/ints/uint16.dark @@ -19,11 +19,11 @@ Stdlib.UInt16.add_v0 88us 9us = 97us Stdlib.UInt16.add_v0 1us 0us = 1us Stdlib.UInt16.add_v0 65534us 1us = 65535us -Stdlib.UInt16.add_v0 65535us 1us = error="Encountered out-of-range value for type of Int" +Stdlib.UInt16.add_v0 65535us 1us = 0us Stdlib.UInt16.subtract_v0 10us 9us = 1us Stdlib.UInt16.subtract_v0 88us 9us = 79us -Stdlib.UInt16.subtract_v0 0us 1us = error="Encountered out-of-range value for type of Int" +Stdlib.UInt16.subtract_v0 0us 1us = 65535us Stdlib.UInt16.subtract_v0 1us 0us = 1us Stdlib.UInt16.subtract_v0 65535us 1us = 65534us @@ -31,15 +31,15 @@ Stdlib.UInt16.multiply_v0 8us 8us = 64us Stdlib.UInt16.multiply_v0 8us 0us = 0us Stdlib.UInt16.multiply_v0 32767us 2us = 65534us -Stdlib.UInt16.multiply_v0 32768us 2us = error="Encountered out-of-range value for type of Int" -Stdlib.UInt16.multiply_v0 65535us 2us = error="Encountered out-of-range value for type of Int" +Stdlib.UInt16.multiply_v0 32768us 2us = 0us +Stdlib.UInt16.multiply_v0 65535us 2us = 65534us Stdlib.UInt16.power_v0 2us 3us = 8us Stdlib.UInt16.power_v0 0us 1us = 0us Stdlib.UInt16.power_v0 1us 0us = 1us Stdlib.UInt16.power_v0 0us 0us = 1us Stdlib.UInt16.power_v0 1us 255us = 1us -Stdlib.UInt16.power_v0 256us 2us = error="Encountered out-of-range value for type of Int" +Stdlib.UInt16.power_v0 256us 2us = 0us Stdlib.UInt16.divide_v0 10us 5us = 2us Stdlib.UInt16.divide_v0 17us 3us = 5us Stdlib.UInt16.divide_v0 8us 5us = 1us @@ -125,8 +125,7 @@ Stdlib.UInt16.mod_v0 5us 0us = error="Cannot evaluate modulus against 0" Stdlib.UInt16.sum_v0 [ 1us; 2us ] = 3us -Stdlib.UInt16.sum_v0 [ 1us; 65535us ] = error="Encountered out-of-range value for type of Int" -// out of range +Stdlib.UInt16.sum_v0 [ 1us; 65535us ] = 0us // wraps on overflow Stdlib.UInt16.parse_v0 "-129" = Stdlib.Result.Result.Error Stdlib.UInt16.ParseError.OutOfRange Stdlib.UInt16.parse_v0 "65536" = Stdlib.Result.Result.Error Stdlib.UInt16.ParseError.OutOfRange @@ -223,4 +222,4 @@ Stdlib.UInt16.shiftRight 8us 2us = 2us Stdlib.UInt16.shiftRight 0us 5us = 0us Stdlib.UInt16.shiftRight 1us 0us = 1us Stdlib.UInt16.shiftRight 32768us 15us = 1us -Stdlib.UInt16.shiftRight 40us 3us = 5us \ No newline at end of file +Stdlib.UInt16.shiftRight 40us 3us = 5us diff --git a/backend/testfiles/execution/stdlib/ints/uint32.dark b/backend/testfiles/execution/stdlib/ints/uint32.dark index 90a69e8129..6b3be89296 100644 --- a/backend/testfiles/execution/stdlib/ints/uint32.dark +++ b/backend/testfiles/execution/stdlib/ints/uint32.dark @@ -19,11 +19,11 @@ Stdlib.UInt32.add_v0 88ul 9ul = 97ul Stdlib.UInt32.add_v0 1ul 0ul = 1ul Stdlib.UInt32.add_v0 4294967294ul 1ul = 4294967295ul -Stdlib.UInt32.add_v0 4294967295ul 1ul = error="Encountered out-of-range value for type of Int" +Stdlib.UInt32.add_v0 4294967295ul 1ul = 0ul Stdlib.UInt32.subtract_v0 10ul 9ul = 1ul Stdlib.UInt32.subtract_v0 88ul 9ul = 79ul -Stdlib.UInt32.subtract_v0 0ul 1ul = error="Encountered out-of-range value for type of Int" +Stdlib.UInt32.subtract_v0 0ul 1ul = 4294967295ul Stdlib.UInt32.subtract_v0 1ul 0ul = 1ul Stdlib.UInt32.subtract_v0 4294967295ul 1ul = 4294967294ul @@ -31,14 +31,14 @@ Stdlib.UInt32.multiply_v0 8ul 8ul = 64ul Stdlib.UInt32.multiply_v0 8ul 0ul = 0ul Stdlib.UInt32.multiply_v0 2147483647ul 2ul = 4294967294ul -Stdlib.UInt32.multiply_v0 2147483648ul 2ul = error="Encountered out-of-range value for type of Int" +Stdlib.UInt32.multiply_v0 2147483648ul 2ul = 0ul Stdlib.UInt32.power_v0 2ul 3ul = 8ul Stdlib.UInt32.power_v0 0ul 1ul = 0ul Stdlib.UInt32.power_v0 1ul 0ul = 1ul Stdlib.UInt32.power_v0 0ul 0ul = 1ul Stdlib.UInt32.power_v0 1ul 255ul = 1ul -Stdlib.UInt32.power_v0 65536ul 2ul = error="Encountered out-of-range value for type of Int" +Stdlib.UInt32.power_v0 65536ul 2ul = 0ul Stdlib.UInt32.divide_v0 10ul 5ul = 2ul Stdlib.UInt32.divide_v0 17ul 3ul = 5ul Stdlib.UInt32.divide_v0 8ul 5ul = 1ul @@ -124,8 +124,7 @@ Stdlib.UInt32.mod_v0 5ul 0ul = error="Cannot evaluate modulus against 0" Stdlib.UInt32.sum_v0 [ 1ul; 2ul ] = 3ul -Stdlib.UInt32.sum_v0 [ 1ul; 4294967295ul ] = error="Encountered out-of-range value for type of Int" -// out of range +Stdlib.UInt32.sum_v0 [ 1ul; 4294967295ul ] = 0ul // wraps on overflow Stdlib.UInt32.parse_v0 "-129" = Stdlib.Result.Result.Error Stdlib.UInt32.ParseError.OutOfRange Stdlib.UInt32.parse_v0 "4294967296" = Stdlib.Result.Result.Error Stdlib.UInt32.ParseError.OutOfRange @@ -219,4 +218,4 @@ Stdlib.UInt32.shiftRight 8ul 2ul = 2ul Stdlib.UInt32.shiftRight 0ul 5ul = 0ul Stdlib.UInt32.shiftRight 1ul 0ul = 1ul Stdlib.UInt32.shiftRight 2147483648ul 31ul = 1ul -Stdlib.UInt32.shiftRight 40ul 3ul = 5ul \ No newline at end of file +Stdlib.UInt32.shiftRight 40ul 3ul = 5ul diff --git a/backend/testfiles/execution/stdlib/ints/uint64.dark b/backend/testfiles/execution/stdlib/ints/uint64.dark index 0965c170d4..379327c99d 100644 --- a/backend/testfiles/execution/stdlib/ints/uint64.dark +++ b/backend/testfiles/execution/stdlib/ints/uint64.dark @@ -22,14 +22,14 @@ Stdlib.UInt64.power_v0 0UL 0UL = 1UL Stdlib.UInt64.power_v0 1UL 0UL = 1UL Stdlib.UInt64.power_v0 1000UL 0UL = 1UL -Stdlib.UInt64.power_v0 200UL 20UL = error="Encountered out-of-range value for type of Int" +Stdlib.UInt64.power_v0 200UL 20UL = 1152921504606846976UL Stdlib.UInt64.power_v0 200UL 7UL = 12800000000000000UL Stdlib.UInt64.power_v0 1UL 2147483649UL = 1UL -// Non-trivial base with an out-of-Int32-range exponent overflows rather than -// crashing on the internal `bigint ** (int exp)` narrowing. -Stdlib.UInt64.power_v0 2UL 2147483649UL = error="Encountered out-of-range value for type of Int" -Stdlib.UInt64.power_v0 2UL 64UL = error="Encountered out-of-range value for type of Int" +// Non-trivial base with a huge (out-of-Int32-range) exponent wraps via modular +// exponentiation, which stays cheap instead of building an enormous bigint. +Stdlib.UInt64.power_v0 2UL 2147483649UL = 0UL +Stdlib.UInt64.power_v0 2UL 64UL = 0UL Stdlib.UInt64.greaterThan_v0 20UL 1UL = true @@ -64,8 +64,8 @@ Stdlib.UInt64.add_v0 1UL 0UL = 1UL Stdlib.UInt64.add_v0 18446744073709551614UL 1UL = 18446744073709551615UL // Overflow tests -Stdlib.UInt64.add_v0 18446744073709551615UL 1UL = error="Encountered out-of-range value for type of Int" -Stdlib.UInt64.add_v0 55UL 18446744073709551615UL = error="Encountered out-of-range value for type of Int" +Stdlib.UInt64.add_v0 18446744073709551615UL 1UL = 0UL +Stdlib.UInt64.add_v0 55UL 18446744073709551615UL = 54UL Stdlib.UInt64.subtract_v0 10UL 9UL = 1UL Stdlib.UInt64.subtract_v0 88UL 9UL = 79UL Stdlib.UInt64.subtract_v0 1UL 0UL = 1UL @@ -73,7 +73,7 @@ Stdlib.UInt64.subtract_v0 1UL 0UL = 1UL Stdlib.UInt64.multiply_v0 8UL 8UL = 64UL Stdlib.UInt64.multiply_v0 5145UL 5145UL = 26471025UL -Stdlib.UInt64.multiply_v0 9223372036854775808UL 2UL = error="Encountered out-of-range value for type of Int" +Stdlib.UInt64.multiply_v0 9223372036854775808UL 2UL = 0UL Stdlib.UInt64.divide_v0 10UL 5UL = 2UL Stdlib.UInt64.divide_v0 17UL 3UL = 5UL Stdlib.UInt64.divide_v0 0UL 1UL = 0UL @@ -234,4 +234,4 @@ Stdlib.UInt64.shiftRight 8UL 2UL = 2UL Stdlib.UInt64.shiftRight 0UL 5UL = 0UL Stdlib.UInt64.shiftRight 1UL 0UL = 1UL Stdlib.UInt64.shiftRight 9223372036854775808UL 63UL = 1UL -Stdlib.UInt64.shiftRight 40UL 3UL = 5UL \ No newline at end of file +Stdlib.UInt64.shiftRight 40UL 3UL = 5UL diff --git a/backend/testfiles/execution/stdlib/ints/uint8.dark b/backend/testfiles/execution/stdlib/ints/uint8.dark index dda3a33be2..5c454d95af 100644 --- a/backend/testfiles/execution/stdlib/ints/uint8.dark +++ b/backend/testfiles/execution/stdlib/ints/uint8.dark @@ -19,11 +19,11 @@ Stdlib.UInt8.add_v0 88uy 9uy = 97uy Stdlib.UInt8.add_v0 1uy 0uy = 1uy Stdlib.UInt8.add_v0 254uy 1uy = 255uy -Stdlib.UInt8.add_v0 255uy 1uy = error="Encountered out-of-range value for type of Int" +Stdlib.UInt8.add_v0 255uy 1uy = 0uy Stdlib.UInt8.subtract_v0 10uy 9uy = 1uy Stdlib.UInt8.subtract_v0 88uy 9uy = 79uy -Stdlib.UInt8.subtract_v0 0uy 1uy = error="Encountered out-of-range value for type of Int" +Stdlib.UInt8.subtract_v0 0uy 1uy = 255uy Stdlib.UInt8.subtract_v0 1uy 0uy = 1uy Stdlib.UInt8.subtract_v0 255uy 1uy = 254uy @@ -31,15 +31,15 @@ Stdlib.UInt8.multiply_v0 8uy 8uy = 64uy Stdlib.UInt8.multiply_v0 8uy 0uy = 0uy Stdlib.UInt8.multiply_v0 127uy 2uy = 254uy -Stdlib.UInt8.multiply_v0 128uy 2uy = error="Encountered out-of-range value for type of Int" -Stdlib.UInt8.multiply_v0 255uy 2uy = error="Encountered out-of-range value for type of Int" +Stdlib.UInt8.multiply_v0 128uy 2uy = 0uy +Stdlib.UInt8.multiply_v0 255uy 2uy = 254uy Stdlib.UInt8.power_v0 2uy 3uy = 8uy Stdlib.UInt8.power_v0 0uy 1uy = 0uy Stdlib.UInt8.power_v0 1uy 0uy = 1uy Stdlib.UInt8.power_v0 0uy 0uy = 1uy Stdlib.UInt8.power_v0 1uy 255uy = 1uy -Stdlib.UInt8.power_v0 16uy 2uy = error="Encountered out-of-range value for type of Int" +Stdlib.UInt8.power_v0 16uy 2uy = 0uy Stdlib.UInt8.divide_v0 10uy 5uy = 2uy Stdlib.UInt8.divide_v0 17uy 3uy = 5uy Stdlib.UInt8.divide_v0 8uy 5uy = 1uy @@ -125,8 +125,7 @@ Stdlib.UInt8.mod_v0 5uy 0uy = error="Cannot evaluate modulus against 0" Stdlib.UInt8.sum_v0 [ 1uy; 2uy ] = 3uy -Stdlib.UInt8.sum_v0 [ 1uy; 255uy ] = error="Encountered out-of-range value for type of Int" -// out of range +Stdlib.UInt8.sum_v0 [ 1uy; 255uy ] = 0uy // wraps on overflow Stdlib.UInt8.parse_v0 "-129" = Stdlib.Result.Result.Error Stdlib.UInt8.ParseError.OutOfRange Stdlib.UInt8.parse_v0 "256" = Stdlib.Result.Result.Error Stdlib.UInt8.ParseError.OutOfRange @@ -223,4 +222,4 @@ Stdlib.UInt8.shiftRight 8uy 2uy = 2uy Stdlib.UInt8.shiftRight 0uy 5uy = 0uy Stdlib.UInt8.shiftRight 1uy 0uy = 1uy Stdlib.UInt8.shiftRight 128uy 7uy = 1uy -Stdlib.UInt8.shiftRight 40uy 3uy = 5uy \ No newline at end of file +Stdlib.UInt8.shiftRight 40uy 3uy = 5uy diff --git a/packages/darklang/stdlib/int128.dark b/packages/darklang/stdlib/int128.dark index bb55ce05bd..759bff96dc 100644 --- a/packages/darklang/stdlib/int128.dark +++ b/packages/darklang/stdlib/int128.dark @@ -26,15 +26,15 @@ let remainder Builtin.int128Remainder value divisor -/// Adds two 128-bit signed integers together +/// Adds two 128-bit signed integers together (wraps on overflow) let add (a: Int128) (b: Int128) : Int128 = Builtin.int128Add a b -/// Subtracts two 128-bit signed integers +/// Subtracts two 128-bit signed integers (wraps on overflow) let subtract (a: Int128) (b: Int128) : Int128 = Builtin.int128Subtract a b -/// Multiplies two 128-bit signed integers +/// Multiplies two 128-bit signed integers (wraps on overflow) let multiply (a: Int128) (b: Int128) : Int128 = Builtin.int128Multiply a b @@ -42,14 +42,14 @@ let multiply (a: Int128) (b: Int128) : Int128 = Builtin.int128Multiply a b let divide (a: Int128) (b: Int128) : Int128 = Builtin.int128Divide a b -/// Returns the absolute value of (turning negative inputs into positive outputs) +/// Returns the absolute value of (turning negative inputs into positive outputs). The minimum value wraps back to itself (stays negative). let absoluteValue (a: Int128) : Int128 = if lessThan a 0Q then negate a else a -/// Returns the negation of , {{-a}} +/// Returns the negation of , {{-a}}. Negating the minimum value wraps back to itself. let negate (a: Int128) : Int128 = Builtin.int128Negate a @@ -183,4 +183,4 @@ let shiftLeft (a: Int128) (b: Int128) : Int128 = Builtin.int128ShiftLeft a b /// Bitwise right shift of an value -let shiftRight (a: Int128) (b: Int128) : Int128 = Builtin.int128ShiftRight a b \ No newline at end of file +let shiftRight (a: Int128) (b: Int128) : Int128 = Builtin.int128ShiftRight a b diff --git a/packages/darklang/stdlib/int16.dark b/packages/darklang/stdlib/int16.dark index 61619696d0..ceecd17c62 100644 --- a/packages/darklang/stdlib/int16.dark +++ b/packages/darklang/stdlib/int16.dark @@ -26,21 +26,21 @@ let remainder Builtin.int16Remainder value divisor -/// Adds two 16-bit signed integers together +/// Adds two 16-bit signed integers together (wraps on overflow) let add (a: Int16) (b: Int16) : Int16 = Builtin.int16Add a b -/// Subtracts two 16-bit signed integers +/// Subtracts two 16-bit signed integers (wraps on overflow) let subtract (a: Int16) (b: Int16) : Int16 = Builtin.int16Subtract a b -/// Multiplies two 16-bit signed integers +/// Multiplies two 16-bit signed integers (wraps on overflow) let multiply (a: Int16) (b: Int16) : Int16 = Builtin.int16Multiply a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: Int16) (exponent: Int16) : Int16 = // Handle some edge cases around 1. We want to make this match // OCaml, so we have to support an exponent below int16 @@ -64,7 +64,7 @@ let power (``base``: Int16) (exponent: Int16) : Int16 = let divide (a: Int16) (b: Int16) : Int16 = Builtin.int16Divide a b -/// Returns the absolute value of (turning negative inputs into positive outputs) +/// Returns the absolute value of (turning negative inputs into positive outputs). The minimum value wraps back to itself (stays negative). let absoluteValue (a: Int16) : Int16 = if lessThan a 0s then negate a @@ -72,7 +72,7 @@ let absoluteValue (a: Int16) : Int16 = a -/// Returns the negation of , {{-a}} +/// Returns the negation of , {{-a}}. Negating the minimum value wraps back to itself. let negate (a: Int16) : Int16 = Builtin.int16Negate a @@ -220,4 +220,4 @@ let shiftLeft (a: Int16) (b: Int16) : Int16 = Builtin.int16ShiftLeft a b /// Bitwise right shift of an value -let shiftRight (a: Int16) (b: Int16) : Int16 = Builtin.int16ShiftRight a b \ No newline at end of file +let shiftRight (a: Int16) (b: Int16) : Int16 = Builtin.int16ShiftRight a b diff --git a/packages/darklang/stdlib/int32.dark b/packages/darklang/stdlib/int32.dark index e826b47c0c..3da3dfa703 100644 --- a/packages/darklang/stdlib/int32.dark +++ b/packages/darklang/stdlib/int32.dark @@ -26,15 +26,15 @@ let remainder Builtin.int32Remainder value divisor -/// Adds two integers together +/// Adds two integers together (wraps on overflow) let add (a: Int32) (b: Int32) : Int32 = Builtin.int32Add a b -/// Subtracts two integers +/// Subtracts two integers (wraps on overflow) let subtract (a: Int32) (b: Int32) : Int32 = Builtin.int32Subtract a b -/// Multiplies two integers +/// Multiplies two integers (wraps on overflow) let multiply (a: Int32) (b: Int32) : Int32 = Builtin.int32Multiply a b @@ -44,7 +44,7 @@ let divide (a: Int32) (b: Int32) : Int32 = Builtin.int32Divide a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: Int32) (exponent: Int32) : Int32 = // Handle some edge cases around 1. We want to make this match // OCaml, so we have to support an exponent below int32 @@ -64,7 +64,7 @@ let power (``base``: Int32) (exponent: Int32) : Int32 = Builtin.int32Power ``base`` exponent -/// Returns the absolute value of (turning negative inputs into positive outputs) +/// Returns the absolute value of (turning negative inputs into positive outputs). The minimum value wraps back to itself (stays negative). let absoluteValue (a: Int32) : Int32 = if lessThan a 0l then negate a @@ -72,7 +72,7 @@ let absoluteValue (a: Int32) : Int32 = a -/// Returns the negation of , {{-a}} +/// Returns the negation of , {{-a}}. Negating the minimum value wraps back to itself. let negate (a: Int32) : Int32 = Builtin.int32Negate a @@ -218,4 +218,4 @@ let shiftLeft (a: Int32) (b: Int32) : Int32 = Builtin.int32ShiftLeft a b /// Bitwise right shift of an value -let shiftRight (a: Int32) (b: Int32) : Int32 = Builtin.int32ShiftRight a b \ No newline at end of file +let shiftRight (a: Int32) (b: Int32) : Int32 = Builtin.int32ShiftRight a b diff --git a/packages/darklang/stdlib/int64.dark b/packages/darklang/stdlib/int64.dark index 70de90d915..73f49f661d 100644 --- a/packages/darklang/stdlib/int64.dark +++ b/packages/darklang/stdlib/int64.dark @@ -26,15 +26,15 @@ let remainder Builtin.int64Remainder value divisor -/// Adds two integers together +/// Adds two integers together (wraps on overflow) let add (a: Int64) (b: Int64) : Int64 = Builtin.int64Add a b -/// Subtracts two integers +/// Subtracts two integers (wraps on overflow) let subtract (a: Int64) (b: Int64) : Int64 = Builtin.int64Subtract a b -/// Multiplies two integers +/// Multiplies two integers (wraps on overflow) let multiply (a: Int64) (b: Int64) : Int64 = Builtin.int64Multiply a b @@ -44,7 +44,7 @@ let divide (a: Int64) (b: Int64) : Int64 = Builtin.int64Divide a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: Int64) (exponent: Int64) : Int64 = // Handle some edge cases around 1. We want to make this match // OCaml, so we have to support an exponent above int32, but @@ -58,12 +58,12 @@ let power (``base``: Int64) (exponent: Int64) : Int64 = else Builtin.int64Power ``base`` exponent -/// Returns the absolute value of (turning negative inputs into positive outputs) +/// Returns the absolute value of (turning negative inputs into positive outputs). The minimum value wraps back to itself (stays negative). let absoluteValue (a: Int64) : Int64 = if lessThan a 0L then negate a else a -/// Returns the negation of , {{-a}} +/// Returns the negation of , {{-a}}. Negating the minimum value wraps back to itself. let negate (a: Int64) : Int64 = Builtin.int64Negate a diff --git a/packages/darklang/stdlib/int8.dark b/packages/darklang/stdlib/int8.dark index 333e4efdea..ed3d45c7b7 100644 --- a/packages/darklang/stdlib/int8.dark +++ b/packages/darklang/stdlib/int8.dark @@ -26,21 +26,21 @@ let remainder Builtin.int8Remainder value divisor -/// Adds two 8-bit signed integers together +/// Adds two 8-bit signed integers together (wraps on overflow) let add (a: Int8) (b: Int8) : Int8 = Builtin.int8Add a b -/// Subtracts two 8-bit signed integers +/// Subtracts two 8-bit signed integers (wraps on overflow) let subtract (a: Int8) (b: Int8) : Int8 = Builtin.int8Subtract a b -/// Multiplies two 8-bit signed integers +/// Multiplies two 8-bit signed integers (wraps on overflow) let multiply (a: Int8) (b: Int8) : Int8 = Builtin.int8Multiply a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: Int8) (exponent: Int8) : Int8 = // Handle some edge cases around 1. We want to make this match // OCaml, so we have to support an exponent below int8 @@ -64,7 +64,7 @@ let power (``base``: Int8) (exponent: Int8) : Int8 = let divide (a: Int8) (b: Int8) : Int8 = Builtin.int8Divide a b -/// Returns the absolute value of (turning negative inputs into positive outputs) +/// Returns the absolute value of (turning negative inputs into positive outputs). The minimum value wraps back to itself (stays negative). let absoluteValue (a: Int8) : Int8 = if lessThan a 0y then negate a @@ -72,7 +72,7 @@ let absoluteValue (a: Int8) : Int8 = a -/// Returns the negation of , {{-a}} +/// Returns the negation of , {{-a}}. Negating the minimum value wraps back to itself. let negate (a: Int8) : Int8 = Builtin.int8Negate a @@ -218,4 +218,4 @@ let shiftLeft (a: Int8) (b: Int8) : Int8 = Builtin.int8ShiftLeft a b /// Bitwise right shift of an value -let shiftRight (a: Int8) (b: Int8) : Int8 = Builtin.int8ShiftRight a b \ No newline at end of file +let shiftRight (a: Int8) (b: Int8) : Int8 = Builtin.int8ShiftRight a b diff --git a/packages/darklang/stdlib/uint128.dark b/packages/darklang/stdlib/uint128.dark index 4ed737f9eb..9556656ccc 100644 --- a/packages/darklang/stdlib/uint128.dark +++ b/packages/darklang/stdlib/uint128.dark @@ -13,15 +13,15 @@ type ParseError = let ``mod`` (a: UInt128) (b: UInt128) : UInt128 = Builtin.uint128Mod a b -/// Adds two 128-bit unsigned integers together +/// Adds two 128-bit unsigned integers together (wraps on overflow) let add (a: UInt128) (b: UInt128) : UInt128 = Builtin.uint128Add a b -/// Subtracts two 128-bit unsigned integers +/// Subtracts two 128-bit unsigned integers (wraps on overflow) let subtract (a: UInt128) (b: UInt128) : UInt128 = Builtin.uint128Subtract a b -/// Multiplies two 128-bit unsigned integers +/// Multiplies two 128-bit unsigned integers (wraps on overflow) let multiply (a: UInt128) (b: UInt128) : UInt128 = Builtin.uint128Multiply a b @@ -150,4 +150,4 @@ let shiftLeft (a: UInt128) (b: UInt128) : UInt128 = /// Bitwise right shift of a value let shiftRight (a: UInt128) (b: UInt128) : UInt128 = - Builtin.uint128ShiftRight a b \ No newline at end of file + Builtin.uint128ShiftRight a b diff --git a/packages/darklang/stdlib/uint16.dark b/packages/darklang/stdlib/uint16.dark index 15e0568012..4c4ad9ad55 100644 --- a/packages/darklang/stdlib/uint16.dark +++ b/packages/darklang/stdlib/uint16.dark @@ -13,21 +13,21 @@ type ParseError = let ``mod`` (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16Mod a b -/// Adds two 16-bit unsigned integers together +/// Adds two 16-bit unsigned integers together (wraps on overflow) let add (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16Add a b -/// Subtracts two 16-bit unsigned integers +/// Subtracts two 16-bit unsigned integers (wraps on overflow) let subtract (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16Subtract a b -/// Multiplies two 16-bit unsigned integers +/// Multiplies two 16-bit unsigned integers (wraps on overflow) let multiply (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16Multiply a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: UInt16) (exponent: UInt16) : UInt16 = if ``base`` == 0us && exponent == 0us then 1us else if ``base`` == 0us then 0us @@ -187,4 +187,4 @@ let shiftLeft (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16ShiftLeft a b /// Bitwise right shift of a value -let shiftRight (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16ShiftRight a b \ No newline at end of file +let shiftRight (a: UInt16) (b: UInt16) : UInt16 = Builtin.uint16ShiftRight a b diff --git a/packages/darklang/stdlib/uint32.dark b/packages/darklang/stdlib/uint32.dark index f7f09afbab..cfb94f1e7b 100644 --- a/packages/darklang/stdlib/uint32.dark +++ b/packages/darklang/stdlib/uint32.dark @@ -13,21 +13,21 @@ type ParseError = let ``mod`` (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32Mod a b -/// Adds two 16-bit unsigned integers together +/// Adds two 32-bit unsigned integers together (wraps on overflow) let add (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32Add a b -/// Subtracts two 16-bit unsigned integers +/// Subtracts two 32-bit unsigned integers (wraps on overflow) let subtract (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32Subtract a b -/// Multiplies two 16-bit unsigned integers +/// Multiplies two 32-bit unsigned integers (wraps on overflow) let multiply (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32Multiply a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: UInt32) (exponent: UInt32) : UInt32 = if ``base`` == 0ul && exponent == 0ul then 1ul else if ``base`` == 0ul then 0ul @@ -35,7 +35,7 @@ let power (``base``: UInt32) (exponent: UInt32) : UInt32 = else Builtin.uint32Power ``base`` exponent -/// Divides two 16-bit unsigned integers +/// Divides two 32-bit unsigned integers let divide (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32Divide a b @@ -57,7 +57,7 @@ let lessThanOrEqualTo (a: UInt32) (b: UInt32) : Bool = Builtin.uint32LessThanOrEqualTo a b -/// Returns a random 16-bit unsigned integer between and (inclusive) +/// Returns a random 32-bit unsigned integer between and (inclusive) let random (start: UInt32) (``end``: UInt32) : UInt32 = Builtin.uint32Random start ``end`` @@ -186,4 +186,4 @@ let shiftLeft (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32ShiftLeft a b /// Bitwise right shift of a value -let shiftRight (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32ShiftRight a b \ No newline at end of file +let shiftRight (a: UInt32) (b: UInt32) : UInt32 = Builtin.uint32ShiftRight a b diff --git a/packages/darklang/stdlib/uint64.dark b/packages/darklang/stdlib/uint64.dark index 6e48356c1c..f830da71a8 100644 --- a/packages/darklang/stdlib/uint64.dark +++ b/packages/darklang/stdlib/uint64.dark @@ -11,15 +11,15 @@ type ParseError = let ``mod`` (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64Mod a b -/// Adds 64-bit unsigned integers together +/// Adds 64-bit unsigned integers together (wraps on overflow) let add (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64Add a b -/// Subtracts 64-bit unsigned integers +/// Subtracts 64-bit unsigned integers (wraps on overflow) let subtract (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64Subtract a b -/// Multiplies 64-bit unsigned integers +/// Multiplies 64-bit unsigned integers (wraps on overflow) let multiply (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64Multiply a b @@ -29,7 +29,7 @@ let divide (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64Divide a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: UInt64) (exponent: UInt64) : UInt64 = if ``base`` == 0UL && exponent == 0UL then 1UL else if ``base`` == 0UL then 0UL @@ -186,4 +186,4 @@ let shiftLeft (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64ShiftLeft a b /// Bitwise right shift of a value -let shiftRight (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64ShiftRight a b \ No newline at end of file +let shiftRight (a: UInt64) (b: UInt64) : UInt64 = Builtin.uint64ShiftRight a b diff --git a/packages/darklang/stdlib/uint8.dark b/packages/darklang/stdlib/uint8.dark index e723ace494..014749396c 100644 --- a/packages/darklang/stdlib/uint8.dark +++ b/packages/darklang/stdlib/uint8.dark @@ -13,21 +13,21 @@ type ParseError = let ``mod`` (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8Mod a b -/// Adds two 8-bit unsigned integers together +/// Adds two 8-bit unsigned integers together (wraps on overflow) let add (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8Add a b -/// Subtracts two 8-bit unsigned integers +/// Subtracts two 8-bit unsigned integers (wraps on overflow) let subtract (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8Subtract a b -/// Multiplies two 8-bit unsigned integers +/// Multiplies two 8-bit unsigned integers (wraps on overflow) let multiply (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8Multiply a b /// Raise to the power of . /// must to be positive. -/// Return value wrapped in a {{Result}} +/// Overflow wraps around. let power (``base``: UInt8) (exponent: UInt8) : UInt8 = if ``base`` == 0uy && exponent == 0uy then 1uy else if ``base`` == 0uy then 0uy @@ -185,4 +185,4 @@ let shiftLeft (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8ShiftLeft a b /// Bitwise right shift of a value -let shiftRight (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8ShiftRight a b \ No newline at end of file +let shiftRight (a: UInt8) (b: UInt8) : UInt8 = Builtin.uint8ShiftRight a b