@@ -3312,14 +3312,30 @@ def visit_with_stmt(self, s: WithStmt) -> None:
3312
3312
exit_ret_type = self .check_async_with_item (expr , target , s .unanalyzed_type is None )
3313
3313
else :
3314
3314
exit_ret_type = self .check_with_item (expr , target , s .unanalyzed_type is None )
3315
+
3316
+ # Based on the return type, determine if this context manager 'swallows'
3317
+ # exceptions or not. We determine this using a heuristic based on the
3318
+ # return type of the __exit__ method -- see the discussion in
3319
+ # https://github.com/python/mypy/issues/7214 and the section about context managers
3320
+ # in https://github.com/python/typeshed/blob/master/CONTRIBUTING.md#conventions
3321
+ # for more details.
3322
+
3323
+ exit_ret_type = get_proper_type (exit_ret_type )
3315
3324
if is_literal_type (exit_ret_type , "builtins.bool" , False ):
3316
3325
continue
3317
- if is_literal_type (exit_ret_type , "builtins.bool" , True ):
3318
- exceptions_maybe_suppressed = True
3319
- elif (isinstance (exit_ret_type , Instance )
3320
- and exit_ret_type .type .fullname () == 'builtins.bool' ):
3326
+
3327
+ if (is_literal_type (exit_ret_type , "builtins.bool" , True )
3328
+ or (isinstance (exit_ret_type , Instance )
3329
+ and exit_ret_type .type .fullname () == 'builtins.bool'
3330
+ and state .strict_optional )):
3331
+ # Note: if strict-optional is disabled, this bool instance
3332
+ # could actually be an Optional[bool].
3321
3333
exceptions_maybe_suppressed = True
3334
+
3322
3335
if exceptions_maybe_suppressed :
3336
+ # Treat this 'with' block in the same way we'd treat a 'try: BODY; except: pass'
3337
+ # block. This means control flow can continue after the 'with' even if the 'with'
3338
+ # block immediately returns.
3323
3339
with self .binder .frame_context (can_skip = True , try_frame = True ):
3324
3340
self .accept (s .body )
3325
3341
else :
0 commit comments