aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compile.c3
-rw-r--r--node.h1
-rw-r--r--parse.y14
-rw-r--r--test/ruby/test_keyword.rb28
-rw-r--r--test/ruby/test_syntax.rb16
-rw-r--r--vm_args.c4
-rw-r--r--vm_core.h1
7 files changed, 67 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index 63b893d7de..d11e2f9f32 100644
--- a/compile.c
+++ b/compile.c
@@ -1700,6 +1700,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
body->param.keyword = keyword;
body->param.flags.has_kwrest = TRUE;
}
+ else if (args->no_kwarg) {
+ body->param.flags.accepts_no_kwarg = TRUE;
+ }
if (block_id) {
body->param.block_start = arg_size++;
diff --git a/node.h b/node.h
index 3741e649ca..3b565fc083 100644
--- a/node.h
+++ b/node.h
@@ -450,6 +450,7 @@ struct rb_args_info {
NODE *kw_rest_arg;
NODE *opt_args;
+ int no_kwarg;
};
struct rb_ary_pattern_info {
diff --git a/parse.y b/parse.y
index 4dfdd5d2a3..c7c43e3278 100644
--- a/parse.y
+++ b/parse.y
@@ -3245,6 +3245,10 @@ block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
{
$$ = new_args_tail(p, Qnone, $1, $2, &@1);
}
+ | f_no_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, rb_intern("nil"), $2, &@1);
+ }
| f_block_arg
{
$$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
@@ -4712,6 +4716,10 @@ args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
{
$$ = new_args_tail(p, Qnone, $1, $2, &@1);
}
+ | f_no_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, rb_intern("nil"), $2, &@1);
+ }
| f_block_arg
{
$$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
@@ -4968,6 +4976,9 @@ kwrest_mark : tPOW
| tDSTAR
;
+f_no_kwarg : kwrest_mark keyword_nil
+ ;
+
f_kwrest : kwrest_mark tIDENTIFIER
{
arg_var(p, shadowing_lvar(p, get_id($2)));
@@ -11125,6 +11136,9 @@ new_args_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, ID block,
args->kw_rest_arg = NEW_DVAR(kw_rest_arg, loc);
args->kw_rest_arg->nd_cflag = kw_bits;
}
+ else if (kw_rest_arg == rb_intern("nil")) {
+ args->no_kwarg = 1;
+ }
else if (kw_rest_arg) {
args->kw_rest_arg = NEW_DVAR(kw_rest_arg, loc);
}
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index 791d60b70a..1e707170fd 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -126,6 +126,34 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal(1, f10(b: 42))
end
+ def f11(**nil)
+ local_variables
+ end
+
+ def test_f11
+ h = {}
+
+ assert_equal([], f11)
+ assert_equal([], f11(**{}))
+ assert_equal([], f11(**h))
+ end
+
+ def f12(**nil, &b)
+ [b, local_variables]
+ end
+
+ def test_f12
+ h = {}
+ b = proc{}
+
+ assert_equal([nil, [:b]], f12)
+ assert_equal([nil, [:b]], f12(**{}))
+ assert_equal([nil, [:b]], f12(**h))
+ assert_equal([b, [:b]], f12(&b))
+ assert_equal([b, [:b]], f12(**{}, &b))
+ assert_equal([b, [:b]], f12(**h, &b))
+ end
+
def test_method_parameters
assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters);
assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters);
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 02a95bc60b..72a3cc2fc7 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -249,6 +249,22 @@ class TestSyntax < Test::Unit::TestCase
assert_syntax_error('def o.foo(@@foo: a) end', /class variable/)
end
+ def test_keywords_specified_and_not_accepted
+ assert_syntax_error('def o.foo(a:, **nil) end', /unexpected/)
+ assert_syntax_error('def o.foo(a:, **nil, &b) end', /unexpected/)
+ assert_syntax_error('def o.foo(**a, **nil) end', /unexpected/)
+ assert_syntax_error('def o.foo(**a, **nil, &b) end', /unexpected/)
+ assert_syntax_error('def o.foo(**nil, **a) end', /unexpected/)
+ assert_syntax_error('def o.foo(**nil, **a, &b) end', /unexpected/)
+
+ assert_syntax_error('proc do |a:, **nil| end', /unexpected/)
+ assert_syntax_error('proc do |a:, **nil, &b| end', /unexpected/)
+ assert_syntax_error('proc do |**a, **nil| end', /unexpected/)
+ assert_syntax_error('proc do |**a, **nil, &b| end', /unexpected/)
+ assert_syntax_error('proc do |**nil, **a| end', /unexpected/)
+ assert_syntax_error('proc do |**nil, **a, &b| end', /unexpected/)
+ end
+
def test_optional_self_reference
bug9593 = '[ruby-core:61299] [Bug #9593]'
o = Object.new
diff --git a/vm_args.c b/vm_args.c
index 4e404870da..4eccb62da6 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -702,6 +702,10 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
args->rest = Qfalse;
}
+ if (kw_flag && iseq->body->param.flags.accepts_no_kwarg) {
+ rb_raise(rb_eArgError, "no keywords accepted");
+ }
+
switch (arg_setup_type) {
case arg_setup_method:
break; /* do nothing special */
diff --git a/vm_core.h b/vm_core.h
index cb22fc4115..479698932e 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -385,6 +385,7 @@ struct rb_iseq_constant_body {
unsigned int has_block : 1;
unsigned int ambiguous_param0 : 1; /* {|a|} */
+ unsigned int accepts_no_kwarg : 1;
} flags;
unsigned int size;