Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/Fable.Transforms/Dart/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
40 changes: 40 additions & 0 deletions src/Fable.Transforms/Python/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/Dart/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -49,6 +50,7 @@ void main() {
map.tests();
misc.tests();
// nullness.tests();
nullable.tests();
option.tests();
quotation.tests();
record.tests();
Expand Down
1 change: 1 addition & 0 deletions tests/Dart/src/Fable.Tests.Dart.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Compile Include="MapTests.fs" />
<Compile Include="MiscTests.fs" />
<Compile Include="NullnessTests.fs" />
<Compile Include="NullableTests.fs" />
<Compile Include="OptionTests.fs" />
<Compile Include="QuotationTests.fs" />
<Compile Include="RecordTests.fs" />
Expand Down
60 changes: 60 additions & 0 deletions tests/Dart/src/NullableTests.fs
Original file line number Diff line number Diff line change
@@ -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<int> |> equal none<char>

testCase "Nullable.enum works" <| fun () ->
(Nullable.enum (Nullable 2): Nullable<DayOfWeek>) |> equal (Nullable DayOfWeek.Tuesday)
(Nullable.enum none<int>: Nullable<DayOfWeek>) |> equal none<DayOfWeek>

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<int> |> equal none<float>
Nullable.float32 (Nullable 5) |> equal (Nullable 5.0f)
Nullable.float32 (Nullable 10.0) |> equal (Nullable 10.0f)
Nullable.float32 none<int> |> equal none<float32>
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<float> |> equal none<int>
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<int> |> equal none<int64>
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<int> |> equal none<uint64>

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
1 change: 1 addition & 0 deletions tests/Js/Main/Fable.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<Compile Include="MiscTests.fs" />
<Compile Include="NestedAndRecursivePatternTests.fs" />
<Compile Include="NullnessTests.fs" />
<Compile Include="NullableTests.fs" />
<Compile Include="ObservableTests.fs" />
<Compile Include="OptionTests.fs" />
<Compile Include="SystemIOTests.fs" />
Expand Down
1 change: 1 addition & 0 deletions tests/Js/Main/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ let allTests =
Maps.tests
Misc.tests
Nullness.tests
Nullable.tests
NestedAndRecursivePatternTests.tests
Observable.tests
Option.tests
Expand Down
Loading
Loading