Tarmil / FSharp.SystemTextJson

System.Text.Json extensions for F# types
MIT License
323 stars 44 forks source link

Never ending recursion when trying to handle recursive discriminated unions. #147

Open gdar91 opened 1 year ago

gdar91 commented 1 year ago

There is a problem when it tries to process a discriminated union. If you have a union type parametrized by another Never-like union (type Never = Never of Never) the function responsible for calculating the null value - System.Text.Json.Serialization.Helpers.tryGetNullValue - enters into infinite recursion. Maybe it needs to keep track of visited types and do an early exit.

Exception:

...
   at System.Text.Json.Serialization.Helpers.tryGetNullValue(System.Text.Json.Serialization.JsonFSharpOptions, System.Type)
   at System.Text.Json.Serialization.Helpers.tryGetNullValue(System.Text.Json.Serialization.JsonFSharpOptions, System.Type)
...
...
...
   at System.Text.Json.Serialization.Helpers.tryGetNullValue(System.Text.Json.Serialization.JsonFSharpOptions, System.Type)
   at System.Text.Json.Serialization.Helpers.tryGetNullValue(System.Text.Json.Serialization.JsonFSharpOptions, System.Type)
   at <StartupCode$FSharp-SystemTextJson>.$Union.mapping@1-2[[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Text.Json.JsonSerializerOptions, System.Text.Json.Serialization.JsonUnionConverter`1<System.__Canon>, System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.Text.Json.Serialization.JsonName[]>, System.Collections.Generic.Dictionary`2<System.String,Int32>, System.Reflection.PropertyInfo, System.String, Int32)
   at <StartupCode$FSharp-SystemTextJson>.$Union.mapping@1-1[[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.Collections.Generic.IDictionary`2<System.Type,System.Text.Json.Serialization.JsonFSharpOptions>, System.Text.Json.JsonSerializerOptions, System.Text.Json.Serialization.JsonUnionConverter`1<System.__Canon>, Microsoft.FSharp.Reflection.UnionCaseInfo)
...

The code to reproduce the error:

open System.Text.Json
open System.Text.Json.Serialization

type Never = Never of Never

type MyChoice = MyChoice of Choice<int, Never>

let myChoice = MyChoice (Choice1Of2 10)

let options = JsonSerializerOptions ()

options.Converters.Add (JsonFSharpConverter ())

let json = JsonSerializer.Serialize (myChoice, options)

printfn "%s" json