Skip to content

Commit 7184d68

Browse files
committed
[GR-21376] Update String#insert to call primitive replace
PullRequest: truffleruby/3368
2 parents 883e7e6 + beda3ff commit 7184d68

File tree

4 files changed

+27
-13
lines changed

4 files changed

+27
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Bug fixes:
1515
* Fix `rb_scan_args_kw` macro to avoid shadowing variables (#2649, @aardvark179).
1616
* Fix `String#unpack("Z")` to not advance after the null byte, like CRuby (#2659, @aardvark179).
1717
* Fix `Float#round` to avoid losing precision during the rounding process (@aardvark179).
18+
* Fix `String#insert` to not call a subclassed string method (@bjfish).
1819

1920
Compatibility:
2021

spec/ruby/core/string/insert_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,13 @@
6969
"あれ".insert 0, pat
7070
end.should raise_error(Encoding::CompatibilityError)
7171
end
72+
73+
it "should not call subclassed string methods" do
74+
cls = Class.new(String) do
75+
def replace(arg)
76+
raise "should not call replace"
77+
end
78+
end
79+
cls.new("abcd").insert(0, 'X').should == "Xabcd"
80+
end
7281
end

src/main/java/org/truffleruby/core/string/StringNodes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,10 +1882,10 @@ protected int ord(Object string,
18821882

18831883
}
18841884

1885-
@CoreMethod(names = "replace", required = 1, raiseIfNotMutableSelf = true)
1885+
@Primitive(name = "string_replace", raiseIfNotMutable = 0)
18861886
@NodeChild(value = "string", type = RubyNode.class)
18871887
@NodeChild(value = "other", type = RubyBaseNodeWithExecute.class)
1888-
public abstract static class ReplaceNode extends CoreMethodNode {
1888+
public abstract static class ReplaceNode extends PrimitiveNode {
18891889

18901890
@CreateCast("other")
18911891
protected ToStrNode coerceOtherToString(RubyBaseNodeWithExecute other) {

src/main/ruby/truffleruby/core/string.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ def hex
172172
Primitive.string_to_inum(self, 16, false, true)
173173
end
174174

175+
def replace(other)
176+
Primitive.string_replace(self, other)
177+
end
178+
175179
def reverse
176180
Primitive.dup_as_string_instance(self).reverse!
177181
end
@@ -392,7 +396,7 @@ def encode!(to=undefined, from=undefined, **options)
392396
status = ec.primitive_convert src, dest, nil, nil
393397
end
394398

395-
return replace(dest)
399+
return Primitive.string_replace(self, dest)
396400
else
397401
force_encoding to_enc
398402
end
@@ -568,10 +572,10 @@ def inspect
568572

569573
def prepend(*others)
570574
if others.size == 1
571-
replace(StringValue(others.first) + self)
575+
Primitive.string_replace(self, StringValue(others.first) + self)
572576
else
573577
reduced = others.reduce(''.encode(self.encoding)) { |memo, other| memo + StringValue(other) }
574-
replace(StringValue(reduced) + self)
578+
Primitive.string_replace(self, StringValue(reduced) + self)
575579
end
576580
end
577581

@@ -622,7 +626,7 @@ def sub(pattern, replacement=undefined, &block)
622626
matches = Truffle::StringOperations.gsub_internal_matches(false, self, pattern)
623627
res = Truffle::StringOperations.gsub_match_and_replace(s, matches, replacement, &block)
624628
Primitive.regexp_last_match_set(Primitive.caller_special_variables, matches.last)
625-
s.replace(res) if res
629+
Primitive.string_replace(s, res) if res
626630
s
627631
end
628632

@@ -637,7 +641,7 @@ def sub!(pattern, replacement=undefined, &block)
637641
res = Truffle::StringOperations.gsub_match_and_replace(self, matches, replacement, &block)
638642
Primitive.regexp_last_match_set(Primitive.caller_special_variables, matches.last)
639643
if res
640-
replace(res)
644+
Primitive.string_replace(self, res)
641645
self
642646
else
643647
nil
@@ -867,7 +871,7 @@ def gsub(pattern, replacement=undefined, &block)
867871
matches = Truffle::StringOperations.gsub_internal_matches(true, self, pattern)
868872
res = Truffle::StringOperations.gsub_match_and_replace(s, matches, replacement, &block)
869873
Primitive.regexp_last_match_set(Primitive.caller_special_variables, matches.last)
870-
s.replace(res) if res
874+
Primitive.string_replace(s, res) if res
871875
s
872876
end
873877

@@ -882,7 +886,7 @@ def gsub!(pattern, replacement=undefined, &block)
882886
res = Truffle::StringOperations.gsub_match_and_replace(self, matches, replacement, &block)
883887
Primitive.regexp_last_match_set(Primitive.caller_special_variables, matches.last)
884888
if res
885-
replace(res)
889+
Primitive.string_replace(self, res)
886890
self
887891
else
888892
nil
@@ -946,7 +950,7 @@ def scrub(replace = nil, &block)
946950

947951
def scrub!(replace = nil, &block)
948952
return self if valid_encoding?
949-
replace(scrub(replace, &block))
953+
Primitive.string_replace(self, scrub(replace, &block))
950954
self
951955
end
952956

@@ -1151,13 +1155,13 @@ def insert(index, other)
11511155
Primitive.check_mutable_string self
11521156

11531157
if index == 0
1154-
replace(other + self)
1158+
Primitive.string_replace(self, other + self)
11551159
elsif index == length
11561160
self << other
11571161
else
11581162
left = self[0...index]
11591163
right = self[index..-1]
1160-
replace(left + other + right)
1164+
Primitive.string_replace(self, left + other + right)
11611165
end
11621166

11631167
self
@@ -1297,7 +1301,7 @@ def unicode_normalize(form = :nfc)
12971301
end
12981302

12991303
def unicode_normalize!(form = :nfc)
1300-
replace(unicode_normalize(form))
1304+
Primitive.string_replace(self, unicode_normalize(form))
13011305
end
13021306

13031307
def unicode_normalized?(form = :nfc)

0 commit comments

Comments
 (0)