[Bug #20218] Reject keyword arguments in index

This commit is contained in:
Nobuyoshi Nakada 2024-02-20 11:59:36 +09:00
Родитель df5ef28233
Коммит 0d5b16599a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 3582D74E1FEE4465
7 изменённых файлов: 152 добавлений и 563 удалений

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

@ -1088,10 +1088,6 @@ assert_equal 'ok', %q{
'ok'
end
}
assert_equal 'ok', %q{
[0][0, &proc{}] += 21
'ok'
}, '[ruby-core:30534]'
# should not cache when splat
assert_equal 'ok', %q{

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

@ -13872,12 +13872,38 @@ new_bv(struct parser_params *p, ID name)
dyna_var(p, name);
}
static void
aryset_check(struct parser_params *p, NODE *args)
{
NODE *block = 0, *kwds = 0;
if (args && nd_type_p(args, NODE_BLOCK_PASS)) {
block = RNODE_BLOCK_PASS(args)->nd_body;
args = RNODE_BLOCK_PASS(args)->nd_head;
}
if (args && nd_type_p(args, NODE_ARGSCAT)) {
args = RNODE_ARGSCAT(args)->nd_body;
}
if (args && nd_type_p(args, NODE_ARGSPUSH)) {
kwds = RNODE_ARGSPUSH(args)->nd_body;
}
else {
for (NODE *next = args; next && nd_type_p(next, NODE_LIST);
next = RNODE_LIST(next)->nd_next) {
kwds = RNODE_LIST(next)->nd_head;
}
}
if (kwds && nd_type_p(kwds, NODE_HASH) && !RNODE_HASH(kwds)->nd_brace) {
yyerror1(&kwds->nd_loc, "keyword arg given in index");
}
if (block) {
yyerror1(&block->nd_loc, "block arg given in index");
}
}
static NODE *
aryset(struct parser_params *p, NODE *recv, NODE *idx, const YYLTYPE *loc)
{
if (idx && nd_type_p(idx, NODE_BLOCK_PASS)) {
compile_error(p, "block arg given in index");
}
aryset_check(p, idx);
return NEW_ATTRASGN(recv, tASET, idx, loc);
}
@ -15334,6 +15360,7 @@ new_ary_op_assign(struct parser_params *p, NODE *ary,
{
NODE *asgn;
aryset_check(p, args);
args = make_list(args, args_loc);
asgn = NEW_OP_ASGN1(ary, op, args, rhs, loc);
fixpos(asgn, ary);

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

@ -113,17 +113,17 @@ foo.foo[bar] ||= 1
foo.foo[bar] &&= 1
foo[bar, &baz] += 1
# foo[bar, &baz] += 1
foo[bar, &baz] ||= 1
# foo[bar, &baz] ||= 1
foo[bar, &baz] &&= 1
# foo[bar, &baz] &&= 1
foo.foo[bar, &baz] += 1
# foo.foo[bar, &baz] += 1
foo.foo[bar, &baz] ||= 1
# foo.foo[bar, &baz] ||= 1
foo.foo[bar, &baz] &&= 1
# foo.foo[bar, &baz] &&= 1
def f(*); a[*]; end

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

@ -2,7 +2,7 @@
├── locals: []
└── statements:
@ StatementsNode (location: (1,0)-(142,32))
└── body: (length: 56)
└── body: (length: 50)
├── @ ArrayNode (location: (1,0)-(1,4))
│ ├── flags: contains_splat
│ ├── elements: (length: 1)
@ -1360,332 +1360,6 @@
│ @ IntegerNode (location: (114,17)-(114,18))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexOperatorWriteNode (location: (116,0)-(116,19))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (116,0)-(116,3))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :foo
│ │ ├── message_loc: (116,0)-(116,3) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (116,3)-(116,4) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (116,4)-(116,7))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (116,4)-(116,7))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (116,4)-(116,7) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (116,13)-(116,14) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (116,9)-(116,13))
│ │ ├── expression:
│ │ │ @ CallNode (location: (116,10)-(116,13))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (116,10)-(116,13) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (116,9)-(116,10) = "&"
│ ├── operator: :+
│ ├── operator_loc: (116,15)-(116,17) = "+="
│ └── value:
│ @ IntegerNode (location: (116,18)-(116,19))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexOrWriteNode (location: (118,0)-(118,20))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (118,0)-(118,3))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :foo
│ │ ├── message_loc: (118,0)-(118,3) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (118,3)-(118,4) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (118,4)-(118,7))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (118,4)-(118,7))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (118,4)-(118,7) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (118,13)-(118,14) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (118,9)-(118,13))
│ │ ├── expression:
│ │ │ @ CallNode (location: (118,10)-(118,13))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (118,10)-(118,13) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (118,9)-(118,10) = "&"
│ ├── operator_loc: (118,15)-(118,18) = "||="
│ └── value:
│ @ IntegerNode (location: (118,19)-(118,20))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexAndWriteNode (location: (120,0)-(120,20))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (120,0)-(120,3))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :foo
│ │ ├── message_loc: (120,0)-(120,3) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (120,3)-(120,4) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (120,4)-(120,7))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (120,4)-(120,7))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (120,4)-(120,7) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (120,13)-(120,14) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (120,9)-(120,13))
│ │ ├── expression:
│ │ │ @ CallNode (location: (120,10)-(120,13))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (120,10)-(120,13) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (120,9)-(120,10) = "&"
│ ├── operator_loc: (120,15)-(120,18) = "&&="
│ └── value:
│ @ IntegerNode (location: (120,19)-(120,20))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexOperatorWriteNode (location: (122,0)-(122,23))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (122,0)-(122,7))
│ │ ├── flags: ∅
│ │ ├── receiver:
│ │ │ @ CallNode (location: (122,0)-(122,3))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :foo
│ │ │ ├── message_loc: (122,0)-(122,3) = "foo"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── call_operator_loc: (122,3)-(122,4) = "."
│ │ ├── name: :foo
│ │ ├── message_loc: (122,4)-(122,7) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (122,7)-(122,8) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (122,8)-(122,11))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (122,8)-(122,11))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (122,8)-(122,11) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (122,17)-(122,18) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (122,13)-(122,17))
│ │ ├── expression:
│ │ │ @ CallNode (location: (122,14)-(122,17))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (122,14)-(122,17) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (122,13)-(122,14) = "&"
│ ├── operator: :+
│ ├── operator_loc: (122,19)-(122,21) = "+="
│ └── value:
│ @ IntegerNode (location: (122,22)-(122,23))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexOrWriteNode (location: (124,0)-(124,24))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (124,0)-(124,7))
│ │ ├── flags: ∅
│ │ ├── receiver:
│ │ │ @ CallNode (location: (124,0)-(124,3))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :foo
│ │ │ ├── message_loc: (124,0)-(124,3) = "foo"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── call_operator_loc: (124,3)-(124,4) = "."
│ │ ├── name: :foo
│ │ ├── message_loc: (124,4)-(124,7) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (124,7)-(124,8) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (124,8)-(124,11))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (124,8)-(124,11))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (124,8)-(124,11) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (124,17)-(124,18) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (124,13)-(124,17))
│ │ ├── expression:
│ │ │ @ CallNode (location: (124,14)-(124,17))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (124,14)-(124,17) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (124,13)-(124,14) = "&"
│ ├── operator_loc: (124,19)-(124,22) = "||="
│ └── value:
│ @ IntegerNode (location: (124,23)-(124,24))
│ ├── flags: decimal
│ └── value: 1
├── @ IndexAndWriteNode (location: (126,0)-(126,24))
│ ├── flags: ∅
│ ├── receiver:
│ │ @ CallNode (location: (126,0)-(126,7))
│ │ ├── flags: ∅
│ │ ├── receiver:
│ │ │ @ CallNode (location: (126,0)-(126,3))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :foo
│ │ │ ├── message_loc: (126,0)-(126,3) = "foo"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ ├── call_operator_loc: (126,3)-(126,4) = "."
│ │ ├── name: :foo
│ │ ├── message_loc: (126,4)-(126,7) = "foo"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── call_operator_loc: ∅
│ ├── opening_loc: (126,7)-(126,8) = "["
│ ├── arguments:
│ │ @ ArgumentsNode (location: (126,8)-(126,11))
│ │ ├── flags: ∅
│ │ └── arguments: (length: 1)
│ │ └── @ CallNode (location: (126,8)-(126,11))
│ │ ├── flags: variable_call, ignore_visibility
│ │ ├── receiver: ∅
│ │ ├── call_operator_loc: ∅
│ │ ├── name: :bar
│ │ ├── message_loc: (126,8)-(126,11) = "bar"
│ │ ├── opening_loc: ∅
│ │ ├── arguments: ∅
│ │ ├── closing_loc: ∅
│ │ └── block: ∅
│ ├── closing_loc: (126,17)-(126,18) = "]"
│ ├── block:
│ │ @ BlockArgumentNode (location: (126,13)-(126,17))
│ │ ├── expression:
│ │ │ @ CallNode (location: (126,14)-(126,17))
│ │ │ ├── flags: variable_call, ignore_visibility
│ │ │ ├── receiver: ∅
│ │ │ ├── call_operator_loc: ∅
│ │ │ ├── name: :baz
│ │ │ ├── message_loc: (126,14)-(126,17) = "baz"
│ │ │ ├── opening_loc: ∅
│ │ │ ├── arguments: ∅
│ │ │ ├── closing_loc: ∅
│ │ │ └── block: ∅
│ │ └── operator_loc: (126,13)-(126,14) = "&"
│ ├── operator_loc: (126,19)-(126,22) = "&&="
│ └── value:
│ @ IntegerNode (location: (126,23)-(126,24))
│ ├── flags: decimal
│ └── value: 1
├── @ DefNode (location: (128,0)-(128,19))
│ ├── name: :f
│ ├── name_loc: (128,4)-(128,5) = "f"

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

@ -133,125 +133,127 @@ class TestCall < Test::Unit::TestCase
kw = {}
b = lambda{}
message = /keyword arg given in index/
# +=, without block, non-popped
assert_equal([[], {}, nil, [4], {}, nil], h.v{h[**kw] += 1})
assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, **kw] += 1})
assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, *a, **kw] += 1})
assert_equal([[], {kw: 5}, nil, [4], {kw: 5}, nil], h.v{h[kw: 5] += 1})
assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1})
assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1})
assert_equal([[0], {kw: 5, a: 2}, nil, [0, 4], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] += 1})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 4], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] += 1})
assert_syntax_error(%q{h[**kw] += 1}, message)
assert_syntax_error(%q{h[0, **kw] += 1}, message)
assert_syntax_error(%q{h[0, *a, **kw] += 1}, message)
assert_syntax_error(%q{h[kw: 5] += 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] += 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] += 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] += 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] += 1}, message)
# +=, with block, non-popped
assert_equal([[], {}, b, [4], {}, b], h.v{h[**kw, &b] += 1})
assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, **kw, &b] += 1})
assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, *a, **kw, &b] += 1})
assert_equal([[], {kw: 5}, b, [4], {kw: 5}, b], h.v{h[kw: 5, &b] += 1})
assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1})
assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1})
assert_equal([[0], {kw: 5, a: 2}, b, [0, 4], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] += 1})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 4], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1})
assert_syntax_error(%q{h[**kw, &b] += 1}, message)
assert_syntax_error(%q{h[0, **kw, &b] += 1}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] += 1}, message)
assert_syntax_error(%q{h[kw: 5, &b] += 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] += 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] += 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] += 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1}, message)
# +=, without block, popped
assert_equal([[], {}, nil, [4], {}, nil], h.v{h[**kw] += 1; nil})
assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, **kw] += 1; nil})
assert_equal([[0], {}, nil, [0, 4], {}, nil], h.v{h[0, *a, **kw] += 1; nil})
assert_equal([[], {kw: 5}, nil, [4], {kw: 5}, nil], h.v{h[kw: 5] += 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil, [4], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] += 1; nil})
assert_equal([[0], {kw: 5, a: 2}, nil, [0, 4], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] += 1; nil})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 4], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] += 1; nil})
assert_syntax_error(%q{h[**kw] += 1; nil}, message)
assert_syntax_error(%q{h[0, **kw] += 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] += 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] += 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] += 1; nil}, message)
# +=, with block, popped
assert_equal([[], {}, b, [4], {}, b], h.v{h[**kw, &b] += 1; nil})
assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, **kw, &b] += 1; nil})
assert_equal([[0], {}, b, [0, 4], {}, b], h.v{h[0, *a, **kw, &b] += 1; nil})
assert_equal([[], {kw: 5}, b, [4], {kw: 5}, b], h.v{h[kw: 5, &b] += 1; nil})
assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1; nil})
assert_equal([[], {kw: 5, a: 2}, b, [4], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] += 1; nil})
assert_equal([[0], {kw: 5, a: 2}, b, [0, 4], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] += 1; nil})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 4], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1; nil})
assert_syntax_error(%q{h[**kw, &b] += 1; nil}, message)
assert_syntax_error(%q{h[0, **kw, &b] += 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, &b] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] += 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] += 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] += 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] += 1; nil}, message)
# &&=, without block, non-popped
assert_equal([[], {}, nil, [1], {}, nil], h.v{h[**kw] &&= 1})
assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, **kw] &&= 1})
assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, *a, **kw] &&= 1})
assert_equal([[], {kw: 5}, nil, [1], {kw: 5}, nil], h.v{h[kw: 5] &&= 1})
assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1})
assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1})
assert_equal([[0], {kw: 5, a: 2}, nil, [0, 1], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] &&= 1})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 1], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1})
assert_syntax_error(%q{h[**kw] &&= 1}, message)
assert_syntax_error(%q{h[0, **kw] &&= 1}, message)
assert_syntax_error(%q{h[0, *a, **kw] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] &&= 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] &&= 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1}, message)
# &&=, with block, non-popped
assert_equal([[], {}, b, [1], {}, b], h.v{h[**kw, &b] &&= 1})
assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, **kw, &b] &&= 1})
assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, *a, **kw, &b] &&= 1})
assert_equal([[], {kw: 5}, b, [1], {kw: 5}, b], h.v{h[kw: 5, &b] &&= 1})
assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1})
assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1})
assert_equal([[0], {kw: 5, a: 2}, b, [0, 1], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] &&= 1})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 1], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1})
assert_syntax_error(%q{h[**kw, &b] &&= 1}, message)
assert_syntax_error(%q{h[0, **kw, &b] &&= 1}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5, &b] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] &&= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] &&= 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] &&= 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1}, message)
# &&=, without block, popped
assert_equal([[], {}, nil, [1], {}, nil], h.v{h[**kw] &&= 1; nil})
assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, **kw] &&= 1; nil})
assert_equal([[0], {}, nil, [0, 1], {}, nil], h.v{h[0, *a, **kw] &&= 1; nil})
assert_equal([[], {kw: 5}, nil, [1], {kw: 5}, nil], h.v{h[kw: 5] &&= 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil, [1], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] &&= 1; nil})
assert_equal([[0], {kw: 5, a: 2}, nil, [0, 1], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] &&= 1; nil})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil, [0, 1], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1; nil})
assert_syntax_error(%q{h[**kw] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, **kw] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] &&= 1; nil}, message)
# &&=, with block, popped
assert_equal([[], {}, b, [1], {}, b], h.v{h[**kw, &b] &&= 1; nil})
assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, **kw, &b] &&= 1; nil})
assert_equal([[0], {}, b, [0, 1], {}, b], h.v{h[0, *a, **kw, &b] &&= 1; nil})
assert_equal([[], {kw: 5}, b, [1], {kw: 5}, b], h.v{h[kw: 5, &b] &&= 1; nil})
assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1; nil})
assert_equal([[], {kw: 5, a: 2}, b, [1], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] &&= 1; nil})
assert_equal([[0], {kw: 5, a: 2}, b, [0, 1], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] &&= 1; nil})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b, [0, 1], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1; nil})
assert_syntax_error(%q{h[**kw, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, **kw, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] &&= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] &&= 1; nil}, message)
# ||=, without block, non-popped
assert_equal([[], {}, nil], h.v{h[**kw] ||= 1})
assert_equal([[0], {}, nil], h.v{h[0, **kw] ||= 1})
assert_equal([[0], {}, nil], h.v{h[0, *a, **kw] ||= 1})
assert_equal([[], {kw: 5}, nil], h.v{h[kw: 5] ||= 1})
assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1})
assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1})
assert_equal([[0], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] ||= 1})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1})
assert_syntax_error(%q{h[**kw] ||= 1}, message)
assert_syntax_error(%q{h[0, **kw] ||= 1}, message)
assert_syntax_error(%q{h[0, *a, **kw] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] ||= 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] ||= 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1}, message)
# ||=, with block, non-popped
assert_equal([[], {}, b], h.v{h[**kw, &b] ||= 1})
assert_equal([[0], {}, b], h.v{h[0, **kw, &b] ||= 1})
assert_equal([[0], {}, b], h.v{h[0, *a, **kw, &b] ||= 1})
assert_equal([[], {kw: 5}, b], h.v{h[kw: 5, &b] ||= 1})
assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1})
assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1})
assert_equal([[0], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] ||= 1})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1})
assert_syntax_error(%q{h[**kw, &b] ||= 1}, message)
assert_syntax_error(%q{h[0, **kw, &b] ||= 1}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5, &b] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] ||= 1}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] ||= 1}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] ||= 1}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1}, message)
# ||=, without block, popped
assert_equal([[], {}, nil], h.v{h[**kw] ||= 1; nil})
assert_equal([[0], {}, nil], h.v{h[0, **kw] ||= 1; nil})
assert_equal([[0], {}, nil], h.v{h[0, *a, **kw] ||= 1; nil})
assert_equal([[], {kw: 5}, nil], h.v{h[kw: 5] ||= 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1; nil})
assert_equal([[], {kw: 5, a: 2}, nil], h.v{h[kw: 5, a: 2] ||= 1; nil})
assert_equal([[0], {kw: 5, a: 2}, nil], h.v{h[0, kw: 5, a: 2] ||= 1; nil})
assert_equal([[0], {kw: 5, a: 2, nil: 3}, nil], h.v{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1; nil})
assert_syntax_error(%q{h[**kw] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, **kw] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, nil: 3] ||= 1; nil}, message)
# ||=, with block, popped
assert_equal([[], {}, b], h.v{h[**kw, &b] ||= 1; nil})
assert_equal([[0], {}, b], h.v{h[0, **kw, &b] ||= 1; nil})
assert_equal([[0], {}, b], h.v{h[0, *a, **kw, &b] ||= 1; nil})
assert_equal([[], {kw: 5}, b], h.v{h[kw: 5, &b] ||= 1; nil})
assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1; nil})
assert_equal([[], {kw: 5, a: 2}, b], h.v{h[kw: 5, a: 2, &b] ||= 1; nil})
assert_equal([[0], {kw: 5, a: 2}, b], h.v{h[0, kw: 5, a: 2, &b] ||= 1; nil})
assert_equal([[0], {kw: 5, a: 2, b: 3}, b], h.v{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1; nil})
assert_syntax_error(%q{h[**kw, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, **kw, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, **kw, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[kw: 5, a: 2, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, kw: 5, a: 2, &b] ||= 1; nil}, message)
assert_syntax_error(%q{h[0, *a, kw: 5, a: 2, b: 3, &b] ||= 1; nil}, message)
end
@ -265,20 +267,12 @@ class TestCall < Test::Unit::TestCase
def o.[](...) 2 end
def o.[]=(...) end
o[kw: 1] += 1
assert_equal([], ary)
message = /keyword arg given in index/
o[**o] += 1
assert_equal([:to_hash], ary)
ary.clear
o[**o, &o] += 1
# to_proc called twice because no VM instruction for coercing to proc
assert_equal([:to_hash, :to_proc, :to_proc], ary)
ary.clear
o[*o, **o, &o] += 1
assert_equal([:to_a, :to_hash, :to_proc, :to_proc], ary)
assert_syntax_error(%q{o[kw: 1] += 1}, message)
assert_syntax_error(%q{o[**o] += 1}, message)
assert_syntax_error(%q{o[**o, &o] += 1}, message)
assert_syntax_error(%q{o[*o, **o, &o] += 1}, message)
end
def test_call_op_asgn_keywords_mutable
@ -295,10 +289,12 @@ class TestCall < Test::Unit::TestCase
def []=(*a, **b) @set = [a, b] end
end.new
message = /keyword arg given in index/
a = []
kw = {}
assert_equal([[2], {b: 5}, [2, 4], {b: 5}], h.v{h[*a, 2, b: 5, **kw] += 1})
assert_syntax_error(%q{h[*a, 2, b: 5, **kw] += 1}, message)
end
def test_call_splat_order

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

@ -362,110 +362,6 @@ module Prism
assert_prism_eval("$pit = 1")
end
def test_IndexAndWriteNode
assert_prism_eval("[0][0] &&= 1")
assert_prism_eval("[nil][0] &&= 1")
# Testing `[]` with a block passed in
assert_prism_eval(<<-CODE)
class CustomHash < Hash
def []=(key, value, &block)
block ? super(block.call(key), value) : super(key, value)
end
end
hash = CustomHash.new
# Call the custom method with a block that modifies
# the key before assignment
hash["KEY"] = "test"
hash["key", &(Proc.new { _1.upcase })] &&= "value"
hash
CODE
# Test with keyword arguments
assert_prism_eval(<<~RUBY)
h = Object.new
def h.[](**b) = 0
def h.[]=(*a, **b); end
h[foo: 1] &&= 2
RUBY
# Test with keyword splat
assert_prism_eval(<<~RUBY)
h = Object.new
def h.[](**b) = 1
def h.[]=(*a, **b); end
h[**{}] &&= 2
RUBY
end
def test_IndexOrWriteNode
assert_prism_eval("[0][0] ||= 1")
assert_prism_eval("[nil][0] ||= 1")
# Testing `[]` with a block passed in
assert_prism_eval(<<-CODE)
class CustomHash < Hash
def []=(key, value, &block)
super(block.call(key), value)
end
end
hash = CustomHash.new
# Call the custom method with a block that modifies
# the key before assignment
hash["key", &(Proc.new { _1.upcase })] ||= "value"
hash
CODE
# Test with keyword arguments
assert_prism_eval(<<~RUBY)
h = Object.new
def h.[](**b) = 0
def h.[]=(*a, **b); end
h[foo: 1] ||= 2
RUBY
# Test with keyword splat
assert_prism_eval(<<~RUBY)
h = Object.new
def h.[](**b) = nil
def h.[]=(*a, **b); end
h[**{}] ||= 2
RUBY
end
def test_IndexOperatorWriteNode
assert_prism_eval("[0][0] += 1")
# Testing `[]` with a block passed in
assert_prism_eval(<<-CODE)
class CustomHash < Hash
def [](key, &block)
block ? super(block.call(key)) : super(key)
end
def []=(key, value, &block)
block ? super(block.call(key), value) : super(key, value)
end
end
hash = CustomHash.new
# Call the custom method with a block that modifies
# the key before assignment
hash["KEY"] = "test"
hash["key", &(Proc.new { _1.upcase })] &&= "value"
hash
CODE
end
def test_InstanceVariableAndWriteNode
assert_prism_eval("@pit = 0; @pit &&= 1")
end

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

@ -507,16 +507,16 @@ class TestParse < Test::Unit::TestCase
end
def t.dummy(_)
end
eval <<-END, nil, __FILE__, __LINE__+1
assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index/)
begin;
t[42, &blk] ||= 42
END
assert_equal([:aref, :aset], a)
a.clear
eval <<-END, nil, __FILE__, __LINE__+1
t[42, &blk] ||= t.dummy 42 # command_asgn test
END
assert_equal([:aref, :aset], a)
blk
end;
assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index/)
begin;
t[42, &blk] ||= t.dummy 42 # command_asgn test
end;
end
def test_backquote