@@ -211,7 +211,7 @@ module TaskTests_Net10 =
211211 ]
212212
213213 testList " TryWith" [
214- testCaseAsync " try with"
214+ testCaseAsync " try with syntax "
215215 <| async {
216216 let data = 42
217217
@@ -230,27 +230,227 @@ module TaskTests_Net10 =
230230
231231 Expect.equal actual data " TryWith should work"
232232 }
233+
234+ testList " StackTracePreservation" [
235+ testCaseAsync " threadpool"
236+ <| async {
237+ let data = 42
238+
239+ let func0 ( x : int ) : Task < int > =
240+ Task.Run< int>( fun () ->
241+ task {
242+ do ! Task.Yield()
243+ return x + 1
244+ }
245+ )
246+
247+ let func1 ( x : int ) : Task < int > =
248+ Task.Run< int>( fun () ->
249+ task {
250+ do ! Task.Yield()
251+ failwith " boom"
252+ return ! func0 x
253+ }
254+ )
255+
256+ let func2 ( x : int ) =
257+ Task.Run< int>( fun () ->
258+ task {
259+ let y = x + 1
260+ do ! Task.Yield()
261+ return ! func1 y
262+ }
263+ )
264+
265+ let func3 ( x : int ) =
266+ Task.Run< int>( fun () ->
267+ task {
268+ let y = x + 1
269+ do ! Task.Yield()
270+ return ! func2 y
271+ }
272+ )
273+
274+ let mutable exn = None
275+
276+ let! actual =
277+ task {
278+ let data = data
279+
280+ try
281+ let! _ = func3 3
282+ ()
283+ with e ->
284+ exn <- Some e
285+
286+ return data
287+ }
288+ |> Async.AwaitTask
289+
290+
291+ Expect.equal actual data " TryWith should work"
292+ Expect.isSome exn " Exception should have been caught"
293+
294+ exn
295+ |> Option.iter ( fun e ->
296+ Expect.equal e.Message " boom" " Exception message should match"
297+ Expect.stringContains e.StackTrace " func3" " "
298+ Expect.stringContains e.StackTrace " func2" " "
299+ Expect.stringContains e.StackTrace " func1" " "
300+ Expect.stringContainsNot e.StackTrace " func0" " "
301+ )
302+ }
303+
304+
305+ testCaseAsync " yield"
306+ <| async {
307+ let data = 42
308+
309+ let func0 ( x : int ) : Task < int > =
310+ task {
311+ do ! Task.Yield()
312+ return x + 1
313+ }
314+
315+ let func1 ( x : int ) : Task < int > =
316+ task {
317+ do ! Task.Yield()
318+ failwith " boom"
319+ return ! func0 x
320+ }
321+
322+
323+ let func2 ( x : int ) =
324+ task {
325+ let y = x + 1
326+ do ! Task.Yield()
327+ return ! func1 y
328+ }
329+
330+
331+ let func3 ( x : int ) =
332+ task {
333+ let y = x + 1
334+ do ! Task.Yield()
335+ return ! func2 y
336+ }
337+
338+
339+ let mutable exn = None
340+
341+ let! actual =
342+ task {
343+ let data = data
344+
345+ try
346+ let! _ = func3 3
347+ ()
348+ with e ->
349+ exn <- Some e
350+
351+ return data
352+ }
353+ |> Async.AwaitTask
354+
355+
356+ Expect.equal actual data " TryWith should work"
357+ Expect.isSome exn " Exception should have been caught"
358+
359+ exn
360+ |> Option.iter ( fun e ->
361+ Expect.equal e.Message " boom" " Exception message should match"
362+ Expect.stringContains e.StackTrace " func3" " "
363+ Expect.stringContains e.StackTrace " func2" " "
364+ Expect.stringContains e.StackTrace " func1" " "
365+ Expect.stringContainsNot e.StackTrace " func0" " "
366+ )
367+ }
368+
369+
370+ testCaseAsync " sync"
371+ <| async {
372+ let data = 42
373+
374+ let func0 ( x : int ) : Task < int > =
375+ task {
376+ do ! Task.Yield()
377+ return x + 1
378+ }
379+
380+ let func1 ( x : int ) : Task < int > =
381+
382+ task {
383+ failwith " boom"
384+ return ! func0 x
385+ }
386+
387+ let func2 ( x : int ) =
388+ task {
389+ let y = x + 1
390+ return ! func1 y
391+ }
392+
393+ let func3 ( x : int ) =
394+ task {
395+ let y = x + 1
396+ return ! func2 y
397+ }
398+
399+ let mutable exn = None
400+
401+ let! actual =
402+ task {
403+ let data = data
404+
405+ try
406+ let! _ = func3 3
407+ ()
408+ with e ->
409+ exn <- Some e
410+
411+ return data
412+ }
413+ |> Async.AwaitTask
414+
415+
416+ Expect.equal actual data " TryWith should work"
417+ Expect.isSome exn " Exception should have been caught"
418+
419+ exn
420+ |> Option.iter ( fun e ->
421+ Expect.equal e.Message " boom" " Exception message should match"
422+ Expect.stringContains e.StackTrace " func3" " "
423+ Expect.stringContains e.StackTrace " func2" " "
424+ Expect.stringContains e.StackTrace " func1" " "
425+ Expect.stringContainsNot e.StackTrace " func0" " "
426+ )
427+ }
428+
429+ ]
233430 ]
234431
235432 testList " TryFinally" [
236433 testCaseAsync " try finally"
237434 <| async {
238435 let data = 42
239436
437+ let mutable wasFinalized = false
438+
240439 let! actual =
241440 task {
242441 let data = data
243442
244443 try
245444 ()
246445 finally
247- ()
446+ wasFinalized <- true
248447
249448 return data
250449 }
251450 |> Async.AwaitTask
252451
253452 Expect.equal actual data " TryFinally should work"
453+ Expect.isTrue wasFinalized " Finally block should have run"
254454 }
255455 ]
256456
@@ -697,17 +897,17 @@ module TaskTests_Net10 =
697897
698898 let fakeWork id yieldTimes ( l : ResizeArray < _ >) =
699899 // TODO: Figure out why we need to wrap this in Task.Run to avoid deadlocks
700- // Task.Run<DateTimeOffset>(fun () ->
701- backgroundTask {
702- // task {
703- lock l ( fun () -> l.Add( id))
704- do ! Task.yieldMany yieldTimes
705- // do! Task.Delay(250)
706- let dt = DateTimeOffset.UtcNow
707- lock l ( fun () -> l.Add( id))
708- return dt
709- }
710- // )
900+ Task.Run< DateTimeOffset>( fun () ->
901+ task {
902+ // task {
903+ lock l ( fun () -> l.Add( id))
904+ do ! Task.yieldMany yieldTimes
905+ // do! Task.Delay(250)
906+ let dt = DateTimeOffset.UtcNow
907+ lock l ( fun () -> l.Add( id))
908+ return dt
909+ }
910+ )
711911
712912 // Have earlier tasks take longer to complete
713913 // so we can see if they are sequenced or not
0 commit comments