Skip to content

Commit d4151a8

Browse files
authored
Fix interaction of list comprehension shadowing and binders (#7476)
Binders are keyed by "literal_hash" which uses the name of the variable as part of the key. Use the Var node instead so that shadowing works. Fixes mypyc/mypyc#695 but also was a bug separate from mypyc.
1 parent 9958295 commit d4151a8

File tree

3 files changed

+24
-1
lines changed

3 files changed

+24
-1
lines changed

mypy/literals.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ def visit_star_expr(self, e: StarExpr) -> Key:
113113
return ('Star', literal_hash(e.expr))
114114

115115
def visit_name_expr(self, e: NameExpr) -> Key:
116-
return ('Var', e.name)
116+
# N.B: We use the node itself as the key, and not the name,
117+
# because using the name causes issues when there is shadowing
118+
# (for example, in list comprehensions).
119+
return ('Var', e.node)
117120

118121
def visit_member_expr(self, e: MemberExpr) -> Key:
119122
return ('Member', literal_hash(e.expr), e.name)

mypyc/test-data/run.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4633,3 +4633,15 @@ with assertRaises(TypeError, "errored formatting real type!"):
46334633

46344634
with assertRaises(TypeError, "tuple[int, native.A] object expected; got tuple[int, int]"):
46354635
g((20, 30))
4636+
4637+
[case testComprehensionShadowBinder]
4638+
def foo(x: object) -> object:
4639+
if isinstance(x, list):
4640+
return tuple(x for x in x), x
4641+
return None
4642+
4643+
[file driver.py]
4644+
from native import foo
4645+
4646+
assert foo(None) == None
4647+
assert foo([1, 2, 3]) == ((1, 2, 3), [1, 2, 3])

test-data/unit/check-lists.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,11 @@ reveal_type(b) # N: Revealed type is 'builtins.list[builtins.int*]'
7777
c = [*a, 0]
7878
reveal_type(c) # N: Revealed type is 'builtins.list[builtins.int*]'
7979
[builtins fixtures/list.pyi]
80+
81+
[case testComprehensionShadowBinder]
82+
# flags: --strict-optional
83+
def foo(x: object) -> None:
84+
if isinstance(x, str):
85+
[reveal_type(x) for x in [1, 2, 3]] # N: Revealed type is 'builtins.int*'
86+
87+
[builtins fixtures/isinstancelist.pyi]

0 commit comments

Comments
 (0)