Feature #16891 ยป keyword-hash-integration.diff
vm_args.c | ||
---|---|---|
return ary;
|
||
}
|
||
static int
|
||
keyword_hash_has_symbol_p_iter(st_data_t key, st_data_t val, st_data_t arg)
|
||
{
|
||
if (SYMBOL_P((VALUE)key)) {
|
||
*(int*)arg |= 1;
|
||
return ST_STOP;
|
||
}
|
||
return ST_CONTINUE;
|
||
}
|
||
static int
|
||
keyword_hash_has_symbol_p(VALUE kw_hash) {
|
||
int has_symbol = 0;
|
||
rb_hash_stlike_foreach(kw_hash, keyword_hash_has_symbol_p_iter, (st_data_t)(&has_symbol));
|
||
return has_symbol;
|
||
}
|
||
static int
|
||
keyword_hash_p(VALUE *kw_hash_ptr, int check_symbol)
|
||
{
|
||
*kw_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
|
||
if (NIL_P(*kw_hash_ptr)) {
|
||
return FALSE;
|
||
}
|
||
if (!check_symbol || RHASH_EMPTY_P(*kw_hash_ptr) ||
|
||
keyword_hash_has_symbol_p(*kw_hash_ptr)) {
|
||
return TRUE;
|
||
}
|
||
*kw_hash_ptr = Qnil;
|
||
return FALSE;
|
||
}
|
||
static VALUE
|
||
args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, int check_symbol)
|
||
{
|
||
if (args->rest == Qfalse) {
|
||
from_argv:
|
||
VM_ASSERT(args->argc > 0);
|
||
*kw_hash_ptr = args->argv[args->argc-1];
|
||
if (keyword_hash_p(kw_hash_ptr, check_symbol)) {
|
||
args->argc--;
|
||
return TRUE;
|
||
}
|
||
}
|
||
else {
|
||
long len = RARRAY_LEN(args->rest);
|
||
if (len > 0) {
|
||
*kw_hash_ptr = RARRAY_AREF(args->rest, len - 1);
|
||
if (keyword_hash_p(kw_hash_ptr, check_symbol)) {
|
||
arg_rest_dup(args);
|
||
rb_ary_pop(args->rest);
|
||
return TRUE;
|
||
}
|
||
}
|
||
else {
|
||
goto from_argv;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
static int
|
||
args_kw_argv_to_hash(struct args_info *args)
|
||
{
|
||
... | ... | |
RHASH_EMPTY_P(keyword_hash);
|
||
}
|
||
VALUE rb_iseq_location(const rb_iseq_t *iseq);
|
||
static st_table *caller_to_callees = 0;
|
||
static VALUE
|
||
rb_warn_check(const rb_execution_context_t * const ec, const rb_iseq_t *const iseq)
|
||
{
|
||
if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) return 1;
|
||
if (!iseq) return 0;
|
||
const st_data_t callee = (st_data_t)(iseq->body->iseq_unique_id * 2);
|
||
const rb_control_frame_t * const cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
||
if (!cfp) return 0;
|
||
const st_data_t caller = (st_data_t)cfp->pc;
|
||
if (!caller_to_callees) {
|
||
caller_to_callees = st_init_numtable();
|
||
}
|
||
st_data_t val;
|
||
if (st_lookup(caller_to_callees, caller, &val)) {
|
||
st_table *callees;
|
||
if (val & 1) {
|
||
val &= ~(st_data_t)1;
|
||
if (val == callee) return 1; /* already warned */
|
||
callees = st_init_numtable();
|
||
st_insert(callees, val, 1);
|
||
}
|
||
else {
|
||
callees = (st_table *) val;
|
||
if (st_is_member(callees, callee)) return 1; /* already warned */
|
||
}
|
||
st_insert(callees, callee, 1);
|
||
st_insert(caller_to_callees, caller, (st_data_t) callees);
|
||
}
|
||
else {
|
||
st_insert(caller_to_callees, caller, callee | 1);
|
||
}
|
||
return 0; /* not warned yet for the pair of caller and callee */
|
||
}
|
||
static inline void
|
||
rb_warn_last_hash_to_keyword(rb_execution_context_t * const ec,
|
||
struct rb_calling_info * const calling,
|
||
const struct rb_callinfo *ci,
|
||
const rb_iseq_t * const iseq)
|
||
{
|
||
if (rb_warn_check(ec, iseq)) return;
|
||
VALUE name, loc;
|
||
name = rb_id2str(vm_ci_mid(ci));
|
||
loc = rb_iseq_location(iseq);
|
||
if (NIL_P(loc)) {
|
||
rb_warning("Using the last argument for `%"PRIsVALUE"' as keyword parameters is deprecated; maybe ** should be added to the call",
|
||
name);
|
||
}
|
||
else {
|
||
rb_warning("Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call");
|
||
if (calling->recv != Qundef) {
|
||
rb_compile_warning(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)),
|
||
"The called method `%"PRIsVALUE"' is defined here", name);
|
||
}
|
||
else {
|
||
rb_compile_warning(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)),
|
||
"The called method is defined here");
|
||
}
|
||
}
|
||
}
|
||
static int
|
||
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
|
||
struct rb_calling_info *const calling,
|
||
... | ... | |
}
|
||
}
|
||
if (!kw_flag && args->kw_argv == NULL &&
|
||
(iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) &&
|
||
given_argc > min_argc &&
|
||
args_pop_keyword_hash(args, &keyword_hash, !iseq->body->param.flags.has_kwrest)) {
|
||
rb_warn_last_hash_to_keyword(ec, calling, ci, iseq);
|
||
given_argc--;
|
||
}
|
||
if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
|
||
if (arg_setup_type == arg_setup_block) {
|
||
/* truncate */
|