diff --git a/src/Fable.Transforms/Dart/Replacements.fs b/src/Fable.Transforms/Dart/Replacements.fs
index 062403f731..66b24c4b58 100644
--- a/src/Fable.Transforms/Dart/Replacements.fs
+++ b/src/Fable.Transforms/Dart/Replacements.fs
@@ -2055,6 +2055,43 @@ let nullables (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg:
| "get_HasValue", Some c -> makeEqOp r c (makeNull ()) BinaryUnequal |> Some
| _ -> None
+let nullableModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
+ let convert (targetType: Type) (value: Expr) =
+ match targetType with
+ | Char -> toChar com ctx r value
+ | Number((Float16 | Float32 | Float64), _) -> toFloat com ctx r targetType [ value ]
+ | Number(Decimal, _) -> toDecimal com ctx r targetType [ value ]
+ | Number _ -> toInt com ctx r targetType [ value ]
+ | _ -> TypeCast(value, targetType)
+
+ match i.CompiledName.Replace("$W", ""), List.tryLast args, t with
+ | ("ToByte" | "ToUInt8" | "ToSByte" | "ToInt8" | "ToInt16" | "ToUInt16" | "ToInt" | "ToInt32" | "ToUInt" | "ToUInt32" | "ToInt64" | "ToUInt64" | "ToIntPtr" | "ToUIntPtr" | "ToSingle" | "ToFloat32" | "ToDouble" | "ToFloat" | "ToDecimal" | "ToChar" | "ToEnum"),
+ Some value,
+ Nullable(targetType, _) ->
+ match value with
+ | Value(Null _, _) -> makeNull () |> Some
+ | Value((NumberConstant _ | CharConstant _), _) -> convert targetType value |> Some
+ | _ ->
+ let sourceType =
+ match value.Type with
+ | Nullable(sourceType, _) -> sourceType
+ | sourceType -> sourceType
+
+ let v = makeUniqueIdent com ctx value.Type "v"
+
+ Let(
+ v,
+ value,
+ IfThenElse(
+ makeEqOp None (IdentExpr v) (makeNull ()) BinaryUnequal,
+ TypeCast(convert targetType (TypeCast(IdentExpr v, sourceType)), t),
+ makeNull (),
+ r
+ )
+ )
+ |> Some
+ | _ -> None
+
let options isStruct (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg with
| "Some", _ -> NewOption(List.tryHead args, t.Generics.Head, isStruct) |> makeValue r |> Some
@@ -4022,6 +4059,7 @@ let private replacedModules =
"System.Math", operators
"System.MathF", operators
"Microsoft.FSharp.Core.Operators", operators
+ "Microsoft.FSharp.Linq.NullableModule", nullableModule
"Microsoft.FSharp.Core.Operators.Checked", operators
"Microsoft.FSharp.Core.Operators.Unchecked", unchecked
"Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions
diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs
index 694e9c69c7..3da6ef0dfd 100644
--- a/src/Fable.Transforms/Python/Replacements.fs
+++ b/src/Fable.Transforms/Python/Replacements.fs
@@ -2247,6 +2247,45 @@ let nullables (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg:
| "get_HasValue", Some c -> Test(c, OptionTest true, r) |> Some
| _ -> None
+let nullableModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
+ let convert (targetType: Type) (value: Expr) =
+ match targetType with
+ | Char -> toChar com ctx r value
+ | Number(UInt64, _) -> toLong com ctx r true targetType [ value ]
+ | Number(Int64, _) -> toLong com ctx r false targetType [ value ]
+ | Number((Float16 | Float32 | Float64), _) -> toFloat com ctx r targetType [ value ]
+ | Number(Decimal, _) -> toDecimal com ctx r targetType [ value ]
+ | Number _ -> toInt com ctx r targetType [ value ]
+ | _ -> TypeCast(value, targetType)
+
+ match i.CompiledName.Replace("$W", ""), List.tryLast args, t with
+ | ("ToByte" | "ToUInt8" | "ToSByte" | "ToInt8" | "ToInt16" | "ToUInt16" | "ToInt" | "ToInt32" | "ToUInt" | "ToUInt32" | "ToInt64" | "ToUInt64" | "ToIntPtr" | "ToUIntPtr" | "ToSingle" | "ToFloat32" | "ToDouble" | "ToFloat" | "ToDecimal" | "ToChar" | "ToEnum"),
+ Some value,
+ Nullable(targetType, _) ->
+ match value with
+ | Value(Null _, _) -> Value(Null t, None) |> Some
+ | Value((NumberConstant _ | CharConstant _), _) -> convert targetType value |> Some
+ | _ ->
+ let sourceType =
+ match value.Type with
+ | Nullable(sourceType, _) -> sourceType
+ | sourceType -> sourceType
+
+ let v = makeUniqueIdent com ctx value.Type "v"
+
+ Let(
+ v,
+ value,
+ IfThenElse(
+ Test(IdentExpr v, OptionTest true, None),
+ TypeCast(convert targetType (TypeCast(IdentExpr v, sourceType)), t),
+ Value(Null t, None),
+ r
+ )
+ )
+ |> Some
+ | _ -> None
+
// See fable-library-ts/Option.ts for more info on how options behave in Fable runtime
let options isStruct (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg with
@@ -4193,6 +4232,7 @@ let private replacedModules =
"System.Math", operators
"System.MathF", operators
"Microsoft.FSharp.Core.Operators", operators
+ "Microsoft.FSharp.Linq.NullableModule", nullableModule
"Microsoft.FSharp.Core.Operators.Checked", operators
"Microsoft.FSharp.Core.Operators.Unchecked", unchecked
"Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions
diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs
index 0c696080db..cf7eccd048 100644
--- a/src/Fable.Transforms/Replacements.fs
+++ b/src/Fable.Transforms/Replacements.fs
@@ -2563,6 +2563,35 @@ let nullables (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg:
| "get_HasValue", Some c -> Test(c, OptionTest true, r) |> Some
| _ -> None
+let nullableModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
+ let convert (targetType: Type) (value: Expr) =
+ match targetType with
+ | Char -> toChar com ctx r value
+ | Number(BigIntegers _, _) -> toLong com ctx r targetType [ value ]
+ | Number(Integers _, _) -> toInt com ctx r targetType [ value ]
+ | Number(Floats _, _) -> toFloat com ctx r targetType [ value ]
+ | Number(Decimal, _) -> toDecimal com ctx r targetType [ value ]
+ | _ -> TypeCast(value, targetType)
+
+ match i.CompiledName.Replace("$W", ""), List.tryLast args, t with
+ | ("ToByte" | "ToUInt8" | "ToSByte" | "ToInt8" | "ToInt16" | "ToUInt16" | "ToInt" | "ToInt32" | "ToUInt" | "ToUInt32" | "ToInt64" | "ToUInt64" | "ToIntPtr" | "ToUIntPtr" | "ToSingle" | "ToFloat32" | "ToDouble" | "ToFloat" | "ToDecimal" | "ToChar" | "ToEnum"),
+ Some value,
+ Nullable(targetType, _) ->
+ match value with
+ | Value(Null _, _) -> Value(Null t, None) |> Some
+ | Value((NumberConstant _ | CharConstant _), _) -> convert targetType value |> Some
+ | _ ->
+ let sourceType =
+ match value.Type with
+ | Nullable(sourceType, _) -> sourceType
+ | sourceType -> sourceType
+
+ let v = makeUniqueIdent com ctx sourceType "v"
+ let mapping = Delegate([ v ], convert targetType (IdentExpr v), None, Tags.empty)
+
+ Helper.LibCall(com, "Option", "map", t, [ mapping; value ], ?loc = r) |> Some
+ | _ -> None
+
// See fable-library-ts/Option.ts for more info on how options behave in Fable runtime
let options isStruct (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg with
@@ -4839,6 +4868,7 @@ let private replacedModules =
"System.Math", operators
"System.MathF", operators
"Microsoft.FSharp.Core.Operators", operators
+ "Microsoft.FSharp.Linq.NullableModule", nullableModule
"Microsoft.FSharp.Core.Operators.Checked", operators
"Microsoft.FSharp.Core.Operators.Unchecked", unchecked
"Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions
diff --git a/tests/Dart/main.dart b/tests/Dart/main.dart
index 9149d8cba7..3a2855f4a6 100644
--- a/tests/Dart/main.dart
+++ b/tests/Dart/main.dart
@@ -14,6 +14,7 @@ import './src/ListTests.dart' as list;
import './src/MapTests.dart' as map;
import './src/MiscTests.dart' as misc;
// import './src/NullnessTests.dart' as nullness;
+import './src/NullableTests.dart' as nullable;
import './src/OptionTests.dart' as option;
import './src/QuotationTests.dart' as quotation;
import './src/RecordTests.dart' as record;
@@ -49,6 +50,7 @@ void main() {
map.tests();
misc.tests();
// nullness.tests();
+ nullable.tests();
option.tests();
quotation.tests();
record.tests();
diff --git a/tests/Dart/src/Fable.Tests.Dart.fsproj b/tests/Dart/src/Fable.Tests.Dart.fsproj
index 4cbb0780d8..47da2d9ccf 100644
--- a/tests/Dart/src/Fable.Tests.Dart.fsproj
+++ b/tests/Dart/src/Fable.Tests.Dart.fsproj
@@ -24,6 +24,7 @@
+
diff --git a/tests/Dart/src/NullableTests.fs b/tests/Dart/src/NullableTests.fs
new file mode 100644
index 0000000000..1a8b13689b
--- /dev/null
+++ b/tests/Dart/src/NullableTests.fs
@@ -0,0 +1,60 @@
+module Fable.Tests.Dart.Nullable
+
+open System
+open Util
+open FSharp.Linq
+
+let private none<'T when 'T: struct and 'T: (new: unit -> 'T) and 'T :> ValueType> = Nullable<'T>()
+
+let tests() =
+ testCase "Nullable.char works" <| fun () ->
+ Nullable.char (Nullable 49uy) |> equal (Nullable '1')
+ Nullable.char (Nullable 53) |> equal (Nullable '5')
+ Nullable.char (Nullable 55L) |> equal (Nullable '7')
+ Nullable.char (Nullable 58.0) |> equal (Nullable ':')
+ Nullable.char (Nullable 'a') |> equal (Nullable 'a')
+ Nullable.char none |> equal none
+
+ testCase "Nullable.enum works" <| fun () ->
+ (Nullable.enum (Nullable 2): Nullable) |> equal (Nullable DayOfWeek.Tuesday)
+ (Nullable.enum none: Nullable) |> equal none
+
+ testCase "Nullable.float and Nullable.float32 work" <| fun () ->
+ Nullable.float (Nullable 1uy) |> equal (Nullable 1.0)
+ Nullable.float (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.float (Nullable 7L) |> equal (Nullable 7.0)
+ Nullable.float (Nullable 'c') |> equal (Nullable 99.0)
+ Nullable.float none |> equal none
+ Nullable.float32 (Nullable 5) |> equal (Nullable 5.0f)
+ Nullable.float32 (Nullable 10.0) |> equal (Nullable 10.0f)
+ Nullable.float32 none |> equal none
+ Nullable.double (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.single (Nullable 9.5) |> equal (Nullable 9.5f)
+
+ testCase "Nullable integer conversions work" <| fun () ->
+ Nullable.int (Nullable 1uy) |> equal (Nullable 1)
+ Nullable.int (Nullable 7L) |> equal (Nullable 7)
+ Nullable.int (Nullable 10.9) |> equal (Nullable 10)
+ Nullable.int (Nullable -11.9) |> equal (Nullable -11)
+ Nullable.int (Nullable 'c') |> equal (Nullable 99)
+ Nullable.int none |> equal none
+ Nullable.int16 (Nullable -7L) |> equal (Nullable -7s)
+ Nullable.int32 (Nullable 5L) |> equal (Nullable 5)
+ Nullable.int64 (Nullable -9.9) |> equal (Nullable -9L)
+ Nullable.int64 none |> equal none
+ Nullable.int8 (Nullable 9.9) |> equal (Nullable 9y)
+ Nullable.sbyte (Nullable -7.9) |> equal (Nullable -7y)
+ Nullable.byte (Nullable 5) |> equal (Nullable 5uy)
+ Nullable.uint8 (Nullable 7L) |> equal (Nullable 7uy)
+ Nullable.uint16 (Nullable 9.9) |> equal (Nullable 9us)
+ Nullable.uint (Nullable 5) |> equal (Nullable 5u)
+ Nullable.uint32 (Nullable 7L) |> equal (Nullable 7u)
+ Nullable.uint64 none |> equal none
+
+ testCase "Nullable conversions evaluate their argument once" <| fun () ->
+ let mutable calls = 0
+ let next () =
+ calls <- calls + 1
+ Nullable 5
+ Nullable.float (next ()) |> equal (Nullable 5.0)
+ calls |> equal 1
diff --git a/tests/Js/Main/Fable.Tests.fsproj b/tests/Js/Main/Fable.Tests.fsproj
index ce2d68b963..1fbca90fc9 100644
--- a/tests/Js/Main/Fable.Tests.fsproj
+++ b/tests/Js/Main/Fable.Tests.fsproj
@@ -68,6 +68,7 @@
+
diff --git a/tests/Js/Main/Main.fs b/tests/Js/Main/Main.fs
index f42d889826..bcf67edab3 100644
--- a/tests/Js/Main/Main.fs
+++ b/tests/Js/Main/Main.fs
@@ -34,6 +34,7 @@ let allTests =
Maps.tests
Misc.tests
Nullness.tests
+ Nullable.tests
NestedAndRecursivePatternTests.tests
Observable.tests
Option.tests
diff --git a/tests/Js/Main/NullableTests.fs b/tests/Js/Main/NullableTests.fs
new file mode 100644
index 0000000000..553e519989
--- /dev/null
+++ b/tests/Js/Main/NullableTests.fs
@@ -0,0 +1,170 @@
+module Fable.Tests.Nullable
+
+open Util.Testing
+open System
+open FSharp.Linq
+
+let private none<'T when 'T: struct and 'T: (new: unit -> 'T) and 'T :> ValueType> = Nullable<'T>()
+
+let tests =
+ testList "Nullable" [
+ testCase "Nullable.char" <| fun () ->
+ Nullable.char (Nullable 49uy) |> equal (Nullable '1')
+ Nullable.char (Nullable 50y) |> equal (Nullable '2')
+ Nullable.char (Nullable 51s) |> equal (Nullable '3')
+ Nullable.char (Nullable 52us) |> equal (Nullable '4')
+ Nullable.char (Nullable 53) |> equal (Nullable '5')
+ Nullable.char (Nullable 54u) |> equal (Nullable '6')
+ Nullable.char (Nullable 55L) |> equal (Nullable '7')
+ Nullable.char (Nullable 56UL) |> equal (Nullable '8')
+ Nullable.char (Nullable 57m) |> equal (Nullable '9')
+ Nullable.char (Nullable 58.0) |> equal (Nullable ':')
+ Nullable.char (Nullable 59.0f) |> equal (Nullable ';')
+ Nullable.char (Nullable 'a') |> equal (Nullable 'a')
+ Nullable.char none |> equal none
+
+ testCase "Nullable.decimal" <| fun () ->
+ Nullable.decimal (Nullable 1uy) |> equal (Nullable 1m)
+ Nullable.decimal (Nullable 2y) |> equal (Nullable 2m)
+ Nullable.decimal (Nullable 3s) |> equal (Nullable 3m)
+ Nullable.decimal (Nullable 4us) |> equal (Nullable 4m)
+ Nullable.decimal (Nullable 5) |> equal (Nullable 5m)
+ Nullable.decimal (Nullable 6u) |> equal (Nullable 6m)
+ Nullable.decimal (Nullable 7L) |> equal (Nullable 7m)
+ Nullable.decimal (Nullable 8UL) |> equal (Nullable 8m)
+ Nullable.decimal (Nullable 9m) |> equal (Nullable 9m)
+ Nullable.decimal (Nullable 10.5) |> equal (Nullable 10.5m)
+ Nullable.decimal (Nullable 11.5f) |> equal (Nullable 11.5m)
+ Nullable.decimal none |> equal none
+
+ testCase "Nullable.double" <| fun () ->
+ Nullable.double (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.double (Nullable 7L) |> equal (Nullable 7.0)
+ Nullable.double (Nullable 9m) |> equal (Nullable 9.0)
+ Nullable.double (Nullable 11.5f) |> equal (Nullable 11.5)
+ Nullable.double none |> equal none
+
+ testCase "Nullable.enum" <| fun () ->
+ (Nullable.enum (Nullable 2): Nullable) |> equal (Nullable DayOfWeek.Tuesday)
+ (Nullable.enum none: Nullable) |> equal none
+
+ testCase "Nullable.float" <| fun () ->
+ Nullable.float (Nullable 1uy) |> equal (Nullable 1.0)
+ Nullable.float (Nullable 2y) |> equal (Nullable 2.0)
+ Nullable.float (Nullable 3s) |> equal (Nullable 3.0)
+ Nullable.float (Nullable 4us) |> equal (Nullable 4.0)
+ Nullable.float (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.float (Nullable 6u) |> equal (Nullable 6.0)
+ Nullable.float (Nullable 7L) |> equal (Nullable 7.0)
+ Nullable.float (Nullable 8UL) |> equal (Nullable 8.0)
+ Nullable.float (Nullable 9m) |> equal (Nullable 9.0)
+ Nullable.float (Nullable 10.0) |> equal (Nullable 10.0)
+ Nullable.float (Nullable 11.0f) |> equal (Nullable 11.0)
+ Nullable.float (Nullable 'c') |> equal (Nullable 99.0)
+ Nullable.float none |> equal none
+
+ testCase "Nullable.float32" <| fun () ->
+ Nullable.float32 (Nullable 1uy) |> equal (Nullable 1.0f)
+ Nullable.float32 (Nullable 2y) |> equal (Nullable 2.0f)
+ Nullable.float32 (Nullable 3s) |> equal (Nullable 3.0f)
+ Nullable.float32 (Nullable 4us) |> equal (Nullable 4.0f)
+ Nullable.float32 (Nullable 5) |> equal (Nullable 5.0f)
+ Nullable.float32 (Nullable 6u) |> equal (Nullable 6.0f)
+ Nullable.float32 (Nullable 7L) |> equal (Nullable 7.0f)
+ Nullable.float32 (Nullable 8UL) |> equal (Nullable 8.0f)
+ Nullable.float32 (Nullable 9m) |> equal (Nullable 9.0f)
+ Nullable.float32 (Nullable 10.0) |> equal (Nullable 10.0f)
+ Nullable.float32 (Nullable 11.0f) |> equal (Nullable 11.0f)
+ Nullable.float32 (Nullable 'c') |> equal (Nullable 99.0f)
+ Nullable.float32 none |> equal none
+
+ testCase "Nullable.int" <| fun () ->
+ Nullable.int (Nullable 1uy) |> equal (Nullable 1)
+ Nullable.int (Nullable 2y) |> equal (Nullable 2)
+ Nullable.int (Nullable 3s) |> equal (Nullable 3)
+ Nullable.int (Nullable 4us) |> equal (Nullable 4)
+ Nullable.int (Nullable 5) |> equal (Nullable 5)
+ Nullable.int (Nullable 6u) |> equal (Nullable 6)
+ Nullable.int (Nullable 7L) |> equal (Nullable 7)
+ Nullable.int (Nullable 8UL) |> equal (Nullable 8)
+ Nullable.int (Nullable 9m) |> equal (Nullable 9)
+ Nullable.int (Nullable 10.9) |> equal (Nullable 10)
+ Nullable.int (Nullable -11.9f) |> equal (Nullable -11)
+ Nullable.int (Nullable 'c') |> equal (Nullable 99)
+ Nullable.int none |> equal none
+
+ testCase "Nullable.int16" <| fun () ->
+ Nullable.int16 (Nullable 5) |> equal (Nullable 5s)
+ Nullable.int16 (Nullable -7L) |> equal (Nullable -7s)
+ Nullable.int16 (Nullable 9.9) |> equal (Nullable 9s)
+ Nullable.int16 none |> equal none
+
+ testCase "Nullable.int32" <| fun () ->
+ Nullable.int32 (Nullable 5L) |> equal (Nullable 5)
+ Nullable.int32 (Nullable -7.9) |> equal (Nullable -7)
+ Nullable.int32 (Nullable 9m) |> equal (Nullable 9)
+ Nullable.int32 none |> equal none
+
+ testCase "Nullable.int64" <| fun () ->
+ Nullable.int64 (Nullable 5) |> equal (Nullable 5L)
+ Nullable.int64 (Nullable 7UL) |> equal (Nullable 7L)
+ Nullable.int64 (Nullable -9.9) |> equal (Nullable -9L)
+ Nullable.int64 (Nullable 11m) |> equal (Nullable 11L)
+ Nullable.int64 none |> equal none
+
+ testCase "Nullable.int8" <| fun () ->
+ Nullable.int8 (Nullable 5) |> equal (Nullable 5y)
+ Nullable.int8 (Nullable -7L) |> equal (Nullable -7y)
+ Nullable.int8 (Nullable 9.9) |> equal (Nullable 9y)
+ Nullable.int8 none |> equal none
+
+ testCase "Nullable.sbyte" <| fun () ->
+ Nullable.sbyte (Nullable 5) |> equal (Nullable 5y)
+ Nullable.sbyte (Nullable -7.9) |> equal (Nullable -7y)
+ Nullable.sbyte none |> equal none
+
+ testCase "Nullable.single" <| fun () ->
+ Nullable.single (Nullable 5) |> equal (Nullable 5.0f)
+ Nullable.single (Nullable 7L) |> equal (Nullable 7.0f)
+ Nullable.single (Nullable 9.5) |> equal (Nullable 9.5f)
+ Nullable.single none |> equal none
+
+ testCase "Nullable.uint" <| fun () ->
+ Nullable.uint (Nullable 5) |> equal (Nullable 5u)
+ Nullable.uint (Nullable 7L) |> equal (Nullable 7u)
+ Nullable.uint (Nullable 9.9) |> equal (Nullable 9u)
+ Nullable.uint none |> equal none
+
+ testCase "Nullable.uint16" <| fun () ->
+ Nullable.uint16 (Nullable 5) |> equal (Nullable 5us)
+ Nullable.uint16 (Nullable 7L) |> equal (Nullable 7us)
+ Nullable.uint16 (Nullable 9.9) |> equal (Nullable 9us)
+ Nullable.uint16 none |> equal none
+
+ testCase "Nullable.uint32" <| fun () ->
+ Nullable.uint32 (Nullable 5) |> equal (Nullable 5u)
+ Nullable.uint32 (Nullable 7L) |> equal (Nullable 7u)
+ Nullable.uint32 (Nullable 9.9) |> equal (Nullable 9u)
+ Nullable.uint32 none |> equal none
+
+ testCase "Nullable.uint64" <| fun () ->
+ Nullable.uint64 (Nullable 5) |> equal (Nullable 5UL)
+ Nullable.uint64 (Nullable 7L) |> equal (Nullable 7UL)
+ Nullable.uint64 (Nullable 9.9) |> equal (Nullable 9UL)
+ Nullable.uint64 (Nullable 11m) |> equal (Nullable 11UL)
+ Nullable.uint64 none |> equal none
+
+ testCase "Nullable.byte and Nullable.uint8" <| fun () ->
+ Nullable.byte (Nullable 5) |> equal (Nullable 5uy)
+ Nullable.uint8 (Nullable 7L) |> equal (Nullable 7uy)
+ Nullable.uint8 (Nullable 9.9) |> equal (Nullable 9uy)
+ Nullable.byte none |> equal none
+
+ testCase "Nullable conversions evaluate their argument once" <| fun () ->
+ let mutable calls = 0
+ let next () =
+ calls <- calls + 1
+ Nullable 5
+ Nullable.float (next ()) |> equal (Nullable 5.0)
+ calls |> equal 1
+ ]
diff --git a/tests/Python/Fable.Tests.Python.fsproj b/tests/Python/Fable.Tests.Python.fsproj
index b5f130a704..1feeccc0dd 100644
--- a/tests/Python/Fable.Tests.Python.fsproj
+++ b/tests/Python/Fable.Tests.Python.fsproj
@@ -64,6 +64,7 @@
+
diff --git a/tests/Python/TestNullable.fs b/tests/Python/TestNullable.fs
new file mode 100644
index 0000000000..0370bddd71
--- /dev/null
+++ b/tests/Python/TestNullable.fs
@@ -0,0 +1,72 @@
+module Fable.Tests.Nullable
+
+open System
+open Util.Testing
+open FSharp.Linq
+
+[]
+let ``test Nullable.char works`` () =
+ Nullable.char (Nullable 49uy) |> equal (Nullable '1')
+ Nullable.char (Nullable 53) |> equal (Nullable '5')
+ Nullable.char (Nullable 55L) |> equal (Nullable '7')
+ Nullable.char (Nullable 57m) |> equal (Nullable '9')
+ Nullable.char (Nullable 58.0) |> equal (Nullable ':')
+ Nullable.char (Nullable 'a') |> equal (Nullable 'a')
+ Nullable.char (Nullable()) |> equal (Nullable())
+
+[]
+let ``test Nullable.decimal works`` () =
+ Nullable.decimal (Nullable 5) |> equal (Nullable 5m)
+ Nullable.decimal (Nullable 7L) |> equal (Nullable 7m)
+ Nullable.decimal (Nullable 10.5) |> equal (Nullable 10.5m)
+ Nullable.decimal (Nullable()) |> equal (Nullable())
+
+[]
+let ``test Nullable.enum works`` () =
+ (Nullable.enum (Nullable 2): Nullable) |> equal (Nullable DayOfWeek.Tuesday)
+ (Nullable.enum (Nullable()): Nullable) |> equal (Nullable())
+
+[]
+let ``test Nullable.float and Nullable.float32 work`` () =
+ Nullable.float (Nullable 1uy) |> equal (Nullable 1.0)
+ Nullable.float (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.float (Nullable 7L) |> equal (Nullable 7.0)
+ Nullable.float (Nullable 9m) |> equal (Nullable 9.0)
+ Nullable.float (Nullable 'c') |> equal (Nullable 99.0)
+ Nullable.float (Nullable()) |> equal (Nullable())
+ Nullable.float32 (Nullable 5) |> equal (Nullable 5.0f)
+ Nullable.float32 (Nullable 10.0) |> equal (Nullable 10.0f)
+ Nullable.float32 (Nullable()) |> equal (Nullable())
+ Nullable.double (Nullable 5) |> equal (Nullable 5.0)
+ Nullable.single (Nullable 9.5) |> equal (Nullable 9.5f)
+
+[]
+let ``test Nullable integer conversions work`` () =
+ Nullable.int (Nullable 1uy) |> equal (Nullable 1)
+ Nullable.int (Nullable 7L) |> equal (Nullable 7)
+ Nullable.int (Nullable 9m) |> equal (Nullable 9)
+ Nullable.int (Nullable 10.9) |> equal (Nullable 10)
+ Nullable.int (Nullable -11.9) |> equal (Nullable -11)
+ Nullable.int (Nullable 'c') |> equal (Nullable 99)
+ Nullable.int (Nullable()) |> equal (Nullable())
+ Nullable.int16 (Nullable -7L) |> equal (Nullable -7s)
+ Nullable.int32 (Nullable 5L) |> equal (Nullable 5)
+ Nullable.int64 (Nullable -9.9) |> equal (Nullable -9L)
+ Nullable.int64 (Nullable()) |> equal (Nullable())
+ Nullable.int8 (Nullable 9.9) |> equal (Nullable 9y)
+ Nullable.sbyte (Nullable -7.9) |> equal (Nullable -7y)
+ Nullable.byte (Nullable 5) |> equal (Nullable 5uy)
+ Nullable.uint8 (Nullable 7L) |> equal (Nullable 7uy)
+ Nullable.uint16 (Nullable 9.9) |> equal (Nullable 9us)
+ Nullable.uint (Nullable 5) |> equal (Nullable 5u)
+ Nullable.uint32 (Nullable 7L) |> equal (Nullable 7u)
+ Nullable.uint64 (Nullable()) |> equal (Nullable())
+
+[]
+let ``test Nullable conversions evaluate their argument once`` () =
+ let mutable calls = 0
+ let next () =
+ calls <- calls + 1
+ Nullable 5
+ Nullable.float (next ()) |> equal (Nullable 5.0)
+ calls |> equal 1