diff --git a/src/Fable.AST/CHANGELOG.md b/src/Fable.AST/CHANGELOG.md index 4503aab499..17a5a108be 100644 --- a/src/Fable.AST/CHANGELOG.md +++ b/src/Fable.AST/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Removed + +* Remove `MemberRefInfo.Attributes` [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) (by @DunetsNM) + +### Added + +* Add `MemberRefInfo.AttributeFullNames` [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) (by @DunetsNM) + ## 4.4.0 - 2024-02-13 ### Changed diff --git a/src/Fable.AST/Fable.fs b/src/Fable.AST/Fable.fs index 4385ef3932..90d2c461d1 100644 --- a/src/Fable.AST/Fable.fs +++ b/src/Fable.AST/Fable.fs @@ -51,7 +51,10 @@ type MemberRefInfo = IsInstance: bool CompiledName: string NonCurriedArgTypes: Type list option - Attributes: Attribute seq + // We only store the attributes fullname otherwise deserialization of precompiled files fails + // System.Text.Json is not able to deserialize the standard Attribute type because it is an interface + // More about it here: https://github.com/fable-compiler/Fable/pull/3817 + AttributeFullNames: string list } type MemberRef = @@ -482,6 +485,26 @@ type ArrayKind = | MutableArray | ImmutableArray +[] +type NumberValue = + | Int8 of sbyte + | UInt8 of byte + | Int16 of int16 + | UInt16 of System.UInt16 + | Int32 of System.Int32 + | UInt32 of System.UInt32 + | Int64 of System.Int64 + | UInt64 of System.UInt64 + | Int128 of upper: System.UInt64 * lower: System.UInt64 // System.Int128 + | UInt128 of upper: System.UInt64 * lower: System.UInt64 // System.UInt128 + | BigInt of bigint + | NativeInt of nativeint + | UNativeInt of unativeint + | Float16 of System.Single // System.Half + | Float32 of System.Single + | Float64 of System.Double + | Decimal of System.Decimal + type ValueKind = // The AST from F# compiler is a bit inconsistent with ThisValue and BaseValue. // ThisValue only appears in constructors and not in instance members (where `this` is passed as first argument) @@ -497,7 +520,7 @@ type ValueKind = /// String interpolation with support for JS tagged templates /// String parts length should always be values.Length + 1 | StringTemplate of tag: Expr option * parts: string list * values: Expr list - | NumberConstant of value: obj * kind: NumberKind * info: NumberInfo + | NumberConstant of value: NumberValue * info: NumberInfo | RegexConstant of source: string * flags: RegexFlag list | NewOption of value: Expr option * typ: Type * isStruct: bool | NewArray of newKind: NewArrayKind * typ: Type * kind: ArrayKind @@ -518,7 +541,26 @@ type ValueKind = | CharConstant _ -> Char | StringConstant _ | StringTemplate _ -> String - | NumberConstant(_, kind, info) -> Number(kind, info) + | NumberConstant(value, info) -> + match value with + | NumberValue.Int8 _ -> NumberKind.Int8 + | NumberValue.UInt8 _ -> NumberKind.UInt8 + | NumberValue.Int16 _ -> NumberKind.Int16 + | NumberValue.UInt16 _ -> NumberKind.UInt16 + | NumberValue.Int32 _ -> NumberKind.Int32 + | NumberValue.UInt32 _ -> NumberKind.UInt32 + | NumberValue.Int64 _ -> NumberKind.Int64 + | NumberValue.UInt64 _ -> NumberKind.UInt64 + | NumberValue.Int128 _ -> NumberKind.Int128 + | NumberValue.UInt128 _ -> NumberKind.UInt128 + | NumberValue.BigInt _ -> NumberKind.BigInt + | NumberValue.NativeInt _ -> NumberKind.NativeInt + | NumberValue.UNativeInt _ -> NumberKind.UNativeInt + | NumberValue.Float16 _ -> NumberKind.Float16 + | NumberValue.Float32 _ -> NumberKind.Float32 + | NumberValue.Float64 _ -> NumberKind.Float64 + | NumberValue.Decimal _ -> NumberKind.Decimal + |> fun kind -> Number(kind, info) | RegexConstant _ -> Regex | NewOption(_, t, isStruct) -> Option(t, isStruct) | NewArray(_, t, k) -> Array(t, k) diff --git a/src/Fable.Cli/CHANGELOG.md b/src/Fable.Cli/CHANGELOG.md index 4bb6c47a69..262923d57f 100644 --- a/src/Fable.Cli/CHANGELOG.md +++ b/src/Fable.Cli/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* [GH-3817](https://github.com/fable-compiler/Fable/pull/3817) [All] Fix broken --precompiledLib switch (#3818) (by @DunetsNM) * [JS/TS] Fixed TimeSpan.FromMilliseconds (#3815) (by @ncave) * [Python] Fixed quotation for union string cases (by @dbrattli) * [Python] Fixed casing issues with identifiers and reflection info (#3811) (by @dbrattli) diff --git a/src/Fable.Transforms/Dart/Fable2Dart.fs b/src/Fable.Transforms/Dart/Fable2Dart.fs index f78bd2bcba..d3002b88c3 100644 --- a/src/Fable.Transforms/Dart/Fable2Dart.fs +++ b/src/Fable.Transforms/Dart/Fable2Dart.fs @@ -719,22 +719,20 @@ module Util = |> Expression.identExpression |> getParts t parts - let transformNumberLiteral com r kind (x: obj) = - match kind, x with - | Dart.Replacements.DartInt, (:? char as x) -> Expression.integerLiteral (int64 x) - | Int8, (:? int8 as x) -> Expression.integerLiteral (int64 x) - | UInt8, (:? uint8 as x) -> Expression.integerLiteral (int64 x) - | Int16, (:? int16 as x) -> Expression.integerLiteral (int64 x) - | UInt16, (:? uint16 as x) -> Expression.integerLiteral (int64 x) - | Int32, (:? int32 as x) -> Expression.integerLiteral (x) - | UInt32, (:? uint32 as x) -> Expression.integerLiteral (int64 x) - | Int64, (:? int64 as x) -> Expression.integerLiteral (x) - | UInt64, (:? uint64 as x) -> Expression.integerLiteral (int64 x) - | Float32, (:? float32 as x) -> Expression.doubleLiteral (float x) - | Float64, (:? float as x) -> Expression.doubleLiteral (x) - | _ -> - $"Expected literal of type %A{kind} but got {x.GetType().FullName}" - |> addErrorAndReturnNull com r + let transformNumberLiteral com (r: Option) (v: Fable.NumberValue) = + match v with + | Fable.NumberValue.Int8 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.UInt8 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.Int16 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.UInt16 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.Int32 x -> Expression.integerLiteral (x) + | Fable.NumberValue.UInt32 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.Int64 x -> Expression.integerLiteral (x) + | Fable.NumberValue.UInt64 x -> Expression.integerLiteral (int64 x) + | Fable.NumberValue.Float16 x -> Expression.doubleLiteral (float x) + | Fable.NumberValue.Float32 x -> Expression.doubleLiteral (float x) + | Fable.NumberValue.Float64 x -> Expression.doubleLiteral (x) + | _ -> $"Numeric literal is not supported: %A{v}" |> addErrorAndReturnNull com r let transformTuple (com: IDartCompiler) ctx (args: Expression list) = let tup = List.length args |> getTupleTypeIdent com ctx @@ -777,7 +775,7 @@ module Util = // Dart enums are limited as we cannot set arbitrary values or combine them as flags // so for now we compile F# enums as integers - | Fable.NumberConstant(x, kind, _) -> transformNumberLiteral com r kind x |> resolveExpr returnStrategy + | Fable.NumberConstant(x, _) -> transformNumberLiteral com r x |> resolveExpr returnStrategy | Fable.RegexConstant(source, flags) -> let flagToArg = diff --git a/src/Fable.Transforms/Dart/Replacements.fs b/src/Fable.Transforms/Dart/Replacements.fs index 76a7f90ded..b5c6f9e045 100644 --- a/src/Fable.Transforms/Dart/Replacements.fs +++ b/src/Fable.Transforms/Dart/Replacements.fs @@ -50,8 +50,12 @@ let coreModFor = | BclKeyValuePair _ -> FableError "Cannot decide core module" |> raise let makeLongInt com r t signed (x: uint64) = - let lowBits = NumberConstant(float (uint32 x), Float64, NumberInfo.Empty) - let highBits = NumberConstant(float (x >>> 32), Float64, NumberInfo.Empty) + let lowBits = + NumberConstant(NumberValue.Float64(float (uint32 x)), NumberInfo.Empty) + + let highBits = + NumberConstant(NumberValue.Float64(float (x >>> 32)), NumberInfo.Empty) + let unsigned = BoolConstant(not signed) let args = @@ -544,7 +548,7 @@ let rec getZero (com: ICompiler) (ctx: Context) (t: Type) = | String -> makeStrConst "" // Using empty string instead of null so Dart doesn't complain | Number(BigInt, _) as t -> Helper.LibCall(com, "BigInt", "fromInt32", t, [ makeIntConst 0 ]) | Number(Decimal, _) as t -> makeIntConst 0 |> makeDecimalFromExpr com None t - | Number(kind, uom) -> NumberConstant(getBoxedZero kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetZero kind, uom) |> makeValue None | Builtin(BclTimeSpan | BclTimeOnly) -> getZeroTimeSpan t | Builtin BclDateTime as t -> Helper.LibCall(com, "Date", "minValue", t, []) | Builtin BclDateTimeOffset as t -> Helper.LibCall(com, "DateOffset", "minValue", t, []) @@ -563,7 +567,7 @@ let getOne (com: ICompiler) (ctx: Context) (t: Type) = | Boolean -> makeBoolConst true | Number(BigInt, _) as t -> Helper.LibCall(com, "BigInt", "fromInt32", t, [ makeIntConst 1 ]) | Number(Decimal, _) as t -> makeIntConst 1 |> makeDecimalFromExpr com None t - | Number(kind, uom) -> NumberConstant(getBoxedOne kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetOne kind, uom) |> makeValue None | ListSingleton(CustomOp com ctx None t "get_One" [] e) -> e | _ -> makeIntConst 1 @@ -2078,7 +2082,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op | "IsInfinity", [ _ ] when isFloat -> Helper.LibCall(com, "Double", "isInfinity", t, args, i.SignatureArgTypes, genArgs = i.GenericArgs, ?loc = r) |> Some - | ("Parse" | "TryParse") as meth, str :: NumberConst(:? int as style, _, _) :: _ -> + | ("Parse" | "TryParse") as meth, str :: NumberConst(NumberValue.Int32 style, _) :: _ -> let hexConst = int System.Globalization.NumberStyles.HexNumber let intConst = int System.Globalization.NumberStyles.Integer diff --git a/src/Fable.Transforms/FSharp2Fable.Util.fs b/src/Fable.Transforms/FSharp2Fable.Util.fs index 39752d0e70..e4cb8e414e 100644 --- a/src/Fable.Transforms/FSharp2Fable.Util.fs +++ b/src/Fable.Transforms/FSharp2Fable.Util.fs @@ -1422,7 +1422,19 @@ module TypeHelpers = // TODO: Check it's effectively measure? // TODO: Raise error if we cannot get the measure fullname? match tryDefinition genArgs[0] with - | Some(_, Some fullname) -> fullname + | Some(_, Some fullname) -> + // Not sure why, but when precompiling F# changes measure types to MeasureProduct<'M, MeasureOne> + match fullname with + | Types.measureProduct2 -> + match + (nonAbbreviatedType genArgs[0]).GenericArguments + |> Seq.map (tryDefinition >> Option.bind snd) + |> List.ofSeq + with + // TODO: generalize it to support aggregate units such as or more complex + | [ Some measure; Some Types.measureOne ] -> measure + | _ -> fullname + | _ -> fullname | _ -> Naming.unknown else Naming.unknown @@ -2147,13 +2159,18 @@ module Util = let fableMemberFunctionOrValue = FsMemberFunctionOrValue(memb) :> Fable.MemberFunctionOrValue + let attributeFullNames = + fableMemberFunctionOrValue.Attributes + |> Seq.map (fun attr -> attr.Entity.FullName) + |> List.ofSeq + Fable.MemberRef( FsEnt.Ref(ent), { CompiledName = memb.CompiledName IsInstance = memb.IsInstanceMember NonCurriedArgTypes = nonCurriedArgTypes - Attributes = fableMemberFunctionOrValue.Attributes + AttributeFullNames = attributeFullNames } ) | ent -> @@ -2182,13 +2199,18 @@ module Util = let fableMemberFunctionOrValue = FsMemberFunctionOrValue(memb) :> Fable.MemberFunctionOrValue + let attributeFullNames = + fableMemberFunctionOrValue.Attributes + |> Seq.map (fun attr -> attr.Entity.FullName) + |> List.ofSeq + Fable.MemberRef( FsEnt.Ref(ent), { CompiledName = memb.CompiledName IsInstance = memb.IsInstanceMember NonCurriedArgTypes = None - Attributes = fableMemberFunctionOrValue.Attributes + AttributeFullNames = attributeFullNames } ) | ent -> diff --git a/src/Fable.Transforms/Fable2Babel.fs b/src/Fable.Transforms/Fable2Babel.fs index 6fcfaf7515..d3917f4e17 100644 --- a/src/Fable.Transforms/Fable2Babel.fs +++ b/src/Fable.Transforms/Fable2Babel.fs @@ -1613,27 +1613,26 @@ module Util = let values = values |> List.mapToArray (fun e -> com.TransformAsExpr(ctx, e)) StringTemplate(tag, List.toArray parts, values, r) |> Literal - | Fable.NumberConstant(x, kind, _) -> - match kind, x with - | Decimal, (:? decimal as x) -> JS.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx - | BigInt, (:? bigint as x) -> Expression.bigintLiteral (string x, ?loc = r) - | Int64, (:? int64 as x) -> Expression.bigintLiteral (string x, ?loc = r) - | UInt64, (:? uint64 as x) -> Expression.bigintLiteral (string x, ?loc = r) - // | Int128, (:? System.Int128 as x) -> Expression.bigintLiteral(string x, ?loc=r) - // | UInt128, (:? System.UInt128 as x) -> Expression.bigintLiteral(string x, ?loc=r) - | NativeInt, (:? nativeint as x) -> Expression.bigintLiteral (string x, ?loc = r) - | UNativeInt, (:? unativeint as x) -> Expression.bigintLiteral (string x, ?loc = r) - | Int8, (:? int8 as x) -> Expression.numericLiteral (float x, ?loc = r) - | UInt8, (:? uint8 as x) -> Expression.numericLiteral (float x, ?loc = r) - | Int16, (:? int16 as x) -> Expression.numericLiteral (float x, ?loc = r) - | UInt16, (:? uint16 as x) -> Expression.numericLiteral (float x, ?loc = r) - | Int32, (:? int32 as x) -> Expression.numericLiteral (float x, ?loc = r) - | UInt32, (:? uint32 as x) -> Expression.numericLiteral (float x, ?loc = r) - // | Float16, (:? System.Half as x) -> Expression.numericLiteral(float x, ?loc=r) - | Float32, (:? float32 as x) -> Expression.numericLiteral (float x, ?loc = r) - | Float64, (:? float as x) -> Expression.numericLiteral (float x, ?loc = r) - | _, (:? char as x) -> Expression.numericLiteral (float x, ?loc = r) - | _ -> addErrorAndReturnNull com r $"Numeric literal is not supported: {x.GetType().FullName}" + | Fable.NumberConstant(v, _) -> + match v with + | Fable.NumberValue.Int8 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.UInt8 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Int16 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.UInt16 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Int32 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.UInt32 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Int64 x -> Expression.bigintLiteral (string x, ?loc = r) + | Fable.NumberValue.UInt64 x -> Expression.bigintLiteral (string x, ?loc = r) + // | Fable.NumberValue.Int128(u,l) -> Expression.bigintLiteral(string System.Int128(u,l), ?loc=r) + // | Fable.NumberValue.UInt128(u,l) -> Expression.bigintLiteral(string System.UInt128(u,l), ?loc=r) + | Fable.NumberValue.BigInt x -> Expression.bigintLiteral (string x, ?loc = r) + | Fable.NumberValue.NativeInt x -> Expression.bigintLiteral (string x, ?loc = r) + | Fable.NumberValue.UNativeInt x -> Expression.bigintLiteral (string x, ?loc = r) + | Fable.NumberValue.Float16 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Float32 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Float64 x -> Expression.numericLiteral (float x, ?loc = r) + | Fable.NumberValue.Decimal x -> JS.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx + | _ -> addErrorAndReturnNull com r $"Numeric literal is not supported: %A{v}" | Fable.RegexConstant(source, flags) -> Expression.regExpLiteral (source, flags, ?loc = r) | Fable.NewArray(newKind, typ, kind) -> match newKind with @@ -1914,8 +1913,8 @@ module Util = match callInfo.MemberRef with | Some(Fable.MemberRef(_, info)) -> let hasParamObjectAttribute = - info.Attributes - |> Seq.tryFind (fun attr -> attr.Entity.FullName = Atts.paramObject) + info.AttributeFullNames + |> List.tryFind (fun attr -> attr = Atts.paramObject) |> Option.isSome if hasParamObjectAttribute then diff --git a/src/Fable.Transforms/FableTransforms.fs b/src/Fable.Transforms/FableTransforms.fs index 01ed034a9e..228b0bbf6f 100644 --- a/src/Fable.Transforms/FableTransforms.fs +++ b/src/Fable.Transforms/FableTransforms.fs @@ -427,7 +427,7 @@ module private Transforms = | Value(BoolConstant a, _), Value(BoolConstant b, _) -> Some(a = b) | Value(CharConstant a, _), Value(CharConstant b, _) -> Some(a = b) | Value(StringConstant a, _), Value(StringConstant b, _) -> Some(a = b) - | Value(NumberConstant(a, _, _), _), Value(NumberConstant(b, _, _), _) -> Some(a = b) + | Value(NumberConstant(a, _), _), Value(NumberConstant(b, _), _) -> Some(a = b) | Value(NewOption(None, _, _), _), Value(NewOption(None, _, _), _) -> Some true | Value(NewOption(Some a, _, _), _), Value(NewOption(Some b, _, _), _) -> tryEqualsAtCompileTime a b | _ -> None @@ -440,9 +440,9 @@ module private Transforms = | Value(StringConstant v1, r1), Value(StringConstant v2, r2) -> Value(StringConstant(v1 + v2), addRanges [ r1; r2 ]) // Assume NumberKind and NumberInfo are the same - | Value(NumberConstant(:? int as v1, AST.Int32, NumberInfo.Empty), r1), - Value(NumberConstant(:? int as v2, AST.Int32, NumberInfo.Empty), r2) -> - Value(NumberConstant(v1 + v2, AST.Int32, NumberInfo.Empty), addRanges [ r1; r2 ]) + | Value(NumberConstant(NumberValue.Int32 v1, NumberInfo.Empty), r1), + Value(NumberConstant(NumberValue.Int32 v2, NumberInfo.Empty), r2) -> + Value(NumberConstant(NumberValue.Int32(v1 + v2), NumberInfo.Empty), addRanges [ r1; r2 ]) | _ -> e | Operation(Logical(AST.LogicalAnd, (Value(BoolConstant b, _) as v1), v2), [], _, _) -> diff --git a/src/Fable.Transforms/OverloadSuffix.fs b/src/Fable.Transforms/OverloadSuffix.fs index 6ef901e554..54fd6c4a25 100644 --- a/src/Fable.Transforms/OverloadSuffix.fs +++ b/src/Fable.Transforms/OverloadSuffix.fs @@ -106,7 +106,9 @@ let rec private getTypeFastFullName (genParams: IDictionary<_, _>) (t: Fable.Typ let genArgs = genArgs |> Seq.mapToList (getTypeFastFullName genParams) // Not sure why, but when precompiling F# changes measure types to MeasureProduct<'M, MeasureOne> match tdef.FullName, genArgs with - | Types.measureProduct2, [ measure; Types.measureOne ] -> measure + | Types.measureProduct2, [ measure; Types.measureOne ] -> + // TODO: generalize it to support aggregate units such as or more complex + measure | _ -> let genArgs = String.concat "," genArgs diff --git a/src/Fable.Transforms/Php/Fable2Php.fs b/src/Fable.Transforms/Php/Fable2Php.fs index 151f7cc940..6a841cc5f1 100644 --- a/src/Fable.Transforms/Php/Fable2Php.fs +++ b/src/Fable.Transforms/Php/Fable2Php.fs @@ -1454,18 +1454,18 @@ and convertValue (com: IPhpCompiler) (value: Fable.ValueKind) range = ) - | Fable.NumberConstant(x, _, _) -> + | Fable.NumberConstant(x, _) -> match x with - | :? int8 as x -> PhpConst(PhpConstNumber(float x)) - | :? uint8 as x -> PhpConst(PhpConstNumber(float x)) - | :? int16 as x -> PhpConst(PhpConstNumber(float x)) - | :? uint16 as x -> PhpConst(PhpConstNumber(float x)) - | :? int32 as x -> PhpConst(PhpConstNumber(float x)) - | :? uint32 as x -> PhpConst(PhpConstNumber(float x)) - | :? float32 as x -> PhpConst(PhpConstNumber(float x)) - | :? float as x -> PhpConst(PhpConstNumber(x)) + | Fable.NumberValue.Int8 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.UInt8 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.Int16 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.UInt16 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.Int32 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.UInt32 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.Float32 x -> PhpConst(PhpConstNumber(float x)) + | Fable.NumberValue.Float64 x -> PhpConst(PhpConstNumber(x)) | _ -> - addError com [] range $"Numeric literal is not supported: {x.GetType().FullName}" + addError com [] range $"Numeric literal is not supported: %A{x}" PhpConst(PhpConstNull) | Fable.StringTemplate _ -> diff --git a/src/Fable.Transforms/Python/Fable2Python.fs b/src/Fable.Transforms/Python/Fable2Python.fs index e0ae8b8e48..614d3b83d4 100644 --- a/src/Fable.Transforms/Python/Fable2Python.fs +++ b/src/Fable.Transforms/Python/Fable2Python.fs @@ -1671,7 +1671,6 @@ module Util = let transformCurry (com: IPythonCompiler) (ctx: Context) expr arity : Expression * Statement list = com.TransformAsExpr(ctx, Replacements.Api.curryExprAtRuntime com arity expr) - let makeInteger (com: IPythonCompiler) (ctx: Context) r _t intName (x: obj) = let cons = libValue com ctx "types" intName let value = Expression.intConstant (x, ?loc = r) @@ -1682,7 +1681,6 @@ module Util = let value = Expression.floatConstant (x, ?loc = r) Expression.call (cons, [ value ], ?loc = r), [] - let transformValue (com: IPythonCompiler) (ctx: Context) r value : Expression * Statement list = match value with | Fable.BaseValue(None, _) -> Expression.identifier "super()", [] @@ -1713,26 +1711,34 @@ module Util = makeBinOp None Fable.String acc (makeStrConst part) BinaryPlus ) |> transformAsExpr com ctx - | Fable.NumberConstant(x, kind, _) -> - match kind, x with - | Decimal, (:? decimal as x) -> Py.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx - | Int64, (:? int64 as x) -> makeInteger com ctx r value.Type "int64" x - | UInt64, (:? uint64 as x) -> makeInteger com ctx r value.Type "uint64" x - | Int8, (:? int8 as x) -> makeInteger com ctx r value.Type "int8" x - | UInt8, (:? uint8 as x) -> makeInteger com ctx r value.Type "uint8" x - | Int16, (:? int16 as x) -> makeInteger com ctx r value.Type "int16" x - | UInt16, (:? uint16 as x) -> makeInteger com ctx r value.Type "uint16" x - | Int32, (:? int32 as x) -> Expression.intConstant (x, ?loc = r), [] - | UInt32, (:? uint32 as x) -> makeInteger com ctx r value.Type "uint32" x - //| _, (:? char as x) -> makeNumber com ctx r value.Type "char" x - | _, x when x = infinity -> Expression.name "float('inf')", [] - | _, x when x = -infinity -> Expression.name "float('-inf')", [] - | _, (:? float as x) when Double.IsNaN(x) -> Expression.name "float('nan')", [] - | _, (:? float32 as x) when Single.IsNaN(x) -> + | Fable.NumberConstant(v, _) -> + match v with + | Fable.NumberValue.Int8 x -> makeInteger com ctx r value.Type "int8" x + | Fable.NumberValue.UInt8 x -> makeInteger com ctx r value.Type "uint8" x + | Fable.NumberValue.Int16 x -> makeInteger com ctx r value.Type "int16" x + | Fable.NumberValue.UInt16 x -> makeInteger com ctx r value.Type "uint16" x + | Fable.NumberValue.Int32 x -> Expression.intConstant (x, ?loc = r), [] + | Fable.NumberValue.UInt32 x -> makeInteger com ctx r value.Type "uint32" x + | Fable.NumberValue.Int64 x -> makeInteger com ctx r value.Type "int64" x + | Fable.NumberValue.UInt64 x -> makeInteger com ctx r value.Type "uint64" x + // | Fable.NumberValue.Int128(u,l) -> Expression.intConstant (System.Int128(u,l), ?loc = r), [] + // | Fable.NumberValue.UInt128(u,l) -> Expression.intConstant (System.UInt128(u,l), ?loc = r), [] + | Fable.NumberValue.BigInt x -> Expression.intConstant (x, ?loc = r), [] + | Fable.NumberValue.NativeInt x -> Expression.intConstant (x, ?loc = r), [] + | Fable.NumberValue.UNativeInt x -> Expression.intConstant (x, ?loc = r), [] + // TODO: special consts also need attention + | Fable.NumberValue.Float64 x when x = infinity -> Expression.name "float('inf')", [] + | Fable.NumberValue.Float64 x when x = -infinity -> Expression.name "float('-inf')", [] + | Fable.NumberValue.Float64 x when Double.IsNaN(x) -> Expression.name "float('nan')", [] + | Fable.NumberValue.Float32 x when Single.IsNaN(x) -> + libCall com ctx r "types" "float32" [ Expression.stringConstant "nan" ], [] + | Fable.NumberValue.Float16 x when Single.IsNaN(x) -> libCall com ctx r "types" "float32" [ Expression.stringConstant "nan" ], [] - | _, (:? float32 as x) -> makeFloat com ctx r value.Type "float32" (float x) - | _, (:? float as x) -> Expression.floatConstant (x, ?loc = r), [] - | _ -> Expression.intConstant (x, ?loc = r), [] + | Fable.NumberValue.Float16 x -> makeFloat com ctx r value.Type "float32" (float x) + | Fable.NumberValue.Float32 x -> makeFloat com ctx r value.Type "float32" (float x) + | Fable.NumberValue.Float64 x -> Expression.floatConstant (x, ?loc = r), [] + | Fable.NumberValue.Decimal x -> Py.Replacements.makeDecimal com r value.Type x |> transformAsExpr com ctx + | _ -> addErrorAndReturnNull com r $"Numeric literal is not supported: %A{v}", [] | Fable.NewArray(newKind, typ, kind) -> match newKind with | Fable.ArrayValues values -> makeArray com ctx values kind typ diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs index 80526dcd7d..475110fcb5 100644 --- a/src/Fable.Transforms/Python/Replacements.fs +++ b/src/Fable.Transforms/Python/Replacements.fs @@ -72,9 +72,9 @@ let makeDecimal com r t (x: decimal) = let makeDecimalFromExpr com r t (e: Expr) = match e with - | Value(Fable.NumberConstant(:? float32 as x, Float32, _), _) -> makeDecimal com r t (decimal x) - | Value(Fable.NumberConstant(:? float as x, Float64, _), _) -> makeDecimal com r t (decimal x) - | Value(Fable.NumberConstant(:? decimal as x, Decimal, _), _) -> makeDecimal com r t x + | Value(Fable.NumberConstant(NumberValue.Float32 x, _), _) -> makeDecimal com r t (decimal x) + | Value(Fable.NumberConstant(NumberValue.Float64 x, _), _) -> makeDecimal com r t (decimal x) + | Value(Fable.NumberConstant(NumberValue.Decimal x, _), _) -> makeDecimal com r t x | _ -> Helper.LibCall(com, "decimal", "Decimal", t, [ e ], isConstructor = true, ?loc = r) let createAtom com (value: Expr) = @@ -351,9 +351,9 @@ let toInt com (ctx: Context) r targetType (args: Expr list) = | _ -> FableError $"Unexpected non-integer type %A{typeTo}" |> raise match sourceType, targetType with - | Char, _ -> - //Helper.InstanceCall(args.Head, "charCodeAt", targetType, [ makeIntConst 0 ]) + | Char, Number(typeTo, _) -> Helper.LibCall(com, "char", "char_code_at", targetType, [ args.Head; makeIntConst 0 ]) + |> emitCast typeTo | String, _ -> stringToInt com ctx r targetType args | Number(BigInt, _), _ -> Helper.LibCall(com, "big_int", castBigIntMethod targetType, targetType, args) | Number(typeFrom, _), Number(typeTo, _) -> @@ -696,7 +696,7 @@ let rec getZero (com: ICompiler) ctx (t: Type) = | Boolean -> makeBoolConst false | Number(BigInt, _) as t -> Helper.LibCall(com, "big_int", "fromInt32", t, [ makeIntConst 0 ]) | Number(Decimal, _) as t -> makeIntConst 0 |> makeDecimalFromExpr com None t - | Number(kind, uom) -> NumberConstant(getBoxedZero kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetZero kind, uom) |> makeValue None | Char | String -> makeStrConst "" // TODO: Use null for string? | Builtin BclTimeSpan -> Helper.LibCall(com, "time_span", "create", t, [ makeIntConst 0 ]) @@ -710,16 +710,14 @@ let rec getZero (com: ICompiler) ctx (t: Type) = let getOne (com: ICompiler) ctx (t: Type) = match t with | Boolean -> makeBoolConst true - | Number(kind, uom) -> NumberConstant(getBoxedOne kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetOne kind, uom) |> makeValue None | ListSingleton(CustomOp com ctx None t "get_One" [] e) -> e | _ -> makeIntConst 1 let makeAddFunction (com: ICompiler) ctx t = let x = makeUniqueIdent ctx t "x" let y = makeUniqueIdent ctx t "y" - let body = applyOp com ctx None t Operators.addition [ IdentExpr x; IdentExpr y ] - Delegate([ x; y ], body, None, Tags.empty) let makeGenericAdder (com: ICompiler) ctx t = @@ -733,9 +731,7 @@ let makeGenericAverager (com: ICompiler) ctx t = let divideFn = let x = makeUniqueIdent ctx t "x" let i = makeUniqueIdent ctx (Int32.Number) "i" - let body = applyOp com ctx None t Operators.divideByInt [ IdentExpr x; IdentExpr i ] - Delegate([ x; i ], body, None, Tags.empty) objExpr @@ -1403,7 +1399,11 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt c, "rfind", t, - [ str; Value(NumberConstant(0, Int32, NumberInfo.Empty), None); start ], + [ + str + Value(NumberConstant(NumberValue.Int32 0, NumberInfo.Empty), None) + start + ], i.SignatureArgTypes, ?loc = r ) @@ -1999,7 +1999,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op | "IsPositiveInfinity", [ _ ] when isFloat -> Helper.LibCall(com, "double", "is_positive_inf", t, args, i.SignatureArgTypes, ?loc = r) |> Some - | ("Parse" | "TryParse") as meth, str :: NumberConst(:? int as style, _, _) :: _ -> + | ("Parse" | "TryParse") as meth, str :: NumberConst(NumberValue.Int32 style, _) :: _ -> let hexConst = int System.Globalization.NumberStyles.HexNumber let intConst = int System.Globalization.NumberStyles.Integer @@ -2734,7 +2734,6 @@ let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio | _ -> None | meth -> let args = ignoreFormatProvider com ctx r i.DeclaringEntityFullName meth args - let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst Helper.LibCall(com, moduleName, meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) diff --git a/src/Fable.Transforms/Replacements.Util.fs b/src/Fable.Transforms/Replacements.Util.fs index 6499eca4e1..7da6cb9b58 100644 --- a/src/Fable.Transforms/Replacements.Util.fs +++ b/src/Fable.Transforms/Replacements.Util.fs @@ -256,45 +256,47 @@ let toArray r t expr = Value(NewArray(ArrayFrom expr, t, kind), r) -let getBoxedZero kind : obj = - match kind with - | Int8 -> 0y: int8 - | UInt8 -> 0uy: uint8 - | Int16 -> 0s: int16 - | UInt16 -> 0us: uint16 - | Int32 -> 0: int32 - | UInt32 -> 0u: uint32 - | Int64 -> 0L: int64 - | UInt64 -> 0UL: uint64 - | Int128 -> 0L: int64 //System.Int128.Zero - | UInt128 -> 0UL: uint64 //System.UInt128.Zero - | BigInt -> 0I: bigint - | NativeInt -> 0n: nativeint - | UNativeInt -> 0un: unativeint - | Float16 -> 0.f: float32 //System.Half.Zero - | Float32 -> 0.f: float32 - | Float64 -> 0.: float - | Decimal -> 0M: decimal - -let getBoxedOne kind : obj = - match kind with - | Int8 -> 1y: int8 - | UInt8 -> 1uy: uint8 - | Int16 -> 1s: int16 - | UInt16 -> 1us: uint16 - | Int32 -> 1: int32 - | UInt32 -> 1u: uint32 - | Int64 -> 1L: int64 - | UInt64 -> 1UL: uint64 - | Int128 -> 1L: int64 //System.Int128.One - | UInt128 -> 1UL: uint64 //System.UInt128.One - | BigInt -> 1I: bigint - | NativeInt -> 1n: nativeint - | UNativeInt -> 1un: unativeint - | Float16 -> 1.f: float32 //System.Half.One - | Float32 -> 1.f: float32 - | Float64 -> 1.: float - | Decimal -> 1M: decimal +type NumberValue with + + static member GetZero(kind: NumberKind) : NumberValue = + match kind with + | NumberKind.Int8 -> NumberValue.Int8(0y: int8) + | NumberKind.UInt8 -> NumberValue.UInt8(0uy: uint8) + | NumberKind.Int16 -> NumberValue.Int16(0s: int16) + | NumberKind.UInt16 -> NumberValue.UInt16(0us: uint16) + | NumberKind.Int32 -> NumberValue.Int32(0: int32) + | NumberKind.UInt32 -> NumberValue.UInt32(0u: uint32) + | NumberKind.Int64 -> NumberValue.Int64(0L: int64) + | NumberKind.UInt64 -> NumberValue.UInt64(0UL: uint64) + | NumberKind.Int128 -> NumberValue.Int128(0UL, 0UL) //System.Int128.Zero + | NumberKind.UInt128 -> NumberValue.UInt128(0UL, 0UL) //System.UInt128.Zero + | NumberKind.BigInt -> NumberValue.BigInt(0I: bigint) + | NumberKind.NativeInt -> NumberValue.NativeInt(0n: nativeint) + | NumberKind.UNativeInt -> NumberValue.UNativeInt(0un: unativeint) + | NumberKind.Float16 -> NumberValue.Float16(0.f: float32) //System.Half.Zero + | NumberKind.Float32 -> NumberValue.Float32(0.f: float32) + | NumberKind.Float64 -> NumberValue.Float64(0.: float) + | NumberKind.Decimal -> NumberValue.Decimal(0M: decimal) + + static member GetOne(kind: NumberKind) : NumberValue = + match kind with + | NumberKind.Int8 -> NumberValue.Int8(1y: int8) + | NumberKind.UInt8 -> NumberValue.UInt8(1uy: uint8) + | NumberKind.Int16 -> NumberValue.Int16(1s: int16) + | NumberKind.UInt16 -> NumberValue.UInt16(1us: uint16) + | NumberKind.Int32 -> NumberValue.Int32(1: int32) + | NumberKind.UInt32 -> NumberValue.UInt32(1u: uint32) + | NumberKind.Int64 -> NumberValue.Int64(1L: int64) + | NumberKind.UInt64 -> NumberValue.UInt64(1UL: uint64) + | NumberKind.Int128 -> NumberValue.Int128(0UL, 1UL) //System.Int128.One + | NumberKind.UInt128 -> NumberValue.UInt128(0UL, 1UL) //System.UInt128.One + | NumberKind.BigInt -> NumberValue.BigInt(1I: bigint) + | NumberKind.NativeInt -> NumberValue.NativeInt(1n: nativeint) + | NumberKind.UNativeInt -> NumberValue.UNativeInt(1un: unativeint) + | NumberKind.Float16 -> NumberValue.Float16(1.f: float32) //System.Half.One + | NumberKind.Float32 -> NumberValue.Float32(1.f: float32) + | NumberKind.Float64 -> NumberValue.Float64(1.: float) + | NumberKind.Decimal -> NumberValue.Decimal(1M: decimal) type BuiltinType = | BclGuid @@ -852,7 +854,7 @@ let (|CustomOp|_|) (com: ICompiler) (ctx: Context) r t opName (argExprs: Expr li let (|RegexFlags|_|) e = let rec getFlags = function - | NumberConst(:? int as value, _, _) -> + | NumberConst(NumberValue.Int32 value, _) -> match value with | 1 -> Some [ RegexIgnoreCase ] | 2 -> Some [ RegexMultiline ] diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index 23f04a8ea6..efce42c565 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -303,7 +303,6 @@ let toLong com (ctx: Context) r targetType (args: Expr list) : Expr = |> wrapLong com ctx r targetType | _ -> addWarning com ctx.InlinePath r "Cannot make conversion because source type is unknown" - TypeCast(args.Head, targetType) let emitIntCast toKind arg = @@ -321,10 +320,9 @@ let toInt com (ctx: Context) r targetType (args: Expr list) = let sourceType = args.Head.Type match sourceType, targetType with - | Char, _ -> - match targetType, args with - | Number(kind, _), Value(CharConstant c, r) :: _ -> Value(NumberConstant(c, kind, NumberInfo.Empty), r) - | _ -> Helper.InstanceCall(args.Head, "charCodeAt", targetType, [ makeIntConst 0 ]) + | Char, Number(toKind, _) -> + Helper.InstanceCall(args.Head, "charCodeAt", targetType, [ makeIntConst 0 ]) + |> emitIntCast toKind | String, _ -> stringToInt com ctx r targetType args | Number(fromKind, _), Number(toKind, _) -> if needToCast fromKind toKind then @@ -339,7 +337,6 @@ let toInt com (ctx: Context) r targetType (args: Expr list) = TypeCast(args.Head, targetType) | _ -> addWarning com ctx.InlinePath r "Cannot make conversion because source type is unknown" - TypeCast(args.Head, targetType) let round com (args: Expr list) = @@ -668,7 +665,7 @@ let rec getZero (com: ICompiler) (ctx: Context) (t: Type) = | Boolean -> makeBoolConst false | Char | String -> makeStrConst "" // TODO: Use null for string? - | Number(kind, uom) -> NumberConstant(getBoxedZero kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetZero kind, uom) |> makeValue None | Builtin(BclTimeSpan | BclTimeOnly) -> makeIntConst 0 // TODO: Type cast | Builtin BclDateTime as t -> Helper.LibCall(com, "Date", "minValue", t, []) | Builtin BclDateTimeOffset as t -> Helper.LibCall(com, "DateOffset", "minValue", t, []) @@ -681,7 +678,7 @@ let rec getZero (com: ICompiler) (ctx: Context) (t: Type) = let getOne (com: ICompiler) (ctx: Context) (t: Type) = match t with | Boolean -> makeBoolConst true - | Number(kind, uom) -> NumberConstant(getBoxedOne kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetOne kind, uom) |> makeValue None | ListSingleton(CustomOp com ctx None t "get_One" [] e) -> e | _ -> makeIntConst 1 @@ -757,7 +754,7 @@ let makePojo (com: Compiler) caseRule keyValueList = let caseRule = match caseRule with - | Some(NumberConst(:? int as rule, _, _)) -> Some rule + | Some(NumberConst(NumberValue.Int32 rule, _)) -> Some rule | _ -> None |> Option.map enum |> Option.defaultValue Fable.Core.CaseRules.None @@ -2283,7 +2280,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op Helper.LibCall(com, "Double", "isInfinity", t, args, i.SignatureArgTypes, ?loc = r) |> Some | ("Min" | "Max" | "MinMagnitude" | "MaxMagnitude" | "Clamp"), _ -> operators com ctx r t i thisArg args - | ("Parse" | "TryParse") as meth, str :: NumberConst(:? int as style, _, _) :: _ -> + | ("Parse" | "TryParse") as meth, str :: NumberConst(NumberValue.Int32 style, _) :: _ -> let hexConst = int System.Globalization.NumberStyles.HexNumber let intConst = int System.Globalization.NumberStyles.Integer diff --git a/src/Fable.Transforms/Rust/Fable2Rust.fs b/src/Fable.Transforms/Rust/Fable2Rust.fs index f566a988fd..814e52c632 100644 --- a/src/Fable.Transforms/Rust/Fable2Rust.fs +++ b/src/Fable.Transforms/Rust/Fable2Rust.fs @@ -1650,90 +1650,95 @@ module Util = else expr - let makeNumber com ctx r t kind (x: obj) = - match kind, x with - | Int8, (:? int8 as x) when x = System.SByte.MinValue -> mkGenericPathExpr ("i8" :: "MIN" :: []) None - | Int8, (:? int8 as x) when x = System.SByte.MaxValue -> mkGenericPathExpr ("i8" :: "MAX" :: []) None - | Int16, (:? int16 as x) when x = System.Int16.MinValue -> mkGenericPathExpr ("i16" :: "MIN" :: []) None - | Int16, (:? int16 as x) when x = System.Int16.MaxValue -> mkGenericPathExpr ("i16" :: "MAX" :: []) None - | Int32, (:? int32 as x) when x = System.Int32.MinValue -> mkGenericPathExpr ("i32" :: "MIN" :: []) None - | Int32, (:? int32 as x) when x = System.Int32.MaxValue -> mkGenericPathExpr ("i32" :: "MAX" :: []) None - | Int64, (:? int64 as x) when x = System.Int64.MinValue -> mkGenericPathExpr ("i64" :: "MIN" :: []) None - | Int64, (:? int64 as x) when x = System.Int64.MaxValue -> mkGenericPathExpr ("i64" :: "MAX" :: []) None - // | Int128, (:? System.Int128 as x) when x = System.Int128.MinValue -> + let makeNumber com ctx r t (v: Fable.NumberValue) = + match v with + | Fable.NumberValue.Int8 x when x = System.SByte.MinValue -> mkGenericPathExpr ("i8" :: "MIN" :: []) None + | Fable.NumberValue.Int8 x when x = System.SByte.MaxValue -> mkGenericPathExpr ("i8" :: "MAX" :: []) None + | Fable.NumberValue.Int16 x when x = System.Int16.MinValue -> mkGenericPathExpr ("i16" :: "MIN" :: []) None + | Fable.NumberValue.Int16 x when x = System.Int16.MaxValue -> mkGenericPathExpr ("i16" :: "MAX" :: []) None + | Fable.NumberValue.Int32 x when x = System.Int32.MinValue -> mkGenericPathExpr ("i32" :: "MIN" :: []) None + | Fable.NumberValue.Int32 x when x = System.Int32.MaxValue -> mkGenericPathExpr ("i32" :: "MAX" :: []) None + | Fable.NumberValue.Int64 x when x = System.Int64.MinValue -> mkGenericPathExpr ("i64" :: "MIN" :: []) None + | Fable.NumberValue.Int64 x when x = System.Int64.MaxValue -> mkGenericPathExpr ("i64" :: "MAX" :: []) None + // | Fable.NumberValue.Int128 x when x = System.Int128.MinValue -> // mkGenericPathExpr ("i128"::"MIN"::[]) None - // | Int128, (:? System.Int128 as x) when x = System.Int128.MaxValue -> + // | Fable.NumberValue.Int128 x when x = System.Int128.MaxValue -> // mkGenericPathExpr ("i128"::"MAX"::[]) None - // | UInt8, (:? uint8 as x) when x = System.Byte.MinValue -> + // | Fable.NumberValue.UInt8 x when x = System.Byte.MinValue -> // mkGenericPathExpr ("u8"::"MIN"::[]) None - | UInt8, (:? uint8 as x) when x = System.Byte.MaxValue -> mkGenericPathExpr ("u8" :: "MAX" :: []) None - // | UInt16, (:? uint16 as x) when x = System.UInt16.MinValue -> + | Fable.NumberValue.UInt8 x when x = System.Byte.MaxValue -> mkGenericPathExpr ("u8" :: "MAX" :: []) None + // | Fable.NumberValue.UInt16 x when x = System.UInt16.MinValue -> // mkGenericPathExpr ("u16"::"MIN"::[]) None - | UInt16, (:? uint16 as x) when x = System.UInt16.MaxValue -> mkGenericPathExpr ("u16" :: "MAX" :: []) None - // | UInt32, (:? uint32 as x) when x = System.UInt32.MinValue -> + | Fable.NumberValue.UInt16 x when x = System.UInt16.MaxValue -> mkGenericPathExpr ("u16" :: "MAX" :: []) None + // | Fable.NumberValue.UInt32, (:? uint32 as x) when x = System.UInt32.MinValue -> // mkGenericPathExpr ("u32"::"MIN"::[]) None - | UInt32, (:? uint32 as x) when x = System.UInt32.MaxValue -> mkGenericPathExpr ("u32" :: "MAX" :: []) None - // | UInt64, (:? uint64 as x) when x = System.UInt64.MinValue -> + | Fable.NumberValue.UInt32 x when x = System.UInt32.MaxValue -> mkGenericPathExpr ("u32" :: "MAX" :: []) None + // | Fable.NumberValue.UInt64 x when x = System.UInt64.MinValue -> // mkGenericPathExpr ("u64"::"MIN"::[]) None - | UInt64, (:? uint64 as x) when x = System.UInt64.MaxValue -> mkGenericPathExpr ("u64" :: "MAX" :: []) None - // | UInt128, (:? System.UInt128 as x) when x = System.UInt128.MinValue -> + | Fable.NumberValue.UInt64 x when x = System.UInt64.MaxValue -> mkGenericPathExpr ("u64" :: "MAX" :: []) None + // | Fable.NumberValue.UInt128 x when x = System.UInt128.MinValue -> // mkGenericPathExpr ("u128"::"MIN"::[]) None - // | UInt128, (:? System.UInt128 as x) when x = System.UInt128.MaxValue -> + // | Fable.NumberValue.UInt128 x when x = System.UInt128.MaxValue -> // mkGenericPathExpr ("u128"::"MAX"::[]) None - | Float32, (:? float32 as x) when System.Single.IsNaN(x) -> mkGenericPathExpr ("f32" :: "NAN" :: []) None - | Float64, (:? float as x) when System.Double.IsNaN(x) -> mkGenericPathExpr ("f64" :: "NAN" :: []) None - | Float32, (:? float32 as x) when System.Single.IsPositiveInfinity(x) -> + | Fable.NumberValue.Float32 x when System.Single.IsNaN(x) -> mkGenericPathExpr ("f32" :: "NAN" :: []) None + | Fable.NumberValue.Float64 x when System.Double.IsNaN(x) -> mkGenericPathExpr ("f64" :: "NAN" :: []) None + | Fable.NumberValue.Float32 x when System.Single.IsPositiveInfinity(x) -> mkGenericPathExpr ("f32" :: "INFINITY" :: []) None - | Float64, (:? float as x) when System.Double.IsPositiveInfinity(x) -> + | Fable.NumberValue.Float64 x when System.Double.IsPositiveInfinity(x) -> mkGenericPathExpr ("f64" :: "INFINITY" :: []) None - | Float32, (:? float32 as x) when System.Single.IsNegativeInfinity(x) -> + | Fable.NumberValue.Float32 x when System.Single.IsNegativeInfinity(x) -> mkGenericPathExpr ("f32" :: "NEG_INFINITY" :: []) None - | Float64, (:? float as x) when System.Double.IsNegativeInfinity(x) -> + | Fable.NumberValue.Float64 x when System.Double.IsNegativeInfinity(x) -> mkGenericPathExpr ("f64" :: "NEG_INFINITY" :: []) None - | NativeInt, (:? nativeint as x) -> + | Fable.NumberValue.NativeInt x -> let expr = mkIsizeLitExpr (abs x |> string) expr |> negateWhen (x < 0n) - | Int8, (:? int8 as x) -> + | Fable.NumberValue.Int8 x -> let expr = mkInt8LitExpr (abs x |> string) expr |> negateWhen (x < 0y) - | Int16, (:? int16 as x) -> + | Fable.NumberValue.Int16 x -> let expr = mkInt16LitExpr (abs x |> string) expr |> negateWhen (x < 0s) - | Int32, (:? int32 as x) -> + | Fable.NumberValue.Int32 x -> let expr = mkInt32LitExpr (abs x |> string) expr |> negateWhen (x < 0) - | Int64, (:? int64 as x) -> + | Fable.NumberValue.Int64 x -> let expr = mkInt64LitExpr (abs x |> string) expr |> negateWhen (x < 0L) - | Int128, x -> // (:? System.Int128 as x) -> - // let expr = mkInt128LitExpr (System.Int128.Abs(x) |> string) - // expr |> negateWhen (System.Int128.IsNegative(x)) - let s = string x + | Fable.NumberValue.Int128(upper, lower) -> + let bytes = + Array.concat [ BitConverter.GetBytes(lower); BitConverter.GetBytes(upper) ] // little endian + + let big = Numerics.BigInteger(bytes) + let s = string big let expr = mkInt128LitExpr (s.TrimStart('-')) expr |> negateWhen (s.StartsWith("-", StringComparison.Ordinal)) - | UNativeInt, (:? unativeint as x) -> mkUsizeLitExpr (x |> string) - | UInt8, (:? uint8 as x) -> mkUInt8LitExpr (x |> string) - | UInt16, (:? uint16 as x) -> mkUInt16LitExpr (x |> string) - | UInt32, (:? uint32 as x) -> mkUInt32LitExpr (x |> string) - | UInt64, (:? uint64 as x) -> mkUInt64LitExpr (x |> string) - | UInt128, x -> // (:? System.UInt128 as x) -> - mkUInt128LitExpr (x |> string) - | Float16, (:? float32 as x) -> + | Fable.NumberValue.UNativeInt x -> mkUsizeLitExpr (x |> string) + | Fable.NumberValue.UInt8 x -> mkUInt8LitExpr (x |> string) + | Fable.NumberValue.UInt16 x -> mkUInt16LitExpr (x |> string) + | Fable.NumberValue.UInt32 x -> mkUInt32LitExpr (x |> string) + | Fable.NumberValue.UInt64 x -> mkUInt64LitExpr (x |> string) + | Fable.NumberValue.UInt128(upper, lower) -> + let bytes = + Array.concat [ BitConverter.GetBytes(lower); BitConverter.GetBytes(upper); [| 0uy |] ] // little endian + + let big = Numerics.BigInteger(bytes) + mkUInt128LitExpr (string big) + | Fable.NumberValue.Float16 x -> let expr = mkFloat32LitExpr (abs x |> string) expr |> negateWhen (x < 0.0f) - | Float32, (:? float32 as x) -> + | Fable.NumberValue.Float32 x -> let expr = mkFloat32LitExpr (abs x |> string) expr |> negateWhen (x < 0.0f) - | Float64, (:? float as x) -> + | Fable.NumberValue.Float64 x -> let expr = mkFloat64LitExpr (abs x |> string) expr |> negateWhen (x < 0.0) - | Decimal, (:? decimal as x) -> Replacements.makeDecimal com r t x |> transformExpr com ctx - | kind, x -> - $"Expected literal of type %A{kind} but got {x.GetType().FullName}" - |> addError com [] r + | Fable.NumberValue.Decimal x -> Replacements.makeDecimal com r t x |> transformExpr com ctx + | _ -> + $"Numeric literal is not supported: %A{v}" |> addError com [] r mkFloat64LitExpr (string 0.) @@ -1943,7 +1948,7 @@ module Util = | Fable.CharConstant c -> mkCharLitExpr c //, ?loc=r) | Fable.StringConstant s -> mkStrLitExpr s |> makeStaticString com ctx | Fable.StringTemplate(_tag, parts, values) -> makeStringTemplate com ctx parts values - | Fable.NumberConstant(x, kind, _) -> makeNumber com ctx r value.Type kind x + | Fable.NumberConstant(x, _) -> makeNumber com ctx r value.Type x | Fable.RegexConstant(source, flags) -> // Expression.regExpLiteral(source, flags, ?loc=r) unimplemented () @@ -3016,7 +3021,7 @@ module Util = |> List.map (fun (caseExpr, targetIndex, boundValues) -> let patOpt = match caseExpr with - | Fable.Value(Fable.NumberConstant(:? int as tag, Int32, Fable.NumberInfo.Empty), r) -> + | Fable.Value(Fable.NumberConstant(Fable.NumberValue.Int32 tag, Fable.NumberInfo.Empty), r) -> makeUnionCasePatOpt evalType evalName tag | _ -> None diff --git a/src/Fable.Transforms/Rust/Replacements.fs b/src/Fable.Transforms/Rust/Replacements.fs index 25d7c7ca92..3f3f9a7945 100644 --- a/src/Fable.Transforms/Rust/Replacements.fs +++ b/src/Fable.Transforms/Rust/Replacements.fs @@ -612,7 +612,7 @@ let rec getZero (com: ICompiler) (ctx: Context) (t: Type) = | Boolean -> makeBoolConst false | Number(BigInt, _) -> Helper.LibCall(com, "BigInt", "zero", t, []) | Number(Decimal, _) -> Helper.LibValue(com, "Decimal", "Zero", t) - | Number(kind, uom) -> NumberConstant(getBoxedZero kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetZero kind, uom) |> makeValue None | Char -> CharConstant '\u0000' |> makeValue None | String -> makeStrConst "" // TODO: Use null for string? | Array(typ, _) -> makeArray typ [] @@ -632,7 +632,7 @@ let getOne (com: ICompiler) (ctx: Context) (t: Type) = | Boolean -> makeBoolConst true | Number(BigInt, _) -> Helper.LibCall(com, "BigInt", "one", t, []) | Number(Decimal, _) -> Helper.LibValue(com, "Decimal", "One", t) - | Number(kind, uom) -> NumberConstant(getBoxedOne kind, kind, uom) |> makeValue None + | Number(kind, uom) -> NumberConstant(NumberValue.GetOne kind, uom) |> makeValue None | ListSingleton(CustomOp com ctx None t "get_One" [] e) -> e | _ -> makeIntConst 1 @@ -1228,8 +1228,8 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt | [] -> false | [ BoolConst ignoreCase ] -> ignoreCase | [ BoolConst ignoreCase; _cultureInfo ] -> ignoreCase - | [ NumberConst(:? int as kind, _, NumberInfo.IsEnum _) ] -> kind = 1 || kind = 3 || kind = 5 - | [ _cultureInfo; NumberConst(:? int as options, _, NumberInfo.IsEnum _) ] -> + | [ NumberConst(NumberValue.Int32 kind, NumberInfo.IsEnum _) ] -> kind = 1 || kind = 3 || kind = 5 + | [ _cultureInfo; NumberConst(NumberValue.Int32 options, NumberInfo.IsEnum _) ] -> (options &&& 1 <> 0) || (options &&& 268435456 <> 0) | _ -> false @@ -1296,8 +1296,9 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt | None, [ ExprTypeAs(String, x); ExprTypeAs(String, y) ] -> Helper.LibCall(com, "String", "equalsOrdinal", t, [ x; y; makeBoolConst false ], ?loc = r) |> Some - | Some x, [ ExprTypeAs(String, y); NumberConst(:? int as kind, _, NumberInfo.IsEnum _) ] - | None, [ ExprTypeAs(String, x); ExprTypeAs(String, y); NumberConst(:? int as kind, _, NumberInfo.IsEnum _) ] -> + | Some x, [ ExprTypeAs(String, y); NumberConst(NumberValue.Int32 kind, NumberInfo.IsEnum _) ] + | None, + [ ExprTypeAs(String, x); ExprTypeAs(String, y); NumberConst(NumberValue.Int32 kind, NumberInfo.IsEnum _) ] -> if kind <> 4 && kind <> 5 then $"String.Equals will be compiled with ordinal equality" |> addWarning com ctx.InlinePath r @@ -2032,7 +2033,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op Operation(Logical(LogicalAnd, op1, op2), Tags.empty, t, None) |> Some | "IsInfinity", [ arg ] when isFloat -> makeInstanceCall r t i arg "is_infinite" [] |> Some | ("Min" | "Max" | "MinMagnitude" | "MaxMagnitude" | "Clamp"), _ -> operators com ctx r t i thisArg args - | ("Parse" | "TryParse") as meth, str :: NumberConst(:? int as style, _, _) :: _ -> + | ("Parse" | "TryParse") as meth, str :: NumberConst(NumberValue.Int32 style, _) :: _ -> let hexConst = int System.Globalization.NumberStyles.HexNumber let intConst = int System.Globalization.NumberStyles.Integer diff --git a/src/Fable.Transforms/Transforms.Util.fs b/src/Fable.Transforms/Transforms.Util.fs index 8022b6fcdc..3d2bcf8b8e 100644 --- a/src/Fable.Transforms/Transforms.Util.fs +++ b/src/Fable.Transforms/Transforms.Util.fs @@ -809,7 +809,7 @@ module AST = let (|NumberConst|_|) = function - | MaybeCasted(Value(NumberConstant(value, kind, info), _)) -> Some(value, kind, info) + | MaybeCasted(Value(NumberConstant(value, info), _)) -> Some(value, info) | _ -> None let (|NullConst|_|) = @@ -993,10 +993,10 @@ module AST = let makeStrConst (x: string) = StringConstant x |> makeValue None let makeIntConst (x: int) = - NumberConstant(x, Int32, NumberInfo.Empty) |> makeValue None + NumberConstant(NumberValue.Int32 x, NumberInfo.Empty) |> makeValue None let makeFloatConst (x: float) = - NumberConstant(x, Float64, NumberInfo.Empty) |> makeValue None + NumberConstant(NumberValue.Float64 x, NumberInfo.Empty) |> makeValue None let makeRegexConst r (pattern: string) flags = let flags = RegexGlobal :: RegexUnicode :: flags // .NET regex are always global & unicode @@ -1008,18 +1008,18 @@ module AST = | :? string as x -> StringConstant x |> makeValue None | :? char as x -> CharConstant x |> makeValue None // Integer types - | :? int8 as x -> NumberConstant(x, Int8, NumberInfo.Empty) |> makeValue None - | :? uint8 as x -> NumberConstant(x, UInt8, NumberInfo.Empty) |> makeValue None - | :? int16 as x -> NumberConstant(x, Int16, NumberInfo.Empty) |> makeValue None - | :? uint16 as x -> NumberConstant(x, UInt16, NumberInfo.Empty) |> makeValue None - | :? int32 as x -> NumberConstant(x, Int32, NumberInfo.Empty) |> makeValue None - | :? uint32 as x -> NumberConstant(x, UInt32, NumberInfo.Empty) |> makeValue None - | :? int64 as x -> NumberConstant(x, Int64, NumberInfo.Empty) |> makeValue None - | :? uint64 as x -> NumberConstant(x, UInt64, NumberInfo.Empty) |> makeValue None + | :? int8 as x -> NumberConstant(NumberValue.Int8 x, NumberInfo.Empty) |> makeValue None + | :? uint8 as x -> NumberConstant(NumberValue.UInt8 x, NumberInfo.Empty) |> makeValue None + | :? int16 as x -> NumberConstant(NumberValue.Int16 x, NumberInfo.Empty) |> makeValue None + | :? uint16 as x -> NumberConstant(NumberValue.UInt16 x, NumberInfo.Empty) |> makeValue None + | :? int32 as x -> NumberConstant(NumberValue.Int32 x, NumberInfo.Empty) |> makeValue None + | :? uint32 as x -> NumberConstant(NumberValue.UInt32 x, NumberInfo.Empty) |> makeValue None + | :? int64 as x -> NumberConstant(NumberValue.Int64 x, NumberInfo.Empty) |> makeValue None + | :? uint64 as x -> NumberConstant(NumberValue.UInt64 x, NumberInfo.Empty) |> makeValue None // Float types - | :? float32 as x -> NumberConstant(x, Float32, NumberInfo.Empty) |> makeValue None - | :? float as x -> NumberConstant(x, Float64, NumberInfo.Empty) |> makeValue None - | :? decimal as x -> NumberConstant(x, Decimal, NumberInfo.Empty) |> makeValue None + | :? float32 as x -> NumberConstant(NumberValue.Float32 x, NumberInfo.Empty) |> makeValue None + | :? float as x -> NumberConstant(NumberValue.Float64 x, NumberInfo.Empty) |> makeValue None + | :? decimal as x -> NumberConstant(NumberValue.Decimal x, NumberInfo.Empty) |> makeValue None | _ -> FableError $"Cannot create expression for object {value} (%s{value.GetType().FullName})" |> raise @@ -1029,21 +1029,52 @@ module AST = | Boolean, (:? bool as x) -> BoolConstant x |> makeValue r | String, (:? string as x) -> StringConstant x |> makeValue r | Char, (:? char as x) -> CharConstant x |> makeValue r - | Number(kind, info), x -> NumberConstant(x, kind, info) |> makeValue r + | Number(kind, info), x -> + + // TODO : this needs some attention. Do kind and type of obj always match here? If not, should we cast early? + + match kind, x with + | Decimal, (:? decimal as x) -> NumberValue.Decimal x + | BigInt, (:? bigint as x) -> NumberValue.BigInt x + | Int64, (:? int64 as x) -> NumberValue.Int64 x + | UInt64, (:? uint64 as x) -> NumberValue.UInt64 x + | NativeInt, (:? nativeint as x) -> NumberValue.NativeInt x + | UNativeInt, (:? unativeint as x) -> NumberValue.UNativeInt x + | Int8, (:? int8 as x) -> NumberValue.Int8 x + | UInt8, (:? uint8 as x) -> NumberValue.UInt8 x + | Int16, (:? int16 as x) -> NumberValue.Int16 x + | UInt16, (:? uint16 as x) -> NumberValue.UInt16 x + | Int32, (:? int32 as x) -> NumberValue.Int32 x + | UInt32, (:? uint32 as x) -> NumberValue.UInt32 x + | Float32, (:? float32 as x) -> NumberValue.Float32 x + | Float64, (:? float as x) -> NumberValue.Float64 x + + | Int128, _ + | UInt128, _ + | Float16, _ -> + FableError $"Unsupported Number Kind %A{kind} and value %A{x} combination" + |> raise + + | _ -> + FableError $"Unexpected Number Kind %A{kind} and value %A{value} combination" + |> raise + + |> fun value -> NumberConstant(value, info) |> makeValue r + | Unit, _ -> UnitConstant |> makeValue r // Arrays with small data type (ushort, byte) are represented // in F# AST as BasicPatterns.Const | Array(Number(kind, uom), arrayKind), (:? (byte[]) as arr) -> let values = arr - |> Array.map (fun x -> NumberConstant(x, kind, uom) |> makeValue None) + |> Array.map (fun x -> NumberConstant(NumberValue.UInt8 x, uom) |> makeValue None) |> Seq.toList NewArray(ArrayValues values, Number(kind, uom), arrayKind) |> makeValue r | Array(Number(kind, uom), arrayKind), (:? (uint16[]) as arr) -> let values = arr - |> Array.map (fun x -> NumberConstant(x, kind, uom) |> makeValue None) + |> Array.map (fun x -> NumberConstant(NumberValue.UInt16 x, uom) |> makeValue None) |> Seq.toList NewArray(ArrayValues values, Number(kind, uom), arrayKind) |> makeValue r diff --git a/tests/Js/Main/ConvertTests.fs b/tests/Js/Main/ConvertTests.fs index dae84f117b..e9f966d2c9 100644 --- a/tests/Js/Main/ConvertTests.fs +++ b/tests/Js/Main/ConvertTests.fs @@ -280,6 +280,7 @@ let tests = Convert.ToSByte(2.6) |> equal (x+x+x) Convert.ToSByte(3.5) |> equal (x+x+x+x) Convert.ToSByte("1") |> equal x + Convert.ToSByte('a') |> equal 97y (fun () -> Convert.ToSByte("1.4")) |> throwsError "" (fun () -> Convert.ToSByte("foo")) |> throwsError "" @@ -323,6 +324,7 @@ let tests = Convert.ToInt16(2.6) |> equal (x+x+x) Convert.ToInt16(3.5) |> equal (x+x+x+x) Convert.ToInt16("1") |> equal x + Convert.ToInt16('a') |> equal 97s (fun () -> Convert.ToInt16("1.4")) |> throwsError "" (fun () -> Convert.ToInt16("foo")) |> throwsError "" @@ -366,6 +368,7 @@ let tests = Convert.ToInt32(2.6) |> equal (x+x+x) Convert.ToInt32(3.5) |> equal (x+x+x+x) Convert.ToInt32("1") |> equal x + Convert.ToInt32('a') |> equal 97 (fun () -> Convert.ToInt32("1.4")) |> throwsError "" (fun () -> Convert.ToInt32("foo")) |> throwsError "" @@ -428,6 +431,7 @@ let tests = Convert.ToInt64(2.6) |> equal (x+x+x) Convert.ToInt64(3.5) |> equal (x+x+x+x) Convert.ToInt64("1") |> equal x + Convert.ToInt64('a') |> equal 97L (fun () -> Convert.ToInt64("1.4")) |> throwsError "" (fun () -> Convert.ToInt64("foo")) |> throwsError "" @@ -471,6 +475,7 @@ let tests = Convert.ToByte(2.6) |> equal (x+x+x) Convert.ToByte(3.5) |> equal (x+x+x+x) Convert.ToByte("1") |> equal x + Convert.ToByte('a') |> equal 97uy (fun () -> Convert.ToByte("1.4")) |> throwsError "" (fun () -> Convert.ToByte("foo")) |> throwsError "" @@ -514,6 +519,7 @@ let tests = Convert.ToUInt16(2.6) |> equal (x+x+x) Convert.ToUInt16(3.5) |> equal (x+x+x+x) Convert.ToUInt16("1") |> equal x + Convert.ToUInt16('a') |> equal 97us (fun () -> Convert.ToUInt16("1.4")) |> throwsError "" (fun () -> Convert.ToUInt16("foo")) |> throwsError "" @@ -557,6 +563,7 @@ let tests = Convert.ToUInt32(2.6) |> equal (x+x+x) Convert.ToUInt32(3.5) |> equal (x+x+x+x) Convert.ToUInt32("1") |> equal x + Convert.ToUInt32('a') |> equal 97u (fun () -> Convert.ToUInt32("1.4")) |> throwsError "" (fun () -> Convert.ToUInt32("foo")) |> throwsError "" @@ -600,6 +607,7 @@ let tests = Convert.ToUInt64(2.6) |> equal (x+x+x) Convert.ToUInt64(3.5) |> equal (x+x+x+x) Convert.ToUInt64("1") |> equal x + Convert.ToUInt64('a') |> equal 97UL (fun () -> Convert.ToUInt64("1.4")) |> throwsError "" (fun () -> Convert.ToUInt64("foo")) |> throwsError "" diff --git a/tests/Python/TestConvert.fs b/tests/Python/TestConvert.fs index 01b3fbcc1f..5d57610232 100644 --- a/tests/Python/TestConvert.fs +++ b/tests/Python/TestConvert.fs @@ -303,6 +303,7 @@ let ``test System.Convert.ToSByte works`` () = Convert.ToSByte(2.6) |> equal (x+x+x) Convert.ToSByte(3.5) |> equal (x+x+x+x) Convert.ToSByte("1") |> equal x + Convert.ToSByte('a') |> equal 97y (fun () -> Convert.ToSByte("1.4")) |> throwsError "" (fun () -> Convert.ToSByte("foo")) |> throwsError "" @@ -347,6 +348,7 @@ let ``test System.Convert.ToInt16 works`` () = Convert.ToInt16(2.6) |> equal (x+x+x) Convert.ToInt16(3.5) |> equal (x+x+x+x) Convert.ToInt16("1") |> equal x + Convert.ToInt16('a') |> equal 97s (fun () -> Convert.ToInt16("1.4")) |> throwsError "" (fun () -> Convert.ToInt16("foo")) |> throwsError "" @@ -391,6 +393,7 @@ let ``test System.Convert.ToInt32 works`` () = Convert.ToInt32(2.6) |> equal (x+x+x) Convert.ToInt32(3.5) |> equal (x+x+x+x) Convert.ToInt32("1") |> equal x + Convert.ToInt32('a') |> equal 97 (fun () -> Convert.ToInt32("1.4")) |> throwsError "" (fun () -> Convert.ToInt32("foo")) |> throwsError "" @@ -456,6 +459,7 @@ let ``test System.Convert.ToInt64 works`` () = Convert.ToInt64(2.6) |> equal (x+x+x) Convert.ToInt64(3.5) |> equal (x+x+x+x) Convert.ToInt64("1") |> equal x + Convert.ToInt64('a') |> equal 97L (fun () -> Convert.ToInt64("1.4")) |> throwsError "" (fun () -> Convert.ToInt64("foo")) |> throwsError "" @@ -500,6 +504,7 @@ let ``test System.Convert.ToByte works`` () = Convert.ToByte(2.6) |> equal (x+x+x) Convert.ToByte(3.5) |> equal (x+x+x+x) Convert.ToByte("1") |> equal x + Convert.ToByte('a') |> equal 97uy (fun () -> Convert.ToByte("1.4")) |> throwsError "" (fun () -> Convert.ToByte("foo")) |> throwsError "" @@ -544,6 +549,7 @@ let ``test System.Convert.ToUInt16 works`` () = Convert.ToUInt16(2.6) |> equal (x+x+x) Convert.ToUInt16(3.5) |> equal (x+x+x+x) Convert.ToUInt16("1") |> equal x + Convert.ToUInt16('a') |> equal 97us (fun () -> Convert.ToUInt16("1.4")) |> throwsError "" (fun () -> Convert.ToUInt16("foo")) |> throwsError "" @@ -588,6 +594,7 @@ let ``test System.Convert.ToUInt32 works`` () = Convert.ToUInt32(2.6) |> equal (x+x+x) Convert.ToUInt32(3.5) |> equal (x+x+x+x) Convert.ToUInt32("1") |> equal x + Convert.ToUInt32('a') |> equal 97u (fun () -> Convert.ToUInt32("1.4")) |> throwsError "" (fun () -> Convert.ToUInt32("foo")) |> throwsError "" @@ -632,6 +639,7 @@ let ``test System.Convert.ToUInt64 works`` () = Convert.ToUInt64(2.6) |> equal (x+x+x) Convert.ToUInt64(3.5) |> equal (x+x+x+x) Convert.ToUInt64("1") |> equal x + Convert.ToUInt64('a') |> equal 97UL (fun () -> Convert.ToUInt64("1.4")) |> throwsError "" (fun () -> Convert.ToUInt64("foo")) |> throwsError "" diff --git a/tests/Rust/tests/src/ConvertTests.fs b/tests/Rust/tests/src/ConvertTests.fs index 2d2a392ebc..bfa40f5a4c 100644 --- a/tests/Rust/tests/src/ConvertTests.fs +++ b/tests/Rust/tests/src/ConvertTests.fs @@ -319,6 +319,7 @@ let ``System.Convert.ToSByte works`` () = Convert.ToSByte(2.6) |> equal (x+x+x) Convert.ToSByte(3.5) |> equal (x+x+x+x) Convert.ToSByte("1") |> equal x + Convert.ToSByte('a') |> equal 97y [] let ``System.Convert.ToInt16 works`` () = @@ -359,6 +360,7 @@ let ``System.Convert.ToInt16 works`` () = Convert.ToInt16(2.6) |> equal (x+x+x) Convert.ToInt16(3.5) |> equal (x+x+x+x) Convert.ToInt16("1") |> equal x + Convert.ToInt16('a') |> equal 97s [] let ``System.Convert.ToInt32 works`` () = @@ -399,6 +401,7 @@ let ``System.Convert.ToInt32 works`` () = Convert.ToInt32(2.6) |> equal (x+x+x) Convert.ToInt32(3.5) |> equal (x+x+x+x) Convert.ToInt32("1") |> equal x + Convert.ToInt32('a') |> equal 97 [] let ``Special cases conversion to and from Int64 work`` () = @@ -460,6 +463,7 @@ let ``System.Convert.ToInt64 works`` () = Convert.ToInt64(2.6) |> equal (x+x+x) Convert.ToInt64(3.5) |> equal (x+x+x+x) Convert.ToInt64("1") |> equal x + Convert.ToInt64('a') |> equal 97L [] let ``System.Convert.ToByte works`` () = @@ -500,6 +504,7 @@ let ``System.Convert.ToByte works`` () = Convert.ToByte(2.6) |> equal (x+x+x) Convert.ToByte(3.5) |> equal (x+x+x+x) Convert.ToByte("1") |> equal x + Convert.ToByte('a') |> equal 97uy [] let ``System.Convert.ToUInt16 works`` () = @@ -540,6 +545,7 @@ let ``System.Convert.ToUInt16 works`` () = Convert.ToUInt16(2.6) |> equal (x+x+x) Convert.ToUInt16(3.5) |> equal (x+x+x+x) Convert.ToUInt16("1") |> equal x + Convert.ToUInt16('a') |> equal 97us [] let ``System.Convert.ToUInt32 works`` () = @@ -580,6 +586,7 @@ let ``System.Convert.ToUInt32 works`` () = Convert.ToUInt32(2.6) |> equal (x+x+x) Convert.ToUInt32(3.5) |> equal (x+x+x+x) Convert.ToUInt32("1") |> equal x + Convert.ToUInt32('a') |> equal 97u [] let ``System.Convert.ToUInt64 works`` () = @@ -620,6 +627,7 @@ let ``System.Convert.ToUInt64 works`` () = Convert.ToUInt64(2.6) |> equal (x+x+x) Convert.ToUInt64(3.5) |> equal (x+x+x+x) Convert.ToUInt64("1") |> equal x + Convert.ToUInt64('a') |> equal 97UL [] let ``Convert between (un)signed long`` () = // See #1485