@@ -3152,6 +3152,80 @@ def check_type_alias_rvalue(self, s: AssignmentStmt) -> None:
3152
3152
alias_type = self .expr_checker .accept (s .rvalue )
3153
3153
self .store_type (s .lvalues [- 1 ], alias_type )
3154
3154
3155
+ def check_function_on_class (
3156
+ self ,
3157
+ lvalue : Lvalue ,
3158
+ rvalue : Expression ,
3159
+ p_lvalue_type : ProperType | None ,
3160
+ p_rvalue_type : ProperType | None ,
3161
+ ):
3162
+ """Special case: function assigned to an instance var via the class will be methodised"""
3163
+ type_type = None
3164
+ expr_type = None
3165
+ if isinstance (lvalue , MemberExpr ):
3166
+ expr_type = self .expr_checker .accept (lvalue .expr )
3167
+ proper = get_proper_type (expr_type )
3168
+ if isinstance (proper , CallableType ) and proper .is_type_obj ():
3169
+ type_type = expr_type
3170
+ if not (
3171
+ (type_type or self .scope .active_class ())
3172
+ and isinstance (p_rvalue_type , CallableType )
3173
+ and isinstance (p_lvalue_type , CallableType )
3174
+ ):
3175
+ return
3176
+ node = None
3177
+ if type_type :
3178
+ assert expr_type
3179
+ proper = get_proper_type (expr_type )
3180
+ assert isinstance (proper , CallableType )
3181
+ proper = get_proper_type (proper .ret_type )
3182
+ if isinstance (proper , TupleType ):
3183
+ proper = proper .partial_fallback
3184
+ if not isinstance (proper , Instance ):
3185
+ self .msg .fail (
3186
+ "This value is some special cased thing, needs to be handled separately" ,
3187
+ rvalue ,
3188
+ code = codes .UNHANDLED_SCENARIO ,
3189
+ )
3190
+ return
3191
+ assert isinstance (lvalue , (NameExpr , MemberExpr ))
3192
+ table_node = proper .type .get (lvalue .name )
3193
+ if table_node is None :
3194
+ # work around https://github.com/python/mypy/issues/17316
3195
+ return
3196
+ node = table_node .node
3197
+ class_var = (isinstance (node , Var ) and node .is_classvar ) or (
3198
+ isinstance (lvalue , NameExpr )
3199
+ and isinstance (lvalue .node , Var )
3200
+ and lvalue .node .is_classvar
3201
+ )
3202
+ if p_rvalue_type .is_function :
3203
+ if codes .CALLABLE_FUNCTIONTYPE in self .options .enabled_error_codes :
3204
+ if not (class_var and p_lvalue_type .is_function ):
3205
+ self .msg .fail (
3206
+ 'Assigning a "FunctionType" on the class will become a "MethodType"' ,
3207
+ rvalue ,
3208
+ code = codes .CALLABLE_FUNCTIONTYPE ,
3209
+ )
3210
+ if not class_var :
3211
+ self .msg .note (
3212
+ 'Consider setting it on the instance, or using "ClassVar"' , rvalue
3213
+ )
3214
+ elif (
3215
+ codes .POSSIBLE_FUNCTION in self .options .enabled_error_codes
3216
+ and type (p_rvalue_type ) is CallableType
3217
+ and p_rvalue_type .is_callable
3218
+ ):
3219
+ self .msg .fail (
3220
+ 'This "CallableType" could be a "FunctionType", which when assigned via the class, would produce a "MethodType"' ,
3221
+ rvalue ,
3222
+ code = codes .POSSIBLE_FUNCTION ,
3223
+ )
3224
+ if class_var :
3225
+ self .msg .note ('Consider changing the type to "FunctionType"' , rvalue )
3226
+ elif not p_lvalue_type .is_function :
3227
+ self .msg .note ('Consider setting it on the instance, or using "ClassVar"' , rvalue )
3228
+
3155
3229
def check_assignment (
3156
3230
self ,
3157
3231
lvalue : Lvalue ,
@@ -3306,66 +3380,8 @@ def check_assignment(
3306
3380
self .msg .concrete_only_assign (p_lvalue_type , rvalue )
3307
3381
return
3308
3382
3309
- # Special case: function assigned to an instance var via the class will be methodised
3310
- type_type = None
3311
- expr_type = None
3312
- if isinstance (lvalue , MemberExpr ):
3313
- expr_type = self .expr_checker .accept (lvalue .expr )
3314
- proper = get_proper_type (expr_type )
3315
- if isinstance (proper , CallableType ) and proper .is_type_obj ():
3316
- type_type = expr_type
3317
- if (
3318
- (type_type or self .scope .active_class ())
3319
- and isinstance (p_rvalue_type , CallableType )
3320
- and isinstance (p_lvalue_type , CallableType )
3321
- ):
3322
- node = None
3323
- if type_type :
3324
- assert expr_type
3325
- proper = get_proper_type (expr_type )
3326
- assert isinstance (proper , CallableType )
3327
- proper = get_proper_type (proper .ret_type )
3328
- assert isinstance (proper , Instance )
3329
- assert isinstance (lvalue , (NameExpr , MemberExpr ))
3330
- table_node = proper .type .get (lvalue .name )
3331
- if table_node is None :
3332
- # work around https://github.com/python/mypy/issues/17316
3333
- return
3334
- node = table_node .node
3335
- class_var = (isinstance (node , Var ) and node .is_classvar ) or (
3336
- isinstance (lvalue , NameExpr )
3337
- and isinstance (lvalue .node , Var )
3338
- and lvalue .node .is_classvar
3339
- )
3340
- if p_rvalue_type .is_function :
3341
- if codes .CALLABLE_FUNCTIONTYPE in self .options .enabled_error_codes :
3342
- if not (class_var and p_lvalue_type .is_function ):
3343
- self .msg .fail (
3344
- 'Assigning a "FunctionType" on the class will become a "MethodType"' ,
3345
- rvalue ,
3346
- code = codes .CALLABLE_FUNCTIONTYPE ,
3347
- )
3348
- if not class_var :
3349
- self .msg .note (
3350
- 'Consider setting it on the instance, or using "ClassVar"' ,
3351
- rvalue ,
3352
- )
3353
- elif (
3354
- codes .POSSIBLE_FUNCTION in self .options .enabled_error_codes
3355
- and type (p_rvalue_type ) is CallableType
3356
- and p_rvalue_type .is_callable
3357
- ):
3358
- self .msg .fail (
3359
- 'This "CallableType" could be a "FunctionType", which when assigned via the class, would produce a "MethodType"' ,
3360
- rvalue ,
3361
- code = codes .POSSIBLE_FUNCTION ,
3362
- )
3363
- if class_var :
3364
- self .msg .note ('Consider changing the type to "FunctionType"' , rvalue )
3365
- elif not p_lvalue_type .is_function :
3366
- self .msg .note (
3367
- 'Consider setting it on the instance, or using "ClassVar"' , rvalue
3368
- )
3383
+ self .check_function_on_class (lvalue , rvalue , p_lvalue_type , p_rvalue_type )
3384
+
3369
3385
proper_right = get_proper_type (rvalue_type )
3370
3386
if (
3371
3387
isinstance (lvalue , RefExpr )
0 commit comments