From 1f5e33fe64b5c449f6ab810e283aea3da2a5a1a2 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Thu, 28 May 2026 11:33:27 +0100 Subject: [PATCH 1/3] feat(Async+Task+ValueTask): consistent helper modules --- docs/release-notes/.FSharp.Core/11.0.100.md | 4 + src/FSharp.Core/async.fs | 42 +++ src/FSharp.Core/async.fsi | 120 +++++++ src/FSharp.Core/tasks.fs | 156 +++++++++ src/FSharp.Core/tasks.fsi | 274 +++++++++++++++ ...p.Core.SurfaceArea.netstandard20.debug.bsl | 20 +- ...Core.SurfaceArea.netstandard20.release.bsl | 20 +- ...p.Core.SurfaceArea.netstandard21.debug.bsl | 28 +- ...Core.SurfaceArea.netstandard21.release.bsl | 26 ++ .../FSharp.Core.UnitTests.fsproj | 2 + .../AsyncModuleFunctions.fs | 85 +++++ .../TaskModuleFunctions.fs | 312 ++++++++++++++++++ 12 files changed, 1084 insertions(+), 5 deletions(-) create mode 100644 tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModuleFunctions.fs create mode 100644 tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs diff --git a/docs/release-notes/.FSharp.Core/11.0.100.md b/docs/release-notes/.FSharp.Core/11.0.100.md index 70bbaae06fe..234863df2c7 100644 --- a/docs/release-notes/.FSharp.Core/11.0.100.md +++ b/docs/release-notes/.FSharp.Core/11.0.100.md @@ -2,3 +2,7 @@ * Fix `Array.exists2` documentation examples to use equal-length arrays; the previous examples would throw `ArgumentException` at runtime instead of returning the documented `false`/`true` values. ([PR #19672](https://github.com/dotnet/fsharp/pull/19672)) * Move `Async.StartChild` to the "Starting Async Computations" docs category alongside `Async.StartChildAsTask`. ([Issue #19667](https://github.com/dotnet/fsharp/issues/19667)) + +### Added + +* Added camelCase module-level functions `result`, `map`, `bind`, `ignore`, `catchWith`, `catch`, and `empty` in `module`s `Async`,`Task` and `ValueTask`, plus `Task.ofValueTask` and `ValueTask.ofTask`. ([LanguageSuggestion #1466](https://github.com/fsharp/fslang-suggestions/issues/1466), [PR #19844](https://github.com/dotnet/fsharp/pull/19844)) diff --git a/src/FSharp.Core/async.fs b/src/FSharp.Core/async.fs index f18e451f357..6f3f238a5e9 100644 --- a/src/FSharp.Core/async.fs +++ b/src/FSharp.Core/async.fs @@ -2355,3 +2355,45 @@ module WebExtensions = start = (fun userToken -> this.DownloadFileAsync(address, fileName, userToken)), result = (fun _ -> ()) ) + +[] +module Async = + + [] + let inline result (value: 'T) : Async<'T> = + async.Return value + + [] + let inline map ([] mapping: 'T -> 'U) (computation: Async<'T>) : Async<'U> = + async.Bind(computation, mapping >> async.Return) + + [] + let inline bind ([] binder: 'T -> Async<'U>) (computation: Async<'T>) : Async<'U> = + async.Bind(computation, binder) + + [] + [] + let inline ignore<'T> (computation: Async<'T>) : Async = + Async.Ignore computation + + [] + let catchWith (handler: exn -> 'T) (computation: Async<'T>) : Async<'T> = + async { + try + return! computation + with e -> + return handler e + } + + [] + let catch (computation: Async<'T>) : Async> = + async { + try + let! v = computation + return Result.Ok v + with e -> + return Result.Error e + } + + [] + let empty: Async = async.Zero() diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index b2fe66ddd13..e9c329931c7 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -1547,3 +1547,123 @@ namespace Microsoft.FSharp.Control module internal AsyncBuilderImpl = val async : AsyncBuilder + /// Contains camelCase module-level functions for computations. + /// + /// Async Programming + [] + [] + module Async = + + /// Creates an asynchronous computation that returns the given value. + /// + /// The value to return. + /// + /// An asynchronous computation that returns value when executed. + /// + /// + /// + /// let computation = Async.result 42 + /// computation |> Async.RunSynchronously // evaluates to 42 + /// + /// + [] + val inline result: value: 'T -> Async<'T> + + /// Creates an asynchronous computation that applies the mapping function to the result of the given computation. + /// + /// The function to apply to the result. + /// The input computation. + /// + /// An asynchronous computation that applies mapping to the result of computation. + /// + /// + /// + /// let computation = Async.result 21 |> Async.map (fun x -> x * 2) + /// computation |> Async.RunSynchronously // evaluates to 42 + /// + /// + [] + val inline map: mapping: ('T -> 'U) -> computation: Async<'T> -> Async<'U> + + /// Creates an asynchronous computation that passes the result of the given computation to the binder function. + /// + /// A function that takes the result of the computation and returns a new asynchronous computation. + /// The input computation. + /// + /// An asynchronous computation that performs a monadic bind on the result of computation. + /// + /// + /// + /// let computation = Async.result 21 |> Async.bind (fun x -> Async.result (x * 2)) + /// computation |> Async.RunSynchronously // evaluates to 42 + /// + /// + [] + val inline bind: binder: ('T -> Async<'U>) -> computation: Async<'T> -> Async<'U> + + /// Creates an asynchronous computation that runs the given computation and ignores its result. + /// + /// The input computation. + /// + /// A computation that is equivalent to the input computation, but disregards the result. + /// + /// + /// + /// let readFile filename numBytes = + /// async { + /// use file = System.IO.File.OpenRead(filename) + /// do! file.AsyncRead(numBytes) |> Async.ignore<int> + /// } + /// + /// + [] + [] + val inline ignore<'T> : computation: Async<'T> -> Async + + /// Creates an asynchronous computation that runs the given computation. + /// If it raises an exception, the handler function is called with the exception and its result is returned. + /// + /// A function to handle exceptions, returning a recovery value. + /// The input computation. + /// + /// An asynchronous computation that returns the result of computation, or the result of handler if an exception is raised. + /// + /// + /// + /// let safeDiv x y = + /// async { return x / y } + /// |> Async.catchWith (fun _ -> 0) + /// safeDiv 10 0 |> Async.RunSynchronously // evaluates to 0 + /// + /// + [] + val catchWith: handler: (exn -> 'T) -> computation: Async<'T> -> Async<'T> + + /// Creates an asynchronous computation that runs the given computation and returns its result as Ok, + /// or returns Error with the exception if one is raised. + /// + /// The input computation. + /// + /// An asynchronous computation that returns Ok of the result or Error of the exception. + /// + /// + /// + /// let safeDiv x y = + /// async { return x / y } |> Async.catch + /// safeDiv 10 2 |> Async.RunSynchronously // evaluates to Ok 5 + /// safeDiv 10 0 |> Async.RunSynchronously // evaluates to Error (DivideByZeroException ...) + /// + /// + [] + val catch: computation: Async<'T> -> Async> + + /// An asynchronous computation that returns unit. This is equivalent to async.Zero(). + /// + /// + /// + /// Async.empty |> Async.RunSynchronously // evaluates to () + /// + /// + [] + val empty: Async + diff --git a/src/FSharp.Core/tasks.fs b/src/FSharp.Core/tasks.fs index eec12a86c63..9c3c2b29390 100644 --- a/src/FSharp.Core/tasks.fs +++ b/src/FSharp.Core/tasks.fs @@ -716,3 +716,159 @@ module LowPlusPriority = this.Bind(computation, fun (result2: ^TResult2) -> this.Return struct (result1, result2)) ) ) + +namespace Microsoft.FSharp.Control + +open System.Threading.Tasks +open Microsoft.FSharp.Core +open TaskBuilder +open Microsoft.FSharp.Control.TaskBuilderExtensions +open Microsoft.FSharp.Control.TaskBuilderExtensions.LowPriority +open Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority + +[] +module Task = + + [] + let inline result (value: 'T) : Task<'T> = + Task.FromResult value + + [] + let empty: Task = result () + + [] + let inline map ([] mapping: 'T -> 'U) (task: Task<'T>) : Task<'U> = + if task.Status = TaskStatus.RanToCompletion then + result (mapping task.Result) + else + TaskBuilder.task { + let! v = task + return mapping v + } + + [] + let inline bind ([] binder: 'T -> Task<'U>) (task: Task<'T>) : Task<'U> = + if task.Status = TaskStatus.RanToCompletion then + binder task.Result + else + TaskBuilder.task { + let! v = task + return! binder v + } + + [] + [] + let inline ignore<'T> (task: Task<'T>) : Task = + if task.Status = TaskStatus.RanToCompletion then + empty + else + map ignore task + + [] + let inline catchWith ([] handler: exn -> 'T) (task: Task<'T>) : Task<'T> = + if task.Status = TaskStatus.RanToCompletion then + task + else + TaskBuilder.task { + try + return! task + with e -> + return handler e + } + + [] + let inline catch (task: Task<'T>) : Task> = + if task.Status = TaskStatus.RanToCompletion then + result (Ok task.Result) + else + TaskBuilder.task { + try + let! v = task + return Ok v + with e -> + return Error e + } + +#if NETSTANDARD2_1 + [] + let inline ofValueTask (valueTask: ValueTask<'T>) : Task<'T> = + valueTask.AsTask() +#endif + +#if NETSTANDARD2_1 +[] +module ValueTask = + + [] + let inline result (value: 'T) : ValueTask<'T> = + ValueTask<'T>(value) + + [] + let inline map ([] mapping: 'T -> 'U) (task: ValueTask<'T>) : ValueTask<'U> = + if task.IsCompletedSuccessfully then + ValueTask<'U>(mapping task.Result) + else + let t: Task<'U> = + TaskBuilder.task { + let! v = task + return mapping v + } + + ValueTask<'U>(t) + + [] + let inline bind ([] binder: 'T -> ValueTask<'U>) (task: ValueTask<'T>) : ValueTask<'U> = + if task.IsCompletedSuccessfully then + binder task.Result + else + let t: Task<'U> = + TaskBuilder.task { + let! v = task + return! binder v + } + + ValueTask<'U>(t) + + [] + [] + let inline ignore<'T> (task: ValueTask<'T>) : ValueTask = + map ignore task + + [] + let inline catchWith ([] handler: exn -> 'T) (task: ValueTask<'T>) : ValueTask<'T> = + if task.IsCompletedSuccessfully then + task + else + let t: Task<'T> = + TaskBuilder.task { + try + return! task + with e -> + return handler e + } + + ValueTask<'T>(t) + + [] + let inline catch (task: ValueTask<'T>) : ValueTask> = + if task.IsCompletedSuccessfully then + ValueTask>(Ok task.Result) + else + let t: Task> = + TaskBuilder.task { + try + let! v = task + return Ok v + with e -> + return Error e + } + + ValueTask>(t) + + [] + let empty: ValueTask = Unchecked.defaultof<_> + + [] + let inline ofTask (task: Task<'T>) : ValueTask<'T> = + ValueTask<'T>(task) +#endif diff --git a/src/FSharp.Core/tasks.fsi b/src/FSharp.Core/tasks.fsi index 76d84bcfd28..70209087369 100644 --- a/src/FSharp.Core/tasks.fsi +++ b/src/FSharp.Core/tasks.fsi @@ -457,3 +457,277 @@ module HighPriority = /// member inline MergeSources< ^TResult1, ^TResult2> : task1: Task< ^TResult1 > * task2: Task< ^TResult2 > -> Task + +namespace Microsoft.FSharp.Control + +open System.Threading.Tasks +open Microsoft.FSharp.Core + +/// Contains camelCase module-level functions for computations. +/// +/// Async Programming +[] +module Task = + + /// Creates a task that returns the given value. + /// + /// The value to return. + /// + /// A completed task that returns value. + /// + /// + /// + /// let t = Task.result 42 + /// t.Result // evaluates to 42 + /// + /// + [] + val inline result: value: 'T -> Task<'T> + + /// Creates a task that applies the mapping function to the result of the given task. + /// + /// The function to apply to the result. + /// The input task. + /// + /// A task that applies mapping to the result of task. + /// + /// + /// + /// let t = Task.result 21 |> Task.map (fun x -> x * 2) + /// t.Result // evaluates to 42 + /// + /// + [] + val inline map: mapping: ('T -> 'U) -> task: Task<'T> -> Task<'U> + + /// Creates a task that passes the result of the given task to the binder function. + /// + /// A function that takes the result of the task and returns a new task. + /// The input task. + /// + /// A task that performs a monadic bind on the result of task. + /// + /// + /// + /// let t = Task.result 21 |> Task.bind (fun x -> Task.result (x * 2)) + /// t.Result // evaluates to 42 + /// + /// + [] + val inline bind: binder: ('T -> Task<'U>) -> task: Task<'T> -> Task<'U> + + /// Creates a task that runs the given task and ignores its result. + /// + /// The input task. + /// + /// A task that is equivalent to the input task, but disregards the result. + /// + /// + /// + /// let t : Task<unit> = Task.result 42 |> Task.ignore<int> + /// t.Result // evaluates to () + /// + /// + [] + [] + val inline ignore<'T> : task: Task<'T> -> Task + + /// Creates a task that runs the given task. + /// If it raises an exception, the handler function is called with the exception and its result is returned. + /// + /// A function to handle exceptions, returning a recovery value. + /// The input task. + /// + /// A task that returns the result of task, or the result of handler if an exception is raised. + /// + /// + /// + /// let safeDiv x y = + /// task { return x / y } + /// |> Task.catchWith (fun _ -> 0) + /// (safeDiv 10 0).Result // evaluates to 0 + /// + /// + [] + val inline catchWith: handler: (exn -> 'T) -> task: Task<'T> -> Task<'T> + + /// Creates a task that runs the given task and returns its result as Ok, + /// or returns Error with the exception if one is raised. + /// + /// The input task. + /// + /// A task that returns Ok of the result or Error of the exception. + /// + /// + /// + /// let safeDiv x y = task { return x / y } |> Task.catch + /// (safeDiv 10 2).Result // evaluates to Ok 5 + /// (safeDiv 10 0).Result // evaluates to Error (DivideByZeroException ...) + /// + /// + [] + val inline catch: task: Task<'T> -> Task> + + /// A completed task that returns unit. This is a Task<unit> (not the non-generic Task.CompletedTask). + /// + /// + /// + /// Task.empty.Result // evaluates to () + /// + /// + [] + val empty: Task + +#if NETSTANDARD2_1 + /// Converts a to a . + /// + /// The input value task. + /// + /// A task equivalent to the given value task. + /// + /// + /// + /// let vt = ValueTask<int>(42) + /// let t = Task.ofValueTask vt + /// t.Result // evaluates to 42 + /// + /// + [] + val inline ofValueTask: valueTask: ValueTask<'T> -> Task<'T> +#endif + +#if NETSTANDARD2_1 +/// Contains camelCase module-level functions for computations. +/// +/// Async Programming +[] +module ValueTask = + + /// Creates a value task that returns the given value. + /// + /// The value to return. + /// + /// A completed value task that returns value. + /// + /// + /// + /// let vt = ValueTask.result 42 + /// vt.Result // evaluates to 42 + /// + /// + [] + val inline result: value: 'T -> ValueTask<'T> + + /// Creates a value task that applies the mapping function to the result of the given value task. + /// + /// The function to apply to the result. + /// The input value task. + /// + /// A value task that applies mapping to the result of task. + /// + /// + /// + /// let vt = ValueTask.result 21 |> ValueTask.map (fun x -> x * 2) + /// vt.Result // evaluates to 42 + /// + /// + [] + val inline map: mapping: ('T -> 'U) -> task: ValueTask<'T> -> ValueTask<'U> + + /// Creates a value task that passes the result of the given value task to the binder function. + /// + /// A function that takes the result of the value task and returns a new value task. + /// The input value task. + /// + /// A value task that performs a monadic bind on the result of task. + /// + /// + /// + /// let vt = ValueTask.result 21 |> ValueTask.bind (fun x -> ValueTask.result (x * 2)) + /// vt.Result // evaluates to 42 + /// + /// + [] + val inline bind: binder: ('T -> ValueTask<'U>) -> task: ValueTask<'T> -> ValueTask<'U> + + /// Creates a value task that runs the given value task and ignores its result. + /// + /// When the value task is already synchronously complete, this avoids allocating a Task. + /// + /// The input value task. + /// + /// A value task that is equivalent to the input value task, but disregards the result. + /// + /// + /// + /// let vt : ValueTask<unit> = ValueTask.result 42 |> ValueTask.ignore<int> + /// vt.Result // evaluates to () + /// + /// + [] + [] + val inline ignore<'T> : task: ValueTask<'T> -> ValueTask + + /// Creates a value task that runs the given value task. + /// If it raises an exception, the handler function is called with the exception and its result is returned. + /// + /// A function to handle exceptions, returning a recovery value. + /// The input value task. + /// + /// A value task that returns the result of task, or the result of handler if an exception is raised. + /// + /// + /// + /// let safeDiv x y = + /// task { return x / y } + /// |> ValueTask.ofTask + /// |> ValueTask.catchWith (fun _ -> 0) + /// (safeDiv 10 0).Result // evaluates to 0 + /// + /// + [] + val inline catchWith: handler: (exn -> 'T) -> task: ValueTask<'T> -> ValueTask<'T> + + /// Creates a value task that runs the given value task and returns its result as Ok, + /// or returns Error with the exception if one is raised. + /// + /// The input value task. + /// + /// A value task that returns Ok of the result or Error of the exception. + /// + /// + /// + /// let safeDiv x y = task { return x / y } |> ValueTask.ofTask |> ValueTask.catch + /// (safeDiv 10 2).Result // evaluates to Ok 5 + /// (safeDiv 10 0).Result // evaluates to Error (DivideByZeroException ...) + /// + /// + [] + val inline catch: task: ValueTask<'T> -> ValueTask> + + /// A completed value task that returns unit. + /// + /// + /// + /// ValueTask.empty.Result // evaluates to () + /// + /// + [] + val empty: ValueTask + + /// Converts a to a . + /// + /// The input task. + /// + /// A value task equivalent to the given task. + /// + /// + /// + /// let t = Task.FromResult 42 + /// let vt = ValueTask.ofTask t + /// vt.Result // evaluates to 42 + /// + /// + [] + val inline ofTask: task: Task<'T> -> ValueTask<'T> +#endif diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 5b6cc0bce4e..33bf7166dac 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -603,8 +603,8 @@ Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1 Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] UnionMany[T](System.Collections.Generic.IEnumerable`1[Microsoft.FSharp.Collections.FSharpSet`1[T]]) Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] Union[T](Microsoft.FSharp.Collections.FSharpSet`1[T], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) -Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T1],Microsoft.FSharp.Collections.FSharpSet`1[T2]] PartitionWith[T,T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[T1,T2]], Microsoft.FSharp.Collections.FSharpSet`1[T]) +Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MaxElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MinElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: TState FoldBack[T,TState](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[TState,TState]], Microsoft.FSharp.Collections.FSharpSet`1[T], TState) @@ -617,6 +617,14 @@ Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncRet Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn OnSuccess(T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn Success(Microsoft.FSharp.Control.AsyncActivation`1[T], T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Void OnExceptionRaised() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Ignore[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Control.FSharpAsync`1[TResult]], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] Result[T](T) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Bind[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], Microsoft.FSharp.Control.FSharpAsync`1[TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn CallThenInvoke[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], TResult, Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Invoke[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Control.AsyncActivation`1[T]) @@ -745,6 +753,14 @@ Microsoft.FSharp.Control.ObservableModule: System.IObservable`1[T] Merge[T](Syst Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[TResult1],System.IObservable`1[TResult2]] Split[T,TResult1,TResult2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[TResult1,TResult2]], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[T],System.IObservable`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: Void Add[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], System.IObservable`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.Task`1[TResult]], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] Result[T](T) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] RunDynamic[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] Run[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilderBase: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit] For[T,TOverall](System.Collections.Generic.IEnumerable`1[T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit]]) @@ -2667,4 +2683,4 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String Name Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType -Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() \ No newline at end of file +Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 217d4b7c837..401ca3f2d59 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -603,8 +603,8 @@ Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1 Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] UnionMany[T](System.Collections.Generic.IEnumerable`1[Microsoft.FSharp.Collections.FSharpSet`1[T]]) Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] Union[T](Microsoft.FSharp.Collections.FSharpSet`1[T], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) -Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T1],Microsoft.FSharp.Collections.FSharpSet`1[T2]] PartitionWith[T,T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[T1,T2]], Microsoft.FSharp.Collections.FSharpSet`1[T]) +Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MaxElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MinElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: TState FoldBack[T,TState](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[TState,TState]], Microsoft.FSharp.Collections.FSharpSet`1[T], TState) @@ -617,6 +617,14 @@ Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncRet Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn OnSuccess(T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn Success(Microsoft.FSharp.Control.AsyncActivation`1[T], T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Void OnExceptionRaised() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Ignore[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Control.FSharpAsync`1[TResult]], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] Result[T](T) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Bind[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], Microsoft.FSharp.Control.FSharpAsync`1[TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn CallThenInvoke[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], TResult, Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Invoke[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Control.AsyncActivation`1[T]) @@ -745,6 +753,14 @@ Microsoft.FSharp.Control.ObservableModule: System.IObservable`1[T] Merge[T](Syst Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[TResult1],System.IObservable`1[TResult2]] Split[T,TResult1,TResult2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[TResult1,TResult2]], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[T],System.IObservable`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: Void Add[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], System.IObservable`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.Task`1[TResult]], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] Result[T](T) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] RunDynamic[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] Run[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilderBase: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit] For[T,TOverall](System.Collections.Generic.IEnumerable`1[T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit]]) @@ -2666,4 +2682,4 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String Name Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType -Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() \ No newline at end of file +Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 43defdb622e..ab4e8539148 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -605,8 +605,8 @@ Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1 Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] UnionMany[T](System.Collections.Generic.IEnumerable`1[Microsoft.FSharp.Collections.FSharpSet`1[T]]) Microsoft.FSharp.Collections.SetModule: Microsoft.FSharp.Collections.FSharpSet`1[T] Union[T](Microsoft.FSharp.Collections.FSharpSet`1[T], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) -Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T1],Microsoft.FSharp.Collections.FSharpSet`1[T2]] PartitionWith[T,T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[T1,T2]], Microsoft.FSharp.Collections.FSharpSet`1[T]) +Microsoft.FSharp.Collections.SetModule: System.Tuple`2[Microsoft.FSharp.Collections.FSharpSet`1[T],Microsoft.FSharp.Collections.FSharpSet`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MaxElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: T MinElement[T](Microsoft.FSharp.Collections.FSharpSet`1[T]) Microsoft.FSharp.Collections.SetModule: TState FoldBack[T,TState](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[TState,TState]], Microsoft.FSharp.Collections.FSharpSet`1[T], TState) @@ -619,6 +619,14 @@ Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncRet Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn OnSuccess(T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn Success(Microsoft.FSharp.Control.AsyncActivation`1[T], T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Void OnExceptionRaised() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Ignore[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Control.FSharpAsync`1[TResult]], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] Result[T](T) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Bind[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], Microsoft.FSharp.Control.FSharpAsync`1[TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn CallThenInvoke[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], TResult, Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Invoke[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Control.AsyncActivation`1[T]) @@ -747,6 +755,15 @@ Microsoft.FSharp.Control.ObservableModule: System.IObservable`1[T] Merge[T](Syst Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[TResult1],System.IObservable`1[TResult2]] Split[T,TResult1,TResult2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[TResult1,TResult2]], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[T],System.IObservable`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: Void Add[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], System.IObservable`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.Task`1[TResult]], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] OfValueTask[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] Result[T](T) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] RunDynamic[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] Run[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilderBase: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit] For[T,TOverall](System.Collections.Generic.IEnumerable`1[T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit]]) @@ -804,6 +821,15 @@ Microsoft.FSharp.Control.TaskBuilderModule: Microsoft.FSharp.Control.TaskBuilder Microsoft.FSharp.Control.TaskBuilderModule: Microsoft.FSharp.Control.TaskBuilder task Microsoft.FSharp.Control.TaskStateMachineData`1[T]: System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[T] MethodBuilder Microsoft.FSharp.Control.TaskStateMachineData`1[T]: T Result +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.ValueTask`1[TResult]], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] OfTask[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] Result[T](T) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] AsyncDownloadFile(System.Net.WebClient, System.Uri, System.String) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[System.Byte[]] AsyncDownloadData(System.Net.WebClient, System.Uri) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[System.Net.WebResponse] AsyncGetResponse(System.Net.WebRequest) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index ed913ea04d3..1a01d717998 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -619,6 +619,14 @@ Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncRet Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn OnSuccess(T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Microsoft.FSharp.Control.AsyncReturn Success(Microsoft.FSharp.Control.AsyncActivation`1[T], T) Microsoft.FSharp.Control.AsyncActivation`1[T]: Void OnExceptionRaised() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] Ignore[T](Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Control.FSharpAsync`1[TResult]], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], Microsoft.FSharp.Control.FSharpAsync`1[T]) +Microsoft.FSharp.Control.AsyncModule: Microsoft.FSharp.Control.FSharpAsync`1[T] Result[T](T) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Bind[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], Microsoft.FSharp.Control.FSharpAsync`1[TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn CallThenInvoke[T,TResult](Microsoft.FSharp.Control.AsyncActivation`1[T], TResult, Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Control.FSharpAsync`1[T]]) Microsoft.FSharp.Control.AsyncPrimitives: Microsoft.FSharp.Control.AsyncReturn Invoke[T](Microsoft.FSharp.Control.FSharpAsync`1[T], Microsoft.FSharp.Control.AsyncActivation`1[T]) @@ -747,6 +755,15 @@ Microsoft.FSharp.Control.ObservableModule: System.IObservable`1[T] Merge[T](Syst Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[TResult1],System.IObservable`1[TResult2]] Split[T,TResult1,TResult2](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpChoice`2[TResult1,TResult2]], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: System.Tuple`2[System.IObservable`1[T],System.IObservable`1[T]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.IObservable`1[T]) Microsoft.FSharp.Control.ObservableModule: Void Add[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], System.IObservable`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.Task`1[TResult]], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] OfValueTask[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.Task: System.Threading.Tasks.Task`1[T] Result[T](T) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] RunDynamic[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilder: System.Threading.Tasks.Task`1[T] Run[T](Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[T],T]) Microsoft.FSharp.Control.TaskBuilderBase: Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit] For[T,TOverall](System.Collections.Generic.IEnumerable`1[T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[Microsoft.FSharp.Control.TaskStateMachineData`1[TOverall],Microsoft.FSharp.Core.Unit]]) @@ -804,6 +821,15 @@ Microsoft.FSharp.Control.TaskBuilderModule: Microsoft.FSharp.Control.TaskBuilder Microsoft.FSharp.Control.TaskBuilderModule: Microsoft.FSharp.Control.TaskBuilder task Microsoft.FSharp.Control.TaskStateMachineData`1[T]: System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[T] MethodBuilder Microsoft.FSharp.Control.TaskStateMachineData`1[T]: T Result +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.FSharpResult`2[T,System.Exception]] Catch[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] Empty +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] Ignore[T](System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[Microsoft.FSharp.Core.Unit] get_Empty() +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Threading.Tasks.ValueTask`1[TResult]], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[TResult] Map[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] CatchWith[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,T], System.Threading.Tasks.ValueTask`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] OfTask[T](System.Threading.Tasks.Task`1[T]) +Microsoft.FSharp.Control.ValueTask: System.Threading.Tasks.ValueTask`1[T] Result[T](T) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] AsyncDownloadFile(System.Net.WebClient, System.Uri, System.String) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[System.Byte[]] AsyncDownloadData(System.Net.WebClient, System.Uri) Microsoft.FSharp.Control.WebExtensions: Microsoft.FSharp.Control.FSharpAsync`1[System.Net.WebResponse] AsyncGetResponse(System.Net.WebRequest) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj b/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj index d4ff59d3cbd..82428892a87 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj @@ -83,6 +83,8 @@ + + diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModuleFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModuleFunctions.fs new file mode 100644 index 00000000000..3166c72ac00 --- /dev/null +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModuleFunctions.fs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +// Tests for camelCase functions in module Async + +namespace FSharp.Core.UnitTests.Control + +open Xunit + +module AsyncModuleFunctionsTests = + + [] + let ``Async.result wraps value`` () = + let actual = Async.result 42 |> Async.RunSynchronously + Assert.Equal(42, actual) + + [] + let ``Async.map transforms value`` () = + let actual = Async.result 21 |> Async.map (fun x -> x * 2) |> Async.RunSynchronously + Assert.Equal(42, actual) + + [] + let ``Async.map preserves exception`` () = + let comp = async { return failwith "boom" : int } |> Async.map (fun x -> x * 2) + let e = Assert.Throws(fun () -> comp |> Async.RunSynchronously |> ignore) + Assert.Equal("boom", e.Message) + + [] + let ``Async.empty returns unit`` () = + let actual = Async.empty |> Async.RunSynchronously + Assert.Equal((), actual) + + [] + let ``Async.bind threads value`` () = + let actual = + Async.result 21 + |> Async.bind (fun x -> Async.result (x * 2)) + |> Async.RunSynchronously + Assert.Equal(42, actual) + + [] + let ``Async.bind preserves exception`` () = + let comp = async { return failwith "boom" : int } |> Async.bind Async.result + let e = Assert.Throws(fun () -> comp |> Async.RunSynchronously |> ignore) + Assert.Equal("boom", e.Message) + + [] + let ``Async.ignore discards result`` () = + let actual = Async.result 42 |> Async.ignore |> Async.RunSynchronously + Assert.Equal((), actual) + + [] + let ``Async.catchWith recovers from exception`` () = + let actual = + async { return failwith "boom" : int } + |> Async.catchWith (fun e -> Assert.Equal("boom", e.Message); -1) + |> Async.RunSynchronously + Assert.Equal(-1, actual) + + [] + let ``Async.catchWith passes through success`` () = + let actual = + Async.result 42 + |> Async.catchWith (fun _ -> -1) + |> Async.RunSynchronously + Assert.Equal(42, actual) + + [] + let ``Async.catch returns Ok on success`` () = + let actual = Async.result 42 |> Async.catch |> Async.RunSynchronously + Assert.Equal(Ok 42, actual) + + [] + let ``Async.catch returns Error on exception`` () = + let comp = async { return failwith "boom" : int } |> Async.catch + match comp |> Async.RunSynchronously with + | Error ex -> Assert.Equal("boom", ex.Message) + | Ok _ -> failwith "expected Error" + + [] + let ``Async.ignore runs the computation`` () : System.Threading.Tasks.Task = + let comp = async { return failwith "boom" : int } |> Async.ignore + task { + let! e = Assert.ThrowsAsync(fun () -> Async.StartAsTask comp) + Assert.Equal("boom", e.Message) + } diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs new file mode 100644 index 00000000000..6cd1fe48a9c --- /dev/null +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs @@ -0,0 +1,312 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +// Tests for camelCase functions in module Task and module ValueTask + +namespace FSharp.Core.UnitTests.Control + +open System +open System.Threading.Tasks +open Xunit + +module TaskModuleFunctionsTests = + + let pendingTaskSource () = TaskCompletionSource() + + [] + let ``Task.result wraps value`` () = + let t = Task.result 42 + Assert.Equal(42, t.Result) + + [] + let ``Task.map transforms value`` () = + let t = Task.result 21 |> Task.map (fun x -> x * 2) + Assert.Equal(42, t.Result) + + [] + let ``Task.map propagates exception`` () = + let t = Task.FromException(Exception "boom") |> Task.map (fun x -> x * 2) + let ex = Assert.Throws(fun () -> t.GetAwaiter().GetResult() |> ignore) + Assert.Equal("boom", ex.Message) + + [] + let ``Task.bind threads value`` () = + let t = Task.result 21 |> Task.bind (fun x -> Task.result (x * 2)) + Assert.Equal(42, t.Result) + + [] + let ``Task.ignore discards result`` () = + let t = Task.result 42 |> Task.ignore + t.Result + Assert.True(t.IsCompletedSuccessfully) + + [] + let ``Task.catchWith recovers from exception (sync)`` () = + let source = Task.FromException(Exception "boom") + Assert.True(source.IsCompleted) + let t = source |> Task.catchWith (fun _ -> -1) + Assert.Equal(-1, t.Result) + + [] + let ``Task.catchWith recovers from exception (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.catchWith (fun _ -> -1) + Assert.False(t.IsCompleted) + tcs.SetException(Exception "boom") + task { + let! result = t + Assert.Equal(-1, result) + } + + [] + let ``Task.catchWith passes through success (sync)`` () = + let source = Task.result 42 + Assert.True(source.IsCompleted) + let t = source |> Task.catchWith (fun _ -> -1) + Assert.Equal(42, t.Result) + + [] + let ``Task.catchWith passes through success (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.catchWith (fun _ -> -1) + Assert.False(t.IsCompleted) + tcs.SetResult(42) + task { + let! result = t + Assert.Equal(42, result) + } + + [] + let ``Task.catch returns Ok on success (sync)`` () = + let source = Task.result 42 + Assert.True(source.IsCompleted) + let t = source |> Task.catch + Assert.Equal(Ok 42, t.Result) + + [] + let ``Task.catch returns Ok on success (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.catch + Assert.False(t.IsCompleted) + tcs.SetResult(42) + task { + let! result = t + Assert.Equal(Ok 42, result) + } + + [] + let ``Task.catch returns Error on exception (sync)`` () = + let source = Task.FromException(Exception "boom") + Assert.True(source.IsCompleted) + let t = source |> Task.catch + match t.Result with + | Error ex -> Assert.Equal("boom", ex.Message) + | Ok _ -> failwith "expected Error" + + [] + let ``Task.catch returns Error on exception (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.catch + Assert.False(t.IsCompleted) + tcs.SetException(Exception "boom") + task { + let! result = t + match result with + | Error ex -> Assert.Equal("boom", ex.Message) + | Ok _ -> failwith "expected Error" + } + + [] + let ``Task.ignore runs the computation`` () : Task = + let t = Task.FromException(Exception "boom") |> Task.ignore + task { + let! e = Assert.ThrowsAsync(fun () -> t) + Assert.Equal("boom", e.Message) + } + + [] + let ``Task.ignore runs the computation (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.ignore + Assert.False(t.IsCompleted) + tcs.SetException(Exception "boom") + task { + let! e = Assert.ThrowsAsync(fun () -> t) + Assert.Equal("boom", e.Message) + } + + [] + let ``Task.empty returns completed unit task`` () = + let t = Task.empty + t.Result + Assert.True(t.IsCompletedSuccessfully) + +#if NETSTANDARD2_1 + [] + let ``Task.ofValueTask converts value task`` () = + let vt = ValueTask(42) + let t = Task.ofValueTask vt + Assert.Equal(42, t.Result) + +module ValueTaskModuleFunctionsTests = + + let pendingTaskSource () = TaskCompletionSource() + + [] + let ``ValueTask.result wraps value`` () = + let vt = ValueTask.result 42 + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.map transforms value (sync)`` () = + let vt = ValueTask.result 21 |> ValueTask.map (fun x -> x * 2) + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.map transforms value (async)`` () = + let vt = ValueTask(Task.FromResult 21) |> ValueTask.map (fun x -> x * 2) + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.bind threads value (sync)`` () = + let vt = ValueTask.result 21 |> ValueTask.bind (fun x -> ValueTask.result (x * 2)) + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.bind threads value (async)`` () = + let vt = ValueTask(Task.FromResult 21) |> ValueTask.bind (fun x -> ValueTask.result (x * 2)) + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.ignore discards result (sync)`` () : unit = + let vt = ValueTask.result 42 |> ValueTask.ignore + Assert.True(vt.IsCompletedSuccessfully) + vt.Result + + [] + let ``ValueTask.ignore discards result (async)`` () : unit = + let vt = ValueTask(Task.FromResult 42) |> ValueTask.ignore + vt.Result + + [] + let ``ValueTask.catchWith recovers from exception (sync)`` () = + let source = ValueTask(Task.FromException(Exception "boom")) + Assert.True(source.IsCompleted) + let vt = source |> ValueTask.catchWith (fun _ -> -1) + Assert.Equal(-1, vt.Result) + + [] + let ``ValueTask.catchWith recovers from exception (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catchWith (fun _ -> -1) + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetException(Exception "boom") + task { + let! result = vt + Assert.Equal(-1, result) + } + + [] + let ``ValueTask.catchWith passes through success (sync)`` () = + let source = ValueTask.result 42 + Assert.True(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catchWith (fun _ -> -1) + Assert.Equal(42, vt.Result) + + [] + let ``ValueTask.catchWith passes through success (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catchWith (fun _ -> -1) + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetResult(42) + task { + let! result = vt + Assert.Equal(42, result) + } + + [] + let ``ValueTask.catch returns Ok on success (sync)`` () = + let source = ValueTask.result 42 + Assert.True(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catch + Assert.Equal(Ok 42, vt.Result) + + [] + let ``ValueTask.catch returns Ok on success (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catch + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetResult(42) + task { + let! result = vt + Assert.Equal(Ok 42, result) + } + + [] + let ``ValueTask.catch returns Error on exception (sync)`` () = + let source = ValueTask(Task.FromException(Exception "boom")) + Assert.True(source.IsCompleted) + let vt = source |> ValueTask.catch + match vt.Result with + | Error ex -> Assert.Equal("boom", ex.Message) + | Ok _ -> failwith "expected Error" + + [] + let ``ValueTask.catch returns Error on exception (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catch + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetException(Exception "boom") + task { + let! result = vt + match result with + | Error ex -> Assert.Equal("boom", ex.Message) + | Ok _ -> failwith "expected Error" + } + + [] + let ``ValueTask.ignore runs the computation`` () : Task = + let faulted = ValueTask(Task.FromException(Exception "boom")) + let vt = faulted |> ValueTask.ignore + task { + let! e = Assert.ThrowsAsync(fun () -> vt.AsTask()) + Assert.Equal("boom", e.Message) + } + + [] + let ``ValueTask.ignore runs the computation (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.ignore + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetException(Exception "boom") + task { + let! e = Assert.ThrowsAsync(fun () -> vt.AsTask()) + Assert.Equal("boom", e.Message) + } + + [] + let ``ValueTask.empty returns completed unit value task`` () : unit = + let vt = ValueTask.empty + Assert.True(vt.IsCompletedSuccessfully) + vt.Result + + [] + let ``ValueTask.ofTask wraps task`` () = + let t = Task.FromResult 42 + let vt = ValueTask.ofTask t + Assert.Equal(42, vt.Result) +#endif From d491971da0846c39a34d382304ee3ac32788753b Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Thu, 28 May 2026 17:26:18 +0100 Subject: [PATCH 2/3] copilot review fixes --- docs/release-notes/.FSharp.Core/11.0.100.md | 2 +- src/FSharp.Core/async.fsi | 1 - src/FSharp.Core/tasks.fs | 6 +-- src/FSharp.Core/tasks.fsi | 4 +- .../TaskModuleFunctions.fs | 46 +++++++++++++++++++ 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/docs/release-notes/.FSharp.Core/11.0.100.md b/docs/release-notes/.FSharp.Core/11.0.100.md index 234863df2c7..90204288adc 100644 --- a/docs/release-notes/.FSharp.Core/11.0.100.md +++ b/docs/release-notes/.FSharp.Core/11.0.100.md @@ -5,4 +5,4 @@ ### Added -* Added camelCase module-level functions `result`, `map`, `bind`, `ignore`, `catchWith`, `catch`, and `empty` in `module`s `Async`,`Task` and `ValueTask`, plus `Task.ofValueTask` and `ValueTask.ofTask`. ([LanguageSuggestion #1466](https://github.com/fsharp/fslang-suggestions/issues/1466), [PR #19844](https://github.com/dotnet/fsharp/pull/19844)) +* Added camelCase module-level functions `result`, `map`, `bind`, `ignore`, `catchWith`, `catch`, and `empty` in `module`s `Async`,`Task`, `ValueTask`, plus `Task.ofValueTask` and `ValueTask.ofTask`. ([LanguageSuggestion #1466](https://github.com/fsharp/fslang-suggestions/issues/1466), [PR #19844](https://github.com/dotnet/fsharp/pull/19844)) diff --git a/src/FSharp.Core/async.fsi b/src/FSharp.Core/async.fsi index e9c329931c7..60d2f329613 100644 --- a/src/FSharp.Core/async.fsi +++ b/src/FSharp.Core/async.fsi @@ -1550,7 +1550,6 @@ namespace Microsoft.FSharp.Control /// Contains camelCase module-level functions for computations. /// /// Async Programming - [] [] module Async = diff --git a/src/FSharp.Core/tasks.fs b/src/FSharp.Core/tasks.fs index 9c3c2b29390..d102885b0a6 100644 --- a/src/FSharp.Core/tasks.fs +++ b/src/FSharp.Core/tasks.fs @@ -777,7 +777,7 @@ module Task = } [] - let inline catch (task: Task<'T>) : Task> = + let catch (task: Task<'T>) : Task> = if task.Status = TaskStatus.RanToCompletion then result (Ok task.Result) else @@ -850,7 +850,7 @@ module ValueTask = ValueTask<'T>(t) [] - let inline catch (task: ValueTask<'T>) : ValueTask> = + let catch (task: ValueTask<'T>) : ValueTask> = if task.IsCompletedSuccessfully then ValueTask>(Ok task.Result) else @@ -866,7 +866,7 @@ module ValueTask = ValueTask>(t) [] - let empty: ValueTask = Unchecked.defaultof<_> + let empty: ValueTask = result () [] let inline ofTask (task: Task<'T>) : ValueTask<'T> = diff --git a/src/FSharp.Core/tasks.fsi b/src/FSharp.Core/tasks.fsi index 70209087369..05a502e451e 100644 --- a/src/FSharp.Core/tasks.fsi +++ b/src/FSharp.Core/tasks.fsi @@ -566,7 +566,7 @@ module Task = /// /// [] - val inline catch: task: Task<'T> -> Task> + val catch: task: Task<'T> -> Task> /// A completed task that returns unit. This is a Task<unit> (not the non-generic Task.CompletedTask). /// @@ -703,7 +703,7 @@ module ValueTask = /// /// [] - val inline catch: task: ValueTask<'T> -> ValueTask> + val catch: task: ValueTask<'T> -> ValueTask> /// A completed value task that returns unit. /// diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs index 6cd1fe48a9c..36b1c8f8fc2 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs @@ -5,6 +5,7 @@ namespace FSharp.Core.UnitTests.Control open System +open System.Threading open System.Threading.Tasks open Xunit @@ -119,6 +120,28 @@ module TaskModuleFunctionsTests = | Ok _ -> failwith "expected Error" } + [] + let ``Task.catch returns Error on cancellation (sync)`` () = + let source = Task.FromCanceled(CancellationToken(true)) + Assert.True(source.IsCompleted) + let t = source |> Task.catch + match t.Result with + | Error (:? TaskCanceledException) -> () + | r -> failwithf "expected Error(OperationCanceledException) but got %A" r + + [] + let ``Task.catch returns Error on cancellation (async)`` () : Task = + let tcs = pendingTaskSource() + Assert.False(tcs.Task.IsCompleted) + let t = tcs.Task |> Task.catch + Assert.False(t.IsCompleted) + tcs.SetCanceled() + task { + match! t with + | Error (:? TaskCanceledException) -> () + | r -> failwithf "expected Error(OperationCanceledException) but got %A" r + } + [] let ``Task.ignore runs the computation`` () : Task = let t = Task.FromException(Exception "boom") |> Task.ignore @@ -276,6 +299,29 @@ module ValueTaskModuleFunctionsTests = | Ok _ -> failwith "expected Error" } + [] + let ``ValueTask.catch returns Error on cancellation (sync)`` () = + let source = ValueTask(Task.FromCanceled(CancellationToken(true))) + Assert.True(source.IsCompleted) + let vt = source |> ValueTask.catch + match vt.Result with + | Error (:? TaskCanceledException) -> () + | r -> failwithf "expected Error(TaskCanceledException) but got %A" r + + [] + let ``ValueTask.catch returns Error on cancellation (async)`` () : Task = + let tcs = pendingTaskSource() + let source = ValueTask(tcs.Task) + Assert.False(source.IsCompletedSuccessfully) + let vt = source |> ValueTask.catch + Assert.False(vt.IsCompletedSuccessfully) + tcs.SetCanceled() + task { + match! with + | Error (:? TaskCanceledException) -> () + | r -> failwithf "expected Error(TaskCanceledException) but got %A" r + } + [] let ``ValueTask.ignore runs the computation`` () : Task = let faulted = ValueTask(Task.FromException(Exception "boom")) From 2f5acf61ebf8151230db4fe8291283118aaf3ab5 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Thu, 28 May 2026 18:12:22 +0100 Subject: [PATCH 3/3] Fix netstandard2.0 build --- .../Microsoft.FSharp.Control/TaskModuleFunctions.fs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs index 36b1c8f8fc2..729d464973a 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TaskModuleFunctions.fs @@ -38,7 +38,7 @@ module TaskModuleFunctionsTests = let ``Task.ignore discards result`` () = let t = Task.result 42 |> Task.ignore t.Result - Assert.True(t.IsCompletedSuccessfully) + Assert.True(t.Status = TaskStatus.RanToCompletion) // IsCompletedSuccessfully would work but netstandard2.0 [] let ``Task.catchWith recovers from exception (sync)`` () = @@ -114,8 +114,7 @@ module TaskModuleFunctionsTests = Assert.False(t.IsCompleted) tcs.SetException(Exception "boom") task { - let! result = t - match result with + match! t with | Error ex -> Assert.Equal("boom", ex.Message) | Ok _ -> failwith "expected Error" } @@ -166,7 +165,7 @@ module TaskModuleFunctionsTests = let ``Task.empty returns completed unit task`` () = let t = Task.empty t.Result - Assert.True(t.IsCompletedSuccessfully) + Assert.True(t.Status = TaskStatus.RanToCompletion) // IsCompletedSuccessfully would work but netstandard2.0 #if NETSTANDARD2_1 [] @@ -293,8 +292,7 @@ module ValueTaskModuleFunctionsTests = Assert.False(vt.IsCompletedSuccessfully) tcs.SetException(Exception "boom") task { - let! result = vt - match result with + match! vt with | Error ex -> Assert.Equal("boom", ex.Message) | Ok _ -> failwith "expected Error" } @@ -317,7 +315,7 @@ module ValueTaskModuleFunctionsTests = Assert.False(vt.IsCompletedSuccessfully) tcs.SetCanceled() task { - match! with + match! vt with | Error (:? TaskCanceledException) -> () | r -> failwithf "expected Error(TaskCanceledException) but got %A" r }