Skip to content

Commit e512a15

Browse files
authored
perform sourceExpr translation on match-bang expressions (#9407)
* perform sourceExpr translation on match-bang expressions * add test for match-bang source translations
1 parent cce16a4 commit e512a15

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

src/fsharp/TypeChecker.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8571,6 +8571,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
85718571

85728572
// 'match! expr with pats ...' --> build.Bind(e1, (function pats ...))
85738573
| SynExpr.MatchBang (spMatch, expr, clauses, m) ->
8574+
let matchExpr = mkSourceExpr expr
85748575
let mMatch = match spMatch with DebugPointAtBinding mMatch -> mMatch | _ -> m
85758576
if isQuery then error(Error(FSComp.SR.tcMatchMayNotBeUsedWithQuery(), mMatch))
85768577

@@ -8581,7 +8582,7 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
85818582
let consumeExpr = SynExpr.MatchLambda (false, mMatch, clauses, spMatch, mMatch)
85828583

85838584
// TODO: consider allowing translation to BindReturn
8584-
Some(translatedCtxt (mkSynCall "Bind" mMatch [expr; consumeExpr]))
8585+
Some(translatedCtxt (mkSynCall "Bind" mMatch [matchExpr; consumeExpr]))
85858586

85868587
| SynExpr.TryWith (innerComp, _mTryToWith, clauses, _mWithToLast, mTryToLast, spTry, _spWith) ->
85878588
let mTry = match spTry with DebugPointAtTry.Yes m -> m | _ -> mTryToLast

tests/fsharp/Compiler/Language/ComputationExpressionTests.fs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ open FSharp.Compiler.SourceCodeServices
77
[<TestFixture>]
88
module ComputationExpressionTests =
99

10-
[<Test>]
11-
let ``do-bang can be used with nested CE expressions``() =
12-
let code = """
10+
let ``complex CE with source member and applicatives`` ceUsage =
11+
sprintf """
1312
module Code
1413
type ResultBuilder() =
1514
member __.Return value = Ok value
@@ -29,10 +28,12 @@ module Result =
2928
| Ok x1res, Ok x2res -> Ok (x1res, x2res)
3029
| Error e, _ -> Error e
3130
| _, Error e -> Error e
31+
3232
let ofChoice c =
3333
match c with
3434
| Choice1Of2 x -> Ok x
3535
| Choice2Of2 x -> Error x
36+
3637
let fold onOk onError r =
3738
match r with
3839
| Ok x -> onOk x
@@ -49,9 +50,10 @@ module Async =
4950
}
5051
5152
module AsyncResult =
52-
let zip x1 x2 =
53+
let zip x1 x2 =
5354
Async.zip x1 x2
5455
|> Async.map(fun (r1, r2) -> Result.zip r1 r2)
56+
5557
let foldResult onSuccess onError ar =
5658
Async.map (Result.fold onSuccess onError) ar
5759
@@ -101,7 +103,7 @@ type AsyncResultBuilder() =
101103
compensation: unit -> unit)
102104
: Async<Result<'T, 'TError>> =
103105
async.TryFinally(computation, compensation)
104-
106+
105107
member __.Using
106108
(resource: 'T when 'T :> System.IDisposable,
107109
binder: 'T -> Async<Result<'U, 'TError>>)
@@ -127,6 +129,7 @@ type AsyncResultBuilder() =
127129
128130
member inline _.Source(result : Async<Result<_,_>>) : Async<Result<_,_>> = result
129131
132+
[<AutoOpen>]
130133
module ARExts =
131134
type AsyncResultBuilder with
132135
/// <summary>
@@ -151,9 +154,14 @@ module ARExts =
151154
/// Method lets us transform data types into our internal representation.
152155
/// </summary>
153156
member inline __.Source(asyncComputation : Async<_>) : Async<Result<_,_>> = asyncComputation |> Async.map Ok
154-
157+
155158
let asyncResult = AsyncResultBuilder()
156159
160+
%s""" ceUsage
161+
162+
[<Test>]
163+
let ``do-bang can be used with nested CE expressions``() =
164+
let code = ``complex CE with source member and applicatives`` """
157165
asyncResult {
158166
let! something = asyncResult { return 5 }
159167
do! asyncResult {
@@ -165,4 +173,21 @@ asyncResult {
165173
|> Async.RunSynchronously
166174
|> printfn "%d"
167175
"""
168-
CompilerAssert.Pass code
176+
CompilerAssert.Pass code
177+
178+
[<Test>]
179+
let ``match-bang should apply source transformations to its inputs`` () =
180+
let code = ``complex CE with source member and applicatives`` """
181+
asyncResult {
182+
// if the source transformation is not applied, the match will not work,
183+
// because match! is only defined in terms of let!, and the only
184+
// bind overload provided takes AsyncResult as its input.
185+
match! Ok 5 with
186+
| 5 -> return "ok"
187+
| n -> return! (Error (sprintf "boo %d" n))
188+
}
189+
|> AsyncResult.foldResult id (fun (err: string) -> err)
190+
|> Async.RunSynchronously
191+
|> printfn "%s"
192+
"""
193+
CompilerAssert.Pass code

0 commit comments

Comments
 (0)