Bind local name for decorated function early so it can be closed
This commit is contained in:
parent
0425becba9
commit
f247bba985
@ -1847,6 +1847,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
|
||||
if (identifiersEqual(&at_classmethod, &state->parser.current)) type = TYPE_CLASSMETHOD;
|
||||
}
|
||||
|
||||
if (level == 0 && inType == TYPE_FUNCTION && state->current->scopeDepth != 0) {
|
||||
emitByte(OP_NONE);
|
||||
}
|
||||
|
||||
expression(state);
|
||||
|
||||
consume(TOKEN_EOL, "Expected end of line after decorator.");
|
||||
@ -1863,6 +1867,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
|
||||
if (type == TYPE_METHOD && funcName.length == 8 && !memcmp(funcName.start,"__init__",8)) {
|
||||
type = TYPE_INIT;
|
||||
}
|
||||
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
|
||||
declareVariable(state);
|
||||
markInitialized(state);
|
||||
}
|
||||
function(state, type, blockWidth);
|
||||
} else if (match(TOKEN_ASYNC)) {
|
||||
if (!match(TOKEN_DEF)) {
|
||||
@ -1871,6 +1879,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
|
||||
}
|
||||
consume(TOKEN_IDENTIFIER, "Expected coroutine name after 'def'.");
|
||||
funcName = state->parser.previous;
|
||||
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
|
||||
declareVariable(state);
|
||||
markInitialized(state);
|
||||
}
|
||||
function(state, type == TYPE_METHOD ? TYPE_COROUTINE_METHOD : TYPE_COROUTINE, blockWidth);
|
||||
} else if (check(TOKEN_AT)) {
|
||||
funcName = decorator(state, level+1, type);
|
||||
@ -1889,10 +1901,12 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
|
||||
|
||||
if (level == 0) {
|
||||
if (inType == TYPE_FUNCTION) {
|
||||
state->parser.previous = funcName;
|
||||
declareVariable(state);
|
||||
size_t ind = (state->current->scopeDepth > 0) ? 0 : identifierConstant(state, &funcName);
|
||||
if (state->current->scopeDepth == 0) {
|
||||
size_t ind = identifierConstant(state, &funcName);
|
||||
defineVariable(state, ind);
|
||||
} else {
|
||||
emitByte(OP_SWAP_POP);
|
||||
}
|
||||
} else {
|
||||
size_t ind = identifierConstant(state, &funcName);
|
||||
rememberClassProperty(state, ind);
|
||||
|
@ -121,3 +121,4 @@ SIMPLE(OP_TUPLE_FROM_LIST)
|
||||
|
||||
OPERAND(OP_UNPACK_EX,NOOP)
|
||||
JUMP(OP_ENTER_EXCEPT,+)
|
||||
SIMPLE(OP_SWAP_POP)
|
||||
|
1
src/vm.c
1
src/vm.c
@ -2258,6 +2258,7 @@ _finishReturn: (void)0;
|
||||
case OP_FALSE: krk_push(BOOLEAN_VAL(0)); break;
|
||||
case OP_UNSET: krk_push(KWARGS_VAL(0)); break;
|
||||
case OP_NOT: krk_currentThread.stackTop[-1] = BOOLEAN_VAL(krk_isFalsey(krk_peek(0))); break;
|
||||
case OP_SWAP_POP: krk_swap(1); /* fallthrough */
|
||||
case OP_POP: krk_pop(); break;
|
||||
|
||||
case OP_INPLACE_ADD: INPLACE_BINARY_OP(add)
|
||||
|
18
test/testDecoratedRecursiveFunction.krk
Normal file
18
test/testDecoratedRecursiveFunction.krk
Normal file
@ -0,0 +1,18 @@
|
||||
def decorate(func):
|
||||
def _inner(a):
|
||||
print('in')
|
||||
a = func(a)
|
||||
print('out')
|
||||
return a
|
||||
return _inner
|
||||
|
||||
def foo():
|
||||
@decorate
|
||||
def bar(a):
|
||||
if a <= 0:
|
||||
return 0
|
||||
return bar(a-1)
|
||||
|
||||
bar(2)
|
||||
|
||||
foo()
|
6
test/testDecoratedRecursiveFunction.krk.expect
Normal file
6
test/testDecoratedRecursiveFunction.krk.expect
Normal file
@ -0,0 +1,6 @@
|
||||
in
|
||||
in
|
||||
in
|
||||
out
|
||||
out
|
||||
out
|
Loading…
Reference in New Issue
Block a user