diff --git a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
index 6220133d98ee..e8acbb991e62 100644
--- a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
+++ b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
@@ -216,10 +216,16 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) {
super.visitPyStringLiteralExpression(node);
+ boolean seenBytes = false;
+ boolean seenNonBytes = false;
for (PyStringElement element : node.getStringElements()) {
final String prefix = element.getPrefix().toUpperCase();
if (prefix.isEmpty()) continue;
+ final boolean bytes = element.isBytes();
+ seenBytes |= bytes;
+ seenNonBytes |= !bytes;
+
final int elementStart = element.getTextOffset();
registerForAllMatchingVersions(level -> !getSupportedStringPrefixes(level).contains(prefix),
" not support a '" + prefix + "' prefix",
@@ -228,6 +234,13 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
new RemovePrefixQuickFix(prefix),
true);
}
+
+ if (seenBytes && seenNonBytes) {
+ registerForAllMatchingVersions(LanguageLevel::isPy3K,
+ " not allow to mix bytes and non-bytes literals",
+ node,
+ null);
+ }
}
@NotNull
diff --git a/python/testData/highlighting/mixedBytesAndNonBytes.py b/python/testData/highlighting/mixedBytesAndNonBytes.py
new file mode 100644
index 000000000000..cb5389001d8e
--- /dev/null
+++ b/python/testData/highlighting/mixedBytesAndNonBytes.py
@@ -0,0 +1,3 @@
+b'qwe'u'asd'
+b'qwe'r'asd'
+b'qwe'f'asd'
\ No newline at end of file
diff --git a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py
index 8c2b46f5ee61..e36ebcc2df16 100644
--- a/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py
+++ b/python/testData/inspections/PyCompatibilityInspection/stringLiteralExpression.py
@@ -45,8 +45,10 @@ a = u""
a = r""
a = ur""
-# combined
-b = u"" b""
+# combined, PY-32321
+b = u"" b""
+b = r"" b""
+b = f"" b""
# never was available
a = rr""
diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
index 26f01065f8d1..333295c65d30 100644
--- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
@@ -411,6 +411,11 @@ public class PythonHighlightingTest extends PyTestCase {
doTest(LanguageLevel.PYTHON36, false, false);
}
+ // PY-32321
+ public void testMixedBytesAndNonBytes() {
+ doTest(LanguageLevel.PYTHON36, false, false);
+ }
+
@NotNull
private static EditorColorsScheme createTemporaryColorScheme() {
EditorColorsManager manager = EditorColorsManager.getInstance();