mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Align more error messages with CPython 3.14.5 (#7988)
* Cannot assign to True/False/None * cannot use assignment expressions with ... * cannot assign to function call/expression
This commit is contained in:
1 parent
f347ae4fbb
commit
fbdf7c1052
5 files changed
+181
-95
No files matched your search
Vendored
+1
-1
@@ -2525,7 +2525,7 @@ Traceback (most recent call last):
|
||||
...
|
||||
SyntaxError: 'yield from' outside function
|
||||
|
||||
>>> def f(): x = yield = y # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE
|
||||
>>> def f(): x = yield = y
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SyntaxError: assignment to yield expression not possible
|
||||
|
||||
Vendored
+1
-1
@@ -154,7 +154,7 @@ Verify re-use of tuples (a side benefit of using genexps over listcomps)
|
||||
|
||||
Verify that syntax error's are raised for genexps used as lvalues
|
||||
|
||||
>>> (y for y in (1,2)) = 10 # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE
|
||||
>>> (y for y in (1,2)) = 10
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SyntaxError: cannot assign to generator expression
|
||||
|
||||
Vendored
-1
@@ -90,7 +90,6 @@ class NamedExpressionInvalidTest(unittest.TestCase):
|
||||
with self.assertRaisesRegex(SyntaxError, "invalid syntax"):
|
||||
exec(code, {}, {})
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; wrong error message
|
||||
def test_named_expression_invalid_15(self):
|
||||
code = """(lambda: x := 1)"""
|
||||
|
||||
|
||||
Vendored
+43
-43
@@ -31,7 +31,7 @@ Errors from set_context():
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax
|
||||
|
||||
>>> None = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> None = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to None
|
||||
|
||||
@@ -39,11 +39,11 @@ SyntaxError: cannot assign to None
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax
|
||||
|
||||
>>> True = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> True = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to True
|
||||
|
||||
>>> (True := 1) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> (True := 1)
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot use assignment expressions with True
|
||||
|
||||
@@ -79,7 +79,7 @@ SyntaxError: cannot delete __debug__
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
|
||||
|
||||
>>> yield = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> yield = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: assignment to yield expression not possible
|
||||
|
||||
@@ -91,23 +91,23 @@ SyntaxError: cannot delete function call
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?
|
||||
|
||||
>>> (x for x in x) = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> (x for x in x) = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to generator expression
|
||||
|
||||
>>> 1 = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> 1 = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?
|
||||
|
||||
>>> "abc" = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> "abc" = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?
|
||||
|
||||
>>> b"" = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> b"" = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to literal here. Maybe you meant '==' instead of '='?
|
||||
|
||||
>>> ... = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> ... = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to ellipsis here. Maybe you meant '==' instead of '='?
|
||||
|
||||
@@ -124,7 +124,7 @@ them.
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to literal
|
||||
|
||||
>>> (a, True, c) = (1, 2, 3) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> (a, True, c) = (1, 2, 3)
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to True
|
||||
|
||||
@@ -132,7 +132,7 @@ SyntaxError: cannot assign to True
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to __debug__
|
||||
|
||||
>>> (a, *True, c) = (1, 2, 3) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> (a, *True, c) = (1, 2, 3)
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to True
|
||||
|
||||
@@ -140,19 +140,19 @@ SyntaxError: cannot assign to True
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to __debug__
|
||||
|
||||
>>> [a, b, c + 1] = [1, 2, 3] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [a, b, c + 1] = [1, 2, 3]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> [a, b[1], c + 1] = [1, 2, 3] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [a, b[1], c + 1] = [1, 2, 3]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> [a, b.c.d, c + 1] = [1, 2, 3] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [a, b.c.d, c + 1] = [1, 2, 3]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> a if 1 else b = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> a if 1 else b = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to conditional expression
|
||||
|
||||
@@ -188,15 +188,15 @@ SyntaxError: expected expression before 'if', but statement is given
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax
|
||||
|
||||
>>> True = True = 3 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> True = True = 3
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to True
|
||||
|
||||
>>> x = y = True = z = 3 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> x = y = True = z = 3
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to True
|
||||
|
||||
>>> x = y = yield = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> x = y = yield = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: assignment to yield expression not possible
|
||||
|
||||
@@ -215,31 +215,31 @@ SyntaxError: 'list' is an illegal expression for augmented assignment
|
||||
Invalid targets in `for` loops and `with` statements should also
|
||||
produce a specialized error message
|
||||
|
||||
>>> for a() in b: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for a() in b: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> for (a, b()) in b: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for (a, b()) in b: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> for [a, b()] in b: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for [a, b()] in b: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> for (*a, b, c+1) in b: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for (*a, b, c+1) in b: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> for (x, *(y, z.d())) in b: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for (x, *(y, z.d())) in b: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> for a, b() in c: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for a, b() in c: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> for a, b, (c + 1, d()): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> for a, b, (c + 1, d()): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
@@ -251,27 +251,27 @@ SyntaxError: invalid syntax
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax
|
||||
|
||||
>>> with a as b(): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as b(): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> with a as (b, c()): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as (b, c()): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> with a as [b, c()]: pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as [b, c()]: pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> with a as (*b, c, d+1): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as (*b, c, d+1): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> with a as (x, *(y, z.d())): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as (x, *(y, z.d())): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> with a as b, c as d(): pass # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> with a as b, c as d(): pass
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
@@ -293,11 +293,11 @@ SyntaxError: 'in' expected after for-loop variables
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: 'in' expected after for-loop variables
|
||||
|
||||
>>> [x for x() in a] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [x for x() in a]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to function call
|
||||
|
||||
>>> [x for a, b, (c + 1, d()) in y] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [x for a, b, (c + 1, d()) in y]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
@@ -305,11 +305,11 @@ SyntaxError: cannot assign to expression
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: 'in' expected after for-loop variables
|
||||
|
||||
>>> [x for x+1 in y] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [x for x+1 in y]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
>>> [x for x+1, x() in y] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [x for x+1, x() in y]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to expression
|
||||
|
||||
@@ -334,19 +334,19 @@ SyntaxError: invalid syntax. Is this intended to be part of the string?
|
||||
# produce special error messages regarding missing
|
||||
# parentheses, but about missing commas instead
|
||||
|
||||
>>> [1, 2 3] # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> [1, 2 3]
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax. Perhaps you forgot a comma?
|
||||
|
||||
>>> {1, 2 3} # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> {1, 2 3}
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax. Perhaps you forgot a comma?
|
||||
|
||||
>>> {1:2, 2:5 3:12} # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> {1:2, 2:5 3:12}
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax. Perhaps you forgot a comma?
|
||||
|
||||
>>> (1, 2 3) # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> (1, 2 3)
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: invalid syntax. Perhaps you forgot a comma?
|
||||
|
||||
@@ -2114,19 +2114,19 @@ SyntaxError: cannot use subscript as import target
|
||||
# Check that we don't raise a "cannot use name as import target" error
|
||||
# if there is an error in an unrelated statement after ';'
|
||||
|
||||
>>> import a as b; None = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> import a as b; None = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to None
|
||||
|
||||
>>> import a, b as c; d = 1; None = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> import a, b as c; d = 1; None = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to None
|
||||
|
||||
>>> from a import b as c; None = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> from a import b as c; None = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to None
|
||||
|
||||
>>> from a import b, c as d; e = 1; None = 1 # TODO: RUSTPYTHON; Wrong error message # doctest: +EXPECTED_FAILURE
|
||||
>>> from a import b, c as d; e = 1; None = 1
|
||||
Traceback (most recent call last):
|
||||
SyntaxError: cannot assign to None
|
||||
|
||||
|
||||
+136
-49
@@ -1,4 +1,9 @@
|
||||
pub use ruff_python_ast::token::TokenKind;
|
||||
use ruff_python_parser::{LexicalErrorType, ParseErrorType};
|
||||
use ruff_source_file::{PositionEncoding, SourceFile, SourceFileBuilder, SourceLocation};
|
||||
use ruff_text_size::TextSlice;
|
||||
use thiserror::Error;
|
||||
|
||||
use rustpython_codegen::{compile, symboltable};
|
||||
|
||||
pub use rustpython_codegen::compile::CompileOpts;
|
||||
@@ -9,20 +14,19 @@ pub use ruff_python_ast as ast;
|
||||
pub use ruff_python_parser as parser;
|
||||
pub use rustpython_codegen as codegen;
|
||||
pub use rustpython_compiler_core as core;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CompileErrorType {
|
||||
#[error(transparent)]
|
||||
Codegen(#[from] codegen::error::CodegenErrorType),
|
||||
#[error(transparent)]
|
||||
Parse(#[from] parser::ParseErrorType),
|
||||
Parse(#[from] ParseErrorType),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub struct ParseError {
|
||||
#[source]
|
||||
pub error: parser::ParseErrorType,
|
||||
pub error: ParseErrorType,
|
||||
pub raw_location: ruff_text_size::TextRange,
|
||||
pub location: SourceLocation,
|
||||
pub end_location: SourceLocation,
|
||||
@@ -54,57 +58,140 @@ impl CompileError {
|
||||
// For EOF errors (unclosed brackets), find the unclosed bracket position
|
||||
// and adjust both the error location and message
|
||||
let mut is_unclosed_bracket = false;
|
||||
let (error_type, location, end_location) = if matches!(
|
||||
&error.error,
|
||||
parser::ParseErrorType::Lexical(parser::LexicalErrorType::Eof)
|
||||
) {
|
||||
if let Some((bracket_char, bracket_offset)) = find_unclosed_bracket(source_text) {
|
||||
let bracket_text_size = ruff_text_size::TextSize::new(bracket_offset as u32);
|
||||
let loc = source_code.source_location(bracket_text_size, PositionEncoding::Utf8);
|
||||
let end_loc = SourceLocation {
|
||||
line: loc.line,
|
||||
character_offset: loc.character_offset.saturating_add(1),
|
||||
};
|
||||
let msg = format!("'{bracket_char}' was never closed");
|
||||
is_unclosed_bracket = true;
|
||||
(parser::ParseErrorType::OtherError(msg), loc, end_loc)
|
||||
} else {
|
||||
let (error_type, location, end_location) = match &error.error {
|
||||
ParseErrorType::Lexical(LexicalErrorType::Eof) => {
|
||||
if let Some((bracket_char, bracket_offset)) = find_unclosed_bracket(source_text) {
|
||||
let bracket_text_size = ruff_text_size::TextSize::new(bracket_offset as u32);
|
||||
let loc =
|
||||
source_code.source_location(bracket_text_size, PositionEncoding::Utf8);
|
||||
let end_loc = SourceLocation {
|
||||
line: loc.line,
|
||||
character_offset: loc.character_offset.saturating_add(1),
|
||||
};
|
||||
let msg = format!("'{bracket_char}' was never closed");
|
||||
is_unclosed_bracket = true;
|
||||
(ParseErrorType::OtherError(msg), loc, end_loc)
|
||||
} else {
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
(error.error, loc, end_loc)
|
||||
}
|
||||
}
|
||||
|
||||
ParseErrorType::Lexical(LexicalErrorType::IndentationError) => {
|
||||
// For IndentationError, point the offset to the end of the line content
|
||||
// instead of the beginning
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let end_loc =
|
||||
let line_idx = loc.line.to_zero_indexed();
|
||||
let line = source_text.split('\n').nth(line_idx).unwrap_or("");
|
||||
let line_end_col = line.chars().count() + 1; // 1-indexed, past last char
|
||||
let end_loc = SourceLocation {
|
||||
line: loc.line,
|
||||
character_offset: ruff_source_file::OneIndexed::new(line_end_col)
|
||||
.unwrap_or(loc.character_offset),
|
||||
};
|
||||
(error.error, end_loc, end_loc)
|
||||
}
|
||||
ParseErrorType::ExpectedToken { expected, found }
|
||||
if matches!((expected, found), (TokenKind::Comma, TokenKind::Int)) =>
|
||||
{
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let mut end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
|
||||
// If the error range ends at the start of a new line (column 1),
|
||||
// adjust it to the end of the previous line
|
||||
if end_loc.character_offset.get() == 1 && end_loc.line > loc.line {
|
||||
let prev_line_end = error.location.end() - ruff_text_size::TextSize::from(1);
|
||||
end_loc = source_code.source_location(prev_line_end, PositionEncoding::Utf8);
|
||||
end_loc.character_offset = end_loc.character_offset.saturating_add(1);
|
||||
}
|
||||
let msg = "invalid syntax. Perhaps you forgot a comma?".into();
|
||||
(ParseErrorType::OtherError(msg), loc, end_loc)
|
||||
}
|
||||
|
||||
ParseErrorType::InvalidAssignmentTarget => {
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let mut end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
|
||||
// If the error range ends at the start of a new line (column 1),
|
||||
// adjust it to the end of the previous line
|
||||
if end_loc.character_offset.get() == 1 && end_loc.line > loc.line {
|
||||
let prev_line_end = error.location.end() - ruff_text_size::TextSize::from(1);
|
||||
end_loc = source_code.source_location(prev_line_end, PositionEncoding::Utf8);
|
||||
end_loc.character_offset = end_loc.character_offset.saturating_add(1);
|
||||
}
|
||||
|
||||
let expr_str = source_file.source_text().slice(error.location);
|
||||
|
||||
let msg = parser::parse_expression(expr_str).map_or_else(
|
||||
|_| match expr_str {
|
||||
"yield" => "assignment to yield expression not possible".into(),
|
||||
_ => format!("cannot assign to {expr_str}"),
|
||||
},
|
||||
|parsed| match *parsed.syntax().body {
|
||||
ast::Expr::Call(_) => "cannot assign to function call".into(),
|
||||
ast::Expr::BinOp(_) => "cannot assign to expression".into(),
|
||||
ast::Expr::If(_) => "cannot assign to conditional expression".into(),
|
||||
ast::Expr::Generator(_) => "cannot assign to generator expression".into(),
|
||||
ast::Expr::StringLiteral(_)
|
||||
| ast::Expr::BytesLiteral(_)
|
||||
| ast::Expr::NumberLiteral(_) => {
|
||||
"cannot assign to literal here. Maybe you meant '==' instead of '='?"
|
||||
.into()
|
||||
}
|
||||
ast::Expr::EllipsisLiteral(_) => {
|
||||
"cannot assign to ellipsis here. Maybe you meant '==' instead of '='?"
|
||||
.into()
|
||||
}
|
||||
_ => format!("cannot assign to {expr_str}"),
|
||||
},
|
||||
);
|
||||
|
||||
(ParseErrorType::OtherError(msg), loc, end_loc)
|
||||
}
|
||||
|
||||
ParseErrorType::InvalidNamedAssignmentTarget => {
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let mut end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
|
||||
// If the error range ends at the start of a new line (column 1),
|
||||
// adjust it to the end of the previous line
|
||||
if end_loc.character_offset.get() == 1 && end_loc.line > loc.line {
|
||||
let prev_line_end = error.location.end() - ruff_text_size::TextSize::from(1);
|
||||
end_loc = source_code.source_location(prev_line_end, PositionEncoding::Utf8);
|
||||
end_loc.character_offset = end_loc.character_offset.saturating_add(1);
|
||||
}
|
||||
|
||||
let target = source_file.source_text().slice(error.location);
|
||||
let msg = format!("cannot use assignment expressions with {target}");
|
||||
(ParseErrorType::OtherError(msg), loc, end_loc)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let loc =
|
||||
source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let mut end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
|
||||
// If the error range ends at the start of a new line (column 1),
|
||||
// adjust it to the end of the previous line
|
||||
if end_loc.character_offset.get() == 1 && end_loc.line > loc.line {
|
||||
let prev_line_end = error.location.end() - ruff_text_size::TextSize::from(1);
|
||||
end_loc = source_code.source_location(prev_line_end, PositionEncoding::Utf8);
|
||||
end_loc.character_offset = end_loc.character_offset.saturating_add(1);
|
||||
}
|
||||
|
||||
(error.error, loc, end_loc)
|
||||
}
|
||||
} else if matches!(
|
||||
&error.error,
|
||||
parser::ParseErrorType::Lexical(parser::LexicalErrorType::IndentationError)
|
||||
) {
|
||||
// For IndentationError, point the offset to the end of the line content
|
||||
// instead of the beginning
|
||||
let loc = source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let line_idx = loc.line.to_zero_indexed();
|
||||
let line = source_text.split('\n').nth(line_idx).unwrap_or("");
|
||||
let line_end_col = line.chars().count() + 1; // 1-indexed, past last char
|
||||
let end_loc = SourceLocation {
|
||||
line: loc.line,
|
||||
character_offset: ruff_source_file::OneIndexed::new(line_end_col)
|
||||
.unwrap_or(loc.character_offset),
|
||||
};
|
||||
(error.error, end_loc, end_loc)
|
||||
} else {
|
||||
let loc = source_code.source_location(error.location.start(), PositionEncoding::Utf8);
|
||||
let mut end_loc =
|
||||
source_code.source_location(error.location.end(), PositionEncoding::Utf8);
|
||||
|
||||
// If the error range ends at the start of a new line (column 1),
|
||||
// adjust it to the end of the previous line
|
||||
if end_loc.character_offset.get() == 1 && end_loc.line > loc.line {
|
||||
let prev_line_end = error.location.end() - ruff_text_size::TextSize::from(1);
|
||||
end_loc = source_code.source_location(prev_line_end, PositionEncoding::Utf8);
|
||||
end_loc.character_offset = end_loc.character_offset.saturating_add(1);
|
||||
}
|
||||
|
||||
(error.error, loc, end_loc)
|
||||
};
|
||||
|
||||
Self::Parse(ParseError {
|
||||
|
||||
Reference in new issue
Block a user