File tree Expand file tree Collapse file tree
src/Fable.Transforms/Python Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -3007,6 +3007,16 @@ let transformFunction
30073007 let cleanName ( input : string ) =
30083008 Regex.Replace( input, @" _mut(_\d+)?$" , " " )
30093009
3010+ // Names of this function's own arguments. TCO capture parameters must not
3011+ // collide with these, otherwise we emit a duplicate argument (see #4610).
3012+ let ownArgNames =
3013+ args
3014+ |> List.map ( fun id ->
3015+ let ( Identifier name ) = ident com ctx id
3016+ name
3017+ )
3018+ |> Set.ofList
3019+
30103020 // For Python we need to append the TC-arguments to any declared (arrow) function inside the while-loop of the
30113021 // TCO. We will set them as default values to themselves e.g `i=i` to capture the value and not the variable.
30123022 let tcArgs , tcDefaults =
@@ -3019,6 +3029,11 @@ let transformFunction
30193029
30203030 match name with
30213031 | " tupled_arg_m" -> None // Remove these arguments (not sure why)
3032+ // Don't capture a TCO variable as a default parameter when this
3033+ // function already declares an argument with the same name: the
3034+ // local argument shadows the outer one and a duplicate parameter
3035+ // is a Python syntax error. See #4610.
3036+ | _ when ownArgNames.Contains name -> None
30223037 // Only capture TCO variables actually referenced in the function body.
30233038 // This avoids unnecessary default parameters on nested lambdas that don't
30243039 // use the outer TCO variables. See #3877.
Original file line number Diff line number Diff line change @@ -237,6 +237,22 @@ let ``test guard expression capture with 5 cases`` () =
237237 guardCaptureMultiple 5 |> equal " small: 5"
238238 guardCaptureMultiple 0 |> equal " zero or negative"
239239
240+ // Guard that uses the bound value multiple times. The guard is hoisted into a
241+ // helper function and must not capture the outer argument as a duplicate
242+ // default parameter (see #4610).
243+ let mkTag ( tag : string option ) =
244+ match tag with
245+ | None -> " "
246+ | Some s when s.StartsWith( " !" ) && not ( s.StartsWith( " !!" )) -> s + " "
247+ | Some s -> " !<" + s + " > "
248+
249+ [<Fact>]
250+ let ``test guard reusing binding does not duplicate captured argument`` () =
251+ mkTag None |> equal " "
252+ mkTag ( Some " !foo" ) |> equal " !foo "
253+ mkTag ( Some " !!foo" ) |> equal " !<!!foo> "
254+ mkTag ( Some " foo" ) |> equal " !<foo> "
255+
240256// ----------------------------------------------------------------------------
241257// 6. Nested Matching
242258// ----------------------------------------------------------------------------
You can’t perform that action at this time.
0 commit comments