From 5852b4e987ab8241bdd291e457175ef402f453a8 Mon Sep 17 00:00:00 2001 From: Mangel Maxime Date: Fri, 18 Sep 2026 17:12:41 +0200 Subject: [PATCH] fix(python): keep the payload type when reading an erased union field --- src/Fable.Transforms/FSharp2Fable.fs | 7 +++++-- tests/Beam/InteropTests.fs | 20 ++++++++++++++++++++ tests/Js/Main/UnionTypeTests.fs | 15 +++++++++++++++ tests/Python/TestUnionType.fs | 16 ++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/Fable.Transforms/FSharp2Fable.fs b/src/Fable.Transforms/FSharp2Fable.fs index ddbabedd80..db18d095fb 100644 --- a/src/Fable.Transforms/FSharp2Fable.fs +++ b/src/Fable.Transforms/FSharp2Fable.fs @@ -1316,10 +1316,13 @@ let private transformExpr (com: IFableCompiler) (ctx: Context) appliedGenArgs fs | ErasedUnionCase -> let index = unionCase.Fields |> Seq.findIndex (fun x -> x.Name = field.Name) - return Fable.Get(unionExpr, Fable.TupleIndex(index), makeType ctx.GenericArgs unionType, r) + return Fable.Get(unionExpr, Fable.TupleIndex(index), fieldType, r) | ErasedUnion _ -> if unionCase.Fields.Count = 1 then - return unionExpr + if unionExpr.Type = fieldType then + return unionExpr + else + return Fable.TypeCast(unionExpr, fieldType) else let index = unionCase.Fields |> Seq.findIndex (fun x -> x.Name = field.Name) diff --git a/tests/Beam/InteropTests.fs b/tests/Beam/InteropTests.fs index 7c4ac25c19..1c0d4282bf 100644 --- a/tests/Beam/InteropTests.fs +++ b/tests/Beam/InteropTests.fs @@ -104,6 +104,13 @@ type ErasedUnion = type ErasedUnionWithMultipleFields = | ErasedUnionWithMultipleFields of string * int +type ErasedPayload = { Description: string; Membership: int } + +[] +type ErasedWrapper = + | ErasedSuccess of ErasedPayload + | ErasedFailure of string + // ============================================================ // StringEnum tests // ============================================================ @@ -408,6 +415,19 @@ let ``test Erased types can have members`` () = () #endif +[] +let ``test Erased union payload fields can be read`` () = +#if FABLE_COMPILER + let payload = { Description = "a"; Membership = 2 } + + match ErasedSuccess payload with + | ErasedSuccess details -> details.Membership + | ErasedFailure _ -> -1 + |> equal 2 +#else + () +#endif + [] let ``test Erased unions with multiple fields work`` () = #if FABLE_COMPILER diff --git a/tests/Js/Main/UnionTypeTests.fs b/tests/Js/Main/UnionTypeTests.fs index 3d714753b4..3c6a311449 100644 --- a/tests/Js/Main/UnionTypeTests.fs +++ b/tests/Js/Main/UnionTypeTests.fs @@ -81,6 +81,13 @@ open Fable.Core.JsInterop #endif type DU = Int of int | Str of string +type ErasedPayload = { Description: string; Membership: int } + +[] +type ErasedWrapper = + | ErasedSuccess of ErasedPayload + | ErasedFailure of string + type T1 = T1 type T2 = T2 type T3 = T3 @@ -213,6 +220,14 @@ let tests = "HELLO" |> Wrapper |> U3.Case3 |> toString |> equal "OLLEH" #endif + testCase "Erased union payload fields can be read" <| fun () -> + let payload = { Description = "a"; Membership = 2 } + + match ErasedSuccess payload with + | ErasedSuccess details -> details.Membership + | ErasedFailure _ -> -1 + |> equal 2 + testCase "Equality works in filter" <| fun () -> let original = [| { Name = "1"; Case = MyUnion.Case1 } ; { Name = "2"; Case = MyUnion.Case1 }; { Name = "3"; Case = MyUnion.Case2 }; { Name = "4"; Case = MyUnion.Case3 } |] original diff --git a/tests/Python/TestUnionType.fs b/tests/Python/TestUnionType.fs index f9b3d3f7bc..a9775b681c 100644 --- a/tests/Python/TestUnionType.fs +++ b/tests/Python/TestUnionType.fs @@ -82,6 +82,13 @@ open Fable.Core #endif type DU = Int of int | Str of string +type ErasedPayload = { Description: string; Membership: int } + +[] +type ErasedWrapper = + | ErasedSuccess of ErasedPayload + | ErasedFailure of string + [] let ``test Union cases matches with no arguments can be generated`` () = let x = Male @@ -200,6 +207,15 @@ let ``test Erased union type testing works`` () = "HELLO" |> Wrapper |> U3.Case3 |> toString |> equal "OLLEH" #endif +[] +let ``test Erased union payload fields can be read`` () = + let payload = { Description = "a"; Membership = 2 } + + match ErasedSuccess payload with + | ErasedSuccess details -> details.Membership + | ErasedFailure _ -> -1 + |> equal 2 + [] let ``test Equality works in filter`` () = let original = [| { Name = "1"; Case = MyUnion3.Case1 } ; { Name = "2"; Case = MyUnion3.Case1 }; { Name = "3"; Case = MyUnion3.Case2 }; { Name = "4"; Case = MyUnion3.Case3 } |]