Project

General

Profile

Feature #14183 ยป vm_args.diff

jeremyevans0 (Jeremy Evans), 03/25/2019 10:48 PM

View differences:

vm_args.c
513 513
    return ST_CONTINUE;
514 514
}
515 515

  
516
static inline int
517
ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq) {
518
    if (keyword_hash == rb_no_keyword_hash) {
519
	return 1;
520
    } else if (!(iseq->body->param.flags.has_kw) &&
521
	      !(iseq->body->param.flags.has_kwrest)) {
522
	keyword_hash = rb_check_hash_type(keyword_hash);
523

  
524
	if (!NIL_P(keyword_hash) && RHASH_EMPTY_P(keyword_hash)) {
525
	    return 1;
526
	}
527
    }
528

  
529
    return 0;
530
}
531

  
516 532
static inline VALUE
517 533
get_loc(struct rb_calling_info *calling, const struct rb_call_info *ci)
518 534
{
......
533 549
    }
534 550
}
535 551

  
536
static inline void
537
rb_warn_keyword_to_last_hash(struct rb_calling_info *calling, const struct rb_call_info *ci)
538
{
539
    if (calling->recv == Qundef) return;
540
    VALUE loc = get_loc(calling, ci);
541
    if (NIL_P(loc)) {
542
        rb_warn("The keyword argument for `%s' is used as the last parameter", rb_id2name(ci->mid));
543
    }
544
    else {
545
        rb_warn("The keyword argument for `%s' (defined at %s:%d) is used as the last parameter",
546
                rb_id2name(ci->mid), RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)));
547
    }
548
}
549

  
550 552
static int
551 553
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
552 554
			 struct rb_calling_info *const calling,
......
563 565
    VALUE keyword_hash = Qnil;
564 566
    VALUE * const orig_sp = ec->cfp->sp;
565 567
    unsigned int i;
566
    int k2n_warned = FALSE;
567 568

  
568 569
    vm_check_canary(ec, orig_sp);
569 570
    /*
......
619 620
	given_argc += RARRAY_LENINT(args->rest) - 1;
620 621
        if (kw_flag & VM_CALL_KW_SPLAT) {
621 622
            int len = RARRAY_LENINT(args->rest);
622
            if (len > 0 && RARRAY_AREF(args->rest, len - 1) == rb_no_keyword_hash) {
623
            if (len > 0 && ignore_keyword_hash_p(RARRAY_AREF(args->rest, len - 1), iseq)) {
623 624
                arg_rest_dup(args);
624 625
                rb_ary_pop(args->rest);
625 626
                given_argc--;
626 627
                kw_flag &= ~VM_CALL_KW_SPLAT;
627
            }
628
	    }
628 629
        }
629 630
    }
630 631
    else {
631 632
        if (kw_flag & VM_CALL_KW_SPLAT) {
632
            if (args->argv[args->argc-1] == rb_no_keyword_hash) {
633
            if (ignore_keyword_hash_p(args->argv[args->argc-1], iseq)) {
633 634
                args->argc--;
634 635
                given_argc--;
635 636
                kw_flag &= ~VM_CALL_KW_SPLAT;
636
            }
637
	    }
637 638
        }
638 639
	args->rest = Qfalse;
639 640
    }
......
655 656
    /* argc check */
656 657
    if (given_argc < min_argc) {
657 658
	if (given_argc == min_argc - 1 && args->kw_argv) {
658
	    /* Warn the following:
659
	     * def foo(a, k:1) p [a, k] end
660
	     * foo(k:42) #=> [{:k=>42}, 1]
661
	     */
662
            rb_warn_keyword_to_last_hash(calling, ci);
663
	    k2n_warned = TRUE;
664 659
	    args_stored_kw_argv_to_hash(args);
665 660
	    given_argc = args_argc(args);
666 661
	}
......
702 697
	    }
703 698
	}
704 699
    }
705
    else if (!k2n_warned &&
706
	    !((kw_flag & VM_CALL_KWARG) && iseq->body->param.flags.has_kw) &&
707
	    given_argc == min_argc + 1 &&
708
	    (kw_flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT))) {
709
	/* Warn the following:
710
	 * def foo(x, opt=1) p [x]; end
711
	 * foo(k:42) #=> [{:k=>42}]
712
	 */
713
        rb_warn_keyword_to_last_hash(calling, ci);
714
    }
715 700

  
716 701
    if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
717 702
	if (arg_setup_type == arg_setup_block) {
......
897 882
    VALUE *sp = cfp->sp;
898 883
    int i;
899 884

  
900
    /* Warn the following:
901
     * def foo(x) p [x] end
902
     * foo(k:42) #=> [{:k=>42}]
903
     */
904
    if (!cfunc) {
905
        rb_warn_keyword_to_last_hash(calling, ci);
906
    }
907

  
908 885
    for (i=0; i<kw_len; i++) {
909 886
	rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
910 887
    }