def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr) -> Value: """Generate IR for an arbitrary call of form e.m(...). This can also deal with calls to module-level functions. """ if builder.is_native_ref_expr(callee): # Call to module-level native function or such return translate_call(builder, expr, callee) elif (isinstance(callee.expr, RefExpr) and isinstance(callee.expr.node, TypeInfo) and callee.expr.node in builder.mapper.type_to_ir and builder.mapper.type_to_ir[callee.expr.node].has_method(callee.name)): # Call a method via the *class* assert isinstance(callee.expr.node, TypeInfo) ir = builder.mapper.type_to_ir[callee.expr.node] decl = ir.method_decl(callee.name) args = [] arg_kinds, arg_names = expr.arg_kinds[:], expr.arg_names[:] # Add the class argument for class methods in extension classes if decl.kind == FUNC_CLASSMETHOD and ir.is_ext_class: args.append( builder.load_native_type_object(callee.expr.node.fullname)) arg_kinds.insert(0, ARG_POS) arg_names.insert(0, None) args += [builder.accept(arg) for arg in expr.args] if ir.is_ext_class: return builder.builder.call(decl, args, arg_kinds, arg_names, expr.line) else: obj = builder.accept(callee.expr) return builder.gen_method_call(obj, callee.name, args, builder.node_type(expr), expr.line, expr.arg_kinds, expr.arg_names) elif builder.is_module_member_expr(callee): # Fall back to a PyCall for non-native module calls function = builder.accept(callee) args = [builder.accept(arg) for arg in expr.args] return builder.py_call(function, args, expr.line, arg_kinds=expr.arg_kinds, arg_names=expr.arg_names) else: receiver_typ = builder.node_type(callee.expr) # If there is a specializer for this method name/type, try calling it. # We would return the first successful one. val = apply_method_specialization(builder, expr, callee, receiver_typ) if val is not None: return val obj = builder.accept(callee.expr) args = [builder.accept(arg) for arg in expr.args] return builder.gen_method_call(obj, callee.name, args, builder.node_type(expr), expr.line, expr.arg_kinds, expr.arg_names)
def transform_call_expr(builder: IRBuilder, expr: CallExpr) -> Value: if isinstance(expr.analyzed, CastExpr): return translate_cast_expr(builder, expr.analyzed) callee = expr.callee if isinstance(callee, IndexExpr) and isinstance(callee.analyzed, TypeApplication): callee = callee.analyzed.expr # Unwrap type application if isinstance(callee, MemberExpr): return apply_method_specialization(builder, expr, callee) or \ translate_method_call(builder, expr, callee) elif isinstance(callee, SuperExpr): return translate_super_method_call(builder, expr, callee) else: return translate_call(builder, expr, callee)