Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fix more
  • Loading branch information
ShaharNaveh committed May 20, 2026
commit c17af963bc86c1f17194a13c07e1e26816442f1f
67 changes: 33 additions & 34 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@
Traceback (most recent call last):
SyntaxError: cannot assign to conditional expression

>>> a = 42 if True # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> a = 42 if True
Traceback (most recent call last):
SyntaxError: expected 'else' after 'if' expression

>>> a = (42 if True) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> a = (42 if True)
Traceback (most recent call last):
SyntaxError: expected 'else' after 'if' expression

>>> a = [1, 42 if True, 4] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> a = [1, 42 if True, 4]
Traceback (most recent call last):
SyntaxError: expected 'else' after 'if' expression

Expand Down Expand Up @@ -275,7 +275,7 @@
Traceback (most recent call last):
SyntaxError: cannot assign to function call

>>> with a as b # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with a as b
Traceback (most recent call last):
SyntaxError: expected ':'

Expand Down Expand Up @@ -1093,27 +1093,27 @@

Missing ':' before suites:

>>> def f() # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> def f()
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> def f[T]() # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> def f[T]()
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> class A # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> class A
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> class A[T] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> class A[T]
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> class A[T]() # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> class A[T]()
... pass
Traceback (most recent call last):
SyntaxError: expected ':'
Expand All @@ -1123,7 +1123,7 @@
Traceback (most recent call last):
SyntaxError: invalid syntax

>>> if 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> if 1
... pass
... elif 1:
... pass
Expand All @@ -1132,7 +1132,7 @@
Traceback (most recent call last):
SyntaxError: expected ':'

>>> if 1: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> if 1:
... pass
... elif 1
... pass
Expand All @@ -1141,7 +1141,7 @@
Traceback (most recent call last):
SyntaxError: expected ':'

>>> if 1: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> if 1:
... pass
... elif 1:
... pass
Expand All @@ -1150,7 +1150,7 @@
Traceback (most recent call last):
SyntaxError: expected ':'

>>> for x in range(10) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> for x in range(10)
... pass
Traceback (most recent call last):
SyntaxError: expected ':'
Expand All @@ -1160,47 +1160,47 @@
Traceback (most recent call last):
SyntaxError: invalid syntax

>>> while True # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> while True
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with blech as something # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with blech as something
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with blech # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with blech
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with blech, block as something # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with blech, block as something
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with blech, block as something, bluch # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with blech, block as something, bluch
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with (blech as something) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with (blech as something)
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with (blech) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with (blech)
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with (blech, block as something) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with (blech, block as something)
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> with (blech, block as something, bluch) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> with (blech, block as something, bluch)
... pass
Traceback (most recent call last):
SyntaxError: expected ':'
Expand All @@ -1210,19 +1210,19 @@
Traceback (most recent call last):
SyntaxError: invalid syntax. Did you mean 'and'?

>>> try # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> try
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> try: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> try:
... pass
... except
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> match x # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> match x
... case list():
... pass
Traceback (most recent call last):
Expand All @@ -1234,13 +1234,13 @@
Traceback (most recent call last):
SyntaxError: invalid syntax

>>> match x: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> match x:
... case list()
... pass
Traceback (most recent call last):
SyntaxError: expected ':'

>>> match x: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> match x:
... case [y] if y > 0
... pass
Traceback (most recent call last):
Expand Down Expand Up @@ -1287,27 +1287,27 @@

Missing parens after function definition

>>> def f: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> def f:
Traceback (most recent call last):
SyntaxError: expected '('

>>> async def f: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> async def f:
Traceback (most recent call last):
SyntaxError: expected '('

>>> def f -> int: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> def f -> int:
Traceback (most recent call last):
SyntaxError: expected '('

>>> async def f -> int: # type: int # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> async def f -> int: # type: int
Traceback (most recent call last):
SyntaxError: expected '('

>>> async def f[T]: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> async def f[T]:
Traceback (most recent call last):
SyntaxError: expected '('

>>> def f[T] -> str: # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
>>> def f[T] -> str:
Traceback (most recent call last):
SyntaxError: expected '('

Expand Down Expand Up @@ -3092,7 +3092,6 @@ async def bug():
with self.subTest(f"out of range: {n=}"):
self._check_error(get_code(n), "too many statically nested blocks")

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_barry_as_flufl_with_syntax_errors(self):
# The "barry_as_flufl" rule can produce some "bugs-at-a-distance" if
# is reading the wrong token in the presence of syntax errors later
Expand Down
44 changes: 33 additions & 11 deletions crates/vm/src/vm/vm_new.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(feature = "parser")]
use ruff_python_ast::token::TokenKind;

use ruff_python_parser::{InterpolatedStringErrorType, LexicalErrorType, ParseErrorType};

use rustpython_common::wtf8::Wtf8Buf;
Expand Down Expand Up @@ -59,6 +62,22 @@ impl SyntaxErrorInfo {
self.narrow_caret = narrow_caret;
}

#[cfg(feature = "parser")]
#[must_use]
const fn handle_expected_token(expected: &TokenKind, found: &TokenKind) -> &'static str {
match (*expected, *found) {
(TokenKind::Colon, TokenKind::Newline) => "expected ':'",

(TokenKind::Lpar, _) => "expected '('",

(TokenKind::Else, y) if !matches!(y, TokenKind::Colon) => {
"expected 'else' after 'if' expression"
}

_ => "invalid syntax",
}
}

#[cfg(feature = "parser")]
fn analyze_compile_error(&mut self, compile_error: &CompileError) {
let CompileError::Parse(ParseError {
Expand Down Expand Up @@ -89,11 +108,9 @@ impl SyntaxErrorInfo {

ParseErrorType::UnexpectedExpressionToken => format!("invalid syntax: {}", self.msg),

ParseErrorType::Lexical(LexicalErrorType::UnrecognizedToken { .. })
| ParseErrorType::SimpleStatementsOnSameLine
| ParseErrorType::SimpleAndCompoundStatementOnSameLine
| ParseErrorType::ExpectedToken { .. }
| ParseErrorType::ExpectedExpression => "invalid syntax".into(),
ParseErrorType::ExpectedToken { expected, found } => {
Self::handle_expected_token(expected, found).into()
}

ParseErrorType::InvalidStarredExpressionUsage => {
self.with_narrow_caret(true);
Expand Down Expand Up @@ -156,18 +173,23 @@ impl SyntaxErrorInfo {
"arguments cannot follow var-keyword argument".into()
}

ParseErrorType::Lexical(LexicalErrorType::UnrecognizedToken { .. })
| ParseErrorType::SimpleStatementsOnSameLine
| ParseErrorType::SimpleAndCompoundStatementOnSameLine
| ParseErrorType::ExpectedExpression => "invalid syntax".into(),

ParseErrorType::OtherError(s)
if s.eq_ignore_ascii_case(
"bytes literal cannot be mixed with non-bytes literals",
) =>
if s.starts_with("Expected an identifier, but found a keyword") =>
{
"cannot mix bytes and nonbytes literals".into()
"invalid syntax".into()
}

ParseErrorType::OtherError(s)
if s.starts_with("Expected an identifier, but found a keyword") =>
if s.eq_ignore_ascii_case(
"bytes literal cannot be mixed with non-bytes literals",
) =>
{
"invalid syntax".into()
"cannot mix bytes and nonbytes literals".into()
}

ParseErrorType::OtherError(s)
Expand Down
Loading