[Bug #19175] p_rest should be `assignable'

It should also check for duplicate names.
This commit is contained in:
Kazuki Tsujimoto 2023-03-26 15:33:43 +09:00
Родитель 2f916812a9
Коммит 6c0925ba70
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: BCEA306C49B81CD7
3 изменённых файлов: 55 добавлений и 38 удалений

59
parse.y
Просмотреть файл

@ -761,9 +761,9 @@ static bool args_info_empty_p(struct rb_args_info *args);
static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYLTYPE*);
static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
static NODE *new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc);
static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc);
static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
static NODE *new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
static NODE *new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc);
static NODE *new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
static NODE *new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc);
static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc);
@ -1116,12 +1116,6 @@ new_array_pattern_tail(struct parser_params *p, VALUE pre_args, VALUE has_rest,
{
NODE *t;
if (has_rest) {
rest_arg = dispatch1(var_field, rest_arg ? rest_arg : Qnil);
}
else {
rest_arg = Qnil;
}
t = rb_node_newnode(NODE_ARYPTN, pre_args, rest_arg, post_args, &NULL_LOC);
add_mark_object(p, pre_args);
@ -1144,9 +1138,6 @@ new_find_pattern_tail(struct parser_params *p, VALUE pre_rest_arg, VALUE args, V
{
NODE *t;
pre_rest_arg = dispatch1(var_field, pre_rest_arg ? pre_rest_arg : Qnil);
post_rest_arg = dispatch1(var_field, post_rest_arg ? post_rest_arg : Qnil);
t = rb_node_newnode(NODE_FNDPTN, pre_rest_arg, args, post_rest_arg, &NULL_LOC);
add_mark_object(p, pre_rest_arg);
add_mark_object(p, args);
@ -1485,13 +1476,13 @@ static int looking_at_eol_p(struct parser_params *p);
%type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
%type <node> p_expr p_as p_alt p_expr_basic p_find
%type <node> p_args p_args_head p_args_tail p_args_post p_arg
%type <node> p_args p_args_head p_args_tail p_args_post p_arg p_rest
%type <node> p_value p_primitive p_variable p_var_ref p_expr_ref p_const
%type <node> p_kwargs p_kwarg p_kw
%type <id> keyword_variable user_variable sym operation operation2 operation3
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
%type <id> f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
%type <id> p_rest p_kwrest p_kwnorest p_any_kwrest p_kw_label
%type <id> p_kwrest p_kwnorest p_any_kwrest p_kw_label
%type <id> f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var
%type <ctxt> lex_ctxt /* keep <ctxt> in ripper */
%token END_OF_INPUT 0 "end-of-input"
@ -4439,7 +4430,7 @@ p_top_expr : p_top_expr_body
p_top_expr_body : p_expr
| p_expr ','
{
$$ = new_array_pattern_tail(p, Qnone, 1, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, Qnone, 1, Qnone, Qnone, &@$);
$$ = new_array_pattern(p, Qnone, get_value($1), $$, &@$);
}
| p_expr ',' p_args
@ -4523,7 +4514,7 @@ p_expr_basic : p_value
}
| p_const '(' rparen
{
$$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
$$ = new_array_pattern(p, $1, Qnone, $$, &@$);
}
| p_const p_lbracket p_args rbracket
@ -4555,7 +4546,7 @@ p_expr_basic : p_value
}
| p_const '[' rbracket
{
$$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
$$ = new_array_pattern(p, $1, Qnone, $$, &@$);
}
| tLBRACK p_args rbracket
@ -4568,7 +4559,7 @@ p_expr_basic : p_value
}
| tLBRACK rbracket
{
$$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, Qnone, 0, Qnone, Qnone, &@$);
$$ = new_array_pattern(p, Qnone, Qnone, $$, &@$);
}
| tLBRACE
@ -4599,22 +4590,22 @@ p_args : p_expr
{
/*%%%*/
NODE *pre_args = NEW_LIST($1, &@$);
$$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, pre_args, 0, Qnone, Qnone, &@$);
/*%
$$ = new_array_pattern_tail(p, rb_ary_new_from_args(1, get_value($1)), 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, rb_ary_new_from_args(1, get_value($1)), 0, Qnone, Qnone, &@$);
%*/
}
| p_args_head
{
$$ = new_array_pattern_tail(p, $1, 1, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, $1, 1, Qnone, Qnone, &@$);
}
| p_args_head p_arg
{
/*%%%*/
$$ = new_array_pattern_tail(p, list_concat($1, $2), 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, list_concat($1, $2), 0, Qnone, Qnone, &@$);
/*%
VALUE pre_args = rb_ary_concat($1, get_value($2));
$$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
$$ = new_array_pattern_tail(p, pre_args, 0, Qnone, Qnone, &@$);
%*/
}
| p_args_head p_rest
@ -4660,11 +4651,18 @@ p_find : p_rest ',' p_args_post ',' p_rest
p_rest : tSTAR tIDENTIFIER
{
$$ = $2;
/*%%%*/
error_duplicate_pattern_variable(p, $2, &@2);
$$ = assignable(p, $2, 0, &@$);
/*% %*/
/*% ripper: assignable(p, var_field(p, $2)) %*/
}
| tSTAR
{
/*%%%*/
$$ = 0;
/*% %*/
/*% ripper: Qnil %*/
}
;
@ -12687,7 +12685,7 @@ new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *
}
static NODE*
new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc)
new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc)
{
int saved_line = p->ruby_sourceline;
NODE *node;
@ -12700,12 +12698,7 @@ new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID
apinfo->pre_args = pre_args;
if (has_rest) {
if (rest_arg) {
apinfo->rest_arg = assignable(p, rest_arg, 0, loc);
}
else {
apinfo->rest_arg = NODE_SPECIAL_NO_NAME_REST;
}
apinfo->rest_arg = rest_arg ? rest_arg : NODE_SPECIAL_NO_NAME_REST;
}
else {
apinfo->rest_arg = NULL;
@ -12726,7 +12719,7 @@ new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YY
}
static NODE*
new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc)
new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc)
{
int saved_line = p->ruby_sourceline;
NODE *node;
@ -12736,9 +12729,9 @@ new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID p
node = NEW_NODE(NODE_FNDPTN, 0, tmpbuf, fpinfo, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
fpinfo->pre_rest_arg = pre_rest_arg ? assignable(p, pre_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
fpinfo->pre_rest_arg = pre_rest_arg ? pre_rest_arg : NODE_SPECIAL_NO_NAME_REST;
fpinfo->args = args;
fpinfo->post_rest_arg = post_rest_arg ? assignable(p, post_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
fpinfo->post_rest_arg = post_rest_arg ? post_rest_arg : NODE_SPECIAL_NO_NAME_REST;
p->ruby_sourceline = saved_line;
return node;

Просмотреть файл

@ -175,7 +175,7 @@ eot
[:aryptn,
nil,
[[:var_field, [:@ident, "a", [1, 11]]]],
[:var_field, nil],
nil,
nil],
[[:void_stmt]],
nil]],
@ -229,7 +229,7 @@ eot
[__LINE__, %q{ case 0; in *; end }] =>
[:case,
[:@int, "0", [1, 5]],
[:in, [:aryptn, nil, nil, [:var_field, nil], nil], [[:void_stmt]], nil]],
[:in, [:aryptn, nil, nil, nil, nil], [[:void_stmt]], nil]],
[__LINE__, %q{ case 0; in *,a; end }] =>
[:case,
@ -238,7 +238,7 @@ eot
[:aryptn,
nil,
nil,
[:var_field, nil],
nil,
[[:var_field, [:@ident, "a", [1, 13]]]]],
[[:void_stmt]],
nil]],
@ -407,6 +407,14 @@ eot
[[:void_stmt]],
nil]],
[__LINE__, %q{ case 0; in [a,]; end }] =>
[:case,
[:@int, "0", [1, 5]],
[:in,
[:aryptn, nil, [[:var_field, [:@ident, "a", [1, 12]]]], nil, nil],
[[:void_stmt]],
nil]],
[__LINE__, %q{ case 0; in []; end }] =>
[:case,
[:@int, "0", [1, 5]],
@ -418,9 +426,9 @@ eot
[:in,
[:fndptn,
nil,
[:var_field, nil],
nil,
[[:var_field, [:@ident, "a", [1, 9]]]],
[:var_field, nil]],
nil],
nil,
nil]],
@ -486,6 +494,14 @@ eot
[:begin, [:binary, [:@int, "0", [1, 13]], :+, [:@int, "0", [1, 15]]]],
[[:void_stmt]],
nil]],
[__LINE__, %q{ case 0; in [*a]; a; end } ] =>
[:case,
[:@int, "0", [1, 5]],
[:in,
[:aryptn, nil, nil, [:var_field, [:@ident, "a", [1, 13]]], nil],
[[:var_ref, [:@ident, "a", [1, 17]]]],
nil]],
}
pattern_matching_data.each do |(i, src), expected|
define_method(:"test_pattern_matching_#{i}") do

Просмотреть файл

@ -800,6 +800,10 @@ END
true
end
end
assert_syntax_error(%q{
0 => [a, *a]
}, /duplicated variable name/)
end
def test_find_pattern
@ -868,6 +872,10 @@ END
false
end
end
assert_syntax_error(%q{
0 => [*a, a, b, *b]
}, /duplicated variable name/)
end
def test_hash_pattern