@@ -361,21 +361,24 @@ def visit_get_attr(self, op: GetAttr) -> None:
361361 attr_rtype , decl_cl = cl .attr_details (op .attr )
362362 prefer_method = cl .is_trait and attr_rtype .error_overlap
363363 if cl .get_method (op .attr , prefer_method = prefer_method ):
364- # Properties are essentially methods, so use vtable access for them.
365- version = "_TRAIT" if cl .is_trait else ""
366- self .emit_line (
367- "%s = CPY_GET_ATTR%s(%s, %s, %d, %s, %s); /* %s */"
368- % (
369- dest ,
370- version ,
371- obj ,
372- self .emitter .type_struct_name (rtype .class_ir ),
373- rtype .getter_index (op .attr ),
374- rtype .struct_name (self .names ),
375- self .ctype (rtype .attr_type (op .attr )),
376- op .attr ,
364+ if cl .is_method_final (op .attr ):
365+ self .emit_method_call (f"{ dest } = " , op .obj , op .attr , [])
366+ else :
367+ # Properties are essentially methods, so use vtable access for them.
368+ version = "_TRAIT" if cl .is_trait else ""
369+ self .emit_line (
370+ "%s = CPY_GET_ATTR%s(%s, %s, %d, %s, %s); /* %s */"
371+ % (
372+ dest ,
373+ version ,
374+ obj ,
375+ self .emitter .type_struct_name (rtype .class_ir ),
376+ rtype .getter_index (op .attr ),
377+ rtype .struct_name (self .names ),
378+ self .ctype (rtype .attr_type (op .attr )),
379+ op .attr ,
380+ )
377381 )
378- )
379382 else :
380383 # Otherwise, use direct or offset struct access.
381384 attr_expr = self .get_attr_expr (obj , op , decl_cl )
@@ -529,11 +532,12 @@ def visit_call(self, op: Call) -> None:
529532 def visit_method_call (self , op : MethodCall ) -> None :
530533 """Call native method."""
531534 dest = self .get_dest_assign (op )
532- obj = self .reg ( op .obj )
535+ self .emit_method_call ( dest , op .obj , op . method , op . args )
533536
534- rtype = op .receiver_type
537+ def emit_method_call (self , dest : str , op_obj : Value , name : str , op_args : list [Value ]) -> None :
538+ obj = self .reg (op_obj )
539+ rtype = op_obj .type
535540 class_ir = rtype .class_ir
536- name = op .method
537541 method = rtype .class_ir .get_method (name )
538542 assert method is not None
539543
@@ -547,7 +551,7 @@ def visit_method_call(self, op: MethodCall) -> None:
547551 if method .decl .kind == FUNC_STATICMETHOD
548552 else [f"(PyObject *)Py_TYPE({ obj } )" ] if method .decl .kind == FUNC_CLASSMETHOD else [obj ]
549553 )
550- args = ", " .join (obj_args + [self .reg (arg ) for arg in op . args ])
554+ args = ", " .join (obj_args + [self .reg (arg ) for arg in op_args ])
551555 mtype = native_function_type (method , self .emitter )
552556 version = "_TRAIT" if rtype .class_ir .is_trait else ""
553557 if is_direct :
@@ -567,7 +571,7 @@ def visit_method_call(self, op: MethodCall) -> None:
567571 rtype .struct_name (self .names ),
568572 mtype ,
569573 args ,
570- op . method ,
574+ name ,
571575 )
572576 )
573577
0 commit comments