mirror of
https://github.com/python/cpython.git
synced 2025-08-28 12:45:07 +00:00
bpo-35169: Improve error messages for forbidden assignments. (GH-10342)
This commit is contained in:
parent
6c48bf2d9e
commit
97f1efb606
6 changed files with 140 additions and 96 deletions
|
@ -73,11 +73,11 @@ class DictComprehensionTest(unittest.TestCase):
|
||||||
self.assertEqual(v, "Local variable")
|
self.assertEqual(v, "Local variable")
|
||||||
|
|
||||||
def test_illegal_assignment(self):
|
def test_illegal_assignment(self):
|
||||||
with self.assertRaisesRegex(SyntaxError, "can't assign"):
|
with self.assertRaisesRegex(SyntaxError, "cannot assign"):
|
||||||
compile("{x: y for y, x in ((1, 2), (3, 4))} = 5", "<test>",
|
compile("{x: y for y, x in ((1, 2), (3, 4))} = 5", "<test>",
|
||||||
"exec")
|
"exec")
|
||||||
|
|
||||||
with self.assertRaisesRegex(SyntaxError, "can't assign"):
|
with self.assertRaisesRegex(SyntaxError, "cannot assign"):
|
||||||
compile("{x: y for y, x in ((1, 2), (3, 4))} += 5", "<test>",
|
compile("{x: y for y, x in ((1, 2), (3, 4))} += 5", "<test>",
|
||||||
"exec")
|
"exec")
|
||||||
|
|
||||||
|
|
|
@ -1865,12 +1865,12 @@ SyntaxError: assignment to yield expression not possible
|
||||||
>>> def f(): (yield bar) = y
|
>>> def f(): (yield bar) = y
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to yield expression
|
SyntaxError: cannot assign to yield expression
|
||||||
|
|
||||||
>>> def f(): (yield bar) += y
|
>>> def f(): (yield bar) += y
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to yield expression
|
SyntaxError: cannot assign to yield expression
|
||||||
|
|
||||||
|
|
||||||
Now check some throw() conditions:
|
Now check some throw() conditions:
|
||||||
|
|
|
@ -137,12 +137,12 @@ Verify that syntax error's are raised for genexps used as lvalues
|
||||||
>>> (y for y in (1,2)) = 10
|
>>> (y for y in (1,2)) = 10
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to generator expression
|
SyntaxError: cannot assign to generator expression
|
||||||
|
|
||||||
>>> (y for y in (1,2)) += 10
|
>>> (y for y in (1,2)) += 10
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to generator expression
|
SyntaxError: cannot assign to generator expression
|
||||||
|
|
||||||
|
|
||||||
########### Tests borrowed from or inspired by test_generators.py ############
|
########### Tests borrowed from or inspired by test_generators.py ############
|
||||||
|
|
|
@ -33,35 +33,55 @@ SyntaxError: invalid syntax
|
||||||
|
|
||||||
>>> None = 1
|
>>> None = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to keyword
|
SyntaxError: cannot assign to None
|
||||||
|
|
||||||
|
>>> obj.True = 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: invalid syntax
|
||||||
|
|
||||||
|
>>> True = 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to True
|
||||||
|
|
||||||
|
>>> obj.__debug__ = 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
|
>>> __debug__ = 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> f() = 1
|
>>> f() = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
>>> del f()
|
>>> del f()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't delete function call
|
SyntaxError: cannot delete function call
|
||||||
|
|
||||||
>>> a + 1 = 2
|
>>> a + 1 = 2
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to operator
|
SyntaxError: cannot assign to operator
|
||||||
|
|
||||||
>>> (x for x in x) = 1
|
>>> (x for x in x) = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to generator expression
|
SyntaxError: cannot assign to generator expression
|
||||||
|
|
||||||
>>> 1 = 1
|
>>> 1 = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to literal
|
SyntaxError: cannot assign to literal
|
||||||
|
|
||||||
>>> "abc" = 1
|
>>> "abc" = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to literal
|
SyntaxError: cannot assign to literal
|
||||||
|
|
||||||
>>> b"" = 1
|
>>> b"" = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to literal
|
SyntaxError: cannot assign to literal
|
||||||
|
|
||||||
|
>>> ... = 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to Ellipsis
|
||||||
|
|
||||||
>>> `1` = 1
|
>>> `1` = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
|
@ -74,15 +94,31 @@ them.
|
||||||
|
|
||||||
>>> (a, "b", c) = (1, 2, 3)
|
>>> (a, "b", c) = (1, 2, 3)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to literal
|
SyntaxError: cannot assign to literal
|
||||||
|
|
||||||
|
>>> (a, True, c) = (1, 2, 3)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to True
|
||||||
|
|
||||||
|
>>> (a, __debug__, c) = (1, 2, 3)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
|
>>> (a, *True, c) = (1, 2, 3)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to True
|
||||||
|
|
||||||
|
>>> (a, *__debug__, c) = (1, 2, 3)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> [a, b, c + 1] = [1, 2, 3]
|
>>> [a, b, c + 1] = [1, 2, 3]
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to operator
|
SyntaxError: cannot assign to operator
|
||||||
|
|
||||||
>>> a if 1 else b = 1
|
>>> a if 1 else b = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to conditional expression
|
SyntaxError: cannot assign to conditional expression
|
||||||
|
|
||||||
From compiler_complex_args():
|
From compiler_complex_args():
|
||||||
|
|
||||||
|
@ -255,36 +291,45 @@ SyntaxError: invalid syntax
|
||||||
|
|
||||||
>>> f(lambda x: x[0] = 3)
|
>>> f(lambda x: x[0] = 3)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: lambda cannot contain assignment
|
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
|
||||||
|
|
||||||
The grammar accepts any test (basically, any expression) in the
|
The grammar accepts any test (basically, any expression) in the
|
||||||
keyword slot of a call site. Test a few different options.
|
keyword slot of a call site. Test a few different options.
|
||||||
|
|
||||||
>>> f(x()=2)
|
>>> f(x()=2)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: keyword can't be an expression
|
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
|
||||||
>>> f(a or b=1)
|
>>> f(a or b=1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: keyword can't be an expression
|
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
|
||||||
>>> f(x.y=1)
|
>>> f(x.y=1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: keyword can't be an expression
|
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
|
||||||
>>> f((x)=2)
|
>>> f((x)=2)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: keyword can't be an expression
|
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
|
||||||
|
>>> f(True=2)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to True
|
||||||
|
>>> f(__debug__=1)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
|
|
||||||
More set_context():
|
More set_context():
|
||||||
|
|
||||||
>>> (x for x in x) += 1
|
>>> (x for x in x) += 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to generator expression
|
SyntaxError: cannot assign to generator expression
|
||||||
>>> None += 1
|
>>> None += 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to keyword
|
SyntaxError: cannot assign to None
|
||||||
|
>>> __debug__ += 1
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to __debug__
|
||||||
>>> f() += 1
|
>>> f() += 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
|
|
||||||
Test continue in finally in weird combinations.
|
Test continue in finally in weird combinations.
|
||||||
|
@ -481,7 +526,7 @@ leading to spurious errors.
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
>>> if 1:
|
>>> if 1:
|
||||||
... pass
|
... pass
|
||||||
|
@ -489,7 +534,7 @@ leading to spurious errors.
|
||||||
... x() = 1
|
... x() = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
>>> if 1:
|
>>> if 1:
|
||||||
... x() = 1
|
... x() = 1
|
||||||
|
@ -499,7 +544,7 @@ leading to spurious errors.
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
>>> if 1:
|
>>> if 1:
|
||||||
... pass
|
... pass
|
||||||
|
@ -509,7 +554,7 @@ leading to spurious errors.
|
||||||
... pass
|
... pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
>>> if 1:
|
>>> if 1:
|
||||||
... pass
|
... pass
|
||||||
|
@ -519,7 +564,7 @@ leading to spurious errors.
|
||||||
... x() = 1
|
... x() = 1
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
SyntaxError: can't assign to function call
|
SyntaxError: cannot assign to function call
|
||||||
|
|
||||||
Make sure that the old "raise X, Y[, Z]" form is gone:
|
Make sure that the old "raise X, Y[, Z]" form is gone:
|
||||||
>>> raise X, Y
|
>>> raise X, Y
|
||||||
|
@ -539,21 +584,33 @@ SyntaxError: keyword argument repeated
|
||||||
|
|
||||||
>>> {1, 2, 3} = 42
|
>>> {1, 2, 3} = 42
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: can't assign to literal
|
SyntaxError: cannot assign to set display
|
||||||
|
|
||||||
|
>>> {1: 2, 3: 4} = 42
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to dict display
|
||||||
|
|
||||||
|
>>> f'{x}' = 42
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to f-string expression
|
||||||
|
|
||||||
|
>>> f'{x}-{y}' = 42
|
||||||
|
Traceback (most recent call last):
|
||||||
|
SyntaxError: cannot assign to f-string expression
|
||||||
|
|
||||||
Corner-cases that used to fail to raise the correct error:
|
Corner-cases that used to fail to raise the correct error:
|
||||||
|
|
||||||
>>> def f(*, x=lambda __debug__:0): pass
|
>>> def f(*, x=lambda __debug__:0): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: assignment to keyword
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> def f(*args:(lambda __debug__:0)): pass
|
>>> def f(*args:(lambda __debug__:0)): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: assignment to keyword
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> def f(**kwargs:(lambda __debug__:0)): pass
|
>>> def f(**kwargs:(lambda __debug__:0)): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: assignment to keyword
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> with (lambda *:0): pass
|
>>> with (lambda *:0): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
|
@ -563,11 +620,11 @@ Corner-cases that used to crash:
|
||||||
|
|
||||||
>>> def f(**__debug__): pass
|
>>> def f(**__debug__): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: assignment to keyword
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
>>> def f(*xx, __debug__): pass
|
>>> def f(*xx, __debug__): pass
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
SyntaxError: assignment to keyword
|
SyntaxError: cannot assign to __debug__
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improved error messages for forbidden assignments.
|
106
Python/ast.c
106
Python/ast.c
|
@ -647,21 +647,25 @@ new_identifier(const char *n, struct compiling *c)
|
||||||
#define NEW_IDENTIFIER(n) new_identifier(STR(n), c)
|
#define NEW_IDENTIFIER(n) new_identifier(STR(n), c)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ast_error(struct compiling *c, const node *n, const char *errmsg)
|
ast_error(struct compiling *c, const node *n, const char *errmsg, ...)
|
||||||
{
|
{
|
||||||
PyObject *value, *errstr, *loc, *tmp;
|
PyObject *value, *errstr, *loc, *tmp;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start(va, errmsg);
|
||||||
|
errstr = PyUnicode_FromFormatV(errmsg, va);
|
||||||
|
va_end(va);
|
||||||
|
if (!errstr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
loc = PyErr_ProgramTextObject(c->c_filename, LINENO(n));
|
loc = PyErr_ProgramTextObject(c->c_filename, LINENO(n));
|
||||||
if (!loc) {
|
if (!loc) {
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
loc = Py_None;
|
loc = Py_None;
|
||||||
}
|
}
|
||||||
tmp = Py_BuildValue("(OiiN)", c->c_filename, LINENO(n), n->n_col_offset + 1, loc);
|
tmp = Py_BuildValue("(OiiN)", c->c_filename, LINENO(n), n->n_col_offset + 1, loc);
|
||||||
if (!tmp)
|
if (!tmp) {
|
||||||
return 0;
|
Py_DECREF(errstr);
|
||||||
errstr = PyUnicode_FromString(errmsg);
|
|
||||||
if (!errstr) {
|
|
||||||
Py_DECREF(tmp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
value = PyTuple_Pack(2, errstr, tmp);
|
value = PyTuple_Pack(2, errstr, tmp);
|
||||||
|
@ -903,6 +907,7 @@ static const char * const FORBIDDEN[] = {
|
||||||
"None",
|
"None",
|
||||||
"True",
|
"True",
|
||||||
"False",
|
"False",
|
||||||
|
"__debug__",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -911,17 +916,16 @@ forbidden_name(struct compiling *c, identifier name, const node *n,
|
||||||
int full_checks)
|
int full_checks)
|
||||||
{
|
{
|
||||||
assert(PyUnicode_Check(name));
|
assert(PyUnicode_Check(name));
|
||||||
if (_PyUnicode_EqualToASCIIString(name, "__debug__")) {
|
const char * const *p = FORBIDDEN;
|
||||||
ast_error(c, n, "assignment to keyword");
|
if (!full_checks) {
|
||||||
return 1;
|
/* In most cases, the parser will protect True, False, and None
|
||||||
|
from being assign to. */
|
||||||
|
p += 3;
|
||||||
}
|
}
|
||||||
if (full_checks) {
|
for (; *p; p++) {
|
||||||
const char * const *p;
|
if (_PyUnicode_EqualToASCIIString(name, *p)) {
|
||||||
for (p = FORBIDDEN; *p; p++) {
|
ast_error(c, n, "cannot assign to %U", name);
|
||||||
if (_PyUnicode_EqualToASCIIString(name, *p)) {
|
return 1;
|
||||||
ast_error(c, n, "assignment to keyword");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1012,22 +1016,25 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
|
||||||
expr_name = "dict comprehension";
|
expr_name = "dict comprehension";
|
||||||
break;
|
break;
|
||||||
case Dict_kind:
|
case Dict_kind:
|
||||||
|
expr_name = "dict display";
|
||||||
|
break;
|
||||||
case Set_kind:
|
case Set_kind:
|
||||||
|
expr_name = "set display";
|
||||||
|
break;
|
||||||
case JoinedStr_kind:
|
case JoinedStr_kind:
|
||||||
case FormattedValue_kind:
|
case FormattedValue_kind:
|
||||||
expr_name = "literal";
|
expr_name = "f-string expression";
|
||||||
break;
|
break;
|
||||||
case Constant_kind: {
|
case Constant_kind: {
|
||||||
PyObject *value = e->v.Constant.value;
|
PyObject *value = e->v.Constant.value;
|
||||||
if (value == Py_None || value == Py_False || value == Py_True) {
|
if (value == Py_None || value == Py_False || value == Py_True
|
||||||
expr_name = "keyword";
|
|| value == Py_Ellipsis)
|
||||||
}
|
{
|
||||||
else if (value == Py_Ellipsis) {
|
return ast_error(c, n, "cannot %s %R",
|
||||||
expr_name = "Ellipsis";
|
ctx == Store ? "assign to" : "delete",
|
||||||
}
|
value);
|
||||||
else {
|
|
||||||
expr_name = "literal";
|
|
||||||
}
|
}
|
||||||
|
expr_name = "literal";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Compare_kind:
|
case Compare_kind:
|
||||||
|
@ -1044,12 +1051,9 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
|
||||||
}
|
}
|
||||||
/* Check for error string set by switch */
|
/* Check for error string set by switch */
|
||||||
if (expr_name) {
|
if (expr_name) {
|
||||||
char buf[300];
|
return ast_error(c, n, "cannot %s %s",
|
||||||
PyOS_snprintf(buf, sizeof(buf),
|
ctx == Store ? "assign to" : "delete",
|
||||||
"can't %s %s",
|
expr_name);
|
||||||
ctx == Store ? "assign to" : "delete",
|
|
||||||
expr_name);
|
|
||||||
return ast_error(c, n, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the LHS is a list or tuple, we need to set the assignment
|
/* If the LHS is a list or tuple, we need to set the assignment
|
||||||
|
@ -2083,21 +2087,17 @@ ast_for_atom(struct compiling *c, const node *n)
|
||||||
else if (PyErr_ExceptionMatches(PyExc_ValueError))
|
else if (PyErr_ExceptionMatches(PyExc_ValueError))
|
||||||
errtype = "value error";
|
errtype = "value error";
|
||||||
if (errtype) {
|
if (errtype) {
|
||||||
char buf[128];
|
|
||||||
const char *s = NULL;
|
|
||||||
PyObject *type, *value, *tback, *errstr;
|
PyObject *type, *value, *tback, *errstr;
|
||||||
PyErr_Fetch(&type, &value, &tback);
|
PyErr_Fetch(&type, &value, &tback);
|
||||||
errstr = PyObject_Str(value);
|
errstr = PyObject_Str(value);
|
||||||
if (errstr)
|
if (errstr) {
|
||||||
s = PyUnicode_AsUTF8(errstr);
|
ast_error(c, n, "(%s) %U", errtype, errstr);
|
||||||
if (s) {
|
Py_DECREF(errstr);
|
||||||
PyOS_snprintf(buf, sizeof(buf), "(%s) %s", errtype, s);
|
}
|
||||||
} else {
|
else {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
PyOS_snprintf(buf, sizeof(buf), "(%s) unknown error", errtype);
|
ast_error(c, n, "(%s) unknown error", errtype);
|
||||||
}
|
}
|
||||||
Py_XDECREF(errstr);
|
|
||||||
ast_error(c, n, buf);
|
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
Py_XDECREF(value);
|
Py_XDECREF(value);
|
||||||
Py_XDECREF(tback);
|
Py_XDECREF(tback);
|
||||||
|
@ -2815,18 +2815,10 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func, bool allowgen)
|
||||||
break;
|
break;
|
||||||
expr_node = CHILD(expr_node, 0);
|
expr_node = CHILD(expr_node, 0);
|
||||||
}
|
}
|
||||||
if (TYPE(expr_node) == lambdef) {
|
if (TYPE(expr_node) != NAME) {
|
||||||
// f(lambda x: x[0] = 3) ends up getting parsed with LHS
|
|
||||||
// test = lambda x: x[0], and RHS test = 3. Issue #132313
|
|
||||||
// points out that complaining about a keyword then is very
|
|
||||||
// confusing.
|
|
||||||
ast_error(c, chch,
|
ast_error(c, chch,
|
||||||
"lambda cannot contain assignment");
|
"expression cannot contain assignment, "
|
||||||
return NULL;
|
"perhaps you meant \"==\"?");
|
||||||
}
|
|
||||||
else if (TYPE(expr_node) != NAME) {
|
|
||||||
ast_error(c, chch,
|
|
||||||
"keyword can't be an expression");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
key = new_identifier(STR(expr_node), c);
|
key = new_identifier(STR(expr_node), c);
|
||||||
|
@ -4127,16 +4119,10 @@ warn_invalid_escape_sequence(struct compiling *c, const node *n,
|
||||||
NULL, NULL) < 0)
|
NULL, NULL) < 0)
|
||||||
{
|
{
|
||||||
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
|
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
|
||||||
const char *s;
|
|
||||||
|
|
||||||
/* Replace the SyntaxWarning exception with a SyntaxError
|
/* Replace the SyntaxWarning exception with a SyntaxError
|
||||||
to get a more accurate error report */
|
to get a more accurate error report */
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
ast_error(c, n, "%U", msg);
|
||||||
s = PyUnicode_AsUTF8(msg);
|
|
||||||
if (s != NULL) {
|
|
||||||
ast_error(c, n, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Py_DECREF(msg);
|
Py_DECREF(msg);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue