Skip to content
This repository has been archived by the owner on Aug 23, 2020. It is now read-only.

Invalid mutation for a bare rescue inside a method with a kwarg splat signature #85

Open
backus opened this issue Jun 13, 2017 · 0 comments
Labels

Comments

@backus
Copy link
Collaborator

backus commented Jun 13, 2017

Minimal code to reproduce

def foo(**bar)
  rescue Baz
end

AST of original code

(def :foo
  (args
    (kwrestarg :bar))
  (rescue nil
    (resbody
      (array
        (const nil :Baz)) nil nil) nil))

Invalid AST

(def :foo
  (args
    (kwrestarg :bar))
  (begin
    (lvasgn :bar
      (hash))
    (rescue nil
      (resbody
        (array
          (const nil :Baz)) nil nil) nil)))

Error

$ bundle exec ruby example.rb
warning: parser/current is loading parser/ruby24, which recognizes
warning: HEAD-compliant syntax, but you are running 2.4.1.
warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
/Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/literal/primitive.rb:39: warning: constant ::Fixnum is deprecated
/Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/literal/primitive.rb:40: warning: constant ::Bignum is deprecated
/Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:128:in `emitter': undefined method `type' for nil:NilClass (NoMethodError)
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:256:in `emitter'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:198:in `visit_plain'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/rescue.rb:58:in `emit_standalone'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/rescue.rb:28:in `dispatch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:104:in `write_to_buffer'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `call'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `block (3 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:63:in `block (3 levels) in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:62:in `block (2 levels) in fetch'
	from /Users/johnbackus/.rubies/ruby-2.4.1/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:61:in `block in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:60:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:116:in `block (2 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:199:in `visit_plain'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/begin.rb:19:in `block in emit_inner'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/begin.rb:18:in `each'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/begin.rb:18:in `each_with_index'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/begin.rb:18:in `emit_inner'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/begin.rb:53:in `dispatch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:104:in `write_to_buffer'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `call'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `block (3 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:63:in `block (3 levels) in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:62:in `block (2 levels) in fetch'
	from /Users/johnbackus/.rubies/ruby-2.4.1/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:61:in `block in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:60:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:116:in `block (2 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:199:in `visit_plain'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:472:in `block in visit_indented'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:437:in `indented'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:472:in `visit_indented'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:457:in `emit_body'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter/def.rb:38:in `dispatch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser/emitter.rb:104:in `write_to_buffer'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `call'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:117:in `block (3 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:63:in `block (3 levels) in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:62:in `block (2 levels) in fetch'
	from /Users/johnbackus/.rubies/ruby-2.4.1/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:61:in `block in fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/thread_safe-0.3.5/lib/thread_safe/cache.rb:58:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/memory.rb:60:in `fetch'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/memoizable-0.4.2/lib/memoizable/method_builder.rb:116:in `block (2 levels) in create_memoized_method'
	from /Users/johnbackus/.gem/ruby/2.4.1/gems/unparser-0.2.5/lib/unparser.rb:29:in `unparse'
	from example.rb:14:in `block in <main>'
	from /Users/johnbackus/.rubies/ruby-2.4.1/lib/ruby/2.4.0/set.rb:324:in `each_key'
	from /Users/johnbackus/.rubies/ruby-2.4.1/lib/ruby/2.4.0/set.rb:324:in `each'
	from example.rb:13:in `<main>'

Invalid mutation

(def :foo
  (args
    (kwrestarg :bar))
  (begin
    (lvasgn :bar
      (hash))
    (rescue nil
      (resbody
        (array
          (const nil :Baz)) nil nil) nil)))

The faulty mutation is trying to insert bar = {} at the beginning of the mutation but it should be wrapping the body in a kwrestarg in this case which would look like

def foo(**bar)
  begin
    bar = {}
  rescue Baz
  end
end

The mutation emitted uses a normal begin which does not correspond to the begin keyword but instead parens. The closest source representing the invalid operation would be

def foo(**bar)
  (
    bar = {}
  rescue Baz
  )
end

which is invalid due to the presence of the rescue.

This only happens in the cases where mutest thinks it can inline a default argument. Another reproduction is

mutate(<<-RUBY)
  def foo(bar = 1)
  rescue Baz
  end
RUBY

Thanks @JTBooth for helping find this

@backus backus added the bug label Jun 13, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

1 participant