oracle / truffleruby

A high performance implementation of the Ruby programming language, built on GraalVM.
https://www.graalvm.org/ruby/
Other
3.02k stars 185 forks source link

Different behavior between TruffleRuby and CRuby #2658

Closed Maumagnaguagno closed 2 years ago

Maumagnaguagno commented 2 years ago

The following code has different behavior in TruffleRuby 22.1.0 and CRuby 3.1.2.

a = [1,2,3]
h = {}
until a.empty?
  p a
  h[a.shift] ||= false
end
p h

See outputs below:

# CRuby
[1, 2, 3]
[2, 3]
[3]
{1=>false, 2=>false, 3=>false}

# TruffleRuby
[1, 2, 3]
[3]
{2=>false, nil=>false}

To my surprise, replacing ||= with = makes both Rubies output the same. Forgive me if this is already fixed or if there is a related open issue, my search resulted in nothing similar.

eregon commented 2 years ago

This is because the a.shift is evaluated twice by TruffleRuby, but only once by CRuby. We should fix that.

This variant has no issue:

a = [1,2,3]
h = {}
until a.empty?
  p a
  e = a.shift
  h[e] ||= false
end
p h
aardvark179 commented 2 years ago

Our translation of operator assignment nodes seems half correct. We correctly store the receiver as a local variable, but we do not do this correctly with any arguments passed to that receiver.

aardvark179 commented 2 years ago

The fix for this has now been merged into master.