@@ -3462,7 +3462,7 @@ def visit_raise_stmt(self, s: RaiseStmt) -> None:
3462
3462
if s .expr :
3463
3463
self .type_check_raise (s .expr , s )
3464
3464
if s .from_expr :
3465
- self .type_check_raise (s .from_expr , s , True )
3465
+ self .type_check_raise (s .from_expr , s , optional = True )
3466
3466
self .binder .unreachable ()
3467
3467
3468
3468
def type_check_raise (self , e : Expression , s : RaiseStmt ,
@@ -3471,24 +3471,88 @@ def type_check_raise(self, e: Expression, s: RaiseStmt,
3471
3471
if isinstance (typ , DeletedType ):
3472
3472
self .msg .deleted_as_rvalue (typ , e )
3473
3473
return
3474
+
3475
+ if self .options .python_version [0 ] == 2 :
3476
+ # Since `raise` has very different rule on python2, we use a different helper.
3477
+ # https://github.com/python/mypy/pull/11289
3478
+ self ._type_check_raise_python2 (e , s , typ )
3479
+ return
3480
+
3481
+ # Python3 case:
3474
3482
exc_type = self .named_type ('builtins.BaseException' )
3475
- expected_type = UnionType ( [exc_type , TypeType (exc_type )])
3483
+ expected_type_items = [exc_type , TypeType (exc_type )]
3476
3484
if optional :
3477
- expected_type .items .append (NoneType ())
3478
- if self .options .python_version [0 ] == 2 :
3479
- # allow `raise type, value, traceback`
3480
- # https://docs.python.org/2/reference/simple_stmts.html#the-raise-statement
3481
- # TODO: Also check tuple item types.
3482
- any_type = AnyType (TypeOfAny .implementation_artifact )
3483
- tuple_type = self .named_type ('builtins.tuple' )
3484
- expected_type .items .append (TupleType ([any_type , any_type ], tuple_type ))
3485
- expected_type .items .append (TupleType ([any_type , any_type , any_type ], tuple_type ))
3486
- self .check_subtype (typ , expected_type , s , message_registry .INVALID_EXCEPTION )
3485
+ # This is used for `x` part in a case like `raise e from x`,
3486
+ # where we allow `raise e from None`.
3487
+ expected_type_items .append (NoneType ())
3488
+
3489
+ self .check_subtype (
3490
+ typ , UnionType .make_union (expected_type_items ), s ,
3491
+ message_registry .INVALID_EXCEPTION ,
3492
+ )
3487
3493
3488
3494
if isinstance (typ , FunctionLike ):
3489
3495
# https://github.com/python/mypy/issues/11089
3490
3496
self .expr_checker .check_call (typ , [], [], e )
3491
3497
3498
+ def _type_check_raise_python2 (self , e : Expression , s : RaiseStmt , typ : ProperType ) -> None :
3499
+ # Python2 has two possible major cases:
3500
+ # 1. `raise expr`, where `expr` is some expression, it can be:
3501
+ # - Exception typ
3502
+ # - Exception instance
3503
+ # - Old style class (not supported)
3504
+ # - Tuple, where 0th item is exception type or instance
3505
+ # 2. `raise exc, msg, traceback`, where:
3506
+ # - `exc` is exception type (not instance!)
3507
+ # - `traceback` is `types.TracebackType | None`
3508
+ # Important note: `raise exc, msg` is not the same as `raise (exc, msg)`
3509
+ # We call `raise exc, msg, traceback` - legacy mode.
3510
+ exc_type = self .named_type ('builtins.BaseException' )
3511
+
3512
+ if (not s .legacy_mode and (isinstance (typ , TupleType ) and typ .items
3513
+ or (isinstance (typ , Instance ) and typ .args
3514
+ and typ .type .fullname == 'builtins.tuple' ))):
3515
+ # `raise (exc, ...)` case:
3516
+ item = typ .items [0 ] if isinstance (typ , TupleType ) else typ .args [0 ]
3517
+ self .check_subtype (
3518
+ item , UnionType ([exc_type , TypeType (exc_type )]), s ,
3519
+ 'When raising a tuple, first element must by derived from BaseException' ,
3520
+ )
3521
+ return
3522
+ elif s .legacy_mode :
3523
+ # `raise Exception, msg` case
3524
+ # `raise Exception, msg, traceback` case
3525
+ # https://docs.python.org/2/reference/simple_stmts.html#the-raise-statement
3526
+ assert isinstance (typ , TupleType ) # Is set in fastparse2.py
3527
+ self .check_subtype (
3528
+ typ .items [0 ], TypeType (exc_type ), s ,
3529
+ 'First argument must be BaseException subtype' ,
3530
+ )
3531
+
3532
+ # Typecheck `traceback` part:
3533
+ if len (typ .items ) == 3 :
3534
+ # Now, we typecheck `traceback` argument if it is present.
3535
+ # We do this after the main check for better error message
3536
+ # and better ordering: first about `BaseException` subtype,
3537
+ # then about `traceback` type.
3538
+ traceback_type = UnionType .make_union ([
3539
+ self .named_type ('types.TracebackType' ),
3540
+ NoneType (),
3541
+ ])
3542
+ self .check_subtype (
3543
+ typ .items [2 ], traceback_type , s ,
3544
+ 'Third argument to raise must have "{}" type' .format (traceback_type ),
3545
+ )
3546
+ else :
3547
+ expected_type_items = [
3548
+ # `raise Exception` and `raise Exception()` cases:
3549
+ exc_type , TypeType (exc_type ),
3550
+ ]
3551
+ self .check_subtype (
3552
+ typ , UnionType .make_union (expected_type_items ),
3553
+ s , message_registry .INVALID_EXCEPTION ,
3554
+ )
3555
+
3492
3556
def visit_try_stmt (self , s : TryStmt ) -> None :
3493
3557
"""Type check a try statement."""
3494
3558
# Our enclosing frame will get the result if the try/except falls through.
0 commit comments