Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
* Fix signature generation: `private` keyword placement for prefix-style type abbreviations. ([Issue #15560](https://github.com/dotnet/fsharp/issues/15560), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
* Fix signature generation: missing `[<Class>]` attribute for types without visible constructors. ([Issue #16531](https://github.com/dotnet/fsharp/issues/16531), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
* Fix F# exception serialization now preserves fields (gated behind `--langversion:11`). (Issue [#878](https://github.com/dotnet/fsharp/issues/878), [PR #19342](https://github.com/dotnet/fsharp/pull/19342), [PR #19746](https://github.com/dotnet/fsharp/pull/19746))
* Fix computation expressions desugaring final-position `do!` as `return!`/`yield!`; it now uses `Bind` while explicit `return!`/`yield!` retain final methods. ([Issue #20448](https://github.com/dotnet/fsharp/issues/20448), [PR #20449](https://github.com/dotnet/fsharp/pull/20449))
* Fix methods being tagged as `Member` instead of `Method` in tooltips. ([Issue #10540](https://github.com/dotnet/fsharp/issues/10540), [PR #19507](https://github.com/dotnet/fsharp/pull/19507))
* Fix Debug-mode compilation when mixing resumable and standard computation expressions. ([Issue #19625](https://github.com/dotnet/fsharp/issues/19625), [PR #19630](https://github.com/dotnet/fsharp/pull/19630))
* IlxGen: fix missing CompilationMapping attribute for generic values ([PR #19643](https://github.com/dotnet/fsharp/pull/19643))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2878,22 +2878,6 @@ and TranslateComputationExpression (ceenv: ComputationExpressionContext<'a>) fir
| None ->
// This only occurs in final position in a sequence
match comp with
// "do! expr;" in tail call position is treated as { return! expr } when ReturnFromFinal is provided
| SynExpr.DoBang(rhsExpr, m, _) when ceenv.tailCall && (hasBuilderMethod ceenv m "ReturnFromFinal") ->
let returnFrom =
// Flags indicate isTrueYield, isTrueReturn
SynExpr.YieldOrReturnFrom((false, true), rhsExpr, m, SynExprYieldOrReturnFromTrivia.Zero)

TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace returnFrom translatedCtxt

// "do! expr;" in tail call position is treated as { yield! expr } when YieldFromFinal is provided
| SynExpr.DoBang(rhsExpr, m, _) when ceenv.tailCall && (hasBuilderMethod ceenv m "YieldFromFinal") ->
let returnFrom =
// Flags indicate isTrueYield, isTrueReturn
SynExpr.YieldOrReturnFrom((true, false), rhsExpr, m, SynExprYieldOrReturnFromTrivia.Zero)

TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace returnFrom translatedCtxt

// "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided (and no Zero with Default attribute is available) or as { let! () = expr in zero } otherwise
| SynExpr.DoBang(expr = rhsExpr; trivia = { DoBangKeyword = m }) ->
let mUnit = rhsExpr.Range
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,6 @@ let testTailcallTiny () =

testTailcallTiny() |> expect 2 0

let testTailcallTinyDoBang () =
coroutine {
printfn "in testTailcallTinyDoBang, desugaring do!"
do! t1() // this should desugr to YieldFromFinal, because ReturnFromFinal is not provided.
}

testTailcallTinyDoBang() |> expect 2 0

let rec testTailcall (n: int) =
coroutine {
if n % 10_000 = 0 then printfn $"in testTailcall, n = {n}"
Expand Down Expand Up @@ -431,4 +423,3 @@ let testHandlerNonTailCall () =

testHandlerNonTailCall () |> expect 0 2


25 changes: 23 additions & 2 deletions tests/FSharp.Compiler.ComponentTests/Language/tailcalls.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ do


do
let sync = SyncBuilder (expect ReturnFromFinal)
let sync = SyncBuilder expectNone

sync {
printf "expect ReturnFromFinal: "
printf "expectNone: "
do! sync { printfn "inner" }
} |> run

Expand Down Expand Up @@ -154,6 +154,27 @@ do
shouldEqual b.YieldFromCount 1
shouldEqual b.YieldFromFinalCount 0

// do! in final position should use Bind rather than a final YieldFrom method.
type DoBangBuilder() =
member _.Bind(_: System.Threading.Tasks.Task, continuation: unit -> int list) = continuation()
member _.Yield(value: int) = [ value ]
member _.YieldFrom(_: int list) = []
member _.YieldFromFinal(_: int list) = []
member _.Return(_: unit) = []
member _.Combine(first: int list, second: unit -> int list) = first @ second ()
member _.Delay(computation: unit -> int list) = computation
member _.Run(computation: unit -> int list) = computation ()

do
let builder = DoBangBuilder()
let result =
builder {
yield 1
do! System.Threading.Tasks.Task.CompletedTask
}

shouldEqual result [ 1 ]

// yield! in try/finally body → YieldFrom (not tail), result correct
do
let b = ListBuilder()
Expand Down
Loading