Skip to content

Commit

Permalink
[PRISM] Fix break in super block
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Apr 11, 2024
1 parent bb5ed8b commit 58f93ee
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 8 deletions.
45 changes: 38 additions & 7 deletions prism_compile.c
Expand Up @@ -5791,14 +5791,28 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
const pm_forwarding_super_node_t *cast = (const pm_forwarding_super_node_t *) node;
const rb_iseq_t *block = NULL;

const rb_iseq_t *previous_block;
LABEL *retry_label;
LABEL *retry_end_l;

if (cast->block != NULL) {
previous_block = ISEQ_COMPILE_DATA(iseq)->current_block;
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;

retry_label = NEW_LABEL(location.line);
retry_end_l = NEW_LABEL(location.line);

PUSH_LABEL(ret, retry_label);
}

PUSH_INSN(ret, location, putself);
int flag = VM_CALL_ZSUPER | VM_CALL_SUPER | VM_CALL_FCALL;

if (cast->block != NULL) {
pm_scope_node_t next_scope_node;
pm_scope_node_init((const pm_node_t *) cast->block, &next_scope_node, scope_node);

block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location.line);
ISEQ_COMPILE_DATA(iseq)->current_block = block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location.line);
pm_scope_node_destroy(&next_scope_node);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) block);
}
Expand Down Expand Up @@ -5898,8 +5912,14 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,

PUSH_SEQ(ret, args);
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flag, NULL, block != NULL), block);
if (popped) PUSH_INSN(ret, location, pop);

if (cast->block != NULL) {
PUSH_LABEL(ret, retry_end_l);
PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, block, retry_end_l);
ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
}

if (popped) PUSH_INSN(ret, location, pop);
return;
}
case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: {
Expand Down Expand Up @@ -8271,20 +8291,27 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,

DECL_ANCHOR(args);
INIT_ANCHOR(args);
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;

LABEL *retry_label = NEW_LABEL(location.line);
LABEL *retry_end_l = NEW_LABEL(location.line);

const rb_iseq_t *previous_block = ISEQ_COMPILE_DATA(iseq)->current_block;
const rb_iseq_t *current_block;
ISEQ_COMPILE_DATA(iseq)->current_block = current_block = NULL;

PUSH_LABEL(ret, retry_label);
PUSH_INSN(ret, location, putself);

int flags = 0;
struct rb_callinfo_kwarg *keywords = NULL;
int argc = pm_setup_args(cast->arguments, cast->block, &flags, &keywords, iseq, ret, scope_node, &location);
flags |= VM_CALL_SUPER | VM_CALL_FCALL;

const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
if (cast->block && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)) {
pm_scope_node_t next_scope_node;
pm_scope_node_init(cast->block, &next_scope_node, scope_node);
parent_block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);

ISEQ_COMPILE_DATA(iseq)->current_block = current_block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
pm_scope_node_destroy(&next_scope_node);
}

Expand All @@ -8293,9 +8320,13 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
}

PUSH_SEQ(ret, args);
PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flags, keywords, parent_block != NULL), parent_block);

PUSH_INSN2(ret, location, invokesuper, new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL), current_block);
PUSH_LABEL(ret, retry_end_l);
if (popped) PUSH_INSN(ret, location, pop);

ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, current_block, retry_end_l);

return;
}
case PM_SYMBOL_NODE: {
Expand Down
1 change: 0 additions & 1 deletion spec/prism.mspec
@@ -1,7 +1,6 @@
# frozen_string_literal: true

## Language
MSpec.register(:exclude, "Executing break from within a block works when passing through a super call")
MSpec.register(:exclude, "The defined? keyword when called with a method name in a void context warns about the void context when parsing it")
MSpec.register(:exclude, "Hash literal expands an '**{}' or '**obj' element with the last key/value pair taking precedence")
MSpec.register(:exclude, "Hash literal expands an '**{}' and warns when finding an additional duplicate key afterwards")
Expand Down

0 comments on commit 58f93ee

Please sign in to comment.