mirror of https://github.com/python/cpython
bpo-45759: Better error messages for non-matching 'elif'/'else' statements (#29513)
This commit is contained in:
parent
56e59a49ae
commit
1c8f912ebd
|
@ -124,6 +124,7 @@ simple_stmt[stmt_ty] (memo):
|
||||||
| &'nonlocal' nonlocal_stmt
|
| &'nonlocal' nonlocal_stmt
|
||||||
|
|
||||||
compound_stmt[stmt_ty]:
|
compound_stmt[stmt_ty]:
|
||||||
|
| invalid_compound_stmt
|
||||||
| &('def' | '@' | 'async') function_def
|
| &('def' | '@' | 'async') function_def
|
||||||
| &'if' if_stmt
|
| &'if' if_stmt
|
||||||
| &('class' | '@') class_def
|
| &('class' | '@') class_def
|
||||||
|
@ -1298,6 +1299,10 @@ invalid_import_from_targets:
|
||||||
| import_from_as_names ',' NEWLINE {
|
| import_from_as_names ',' NEWLINE {
|
||||||
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
|
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
|
||||||
|
|
||||||
|
invalid_compound_stmt:
|
||||||
|
| a='elif' named_expression ':' { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "'elif' must match an if-statement here") }
|
||||||
|
| a='else' ':' { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "'else' must match a valid statement here") }
|
||||||
|
|
||||||
invalid_with_stmt:
|
invalid_with_stmt:
|
||||||
| ['async'] 'with' ','.(expression ['as' star_target])+ NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
| ['async'] 'with' ','.(expression ['as' star_target])+ NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
||||||
| ['async'] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
| ['async'] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
|
||||||
|
|
|
@ -1752,6 +1752,28 @@ Corner-cases that used to crash:
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: positional patterns follow keyword patterns
|
SyntaxError: positional patterns follow keyword patterns
|
||||||
|
|
||||||
|
Non-matching 'elif'/'else' statements:
|
||||||
|
|
||||||
|
>>> if a == b:
|
||||||
|
... ...
|
||||||
|
... elif a == c:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: 'elif' must match an if-statement here
|
||||||
|
|
||||||
|
>>> if x == y:
|
||||||
|
... ...
|
||||||
|
... else:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: 'else' must match a valid statement here
|
||||||
|
|
||||||
|
>>> elif m == n:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: 'elif' must match an if-statement here
|
||||||
|
|
||||||
|
>>> else:
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: 'else' must match a valid statement here
|
||||||
|
|
||||||
Uses of the star operator which should fail:
|
Uses of the star operator which should fail:
|
||||||
|
|
||||||
A[:*b]
|
A[:*b]
|
||||||
|
@ -2006,8 +2028,8 @@ class SyntaxTestCase(unittest.TestCase):
|
||||||
lineno=None, offset=None, end_lineno=None, end_offset=None):
|
lineno=None, offset=None, end_lineno=None, end_offset=None):
|
||||||
"""Check that compiling code raises SyntaxError with errtext.
|
"""Check that compiling code raises SyntaxError with errtext.
|
||||||
|
|
||||||
errtest is a regular expression that must be present in the
|
errtext is a regular expression that must be present in the
|
||||||
test of the exception raised. If subclass is specified it
|
test of the exception raised. If subclass is specified, it
|
||||||
is the expected subclass of SyntaxError (e.g. IndentationError).
|
is the expected subclass of SyntaxError (e.g. IndentationError).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
@ -2031,6 +2053,22 @@ class SyntaxTestCase(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.fail("compile() did not raise SyntaxError")
|
self.fail("compile() did not raise SyntaxError")
|
||||||
|
|
||||||
|
def _check_noerror(self, code,
|
||||||
|
errtext="compile() raised unexpected SyntaxError",
|
||||||
|
filename="<testcase>", mode="exec", subclass=None):
|
||||||
|
"""Check that compiling code does not raise a SyntaxError.
|
||||||
|
|
||||||
|
errtext is the message passed to self.fail if there is
|
||||||
|
a SyntaxError. If the subclass parameter is specified,
|
||||||
|
it is the subclass of SyntaxError (e.g. IndentationError)
|
||||||
|
that the raised error is checked against.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
compile(code, filename, mode)
|
||||||
|
except SyntaxError as err:
|
||||||
|
if (not subclass) or isinstance(err, subclass):
|
||||||
|
self.fail(errtext)
|
||||||
|
|
||||||
def test_expression_with_assignment(self):
|
def test_expression_with_assignment(self):
|
||||||
self._check_error(
|
self._check_error(
|
||||||
"print(end1 + end2 = ' ')",
|
"print(end1 + end2 = ' ')",
|
||||||
|
@ -2372,6 +2410,25 @@ while 1:
|
||||||
"""
|
"""
|
||||||
self._check_error(source, "too many statically nested blocks")
|
self._check_error(source, "too many statically nested blocks")
|
||||||
|
|
||||||
|
def test_syntax_error_non_matching_elif_else_statements(self):
|
||||||
|
# Check bpo-45759: 'elif' statements that doesn't match an
|
||||||
|
# if-statement or 'else' statements that doesn't match any
|
||||||
|
# valid else-able statement (e.g. 'while')
|
||||||
|
self._check_error(
|
||||||
|
"elif m == n:\n ...",
|
||||||
|
"'elif' must match an if-statement here")
|
||||||
|
self._check_error(
|
||||||
|
"else:\n ...",
|
||||||
|
"'else' must match a valid statement here")
|
||||||
|
self._check_noerror("if a == b:\n ...\nelif a == c:\n ...")
|
||||||
|
self._check_noerror("if x == y:\n ...\nelse:\n ...")
|
||||||
|
self._check_error(
|
||||||
|
"else = 123",
|
||||||
|
"invalid syntax")
|
||||||
|
self._check_error(
|
||||||
|
"elif 55 = 123",
|
||||||
|
"cannot assign to literal here")
|
||||||
|
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
def test_error_on_parser_stack_overflow(self):
|
def test_error_on_parser_stack_overflow(self):
|
||||||
source = "-" * 100000 + "4"
|
source = "-" * 100000 + "4"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improved error messages for ``elif``/``else`` statements not matching any valid statements. Patch by Jeremiah Vivian.
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue