Skip to content

Commit a0c75e8

Browse files
committed
[GR-18163] Replace ArrayCastNode by SplatCastNode and ArrayConvertNode (#2355)
PullRequest: truffleruby/2665
2 parents 72ce69e + 056951a commit a0c75e8

File tree

5 files changed

+35
-142
lines changed

5 files changed

+35
-142
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Bug fixes:
1010
* `Truffle::POSIX.select` was being redefined repeatedly (#2332).
1111
* Fix the `--backtraces-raise` and `--backtraces-rescue` options in JVM mode (#2335).
1212
* Fix `File.{atime, mtime, ctime}` to include nanoseconds (#2337).
13+
* Fix `Array#[a, b] = "frozen string literal".freeze` (#2355).
1314

1415
Compatibility:
1516

spec/ruby/core/array/element_set_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
a[3, 2] = ['a', 'b', 'c', 'd']
3737
a.should == [2, 2, 3, "a", "b", "c", "d", 6]
3838
end
39+
3940
it "replaces the section defined by [start,length] with the given values" do
4041
a = [1, 2, 3, 4, 5, 6]
4142
a[3, 2] = 'a', 'b', 'c', 'd'
@@ -169,6 +170,7 @@
169170
ary[1...1] = []
170171
ary.should == [1, 2, 3]
171172
end
173+
172174
it "does nothing if the section defined by range has negative width and the rhs is an empty array" do
173175
ary = [1, 2, 3, 4, 5]
174176
ary[1...0] = []
@@ -284,6 +286,12 @@ def obj.to_ary() [1, 2, 3] end
284286
(a[2, 3] = [4, 5]).should == [4, 5]
285287
end
286288

289+
it "accepts a frozen String literal as RHS" do
290+
a = ['a', 'b', 'c']
291+
a[0, 2] = 'd'.freeze
292+
a.should == ['d', 'c']
293+
end
294+
287295
it "just sets the section defined by [start,length] to nil even if the rhs is nil" do
288296
a = ['a', 'b', 'c', 'd', 'e']
289297
a[1, 3] = nil

src/main/java/org/truffleruby/core/array/ArrayConvertNode.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,34 @@
99
*/
1010
package org.truffleruby.core.array;
1111

12+
import com.oracle.truffle.api.dsl.Cached;
13+
import com.oracle.truffle.api.dsl.Specialization;
1214
import com.oracle.truffle.api.profiles.ConditionProfile;
13-
import org.truffleruby.core.cast.ArrayCastNode;
1415
import org.truffleruby.language.RubyContextNode;
16+
import org.truffleruby.language.dispatch.DispatchNode;
1517

16-
/** Attempts converting its argument to an array, via {@link ArrayCastNode} (i.e. calling "to_ary"), or if that doesn't
17-
* work, by wrapping it inside a one-element array. */
18-
public final class ArrayConvertNode extends RubyContextNode {
18+
/** Attempts converting its argument to an array by calling #to_ary, or if that doesn't work, by wrapping it inside a
19+
* one-element array. */
20+
public abstract class ArrayConvertNode extends RubyContextNode {
1921

20-
@Child ArrayCastNode arrayCast = ArrayCastNode.create();
21-
@Child ArrayBuilderNode arrayBuilder = ArrayBuilderNode.create();
22-
private final ConditionProfile cantCast = ConditionProfile.create();
22+
public abstract RubyArray execute(Object value);
2323

24-
public static ArrayConvertNode create() {
25-
return new ArrayConvertNode();
24+
@Specialization
25+
protected RubyArray castArray(RubyArray array) {
26+
return array;
2627
}
2728

28-
public RubyArray execute(Object object) {
29-
Object converted = arrayCast.execute(object);
30-
if (cantCast.profile(converted == nil)) {
29+
@Specialization(guards = "!isRubyArray(object)")
30+
protected RubyArray cast(Object object,
31+
@Cached ConditionProfile canCast,
32+
@Cached ArrayBuilderNode arrayBuilder,
33+
@Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode toArrayNode) {
34+
final Object result = toArrayNode.call(object, "to_ary");
35+
if (canCast.profile(result instanceof RubyArray)) {
36+
return (RubyArray) result;
37+
} else {
3138
return ArrayHelpers.specializedRubyArrayOf(getContext(), getLanguage(), arrayBuilder, object);
3239
}
33-
return (RubyArray) converted;
3440
}
41+
3542
}

src/main/java/org/truffleruby/core/cast/ArrayCastNode.java

Lines changed: 0 additions & 127 deletions
This file was deleted.

src/main/java/org/truffleruby/parser/MethodTranslator.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import org.truffleruby.RubyLanguage;
1616
import org.truffleruby.collections.CachedSupplier;
1717
import org.truffleruby.core.IsNilNode;
18-
import org.truffleruby.core.cast.ArrayCastNodeGen;
18+
import org.truffleruby.core.cast.SplatCastNode;
19+
import org.truffleruby.core.cast.SplatCastNode.NilBehavior;
20+
import org.truffleruby.core.cast.SplatCastNodeGen;
1921
import org.truffleruby.core.proc.ProcCallTargets;
2022
import org.truffleruby.core.proc.ProcType;
2123
import org.truffleruby.language.RubyLambdaRootNode;
@@ -201,7 +203,9 @@ private RubyNode preludeProc(
201203
final RubyNode readArrayNode = profileArgument(
202204
language,
203205
new ReadPreArgumentNode(0, MissingArgumentBehavior.RUNTIME_ERROR));
204-
final RubyNode castArrayNode = ArrayCastNodeGen.create(readArrayNode);
206+
final SplatCastNode castArrayNode = SplatCastNodeGen
207+
.create(language, NilBehavior.NIL, true, readArrayNode);
208+
castArrayNode.doNotCopy();
205209

206210
final FrameSlot arraySlot = environment.declareVar(environment.allocateLocalTemp("destructure"));
207211
final RubyNode writeArrayNode = new WriteLocalVariableNode(arraySlot, castArrayNode);

0 commit comments

Comments
 (0)