4848)
4949from mypy .types import Instance , ProperType , TupleType , TypeType , get_proper_type
5050from mypyc .common import MAX_SHORT_INT
51+ from mypyc .ir .class_ir import ClassIR
5152from mypyc .ir .func_ir import FUNC_CLASSMETHOD , FUNC_STATICMETHOD
5253from mypyc .ir .ops import (
5354 Assign ,
@@ -174,7 +175,7 @@ def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value:
174175 )
175176 return obj
176177 else :
177- return builder .read (builder .get_assignment_target (expr ), expr .line )
178+ return builder .read (builder .get_assignment_target (expr , for_read = True ), expr .line )
178179
179180 return builder .load_global (expr )
180181
@@ -336,30 +337,7 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr
336337 # Call a method via the *class*
337338 assert isinstance (callee .expr .node , TypeInfo )
338339 ir = builder .mapper .type_to_ir [callee .expr .node ]
339- decl = ir .method_decl (callee .name )
340- args = []
341- arg_kinds , arg_names = expr .arg_kinds [:], expr .arg_names [:]
342- # Add the class argument for class methods in extension classes
343- if decl .kind == FUNC_CLASSMETHOD and ir .is_ext_class :
344- args .append (builder .load_native_type_object (callee .expr .node .fullname ))
345- arg_kinds .insert (0 , ARG_POS )
346- arg_names .insert (0 , None )
347- args += [builder .accept (arg ) for arg in expr .args ]
348-
349- if ir .is_ext_class :
350- return builder .builder .call (decl , args , arg_kinds , arg_names , expr .line )
351- else :
352- obj = builder .accept (callee .expr )
353- return builder .gen_method_call (
354- obj ,
355- callee .name ,
356- args ,
357- builder .node_type (expr ),
358- expr .line ,
359- expr .arg_kinds ,
360- expr .arg_names ,
361- )
362-
340+ return call_classmethod (builder , ir , expr , callee )
363341 elif builder .is_module_member_expr (callee ):
364342 # Fall back to a PyCall for non-native module calls
365343 function = builder .accept (callee )
@@ -368,6 +346,17 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr
368346 function , args , expr .line , arg_kinds = expr .arg_kinds , arg_names = expr .arg_names
369347 )
370348 else :
349+ if isinstance (callee .expr , RefExpr ):
350+ node = callee .expr .node
351+ if isinstance (node , Var ) and node .is_cls :
352+ typ = get_proper_type (node .type )
353+ if isinstance (typ , TypeType ) and isinstance (typ .item , Instance ):
354+ class_ir = builder .mapper .type_to_ir .get (typ .item .type )
355+ if class_ir and class_ir .is_ext_class and class_ir .has_no_subclasses ():
356+ # Call a native classmethod via cls that can be statically bound,
357+ # since the class has no subclasses.
358+ return call_classmethod (builder , class_ir , expr , callee )
359+
371360 receiver_typ = builder .node_type (callee .expr )
372361
373362 # If there is a specializer for this method name/type, try calling it.
@@ -389,6 +378,32 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr
389378 )
390379
391380
381+ def call_classmethod (builder : IRBuilder , ir : ClassIR , expr : CallExpr , callee : MemberExpr ) -> Value :
382+ decl = ir .method_decl (callee .name )
383+ args = []
384+ arg_kinds , arg_names = expr .arg_kinds [:], expr .arg_names [:]
385+ # Add the class argument for class methods in extension classes
386+ if decl .kind == FUNC_CLASSMETHOD and ir .is_ext_class :
387+ args .append (builder .load_native_type_object (ir .fullname ))
388+ arg_kinds .insert (0 , ARG_POS )
389+ arg_names .insert (0 , None )
390+ args += [builder .accept (arg ) for arg in expr .args ]
391+
392+ if ir .is_ext_class :
393+ return builder .builder .call (decl , args , arg_kinds , arg_names , expr .line )
394+ else :
395+ obj = builder .accept (callee .expr )
396+ return builder .gen_method_call (
397+ obj ,
398+ callee .name ,
399+ args ,
400+ builder .node_type (expr ),
401+ expr .line ,
402+ expr .arg_kinds ,
403+ expr .arg_names ,
404+ )
405+
406+
392407def translate_super_method_call (builder : IRBuilder , expr : CallExpr , callee : SuperExpr ) -> Value :
393408 if callee .info is None or (len (callee .call .args ) != 0 and len (callee .call .args ) != 2 ):
394409 return translate_call (builder , expr , callee )
0 commit comments