Skip to content

Commit 470d550

Browse files
committed
Bytecode DSL: fix f-strings with non-TruffleString components
1 parent a1da039 commit 470d550

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_string.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,3 +1210,22 @@ def test_raw_unicode_escape_does_not_alter_encoded_string():
12101210
original = "[\\xA0]"
12111211
decoded = bytes(original, encoding="raw-unicode-escape").decode("raw-unicode-escape")
12121212
assert original == decoded
1213+
1214+
1215+
def test_fstring():
1216+
class FunkyFormat:
1217+
def __init__(self, f):
1218+
self.f = f
1219+
def __format__(self, _):
1220+
return self.f
1221+
1222+
class FunkyStr(str):
1223+
def __str__(self):
1224+
return self
1225+
1226+
assert type(f"{FunkyStr('abc')}") == FunkyStr
1227+
assert type(f"hello {FunkyFormat('world')}!") == str
1228+
1229+
assert f"hello {FunkyFormat('world')}!" == "hello world!"
1230+
assert f"hello {FunkyStr('world')}!" == "hello world!"
1231+
assertRaises(TypeError, lambda: f"hello {FunkyFormat(33)}!")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@
218218
import com.oracle.graal.python.nodes.object.GetClassNode;
219219
import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode;
220220
import com.oracle.graal.python.nodes.object.IsNode;
221+
import com.oracle.graal.python.nodes.util.CannotCastException;
222+
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
221223
import com.oracle.graal.python.nodes.util.ExceptionStateNodes;
222224
import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext;
223225
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
@@ -3203,12 +3205,22 @@ public static final class BuildString {
32033205
public static Object perform(
32043206
int length,
32053207
@Variadic Object[] strings,
3208+
@Bind Node inliningTarget,
3209+
@Cached CastToTruffleStringNode castToStringNode,
32063210
@Cached TruffleStringBuilder.AppendStringNode appendNode,
3207-
@Cached TruffleStringBuilder.ToStringNode toString) {
3211+
@Cached TruffleStringBuilder.ToStringNode toString,
3212+
@Cached PRaiseNode raise) {
32083213
var tsb = TruffleStringBuilderUTF32.create(PythonUtils.TS_ENCODING);
32093214
CompilerAsserts.partialEvaluationConstant(length);
32103215
for (int i = 0; i < length; i++) {
3211-
appendNode.execute(tsb, (TruffleString) strings[i]);
3216+
try {
3217+
appendNode.execute(tsb, castToStringNode.execute(inliningTarget, strings[i]));
3218+
} catch (CannotCastException ex) {
3219+
// Python should only permit str literals or calls to `format` builtin as
3220+
// argument to this operation. The `format` builtin already ensures the result
3221+
// is a Python string.
3222+
throw CompilerDirectives.shouldNotReachHere(ex);
3223+
}
32123224
}
32133225
return toString.execute(tsb);
32143226
}

0 commit comments

Comments
 (0)