aboutsummaryrefslogtreecommitdiffstats
path: root/test/ruby/test_keyword.rb
Commit message (Collapse)AuthorAgeFilesLines
* fix bug in keyword + protected combination卜部昌平2019-10-281-0/+16
| | | | Test included for the situation formerly was not working.
* Handle case where ruby2_keywords method splats to ruby2_keywords methodJeremy Evans2019-10-241-0/+26
| | | | | | Previously, the keyword hash was duped (which results in a regular hash), but the dup was not marked as a keyword hash, causing the hash not to be marked as keyword hash even though it should be.
* Duplicate hash when converting keyword hash to keywordsJeremy Evans2019-10-241-0/+8
| | | | | | | This mirrors the behavior when manually splatting a hash. This mirrors the changes made in setup_parameters_complex in 6081ddd6e6f2297862b3c7e898d28a76b8f9240b, so that splatting to a non-iseq method works the same as splatting to an iseq method.
* Dup hash with keyword flag when converted to keywordsJeremy Evans2019-10-151-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | When ruby2_keywords is used on a method, keywords passed to the method are flagged. When the hash is passed as the last element of an argument splat to another method, the hash should be treated as a keyword splat. When keyword splatting a hash, a duplicate of the hash is made. So when auto-splatting the hash with the keyword flag, a duplicate of the hash should also be made. This fixes cases where the hash is later passed to another method and would be treated as keywords there: class Object ruby2_keywords def foo(*a) bar(*a) end def bar(*a) baz(*a) end def baz(*a, **kw) [a, kw] end end foo(:a=>1) Previously, this would pass the :a=>1 as keywords to bar and also as keywords to baz. Now it only passes :a=>1 as keywords to bar, but bar passes :a=>1 as a positional hash to baz (which in this case generates a warning in 2.7).
* Allow ruby2_keywords to be used with bmethodsJeremy Evans2019-10-071-1/+32
| | | | | | | | There are libraries that use define_method with argument splats where they would like to pass keywords through the method. To more easily allow such libraries to use ruby2_keywords to handle backwards compatibility, it is necessary for ruby2_keywords to support bmethods.
* Correctly issue ArgumentError when calling method that accepts no keywordsJeremy Evans2019-09-271-0/+13
| | | | | | | If a method accepts no keywords and was called with a keyword, an ArgumentError was not always issued previously. Force methods that accept no keywords to go through setup_parameters_complex so that an ArgumentError is raised if keywords are provided.
* Fix more keyword separation issuesJeremy Evans2019-09-261-0/+648
| | | | | | | | | | | | | | | | | | | | | This fixes instance_exec and similar methods. It also fixes Enumerator::Yielder#yield, rb_yield_block, and a couple of cases with Proc#{<<,>>}. This support requires the addition of rb_yield_values_kw, similar to rb_yield_values2, for passing the keyword flag. Unlike earlier attempts at this, this does not modify the rb_block_call_func type or add a separate function type. The functions of type rb_block_call_func are called by Ruby with a separate VM frame, and we can get the keyword flag information from the VM frame flags, so it doesn't need to be passed as a function argument. These changes require the following VM functions accept a keyword flag: * vm_yield_with_cref * vm_yield * vm_yield_with_block
* Fix keyword argument separation issues in Enumerator::Generator#eachJeremy Evans2019-09-261-0/+77
| | | | This requires adding rb_proc_call_kw to pass the keyword flag.
* Fix keyword argument separation issues in Fiber#resumeJeremy Evans2019-09-261-0/+77
|
* Fix keyword argument separation issues in Thread.newJeremy Evans2019-09-261-0/+80
|
* Add Module#ruby2_keywords for passing keywords through regular argument splatsJeremy Evans2019-09-251-0/+272
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This approach uses a flag bit on the final hash object in the regular splat, as opposed to a previous approach that used a VM frame flag. The hash flag approach is less invasive, and handles some cases that the VM frame flag approach does not, such as saving the argument splat array and splatting it later: ruby2_keywords def foo(*args) @args = args bar end def bar baz(*@args) end def baz(*args, **kw) [args, kw] end foo(a:1) #=> [[], {a: 1}] foo({a: 1}, **{}) #=> [[{a: 1}], {}] foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning foo({a: 1}) #=> 3.0: [[{a: 1}], {}] It doesn't handle some cases that the VM frame flag handles, such as when the final hash object is replaced using Hash#merge, but those cases are probably less common and are unlikely to properly support keyword argument separation. Use ruby2_keywords to handle argument delegation in the delegate library.
* Make public_send and rb_f_send handle keyword argument separationJeremy Evans2019-09-231-0/+102
| | | | | Kernel#send takes a different optimized code path that was already handled.
* Handle keyword argument separation for Enumerator#sizeJeremy Evans2019-09-201-0/+99
| | | | | | | | | When Object#to_enum is passed a block, the block is called to get a size with the arguments given to to_enum. This calls the block with the same keyword flag as to_enum is called with. This requires adding rb_check_funcall_kw and rb_check_funcall_default_kw to handle keyword flags.
* Make passing empty keywords to dig pass empty keywords to next dig methodJeremy Evans2019-09-201-0/+220
| | | | | | | | | | | | | | | | If defined in Ruby, dig would be defined as def dig(arg, *rest) end, it would not use keywords. If the last dig argument was an empty hash, it could be treated as keyword arguments by the next dig method. Allow dig to pass along the empty keyword flag if called with an empty keyword, to suppress the previous behavior and force treating the hash as a positional argument and not keywords. Also handle the case where dig calls method_missing, passing the empty keyword flag to that as well. This requires adding rb_check_funcall_with_hook_kw functions, so that dig can specify how arguments are treated. It also adds kw_splat arguments to a couple static functions.
* Add and fix some keyword testsJeremy Evans2019-09-181-17/+182
| | | | | | | | | | Replace [arg=1, args] with [arg, args] so we can actually test the value correctly. Add some missing tests for **h3 when method accepts (**args). Add tests for passing positional hashes to (**args) methods and check for the expected warnings/errors.
* Fix keyword argument separation issues with sym procs when using refinementsJeremy Evans2019-09-171-0/+303
| | | | | | | | | | | | Make sure that vm_yield_with_cfunc can correctly set the empty keyword flag by passing 2 as the kw_splat value when calling it in vm_invoke_ifunc_block. Make sure calling.kw_splat is set to 1 and not 128 in vm_sendish, so we can safely check for different kw_splat values. vm_args.c needs to call add_empty_keyword, and to make JIT happy, the function needs to be exported. Rename the function to rb_adjust_argv_kw_splat to more accurately reflect what it does, and mark it as MJIT exported.
* Pass keyword argument flag when rb_call_super_kw calls method_missingJeremy Evans2019-09-171-0/+194
| | | | | | | | This makes method_missing take a flag for whether keyword arguments were passed. Adds tests both for rb_call_super_kw usage as well as general usage of super calling method_missing in Ruby methods.
* Correctly handle keywords for Method#call for cfuncs, send, and attr_*Jeremy Evans2019-09-131-0/+554
| | | | | | | | | This sets the correct VM frame flags when using Method#call to call funcs, and handles empty keyword hashes for cfuncs, attr_reader, and attr_writer. It also fixes calls to send through Method#call. It adds tests for all of those, as well as tests for using Method#call to call define_method, lambda, and sym_procs (which didn't require code changes).
* Emit missing keyword argument separation warnings for define_methodJeremy Evans2019-09-111-0/+22
| | | | | | | | | Previously, the warning functions skipped warning in these cases. This removes the skipping, and uses a less descriptive warning instead. This affected both last argument to keyword warnings and keyword split warnings.
* Fix invalid keyword argument separation warning for delegating callsJeremy Evans2019-09-081-0/+1
| | | | | | | | | | | | | | | | | | | | This removes an invalid keyword argument separation warning for code such as: ```ruby def foo(arg) arg end kw = {} foo(*[1], **kw) ``` This warning was caused because the remove_empty_keyword_hash was set based on a comparison with two variables, and in this case, one of the variables was updated after the check and we need to use the updated variable. Simplify things by just inlining the comparison.
* Add keyword argument separation tests for implicit/explicit super callsJeremy Evans2019-09-081-0/+220
| | | | | No code changes are necessary, but we didn't have as extensive tests for these calls previously.
* Convert keyword argument to required positional hash argument for Class#new, ↵Jeremy Evans2019-09-061-20/+152
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Method#call, UnboundMethod#bind_call Also add keyword argument separation warnings for Class#new and Method#call. To allow for keyword argument to required positional hash converstion in cfuncs, add a vm frame flag indicating the cfunc was called with an empty keyword hash (which was removed before calling the cfunc). The cfunc can check this frame flag and add back an empty hash if it is passing its arguments to another Ruby method. Add rb_empty_keyword_given_p function for checking if called with an empty keyword hash, and rb_add_empty_keyword for adding back an empty hash to argv. All of this empty keyword argument support is only for 2.7. It will be removed in 3.0 as Ruby 3 will not convert empty keyword arguments to required positional hash arguments. Comment all of the relevent code to make it obvious this is expected to be removed. Add rb_funcallv_kw as an public C-API function, just like rb_funcallv but with a keyword flag. This is used by rb_obj_call_init (internals of Class#new). This also required expected call_type enum with CALL_FCALL_KW, similar to the recent addition of CALL_PUBLIC_KW. Add rb_vm_call_kw as a internal function, used by call_method_data (internals of Method#call and UnboundMethod#bind_call). Add tests for UnboundMethod#bind_call keyword handling.
* Convert empty keyword hash to required positional argument and warn for ↵Jeremy Evans2019-09-051-4/+12
| | | | | | | | method_missing This is the same as the bmethod, sym proc, and send cases, where we don't remove the keyword splat, so later code can move it to a required positional parameter and warn.
* Convert empty keyword hash to required positional argument and warn for sym ↵Jeremy Evans2019-09-051-4/+12
| | | | | | | | procs This is the same as the bmethod and send cases, where we don't remove the keyword splat, so later code can move it to to a a required positional parameter and warn.
* Convert empty keyword hash to required positional argument and warn for ↵Jeremy Evans2019-09-051-61/+31
| | | | | | | | | | | | | | | | | | | | | | | lambda and bmethod The lambda case is similar to the attr_writer case, except we have to determine the number of required parameters from the iseq instead of being able to assume a single required parameter. This fixes a lot of lambda tests which were switched to require warnings for all usage of keyword arguments. Similar to method handling, we do not warn when passing keyword arguments to lambdas that do not accept keyword arguments, the argument is just passed as a positional hash in that case, unless it is empty. If it is empty and not the final required parameter, then we ignore it. If it is empty and the final required parameter, then we pass it for backwards compatibility and emit a warning, as in Ruby 3 we will not pass it. The bmethod case is similar to the send case, in that we do not want to remove empty keyword splats in vm_call_bmethod, as that prevents later call handling from moving them to required positional arguments and warning.
* Convert empty keyword hash to required positional argument and warnJeremy Evans2019-09-051-6/+112
| | | | | | | | | | | | | | | | | | | | | | | | | In general, we want to ignore empty keyword hashes. The only case where we want to allow them for backwards compatibility is when they are necessary to satify the final required positional argument. In that case, we want to not ignore them, but we do want to warn, as that will be going away in Ruby 3. This commit implements this support for regular methods and attr_writer methods. In order to allow send to forward arguments correctly, send no longer removes empty keyword hashes. It is the responsibility of the final method to remove the empty keyword hashes now. This change was necessary as otherwise send could remove the empty keyword hashes before the regular or attr_writer methods could move them to required positional arguments. For completeness, add tests for keyword handling regular methods calls. This makes rb_warn_keyword_to_last_hash non-static in vm_args.c so it can be reused in vm_insnhelper.c, and also moves declarations before statements in the rb_warn_* functions in vm_args.c.
* Always remove empty keyword hashes when calling methodsJeremy Evans2019-09-051-32/+16
| | | | | | | | | | | | | | | While doing so is not backwards compatible with Ruby 2.6, it is necessary for generic argument forwarding to work for all methods: ```ruby def foo(*args, **kw, &block) bar(*args, **kw, &block) end ``` If you do not remove empty keyword hashes, and bar does not accept keyword arguments, then a call to foo without keyword arguments calls bar with an extra positional empty hash argument.
* Add a keyword-to-last-hash warning for some case of define_method methodYusuke Endoh2019-09-051-25/+75
| | | | | | | and lambda. When define_method is a simple iseq (`define_method(:m) {|x| ... }`), passing keywords to it (`m(**kw)`) didn't print a warning.
* define_method should not drop the empty keyword hashYusuke Endoh2019-09-051-4/+4
| | | | Similar to 38e9c1bc35d5549575fbb263afff560e97db068e
* vm_call_bmethod should not drop the empty keyword hashYusuke Endoh2019-09-051-1/+3
| | | | Similar to 38e9c1bc35d5549575fbb263afff560e97db068e
* vm_call_opt_send should not drop the empty keyword hashYusuke Endoh2019-09-051-2/+3
| | | | | | Now the mechanism that conveys kw_splat flag is gradually established, so the hack to drop the empty keyword hash is not needed for vm_call_opt_send.
* test_method_missing_kwsplat should call the target directlyYusuke Endoh2019-09-051-41/+44
| | | | not via Object#send which uses a fast path vm_call_opt_send.
* Ignore an empty keyword splat for attr_reader/writer methodsYusuke Endoh2019-09-051-0/+46
|
* C method should accept a keyword hash (for compatibility with 2.6)Yusuke Endoh2019-09-051-8/+8
|
* CALLER_SETUP_ARG removes an empty keyword hash from argvYusuke Endoh2019-09-051-15/+5
| | | | | | | | | ...only when a "remove_empty_keyword_hash" flag is specified. After CALLER_SETUP_ARG is called, `ci->flag & VM_CALL_KW_SPLAT` must not be used. Instead. use `calling->kw_splat`. This is because CALLER_SETUP_ARG may modify argv and update `calling->kw_splat`, and `ci->flag & VM_CALL_KW_SPLAT` may be inconsistent with the result.
* Fix passing keywords without splats to sym procs, define_method, and ↵Jeremy Evans2019-09-051-32/+131
| | | | method_missing
* Make Symbol#to_proc calls handle keyword argumentsJeremy Evans2019-09-051-0/+73
| | | | | | Make rb_sym_proc_call take a flag for whether a keyword argument is used, and use the new rb_funcall_with_block_kw function to pass that information.
* Propagate kw_splat informationYusuke Endoh2019-09-051-0/+75
| | | | | | | The kw_splat flag is whether the original call passes keyword or not. Some types of methods (e.g., bmethod and sym_proc) drops the information. This change tries to propagate the flag to the final callee, as far as I can.
* Make m(**{}) mean call without keywordsJeremy Evans2019-09-051-3/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Previously, **{} was removed by the parser: ``` $ ruby --dump=parse -e '{**{}}' @ NODE_SCOPE (line: 1, location: (1,0)-(1,6)) +- nd_tbl: (empty) +- nd_args: | (null node) +- nd_body: @ NODE_HASH (line: 1, location: (1,0)-(1,6))* +- nd_brace: 1 (hash literal) +- nd_head: (null node) ``` Since it was removed by the parser, the compiler did not know about it, and `m(**{})` was therefore treated as `m()`. This modifies the parser to not remove the `**{}`. A simple approach for this is fairly simple by just removing a few lines from the parser, but that would cause two hash allocations every time it was used. The approach taken here modifies both the parser and the compiler, and results in `**{}` not allocating any hashes in the usual case. The basic idea is we use a literal node in the parser containing a frozen empty hash literal. In the compiler, we recognize when that is used, and if it is the only keyword present, we just push it onto the VM stack (no creation of a new hash or merging of keywords). If it is the first keyword present, we push a new empty hash onto the VM stack, so that later keywords can merge into it. If it is not the first keyword present, we can ignore it, since the there is no reason to merge an empty hash into the existing hash. Example instructions for `m(**{})` Before (note ARGS_SIMPLE): ``` == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,7)> (catch: FALSE) 0000 putself ( 1)[Li] 0001 opt_send_without_block <callinfo!mid:m, argc:0, FCALL|ARGS_SIMPLE>, <callcache> 0004 leave ``` After (note putobject and KW_SPLAT): ``` == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,7)> (catch: FALSE) 0000 putself ( 1)[Li] 0001 putobject {} 0003 opt_send_without_block <callinfo!mid:m, argc:1, FCALL|KW_SPLAT>, <callcache> 0006 leave ``` Example instructions for `m(**h, **{})` Before and After (no change): ``` == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE) 0000 putself ( 1)[Li] 0001 putspecialobject 1 0003 newhash 0 0005 putself 0006 opt_send_without_block <callinfo!mid:h, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache> 0009 opt_send_without_block <callinfo!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>, <callcache> 0012 opt_send_without_block <callinfo!mid:m, argc:1, FCALL|KW_SPLAT>, <callcache> 0015 leave ``` Example instructions for `m(**{}, **h)` Before: ``` == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE) 0000 putself ( 1)[Li] 0001 putspecialobject 1 0003 newhash 0 0005 putself 0006 opt_send_without_block <callinfo!mid:h, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache> 0009 opt_send_without_block <callinfo!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>, <callcache> 0012 opt_send_without_block <callinfo!mid:m, argc:1, FCALL|KW_SPLAT>, <callcache> 0015 leave ``` After (basically the same except for the addition of swap): ``` == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE) 0000 putself ( 1)[Li] 0001 newhash 0 0003 putspecialobject 1 0005 swap 0006 putself 0007 opt_send_without_block <callinfo!mid:h, argc:0, FCALL|VCALL|ARGS_SIMPLE>, <callcache> 0010 opt_send_without_block <callinfo!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>, <callcache> 0013 opt_send_without_block <callinfo!mid:m, argc:1, FCALL|KW_SPLAT>, <callcache> 0016 leave ```
* Fix method name in test to not override existing method nameJeremy Evans2019-09-011-1/+1
|
* Fix keyword argument separation warning in method_missingJeremy Evans2019-09-011-0/+73
| | | | | | vm_call_method_missing was dropping VM_CALL_KW_SPLAT, so this just makes it not drop it, to get the same behavior as calling the method directly.
* test/ruby/test_keyword.rb: Add remove_method before method redefinitionYusuke Endoh2019-09-011-0/+10
| | | | to suppress redefinition warnings.
* Fix keyword argument separation warning when using sendJeremy Evans2019-08-311-0/+68
| | | | | | vm_call_opt_send was dropping VM_CALL_KW_SPLAT, so this just makes it not drop it, to get the same behavior as calling the method directly.
* Don't pass an empty keyword hash when double splatting empty hash when ↵Jeremy Evans2019-08-311-0/+138
| | | | | | | | calling cfunc This mirrors earlier changes in keyword argument separation for calling Ruby methods and calling procs/lambdas, so that behavior is kept the same.
* Split warning messages for tag-jumpNobuyoshi Nakada2019-09-011-20/+20
|
* Don't pass an empty keyword hash when double splatting empty hashJeremy Evans2019-08-301-0/+49
|
* Use more accurate source location in keyword argument separation warningsJeremy Evans2019-08-301-4/+4
| | | | | | | | This shows locations in places it didn't before, such as for proc calls, and fixes the location for super calls. This requires making iseq_location non-static and MJIT exported, which I hope will not cause problems.
* Warn for keyword to last hash parameter when method has no optional/rest ↵Jeremy Evans2019-08-301-2/+23
| | | | | | | | | parameters Previously, there was no warning in this case, even though we will be changing the behavior in Ruby 3. Fixes [Bug #14130]
* Remove a verbose warning that is no longer neededJeremy Evans2019-08-301-3/+3
| | | | This warns about a case that we will continue to support.
* Fix remaining warning issues in the tests due to keyword argument separationJeremy Evans2019-08-301-11/+33
|