relax unused block warning for duck typing
if a method `foo` uses a block, other (unrelated) method `foo` can receives a block. So try to relax the unused block warning condition. ```ruby class C0 def f = yield end class C1 < C0 def f = nil end [C0, C1].f{ block } # do not warn ```
This commit is contained in:
parent
6ade36c06b
commit
e9d7478ded
23
compile.c
23
compile.c
@ -1998,6 +1998,19 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
|
||||
return arg_size;
|
||||
}
|
||||
|
||||
static void
|
||||
iseq_set_use_block(rb_iseq_t *iseq)
|
||||
{
|
||||
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
|
||||
if (!body->param.flags.use_block) {
|
||||
body->param.flags.use_block = 1;
|
||||
|
||||
rb_vm_t *vm = GET_VM();
|
||||
st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
|
||||
st_insert(vm->unused_block_warning_table, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
|
||||
{
|
||||
@ -2099,7 +2112,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
|
||||
if (block_id) {
|
||||
body->param.block_start = arg_size++;
|
||||
body->param.flags.has_block = TRUE;
|
||||
body->param.flags.use_block = 1;
|
||||
iseq_set_use_block(iseq);
|
||||
}
|
||||
|
||||
iseq_calc_param_size(iseq);
|
||||
@ -5920,7 +5933,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
||||
ADD_INSN(ret, line_node, putnil);
|
||||
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
|
||||
PUSH_VAL(DEFINED_YIELD));
|
||||
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
|
||||
iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
|
||||
return;
|
||||
|
||||
case NODE_BACK_REF:
|
||||
@ -8632,7 +8645,7 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
|
||||
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
|
||||
}
|
||||
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
|
||||
ISEQ_BODY(iseq)->param.flags.use_block = 1;
|
||||
iseq_set_use_block(iseq);
|
||||
}
|
||||
else {
|
||||
goto unknown_arg;
|
||||
@ -9481,7 +9494,7 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
|
||||
}
|
||||
|
||||
if (use_block && parent_block == NULL) {
|
||||
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
|
||||
iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
|
||||
}
|
||||
|
||||
flag |= VM_CALL_SUPER | VM_CALL_FCALL;
|
||||
@ -9527,7 +9540,7 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
|
||||
|
||||
ADD_SEQ(ret, args);
|
||||
ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
|
||||
ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.use_block = 1;
|
||||
iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
|
||||
|
||||
if (popped) {
|
||||
ADD_INSN(ret, node, pop);
|
||||
|
@ -1692,5 +1692,19 @@ class TestMethod < Test::Unit::TestCase
|
||||
assert_match(/-:23: warning.+f5/, err.join)
|
||||
assert_match(/-:24: warning.+f6/, err.join)
|
||||
end
|
||||
|
||||
assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
|
||||
class C0
|
||||
def f = yield
|
||||
end
|
||||
|
||||
class C1 < C0
|
||||
def f = nil
|
||||
end
|
||||
|
||||
C1.new.f{} # do not warn on duck typing
|
||||
RUBY
|
||||
assert_equal 0, err.size, err.join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
1
vm.c
1
vm.c
@ -4254,6 +4254,7 @@ Init_BareVM(void)
|
||||
vm->negative_cme_table = rb_id_table_create(16);
|
||||
vm->overloaded_cme_table = st_init_numtable();
|
||||
vm->constant_cache = rb_id_table_create(0);
|
||||
vm->unused_block_warning_table = st_init_numtable();
|
||||
|
||||
// setup main thread
|
||||
th->nt = ZALLOC(struct rb_native_thread);
|
||||
|
@ -773,6 +773,7 @@ typedef struct rb_vm_struct {
|
||||
st_table *ci_table;
|
||||
struct rb_id_table *negative_cme_table;
|
||||
st_table *overloaded_cme_table; // cme -> overloaded_cme
|
||||
st_table *unused_block_warning_table;
|
||||
|
||||
// This id table contains a mapping from ID to ICs. It does this with ID
|
||||
// keys and nested st_tables as values. The nested tables have ICs as keys
|
||||
|
@ -2971,9 +2971,9 @@ VALUE rb_gen_method_name(VALUE owner, VALUE name); // in vm_backtrace.c
|
||||
static void
|
||||
warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, void *pc)
|
||||
{
|
||||
static st_table *dup_check_table = NULL;
|
||||
rb_vm_t *vm = GET_VM();
|
||||
st_table *dup_check_table = vm->unused_block_warning_table;
|
||||
|
||||
st_data_t key = 0;
|
||||
union {
|
||||
VALUE v;
|
||||
unsigned char b[SIZEOF_VALUE];
|
||||
@ -2983,6 +2983,14 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
||||
.v = (VALUE)cme->def,
|
||||
};
|
||||
|
||||
// relax check
|
||||
st_data_t key = (st_data_t)cme->def->original_id;
|
||||
|
||||
if (st_lookup(dup_check_table, key, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// strict check
|
||||
// make unique key from pc and me->def pointer
|
||||
for (int i=0; i<SIZEOF_VALUE; i++) {
|
||||
// fprintf(stderr, "k1:%3d k2:%3d\n", k1.b[i], k2.b[SIZEOF_VALUE-1-i]);
|
||||
@ -2995,10 +3003,6 @@ warn_unused_block(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq,
|
||||
fprintf(stderr, "key:%p\n", (void *)key);
|
||||
}
|
||||
|
||||
if (!dup_check_table) {
|
||||
dup_check_table = st_init_numtable();
|
||||
}
|
||||
|
||||
// duplication check
|
||||
if (st_insert(dup_check_table, key, 1)) {
|
||||
// already shown
|
||||
|
Loading…
x
Reference in New Issue
Block a user