@@ -69,16 +69,7 @@ let getMemberArgsAndBody (com: IPythonCompiler) ctx kind hasSpread (args: Fable.
6969 let args , body , returnType , _typeParams =
7070 Annotation.transformFunctionWithAnnotations com ctx funcName args body
7171
72- let args =
73- let len = args.Args.Length
74-
75- if not hasSpread || len = 0 then
76- args
77- else
78- { args with
79- VarArg = Some { args.Args[ len - 1 ] with Annotation = None }
80- Args = args.Args[.. len - 2 ]
81- }
72+ let args = adjustArgsForSpread hasSpread args
8273
8374 args, body, returnType
8475
@@ -740,6 +731,16 @@ let transformCallArgs
740731 let hasSpread =
741732 paramsInfo |> Option.map ( fun i -> i.HasSpread) |> Option.defaultValue false
742733
734+ // Helper to transform an arg and wrap with widen() if needed
735+ let transformArgWithWiden ( sigType : Fable.Type option ) ( argExpr : Fable.Expr ) =
736+ let expr , stmts = com.TransformAsExpr( ctx, argExpr)
737+
738+ if needsOptionWidenForArg sigType argExpr then
739+ let widen = com.TransformImport( ctx, " widen" , getLibPath com " option" )
740+ Expression.call ( widen, [ expr ]), stmts
741+ else
742+ expr, stmts
743+
743744 let args , stmts' =
744745 match args with
745746 | [] -> [], []
@@ -759,7 +760,14 @@ let transformCallArgs
759760
760761 let expr , stmts' = com.TransformAsExpr( ctx, last)
761762 rest @ [ Expression.starred expr ], stmts @ stmts'
762- | args -> List.map ( fun e -> com.TransformAsExpr( ctx, e)) args |> Helpers.unzipArgs
763+ | args ->
764+ // Transform args with widen() where needed based on signature types
765+ args
766+ |> List.mapi ( fun i e ->
767+ let sigType = List.tryItem i callInfo.SignatureArgTypes
768+ transformArgWithWiden sigType e
769+ )
770+ |> Helpers.unzipArgs
763771
764772 match objArg with
765773 | None -> args, [], stmts @ stmts'
@@ -1515,7 +1523,12 @@ let getDecisionTargetAndBoundValues (com: IPythonCompiler) (ctx: Context) target
15151523 let bindings , replacements =
15161524 (([], Map.empty), identsAndValues)
15171525 ||> List.fold ( fun ( bindings , replacements ) ( ident , expr ) ->
1518- if canHaveSideEffects com expr then
1526+ // Only inline if the expression has no side effects AND is referenced at most once.
1527+ // If referenced multiple times, we should bind to a variable to avoid duplicating
1528+ // the expression (which can cause issues like accessing properties on literals).
1529+ let refCount = FableTransforms.countReferencesUntil 2 ident.Name target
1530+
1531+ if canHaveSideEffects com expr || refCount > 1 then
15191532 ( ident, expr) :: bindings, replacements
15201533 else
15211534 bindings, Map.add ident.Name expr replacements
@@ -4129,23 +4142,42 @@ let transformInterface (com: IPythonCompiler) ctx (classEnt: Fable.Entity) (_cla
41294142 // Make protocol method parameters positional-only (using /) to avoid
41304143 // parameter name mismatch errors when subclasses use different names
41314144 // (e.g., value_1 instead of value due to closure captures)
4145+ let allParams =
4146+ memb.CurriedParameterGroups
4147+ |> Seq.indexed
4148+ |> Seq.collect ( fun ( n , parameterGroup ) ->
4149+ parameterGroup |> Seq.indexed |> Seq.map ( fun ( m , pg ) -> ( n + m, pg))
4150+ )
4151+ |> Seq.toList
4152+
4153+ // Split regular params from vararg param using shared helper
4154+ let regularParams , varArgParam = splitVarArg memb.HasSpread allParams
4155+
41324156 let posOnlyArgs =
41334157 [
41344158 if memb.IsInstance then
41354159 Arg.arg " self"
41364160
4137- for n, parameterGroup in memb.CurriedParameterGroups |> Seq.indexed do
4138- for m, pg in parameterGroup |> Seq.indexed do
4139- // Uncurry function types to match class implementations
4140- // F# interface uses curried types (LambdaType) but class methods
4141- // use uncurried types (DelegateType) at runtime
4142- let paramType = FableTransforms.uncurryType pg.Type
4143- let ta , _ = Annotation.typeAnnotation com ctx None paramType
4161+ for idx, pg in regularParams do
4162+ // Uncurry function types to match class implementations
4163+ // F# interface uses curried types (LambdaType) but class methods
4164+ // use uncurried types (DelegateType) at runtime
4165+ let paramType = FableTransforms.uncurryType pg.Type
4166+ let ta , _ = Annotation.typeAnnotation com ctx None paramType
41444167
4145- Arg.arg ( pg.Name |> Option.defaultValue $" __arg%d {n + m }" , annotation = ta)
4168+ Arg.arg ( pg.Name |> Option.defaultValue $" __arg%d {idx }" , annotation = ta)
41464169 ]
41474170
4148- Arguments.arguments ( posonlyargs = posOnlyArgs)
4171+ // For vararg parameter, extract element type from array type for annotation
4172+ let vararg =
4173+ varArgParam
4174+ |> Option.map ( fun ( _idx , pg ) ->
4175+ let elementType = getVarArgElementType pg.Type
4176+ let ta , _ = Annotation.typeAnnotation com ctx None elementType
4177+ Arg.arg ( pg.Name |> Option.defaultValue " rest" , annotation = ta)
4178+ )
4179+
4180+ Arguments.arguments ( posonlyargs = posOnlyArgs, ?vararg = vararg)
41494181
41504182 // Also uncurry return type for consistency with class implementations
41514183 let uncurriedReturnType = FableTransforms.uncurryType memb.ReturnParameter.Type
0 commit comments