Skip to content

Commit fc0f255

Browse files
github-actions[bot]claudedbrattli
authored
[Python] Fix unsafe option unwrapping in Replacements.fs (#4480)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Dag Brattli <dag@brattli.net>
1 parent ea87e3b commit fc0f255

3 files changed

Lines changed: 67 additions & 63 deletions

File tree

src/Fable.Cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19+
* [Python] Fix unsafe option unwrapping in `DateTimeOffset.get_Offset` and regex replacements (by @dbrattli)
1920
* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
2021
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
2122
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)

src/Fable.Compiler/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19+
* [Python] Fix unsafe option unwrapping in `DateTimeOffset.get_Offset` and regex replacements (by @dbrattli)
1920
* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
2021
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
2122
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)

src/Fable.Transforms/Python/Replacements.fs

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3074,26 +3074,26 @@ let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio
30743074
Helper.LibCall(com, "Date", "toString", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r)
30753075
|> Some
30763076
| "get_Offset" ->
3077-
Naming.removeGetSetPrefix i.CompiledName
3078-
|> Naming.lowerFirst
3079-
|> getFieldWith r t thisArg.Value
3080-
|> Some
3077+
thisArg
3078+
|> Option.map (fun thisArg ->
3079+
Naming.removeGetSetPrefix i.CompiledName
3080+
|> Naming.lowerFirst
3081+
|> getFieldWith r t thisArg
3082+
)
30813083
// DateTimeOffset
30823084
| "get_LocalDateTime" when i.DeclaringEntityFullName = Types.datetimeOffset ->
3083-
match thisArg with
3084-
| Some thisArg ->
3085+
thisArg
3086+
|> Option.map (fun thisArg ->
30853087
Helper.LibCall(com, "date_offset", "localDateTime", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3086-
|> Some
3087-
| None -> None
3088+
)
30883089
| "get_UtcDateTime" when i.DeclaringEntityFullName = Types.datetimeOffset ->
3089-
match thisArg with
3090-
| Some thisArg ->
3090+
thisArg
3091+
|> Option.map (fun thisArg ->
30913092
Helper.LibCall(com, "date_offset", "utcDateTime", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3092-
|> Some
3093-
| None -> None
3093+
)
30943094
| "get_DateTime" when i.DeclaringEntityFullName = Types.datetimeOffset ->
3095-
match thisArg with
3096-
| Some thisArg ->
3095+
thisArg
3096+
|> Option.map (fun thisArg ->
30973097
let kind = System.DateTimeKind.Unspecified |> int |> makeIntConst
30983098

30993099
Helper.LibCall(
@@ -3105,8 +3105,7 @@ let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio
31053105
[ thisArg.Type; kind.Type ],
31063106
?loc = r
31073107
)
3108-
|> Some
3109-
| None -> None
3108+
)
31103109
| "FromUnixTimeSeconds" ->
31113110
let value =
31123111
Helper.LibCall(com, "Long", "toNumber", Float64.Number, args, i.SignatureArgTypes)
@@ -3120,38 +3119,33 @@ let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio
31203119
Helper.LibCall(com, "DateOffset", "fromUnixTimeMilliseconds", t, [ value ], [ value.Type ], ?loc = r)
31213120
|> Some
31223121
| "ToUnixTimeSeconds" ->
3123-
match thisArg with
3124-
| Some thisArg ->
3122+
thisArg
3123+
|> Option.map (fun thisArg ->
31253124
Helper.LibCall(com, "DateOffset", "toUnixTimeSeconds", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3126-
|> Some
3127-
| None -> None
3125+
)
31283126
| "ToUnixTimeMilliseconds" ->
3129-
match thisArg with
3130-
| Some thisArg ->
3127+
thisArg
3128+
|> Option.map (fun thisArg ->
31313129
Helper.LibCall(com, "DateOffset", "toUnixTimeMilliseconds", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3132-
|> Some
3133-
| None -> None
3130+
)
31343131
| "get_UtcTicks" ->
3135-
match thisArg with
3136-
| Some thisArg ->
3132+
thisArg
3133+
|> Option.map (fun thisArg ->
31373134
Helper.LibCall(com, "DateOffset", "getUtcTicks", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3138-
|> Some
3139-
| None -> None
3135+
)
31403136
| "EqualsExact" ->
3141-
match thisArg with
3142-
| Some thisArg ->
3137+
thisArg
3138+
|> Option.map (fun thisArg ->
31433139
Helper.LibCall(com, "DateOffset", "equalsExact", Boolean, [ thisArg; args.Head ], ?loc = r)
3144-
|> Some
3145-
| None -> None
3140+
)
31463141
| "Compare" ->
31473142
Helper.LibCall(com, "DateOffset", "compare", t, args, i.SignatureArgTypes, ?loc = r)
31483143
|> Some
31493144
| "CompareTo" ->
3150-
match thisArg with
3151-
| Some thisArg ->
3145+
thisArg
3146+
|> Option.map (fun thisArg ->
31523147
Helper.LibCall(com, "DateOffset", "compareTo", t, [ thisArg; args.Head ], ?loc = r)
3153-
|> Some
3154-
| None -> None
3148+
)
31553149
| "TryParse" ->
31563150
let args =
31573151
ignoreFormatProvider com ctx r i.DeclaringEntityFullName i.CompiledName args
@@ -3356,47 +3350,55 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp
33563350
Helper.LibCall(com, "reg_exp", "create", t, args, i.SignatureArgTypes, ?loc = r)
33573351
|> Some
33583352
| "get_Options" ->
3359-
Helper.LibCall(com, "reg_exp", "options", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r)
3360-
|> Some
3353+
thisArg
3354+
|> Option.map (fun thisArg ->
3355+
Helper.LibCall(com, "reg_exp", "options", t, [ thisArg ], [ thisArg.Type ], ?loc = r)
3356+
)
33613357
// Capture
33623358
| "get_Index" ->
3363-
if not isGroup then
3364-
Helper.InstanceCall(thisArg.Value, "start", t, [], i.SignatureArgTypes, ?loc = r)
3365-
|> Some
3366-
else
3367-
"Accessing index of Regex groups is not supported"
3368-
|> addErrorAndReturnNull com ctx.InlinePath r
3369-
|> Some
3359+
thisArg
3360+
|> Option.map (fun thisArg ->
3361+
if not isGroup then
3362+
Helper.InstanceCall(thisArg, "start", t, [], i.SignatureArgTypes, ?loc = r)
3363+
else
3364+
"Accessing index of Regex groups is not supported"
3365+
|> addErrorAndReturnNull com ctx.InlinePath r
3366+
)
33703367
| "get_Value" ->
3371-
if
3372-
isGroup
3373-
// In JS Regex group values can be undefined, ensure they're empty strings #838
3374-
then
3375-
Operation(Logical(LogicalOr, thisArg.Value, makeStrConst ""), Tags.empty, t, r)
3376-
|> Some
3377-
else
3378-
propInt 0 thisArg.Value |> Some
3368+
thisArg
3369+
|> Option.map (fun thisArg ->
3370+
if isGroup then
3371+
// In JS Regex group values can be undefined, ensure they're empty strings #838
3372+
Operation(Logical(LogicalOr, thisArg, makeStrConst ""), Tags.empty, t, r)
3373+
else
3374+
propInt 0 thisArg
3375+
)
33793376
| "get_Length" ->
3380-
if isGroup then
3381-
Helper.GlobalCall("len", t, [ thisArg.Value ], [ t ], ?loc = r) |> Some
3382-
else
3383-
let prop = propInt 0 thisArg.Value
3384-
Helper.GlobalCall("len", t, [ prop ], [ t ], ?loc = r) |> Some
3377+
thisArg
3378+
|> Option.map (fun thisArg ->
3379+
if isGroup then
3380+
Helper.GlobalCall("len", t, [ thisArg ], [ t ], ?loc = r)
3381+
else
3382+
let prop = propInt 0 thisArg
3383+
Helper.GlobalCall("len", t, [ prop ], [ t ], ?loc = r)
3384+
)
33853385
// Group
3386-
| "get_Success" -> nullCheck r false thisArg.Value |> Some
3386+
| "get_Success" -> thisArg |> Option.map (fun thisArg -> nullCheck r false thisArg)
33873387
// MatchCollection & GroupCollection
33883388
| "get_Item" when i.DeclaringEntityFullName = Types.regexGroupCollection ->
3389-
Helper.LibCall(com, "RegExp", "get_item", t, [ thisArg.Value; args.Head ], [ thisArg.Value.Type ], ?loc = r)
3390-
|> Some
3391-
| "get_Item" -> thisArg |> Option.map (fun this -> getExpr r t this args.Head)
3389+
thisArg
3390+
|> Option.map (fun thisArg ->
3391+
Helper.LibCall(com, "RegExp", "get_item", t, [ thisArg; args.Head ], [ thisArg.Type ], ?loc = r)
3392+
)
3393+
| "get_Item" -> thisArg |> Option.map (fun thisArg -> getExpr r t thisArg args.Head)
33923394
| "get_Count" ->
33933395
// Use int32(len()) to ensure consistent return type
33943396
thisArg
33953397
|> Option.map (fun c ->
33963398
let lenExpr = Helper.GlobalCall("len", Int32.Number, [ c ], ?loc = r)
33973399
Helper.LibCall(com, "core", "int32", t, [ lenExpr ], ?loc = r)
33983400
)
3399-
| "GetEnumerator" -> getEnumerator com r t thisArg.Value |> Some
3401+
| "GetEnumerator" -> thisArg |> Option.map (fun thisArg -> getEnumerator com r t thisArg)
34003402
| "IsMatch"
34013403
| "Match"
34023404
| "Matches" as meth ->

0 commit comments

Comments
 (0)