@@ -2426,20 +2426,7 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
24262426
24272427 # Special case: only non-abstract non-protocol classes can be assigned to
24282428 # variables with explicit type Type[A], where A is protocol or abstract.
2429- rvalue_type = get_proper_type (rvalue_type )
2430- lvalue_type = get_proper_type (lvalue_type )
2431- if (isinstance (rvalue_type , CallableType ) and rvalue_type .is_type_obj () and
2432- (rvalue_type .type_object ().is_abstract or
2433- rvalue_type .type_object ().is_protocol ) and
2434- ((isinstance (lvalue_type , TypeType ) and
2435- isinstance (lvalue_type .item , Instance ) and
2436- (lvalue_type .item .type .is_abstract or
2437- lvalue_type .item .type .is_protocol )) or
2438- (isinstance (lvalue_type , CallableType ) and
2439- isinstance (lvalue_type .ret_type , Instance ) and
2440- (lvalue_type .ret_type .type .is_abstract or
2441- lvalue_type .ret_type .type .is_protocol )))):
2442- self .msg .concrete_only_assign (lvalue_type , rvalue )
2429+ if not self .check_concrete_only_assign (lvalue_type , rvalue_type , rvalue ):
24432430 return
24442431 if rvalue_type and infer_lvalue_type and not isinstance (lvalue_type , PartialType ):
24452432 # Don't use type binder for definitions of special forms, like named tuples.
@@ -2457,6 +2444,38 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
24572444 self .infer_variable_type (inferred , lvalue , rvalue_type , rvalue )
24582445 self .check_assignment_to_slots (lvalue )
24592446
2447+ def check_concrete_only_assign (self , lvalue_type : Optional [Type ],
2448+ rvalue_type : Type , rvalue : Expression ) -> bool :
2449+ rvalue_type = get_proper_type (rvalue_type )
2450+ lvalue_type = get_proper_type (lvalue_type )
2451+ if not (
2452+ isinstance (rvalue_type , CallableType ) and
2453+ rvalue_type .is_type_obj () and
2454+ (rvalue_type .type_object ().is_abstract or
2455+ rvalue_type .type_object ().is_protocol )):
2456+ return True
2457+
2458+ lvalue_is_a_type = (
2459+ isinstance (lvalue_type , TypeType ) and
2460+ isinstance (lvalue_type .item , Instance ) and
2461+ (lvalue_type .item .type .is_abstract or
2462+ lvalue_type .item .type .is_protocol )
2463+ )
2464+
2465+ lvalue_is_a_callable = False
2466+ if isinstance (lvalue_type , CallableType ):
2467+ ret_type = get_proper_type (lvalue_type .ret_type )
2468+ lvalue_is_a_callable = (
2469+ isinstance (ret_type , Instance ) and
2470+ (ret_type .type .is_abstract or ret_type .type .is_protocol )
2471+ )
2472+
2473+ if lvalue_is_a_type or lvalue_is_a_callable :
2474+ # `lvalue_type` here is either `TypeType` or `CallableType`:
2475+ self .msg .concrete_only_assign (cast (Type , lvalue_type ), rvalue )
2476+ return False
2477+ return True
2478+
24602479 # (type, operator) tuples for augmented assignments supported with partial types
24612480 partial_type_augmented_ops : Final = {
24622481 ('builtins.list' , '+' ),
0 commit comments