Skip to content
This repository was archived by the owner on Aug 23, 2020. It is now read-only.
This repository was 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

@backus

Description

@backus

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions