@@ -73,7 +73,15 @@ let transformImport (com: IPythonCompiler) ctx (_r: SourceLocation option) (name
7373
7474 com.GetImportExpr( ctx, moduleName, name) |> getParts com ctx parts
7575
76- let getMemberArgsAndBody ( com : IPythonCompiler ) ctx kind hasSpread ( args : Fable.Ident list ) ( body : Fable.Expr ) =
76+ let getMemberArgsAndBodyCore
77+ ( com : IPythonCompiler )
78+ ctx
79+ kind
80+ hasSpread
81+ ( args : Fable.Ident list )
82+ ( body : Fable.Expr )
83+ ( selfName : string )
84+ =
7785 // printfn "getMemberArgsAndBody: %A" hasSpread
7886 let funcName , genTypeParams , args , body =
7987 match kind, args with
@@ -82,9 +90,8 @@ let getMemberArgsAndBody (com: IPythonCompiler) ctx kind hasSpread (args: Fable.
8290 Set.difference ( Annotation.getGenericTypeParams [ thisArg.Type ]) ctx.ScopedTypeParams
8391
8492 let body =
85- // TODO: If ident is not captured maybe we can just replace it with "this"
8693 if isIdentUsed thisArg.Name body then
87- let thisKeyword = Fable.IdentExpr { thisArg with Name = " self " }
94+ let thisKeyword = Fable.IdentExpr { thisArg with Name = selfName }
8895
8996 Fable.Let( thisArg, thisKeyword, body)
9097 else
@@ -106,6 +113,9 @@ let getMemberArgsAndBody (com: IPythonCompiler) ctx kind hasSpread (args: Fable.
106113
107114 args, body, returnType
108115
116+ let getMemberArgsAndBody ( com : IPythonCompiler ) ctx kind hasSpread ( args : Fable.Ident list ) ( body : Fable.Expr ) =
117+ getMemberArgsAndBodyCore com ctx kind hasSpread args body " self"
118+
109119let getUnionCaseName ( uci : Fable.UnionCase ) =
110120 match uci.CompiledName with
111121 | Some cname -> cname
@@ -365,14 +375,23 @@ let transformCast (com: IPythonCompiler) (ctx: Context) t e : Expression * State
365375
366376 // Wrap ResizeArray (Python list) when cast to IEnumerable
367377 // Python lists don't implement IEnumerable_1, so they need wrapping
378+ // Optimization: If ResizeArray was created via of_seq from IEnumerable, use the original arg
368379 | Types.ienumerableGeneric, _ when
369380 match e.Type with
370381 | Fable.Array(_, Fable.ArrayKind.ResizeArray) -> true
371382 | Fable.DeclaredType( entRef, _) when entRef.FullName = Types.resizeArray -> true
372383 | _ -> false
373384 ->
374385 let listExpr , stmts = com.TransformAsExpr( ctx, e)
375- libCall com ctx None " util" " to_enumerable" [ listExpr ], stmts
386+ // Check if the expression is of_seq(arg) - if so, use arg directly (already IEnumerable)
387+ match listExpr with
388+ | Expression.Call {
389+ Func = Expression.Name { Id = Identifier " of_seq" }
390+ Args = [ innerArg ]
391+ } ->
392+ // Skip both of_seq and to_enumerable - use original IEnumerable directly
393+ innerArg, stmts
394+ | _ -> libCall com ctx None " util" " to_enumerable" [ listExpr ], stmts
376395
377396 | _ -> com.TransformAsExpr( ctx, e)
378397 | Fable.Number( Float32, _), _ ->
@@ -601,7 +620,59 @@ let transformObjectExpr
601620 // A generic class nested in another generic class cannot use same type variables. (PEP-484)
602621 let ctx = { ctx with TypeParamsScope = ctx.TypeParamsScope + 1 }
603622
623+ // Check if any member body uses ThisValue from an outer scope (e.g., inside a constructor).
624+ // ThisValue specifically represents `self` in a constructor/method context.
625+ // Note: IsThisArgument identifiers are captured via default arguments (x: Any=x),
626+ // so we only need to handle explicit ThisValue here.
627+ let usesOuterThis =
628+ members
629+ |> List.exists ( fun memb ->
630+ memb.Body
631+ |> deepExists (
632+ function
633+ | Fable.Value( Fable.ThisValue _, _) -> true
634+ | _ -> false
635+ )
636+ )
637+
638+ // Only generate capture statement if outer this is actually used.
639+ // This allows inner class methods to reference the outer instance via "_this"
640+ // while using standard "self" for the inner instance (satisfies Pylance).
641+ let thisCaptureStmts =
642+ if usesOuterThis then
643+ let anyType = stdlibModuleAnnotation com ctx " typing" " Any" []
644+
645+ [
646+ Statement.assign ( Expression.name " _this" , anyType, value = Expression.name " self" )
647+ ]
648+ else
649+ []
650+
651+ // Replace ThisValue in the body with an identifier reference to "_this"
652+ // This ensures that outer self references correctly bind to the captured variable
653+ let replaceThisValue ( body : Fable.Expr ) =
654+ if usesOuterThis then
655+ body
656+ |> visitFromInsideOut (
657+ function
658+ | Fable.Value( Fable.ThisValue typ, r) ->
659+ Fable.IdentExpr
660+ {
661+ Name = " _this"
662+ Type = typ
663+ IsMutable = false
664+ IsThisArgument = false
665+ IsCompilerGenerated = true
666+ Range = r
667+ }
668+ | e -> e
669+ )
670+ else
671+ body
672+
604673 let makeMethod prop hasSpread ( fableArgs : Fable.Ident list ) ( fableBody : Fable.Expr ) decorators =
674+ let fableBody = replaceThisValue fableBody
675+
605676 let args , body , returnType =
606677 getMemberArgsAndBody com ctx ( Attached( isStatic = false )) hasSpread fableArgs fableBody
607678
@@ -614,16 +685,7 @@ let transformObjectExpr
614685 com.GetIdentifier( ctx, Naming.toPythonNaming name)
615686
616687 let self = Arg.arg " self"
617-
618- let args =
619- match decorators with
620- // Remove extra parameters from getters, i.e __unit=None
621- | [ Expression.Name { Id = Identifier " property" } ] ->
622- { args with
623- Args = [ self ]
624- Defaults = []
625- }
626- | _ -> { args with Args = self :: args.Args }
688+ let args = { args with Args = self :: args.Args }
627689
628690 // Calculate type parameters for generic object expression methods
629691 let argTypes = fableArgs |> List.map _. Type
@@ -666,12 +728,16 @@ let transformObjectExpr
666728 | Fable.Lambda( arg, body, _) -> [ arg ], body
667729 | _ -> memb.Args, memb.Body
668730
731+ // Replace ThisValue with this_ identifier for outer self references
732+ let body = replaceThisValue body
733+
669734 let args ' , body' , returnType =
670735 getMemberArgsAndBody com ctx ( NonAttached memb.Name) false args body
671736
672737 let name = com.GetIdentifier( ctx, Naming.toPythonNaming memb.Name)
673738 let self = Arg.arg " self"
674739 let args ' = { args' with Args = self :: args'.Args }
740+
675741 let argTypes = args |> List.map _. Type
676742 let typeParams = Annotation.calculateMethodTypeParams com ctx argTypes body.Type
677743
@@ -716,7 +782,7 @@ let transformObjectExpr
716782
717783 let stmt = Statement.classDef ( name, body = classBody, bases = interfaces)
718784
719- Expression.call ( Expression.name name), [ stmt ] @ stmts
785+ Expression.call ( Expression.name name), thisCaptureStmts @ [ stmt ] @ stmts
720786
721787
722788let transformCallArgs
0 commit comments