1+ namespace FSharp.Compiler.UnitTests
2+
3+ open NUnit.Framework
4+ open FSharp.TestHelpers
5+ open FSharp.Compiler .SourceCodeServices
6+
7+ [<TestFixture>]
8+ module ComputationExpressionTests =
9+
10+ [<Test>]
11+ let ``do - bang can be used with nested CE expressions`` () =
12+ let code = """
13+ module Code
14+ type ResultBuilder() =
15+ member __.Return value = Ok value
16+ member __.ReturnFrom (result: Result<_,_>) = result
17+ member x.Zero() = x.Return ()
18+ member __.Bind(r: Result<'t,_>, binder: 't -> Result<_,_>) = match r with | Ok r' -> binder r' | Error e -> e
19+ member __.Delay(gen: unit -> Result<_,_>) = gen
20+ member __.Run(gen: unit -> Result<_,_>) = gen()
21+ member _.BindReturn(x: Result<'t,_>, f) = Result.map f x
22+ member inline _.Source(result : Result<_,_>) : Result<_,_> = result
23+
24+ let result = ResultBuilder()
25+
26+ module Result =
27+ let zip x1 x2 =
28+ match x1,x2 with
29+ | Ok x1res, Ok x2res -> Ok (x1res, x2res)
30+ | Error e, _ -> Error e
31+ | _, Error e -> Error e
32+ let ofChoice c =
33+ match c with
34+ | Choice1Of2 x -> Ok x
35+ | Choice2Of2 x -> Error x
36+ let fold onOk onError r =
37+ match r with
38+ | Ok x -> onOk x
39+ | Error y -> onError y
40+
41+ module Async =
42+ let inline singleton value = value |> async.Return
43+ let inline bind f x = async.Bind(x, f)
44+ let inline map f x = x |> bind (f >> singleton)
45+ let zip a1 a2 = async {
46+ let! r1 = a1
47+ let! r2 = a2
48+ return r1,r2
49+ }
50+
51+ module AsyncResult =
52+ let zip x1 x2 =
53+ Async.zip x1 x2
54+ |> Async.map(fun (r1, r2) -> Result.zip r1 r2)
55+ let foldResult onSuccess onError ar =
56+ Async.map (Result.fold onSuccess onError) ar
57+
58+ type AsyncResultBuilder() =
59+
60+ member __.Return (value: 'T) : Async<Result<'T, 'TError>> =
61+ async.Return <| result.Return value
62+
63+ member inline __.ReturnFrom
64+ (asyncResult: Async<Result<'T, 'TError>>)
65+ : Async<Result<'T, 'TError>> =
66+ asyncResult
67+
68+ member __.Zero () : Async<Result<unit, 'TError>> =
69+ async.Return <| result.Zero ()
70+
71+ member inline __.Bind
72+ (asyncResult: Async<Result<'T, 'TError>>,
73+ binder: 'T -> Async<Result<'U, 'TError>>)
74+ : Async<Result<'U, 'TError>> =
75+ async {
76+ let! result = asyncResult
77+ match result with
78+ | Ok x -> return! binder x
79+ | Error x -> return Error x
80+ }
81+
82+ member __.Delay
83+ (generator: unit -> Async<Result<'T, 'TError>>)
84+ : Async<Result<'T, 'TError>> =
85+ async.Delay generator
86+
87+ member this.Combine
88+ (computation1: Async<Result<unit, 'TError>>,
89+ computation2: Async<Result<'U, 'TError>>)
90+ : Async<Result<'U, 'TError>> =
91+ this.Bind(computation1, fun () -> computation2)
92+
93+ member __.TryWith
94+ (computation: Async<Result<'T, 'TError>>,
95+ handler: System.Exception -> Async<Result<'T, 'TError>>)
96+ : Async<Result<'T, 'TError>> =
97+ async.TryWith(computation, handler)
98+
99+ member __.TryFinally
100+ (computation: Async<Result<'T, 'TError>>,
101+ compensation: unit -> unit)
102+ : Async<Result<'T, 'TError>> =
103+ async.TryFinally(computation, compensation)
104+
105+ member __.Using
106+ (resource: 'T when 'T :> System.IDisposable,
107+ binder: 'T -> Async<Result<'U, 'TError>>)
108+ : Async<Result<'U, 'TError>> =
109+ async.Using(resource, binder)
110+
111+ member this.While
112+ (guard: unit -> bool, computation: Async<Result<unit, 'TError>>)
113+ : Async<Result<unit, 'TError>> =
114+ if not <| guard () then this.Zero ()
115+ else this.Bind(computation, fun () -> this.While (guard, computation))
116+
117+ member this.For
118+ (sequence: #seq<'T>, binder: 'T -> Async<Result<unit, 'TError>>)
119+ : Async<Result<unit, 'TError>> =
120+ this.Using(sequence.GetEnumerator (), fun enum ->
121+ this.While(enum.MoveNext,
122+ this.Delay(fun () -> binder enum.Current)))
123+
124+ member inline __.BindReturn(x: Async<Result<'T,'U>>, f) = async.Bind(x, fun r -> Result.map f r |> async.Return)
125+ member inline __.MergeSources(t1: Async<Result<'T,'U>>, t2: Async<Result<'T1,'U>>) =
126+ AsyncResult.zip t1 t2
127+
128+ member inline _.Source(result : Async<Result<_,_>>) : Async<Result<_,_>> = result
129+
130+ module ARExts =
131+ type AsyncResultBuilder with
132+ /// <summary>
133+ /// Needed to allow `for..in` and `for..do` functionality
134+ /// </summary>
135+ member inline __.Source(s: #seq<_>) = s
136+
137+ /// <summary>
138+ /// Method lets us transform data types into our internal representation.
139+ /// </summary>
140+ member inline _.Source(result : Result<_,_>) : Async<Result<_,_>> = Async.singleton result
141+
142+ /// <summary>
143+ /// Method lets us transform data types into our internal representation.
144+ /// </summary>
145+ member inline _.Source(choice : Choice<_,_>) : Async<Result<_,_>> =
146+ choice
147+ |> Result.ofChoice
148+ |> Async.singleton
149+
150+ /// <summary>
151+ /// Method lets us transform data types into our internal representation.
152+ /// </summary>
153+ member inline __.Source(asyncComputation : Async<_>) : Async<Result<_,_>> = asyncComputation |> Async.map Ok
154+
155+ let asyncResult = AsyncResultBuilder()
156+
157+ asyncResult {
158+ let! something = asyncResult { return 5 }
159+ do! asyncResult {
160+ return ()
161+ }
162+ return something
163+ }
164+ |> AsyncResult.foldResult id (fun (_err: string) -> 10)
165+ |> Async.RunSynchronously
166+ |> printfn "%d "
167+ """
168+ CompilerAssert.Pass code
0 commit comments