Bug #12402


Inline rescue behavior inconsistent for method calls with arguments and assignment

Added by bklang (Ben Klang) over 6 years ago. Updated almost 6 years ago.

Target version:


In this example l'm intentionally passing bad data to Date.parse to trigger an exception. Depending on whether I use parenthesis in the method call, and whether I assign the result, I get different behavior for the inline rescue.


var1 = "apple"
var1 = Date.parse var1 rescue nil

var2 = "apple"
var2 = Date.parse(var2) rescue nil

def example1(bar)
  Date.parse bar rescue nil

def example2(bar)
  bar = Date.parse bar rescue nil

def example3(bar)
  bar = Date.parse(bar) rescue nil

puts "Variable 1: #{var1.nil?}"
puts "Variable 2: #{var2.nil?}"
puts "Example method 1: #{example1("apple").nil?}"
puts "Example method 2: #{example2("apple").nil?}"
puts "Example method 3: #{example3("apple").nil?}"

I would expect all 5 outputs from the above script to return true.


Variable 1: false
Variable 2: true
Example method 1: true
Example method 2: false
Example method 3: true

Related issues 1 (0 open1 closed)

Related to Ruby master - Bug #13005: Inline rescue is inconsistent when rescuing NoMethodErrorClosedmatz (Yukihiro Matsumoto)Actions

Updated by noahgibbs (Noah Gibbs) over 6 years ago

Hm. Yup, that definitely seems to bind funny, specifically during the parsing. Here's the Ripper output for "var1 = Date.parse var1 rescue nil" versus "var1 = Date.parse(var1) rescue nil":

2.3.1 :006 > pp Ripper.sexp("var1 = Date.parse var1 rescue nil")
    [:var_field, [:@ident, "var1", [1, 0]]],
     [:var_ref, [:@const, "Date", [1, 7]]],
     [:@ident, "parse", [1, 12]],
     [:args_add_block, [[:var_ref, [:@ident, "var1", [1, 18]]]], false]]],
   [:var_ref, [:@kw, "nil", [1, 30]]]]]]


2.3.1 :007 > pp Ripper.sexp("var1 = Date.parse(var1) rescue nil")
   [:var_field, [:@ident, "var1", [1, 0]]],
      [:var_ref, [:@const, "Date", [1, 7]]],
      [:@ident, "parse", [1, 12]]],
      [:args_add_block, [[:var_ref, [:@ident, "var1", [1, 18]]]], false]]],
    [:var_ref, [:@kw, "nil", [1, 31]]]]]]]

That shows the rescue surrounding the whole assignment in the first case (in case of failure, no assignment happens) and around just the Date.parse() call for the second one.

Not sure why it binds at a different level for one versus the other, but that's one more level of "what's happening here?" I think that means that the answer would be in parse.y.

Updated by matz (Yukihiro Matsumoto) about 6 years ago

I consider this is a bug. They should be consistent.
But I am not sure we can fix the issue soon. When in doubt, put parens.


Updated by nobu (Nobuyoshi Nakada) about 6 years ago

  • Description updated (diff)
  • Status changed from Open to Assigned
  • Assignee set to nobu (Nobuyoshi Nakada)
Actions #4

Updated by nobu (Nobuyoshi Nakada) about 6 years ago

  • Status changed from Assigned to Closed

Applied in changeset r55851.

parse.y: rescue modifier in rhs

  • parse.y (command_asgn): rescue modifier in command assignment
    should be limited to rhs only. [ruby-core:75621] [Bug #12402]

Updated by whitequark (whitequark *) about 6 years ago

Will this be backported?

Updated by nagachika (Tomoyuki Chikanaga) almost 6 years ago

  • Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: WONTFIX

Even though it's a bug, the behavior change could break existing applications. I won't backport into ruby_2_3 branch.

Actions #7

Updated by shyouhei (Shyouhei Urabe) almost 6 years ago

  • Related to Bug #13005: Inline rescue is inconsistent when rescuing NoMethodError added

Also available in: Atom PDF