Skip to content

Commit 9986cef

Browse files
committed
Changed index of for-stmt and generator expressions to be a single node (possibly a tuple) instead of a list. Updated tests accordingly.
1 parent ccc9275 commit 9986cef

12 files changed

+82
-88
lines changed

mypy/checker.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,21 +1537,10 @@ def analyse_iterable_item_type(self, expr: Node) -> Type:
15371537
expr)
15381538
return echk.check_call(method, [], [], expr)[0]
15391539

1540-
def analyse_index_variables(self, index: List[Node],
1541-
item_type: Type, context: Context) -> None:
1540+
def analyse_index_variables(self, index: Node, item_type: Type,
1541+
context: Context) -> None:
15421542
"""Type check or infer for loop or list comprehension index vars."""
1543-
# Create a temporary copy of variables with Node item type.
1544-
# TODO this is ugly
1545-
node_index = [] # type: List[Node]
1546-
for i in index:
1547-
node_index.append(i)
1548-
1549-
if len(node_index) == 1:
1550-
self.check_assignment(node_index[0], self.temp_node(item_type, context))
1551-
else:
1552-
self.check_multi_assignment(node_index,
1553-
self.temp_node(item_type, context),
1554-
context)
1543+
self.check_assignment(index, self.temp_node(item_type, context))
15551544

15561545
def visit_del_stmt(self, s: DelStmt) -> Type:
15571546
if isinstance(s.expr, IndexExpr):

mypy/noderepr.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,9 @@ def __init__(self, while_tok: Any, else_tok: Any) -> None:
144144

145145

146146
class ForStmtRepr:
147-
def __init__(self, for_tok: Any, commas: Any, in_tok: Any,
147+
def __init__(self, for_tok: Any, in_tok: Any,
148148
else_tok: Any) -> None:
149149
self.for_tok = for_tok
150-
self.commas = commas
151150
self.in_tok = in_tok
152151
self.else_tok = else_tok
153152

@@ -331,10 +330,9 @@ def __init__(self, langle: Any, commas: Any, rangle: Any) -> None:
331330

332331

333332
class GeneratorExprRepr:
334-
def __init__(self, for_toks: List[Token], commas: List[Token], in_toks: List[Token],
333+
def __init__(self, for_toks: List[Token], in_toks: List[Token],
335334
if_toklists: List[List[Token]]) -> None:
336335
self.for_toks = for_toks
337-
self.commas = commas
338336
self.in_toks = in_toks
339337
self.if_toklists = if_toklists
340338

mypy/nodes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -568,13 +568,13 @@ def accept(self, visitor: NodeVisitor[T]) -> T:
568568

569569
class ForStmt(Node):
570570
# Index variables
571-
index = Undefined(List['Node'])
571+
index = Undefined(Node)
572572
# Expression to iterate
573573
expr = Undefined(Node)
574574
body = Undefined(Block)
575575
else_body = Undefined(Block)
576576

577-
def __init__(self, index: List['Node'], expr: Node, body: Block,
577+
def __init__(self, index: Node, expr: Node, body: Block,
578578
else_body: Block) -> None:
579579
self.index = index
580580
self.expr = expr
@@ -1192,9 +1192,9 @@ class GeneratorExpr(Node):
11921192
left_expr = Undefined(Node)
11931193
sequences_expr = Undefined(List[Node])
11941194
condlists = Undefined(List[List[Node]])
1195-
indices = Undefined(List[List[Node]])
1195+
indices = Undefined(List[Node])
11961196

1197-
def __init__(self, left_expr: Node, indices: List[List[Node]],
1197+
def __init__(self, left_expr: Node, indices: List[Node],
11981198
sequences: List[Node], condlists: List[List[Node]]) -> None:
11991199
self.left_expr = left_expr
12001200
self.sequences = sequences

mypy/output.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,7 @@ def visit_while_stmt(self, o):
262262
def visit_for_stmt(self, o):
263263
r = o.repr
264264
self.token(r.for_tok)
265-
for i in range(len(o.index)):
266-
self.node(o.index[i])
267-
self.token(r.commas[i])
265+
self.node(o.index)
268266
self.token(r.in_tok)
269267
self.node(o.expr)
270268

@@ -450,10 +448,7 @@ def visit_generator_expr(self, o):
450448
self.node(o.left_expr)
451449
for i in range(len(o.indices)):
452450
self.token(r.for_toks[i])
453-
for j in range(len(o.indices[i])):
454-
self.node(o.indices[i][j])
455-
if j < len(o.indices[i]) - 1:
456-
self.token(r.commas[0])
451+
self.node(o.indices[i])
457452
self.token(r.in_toks[i])
458453
self.node(o.sequences[i])
459454
for cond, if_tok in zip(o.condlists[i], r.if_toklists[i]):

mypy/parse.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ def parse_while_stmt(self) -> WhileStmt:
852852

853853
def parse_for_stmt(self) -> ForStmt:
854854
for_tok = self.expect('for')
855-
index, commas = self.parse_for_index_variables()
855+
index = self.parse_for_index_variables()
856856
in_tok = self.expect('in')
857857
expr = self.parse_expression()
858858

@@ -866,13 +866,12 @@ def parse_for_stmt(self) -> ForStmt:
866866
else_tok = none
867867

868868
node = ForStmt(index, expr, body, else_body)
869-
self.set_repr(node, noderepr.ForStmtRepr(for_tok, commas, in_tok,
870-
else_tok))
869+
self.set_repr(node, noderepr.ForStmtRepr(for_tok, in_tok, else_tok))
871870
return node
872871

873-
def parse_for_index_variables(self) -> Tuple[List[Node], List[Token]]:
872+
def parse_for_index_variables(self) -> Node:
874873
# Parse index variables of a 'for' statement.
875-
index = List[Node]()
874+
index_items = List[Node]()
876875
commas = List[Token]()
877876

878877
is_paren = self.current_str() == '('
@@ -881,7 +880,7 @@ def parse_for_index_variables(self) -> Tuple[List[Node], List[Token]]:
881880

882881
while True:
883882
v = self.parse_expression(precedence['in'], star_expr_allowed=True) # prevent parsing of for-stmt's 'in'
884-
index.append(v)
883+
index_items.append(v)
885884
if self.current_str() != ',':
886885
commas.append(none)
887886
break
@@ -890,7 +889,14 @@ def parse_for_index_variables(self) -> Tuple[List[Node], List[Token]]:
890889
if is_paren:
891890
self.expect(')')
892891

893-
return index, commas
892+
if len(index_items) == 1:
893+
index = index_items[0]
894+
else:
895+
index = TupleExpr(index_items)
896+
index.set_line(index_items[0].get_line())
897+
self.set_repr(index, noderepr.TupleExprRepr(none, commas, none))
898+
899+
return index
894900

895901
def parse_if_stmt(self) -> IfStmt:
896902
is_error = False
@@ -1196,7 +1202,7 @@ def parse_generator_expr(self, left_expr: Node) -> GeneratorExpr:
11961202
if_toks = List[Token]()
11971203
conds = List[Node]()
11981204
for_toks.append(self.expect('for'))
1199-
index, commas = self.parse_for_index_variables()
1205+
index = self.parse_for_index_variables()
12001206
indices.append(index)
12011207
in_toks.append(self.expect('in'))
12021208
sequence = self.parse_expression_list()
@@ -1209,8 +1215,7 @@ def parse_generator_expr(self, left_expr: Node) -> GeneratorExpr:
12091215

12101216
gen = GeneratorExpr(left_expr, indices, sequences, condlists)
12111217
gen.set_line(for_toks[0])
1212-
self.set_repr(gen, noderepr.GeneratorExprRepr(for_toks, commas, in_toks,
1213-
if_toklists))
1218+
self.set_repr(gen, noderepr.GeneratorExprRepr(for_toks, in_toks, if_toklists))
12141219
return gen
12151220

12161221
def parse_expression_list(self) -> Node:

mypy/semanal.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,7 @@ def visit_for_stmt(self, s: ForStmt) -> None:
10551055
s.expr.accept(self)
10561056

10571057
# Bind index variables and check if they define new names.
1058-
for n in s.index:
1059-
self.analyse_lvalue(n)
1058+
self.analyse_lvalue(s.index)
10601059

10611060
self.loop_depth += 1
10621061
self.visit_block(s.body)
@@ -1333,8 +1332,7 @@ def visit_generator_expr(self, expr: GeneratorExpr) -> None:
13331332
expr.condlists):
13341333
sequence.accept(self)
13351334
# Bind index variables.
1336-
for n in index:
1337-
self.analyse_lvalue(n)
1335+
self.analyse_lvalue(index)
13381336
for cond in conditions:
13391337
cond.accept(self)
13401338

@@ -1595,8 +1593,7 @@ def visit_var_def(self, d: VarDef) -> None:
15951593
self.sem.cur_mod_id)
15961594

15971595
def visit_for_stmt(self, s: ForStmt) -> None:
1598-
for n in s.index:
1599-
self.sem.analyse_lvalue(n, add_global=True)
1596+
self.sem.analyse_lvalue(s.index, add_global=True)
16001597

16011598
def visit_with_stmt(self, s: WithStmt) -> None:
16021599
for n in s.name:

mypy/test/data/parse.test

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -843,11 +843,12 @@ MypyFile:1(
843843
Block:1(
844844
PassStmt:2()))
845845
ForStmt:3(
846-
NameExpr(x)
847-
ParenExpr:3(
848-
TupleExpr:3(
849-
NameExpr(y)
850-
NameExpr(w)))
846+
TupleExpr:3(
847+
NameExpr(x)
848+
ParenExpr:3(
849+
TupleExpr:3(
850+
NameExpr(y)
851+
NameExpr(w))))
851852
NameExpr(z)
852853
Block:3(
853854
ExpressionStmt:4(
@@ -1196,11 +1197,12 @@ MypyFile:1(
11961197
ExpressionStmt:1(
11971198
GeneratorExpr:1(
11981199
NameExpr(x)
1199-
NameExpr(y)
1200-
ParenExpr:1(
1201-
TupleExpr:1(
1202-
NameExpr(p)
1203-
NameExpr(q)))
1200+
TupleExpr:1(
1201+
NameExpr(y)
1202+
ParenExpr:1(
1203+
TupleExpr:1(
1204+
NameExpr(p)
1205+
NameExpr(q))))
12041206
NameExpr(z))))
12051207

12061208
[case testListComprehension]
@@ -1227,8 +1229,9 @@ MypyFile:1(
12271229
TupleExpr:1(
12281230
NameExpr(x)
12291231
NameExpr(y)))
1230-
NameExpr(y)
1231-
NameExpr(z)
1232+
TupleExpr:1(
1233+
NameExpr(y)
1234+
NameExpr(z))
12321235
TupleExpr:1(
12331236
IntExpr(1)
12341237
IntExpr(2))))))
@@ -1458,8 +1461,9 @@ for (i, j) in x:
14581461
[out]
14591462
MypyFile:1(
14601463
ForStmt:1(
1461-
NameExpr(i)
1462-
NameExpr(j)
1464+
TupleExpr:1(
1465+
NameExpr(i)
1466+
NameExpr(j))
14631467
NameExpr(x)
14641468
Block:1(
14651469
PassStmt:2())))
@@ -2787,16 +2791,18 @@ MypyFile:1(
27872791
Block:1(
27882792
PassStmt:2()))
27892793
ForStmt:4(
2790-
NameExpr(a)
2791-
StarExpr:4(
2792-
NameExpr(b))
2794+
TupleExpr:4(
2795+
NameExpr(a)
2796+
StarExpr:4(
2797+
NameExpr(b)))
27932798
NameExpr(c)
27942799
Block:4(
27952800
PassStmt:5()))
27962801
ForStmt:7(
2797-
StarExpr:7(
2798-
NameExpr(a))
2799-
NameExpr(b)
2802+
TupleExpr:7(
2803+
StarExpr:7(
2804+
NameExpr(a))
2805+
NameExpr(b))
28002806
NameExpr(c)
28012807
Block:7(
28022808
PassStmt:8())))
@@ -2810,22 +2816,25 @@ MypyFile:1(
28102816
ExpressionStmt:1(
28112817
GeneratorExpr:1(
28122818
NameExpr(x)
2813-
NameExpr(y)
2814-
StarExpr:1(
2815-
NameExpr(p))
2819+
TupleExpr:1(
2820+
NameExpr(y)
2821+
StarExpr:1(
2822+
NameExpr(p)))
28162823
NameExpr(z)))
28172824
ExpressionStmt:2(
28182825
GeneratorExpr:2(
28192826
NameExpr(x)
2820-
StarExpr:2(
2821-
NameExpr(p))
2822-
NameExpr(y)
2827+
TupleExpr:2(
2828+
StarExpr:2(
2829+
NameExpr(p))
2830+
NameExpr(y))
28232831
NameExpr(z)))
28242832
ExpressionStmt:3(
28252833
GeneratorExpr:3(
28262834
NameExpr(x)
2827-
NameExpr(y)
2828-
StarExpr:3(
2829-
NameExpr(p))
2830-
NameExpr(q)
2835+
TupleExpr:3(
2836+
NameExpr(y)
2837+
StarExpr:3(
2838+
NameExpr(p))
2839+
NameExpr(q))
28312840
NameExpr(z))))

mypy/test/data/semanal-errors.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ main, line 7: Two starred expressions in assignment
419419
(a for a, (*b, *c) in [])
420420
[out]
421421
main, line 1: Two starred expressions in assignment
422+
main, line 1: Name 'a' is not defined
422423
main, line 3: Two starred expressions in assignment
423424

424425
[case testStarExpressionRhs]

mypy/test/data/semanal-expressions.test

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,12 @@ MypyFile:1(
261261
ExpressionStmt:2(
262262
GeneratorExpr:2(
263263
NameExpr(x [l])
264-
NameExpr(x* [l])
265-
ParenExpr:2(
266-
TupleExpr:2(
267-
NameExpr(y* [l])
268-
NameExpr(z* [l])))
264+
TupleExpr:2(
265+
NameExpr(x* [l])
266+
ParenExpr:2(
267+
TupleExpr:2(
268+
NameExpr(y* [l])
269+
NameExpr(z* [l]))))
269270
NameExpr(a [__main__.a]))))
270271

271272
[case testLambda]

mypy/test/data/semanal-statements.test

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ for x, y in []:
113113
[out]
114114
MypyFile:1(
115115
ForStmt:1(
116-
NameExpr(x* [__main__.x])
117-
NameExpr(y* [__main__.y])
116+
TupleExpr:1(
117+
NameExpr(x* [__main__.x])
118+
NameExpr(y* [__main__.y]))
118119
ListExpr:1()
119120
Block:1(
120121
ExpressionStmt:2(

0 commit comments

Comments
 (0)