Skip to content

Override freeze-related behaviour in RubyRange for compatibility with Ruby 3.0 #2570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions spec/ruby/language/range_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
it "is frozen" do
(42..).should.frozen?
end

it "is not frozen if duplicated" do
(42..).dup.should_not.frozen?
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should move to spec/ruby/core/range/dup_spec.rb, I'll do that.

end

ruby_version_is "2.7" do
Expand All @@ -28,3 +32,25 @@
end
end
end

describe "Object Ranges" do
ruby_version_is "3.0" do

it "is frozen" do
Range.new(1, 2).should.frozen?
end

it "is not frozen if duplicated" do
Range.new(1, 2).dup.should_not.frozen?
end

it "is not frozen if it is a subclass of Range" do
change_range = Class.new(Range).new(1, 2)
change_range.should_not.frozen?
end

it "is not frozen if it is created through allocate" do
Range.allocate.should_not.frozen?
end
end
end
1 change: 0 additions & 1 deletion spec/tags/language/range_tags.txt

This file was deleted.

44 changes: 29 additions & 15 deletions src/main/java/org/truffleruby/core/range/RangeNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package org.truffleruby.core.range;

import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.profiles.LoopConditionProfile;
import org.truffleruby.builtins.CoreMethod;
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
Expand Down Expand Up @@ -196,7 +197,8 @@ protected RubyIntRange dupIntRange(RubyIntRange range) {
shape,
range.excludedEnd,
range.begin,
range.end);
range.end,
false);
AllocationTracing.trace(copy, this);
return copy;
}
Expand All @@ -210,7 +212,8 @@ protected RubyLongRange dupLongRange(RubyLongRange range) {
shape,
range.excludedEnd,
range.begin,
range.end);
range.end,
false);
AllocationTracing.trace(copy, this);
return copy;
}
Expand All @@ -223,7 +226,8 @@ protected RubyObjectRange dup(RubyObjectRange range) {
getLanguage().objectRangeShape,
range.excludedEnd,
range.begin,
range.end);
range.end,
false);
AllocationTracing.trace(copy, this);
return copy;
}
Expand Down Expand Up @@ -423,7 +427,8 @@ protected RubyIntRange longRange(RubyLongRange range, RubyArray array) {
getLanguage().intRangeShape,
range.excludedEnd,
begin,
end);
end,
range.frozen);
}

@Specialization(guards = "range.isBounded()")
Expand All @@ -435,7 +440,8 @@ protected RubyIntRange boundedObjectRange(RubyObjectRange range, RubyArray array
getLanguage().intRangeShape,
range.excludedEnd,
begin,
end);
end,
range.frozen);
}

@Specialization(guards = "range.isEndless()")
Expand All @@ -446,7 +452,8 @@ protected RubyIntRange endlessObjectRange(RubyObjectRange range, RubyArray array
getLanguage().intRangeShape,
true,
toInt(range.begin),
end);
end,
range.frozen);
}

@Specialization(guards = "range.isBeginless()")
Expand All @@ -458,7 +465,8 @@ protected RubyIntRange beginlessObjectRange(RubyObjectRange range, RubyArray arr
getLanguage().intRangeShape,
range.excludedEnd,
begin,
end);
end,
range.frozen);
}

@Specialization(guards = "range.isBoundless()")
Expand All @@ -470,7 +478,8 @@ protected RubyIntRange nilNilObjectRange(RubyObjectRange range, RubyArray array)
getLanguage().intRangeShape,
false,
begin,
end);
end,
range.frozen);
}

private int toInt(Object indexObject) {
Expand Down Expand Up @@ -514,7 +523,8 @@ protected RubyIntRange intRange(RubyClass rubyClass, int begin, int end, boolean
getLanguage().intRangeShape,
excludeEnd,
begin,
end);
end,
true);
AllocationTracing.trace(range, this);
return range;
}
Expand All @@ -528,7 +538,8 @@ protected RubyIntRange longFittingIntRange(RubyClass rubyClass, long begin, long
shape,
excludeEnd,
(int) begin,
(int) end);
(int) end,
true);
AllocationTracing.trace(range, this);
return range;
}
Expand All @@ -541,21 +552,24 @@ protected RubyLongRange longRange(RubyClass rubyClass, long begin, long end, boo
getLanguage().longRangeShape,
excludeEnd,
begin,
end);
end,
true);
AllocationTracing.trace(range, this);
return range;
}

@Specialization(guards = { "rubyClass != getRangeClass() || (!isImplicitLong(begin) || !isImplicitLong(end))" })
@Specialization(guards = { "!standardClass || (!isImplicitLong(begin) || !isImplicitLong(end))" })
protected RubyObjectRange objectRange(RubyClass rubyClass, Object begin, Object end, boolean excludeEnd,
@Cached DispatchNode compare) {
@Cached DispatchNode compare,
@Bind("rubyClass == getRangeClass()") boolean standardClass) {

if (compare.call(begin, "<=>", end) == nil && end != nil && begin != nil) {
throw new RaiseException(getContext(), coreExceptions().argumentError("bad value for range", this));
}

final Shape shape = getLanguage().objectRangeShape;
final RubyObjectRange range = new RubyObjectRange(rubyClass, shape, excludeEnd, begin, end);
final RubyObjectRange range = new RubyObjectRange(rubyClass, shape, excludeEnd, begin, end,
standardClass);
AllocationTracing.trace(range, this);
return range;
}
Expand All @@ -571,7 +585,7 @@ public abstract static class AllocateNode extends UnaryCoreMethodNode {
@Specialization
protected RubyObjectRange allocate(RubyClass rubyClass) {
final Shape shape = getLanguage().objectRangeShape;
final RubyObjectRange range = new RubyObjectRange(rubyClass, shape, false, nil, nil);
final RubyObjectRange range = new RubyObjectRange(rubyClass, shape, false, nil, nil, false);
AllocationTracing.trace(range, this);
return range;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/truffleruby/core/range/RubyIntRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public final class RubyIntRange extends RubyRange {
public final int begin;
public final int end;

public RubyIntRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, int begin, int end) {
super(rubyClass, shape, excludedEnd);
public RubyIntRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, int begin, int end, boolean frozen) {
super(rubyClass, shape, excludedEnd, frozen);
this.begin = begin;
this.end = end;
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/truffleruby/core/range/RubyLongRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public final class RubyLongRange extends RubyRange {
public final long begin;
public final long end;

public RubyLongRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, long begin, long end) {
super(rubyClass, shape, excludedEnd);
public RubyLongRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, long begin, long end, boolean frozen) {
super(rubyClass, shape, excludedEnd, frozen);
this.begin = begin;
this.end = end;
}
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/truffleruby/core/range/RubyObjectRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@ public final class RubyObjectRange extends RubyRange implements ObjectGraphNode
public Object begin;
public Object end;

public RubyObjectRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, Object begin, Object end) {
super(rubyClass, shape, excludedEnd);
public RubyObjectRange(
RubyClass rubyClass,
Shape shape,
boolean excludedEnd,
Object begin,
Object end,
boolean frozen) {
super(rubyClass, shape, excludedEnd, frozen);
this.begin = begin;
this.end = end;
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/org/truffleruby/core/range/RubyRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,32 @@
*/
package org.truffleruby.core.range;

import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.object.Shape;
import org.truffleruby.core.klass.RubyClass;
import org.truffleruby.language.RubyDynamicObject;
import org.truffleruby.language.library.RubyLibrary;

@ExportLibrary(RubyLibrary.class)
public abstract class RubyRange extends RubyDynamicObject {

public boolean excludedEnd;
public boolean frozen;

public RubyRange(RubyClass rubyClass, Shape shape, boolean excludedEnd) {
public RubyRange(RubyClass rubyClass, Shape shape, boolean excludedEnd, boolean frozen) {
super(rubyClass, shape);
this.excludedEnd = excludedEnd;
this.frozen = frozen;
}

@ExportMessage
protected void freeze() {
frozen = true;
}

@ExportMessage
protected boolean isFrozen() {
return frozen;
}
}