2424from mypy .erasetype import erase_type , erase_typevars , remove_instance_last_known_values
2525from mypy .errorcodes import TYPE_VAR , UNUSED_AWAITABLE , UNUSED_COROUTINE , ErrorCode
2626from mypy .errors import Errors , ErrorWatcher , report_internal_error
27- from mypy .expandtype import expand_self_type , expand_type
27+ from mypy .expandtype import expand_type
2828from mypy .literals import Key , extract_var_from_literal_hash , literal , literal_hash
2929from mypy .maptype import map_instance_to_supertype
3030from mypy .meet import is_overlapping_erased_types , is_overlapping_types , meet_types
161161 is_literal_type_like ,
162162 is_singleton_type ,
163163 make_simplified_union ,
164- map_type_from_supertype ,
165164 true_only ,
166165 try_expanding_sum_type_to_union ,
167166 try_getting_int_literals_from_type ,
@@ -2141,8 +2140,8 @@ def check_setter_type_override(self, defn: OverloadedFuncDef, base: TypeInfo) ->
21412140 is a custom settable property (i.e. where setter type is different from getter type).
21422141 Note that this check is contravariant.
21432142 """
2144- typ , _ = self .node_type_from_base (defn , defn .info , setter_type = True )
2145- original_type , _ = self .node_type_from_base (defn , base , setter_type = True )
2143+ typ , _ = self .node_type_from_base (defn . name , defn .info , defn , setter_type = True )
2144+ original_type , _ = self .node_type_from_base (defn . name , base , defn , setter_type = True )
21462145 # The caller should handle deferrals.
21472146 assert typ is not None and original_type is not None
21482147
@@ -2173,14 +2172,14 @@ def check_method_override_for_base_with_name(
21732172 override_class_or_static = defn .is_class or defn .is_static
21742173 else :
21752174 override_class_or_static = defn .func .is_class or defn .func .is_static
2176- typ , _ = self .node_type_from_base (defn , defn .info )
2175+ typ , _ = self .node_type_from_base (defn . name , defn .info , defn )
21772176 assert typ is not None
21782177
21792178 original_node = base_attr .node
21802179 # `original_type` can be partial if (e.g.) it is originally an
21812180 # instance variable from an `__init__` block that becomes deferred.
21822181 supertype_ready = True
2183- original_type , _ = self .node_type_from_base (defn , base , name_override = name )
2182+ original_type , _ = self .node_type_from_base (name , base , defn )
21842183 if original_type is None :
21852184 supertype_ready = False
21862185 if self .pass_num < self .last_pass :
@@ -2321,51 +2320,6 @@ def check_method_override_for_base_with_name(
23212320 )
23222321 return False
23232322
2324- def bind_and_map_method (
2325- self , sym : SymbolTableNode , typ : FunctionLike , sub_info : TypeInfo , super_info : TypeInfo
2326- ) -> FunctionLike :
2327- """Bind self-type and map type variables for a method.
2328-
2329- Arguments:
2330- sym: a symbol that points to method definition
2331- typ: method type on the definition
2332- sub_info: class where the method is used
2333- super_info: class where the method was defined
2334- """
2335- if isinstance (sym .node , (FuncDef , OverloadedFuncDef , Decorator )) and not is_static (
2336- sym .node
2337- ):
2338- if isinstance (sym .node , Decorator ):
2339- is_class_method = sym .node .func .is_class
2340- else :
2341- is_class_method = sym .node .is_class
2342-
2343- mapped_typ = cast (FunctionLike , map_type_from_supertype (typ , sub_info , super_info ))
2344- active_self_type = fill_typevars (sub_info )
2345- if isinstance (mapped_typ , Overloaded ):
2346- # If we have an overload, filter to overloads that match the self type.
2347- # This avoids false positives for concrete subclasses of generic classes,
2348- # see testSelfTypeOverrideCompatibility for an example.
2349- filtered_items = []
2350- for item in mapped_typ .items :
2351- if not item .arg_types :
2352- filtered_items .append (item )
2353- item_arg = item .arg_types [0 ]
2354- if isinstance (item_arg , TypeVarType ):
2355- item_arg = item_arg .upper_bound
2356- if is_subtype (active_self_type , item_arg ):
2357- filtered_items .append (item )
2358- # If we don't have any filtered_items, maybe it's always a valid override
2359- # of the superclass? However if you get to that point you're in murky type
2360- # territory anyway, so we just preserve the type and have the behaviour match
2361- # that of older versions of mypy.
2362- if filtered_items :
2363- mapped_typ = Overloaded (filtered_items )
2364-
2365- return bind_self (mapped_typ , active_self_type , is_class_method )
2366- else :
2367- return cast (FunctionLike , map_type_from_supertype (typ , sub_info , super_info ))
2368-
23692323 def get_op_other_domain (self , tp : FunctionLike ) -> Type | None :
23702324 if isinstance (tp , CallableType ):
23712325 if tp .arg_kinds and tp .arg_kinds [0 ] == ARG_POS :
@@ -2882,6 +2836,7 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
28822836 self .check_compatibility (name , base , base2 , typ )
28832837
28842838 def determine_type_of_member (self , sym : SymbolTableNode ) -> Type | None :
2839+ # TODO: this duplicates both checkmember.py and analyze_ref_expr(), delete.
28852840 if sym .type is not None :
28862841 return sym .type
28872842 if isinstance (sym .node , SYMBOL_FUNCBASE_TYPES ):
@@ -2901,7 +2856,6 @@ def determine_type_of_member(self, sym: SymbolTableNode) -> Type | None:
29012856 # Suppress any errors, they will be given when analyzing the corresponding node.
29022857 # Here we may have incorrect options and location context.
29032858 return self .expr_checker .alias_type_in_runtime_context (sym .node , ctx = sym .node )
2904- # TODO: handle more node kinds here.
29052859 return None
29062860
29072861 def check_compatibility (
@@ -2932,50 +2886,47 @@ class C(B, A[int]): ... # this is unsafe because...
29322886 return
29332887 first = base1 .names [name ]
29342888 second = base2 .names [name ]
2935- first_type = get_proper_type (self .determine_type_of_member (first ))
2936- second_type = get_proper_type (self .determine_type_of_member (second ))
2889+ # Specify current_class explicitly as this function is called after leaving the class.
2890+ first_type , _ = self .node_type_from_base (name , base1 , ctx , current_class = ctx )
2891+ second_type , _ = self .node_type_from_base (name , base2 , ctx , current_class = ctx )
29372892
29382893 # TODO: use more principled logic to decide is_subtype() vs is_equivalent().
29392894 # We should rely on mutability of superclass node, not on types being Callable.
29402895 # (in particular handle settable properties with setter type different from getter).
29412896
2942- # start with the special case that Instance can be a subtype of FunctionLike
2943- call = None
2944- if isinstance (first_type , Instance ):
2945- call = find_member ("__call__" , first_type , first_type , is_operator = True )
2946- if call and isinstance (second_type , FunctionLike ):
2947- second_sig = self .bind_and_map_method (second , second_type , ctx , base2 )
2948- ok = is_subtype (call , second_sig , ignore_pos_arg_names = True )
2949- elif isinstance (first_type , FunctionLike ) and isinstance (second_type , FunctionLike ):
2950- if first_type .is_type_obj () and second_type .is_type_obj ():
2897+ p_first_type = get_proper_type (first_type )
2898+ p_second_type = get_proper_type (second_type )
2899+ if isinstance (p_first_type , FunctionLike ) and isinstance (p_second_type , FunctionLike ):
2900+ if p_first_type .is_type_obj () and p_second_type .is_type_obj ():
29512901 # For class objects only check the subtype relationship of the classes,
29522902 # since we allow incompatible overrides of '__init__'/'__new__'
29532903 ok = is_subtype (
2954- left = fill_typevars_with_any (first_type .type_object ()),
2955- right = fill_typevars_with_any (second_type .type_object ()),
2904+ left = fill_typevars_with_any (p_first_type .type_object ()),
2905+ right = fill_typevars_with_any (p_second_type .type_object ()),
29562906 )
29572907 else :
2958- # First bind/map method types when necessary.
2959- first_sig = self .bind_and_map_method (first , first_type , ctx , base1 )
2960- second_sig = self .bind_and_map_method (second , second_type , ctx , base2 )
2961- ok = is_subtype (first_sig , second_sig , ignore_pos_arg_names = True )
2908+ assert first_type and second_type
2909+ ok = is_subtype (first_type , second_type , ignore_pos_arg_names = True )
29622910 elif first_type and second_type :
2963- if isinstance (first .node , Var ):
2964- first_type = get_proper_type (map_type_from_supertype (first_type , ctx , base1 ))
2965- first_type = expand_self_type (first .node , first_type , fill_typevars (ctx ))
2966- if isinstance (second .node , Var ):
2967- second_type = get_proper_type (map_type_from_supertype (second_type , ctx , base2 ))
2968- second_type = expand_self_type (second .node , second_type , fill_typevars (ctx ))
2969- ok = is_equivalent (first_type , second_type )
2970- if not ok :
2971- second_node = base2 [name ].node
2911+ if second .node is not None and not self .is_writable_attribute (second .node ):
2912+ ok = is_subtype (first_type , second_type )
2913+ else :
2914+ ok = is_equivalent (first_type , second_type )
2915+ if ok :
29722916 if (
2973- isinstance (second_type , FunctionLike )
2974- and second_node is not None
2975- and is_property (second_node )
2917+ first .node
2918+ and second .node
2919+ and self .is_writable_attribute (second .node )
2920+ and is_property (first .node )
2921+ and isinstance (first .node , Decorator )
2922+ and not isinstance (p_second_type , AnyType )
29762923 ):
2977- second_type = get_property_type (second_type )
2978- ok = is_subtype (first_type , second_type )
2924+ self .msg .fail (
2925+ f'Cannot override writeable attribute "{ name } " in base "{ base2 .name } "'
2926+ f' with read-only property in base "{ base1 .name } "' ,
2927+ ctx ,
2928+ code = codes .OVERRIDE ,
2929+ )
29792930 else :
29802931 if first_type is None :
29812932 self .msg .cannot_determine_type_in_base (name , base1 .name , ctx )
@@ -3364,8 +3315,9 @@ def get_variable_type_context(self, inferred: Var, rvalue: Expression) -> Type |
33643315 # a class object for lambdas overriding methods, etc.
33653316 base_node = base .names [inferred .name ].node
33663317 base_type , _ = self .node_type_from_base (
3367- inferred ,
3318+ inferred . name ,
33683319 base ,
3320+ inferred ,
33693321 is_class = is_method (base_node )
33703322 or isinstance (base_node , Var )
33713323 and not is_instance_var (base_node ),
@@ -3474,7 +3426,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
34743426 rvalue_type = self .expr_checker .accept (rvalue , lvalue_node .type )
34753427 actual_lvalue_type = lvalue_node .type
34763428 lvalue_node .type = rvalue_type
3477- lvalue_type , _ = self .node_type_from_base (lvalue_node , lvalue_node .info )
3429+ lvalue_type , _ = self .node_type_from_base (lvalue_node . name , lvalue_node .info , lvalue )
34783430 if lvalue_node .is_inferred and not lvalue_node .explicit_self_type :
34793431 lvalue_node .type = actual_lvalue_type
34803432
@@ -3493,7 +3445,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
34933445 if is_private (lvalue_node .name ):
34943446 continue
34953447
3496- base_type , base_node = self .node_type_from_base (lvalue_node , base )
3448+ base_type , base_node = self .node_type_from_base (lvalue_node . name , base , lvalue )
34973449 custom_setter = is_custom_settable_property (base_node )
34983450 if isinstance (base_type , PartialType ):
34993451 base_type = None
@@ -3513,7 +3465,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
35133465 return
35143466 if lvalue_type and custom_setter :
35153467 base_type , _ = self .node_type_from_base (
3516- lvalue_node , base , setter_type = True
3468+ lvalue_node . name , base , lvalue , setter_type = True
35173469 )
35183470 # Setter type for a custom property must be ready if
35193471 # the getter type is ready.
@@ -3565,12 +3517,13 @@ def check_compatibility_super(
35653517
35663518 def node_type_from_base (
35673519 self ,
3568- node : SymbolNode ,
3520+ name : str ,
35693521 base : TypeInfo ,
3522+ context : Context ,
35703523 * ,
35713524 setter_type : bool = False ,
35723525 is_class : bool = False ,
3573- name_override : str | None = None ,
3526+ current_class : TypeInfo | None = None ,
35743527 ) -> tuple [Type | None , SymbolNode | None ]:
35753528 """Find a type for a name in base class.
35763529
@@ -3580,20 +3533,22 @@ def node_type_from_base(
35803533 If setter_type is True, return setter types for settable properties (otherwise the
35813534 getter type is returned).
35823535 """
3583- name = name_override or node .name
35843536 base_node = base .names .get (name )
35853537
35863538 # TODO: defer current node if the superclass node is not ready.
35873539 if (
35883540 not base_node
3589- or isinstance (base_node .node , Var )
3541+ or isinstance (base_node .node , ( Var , Decorator ) )
35903542 and not base_node .type
35913543 or isinstance (base_node .type , PartialType )
35923544 and base_node .type .type is not None
35933545 ):
35943546 return None , None
35953547
3596- self_type = self .scope .current_self_type ()
3548+ if current_class is None :
3549+ self_type = self .scope .current_self_type ()
3550+ else :
3551+ self_type = fill_typevars (current_class )
35973552 assert self_type is not None , "Internal error: base lookup outside class"
35983553 if isinstance (self_type , TupleType ):
35993554 instance = tuple_fallback (self_type )
@@ -3605,7 +3560,7 @@ def node_type_from_base(
36053560 is_super = False ,
36063561 is_operator = mypy .checkexpr .is_operator_method (name ),
36073562 original_type = self_type ,
3608- context = node ,
3563+ context = context ,
36093564 chk = self ,
36103565 suppress_errors = True ,
36113566 )
0 commit comments