Skip to content

Commit ddacf23

Browse files
authored
Make new parser consistent with the old one (#21377)
This fixes some issues discovered in #21331 Two things here: * Old parser keeps `metaclass` in keywords, so it is better to keep it in the new one as well * Old parser has right-associativity for BoolOps, so should have the new one If we want to have the new behavior for some reason, it is possible to instead make some fixes "downstream" in semantic analysis/type-checking/etc. _But_, it is non-trivial, and IMO it is not a good time to change the behavior while we still have both parsers. Note I don't add test for the metaclass change because a whole bunch of mypyc tests fails with new parser already without this PR.
1 parent 05742e2 commit ddacf23

4 files changed

Lines changed: 31 additions & 17 deletions

File tree

mypy/nativeparse.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -715,14 +715,14 @@ def read_class_def(state: State, data: ReadBuffer) -> ClassDef:
715715
keywords.append((key, value))
716716

717717
metaclass = dict(keywords).get("metaclass") if keywords else None
718-
filtered_keywords = [(k, v) for k, v in keywords if k != "metaclass"] if keywords else None
719718

720719
class_def = ClassDef(
721720
name,
722721
body,
723722
base_type_exprs=base_type_exprs if base_type_exprs else None,
724723
metaclass=metaclass,
725-
keywords=filtered_keywords,
724+
# Note we keep metaclass in keywords as well, to match the old parser.
725+
keywords=keywords if keywords else None,
726726
type_args=type_params,
727727
)
728728
class_def.decorators = decorators
@@ -1329,15 +1329,16 @@ def read_expression(state: State, data: ReadBuffer) -> Expression:
13291329
op = bool_ops[read_int(data)]
13301330
values = read_expression_list(state, data)
13311331
# Convert list of values to nested OpExpr nodes
1332-
# E.g., [a, b, c] with "and" becomes OpExpr("and", OpExpr("and", a, b), c)
1332+
# E.g., [a, b, c] with "and" becomes OpExpr("and", a, OpExpr("and", b, c))
1333+
# This matches the old parser behavior, on which we may implicitly rely.
13331334
assert len(values) >= 2
1334-
result = values[0]
1335-
for val in values[1:]:
1336-
result = OpExpr(op, result, val)
1337-
result.line = values[0].line
1338-
result.column = values[0].column
1339-
result.end_line = val.end_line
1340-
result.end_column = val.end_column
1335+
result = last = values[-1]
1336+
for val in values[-2::-1]:
1337+
result = OpExpr(op, val, result)
1338+
result.line = val.line
1339+
result.column = val.column
1340+
result.end_line = last.end_line
1341+
result.end_column = last.end_column
13411342
read_loc(data, result)
13421343
expect_end_tag(data)
13431344
return result

mypy/plugins/dataclasses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ def collect_attributes(self) -> list[DataclassAttribute] | None:
662662

663663
# Allow bare x: Final[int] in class body, since it will be set in the generated
664664
# __init__() method (unless it is an InitVar), to match regular class semantics.
665-
if node.is_final and not node.is_classvar and node.final_unset_in_class:
665+
if node.is_final and node.final_unset_in_class:
666666
if is_init_var:
667667
self._api.fail("InitVar cannot be final", stmt.rvalue)
668668
else:

test-data/unit/check-flags.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,3 +2705,15 @@ reveal_type(fx) # N: Revealed type is "def [Ts] (int, *args: *tuple[*Ts, int])
27052705
x = 1
27062706
[out]
27072707
main:1: error: --allow-redefinition-old and --allow-redefinition should not be used together
2708+
2709+
[case testRedundantExpressionMultiline]
2710+
# mypy: enable-error-code="redundant-expr"
2711+
x: int
2712+
y: int
2713+
z: int
2714+
if (
2715+
x is None # E: Left operand of "or" is always false
2716+
or y is None # E: Left operand of "or" is always false
2717+
or z is None
2718+
):
2719+
pass

test-data/unit/native-parser.test

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,11 @@ MypyFile:1(
261261
ExpressionStmt:2(
262262
OpExpr:2(
263263
and
264+
NameExpr(a)
264265
OpExpr:2(
265266
and
266-
NameExpr(a)
267-
NameExpr(b))
268-
NameExpr(c))))
267+
NameExpr(b)
268+
NameExpr(c)))))
269269

270270
[case testBoolOpOr]
271271
x or y
@@ -280,11 +280,11 @@ MypyFile:1(
280280
ExpressionStmt:2(
281281
OpExpr:2(
282282
or
283+
IntExpr(1)
283284
OpExpr:2(
284285
or
285-
IntExpr(1)
286-
IntExpr(2))
287-
IntExpr(3))))
286+
IntExpr(2)
287+
IntExpr(3)))))
288288

289289
[case testComparisonSimple]
290290
a < b
@@ -1980,6 +1980,7 @@ class Foo(metaclass=Bar): pass
19801980
MypyFile:1(
19811981
ClassDef:1(
19821982
Foo
1983+
Keywords(metaclass=NameExpr(Bar))
19831984
Metaclass(NameExpr(Bar))
19841985
PassStmt:1()))
19851986

0 commit comments

Comments
 (0)