@@ -2104,9 +2104,7 @@ def check_method_override_for_base_with_name(
21042104 original_class_or_static = False # a variable can't be class or static
21052105
21062106 if isinstance (original_type , FunctionLike ):
2107- original_type = self .bind_and_map_method (
2108- base_attr .node , original_type , defn .info , base
2109- )
2107+ original_type = self .bind_and_map_method (base_attr , original_type , defn .info , base )
21102108 if original_node and is_property (original_node ):
21112109 original_type = get_property_type (original_type )
21122110
@@ -2202,7 +2200,7 @@ def check_method_override_for_base_with_name(
22022200 return False
22032201
22042202 def bind_and_map_method (
2205- self , node : Node | None , typ : FunctionLike , sub_info : TypeInfo , super_info : TypeInfo
2203+ self , sym : SymbolTableNode , typ : FunctionLike , sub_info : TypeInfo , super_info : TypeInfo
22062204 ) -> FunctionLike :
22072205 """Bind self-type and map type variables for a method.
22082206
@@ -2212,11 +2210,13 @@ def bind_and_map_method(
22122210 sub_info: class where the method is used
22132211 super_info: class where the method was defined
22142212 """
2215- if isinstance (node , (FuncDef , OverloadedFuncDef , Decorator )) and not is_static (node ):
2216- if isinstance (node , Decorator ):
2217- is_class_method = node .func .is_class
2213+ if isinstance (sym .node , (FuncDef , OverloadedFuncDef , Decorator )) and not is_static (
2214+ sym .node
2215+ ):
2216+ if isinstance (sym .node , Decorator ):
2217+ is_class_method = sym .node .func .is_class
22182218 else :
2219- is_class_method = node .is_class
2219+ is_class_method = sym . node .is_class
22202220
22212221 mapped_typ = cast (FunctionLike , map_type_from_supertype (typ , sub_info , super_info ))
22222222 active_self_type = self .scope .active_self_type ()
@@ -2783,27 +2783,44 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
27832783 self .check_compatibility (name , base , base2 , typ )
27842784 seen_names .add (name )
27852785
2786- def determine_type_of_member (self , node : SymbolNode ) -> Type | None :
2787- if isinstance (node , FuncBase ):
2788- return self .function_type (node )
2789- if isinstance (node , TypeInfo ):
2790- if node .typeddict_type :
2786+ def determine_type_of_member (self , sym : SymbolTableNode ) -> Type | None :
2787+ if sym .type is not None :
2788+ return sym .type
2789+ if isinstance (sym .node , FuncBase ):
2790+ return self .function_type (sym .node )
2791+ if isinstance (sym .node , TypeInfo ):
2792+ if sym .node .typeddict_type :
27912793 # We special-case TypedDict, because they don't define any constructor.
2792- return self .expr_checker .typeddict_callable (node )
2794+ return self .expr_checker .typeddict_callable (sym . node )
27932795 else :
2794- return type_object_type (node , self .named_type )
2795- if isinstance (node , TypeVarExpr ):
2796+ return type_object_type (sym . node , self .named_type )
2797+ if isinstance (sym . node , TypeVarExpr ):
27962798 # Use of TypeVars is rejected in an expression/runtime context, so
27972799 # we don't need to check supertype compatibility for them.
27982800 return AnyType (TypeOfAny .special_form )
2799- if isinstance (node , TypeAlias ):
2801+ if isinstance (sym . node , TypeAlias ):
28002802 with self .msg .filter_errors ():
28012803 # Suppress any errors, they will be given when analyzing the corresponding node.
28022804 # Here we may have incorrect options and location context.
2803- return self .expr_checker .alias_type_in_runtime_context (node , ctx = node )
2805+ return self .expr_checker .alias_type_in_runtime_context (sym . node , ctx = sym . node )
28042806 # TODO: handle more node kinds here.
28052807 return None
28062808
2809+ def attribute_type_from_base (
2810+ self , name : str , base : Instance
2811+ ) -> tuple [ProperType | None , SymbolTableNode ]:
2812+ """For a NameExpr that is part of a class, walk all base classes and try
2813+ to find the first class that defines a Type for the same name."""
2814+ base_var = base .type [name ]
2815+ base_type = self .determine_type_of_member (base_var )
2816+ if base_type is None :
2817+ return None , base_var
2818+
2819+ if not has_no_typevars (base_type ):
2820+ base_type = expand_type_by_instance (base_type , base )
2821+
2822+ return get_proper_type (base_type ), base_var
2823+
28072824 def check_compatibility (
28082825 self , name : str , base1 : Instance , base2 : Instance , ctx : TypeInfo
28092826 ) -> None :
@@ -2831,17 +2848,8 @@ class C(B, A[int]): ... # this is unsafe because...
28312848 # __init__ and friends can be incompatible -- it's a special case.
28322849 return
28332850
2834- first_type = first_node = None
2835- second_type = second_node = None
2836- orig_var = ctx .get (name )
2837-
2838- if orig_var is not None and orig_var .node is not None :
2839- first_type , first_node = self .attribute_type_from_base (
2840- orig_var .node , base1 .type , base1
2841- )
2842- second_type , second_node = self .attribute_type_from_base (
2843- orig_var .node , base2 .type , base2
2844- )
2851+ first_type , first = self .attribute_type_from_base (name , base1 )
2852+ second_type , second = self .attribute_type_from_base (name , base2 )
28452853
28462854 # TODO: use more principled logic to decide is_subtype() vs is_equivalent().
28472855 # We should rely on mutability of superclass node, not on types being Callable.
@@ -2851,7 +2859,7 @@ class C(B, A[int]): ... # this is unsafe because...
28512859 if isinstance (first_type , Instance ):
28522860 call = find_member ("__call__" , first_type , first_type , is_operator = True )
28532861 if call and isinstance (second_type , FunctionLike ):
2854- second_sig = self .bind_and_map_method (second_node , second_type , ctx , base2 .type )
2862+ second_sig = self .bind_and_map_method (second , second_type , ctx , base2 .type )
28552863 ok = is_subtype (call , second_sig , ignore_pos_arg_names = True )
28562864 elif isinstance (first_type , FunctionLike ) and isinstance (second_type , FunctionLike ):
28572865 if first_type .is_type_obj () and second_type .is_type_obj ():
@@ -2863,22 +2871,21 @@ class C(B, A[int]): ... # this is unsafe because...
28632871 )
28642872 else :
28652873 # First bind/map method types when necessary.
2866- first_sig = self .bind_and_map_method (first_node , first_type , ctx , base1 .type )
2867- second_sig = self .bind_and_map_method (second_node , second_type , ctx , base2 .type )
2874+ first_sig = self .bind_and_map_method (first , first_type , ctx , base1 .type )
2875+ second_sig = self .bind_and_map_method (second , second_type , ctx , base2 .type )
28682876 ok = is_subtype (first_sig , second_sig , ignore_pos_arg_names = True )
28692877 elif first_type and second_type :
2870- if isinstance (first_node , Var ):
2871- first_type = expand_self_type (first_node , first_type , fill_typevars (ctx ))
2872- if isinstance (second_node , Var ):
2873- second_type = expand_self_type (second_node , second_type , fill_typevars (ctx ))
2878+ if isinstance (first . node , Var ):
2879+ first_type = expand_self_type (first . node , first_type , fill_typevars (ctx ))
2880+ if isinstance (second . node , Var ):
2881+ second_type = expand_self_type (second . node , second_type , fill_typevars (ctx ))
28742882 ok = is_equivalent (first_type , second_type )
28752883 if not ok :
2876- second_var = base2 .type . get ( name )
2884+ second_node = base2 .type [ name ]. node
28772885 if (
28782886 isinstance (second_type , FunctionLike )
2879- and second_var is not None
2880- and second_var .node is not None
2881- and is_property (second_var .node )
2887+ and second_node is not None
2888+ and is_property (second_node )
28822889 ):
28832890 second_type = get_property_type (second_type )
28842891 ok = is_subtype (first_type , second_type )
@@ -2890,44 +2897,17 @@ class C(B, A[int]): ... # this is unsafe because...
28902897 ok = True
28912898 # Final attributes can never be overridden, but can override
28922899 # non-final read-only attributes.
2893- if is_final_node (second_node ) and not is_private (name ):
2900+ if is_final_node (second . node ) and not is_private (name ):
28942901 self .msg .cant_override_final (name , base2 .type .name , ctx )
2895- if is_final_node (first_node ):
2896- self .check_if_final_var_override_writable (name , second_node , ctx )
2902+ if is_final_node (first . node ):
2903+ self .check_if_final_var_override_writable (name , second . node , ctx )
28972904 # Some attributes like __slots__ and __deletable__ are special, and the type can
28982905 # vary across class hierarchy.
2899- if isinstance (second_node , Var ) and second_node .allow_incompatible_override :
2906+ if isinstance (second . node , Var ) and second . node .allow_incompatible_override :
29002907 ok = True
29012908 if not ok :
29022909 self .msg .base_class_definitions_incompatible (name , base1 .type , base2 .type , ctx )
29032910
2904- def attribute_type_from_base (
2905- self , expr_node : SymbolNode , base : TypeInfo , self_type : Instance
2906- ) -> tuple [ProperType | None , Node | None ]:
2907- """For a NameExpr that is part of a class, walk all base classes and try
2908- to find the first class that defines a Type for the same name."""
2909- expr_name = expr_node .name
2910- base_var = base .names .get (expr_name )
2911-
2912- if base_var :
2913- base_node = base_var .node
2914- base_type = base_var .type
2915-
2916- if base_type :
2917- if not has_no_typevars (base_type ):
2918- itype = map_instance_to_supertype (self_type , base )
2919- base_type = expand_type_by_instance (base_type , itype )
2920-
2921- return get_proper_type (base_type ), base_node
2922-
2923- if (
2924- base_node is not None
2925- and (base_type := self .determine_type_of_member (base_node )) is not None
2926- ):
2927- return get_proper_type (base_type ), base_node
2928-
2929- return None , None
2930-
29312911 def check_metaclass_compatibility (self , typ : TypeInfo ) -> None :
29322912 """Ensures that metaclasses of all parent types are compatible."""
29332913 if (
0 commit comments