@@ -2367,10 +2367,11 @@ def erase_override(t: Type) -> Type:
23672367 else :
23682368 continue
23692369 if not is_subtype (original_arg_type , erase_override (override_arg_type )):
2370+ context : Context = node
23702371 if isinstance (node , FuncDef ) and not node .is_property :
2371- context : Context = node .arguments [i + len (override .bound_args )]
2372- else :
2373- context = node
2372+ arg_node = node .arguments [i + len (override .bound_args )]
2373+ if arg_node . line != - 1 :
2374+ context = arg_node
23742375 self .msg .argument_incompatible_with_supertype (
23752376 i + 1 ,
23762377 name ,
@@ -4724,11 +4725,11 @@ def visit_if_stmt(self, s: IfStmt) -> None:
47244725
47254726 # XXX Issue a warning if condition is always False?
47264727 with self .binder .frame_context (can_skip = True , fall_through = 2 ):
4727- self .push_type_map (if_map )
4728+ self .push_type_map (if_map , from_assignment = False )
47284729 self .accept (b )
47294730
47304731 # XXX Issue a warning if condition is always True?
4731- self .push_type_map (else_map )
4732+ self .push_type_map (else_map , from_assignment = False )
47324733
47334734 with self .binder .frame_context (can_skip = False , fall_through = 2 ):
47344735 if s .else_body :
@@ -5309,18 +5310,21 @@ def visit_match_stmt(self, s: MatchStmt) -> None:
53095310 if b .is_unreachable or isinstance (
53105311 get_proper_type (pattern_type .type ), UninhabitedType
53115312 ):
5312- self .push_type_map (None )
5313+ self .push_type_map (None , from_assignment = False )
53135314 else_map : TypeMap = {}
53145315 else :
53155316 pattern_map , else_map = conditional_types_to_typemaps (
53165317 named_subject , pattern_type .type , pattern_type .rest_type
53175318 )
53185319 self .remove_capture_conflicts (pattern_type .captures , inferred_types )
5319- self .push_type_map (pattern_map )
5320+ self .push_type_map (pattern_map , from_assignment = False )
53205321 if pattern_map :
53215322 for expr , typ in pattern_map .items ():
5322- self .push_type_map (self ._get_recursive_sub_patterns_map (expr , typ ))
5323- self .push_type_map (pattern_type .captures )
5323+ self .push_type_map (
5324+ self ._get_recursive_sub_patterns_map (expr , typ ),
5325+ from_assignment = False ,
5326+ )
5327+ self .push_type_map (pattern_type .captures , from_assignment = False )
53245328 if g is not None :
53255329 with self .binder .frame_context (can_skip = False , fall_through = 3 ):
53265330 gt = get_proper_type (self .expr_checker .accept (g ))
@@ -5346,11 +5350,11 @@ def visit_match_stmt(self, s: MatchStmt) -> None:
53465350 continue
53475351 type_map [named_subject ] = type_map [expr ]
53485352
5349- self .push_type_map (guard_map )
5353+ self .push_type_map (guard_map , from_assignment = False )
53505354 self .accept (b )
53515355 else :
53525356 self .accept (b )
5353- self .push_type_map (else_map )
5357+ self .push_type_map (else_map , from_assignment = False )
53545358
53555359 # This is needed due to a quirk in frame_context. Without it types will stay narrowed
53565360 # after the match.
@@ -6273,10 +6277,6 @@ def has_no_custom_eq_checks(t: Type) -> bool:
62736277 coerce_only_in_literal_context ,
62746278 )
62756279
6276- # Strictly speaking, we should also skip this check if the objects in the expr
6277- # chain have custom __eq__ or __ne__ methods. But we (maybe optimistically)
6278- # assume nobody would actually create a custom objects that considers itself
6279- # equal to None.
62806280 if if_map == {} and else_map == {}:
62816281 if_map , else_map = self .refine_away_none_in_comparison (
62826282 operands , operand_types , expr_indices , narrowable_operand_index_to_hash .keys ()
@@ -6601,25 +6601,36 @@ def refine_away_none_in_comparison(
66016601 For more details about what the different arguments mean, see the
66026602 docstring of 'refine_identity_comparison_expression' up above.
66036603 """
6604+
66046605 non_optional_types = []
66056606 for i in chain_indices :
66066607 typ = operand_types [i ]
66076608 if not is_overlapping_none (typ ):
66086609 non_optional_types .append (typ )
66096610
6610- # Make sure we have a mixture of optional and non-optional types.
6611- if len (non_optional_types ) == 0 or len (non_optional_types ) == len (chain_indices ):
6612- return {}, {}
6611+ if_map , else_map = {}, {}
66136612
6614- if_map = {}
6615- for i in narrowable_operand_indices :
6616- expr_type = operand_types [i ]
6617- if not is_overlapping_none (expr_type ):
6618- continue
6619- if any (is_overlapping_erased_types (expr_type , t ) for t in non_optional_types ):
6620- if_map [operands [i ]] = remove_optional (expr_type )
6613+ if not non_optional_types or (len (non_optional_types ) != len (chain_indices )):
6614+
6615+ # Narrow e.g. `Optional[A] == "x"` or `Optional[A] is "x"` to `A` (which may be
6616+ # convenient but is strictly not type-safe):
6617+ for i in narrowable_operand_indices :
6618+ expr_type = operand_types [i ]
6619+ if not is_overlapping_none (expr_type ):
6620+ continue
6621+ if any (is_overlapping_erased_types (expr_type , t ) for t in non_optional_types ):
6622+ if_map [operands [i ]] = remove_optional (expr_type )
6623+
6624+ # Narrow e.g. `Optional[A] != None` to `A` (which is stricter than the above step and
6625+ # so type-safe but less convenient, because e.g. `Optional[A] == None` still results
6626+ # in `Optional[A]`):
6627+ if any (isinstance (get_proper_type (ot ), NoneType ) for ot in operand_types ):
6628+ for i in narrowable_operand_indices :
6629+ expr_type = operand_types [i ]
6630+ if is_overlapping_none (expr_type ):
6631+ else_map [operands [i ]] = remove_optional (expr_type )
66216632
6622- return if_map , {}
6633+ return if_map , else_map
66236634
66246635 def is_len_of_tuple (self , expr : Expression ) -> bool :
66256636 """Is this expression a `len(x)` call where x is a tuple or union of tuples?"""
@@ -7364,12 +7375,12 @@ def iterable_item_type(
73647375 def function_type (self , func : FuncBase ) -> FunctionLike :
73657376 return function_type (func , self .named_type ("builtins.function" ))
73667377
7367- def push_type_map (self , type_map : TypeMap ) -> None :
7378+ def push_type_map (self , type_map : TypeMap , * , from_assignment : bool = True ) -> None :
73687379 if type_map is None :
73697380 self .binder .unreachable ()
73707381 else :
73717382 for expr , type in type_map .items ():
7372- self .binder .put (expr , type )
7383+ self .binder .put (expr , type , from_assignment = from_assignment )
73737384
73747385 def infer_issubclass_maps (self , node : CallExpr , expr : Expression ) -> tuple [TypeMap , TypeMap ]:
73757386 """Infer type restrictions for an expression in issubclass call."""
@@ -7742,9 +7753,7 @@ def conditional_types(
77427753 ) and is_proper_subtype (current_type , proposed_type , ignore_promotions = True ):
77437754 # Expression is always of one of the types in proposed_type_ranges
77447755 return default , UninhabitedType ()
7745- elif not is_overlapping_types (
7746- current_type , proposed_type , prohibit_none_typevar_overlap = True , ignore_promotions = True
7747- ):
7756+ elif not is_overlapping_types (current_type , proposed_type , ignore_promotions = True ):
77487757 # Expression is never of any type in proposed_type_ranges
77497758 return UninhabitedType (), default
77507759 else :
0 commit comments