66from typing import Any , cast
77
88from .array_ import Array
9- from .core import FSharpRef , int32
9+ from .core import FSharpRef , int32 , option
1010from .record import Record
1111from .types import IntegerTypes
12- from .union import Union
1312from .union import Union as FsUnion
1413from .util import combine_hash_codes , equal_arrays_with
1514
@@ -111,7 +110,12 @@ def anon_record_type(*fields: FieldInfo) -> TypeInfo:
111110
112111
113112def option_type (generic : TypeInfo ) -> TypeInfo :
114- return TypeInfo ("Microsoft.FSharp.Core.FSharpOption`1" , Array ([generic ]))
113+ t = TypeInfo ("Microsoft.FSharp.Core.FSharpOption`1" , Array ([generic ]))
114+ t .cases = lambda : [
115+ CaseInfo (t , 0 , "None" , []),
116+ CaseInfo (t , 1 , "Some" , [("value" , generic )]),
117+ ]
118+ return t
115119
116120
117121def list_type (generic : TypeInfo ) -> TypeInfo :
@@ -427,6 +431,10 @@ def make_union(uci: CaseInfo, values: Array[Any]) -> Any:
427431 if len (values ) != expectedLength :
428432 raise ValueError (f"Expected an array of length { expectedLength } but got { len (values )} " )
429433
434+ # Options are erased at runtime: None -> None, Some(x) -> x or SomeWrapper
435+ if uci .declaringType .fullname == "Microsoft.FSharp.Core.FSharpOption`1" :
436+ return None if uci .tag == 0 else option .some (values [0 ])
437+
430438 # Use case constructor if available (new tagged_union pattern)
431439 if uci .case_constructor is not None :
432440 return uci .case_constructor (* values )
@@ -442,8 +450,16 @@ def get_union_cases(t: TypeInfo) -> Array[CaseInfo]:
442450 raise ValueError (f"{ t .fullname } is not an F# union type" )
443451
444452
445- def get_union_fields (v : Union , t : TypeInfo ) -> tuple [CaseInfo , Array [Any ]]:
453+ # `v` is `Any` because option values are erased at runtime (None / raw value /
454+ # SomeWrapper) and don't share a base class with `Union`.
455+ def get_union_fields (v : Any , t : TypeInfo ) -> tuple [CaseInfo , Array [Any ]]:
446456 cases : Array [CaseInfo ] = get_union_cases (t )
457+ # Options are erased at runtime: None -> None, Some(x) -> x or SomeWrapper
458+ if t .fullname == "Microsoft.FSharp.Core.FSharpOption`1" :
459+ if v is None :
460+ return (cases [0 ], Array [Any ]([]))
461+ inner = v .value if isinstance (v , option .SomeWrapper ) else v
462+ return (cases [1 ], Array [Any ]([inner ]))
447463 case : CaseInfo = cases [v .tag ]
448464
449465 return (case , Array [Any ](v .fields ))
0 commit comments