fsharp
fsharp copied to clipboard
Mutually recursive non-function values with intermediate module definition not initialized incorrectly
Repro steps
Consider the following code:
type Node =
{
Next: Node
Prev: Node
Value: int
}
let rec one =
{
Next = two
Prev = two
Value = 1
}
and two =
{
Next = one
Prev = one
Value = 2
}
printfn "%A" one
printfn "%A" two
Expected behavior
Either:
- Correctly initialize the mutually recursive values.
- Reject the code as being invalid.
Actual behavior
The code compiles with no warnings/errors. two
is initialized correctly, but one.Next
and one.Prev
are both null
:
{ Next = null
Prev = null
Value = 1 }
{ Next = { Next = null
Prev = null
Value = 1 }
Prev = { Next = null
Prev = null
Value = 1 }
Value = 2 }
Known workarounds
None
Related information
Decompiled C# code with incorrect initialization.
Note that a single self-referencing value is actually initialized correctly:
let rec zero =
{
Next = zero
Prev = zero
Value = 0
}
Ugh, thanks for the bug report. We have an extensive systematic test suite somewhere for almost exactly this case and I can't quite believe this one slipped through, but eveidently it did. I'll get it fixed. I'm impressed you found this.
There is one case not fixed by #12395. I'll leave this open to track this, though won't immediately seek to fix it
module rec Test12384d =
type Node =
{
Next: Node
Value: int
}
let one =
{
Next = two
Value = 1
}
module M =
let x() = one
let two =
{
Next = one
Value = 2
}
I tried this
type Parent = {
Name : string
Age : int
Children : Child list }
and Child = {
Name : string
Parent : Parent }
let createParent name children =
{ Name = name
Age = 42
Children = children }
let createChild name parent =
{ Name = name
Parent = parent }
let create name kids =
let rec makeChild name = createChild name parent
and makeParent name = createParent name children
and parent = name |> makeParent
and children = kids |> List.map makeChild
parent
create "Peter" [ "Sarah"; "Max" ]
|> printfn "%A"
and i get "Children" printed as "null"
am i doing something wrong or is this bug really still open?