Skip to content

Commit 9250574

Browse files
authored
[JS/TS] Improvements to Async support (#4059)
* [JS/TS] Report an error at compilation time when trying to use `Async.RunSynchronously` * [JS/TS] Propagate non-captured exception when running `Async.Start` or `Async.StartImmediate` * fix test for running on .NET * adapt fcs-fable code to not use Async.RunSynchronously * update changelogs
1 parent 3fe371f commit 9250574

File tree

7 files changed

+54
-18
lines changed

7 files changed

+54
-18
lines changed

src/Fable.Cli/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
* [JS/TS] Fix #4025: No reflection info for pojos (by @alfonsogarciacaro)
1717
* [JS/TS] Fix #4049: decimal/bigint to integer conversion checks (by @ncave)
1818
* [JS/TS] Fix `decimal` to `char` conversion checks (by @ManngelMaxime)
19+
* [JS/TS] Propagate non-captured exception when running `Async.Start` or `Async.StartImmediate` (by @MangelMaxime)
20+
* [JS/TS] Report an error at compilation time when trying to use `Async.RunSynchronously` (by @MangelMaxime)
1921

2022
## 5.0.0-alpha.10 - 2025-02-16
2123

src/Fable.Compiler/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
* [JS/TS] Fix #4025: No reflection info for pojos (by @alfonsogarciacaro)
1717
* [JS/TS] Fix #4049: decimal/bigint to integer conversion checks (by @ncave)
1818
* [JS/TS] Fix `decimal` to `char` conversion checks (by @ManngelMaxime)
19+
* [JS/TS] Propagate non-captured exception when running `Async.Start` or `Async.StartImmediate` (by @MangelMaxime)
20+
* [JS/TS] Report an error at compilation time when trying to use `Async.RunSynchronously` (by @MangelMaxime)
1921

2022
## 5.0.0-alpha.10 - 2025-02-16
2123

src/Fable.Transforms/Replacements.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3622,7 +3622,6 @@ let asyncBuilder (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp
36223622

36233623
let asyncs com (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) =
36243624
match i.CompiledName with
3625-
// TODO: Throw error for RunSynchronously
36263625
| "Start" ->
36273626
"Async.Start will behave as StartImmediate" |> addWarning com ctx.InlinePath r
36283627

@@ -3634,6 +3633,7 @@ let asyncs com (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr lis
36343633
| "Catch" ->
36353634
Helper.LibCall(com, "Async", "catchAsync", t, args, i.SignatureArgTypes, genArgs = i.GenericArgs, ?loc = r)
36363635
|> Some
3636+
| "RunSynchronously" -> None
36373637
// Fable.Core extensions
36383638
| meth ->
36393639
Helper.LibCall(

src/fable-library-ts/Async.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,14 @@ export function sleep(millisecondsDueTime: number) {
159159
});
160160
}
161161

162-
export function runSynchronously(): never {
163-
throw new Error("Asynchronous code cannot be run synchronously in JS");
164-
}
165-
166162
export function start<T>(computation: Async<T>, cancellationToken?: CancellationToken) {
167-
return startWithContinuations(computation, cancellationToken);
163+
return startWithContinuations(
164+
computation,
165+
emptyContinuation,
166+
function (err) { throw err },
167+
emptyContinuation,
168+
cancellationToken
169+
);
168170
}
169171

170172
export function startImmediate<T>(computation: Async<T>, cancellationToken?: CancellationToken) {
@@ -173,19 +175,16 @@ export function startImmediate<T>(computation: Async<T>, cancellationToken?: Can
173175

174176
export function startWithContinuations<T>(
175177
computation: Async<T>,
176-
continuation?: Continuation<T> | CancellationToken,
177-
exceptionContinuation?: Continuation<any>,
178-
cancellationContinuation?: Continuation<any>,
178+
continuation: Continuation<T>,
179+
exceptionContinuation: Continuation<any>,
180+
cancellationContinuation: Continuation<any>,
179181
cancelToken?: CancellationToken) {
180-
if (typeof continuation !== "function") {
181-
cancelToken = continuation as CancellationToken;
182-
continuation = undefined;
183-
}
182+
184183
const trampoline = new Trampoline();
185184
computation({
186185
onSuccess: continuation ? continuation as Continuation<T> : emptyContinuation,
187-
onError: exceptionContinuation ? exceptionContinuation : emptyContinuation,
188-
onCancel: cancellationContinuation ? cancellationContinuation : emptyContinuation,
186+
onError: exceptionContinuation,
187+
onCancel: cancellationContinuation,
189188
cancelToken: cancelToken ? cancelToken : defaultCancellationToken,
190189
trampoline,
191190
});

src/fable-library-ts/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
* [JS/TS] Fix #4049: decimal/bigint to integer conversion checks (by @ncave)
1111
* [JS/TS] Fix `decimal` to `char` conversion checks (by @ManngelMaxime)
12+
* [JS/TS] Propagate non-captured exception when running `Async.Start` or `Async.StartImmediate` (by @MangelMaxime)
13+
* [JS/TS] Remove `Async.RunSynchronously` (by @MangelMaxime)
14+
* [JS/TS] Change signature of `startWithContinuations` to always require all its arguments (by @MangelMaxime)
1215

1316
## 2.0.0-beta.1 - 2025-02-16
1417

src/fcs-fable/src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3860,6 +3860,9 @@ type FSharpCheckProjectResults
38603860
|> Array.toSeq
38613861
#endif //!FABLE_COMPILER
38623862
| Choice2Of2 task ->
3863+
#if FABLE_COMPILER
3864+
seq {}
3865+
#else
38633866
Async.RunSynchronously(
38643867
async {
38653868
let! tcSymbolUses = task
@@ -3872,6 +3875,7 @@ type FSharpCheckProjectResults
38723875
},
38733876
?cancellationToken = cancellationToken
38743877
)
3878+
#endif //!FABLE_COMPILER
38753879

38763880
results
38773881
|> Seq.filter (fun symbolUse -> symbolUse.ItemOccurrence <> ItemOccurrence.RelatedText)
@@ -3890,7 +3894,7 @@ type FSharpCheckProjectResults
38903894

38913895
let cenv = SymbolEnv(tcGlobals, thisCcu, Some ccuSig, tcImports)
38923896

3893-
let tcSymbolUses =
3897+
let tcSymbolUses : TcSymbolUses seq =
38943898
match builderOrSymbolUses with
38953899
| Choice1Of2 builder ->
38963900
#if FABLE_COMPILER
@@ -3908,7 +3912,12 @@ type FSharpCheckProjectResults
39083912
| _ -> TcSymbolUses.Empty)
39093913
|> Array.toSeq
39103914
#endif //!FABLE_COMPILER
3911-
| Choice2Of2 tcSymbolUses -> Async.RunSynchronously(tcSymbolUses, ?cancellationToken = cancellationToken)
3915+
| Choice2Of2 tcSymbolUses ->
3916+
#if FABLE_COMPILER
3917+
seq {}
3918+
#else
3919+
Async.RunSynchronously(tcSymbolUses, ?cancellationToken = cancellationToken)
3920+
#endif //!FABLE_COMPILER
39123921

39133922
[|
39143923
for r in tcSymbolUses do

tests/Js/Main/AsyncTests.fs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Fable.Tests.Async
22

33
open System
4+
open Util
45
open Util.Testing
56

67
#if FABLE_COMPILER
@@ -72,6 +73,26 @@ let tests =
7273
!result
7374
f true + f false |> equal 22
7475

76+
testCase "Non captured exception in async is propagated when using Async.StartImmediate" <| fun () ->
77+
throwsAnyError (fun _ ->
78+
async {
79+
failwith "boom!"
80+
} |> Async.StartImmediate
81+
)
82+
83+
#if FABLE_COMPILER
84+
// Behaviour of Async.Start, is the same as Async.StartImmediate in JS
85+
// We disable this test for .NET, because it seems like we can't capture the exception
86+
// This should be fine, because Fable generate a warning about the Async.Start
87+
// behaviour being the same as Async.StartImmediate
88+
testCase "Non captured exception in async is propagated when using Async.Start" <| fun () ->
89+
throwsAnyError (fun _ ->
90+
async {
91+
failwith "boom!"
92+
} |> Async.Start
93+
)
94+
#endif
95+
7596
testCase "Simple async is executed correctly" <| fun () ->
7697
let result = ref false
7798
let x = async { return 99 }
@@ -596,4 +617,4 @@ let tests =
596617
let! res = parentWorkflow()
597618
equal 7 res
598619
}
599-
]
620+
]

0 commit comments

Comments
 (0)