fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

NullReferenceException with Debug build and recursive reference

Open glchapman opened this issue 7 months ago • 1 comments

I'm using dotnet 8.0.101 with Windows 10. The program below, when run in Debug mode, will throw a NullReferenceException. If run in Release mode, it completes successfully. Both versions generate a warning about the reference to parse in paramParse (in Type.parse) needing a runtime check; I believe it is that reference to parse which is null in the Debug build.

type Ident = string

type Type =
    | TPrim of Ident
    | TParam of Ident * Type

let tryParam pv x =
    match x with
    | TParam (name, typ) ->
        pv typ |> Result.map (fun t -> [name, t])
    | _ -> Error "unexpected"

let tryPrim = function
    | TPrim name -> Ok name
    | _ -> Error "unused"

module Type =
    let parse =
        let rec paramParse = tryParam parse
        and parse node =
            match tryPrim node with
            | Ok name -> Ok(TPrim name)
            | _ ->
                match paramParse node with
                | Ok [name, typ] -> Ok(TParam(name,typ))
                | _ -> Error "invalid type"
        parse

[<EntryPoint>]
let main args =
    printfn "%A" (Type.parse (TParam ("ptr", TPrim "float")))
    0

The workaround is to reorder parse and paramParse; this gets rid of the warning and allows both Debug and Release to succeed. E.g.:

module Type =
    let parse =
        let rec  parse node =
            match tryPrim node with
            | Ok name -> Ok(TPrim name)
            | _ ->
                match paramParse node with
                | Ok [name, typ] -> Ok(TParam(name,typ))
                | _ -> Error "invalid type"
        and paramParse = tryParam parse
        parse

glchapman avatar Jan 17 '24 21:01 glchapman

You can also follow the advice in the error message and make parseParam a recursive function instead of a recursive object: let rec paramParse n = tryParam parse n. The code then runs in both debug and release configuration, and you don't get the warning.

Martin521 avatar Jan 18 '24 09:01 Martin521