Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Fable.Cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)
* [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave)
* [Python] Fix `String.IndexOf`/`LastIndexOf` with `StringComparison` argument emitting it as a start-index instead of a compile error (by @repo-assist)
Expand Down
2 changes: 2 additions & 0 deletions src/Fable.Compiler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

* [All] Replace unsafe option `.Value` unwrapping with safe alternatives in Python/Replacements.fs and Rust/Fable2Rust.fs (code scanning alerts IONIDE-006)
* [All] Add `[<return: Struct>]` to partial active patterns in Dart and Rust targets to reduce allocations (code scanning alerts IONIDE-009)
* [JS/TS] Fix `Guid` to use cryptographically strong random values (by @ncave)
* [Python] Fix `DateTimeOffset` millisecond constructor and property (by @ncave)
* [Python] Fix `String.IndexOf`/`LastIndexOf` with `StringComparison` argument emitting it as a start-index instead of a compile error (by @repo-assist)
Expand Down
14 changes: 8 additions & 6 deletions src/Fable.Transforms/Dart/Fable2Dart.fs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,19 @@ module Util =

let (|TransformType|) (com: IDartCompiler) ctx e = com.TransformType(ctx, e)

[<return: Struct>]
let (|Function|_|) =
function
| Fable.Lambda(arg, body, _) -> Some([ arg ], body)
| Fable.Delegate(args, body, _, []) -> Some(args, body)
| _ -> None
| Fable.Lambda(arg, body, _) -> ValueSome([ arg ], body)
| Fable.Delegate(args, body, _, []) -> ValueSome(args, body)
| _ -> ValueNone

[<return: Struct>]
let (|Lets|_|) =
function
| Fable.Let(ident, value, body) -> Some([ ident, value ], body)
| Fable.LetRec(bindings, body) -> Some(bindings, body)
| _ -> None
| Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body)
| Fable.LetRec(bindings, body) -> ValueSome(bindings, body)
| _ -> ValueNone

let makeTypeRefFromName typeName genArgs =
let ident = makeImmutableIdent MetaType typeName
Expand Down
16 changes: 10 additions & 6 deletions src/Fable.Transforms/Dart/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ open Fable.AST.Fable
open Fable.Transforms
open Replacements.Util

[<return: Struct>]
let (|DartInt|_|) =
function
| Int8
Expand All @@ -19,14 +20,15 @@ let (|DartInt|_|) =
| Int32
| UInt32
| Int64
| UInt64 -> Some DartInt
| _ -> None
| UInt64 -> ValueSome DartInt
| _ -> ValueNone

[<return: Struct>]
let (|DartDouble|_|) =
function
| Float32
| Float64 -> Some DartDouble
| _ -> None
| Float64 -> ValueSome DartDouble
| _ -> ValueNone

let error com msg =
let e = makeImportLib com Any "ExceptionBase" "Types"
Expand Down Expand Up @@ -1201,10 +1203,12 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o
let meth = Naming.lowerFirst meth

match meth, t with
| ("min" | "max"), Number((DartInt | DartDouble), NumberInfo.Empty) ->
| ("min" | "max"), Number(DartInt, NumberInfo.Empty)
| ("min" | "max"), Number(DartDouble, NumberInfo.Empty) ->
Helper.ImportedCall("dart:math", meth, t, args, i.SignatureArgTypes, ?loc = r)
|> Some
| ("minMagnitude" | "maxMagnitude"), Number((DartInt | DartDouble), NumberInfo.Empty) ->
| ("minMagnitude" | "maxMagnitude"), Number(DartInt, NumberInfo.Empty)
| ("minMagnitude" | "maxMagnitude"), Number(DartDouble, NumberInfo.Empty) ->
Helper.LibCall(com, "Util", meth, t, args, i.SignatureArgTypes, ?loc = r)
|> Some
| _ ->
Expand Down
2 changes: 1 addition & 1 deletion src/Fable.Transforms/Python/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3245,7 +3245,7 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp
| "get_Item" when i.DeclaringEntityFullName = Types.regexGroupCollection ->
Helper.LibCall(com, "RegExp", "get_item", t, [ thisArg.Value; args.Head ], [ thisArg.Value.Type ], ?loc = r)
|> Some
| "get_Item" -> getExpr r t thisArg.Value args.Head |> Some
| "get_Item" -> thisArg |> Option.map (fun this -> getExpr r t this args.Head)
| "get_Count" ->
// Use int32(len()) to ensure consistent return type
thisArg
Expand Down
67 changes: 39 additions & 28 deletions src/Fable.Transforms/Rust/Fable2Rust.fs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ module TypeInfo =
// most abstract classes are implemented as non-abstract
makeFullNamePathTy entName genArgsOpt

[<return: Struct>]
let (|HasEmitAttribute|_|) (ent: Fable.Entity) =
ent.Attributes
|> Seq.tryPick (fun att ->
Expand All @@ -907,13 +908,15 @@ module TypeInfo =
else
None
)
|> Option.toValueOption

type PointerType =
| Lrc
| Rc
| Arc
| Box

[<return: Struct>]
let (|HasReferenceTypeAttribute|_|) (ent: Fable.Entity) =
ent.Attributes
|> Seq.tryPick (fun att ->
Expand All @@ -930,17 +933,19 @@ module TypeInfo =
else
None
)
|> Option.toValueOption

[<return: Struct>]
let (|IsNonErasedInterface|_|) (com: Compiler) =
function
| Fable.DeclaredType(entRef, genArgs) ->
let ent = com.GetEntity(entRef)

if ent.IsInterface && not (ent |> FSharp2Fable.Util.hasAttribute Atts.erase) then
Some(entRef, genArgs)
ValueSome(entRef, genArgs)
else
None
| _ -> None
ValueNone
| _ -> ValueNone

let transformEntityType (com: IRustCompiler) ctx (entRef: Fable.EntityRef) genArgs : Rust.Ty =
match com.GetEntity(entRef) with
Expand Down Expand Up @@ -1176,43 +1181,50 @@ module Util =

let (|TransformExpr|) (com: IRustCompiler) ctx e = com.TransformExpr(ctx, e)

[<return: Struct>]
let (|Function|_|) =
function
| Fable.Lambda(arg, body, info) -> Some([ arg ], body, info)
| Fable.Delegate(args, body, info, []) -> Some(args, body, info)
| _ -> None
| Fable.Lambda(arg, body, info) -> ValueSome([ arg ], body, info)
| Fable.Delegate(args, body, info, []) -> ValueSome(args, body, info)
| _ -> ValueNone

[<return: Struct>]
let (|Lets|_|) =
function
| Fable.Let(ident, value, body) -> Some([ ident, value ], body)
| Fable.LetRec(bindings, body) -> Some(bindings, body)
| _ -> None
| Fable.Let(ident, value, body) -> ValueSome([ ident, value ], body)
| Fable.LetRec(bindings, body) -> ValueSome(bindings, body)
| _ -> ValueNone

[<return: Struct>]
let (|IDisposable|_|) =
function
| Replacements.Util.IsEntity (Types.idisposable) _ -> Some()
| _ -> None
| Replacements.Util.IsEntity (Types.idisposable) _ -> ValueSome()
| _ -> ValueNone

[<return: Struct>]
let (|IFormattable|_|) =
function
| Replacements.Util.IsEntity (Types.iformattable) _ -> Some()
| _ -> None
| Replacements.Util.IsEntity (Types.iformattable) _ -> ValueSome()
| _ -> ValueNone

[<return: Struct>]
let (|IComparable|_|) =
function
| Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> Some(genArg)
| _ -> None
| Replacements.Util.IsEntity (Types.icomparableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
| _ -> ValueNone

[<return: Struct>]
let (|IEquatable|_|) =
function
| Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> Some(genArg)
| _ -> None
| Replacements.Util.IsEntity (Types.iequatableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
| _ -> ValueNone

[<return: Struct>]
let (|IEnumerable|_|) =
function
| Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> Some(genArg)
| Replacements.Util.IsEntity (Types.ienumerable) _ -> Some(Fable.Any)
| _ -> None
| Replacements.Util.IsEntity (Types.ienumerableGeneric) (_, [ genArg ]) -> ValueSome(genArg)
| Replacements.Util.IsEntity (Types.ienumerable) _ -> ValueSome(Fable.Any)
| _ -> ValueNone

let isUnitArg (ident: Fable.Ident) =
ident.IsCompilerGenerated
Expand Down Expand Up @@ -3779,10 +3791,9 @@ module Util =
let getFunctionBodyCtx com ctx (name: string option) (args: Fable.Ident list) (body: Fable.Expr) isTailRec =

let tco =
if isTailRec then
Some(NamedTailCallOpportunity(com, ctx, name.Value, args) :> ITailCallOpportunity)
else
None
match isTailRec, name with
| true, Some n -> Some(NamedTailCallOpportunity(com, ctx, n, args) :> ITailCallOpportunity)
| _ -> None

let usages = calcIdentUsages args [ body ]

Expand Down Expand Up @@ -3867,17 +3878,17 @@ module Util =
let fnBody = transformFunctionBody com ctx args body

let fnBody =
if isRecursive && not isTailRec then
match isRecursive && not isTailRec, name with
| true, Some n ->
// make the closure recursive with fixed-point combinator
let fixedArgs = (makeIdent name.Value) :: args
let fixedArgs = (makeIdent n) :: args
let fixedDecl = transformFunctionDecl com ctx fixedArgs [] Fable.Unit
let fixedBody = mkClosureExpr true fixedDecl fnBody
let argExprs = args |> List.map Fable.IdentExpr
let callArgs = transformCallArgs com ctx argExprs [] []
let fixCallArgs = (fixedBody |> mkAddrOfExpr) :: callArgs
makeLibCall com ctx None "Native" ("fix" + argCount) fixCallArgs
else
fnBody
| _ -> fnBody

let cloneStmts =
// clone captured idents (in 'move' closures)
Expand Down
Loading