Skip to content

Commit cb2b065

Browse files
Fix #660: Option.fold & bump version
1 parent bf01923 commit cb2b065

File tree

9 files changed

+74
-53
lines changed

9 files changed

+74
-53
lines changed

RELEASE_NOTES_COMPILER.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 0.7.34
2+
3+
* Fix #660: `Option.fold` and `Option.foldBack`
4+
15
### 0.7.33
26

37
* Add operator `enum`

RELEASE_NOTES_CORE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 0.7.25
2+
3+
* Fix #660: `Option.fold` and `Option.foldBack`
4+
15
### 0.7.24
26

37
* Fixed serialization of maps with string keys: #659

src/fable/Fable.Client.Node/ts/options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from "fs";
22
import * as path from "path";
33
import * as commandLineArgs from "command-line-args";
4-
import * as commandLineUsage from "command-line-usage";
4+
import * as commandLineUsage from "command-line-usage/lib/command-line-usage";
55
import * as semver from "semver";
66
import * as json5 from "json5";
77

src/fable/Fable.Client.Node/ts/package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
"fable": "./index.js"
88
},
99
"dependencies": {
10-
"babel-core": "^6.18.2",
11-
"babel-dts-generator": "^0.6.2",
10+
"babel-core": "^6.21.0",
11+
"babel-dts-generator": "^0.6.3",
1212
"babel-plugin-transform-class-properties": "^6.19.0",
13-
"babel-plugin-transform-flow-strip-types": "^6.18.0",
13+
"babel-plugin-transform-flow-strip-types": "^6.21.0",
1414
"babel-preset-es2015": "^6.18.0",
1515
"babel-template": "^6.16.0",
1616
"babel-traverse": "^6.21.0",
1717
"babel-types": "^6.21.0",
1818
"chokidar": "^1.6.1",
19-
"command-line-args": "^3.0.3",
20-
"command-line-usage": "^3.0.7",
21-
"json5": "^0.5.0",
22-
"resolve": "^1.1.7",
23-
"rollup": "^0.36.3",
24-
"rollup-plugin-commonjs": "^5.0.5",
19+
"command-line-args": "^3.0.5",
20+
"command-line-usage": "^4.0.0",
21+
"json5": "^0.5.1",
22+
"resolve": "^1.2.0",
23+
"rollup": "^0.41.4",
24+
"rollup-plugin-commonjs": "^7.0.0",
2525
"rollup-plugin-hypothetical": "^1.2.1",
2626
"rollup-plugin-node-resolve": "^2.0.0",
2727
"semver": "^5.3.0"

src/fable/Fable.Compiler/FSharp2Fable.Util.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ module Util =
11741174
emitMeth.Invoke(emitInstance, args) |> unbox |> Some
11751175
with
11761176
| :? AST.FableError as err -> raise err
1177-
| ex -> let exMsg = if ex.GetType() = typeof<TargetInvocationException>
1177+
| ex -> let exMsg = if ex.GetType() = typeof<TargetInvocationException>
11781178
then ex.InnerException.Message else ex.Message
11791179
sprintf "Error when invoking %s.%s"
11801180
emitFsType.TypeDefinition.DisplayName emitMethName
@@ -1373,7 +1373,7 @@ module Util =
13731373
Fable.Value Fable.This
13741374

13751375
let makeValueFrom com ctx r typ role (v: FSharpMemberOrFunctionOrValue) =
1376-
if typ = Fable.Unit then Fable.Value Fable.Null else
1376+
if typ = Fable.Unit then Fable.Wrapped(Fable.Value Fable.Null, Fable.Unit) else
13771377
let owner = tryEnclosingEntity v
13781378
let i = buildApplyInfoFrom com ctx r typ ([], []) (None, []) owner v
13791379
match v with

src/fable/Fable.Compiler/FSharp2Fable.fs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,15 +414,16 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
414414
FableError("Cannot resolve locally inlined value: " + var.DisplayName, range) |> raise
415415

416416
| BasicPatterns.Application(Transform com ctx callee, _typeArgs, args) ->
417-
let args = List.map (transformExprWithRole AppliedArgument com ctx) args
417+
let args2 = List.map (transformExprWithRole AppliedArgument com ctx) args
418418
let typ, range = makeType com ctx.typeArgs fsExpr.Type, makeRangeFrom fsExpr
419419
if callee.Type.FullName = "Fable.Core.Applicable" then
420-
match args with
421-
| [Fable.Value(Fable.TupleConst args)] -> args
422-
| args -> args
420+
match args, args2 with
421+
| [arg], _ when isUnit arg.Type -> []
422+
| _, [Fable.Value(Fable.TupleConst args2)] -> args2
423+
| _, args2 -> args2
423424
|> List.map (makeDelegate com None)
424425
|> fun args -> Fable.Apply(callee, args, Fable.ApplyMeth, typ, range)
425-
else makeApply range typ callee args
426+
else makeApply range typ callee args2
426427

427428
| BasicPatterns.IfThenElse (Transform com ctx guardExpr, Transform com ctx thenExpr, Transform com ctx elseExpr) ->
428429
Fable.IfThenElse (guardExpr, thenExpr, elseExpr, makeRangeFrom fsExpr)

src/fable/Fable.Compiler/Replacements.fs

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ module private AstPass =
454454
let fableCoreLib com (i: Fable.ApplyInfo) =
455455
let destruct = function
456456
| Fable.Value(Fable.TupleConst exprs) -> exprs
457+
| expr when expr.Type = Fable.Unit -> []
457458
| expr -> [expr]
458459
match i.methodName with
459460
| Naming.StartsWith "import" _ ->
@@ -681,7 +682,7 @@ module private AstPass =
681682
| "toSingle" | "toDouble" | "toDecimal" -> toFloat com info args |> Some
682683
| "toChar" -> toChar com info args.Head |> Some
683684
| "toString" -> toString com info args.Head |> Some
684-
| "toEnum" -> args.Head |> Some
685+
| "toEnum" -> args.Head |> Some
685686
| "createDictionary" ->
686687
GlobalCall("Map", None, true, args) |> makeCall r typ |> Some
687688
| "createSet" ->
@@ -1022,17 +1023,13 @@ module private AstPass =
10221023

10231024
let options (com: ICompiler) (i: Fable.ApplyInfo) =
10241025
// Prevent functions being run twice, see #198
1025-
let wrapInLet f expr =
1026-
let ident = com.GetUniqueVar() |> makeIdent
1027-
[
1028-
Fable.VarDeclaration(ident, expr, false)
1029-
f(Fable.Value(Fable.IdentValue ident))
1030-
]
1031-
|> fun exprs -> Fable.Sequential(exprs, i.range)
1032-
let toArray r optExpr =
1033-
// "$0 != null ? [$0]: []"
1034-
let makeArray exprs = Fable.ArrayConst(Fable.ArrayValues exprs, genArg i.returnType) |> Fable.Value
1035-
Fable.IfThenElse(makeEqOp r [optExpr; Fable.Value Fable.Null] BinaryUnequal, makeArray [optExpr], makeArray [], r)
1026+
let runIfSome r expr defValue f =
1027+
CoreLibCall("Util", Some "defaultArg", false, [expr; defValue; f])
1028+
|> makeCall r Fable.Any
1029+
let toArray r arg =
1030+
let ident = makeIdent "x"
1031+
makeLambdaExpr [ident] (makeArray Fable.Any [Fable.IdentValue ident |> Fable.Value])
1032+
|> runIfSome r arg (makeArray Fable.Any [])
10361033
let getCallee() = match i.callee with Some c -> c | None -> i.args.Head
10371034
match i.methodName with
10381035
| "none" -> Fable.Null |> Fable.Value |> Some
@@ -1049,35 +1046,25 @@ module private AstPass =
10491046
| "map" | "bind" ->
10501047
// emit i "$1 != null ? $0($1) : $1" i.args |> Some
10511048
let f, arg = i.args.Head, i.args.Tail.Head
1052-
arg |> wrapInLet (fun e ->
1053-
Fable.IfThenElse(
1054-
makeEqOp i.range [e; Fable.Value Fable.Null] BinaryUnequal,
1055-
Fable.Apply(f, [e], Fable.ApplyMeth, Fable.Any, i.range),
1056-
e, i.range))
1057-
|> Some
1049+
runIfSome i.range arg (Fable.Value Fable.Null) f |> Some
10581050
| "filter" ->
1059-
// emit i "$1 != null && $0($1) ? $1 : null" i.args |> Some
1060-
let f, arg = i.args.Head, i.args.Tail.Head
1061-
arg |> wrapInLet (fun e ->
1062-
let cond =
1063-
[ makeEqOp i.range [e; Fable.Value Fable.Null] BinaryUnequal
1064-
Fable.Apply(f, [e], Fable.ApplyMeth, Fable.Any, i.range) ]
1065-
|> makeLogOp i.range <| LogicalAnd
1066-
Fable.IfThenElse(cond, e, Fable.Value Fable.Null, i.range))
1051+
let filter, arg = i.args.Head, i.args.Tail.Head
1052+
"x => $0(x) ? x : null"
1053+
|> makeEmit None Fable.Any [filter]
1054+
|> runIfSome i.range arg (Fable.Value Fable.Null)
10671055
|> Some
1068-
| "toArray" -> toArray i.range i.args.Head |> Some
1056+
| "toArray" ->
1057+
toArray i.range i.args.Head |> Some
10691058
| "foldBack" ->
1070-
let opt = wrapInLet (fun e -> toArray i.range e) i.args.Tail.Head
1059+
let opt = toArray None i.args.Tail.Head
10711060
let args = i.args.Head::opt::i.args.Tail.Tail
1072-
CoreLibCall("Seq", Some "foldBack", false, deleg com i args)
1073-
|> makeCall i.range i.returnType |> Some
1061+
ccall com i "Seq" "foldBack" (deleg com i args) |> Some
10741062
| meth ->
10751063
let args =
10761064
let args = List.rev i.args
1077-
wrapInLet (fun e -> toArray i.range e) args.Head
1078-
|> fun argsHead -> List.rev (argsHead::args.Tail)
1079-
CoreLibCall("Seq", Some meth, false, deleg com i args)
1080-
|> makeCall i.range i.returnType |> Some
1065+
let opt = toArray None args.Head
1066+
List.rev (opt::args.Tail)
1067+
ccall com i "Seq" meth (deleg com i args) |> Some
10811068

10821069
let timeSpans com (i: Fable.ApplyInfo) =
10831070
// let callee = match i.callee with Some c -> c | None -> i.args.Head

src/fable/Fable.Core/ts/Util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,6 @@ export function randomNext(min: number, max: number) {
338338
return Math.floor(Math.random() * (max - min)) + min;
339339
}
340340

341-
export function defaultArg<T>(arg: T, defaultValue: T) {
342-
return arg == null ? defaultValue : arg;
341+
export function defaultArg<T,U>(arg: T, defaultValue: T, f?: (x:T)=>U) {
342+
return arg == null ? defaultValue : (f != null ? f(arg) : arg);
343343
}

src/tests/Main/UnionTypeTests.fs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,31 @@ let ``Option.foldBack works``() =
328328
(None, 5) ||> Option.foldBack (*) |> equal 5
329329
(Some 7, 5) ||> Option.foldBack (*) |> equal 35
330330

331+
[<NoEquality; NoComparison>]
332+
type FoldTest =
333+
| FoldA of FoldTest option
334+
| FoldB of int
335+
336+
let rec folding1 test acc =
337+
let f2 (opt:FoldTest option) acc = Option.fold (fun a b -> folding1 b a) acc opt
338+
match test with
339+
| FoldA d -> f2 d acc
340+
| FoldB i -> i::acc
341+
342+
let rec folding2 test acc =
343+
let f2 (opt:FoldTest option) acc = Option.foldBack folding2 opt acc
344+
match test with
345+
| FoldA d -> f2 d acc
346+
| FoldB i -> i::acc
347+
348+
[<Test>]
349+
let ``Option.fold works II``() = // See #660
350+
folding1 (FoldA (Some (FoldB 1))) [] |> equal [1]
351+
352+
[<Test>]
353+
let ``Option.foldBack works II``() = // See #660
354+
folding2 (FoldA (Some (FoldB 1))) [] |> equal [1]
355+
331356
[<Test>]
332357
let ``Option.toArray works``() =
333358
None |> Option.toArray |> equal [||]

0 commit comments

Comments
 (0)