natalie-lang / natalie

a work-in-progress Ruby compiler, written in Ruby and C++
https://natalie-lang.org
MIT License
926 stars 62 forks source link

Calling with_index with a block on an enumerator results in the wrong output type #2150

Open herwinw opened 3 weeks ago

herwinw commented 3 weeks ago

Observed in #2145 where it broke our self hosted compiler. This snippet:

p [:a].map.class
p [:a].map.with_index.class
p [:a].map.with_index { |value, idx| [value, idx] }.class
p [:a].map.with_index { |value, idx| [value, idx] }.to_a.class
p [:a].map.with_index { |value, idx| [value, idx] }
p [:a].map.with_index { |value, idx| [value, idx] }.to_a

The output of MRI (I used version 3.3.3, but it should be the same in any supported version):

Enumerator
Enumerator
Array
Array
[[:a, 0]]
[[:a, 0]]

The output of the same program ran with Natalie:

Enumerator
Enumerator
Enumerator
Array
#<Enumerator:0x564692b83c60>
[:a]

The call to Enumerator#with_index is supposed to return a new Enumerator if no block is given, but should return an array if a block is given. Additionally, the output of [:a].map.with_index { |value, idx| [value, idx] }.to_a is the original array, not the mapped version.

herwinw commented 3 weeks ago
p [:a].each_with_index.map { |value, idx| [value, idx] }

This appears to be working, so this bug is probably specific for with_index and not a generic bug. I've used this one as a mitigation for the issue in #2145, I have to admit this one is a bit more readable as well.