Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullness issue - Additional type hints needed in Computation Expression #17776

Open
1 of 7 tasks
marklam opened this issue Sep 21, 2024 · 2 comments
Open
1 of 7 tasks
Assignees
Labels
Area-Nullness Issues related to handling of Nullable Reference Types Bug Needs-Triage
Milestone

Comments

@marklam
Copy link

marklam commented Sep 21, 2024

Issue description

I found a couple of examples where type hints are needed inside the FsToolkit.ErrorHandling option CE with `--checknulls`` turned on.

I'm providing some example code, and comments where the type hints need to be added. This compiles without the extra hints when `--checknulls`` is not specified.

Choose one or more from the following categories of impact

  • Unexpected nullness warning (false positive in nullness checking, code uses --checknulls and langversion:preview).
  • Missing nullness warning in a case which can produce nulls (false negative, code uses --checknulls and langversion:preview).
  • Breaking change related to older null constructs in code not using the checknulls switch.
  • Breaking change related to generic code and explicit type constraints (null, not null).
  • Type inference issue (i.e. code worked without type annotations before, and applying the --checknulls enforces type annotations).
  • C#/F# interop issue related to nullness metadata.
  • Other (none of the categories above apply).

Operating System

Windows (Default)

What .NET runtime/SDK kind are you seeing the issue on

.NET SDK (.NET Core, .NET 5+)

.NET Runtime/SDK version

9.0.100-rc.1.24452.12

Reproducible code snippet and actual behavior

module Program

open FSharp.UMX
open FsToolkit.ErrorHandling

type [<Measure>] m
type [<Measure>] r

type P = | P
type S = | S

let doThing (a: float<m>) (b:float<m>) =
    ()

let x (mr : (float<m>*float<r>) option) : unit =
    option {
        // Needs annotation
        //let! (m:float<m>,r:float<r>) = mr
        let! (m, r) = mr

        let r = UMX.cast<r, m>r
        doThing r m
    }
    |> ignore

let y (s : S option ) (p : P option)=
    option {
        // Needs annotation
        //let! (_s : S) = s
        let! _s = s

        // Needs annotation
        //let! (_p : P) = p
        let! _p = p

        ()
    } |> ignore

[<EntryPoint>]
let main argv =
    0
  Nullness failed with 3 error(s) (0.9s)
    D:\Git\Temp\Nullness\Nullness\Program.fs(21,17): error FS0041: A unique overload for method 'cast' could not be determined based on type information prior to this program point. A type annotation may be needed.Known type of argument: 'aCandidates: - static member UMX.cast: x: DateTime<'m1> -> DateTime<'m2> - static member UMX.cast: x: DateTimeOffset<'m1> -> DateTimeOffset<'m2> - static member UMX.cast: x: Guid<'m1> -> Guid<'m2> - static member UMX.cast: x: TimeSpan<'m1> -> TimeSpan<'m2> - static member UMX.cast: x: bool<'m1> -> bool<'m2> - static member UMX.cast: x: byte<'m1> -> byte<'m2> - static member UMX.cast: x: decimal<'m1> -> decimal<'m2> - static member UMX.cast: x: float32<'m1> -> float32<'m2> - static member UMX.cast: x: float<'m1> -> float<'m2> - static member UMX.cast: x: int16<'m1> -> int16<'m2> - static member UMX.cast: x: int64<'m1> -> int64<'m2> - static member UMX.cast: x: int<'m1> -> int<'m2> - static member UMX.cast: x: string<'m1> -> string<'m2> - static member UMX.cast: x: uint64<'m1> -> uint64<'m2>
    D:\Git\Temp\Nullness\Nullness\Program.fs(34,9): error FS0041: A unique overload for method 'Bind' could not be determined based on type information prior to this program point. A type annotation may be needed.Known types of arguments: P option * ('a -> unit option)Candidates: - member OptionBuilder.Bind: input: 'input option * [<InlineIfLambda>] binder: ('input -> 'output option) -> 'output option - member OptionBuilder.Bind: m: 'input * [<InlineIfLambda>] binder: ('input -> 'output option) -> 'output option when 'input: null
    D:\Git\Temp\Nullness\Nullness\Program.fs(30,9): error FS0041: A unique overload for method 'Bind' could not be determined based on type information prior to this program point. A type annotation may be needed.Known types of arguments: S option * ('a -> 'b)Candidates: - member OptionBuilder.Bind: input: 'input option * [<InlineIfLambda>] binder: ('input -> 'output option) -> 'output option - member OptionBuilder.Bind: m: 'input * [<InlineIfLambda>] binder: ('input -> 'output option) -> 'output option when 'input: null

Possible workarounds

No response

@marklam marklam added Area-Nullness Issues related to handling of Nullable Reference Types Bug Needs-Triage labels Sep 21, 2024
@github-actions github-actions bot added this to the Backlog milestone Sep 21, 2024
marklam added a commit to marklam/Nullness that referenced this issue Sep 21, 2024
@marklam
Copy link
Author

marklam commented Sep 21, 2024

Added a repo with the code
https://github.com/marklam/Nullness

@T-Gro
Copy link
Member

T-Gro commented Sep 23, 2024

I will have a look.

A potential resolution, at least untill FsToolit.ErrorHandling is updated to make use of NRTs, is to offer an alternative option builder which would understand nullable reference types and offer non conflicting overloads.

The pre-nullness builder can bind either from option, or a from a type which was potentially nullable (the null generic constrain).
With NRTs and full C#-interop, option must be considered as nullable too, because None is represented as null at runtime (and what interop gets to see). Which leads to a conflict of the two overloads, because both are possible.

This is also an example where a "betterness" resolution of overloads would be good (cc @vzarytovskii - a specific option overload winning over a generic one with a constraint), F# does not have it now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Nullness Issues related to handling of Nullable Reference Types Bug Needs-Triage
Projects
Status: New
Development

No branches or pull requests

2 participants