dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.94k stars 788 forks source link

More permissive cast-matching in `function | ...` expressions #17882

Open Smaug123 opened 1 month ago

Smaug123 commented 1 month ago

Is your feature request related to a problem? Please describe.

type Foo =
    inherit IDisposable

let blah () =
    ([] : Foo list)
    |> Seq.iter (function | :? IDisposable as x -> ())

This fails with a rather amusing combination of two errors:

The error messages are telling me that the match is incomplete and complete at the same time!

Describe the solution you'd like

Accept the definition. It's presumably semantically equivalent to:

let blah () =
    ([] : Foo list)
    |> Seq.iter (fun (x : IDisposable) -> ())

Describe alternatives you've considered

Just don't do this. Users can always do an explicit type annotation, and the code is even shorter! The failure mode just amused me.

This is super low priority, of course.

brianrourkeboll commented 1 month ago

I think this probably has to do with :? in patterns more generally, not just function.

You can repro the same contradictory warnings with

open System

type Foo =
    inherit IDisposable

let foo ((_ : Foo) & (:? IDisposable)) = ();;
  let foo ((_ : Foo) & (:? IDisposable)) = ();;
  ----------------------^^^^^^^^^^^^^^

stdin(6,23): warning FS0067: This type test or downcast will always hold

  let foo ((_ : Foo) & (:? IDisposable)) = ();;
  ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(6,10): warning FS0025: Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).

These, on the other hand, trigger no warnings:

let blah () =
    ([] : Foo list)
    |> Seq.iter (function (x : #IDisposable) -> ())
let blah () =
    ([] : Foo list)
    |> Seq.iter (fun (x : #IDisposable) -> ())