Skip to content

Commit b4b0c1c

Browse files
committed
Parse lambda (x): x correctly. Fix #1212. (#1384)
1 parent 532a79c commit b4b0c1c

File tree

3 files changed

+60
-12
lines changed

3 files changed

+60
-12
lines changed

mypy/parse.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -631,9 +631,10 @@ def parse_arg_list(self, allow_signature: bool = True,
631631
elif self.current_str() == '(':
632632
arg, extra_stmt, names = self.parse_tuple_arg(len(args))
633633
args.append(arg)
634-
extra_stmts.append(extra_stmt)
634+
if extra_stmt is not None:
635+
extra_stmts.append(extra_stmt)
636+
has_tuple_arg = True
635637
arg_names.extend(names)
636-
has_tuple_arg = True
637638
else:
638639
arg, require_named = self.parse_normal_arg(
639640
require_named,
@@ -691,6 +692,10 @@ def parse_tuple_arg(self, index: int) -> Tuple[Argument, AssignmentStmt, List[st
691692
function body (the second return value).
692693
693694
Return tuple (argument, decomposing assignment, list of names defined).
695+
696+
Special case: if the argument is just (x) then it's not a tuple;
697+
we indicate this by returning (argument, None, ['x']).
698+
However, if the argument is (x,) then it *is* a (singleton) tuple.
694699
"""
695700
line = self.current().line
696701
# Generate a new argument name that is very unlikely to clash with anything.
@@ -700,13 +705,14 @@ def parse_tuple_arg(self, index: int) -> Tuple[Argument, AssignmentStmt, List[st
700705
paren_arg = self.parse_parentheses()
701706
self.verify_tuple_arg(paren_arg)
702707
if isinstance(paren_arg, NameExpr):
703-
# This isn't a tuple. Revert to a normal argument. We'll still get a no-op
704-
# assignment below but that's benign.
708+
# This isn't a tuple. Revert to a normal argument.
705709
arg_name = paren_arg.name
706-
rvalue = NameExpr(arg_name)
707-
rvalue.set_line(line)
708-
decompose = AssignmentStmt([paren_arg], rvalue)
709-
decompose.set_line(line)
710+
decompose = None
711+
else:
712+
rvalue = NameExpr(arg_name)
713+
rvalue.set_line(line)
714+
decompose = AssignmentStmt([paren_arg], rvalue)
715+
decompose.set_line(line)
710716
kind = nodes.ARG_POS
711717
initializer = None
712718
if self.current_str() == '=':

mypy/test/data/check-python2.test

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,22 @@ main: note: In function "f":
174174
main:1: error: Parse error before ): Ellipses cannot accompany other argument types in function type signature.
175175

176176
[case testLambdaTupleArgInPython2]
177-
lambda (x, y): x + y
177+
f = lambda (x, y): x + y
178+
f((0, 0))
179+
[out]
180+
181+
[case testLambdaSingletonTupleArgInPython2]
182+
f = lambda (x,): x + 1
183+
f((0,))
184+
[out]
185+
186+
[case testLambdaNoTupleArgInPython2]
187+
f = lambda (x): x + 1
188+
f(0)
189+
[out]
190+
191+
[case testDefTupleEdgeCasesPython2]
192+
def f((x,)): return x
193+
def g((x)): return x
194+
f(0) + g(0)
178195
[out]

mypy/test/data/parse-python2.test

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,34 @@ MypyFile:1(
302302
ReturnStmt:1(
303303
NameExpr(z))))))
304304

305+
[case testLambdaSingletonTupleArgListInPython2]
306+
lambda (x,): z
307+
[out]
308+
MypyFile:1(
309+
ExpressionStmt:1(
310+
FuncExpr:1(
311+
Args(
312+
Var(__tuple_arg_1))
313+
Block:1(
314+
AssignmentStmt:1(
315+
TupleExpr:1(
316+
NameExpr(x))
317+
NameExpr(__tuple_arg_1))
318+
ReturnStmt:1(
319+
NameExpr(z))))))
320+
321+
[case testLambdaNoTupleArgListInPython2]
322+
lambda (x): z
323+
[out]
324+
MypyFile:1(
325+
ExpressionStmt:1(
326+
FuncExpr:1(
327+
Args(
328+
Var(x))
329+
Block:1(
330+
ReturnStmt:1(
331+
NameExpr(z))))))
332+
305333
[case testInvalidExprInTupleArgListInPython2_1]
306334
def f(x, ()): pass
307335
[out]
@@ -343,9 +371,6 @@ MypyFile:1(
343371
Var(x)
344372
Var(y))
345373
Block:1(
346-
AssignmentStmt:1(
347-
NameExpr(y)
348-
NameExpr(y))
349374
PassStmt:1())))
350375

351376
[case testDuplicateNameInTupleArgList_python2]

0 commit comments

Comments
 (0)