Feature #8239
closedInline rescue bug
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
Updated by Hanmac (Hans Mackowiak) over 11 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 11 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 11 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 11 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 2makes ((|x|)) (({3})), while
x = [1]
x[0] += raise rescue 2doesn'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.
Updated by naruse (Yui NARUSE) over 11 years ago
- Tracker changed from Bug to Feature
Updated by dunric (David Unric) over 11 years ago
Hi,
any explanation why marked as a feature (request) instead of bug (of Ruby parser) ?
Thanks.
Updated by jasonw (Jason Woodard) over 11 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 11 years ago
I also think this is a bug, but it may not be backported because of backward compatibility.
Updated by jeremyevans (Jeremy Evans) over 5 years 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])