From 77c3f6092198379270b3d17cd61958a46145d0a2 Mon Sep 17 00:00:00 2001 From: cabboose Date: Sat, 21 Jun 2025 08:55:49 +0800 Subject: [PATCH 1/2] Add inline `op_Implicit` methods for erased union types --- src/Fable.Core/Fable.Core.Types.fs | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/Fable.Core/Fable.Core.Types.fs b/src/Fable.Core/Fable.Core.Types.fs index 1641884a0..f5af02806 100644 --- a/src/Fable.Core/Fable.Core.Types.fs +++ b/src/Fable.Core/Fable.Core.Types.fs @@ -134,6 +134,8 @@ type U2<'a, 'b> = static member op_ErasedCast(x: 'a) = Case1 x static member op_ErasedCast(x: 'b) = Case2 x + static member inline op_Implicit(x: 'a) : U2<'a, 'b> = Case1 x + static member inline op_Implicit(x: 'b) : U2<'a, 'b> = Case2 x /// Erased union type to represent one of three possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -146,6 +148,9 @@ type U3<'a, 'b, 'c> = static member op_ErasedCast(x: 'a) = Case1 x static member op_ErasedCast(x: 'b) = Case2 x static member op_ErasedCast(x: 'c) = Case3 x + static member inline op_Implicit(x: 'a) : U3<'a, 'b, 'c> = Case1 x + static member inline op_Implicit(x: 'b) : U3<'a, 'b, 'c> = Case2 x + static member inline op_Implicit(x: 'c) : U3<'a, 'b, 'c> = Case3 x /// Erased union type to represent one of four possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -160,6 +165,10 @@ type U4<'a, 'b, 'c, 'd> = static member op_ErasedCast(x: 'b) = Case2 x static member op_ErasedCast(x: 'c) = Case3 x static member op_ErasedCast(x: 'd) = Case4 x + static member inline op_Implicit(x: 'a) : U4<'a, 'b, 'c, 'd> = Case1 x + static member inline op_Implicit(x: 'b) : U4<'a, 'b, 'c, 'd> = Case2 x + static member inline op_Implicit(x: 'c) : U4<'a, 'b, 'c, 'd> = Case3 x + static member inline op_Implicit(x: 'd) : U4<'a, 'b, 'c, 'd> = Case4 x /// Erased union type to represent one of five possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -176,6 +185,11 @@ type U5<'a, 'b, 'c, 'd, 'e> = static member op_ErasedCast(x: 'c) = Case3 x static member op_ErasedCast(x: 'd) = Case4 x static member op_ErasedCast(x: 'e) = Case5 x + static member inline op_Implicit(x: 'a) : U5<'a, 'b, 'c, 'd, 'e> = Case1 x + static member inline op_Implicit(x: 'b) : U5<'a, 'b, 'c, 'd, 'e> = Case2 x + static member inline op_Implicit(x: 'c) : U5<'a, 'b, 'c, 'd, 'e> = Case3 x + static member inline op_Implicit(x: 'd) : U5<'a, 'b, 'c, 'd, 'e> = Case4 x + static member inline op_Implicit(x: 'e) : U5<'a, 'b, 'c, 'd, 'e> = Case5 x /// Erased union type to represent one of six possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -194,6 +208,12 @@ type U6<'a, 'b, 'c, 'd, 'e, 'f> = static member op_ErasedCast(x: 'd) = Case4 x static member op_ErasedCast(x: 'e) = Case5 x static member op_ErasedCast(x: 'f) = Case6 x + static member inline op_Implicit(x: 'a) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case1 x + static member inline op_Implicit(x: 'b) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case2 x + static member inline op_Implicit(x: 'c) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case3 x + static member inline op_Implicit(x: 'd) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case4 x + static member inline op_Implicit(x: 'e) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case5 x + static member inline op_Implicit(x: 'f) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case6 x /// Erased union type to represent one of seven possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -214,6 +234,13 @@ type U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = static member op_ErasedCast(x: 'e) = Case5 x static member op_ErasedCast(x: 'f) = Case6 x static member op_ErasedCast(x: 'g) = Case7 x + static member inline op_Implicit(x: 'a) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case1 x + static member inline op_Implicit(x: 'b) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case2 x + static member inline op_Implicit(x: 'c) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case3 x + static member inline op_Implicit(x: 'd) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case4 x + static member inline op_Implicit(x: 'e) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case5 x + static member inline op_Implicit(x: 'f) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case6 x + static member inline op_Implicit(x: 'g) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case7 x /// Erased union type to represent one of eight possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -236,6 +263,14 @@ type U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = static member op_ErasedCast(x: 'f) = Case6 x static member op_ErasedCast(x: 'g) = Case7 x static member op_ErasedCast(x: 'h) = Case8 x + static member inline op_Implicit(x: 'a) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case1 x + static member inline op_Implicit(x: 'b) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case2 x + static member inline op_Implicit(x: 'c) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case3 x + static member inline op_Implicit(x: 'd) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case4 x + static member inline op_Implicit(x: 'e) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case5 x + static member inline op_Implicit(x: 'f) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case6 x + static member inline op_Implicit(x: 'g) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case7 x + static member inline op_Implicit(x: 'h) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case8 x /// Erased union type to represent one of nine or more possible values. /// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute @@ -260,6 +295,15 @@ type U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = static member op_ErasedCast(x: 'g) = Case7 x static member op_ErasedCast(x: 'h) = Case8 x static member op_ErasedCast(x: 'i) = Case9 x + static member inline op_Implicit(x: 'a) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case1 x + static member inline op_Implicit(x: 'b) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case2 x + static member inline op_Implicit(x: 'c) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case3 x + static member inline op_Implicit(x: 'd) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case4 x + static member inline op_Implicit(x: 'e) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case5 x + static member inline op_Implicit(x: 'f) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case6 x + static member inline op_Implicit(x: 'g) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case7 x + static member inline op_Implicit(x: 'h) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case8 x + static member inline op_Implicit(x: 'i) : U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = Case9 x static member inline op_ErasedCast(x: 't) : U9<_, _, _, _, _, _, _, _, ^U> = Case9(^U: (static member op_ErasedCast: 't -> ^U) x) From 5626ef43a9c2cc2582e0e95e6eaa7263c925df7e Mon Sep 17 00:00:00 2001 From: cabboose Date: Mon, 23 Jun 2025 17:55:09 +0800 Subject: [PATCH 2/2] DOCS: Added xml docs for erased unions --- src/Fable.Core/Fable.Core.Types.fs | 193 ++++++++++++++++++++++++++--- 1 file changed, 177 insertions(+), 16 deletions(-) diff --git a/src/Fable.Core/Fable.Core.Types.fs b/src/Fable.Core/Fable.Core.Types.fs index f5af02806..5ea2bb33e 100644 --- a/src/Fable.Core/Fable.Core.Types.fs +++ b/src/Fable.Core/Fable.Core.Types.fs @@ -125,8 +125,28 @@ type NamedParamsAttribute = ParamObjectAttribute type InjectAttribute() = inherit Attribute() -/// Erased union type to represent one of two possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of two possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U2<'a, 'b> = | Case1 of 'a @@ -137,8 +157,29 @@ type U2<'a, 'b> = static member inline op_Implicit(x: 'a) : U2<'a, 'b> = Case1 x static member inline op_Implicit(x: 'b) : U2<'a, 'b> = Case2 x -/// Erased union type to represent one of three possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of three possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// + [] type U3<'a, 'b, 'c> = | Case1 of 'a @@ -152,8 +193,28 @@ type U3<'a, 'b, 'c> = static member inline op_Implicit(x: 'b) : U3<'a, 'b, 'c> = Case2 x static member inline op_Implicit(x: 'c) : U3<'a, 'b, 'c> = Case3 x -/// Erased union type to represent one of four possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of four possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U4<'a, 'b, 'c, 'd> = | Case1 of 'a @@ -170,8 +231,28 @@ type U4<'a, 'b, 'c, 'd> = static member inline op_Implicit(x: 'c) : U4<'a, 'b, 'c, 'd> = Case3 x static member inline op_Implicit(x: 'd) : U4<'a, 'b, 'c, 'd> = Case4 x -/// Erased union type to represent one of five possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of five possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U5<'a, 'b, 'c, 'd, 'e> = | Case1 of 'a @@ -191,8 +272,28 @@ type U5<'a, 'b, 'c, 'd, 'e> = static member inline op_Implicit(x: 'd) : U5<'a, 'b, 'c, 'd, 'e> = Case4 x static member inline op_Implicit(x: 'e) : U5<'a, 'b, 'c, 'd, 'e> = Case5 x -/// Erased union type to represent one of six possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of six possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U6<'a, 'b, 'c, 'd, 'e, 'f> = | Case1 of 'a @@ -215,8 +316,28 @@ type U6<'a, 'b, 'c, 'd, 'e, 'f> = static member inline op_Implicit(x: 'e) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case5 x static member inline op_Implicit(x: 'f) : U6<'a, 'b, 'c, 'd, 'e, 'f> = Case6 x -/// Erased union type to represent one of seven possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of seven possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = | Case1 of 'a @@ -242,8 +363,28 @@ type U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = static member inline op_Implicit(x: 'f) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case6 x static member inline op_Implicit(x: 'g) : U7<'a, 'b, 'c, 'd, 'e, 'f, 'g> = Case7 x -/// Erased union type to represent one of eight possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of eight possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = | Case1 of 'a @@ -272,8 +413,28 @@ type U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = static member inline op_Implicit(x: 'g) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case7 x static member inline op_Implicit(x: 'h) : U8<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> = Case8 x -/// Erased union type to represent one of nine or more possible values. -/// More info: https://fable.io/docs/communicate/js-from-fable.html#erase-attribute +/// +/// Erased union type to represent one of nine possible value types mainly intended for typing the signature of imported +/// JS functions. +/// +/// +/// Pattern matching is possible, but should consider the implications of the Erased union and JS type testing (see the +/// docs for details). +///
+/// Member concrete types will be implicitly cast into the union, and will provide a warning to this effect. Usage of +/// the explicit cast operator !^ available in Fable.Core.JsInterop will remove this warning. +/// Collection types, can provide an error that will +/// only be resolved with the explicit operator. Anonymous +/// records have other considerations that may be relevant if you are encountering issues. +/// +/// let test(arg: U3<string, int, float[]>) = +/// match arg with +/// | U3.Case1 x -> printfn "A string %s" x +/// | U3.Case2 x -> printfn "An int %i" x +/// | U3.Case3 xs -> Array.sum xs |> printfn "An array with sum %f" +/// +///
+/// [] type U9<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i> = | Case1 of 'a