mirror of
https://github.com/davidhalter/parso.git
synced 2025-12-07 21:34:32 +08:00
Adjust invalid aug assign target for 3.9+
This commit is contained in:
committed by
Dave Halter
parent
d6b1d19d87
commit
6f29c551fd
@@ -18,6 +18,79 @@ ALLOWED_FUTURES = (
|
||||
)
|
||||
_COMP_FOR_TYPES = ('comp_for', 'sync_comp_for')
|
||||
|
||||
def _get_rhs_name(node, version):
|
||||
type_ = node.type
|
||||
if type_ == "lambdef":
|
||||
return "lambda"
|
||||
elif type_ == "atom":
|
||||
comprehension = _get_comprehension_type(node)
|
||||
first, second = node.children[:2]
|
||||
if comprehension is not None:
|
||||
return comprehension
|
||||
elif second.type == "dictorsetmaker":
|
||||
if version < (3, 8):
|
||||
return "literal"
|
||||
else:
|
||||
if second.children[1] == ":" or second.children[0] == "**":
|
||||
return "dict display"
|
||||
else:
|
||||
return "set display"
|
||||
elif (
|
||||
first == "("
|
||||
and (second == ")"
|
||||
or (len(node.children) == 3 and node.children[1].type == "testlist_comp"))
|
||||
):
|
||||
return "tuple"
|
||||
elif first == "(":
|
||||
return _get_rhs_name(_remove_parens(node), version=version)
|
||||
elif first == "[":
|
||||
return "list"
|
||||
elif first == "{" and second == "}":
|
||||
return "dict display"
|
||||
elif first == "{" and len(node.children) > 2:
|
||||
return "set display"
|
||||
elif type_ == "keyword":
|
||||
if "yield" in node.value:
|
||||
return "yield expression"
|
||||
if version < (3, 8):
|
||||
return "keyword"
|
||||
else:
|
||||
return str(node.value)
|
||||
elif type_ == "operator" and node.value == "...":
|
||||
return "Ellipsis"
|
||||
elif type_ == "comparison":
|
||||
return "comparison"
|
||||
elif type_ in ("string", "number", "strings"):
|
||||
return "literal"
|
||||
elif type_ == "yield_expr":
|
||||
return "yield expression"
|
||||
elif type_ == "test":
|
||||
return "conditional expression"
|
||||
elif type_ in ("atom_expr", "power"):
|
||||
if node.children[0] == "await":
|
||||
return "await expression"
|
||||
elif node.children[-1].type == "trailer":
|
||||
trailer = node.children[-1]
|
||||
if trailer.children[0] == "(":
|
||||
return "function call"
|
||||
elif trailer.children[0] == "[":
|
||||
return "subscript"
|
||||
elif trailer.children[0] == ".":
|
||||
return "attribute"
|
||||
elif (
|
||||
("expr" in type_
|
||||
and "star_expr" not in type_) # is a substring
|
||||
or "_test" in type_
|
||||
or type_ in ("term", "factor")
|
||||
):
|
||||
return "operator"
|
||||
elif type_ == "star_expr":
|
||||
return "starred"
|
||||
elif type_ == "testlist_star_expr":
|
||||
return "tuple"
|
||||
elif type_ == "fstring":
|
||||
return "f-string expression"
|
||||
return type_ # shouldn't reach here
|
||||
|
||||
def _iter_stmts(scope):
|
||||
"""
|
||||
@@ -926,6 +999,16 @@ class _CheckAssignmentRule(SyntaxRule):
|
||||
error = 'dict display'
|
||||
else:
|
||||
error = 'set display'
|
||||
elif first == "{" and second == "}":
|
||||
if self._normalizer.version < (3, 8):
|
||||
error = 'literal'
|
||||
else:
|
||||
error = "dict display"
|
||||
elif first == "{" and len(node.children) > 2:
|
||||
if self._normalizer.version < (3, 8):
|
||||
error = 'literal'
|
||||
else:
|
||||
error = "set display"
|
||||
elif first in ('(', '['):
|
||||
if second.type == 'yield_expr':
|
||||
error = 'yield expression'
|
||||
@@ -945,7 +1028,9 @@ class _CheckAssignmentRule(SyntaxRule):
|
||||
else: # Everything handled, must be useless brackets.
|
||||
self._check_assignment(second, is_deletion, is_namedexpr)
|
||||
elif type_ == 'keyword':
|
||||
if self._normalizer.version < (3, 8):
|
||||
if node.value == "yield":
|
||||
error = "yield expression"
|
||||
elif self._normalizer.version < (3, 8):
|
||||
error = 'keyword'
|
||||
else:
|
||||
error = str(node.value)
|
||||
@@ -977,6 +1062,11 @@ class _CheckAssignmentRule(SyntaxRule):
|
||||
error = 'subscript'
|
||||
elif is_namedexpr and trailer.children[0] == '.':
|
||||
error = 'attribute'
|
||||
elif type_ == "fstring":
|
||||
if self._normalizer.version < (3, 8):
|
||||
error = 'literal'
|
||||
else:
|
||||
error = "f-string expression"
|
||||
elif type_ in ('testlist_star_expr', 'exprlist', 'testlist'):
|
||||
for child in node.children[::2]:
|
||||
self._check_assignment(child, is_deletion, is_namedexpr)
|
||||
@@ -1012,15 +1102,35 @@ class _CompForRule(_CheckAssignmentRule):
|
||||
@ErrorFinder.register_rule(type='expr_stmt')
|
||||
class _ExprStmtRule(_CheckAssignmentRule):
|
||||
message = "illegal expression for augmented assignment"
|
||||
|
||||
extended_message = "'{target}' is an " + message
|
||||
def is_issue(self, node):
|
||||
for before_equal in node.children[:-2:2]:
|
||||
self._check_assignment(before_equal)
|
||||
|
||||
augassign = node.children[1]
|
||||
if augassign != '=' and augassign.type != 'annassign': # Is augassign.
|
||||
return node.children[0].type in ('testlist_star_expr', 'atom', 'testlist')
|
||||
is_aug_assign = augassign != '=' and augassign.type != 'annassign'
|
||||
|
||||
if self._normalizer.version <= (3, 8) or not is_aug_assign:
|
||||
for before_equal in node.children[:-2:2]:
|
||||
self._check_assignment(before_equal)
|
||||
|
||||
if is_aug_assign:
|
||||
target = _remove_parens(node.children[0])
|
||||
# a, a[b], a.b
|
||||
|
||||
if target.type == "name" or (
|
||||
target.type in ("atom_expr", "power")
|
||||
and target.children[1].type == "trailer"
|
||||
and target.children[-1].children[0] != "("
|
||||
):
|
||||
return False
|
||||
|
||||
if self._normalizer.version <= (3, 8):
|
||||
return True
|
||||
else:
|
||||
self.add_issue(
|
||||
node,
|
||||
message=self.extended_message.format(
|
||||
target=_get_rhs_name(node.children[0], self._normalizer.version)
|
||||
),
|
||||
)
|
||||
|
||||
@ErrorFinder.register_rule(type='with_item')
|
||||
class _WithItemRule(_CheckAssignmentRule):
|
||||
|
||||
@@ -52,9 +52,37 @@ FAILING_EXAMPLES = [
|
||||
'f(x=2, y)',
|
||||
'f(**x, *y)',
|
||||
'f(**x, y=3, z)',
|
||||
# augassign
|
||||
'a, b += 3',
|
||||
'(a, b) += 3',
|
||||
'[a, b] += 3',
|
||||
'f() += 1',
|
||||
'lambda x:None+=1',
|
||||
'{} += 1',
|
||||
'{a:b} += 1',
|
||||
'{1} += 1',
|
||||
'{*x} += 1',
|
||||
'(x,) += 1',
|
||||
'(x, y if a else q) += 1',
|
||||
'[] += 1',
|
||||
'[1,2] += 1',
|
||||
'[] += 1',
|
||||
'None += 1',
|
||||
'... += 1',
|
||||
'a > 1 += 1',
|
||||
'"test" += 1',
|
||||
'1 += 1',
|
||||
'1.0 += 1',
|
||||
'(yield) += 1',
|
||||
'(yield from x) += 1',
|
||||
'(x if x else y) += 1',
|
||||
'a() += 1',
|
||||
'a + b += 1',
|
||||
'+a += 1',
|
||||
'a and b += 1',
|
||||
'*a += 1',
|
||||
'a, b += 1',
|
||||
'f"xxx" += 1',
|
||||
# All assignment tests
|
||||
'lambda a: 1 = 1',
|
||||
'[x for x in y] = 1',
|
||||
|
||||
Reference in New Issue
Block a user