@@ -82,7 +82,6 @@ let getMemberArgsAndBody (com: IPythonCompiler) ctx kind hasSpread (args: Fable.
8282 Set.difference ( Annotation.getGenericTypeParams [ thisArg.Type ]) ctx.ScopedTypeParams
8383
8484 let body =
85- // TODO: If ident is not captured maybe we can just replace it with "this"
8685 if isIdentUsed thisArg.Name body then
8786 let thisKeyword = Fable.IdentExpr { thisArg with Name = " self" }
8887
@@ -365,14 +364,23 @@ let transformCast (com: IPythonCompiler) (ctx: Context) t e : Expression * State
365364
366365 // Wrap ResizeArray (Python list) when cast to IEnumerable
367366 // Python lists don't implement IEnumerable_1, so they need wrapping
367+ // Optimization: If ResizeArray was created via of_seq from IEnumerable, use the original arg
368368 | Types.ienumerableGeneric, _ when
369369 match e.Type with
370370 | Fable.Array(_, Fable.ArrayKind.ResizeArray) -> true
371371 | Fable.DeclaredType( entRef, _) when entRef.FullName = Types.resizeArray -> true
372372 | _ -> false
373373 ->
374374 let listExpr , stmts = com.TransformAsExpr( ctx, e)
375- libCall com ctx None " util" " to_enumerable" [ listExpr ], stmts
375+ // Check if the expression is of_seq(arg) - if so, use arg directly (already IEnumerable)
376+ match listExpr with
377+ | Expression.Call {
378+ Func = Expression.Name { Id = Identifier " of_seq" }
379+ Args = [ innerArg ]
380+ } ->
381+ // Skip both of_seq and to_enumerable - use original IEnumerable directly
382+ innerArg, stmts
383+ | _ -> libCall com ctx None " util" " to_enumerable" [ listExpr ], stmts
376384
377385 | _ -> com.TransformAsExpr( ctx, e)
378386 | Fable.Number( Float32, _), _ ->
@@ -601,7 +609,59 @@ let transformObjectExpr
601609 // A generic class nested in another generic class cannot use same type variables. (PEP-484)
602610 let ctx = { ctx with TypeParamsScope = ctx.TypeParamsScope + 1 }
603611
612+ // Check if any member body uses ThisValue from an outer scope (e.g., inside a constructor).
613+ // ThisValue specifically represents `self` in a constructor/method context.
614+ // Note: IsThisArgument identifiers are captured via default arguments (x: Any=x),
615+ // so we only need to handle explicit ThisValue here.
616+ let usesOuterThis =
617+ members
618+ |> List.exists ( fun memb ->
619+ memb.Body
620+ |> deepExists (
621+ function
622+ | Fable.Value( Fable.ThisValue _, _) -> true
623+ | _ -> false
624+ )
625+ )
626+
627+ // Only generate capture statement if outer this is actually used.
628+ // This allows inner class methods to reference the outer instance via "_this"
629+ // while using standard "self" for the inner instance (satisfies Pylance).
630+ let thisCaptureStmts =
631+ if usesOuterThis then
632+ let anyType = stdlibModuleAnnotation com ctx " typing" " Any" []
633+
634+ [
635+ Statement.assign ( Expression.name " _this" , anyType, value = Expression.name " self" )
636+ ]
637+ else
638+ []
639+
640+ // Replace ThisValue in the body with an identifier reference to "_this"
641+ // This ensures that outer self references correctly bind to the captured variable
642+ let replaceThisValue ( body : Fable.Expr ) =
643+ if usesOuterThis then
644+ body
645+ |> visitFromInsideOut (
646+ function
647+ | Fable.Value( Fable.ThisValue typ, r) ->
648+ Fable.IdentExpr
649+ {
650+ Name = " _this"
651+ Type = typ
652+ IsMutable = false
653+ IsThisArgument = false
654+ IsCompilerGenerated = true
655+ Range = r
656+ }
657+ | e -> e
658+ )
659+ else
660+ body
661+
604662 let makeMethod prop hasSpread ( fableArgs : Fable.Ident list ) ( fableBody : Fable.Expr ) decorators =
663+ let fableBody = replaceThisValue fableBody
664+
605665 let args , body , returnType =
606666 getMemberArgsAndBody com ctx ( Attached( isStatic = false )) hasSpread fableArgs fableBody
607667
@@ -614,16 +674,7 @@ let transformObjectExpr
614674 com.GetIdentifier( ctx, Naming.toPythonNaming name)
615675
616676 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 }
677+ let args = { args with Args = self :: args.Args }
627678
628679 // Calculate type parameters for generic object expression methods
629680 let argTypes = fableArgs |> List.map _. Type
@@ -666,12 +717,16 @@ let transformObjectExpr
666717 | Fable.Lambda( arg, body, _) -> [ arg ], body
667718 | _ -> memb.Args, memb.Body
668719
720+ // Replace ThisValue with this_ identifier for outer self references
721+ let body = replaceThisValue body
722+
669723 let args ' , body' , returnType =
670724 getMemberArgsAndBody com ctx ( NonAttached memb.Name) false args body
671725
672726 let name = com.GetIdentifier( ctx, Naming.toPythonNaming memb.Name)
673727 let self = Arg.arg " self"
674728 let args ' = { args' with Args = self :: args'.Args }
729+
675730 let argTypes = args |> List.map _. Type
676731 let typeParams = Annotation.calculateMethodTypeParams com ctx argTypes body.Type
677732
@@ -716,7 +771,7 @@ let transformObjectExpr
716771
717772 let stmt = Statement.classDef ( name, body = classBody, bases = interfaces)
718773
719- Expression.call ( Expression.name name), [ stmt ] @ stmts
774+ Expression.call ( Expression.name name), thisCaptureStmts @ [ stmt ] @ stmts
720775
721776
722777let transformCallArgs
0 commit comments