diff --git a/src/Fable.Transforms/Python/Fable2Python.Transforms.fs b/src/Fable.Transforms/Python/Fable2Python.Transforms.fs index c445abfde4..180e9855e1 100644 --- a/src/Fable.Transforms/Python/Fable2Python.Transforms.fs +++ b/src/Fable.Transforms/Python/Fable2Python.Transforms.fs @@ -382,6 +382,14 @@ let transformCast (com: IPythonCompiler) (ctx: Context) t e : Expression * State let value, stmts = com.TransformAsExpr(ctx, e) libCall com ctx None "core" "int32" [ value ], stmts | _ -> com.TransformAsExpr(ctx, e) + // The other integer widths are wrapper classes too, so `uint32 (x: byte)` needs the same explicit constructor call + | Fable.Number((Int8 | UInt8 | Int16 | UInt16 | UInt32) as kind, _), _ -> + match e.Type with + | Fable.Number(sourceKind, _) when sourceKind = kind -> com.TransformAsExpr(ctx, e) + | Fable.Number _ -> + let value, stmts = com.TransformAsExpr(ctx, e) + libCall com ctx None "core" (Py.Replacements.getIntTypeName kind) [ value ], stmts + | _ -> com.TransformAsExpr(ctx, e) // Float64 is a plain Python `float`, and the same reasoning applies: // `Replacements.toFloat` emits a bare `TypeCast` for every numeric source that is // not bigint/decimal/int64, so `float (x: float32)` would otherwise stay a diff --git a/tests/Python/TestConvert.fs b/tests/Python/TestConvert.fs index 781b711289..a77a50fcaf 100644 --- a/tests/Python/TestConvert.fs +++ b/tests/Python/TestConvert.fs @@ -418,6 +418,26 @@ let private toIntFromInt16 (x: int16) = int x let private toFloatFromSingle (x: float32) = float x let private toFloatFromByte (x: byte) = float x let private toFloatFromInt (x: int) = float x +let private toInt16FromSByte (x: sbyte) = int16 x +let private toUInt16FromByte (x: byte) = uint16 x +let private toUInt32FromByte (x: byte) = uint32 x +let private toUInt32FromUInt16 (x: uint16) = uint32 x + +[] +let ``test Widening between integer wrappers uses the target width`` () = + // Compare as int so wrapper equality cannot truncate the expected value to the source width. + toInt16FromSByte 100y <<< 1 |> int |> equal 200 + toInt16FromSByte -100y <<< 1 |> int |> equal -200 + toUInt16FromByte 200uy <<< 1 |> int |> equal 400 + toUInt32FromByte 200uy <<< 1 |> int |> equal 400 + toUInt32FromUInt16 60000us <<< 1 |> int |> equal 120000 + +[] +let ``test Widening between integer wrappers has the target runtime type`` () = + box (toInt16FromSByte 5y) :? int16 |> equal true + box (toUInt16FromByte 5uy) :? uint16 |> equal true + box (toUInt32FromByte 5uy) :? uint32 |> equal true + box (toUInt32FromUInt16 5us) :? uint32 |> equal true [] let ``test Widening to int does not keep the source width`` () =