Skip to content

Commit

Permalink
Fix bug with exception variable reuse in deferred node. (#2290)
Browse files Browse the repository at this point in the history
* Fix bug with exception variable reuse in deferred node. The fix is actually by @ecprice.

See #1748 (comment)
  • Loading branch information
gvanrossum committed Oct 25, 2016
1 parent b616268 commit 91faa26
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
7 changes: 7 additions & 0 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1680,7 +1680,14 @@ def visit_try_without_finally(self, s: TryStmt, try_frame: bool) -> None:
# To support local variables, we make this a definition line,
# causing assignment to set the variable's type.
s.vars[i].is_def = True
# We also temporarily set current_node_deferred to False to
# make sure the inference happens.
# TODO: Use a better solution, e.g. a
# separate Var for each except block.
am_deferring = self.current_node_deferred
self.current_node_deferred = False
self.check_assignment(s.vars[i], self.temp_node(t, s.vars[i]))
self.current_node_deferred = am_deferring
self.accept(s.handlers[i])
if s.vars[i]:
# Exception variables are deleted in python 3 but not python 2.
Expand Down
104 changes: 104 additions & 0 deletions test-data/unit/check-statements.test
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,110 @@ e = 1 # E: Assignment to variable 'e' outside except: block
e = E1() # E: Assignment to variable 'e' outside except: block
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode1]
def f(*a: BaseException) -> int:
x
try: pass
except BaseException as err: pass
try: pass
except BaseException as err: f(err)
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode2]
def f(*a: BaseException) -> int:
try: pass
except BaseException as err: pass
x
try: pass
except BaseException as err: f(err)
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode3]
def f(*a: BaseException) -> int:
try: pass
except BaseException as err: pass
try: pass
except BaseException as err: f(err)
x
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode4]
class EA(BaseException):
a = None # type: int
class EB(BaseException):
b = None # type: str
def f(*arg: BaseException) -> int:
x
try: pass
except EA as err:
f(err)
a = err.a
reveal_type(a)
try: pass
except EB as err:
f(err)
b = err.b
reveal_type(b)
x = f()
[builtins fixtures/exception.pyi]
[out]
main: note: In function "f":
main:11: error: Revealed type is 'builtins.int'
main:16: error: Revealed type is 'builtins.str'

[case testExceptionVariableReuseInDeferredNode5]
class EA(BaseException):
a = None # type: int
class EB(BaseException):
b = None # type: str
def f(*arg: BaseException) -> int:
try: pass
except EA as err:
f(err)
a = err.a
reveal_type(a)
x
try: pass
except EB as err:
f(err)
b = err.b
reveal_type(b)
x = f()
[builtins fixtures/exception.pyi]
[out]
main: note: In function "f":
main:10: error: Revealed type is 'builtins.int'
main:16: error: Revealed type is 'builtins.str'

[case testExceptionVariableReuseInDeferredNode6]
class EA(BaseException):
a = None # type: int
class EB(BaseException):
b = None # type: str
def f(*arg: BaseException) -> int:
try: pass
except EA as err:
f(err)
a = err.a
reveal_type(a)
try: pass
except EB as err:
f(err)
b = err.b
reveal_type(b)
x
x = f()
[builtins fixtures/exception.pyi]
[out]
main: note: In function "f":
main:10: error: Revealed type is 'builtins.int'
main:15: error: Revealed type is 'builtins.str'



[case testArbitraryExpressionAsExceptionType]
import typing
a = BaseException
Expand Down

0 comments on commit 91faa26

Please sign in to comment.