Type inference on task state machine could be improved
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 22h
- Merged PRs (30d)
- 144
Description
Consider this F# file (self-contained for convenience, originally taken [from this snippet](https://github.com/codingteam/emulsion/blob/3a3b9c9c776aeab422d90758b0a862803df9d3e3/Emulsion.Web/ContentController.fs#L32-L64) of an ASP.NET Core app).
Target is `net7.0`, it can be compiled using .NET SDK 7.
```fsharp
open System.Threading.Tasks
type IActionResult =
abstract member Stub: unit -> unit
type ActionResult() =
interface IActionResult with
member _.Stub() = ()
type StatusCodeResult() =
inherit ActionResult()
type BadRequestResult() =
inherit StatusCodeResult()
type NotFoundResult() =
inherit StatusCodeResult()
type UnprocessableEntityResult() =
inherit StatusCodeResult()
type FileResult() =
inherit ActionResult()
type RedirectResult() =
inherit StatusCodeResult()
type FileStreamResult() =
inherit FileResult()
type ControllerBase() =
member _.BadRequest(): BadRequestResult =
failwith ""
member _.NotFound(): NotFoundResult =
failwith ""
type TestClass() =
inherit ControllerBase()
member this.Task(): Task = task {
match Some "xxx" with
| None ->
return this.BadRequest()
| Some contentId ->
match! Task.FromResult(Some 123) with
| None ->
return this.NotFound() :> IActionResult
| Some content ->
match Some "xx" with
| None ->
match "xxx" with
| "" -> return UnprocessableEntityResult()
| _ ->
return RedirectResult()
| Some cache ->
match! Task.FromResult(Some "xx") with
| None ->
return this.NotFound() :> IActionResult
| Some fileInfo ->
match! Task.FromResult(Some 1) with
| None ->
return this.NotFound() :> IActionResult
| Some stream ->
match "aa" with
| "application/octet-stream" -> return FileStreamResult()
| _ -> return FileStreamResult()
}
```
In this snippet, every `:> IActionResult` is required; the code refuses to compile without them.
Using `` though, it could be as well compiled without these explicit casts:
```fsharp
open System.Threading.Tasks
open FSharp.Control.Tasks
type IActionResult =
abstract member Stub: unit -> unit
type ActionResult() =
interface IActionResult with
member _.Stub() = ()
type StatusCodeResult() =
inherit ActionResult()
type BadRequestResult() =
inherit StatusCodeResult()
type NotFoundResult() =
inherit StatusCodeResult()
type UnprocessableEntityResult() =
inherit StatusCodeResult()
type FileResult() =
inherit ActionResult()
type RedirectResult() =
inherit StatusCodeResult()
type FileStreamResult() =
inherit FileResult()
type ControllerBase() =
member _.BadRequest(): BadRequestResult =
failwith ""
member _.NotFound(): NotFoundResult =
failwith ""
type TestClass() =
inherit ControllerBase()
member this.Task(): Task = task {
match Some "xxx" with
| None ->
return this.BadRequest()
| Some contentId ->
match! Task.FromResult(Some 123) with
| None ->
return this.NotFound()
| Some content ->
match Some "xx" with
| None ->
match "xxx" with
| "" -> return UnprocessableEntityResult()
| _ ->
return RedirectResult()
| Some cache ->
match! Task.FromResult(Some "xx") with
| None ->
return this.NotFound()
| Some fileInfo ->
match! Task.FromResult(Some 1) with
| None ->
return this.NotFound()
| Some stream ->
match "aa" with
| "application/octet-stream" -> return FileStreamResult()
| _ -> return FileStreamResult()
}
```
I believe that this is something that could be improved in the compiler or in the default `task` builder implementation.
Contributor guide
Assessment
This issue has not been assessed yet.