mirror of
https://github.com/python/cpython.git
synced 2025-08-27 12:16:04 +00:00
bpo-45759: Better error messages for non-matching 'elif'/'else' statements (#29513)
This commit is contained in:
parent
56e59a49ae
commit
1c8f912ebd
4 changed files with 598 additions and 437 deletions
|
@ -1752,6 +1752,28 @@ Corner-cases that used to crash:
|
|||
Traceback (most recent call last):
|
||||
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:
|
||||
|
||||
A[:*b]
|
||||
|
@ -2006,8 +2028,8 @@ class SyntaxTestCase(unittest.TestCase):
|
|||
lineno=None, offset=None, end_lineno=None, end_offset=None):
|
||||
"""Check that compiling code raises SyntaxError with errtext.
|
||||
|
||||
errtest is a regular expression that must be present in the
|
||||
test of the exception raised. If subclass is specified it
|
||||
errtext is a regular expression that must be present in the
|
||||
test of the exception raised. If subclass is specified, it
|
||||
is the expected subclass of SyntaxError (e.g. IndentationError).
|
||||
"""
|
||||
try:
|
||||
|
@ -2031,6 +2053,22 @@ class SyntaxTestCase(unittest.TestCase):
|
|||
else:
|
||||
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):
|
||||
self._check_error(
|
||||
"print(end1 + end2 = ' ')",
|
||||
|
@ -2372,6 +2410,25 @@ while 1:
|
|||
"""
|
||||
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
|
||||
def test_error_on_parser_stack_overflow(self):
|
||||
source = "-" * 100000 + "4"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue