From 9a42eb541eb426a04bb0541ccf0e26ce82bdcb22 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 May 2015 13:55:33 +0100 Subject: [PATCH] py: Fix naming of function arguments when function is a closure. Addresses issue #1226. --- py/emitbc.c | 20 +++++++++++++++++++- py/emitnative.c | 11 ++++++++++- tests/basics/closure_namedarg.py | 9 +++++++++ tests/cmdline/cmd_showbc.py.exp | 10 +++++----- 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 tests/basics/closure_namedarg.py diff --git a/py/emitbc.c b/py/emitbc.c index 624b98dd42..f99e703220 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -305,8 +305,26 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { // we store them as full word-sized objects for efficient access in mp_setup_code_state // this is the start of the prelude and is guaranteed to be aligned on a word boundary { + // For a given argument position (indexed by i) we need to find the + // corresponding id_info which is a parameter, as it has the correct + // qstr name to use as the argument name. Note that it's not a simple + // 1-1 mapping (ie i!=j in general) because of possible closed-over + // variables. In the case that the argument i has no corresponding + // parameter we use "*" as its name (since no argument can ever be named + // "*"). We could use a blank qstr but "*" is better for debugging. + // Note: there is some wasted RAM here for the case of storing a qstr + // for each closed-over variable, and maybe there is a better way to do + // it, but that would require changes to mp_setup_code_state. for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { - emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(scope->id_info[i].qst)); + qstr qst = MP_QSTR__star_; + for (int j = 0; j < scope->id_info_len; ++j) { + id_info_t *id = &scope->id_info[j]; + if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { + qst = id->qst; + break; + } + } + emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(qst)); } } diff --git a/py/emitnative.c b/py/emitnative.c index ea81270dbc..8acce83236 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -796,8 +796,17 @@ STATIC void emit_native_end_pass(emit_t *emit) { ASM_DATA(emit->as, 1, emit->code_info_size); ASM_ALIGN(emit->as, ASM_WORD_SIZE); emit->code_info_size = ASM_GET_CODE_POS(emit->as) - emit->code_info_offset; + // see comment in corresponding part of emitbc.c about the logic here for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) { - ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(emit->scope->id_info[i].qst)); + qstr qst = MP_QSTR__star_; + for (int j = 0; j < emit->scope->id_info_len; ++j) { + id_info_t *id = &emit->scope->id_info[j]; + if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { + qst = id->qst; + break; + } + } + ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); } // bytecode prelude: initialise closed over variables diff --git a/tests/basics/closure_namedarg.py b/tests/basics/closure_namedarg.py new file mode 100644 index 0000000000..5c0c451d15 --- /dev/null +++ b/tests/basics/closure_namedarg.py @@ -0,0 +1,9 @@ +# test passing named arg to closed-over function + +def f(): + x = 1 + def g(z): + print(x, z) + return g + +f()(z=42) diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 723a403a18..02e3676542 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -354,7 +354,7 @@ File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## \.\+5b -arg names: c e +arg names: * * * (N_STATE 6) (N_EXC_STACK 0) bc=-\\d\+ line=1 @@ -373,7 +373,7 @@ File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## \.\+5b -arg names: c e +arg names: * * * (N_STATE 7) (N_EXC_STACK 0) bc=-\\d\+ line=1 @@ -391,7 +391,7 @@ File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## \.\+5b -arg names: c e +arg names: * * * (N_STATE 8) (N_EXC_STACK 0) bc=-\\d\+ line=1 @@ -411,7 +411,7 @@ File cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\. Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## \.\+5b -arg names: x +arg names: * (N_STATE 4) (N_EXC_STACK 0) bc=-\\d\+ line=1 @@ -430,7 +430,7 @@ File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ byt Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## \.\+5b -arg names: b a +arg names: * b (N_STATE 4) (N_EXC_STACK 0) bc=-\\d\+ line=1