Skip to content

Commit 145d23e

Browse files
committed
[GR-18163] Fix EncodingError message
PullRequest: truffleruby/3634
2 parents e11a36d + cf50df8 commit 145d23e

File tree

8 files changed

+53
-6
lines changed

8 files changed

+53
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Compatibility:
6969
* Support writing to `RData.dfree` for native extensions (#2830, #2732, #2165, @eregon).
7070
* Fix `IO#write` and support multiple arguments with different encodings (#2829, @andrykonchin).
7171
* Fix `Array` methods `reject`, `reject!`, `inject`, `map`, `select`, `each_index` and handle a case when array is modified by a passed block like CRuby does (#2822, andrykonchin, @eregon).
72+
* Fix `EncodingError` exception message when Symbol has invalid encoding (#2850, @andrykonchin).
73+
* Raise `EncodingError` at parse time when Hash literal contains a Symbol key with invalid encoding (#2848, @andrykonchin).
7274

7375
Performance:
7476

spec/ruby/core/string/shared/to_sym.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@
6767
invalid_utf8.should_not.valid_encoding?
6868
-> {
6969
invalid_utf8.send(@method)
70-
}.should raise_error(EncodingError, /invalid/)
70+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
7171
end
7272
end

spec/ruby/language/hash_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ def h.to_hash; {:b => 2, :c => 3}; end
177177
utf8_hash.keys.first.should == usascii_hash.keys.first
178178
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
179179
end
180+
181+
it "raises an EncodingError at parse time when Symbol key with invalid bytes" do
182+
ScratchPad.record []
183+
-> {
184+
eval 'ScratchPad << 1; {:"\xC3" => 1}'
185+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
186+
ScratchPad.recorded.should == []
187+
end
188+
189+
it "raises an EncodingError at parse time when Symbol key with invalid bytes and 'key: value' syntax used" do
190+
ScratchPad.record []
191+
-> {
192+
eval 'ScratchPad << 1; {"\xC3": 1}'
193+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
194+
ScratchPad.recorded.should == []
195+
end
180196
end
181197

182198
describe "The ** operator" do

spec/ruby/language/symbol_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,11 @@
9696
%I{a b #{"c"}}.should == [:a, :b, :c]
9797
end
9898

99-
it "with invalid bytes raises an EncodingError at parse time" do
99+
it "raises an EncodingError at parse time when Symbol with invalid bytes" do
100100
ScratchPad.record []
101101
-> {
102102
eval 'ScratchPad << 1; :"\xC3"'
103-
}.should raise_error(EncodingError, /invalid/)
103+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
104104
ScratchPad.recorded.should == []
105105
end
106106
end

src/main/java/org/truffleruby/core/exception/CoreExceptions.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1111,8 +1111,9 @@ public RubyException regexpError(String message, Node currentNode) {
11111111
// Encoding conversion errors.
11121112

11131113
@TruffleBoundary
1114-
public RubyException encodingError(String message, Node currentNode) {
1114+
public RubyException encodingError(Object string, RubyEncoding encoding, Node currentNode) {
11151115
RubyClass exceptionClass = context.getCoreLibrary().encodingErrorClass;
1116+
String message = StringUtils.format("invalid symbol in encoding %s :%s", encoding, inspect(string));
11161117
RubyString errorMessage = StringOperations.createUTF8String(context, language, message);
11171118

11181119
return ExceptionOperations.createRubyException(context, exceptionClass, errorMessage, currentNode, null);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2618,7 +2618,7 @@ protected RubySymbol toSymBroken(Object string, boolean preserveSymbol,
26182618
@Cached RubyStringLibrary strings,
26192619
@Bind("strings.getTString(string)") AbstractTruffleString tstring,
26202620
@Bind("strings.getEncoding(string)") RubyEncoding encoding) {
2621-
throw new RaiseException(getContext(), coreExceptions().encodingError("invalid encoding symbol", this));
2621+
throw new RaiseException(getContext(), coreExceptions().encodingError(string, encoding, this));
26222622
}
26232623
}
26242624

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,13 +1307,38 @@ public RubyNode visitDStrNode(DStrParseNode node) {
13071307
public RubyNode visitDSymbolNode(DSymbolParseNode node) {
13081308
SourceIndexLength sourceSection = node.getPosition();
13091309

1310+
// A special case for a symbol in Hash literal {"key": value}
1311+
if (node.size() == 1 && node.getLast() instanceof StrParseNode) {
1312+
final StrParseNode strParseNode = (StrParseNode) node.getLast();
1313+
final SymbolParseNode symbolParseNode = asSymbol(sourceSection, strParseNode);
1314+
return visitSymbolNode(symbolParseNode);
1315+
}
1316+
13101317
final RubyNode stringNode = translateInterpolatedString(sourceSection, node.getEncoding(), node.children());
13111318

13121319
final RubyNode ret = StringToSymbolNodeGen.create(stringNode);
13131320
ret.unsafeSetSourceSection(sourceSection);
13141321
return addNewlineIfNeeded(node, ret);
13151322
}
13161323

1324+
/** Same as {@link ParserSupport#asSymbol(SourceIndexLength position, ParseNode value)} but without needing a
1325+
* ParserSupport instance and only for StrParseNode argument. */
1326+
private SymbolParseNode asSymbol(SourceIndexLength position, StrParseNode value) {
1327+
final SymbolParseNode symbolParseNode = new SymbolParseNode(position, value.getValue(),
1328+
value.encoding);
1329+
1330+
if (!symbolParseNode.getTString().isValidUncached(symbolParseNode.getRubyEncoding().tencoding)) {
1331+
final RubyContext context = RubyLanguage.getCurrentContext();
1332+
throw new RaiseException(
1333+
RubyLanguage.getCurrentContext(),
1334+
context.getCoreExceptions().encodingError(
1335+
symbolParseNode.getTString(),
1336+
symbolParseNode.getRubyEncoding(),
1337+
null));
1338+
}
1339+
return symbolParseNode;
1340+
}
1341+
13171342
private RubyNode translateInterpolatedString(SourceIndexLength sourceSection,
13181343
Encoding encoding, ParseNode[] childNodes) {
13191344
final ToSNode[] children = new ToSNode[childNodes.length];

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,10 @@ private void checkSymbolCodeRange(SymbolParseNode symbolParseNode) {
12591259
if (!symbolParseNode.getTString().isValidUncached(symbolParseNode.getRubyEncoding().tencoding)) {
12601260
throw new RaiseException(
12611261
RubyLanguage.getCurrentContext(),
1262-
getConfiguration().getContext().getCoreExceptions().encodingError("invalid encoding symbol", null));
1262+
getConfiguration().getContext().getCoreExceptions().encodingError(
1263+
symbolParseNode.getTString(),
1264+
symbolParseNode.getRubyEncoding(),
1265+
null));
12631266
}
12641267
}
12651268

0 commit comments

Comments
 (0)