Skip to content

Commit 07e74d1

Browse files
committed
[GR-19220] Range#to_a wasn't working for long ranges (#2198)
PullRequest: truffleruby/2297
2 parents abbcb82 + 1e98361 commit 07e74d1

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ New features:
55

66
Bug fixes:
77

8+
* `Range#to_a` wasn't working for `long` ranges (#2198, @tomstuart and @LillianZ).
89

910
Compatibility:
1011

spec/ruby/core/range/to_a_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
(0xffff...0xfffd).to_a.should == []
1717
end
1818

19+
it "works with Ranges of 64-bit integers" do
20+
large = 1 << 40
21+
(large..large+1).to_a.should == [1099511627776, 1099511627777]
22+
end
23+
1924
it "works with Ranges of Symbols" do
2025
(:A..:z).to_a.size.should == 58
2126
end

src/main/java/org/truffleruby/core/range/RangeNodes.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ protected Object stepFallback(VirtualFrame frame, Object range, Object step, Obj
324324
@CoreMethod(names = "to_a")
325325
public abstract static class ToANode extends CoreMethodArrayArgumentsNode {
326326

327+
private final BranchProfile overflow = BranchProfile.create();
328+
private final ConditionProfile emptyProfile = ConditionProfile.create();
329+
327330
@Child private DispatchNode toAInternalCall;
328331

329332
@Specialization
@@ -337,7 +340,7 @@ protected RubyArray toA(RubyIntRange range) {
337340
}
338341
final int length = result - begin;
339342

340-
if (length < 0) {
343+
if (emptyProfile.profile(length < 0)) {
341344
return createEmptyArray();
342345
} else {
343346
final int[] values = new int[length];
@@ -350,6 +353,39 @@ protected RubyArray toA(RubyIntRange range) {
350353
}
351354
}
352355

356+
@Specialization
357+
protected RubyArray toA(RubyLongRange range) {
358+
final long begin = range.begin;
359+
long result;
360+
if (range.excludedEnd) {
361+
result = range.end;
362+
} else {
363+
result = range.end + 1;
364+
}
365+
366+
final int length;
367+
try {
368+
length = Math.toIntExact(result - begin);
369+
} catch (ArithmeticException e) {
370+
overflow.enter();
371+
throw new RaiseException(
372+
getContext(),
373+
coreExceptions().rangeError("long too big to convert into `int'", this));
374+
}
375+
376+
if (emptyProfile.profile(length < 0)) {
377+
return createEmptyArray();
378+
} else {
379+
final long[] values = new long[length];
380+
381+
for (int n = 0; n < length; n++) {
382+
values[n] = begin + n;
383+
}
384+
385+
return createArray(values);
386+
}
387+
}
388+
353389
@Specialization(guards = "range.isBounded()")
354390
protected Object boundedToA(RubyObjectRange range) {
355391
if (toAInternalCall == null) {

0 commit comments

Comments
 (0)