24
24
from mypy .erasetype import erase_type , erase_typevars , remove_instance_last_known_values
25
25
from mypy .errorcodes import TYPE_VAR , UNUSED_AWAITABLE , UNUSED_COROUTINE , ErrorCode
26
26
from 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
28
28
from mypy .literals import Key , extract_var_from_literal_hash , literal , literal_hash
29
29
from mypy .maptype import map_instance_to_supertype
30
30
from mypy .meet import is_overlapping_erased_types , is_overlapping_types , meet_types
161
161
is_literal_type_like ,
162
162
is_singleton_type ,
163
163
make_simplified_union ,
164
- map_type_from_supertype ,
165
164
true_only ,
166
165
try_expanding_sum_type_to_union ,
167
166
try_getting_int_literals_from_type ,
@@ -2141,8 +2140,8 @@ def check_setter_type_override(self, defn: OverloadedFuncDef, base: TypeInfo) ->
2141
2140
is a custom settable property (i.e. where setter type is different from getter type).
2142
2141
Note that this check is contravariant.
2143
2142
"""
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 )
2146
2145
# The caller should handle deferrals.
2147
2146
assert typ is not None and original_type is not None
2148
2147
@@ -2173,14 +2172,14 @@ def check_method_override_for_base_with_name(
2173
2172
override_class_or_static = defn .is_class or defn .is_static
2174
2173
else :
2175
2174
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 )
2177
2176
assert typ is not None
2178
2177
2179
2178
original_node = base_attr .node
2180
2179
# `original_type` can be partial if (e.g.) it is originally an
2181
2180
# instance variable from an `__init__` block that becomes deferred.
2182
2181
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 )
2184
2183
if original_type is None :
2185
2184
supertype_ready = False
2186
2185
if self .pass_num < self .last_pass :
@@ -2321,51 +2320,6 @@ def check_method_override_for_base_with_name(
2321
2320
)
2322
2321
return False
2323
2322
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
-
2369
2323
def get_op_other_domain (self , tp : FunctionLike ) -> Type | None :
2370
2324
if isinstance (tp , CallableType ):
2371
2325
if tp .arg_kinds and tp .arg_kinds [0 ] == ARG_POS :
@@ -2882,6 +2836,7 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None:
2882
2836
self .check_compatibility (name , base , base2 , typ )
2883
2837
2884
2838
def determine_type_of_member (self , sym : SymbolTableNode ) -> Type | None :
2839
+ # TODO: this duplicates both checkmember.py and analyze_ref_expr(), delete.
2885
2840
if sym .type is not None :
2886
2841
return sym .type
2887
2842
if isinstance (sym .node , SYMBOL_FUNCBASE_TYPES ):
@@ -2901,7 +2856,6 @@ def determine_type_of_member(self, sym: SymbolTableNode) -> Type | None:
2901
2856
# Suppress any errors, they will be given when analyzing the corresponding node.
2902
2857
# Here we may have incorrect options and location context.
2903
2858
return self .expr_checker .alias_type_in_runtime_context (sym .node , ctx = sym .node )
2904
- # TODO: handle more node kinds here.
2905
2859
return None
2906
2860
2907
2861
def check_compatibility (
@@ -2932,50 +2886,47 @@ class C(B, A[int]): ... # this is unsafe because...
2932
2886
return
2933
2887
first = base1 .names [name ]
2934
2888
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 )
2937
2892
2938
2893
# TODO: use more principled logic to decide is_subtype() vs is_equivalent().
2939
2894
# We should rely on mutability of superclass node, not on types being Callable.
2940
2895
# (in particular handle settable properties with setter type different from getter).
2941
2896
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 ():
2951
2901
# For class objects only check the subtype relationship of the classes,
2952
2902
# since we allow incompatible overrides of '__init__'/'__new__'
2953
2903
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 ()),
2956
2906
)
2957
2907
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 )
2962
2910
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 :
2972
2916
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 )
2976
2923
):
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
+ )
2979
2930
else :
2980
2931
if first_type is None :
2981
2932
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 |
3364
3315
# a class object for lambdas overriding methods, etc.
3365
3316
base_node = base .names [inferred .name ].node
3366
3317
base_type , _ = self .node_type_from_base (
3367
- inferred ,
3318
+ inferred . name ,
3368
3319
base ,
3320
+ inferred ,
3369
3321
is_class = is_method (base_node )
3370
3322
or isinstance (base_node , Var )
3371
3323
and not is_instance_var (base_node ),
@@ -3474,7 +3426,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
3474
3426
rvalue_type = self .expr_checker .accept (rvalue , lvalue_node .type )
3475
3427
actual_lvalue_type = lvalue_node .type
3476
3428
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 )
3478
3430
if lvalue_node .is_inferred and not lvalue_node .explicit_self_type :
3479
3431
lvalue_node .type = actual_lvalue_type
3480
3432
@@ -3493,7 +3445,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
3493
3445
if is_private (lvalue_node .name ):
3494
3446
continue
3495
3447
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 )
3497
3449
custom_setter = is_custom_settable_property (base_node )
3498
3450
if isinstance (base_type , PartialType ):
3499
3451
base_type = None
@@ -3513,7 +3465,7 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
3513
3465
return
3514
3466
if lvalue_type and custom_setter :
3515
3467
base_type , _ = self .node_type_from_base (
3516
- lvalue_node , base , setter_type = True
3468
+ lvalue_node . name , base , lvalue , setter_type = True
3517
3469
)
3518
3470
# Setter type for a custom property must be ready if
3519
3471
# the getter type is ready.
@@ -3565,12 +3517,13 @@ def check_compatibility_super(
3565
3517
3566
3518
def node_type_from_base (
3567
3519
self ,
3568
- node : SymbolNode ,
3520
+ name : str ,
3569
3521
base : TypeInfo ,
3522
+ context : Context ,
3570
3523
* ,
3571
3524
setter_type : bool = False ,
3572
3525
is_class : bool = False ,
3573
- name_override : str | None = None ,
3526
+ current_class : TypeInfo | None = None ,
3574
3527
) -> tuple [Type | None , SymbolNode | None ]:
3575
3528
"""Find a type for a name in base class.
3576
3529
@@ -3580,20 +3533,22 @@ def node_type_from_base(
3580
3533
If setter_type is True, return setter types for settable properties (otherwise the
3581
3534
getter type is returned).
3582
3535
"""
3583
- name = name_override or node .name
3584
3536
base_node = base .names .get (name )
3585
3537
3586
3538
# TODO: defer current node if the superclass node is not ready.
3587
3539
if (
3588
3540
not base_node
3589
- or isinstance (base_node .node , Var )
3541
+ or isinstance (base_node .node , ( Var , Decorator ) )
3590
3542
and not base_node .type
3591
3543
or isinstance (base_node .type , PartialType )
3592
3544
and base_node .type .type is not None
3593
3545
):
3594
3546
return None , None
3595
3547
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 )
3597
3552
assert self_type is not None , "Internal error: base lookup outside class"
3598
3553
if isinstance (self_type , TupleType ):
3599
3554
instance = tuple_fallback (self_type )
@@ -3605,7 +3560,7 @@ def node_type_from_base(
3605
3560
is_super = False ,
3606
3561
is_operator = mypy .checkexpr .is_operator_method (name ),
3607
3562
original_type = self_type ,
3608
- context = node ,
3563
+ context = context ,
3609
3564
chk = self ,
3610
3565
suppress_errors = True ,
3611
3566
)
0 commit comments