Project

General

Profile

Feature #8239

Inline rescue bug

Added by dunric (David Unric) over 6 years ago. Updated 3 months ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:54120]

Description

There is a possible bug in parsing of inline rescue.
When an inline rescue is a part of multiple assignment and exception is raised, the assignment is silently ignored.

def foo
raise "error"
end

bar, baz = 1,2 # bar == 1, baz == 2
bar, baz = foo rescue [3,4] # no assignment performed: bar == 1, baz == 2
# expected after the expression: bar == 3, baz == 4

Already discussed at stackoverflow.com:
http://stackoverflow.com/questions/15880136/exceptions-why-does-adding-parenthesis-change-anything


Related issues

Has duplicate Ruby master - Bug #8279: Single-line rescue parsingClosedActions

Associated revisions

Revision 53b3be5d
Added by jeremyevans (Jeremy Evans) 3 months ago

Fix parsing of mutiple assignment with rescue modifier

Single assignment with rescue modifier applies rescue to the RHS:

a = raise rescue 1 # a = (raise rescue 1)

Previously, multiple assignment with rescue modifier applied rescue
to the entire expression:

a, b = raise rescue [1, 2] # (a, b = raise) rescue [1, 2]

This makes multiple assignment with rescue modifier consistent with
single assignment with rescue modifier, applying rescue to the RHS:

a, b = raise rescue [1, 2] # a, b = (raise rescue [1, 2])

Implements [Feature #8239]
Fixes [Bug #8279]

History

Updated by Hanmac (Hans Mackowiak) over 6 years ago

its because its parsed as
(bar, baz = foo) rescue [3,4]
i try
bar, baz = (foo rescue [3,4])
and this works

Updated by nobu (Nobuyoshi Nakada) over 6 years ago

  • Priority changed from 5 to Normal

=begin
Not only this case, some assignments can't include (({rescue})) modifier, e.g.:

x = 1
x += raise rescue 2

makes ((|x|)) (({3})), while

x = [1]
x[0] += raise rescue 2

doesn't change ((|x|)).

It would be possible to make them consistent all, but obviously causes
an incompatibility.

=end

Updated by dunric (David Unric) over 6 years ago

Hanmac (Hans Mackowiak) wrote:

its because its parsed as
(bar, baz = foo) rescue [3,4]
i try
bar, baz = (foo rescue [3,4])
and this works

I think this explanation is not valid. Let's see on an example:

bar = foo rescue [3,4]
If it would be parsed as you've described it would be equivalent to
(bar = foo) rescue [3,4]
but in contrary the assignment is performed !
ie. bar == [3,4] now.

I did pointed out the issue concerns the case of multiple assignment expression.

Updated by dunric (David Unric) over 6 years ago

nobu (Nobuyoshi Nakada) wrote:

=begin
Not only this case, some assignments can't include (({rescue})) modifier, e.g.:

x = 1
x += raise rescue 2

makes ((|x|)) (({3})), while

x = [1]
x[0] += raise rescue 2

doesn't change ((|x|)).

It would be possible to make them consistent all, but obviously causes
an incompatibility.

=end

I can confirm this behaviour. This is another example parsing of expression with inline rescue is broken.

I would like to see at least one real world example relying on this inconsistent behaviour. I don't expect fixing this bug would cause any incompatibility. Prove me wrong.

#5

Updated by naruse (Yui NARUSE) over 6 years ago

  • Tracker changed from Bug to Feature

Updated by dunric (David Unric) over 6 years ago

Hi,

any explanation why marked as a feature (request) instead of bug (of Ruby parser) ?

Thanks.

Updated by jasonw (Jason Woodard) over 6 years ago

I'd also vote for a bug to fix. I do not find it a feature request to implement.
There is nowhere in the documentation confirming the current behaviour to be correct.

Updated by nobu (Nobuyoshi Nakada) over 6 years ago

I also think this is a bug, but it may not be backported because of backward compatibility.

#9

Updated by jeremyevans (Jeremy Evans) 3 months ago

  • Status changed from Open to Closed

Applied in changeset git|53b3be5d58a9bf1efce229b3dce723f96e820c79.


Fix parsing of mutiple assignment with rescue modifier

Single assignment with rescue modifier applies rescue to the RHS:

a = raise rescue 1 # a = (raise rescue 1)

Previously, multiple assignment with rescue modifier applied rescue
to the entire expression:

a, b = raise rescue [1, 2] # (a, b = raise) rescue [1, 2]

This makes multiple assignment with rescue modifier consistent with
single assignment with rescue modifier, applying rescue to the RHS:

a, b = raise rescue [1, 2] # a, b = (raise rescue [1, 2])

Implements [Feature #8239]
Fixes [Bug #8279]

Also available in: Atom PDF