From 5af13f5d53b4e5f5d472cd8a8bc4444f05ea36d6 Mon Sep 17 00:00:00 2001 From: Harold Brenes Date: Tue, 16 Sep 2025 00:49:31 -0400 Subject: Automatically emit objc_msgSend calls when calling imported or implemented Objective-C methods - Add intrinsics.objc_super() - Emit objc_msgSendSuper2 calls when an objc method call is combined with objc_super(self) - Fix objc_block return value ABI for large struct returns - Fix objc_implement method wrappers bad ABI for large struct returns and indirect args - Simplify parameter forwarding for objc_imlpement methods - Add intrinsics.objc_instancetype to mimi Objective-C instancetype* returns This facilitates returning the correct type on subclasses when calling mehtods such as `alloc`, `init`, `retain`, etc. - Refactor Objective-C class implementations generation so that hierarchies are properly initialized - Better codegen for context passing with ivar-based autocontext - Allow @superclass on imported objc-c objects - Better codegen for block forwarding invoker, arguments are forwarded directly --- src/check_expr.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2a22e5c48..5f36bf3a1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8151,6 +8151,73 @@ gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *op } +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types); + +gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast *call, Entity *proc_entity, Type *proc_type) { + auto &proc = proc_type->Proc; + Slice params = proc.params ? proc.params->Tuple.variables : Slice{}; + + Type *self_type = nullptr; + isize params_start = 1; + + ast_node(ce, CallExpr, call); + + Type *return_type = proc.result_count == 0 ? nullptr : proc.results->Tuple.variables[0]->type; + bool is_return_instancetype = return_type != nullptr && return_type == t_objc_instancetype; + + if (params.count == 0 || !is_type_objc_ptr_to_object(params[0]->type)) { + if (!proc_entity->Procedure.is_objc_class_method) { + // Not a class method, invalid call + error(call, "Invalid Objective-C call: The Objective-C method is not a class method but this first parameter is not an Objective-C object pointer."); + return; + } + + if (is_return_instancetype) { + if (ce->proc->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, ce->proc); + + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(se->expr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); + + return_type = alloc_type_pointer(se->expr->tav.type); + } else { + return_type = proc_entity->Procedure.objc_class->type; + } + } + + self_type = t_objc_Class; + params_start = 0; + } else if (ce->args.count > 0) { + GB_ASSERT(is_type_objc_ptr_to_object(params[0]->type)); + + if (ce->args[0]->tav.objc_super_target) { + self_type = t_objc_super_ptr; + } else { + self_type = ce->args[0]->tav.type; + } + + if (is_return_instancetype) { + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(ce->args[0]->tav.type && ce->args[0]->tav.type->kind == Type_Pointer && ce->args[0]->tav.type->Pointer.elem->kind == Type_Named); + + return_type = ce->args[0]->tav.type; + } + } + + auto param_types = slice_make(permanent_allocator(), proc.param_count + 2 - params_start); + param_types[0] = self_type; + param_types[1] = t_objc_SEL; + + for (isize i = params_start; i < params.count; i++) { + param_types[i+2-params_start] = params[i]->type; + } + + if (is_return_instancetype) { + operand->type = return_type; + } + + add_objc_proc_type(c, call, return_type, param_types); +} gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && @@ -8414,6 +8481,12 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } + Entity *proc_entity = entity_from_expr(call->CallExpr.proc); + bool is_objc_call = proc_entity && proc_entity->kind == Entity_Procedure && proc_entity->Procedure.is_objc_impl_or_import; + if (is_objc_call) { + check_objc_call_expr(c, operand, call, proc_entity, pt); + } + return Expr_Expr; } -- cgit v1.2.3 From 51a8660d521040e3c15842fa6e5a74c78b2cf7b5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 30 Sep 2025 10:24:20 +0100 Subject: Disallow dynamic-literals withint procedure scopes where `context` is not defined --- src/check_expr.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2a22e5c48..c1861652a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9719,7 +9719,10 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { } gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { - if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) { + if (cl->elems.count == 0) { + return false; + } + if ((check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) { ERROR_BLOCK(); error(node, "Compound literals of dynamic types are disabled by default"); error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); @@ -9730,9 +9733,13 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); } return false; + } else if (c->curr_proc_decl != nullptr && c->curr_proc_calling_convention != ProcCC_Odin) { + if (c->scope != nullptr && (c->scope->flags & ScopeFlag_ContextDefined) == 0) { + error(node, "Compound literals of dynamic types require a 'context' to defined"); + } } - return cl->elems.count > 0; + return true; } gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) { -- cgit v1.2.3 From 0158e4009b7bbb68a378037ecb33bd2a836cae2f Mon Sep 17 00:00:00 2001 From: xenobas Date: Wed, 1 Oct 2025 18:01:10 +0100 Subject: Fix proc group named operands issue #4971 --- src/check_expr.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c1861652a..fa9de90bb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7488,8 +7488,6 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, Entity *e = proc_entities[valids[0].index]; GB_ASSERT(e != nullptr); - Array named_operands = {}; - check_call_arguments_single(c, call, operand, e, e->type, positional_operands, named_operands, -- cgit v1.2.3 From 89a5e93818425bb15743a0dcc65272a10620a177 Mon Sep 17 00:00:00 2001 From: Yhya Ibrahim Date: Sun, 5 Oct 2025 09:56:03 +0300 Subject: Remove a debug printf that caused regression --- src/check_expr.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c1861652a..c6f7e022e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1296,11 +1296,6 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ error_line("\t Got: %s\n", s_got); gb_string_free(s_got); gb_string_free(s_expected); - - Type *tx = x->Proc.params->Tuple.variables[0]->type; - Type *ty = y->Proc.params->Tuple.variables[0]->type; - gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(tx), LIT(type_strings[tx->kind]), tx->Named.type_name, tx->Named.type_name->TypeName.original_type_for_parapoly); - gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(ty), LIT(type_strings[ty->kind]), ty->Named.type_name, ty->Named.type_name->TypeName.original_type_for_parapoly); } else { gbString s_expected = type_to_string(y); gbString s_got = type_to_string(x); -- cgit v1.2.3 From 61db9c71f697233773764e51830e413b6bb487f4 Mon Sep 17 00:00:00 2001 From: xenobas Date: Sun, 5 Oct 2025 15:46:02 +0100 Subject: Fix non infix params with default value exclusion counting --- src/check_expr.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c6f7e022e..fbd2a815c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6211,7 +6211,6 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize * continue; } } - break; } } -- cgit v1.2.3 From 7e64dedb7738cdfb6cddd9eb391629b3ad69dc8b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 10 Oct 2025 14:31:41 +0100 Subject: Fix #5778 --- src/check_expr.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8834091d1..d638cf97e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3523,20 +3523,27 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) Type *bt = base_type(type); if (is_const_expr && is_type_constant_type(bt)) { + Type *elem = core_array_type(bt); + if (core_type(bt)->kind == Type_Basic) { if (check_representable_as_constant(c, x->value, bt, &x->value)) { return true; - } else if (check_is_castable_to(c, x, type)) { - if (is_type_pointer(type)) { - return true; - } } - } else if (check_is_castable_to(c, x, type)) { - x->value = {}; - x->mode = Addressing_Value; - return true; + goto check_castable; + } else if (!are_types_identical(elem, bt) && + elem->kind == Type_Basic && + check_representable_as_constant(c, x->value, elem, &x->value)) { + if (check_representable_as_constant(c, x->value, bt, &x->value)) { + return true; + } + goto check_castable; } - } else if (check_is_castable_to(c, x, type)) { + + return false; + } + +check_castable: + if (check_is_castable_to(c, x, type)) { if (x->mode != Addressing_Constant) { x->mode = Addressing_Value; } else if (is_type_slice(type) && is_type_string(x->type)) { -- cgit v1.2.3 From 7e7b6ac0de9f34dd8efd08a9c6f303bcd25ed1cc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 10 Oct 2025 14:37:18 +0100 Subject: Add short-circuit for `check_cast_internal` --- src/check_expr.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d638cf97e..e22f12323 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3239,6 +3239,9 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod } gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { + if (are_types_identical(operand->type, y)) { + return true; + } if (check_is_assignable_to(c, operand, y)) { return true; } @@ -3526,17 +3529,21 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) Type *elem = core_array_type(bt); if (core_type(bt)->kind == Type_Basic) { - if (check_representable_as_constant(c, x->value, bt, &x->value)) { + if (check_representable_as_constant(c, x->value, type, &x->value)) { return true; } goto check_castable; } else if (!are_types_identical(elem, bt) && elem->kind == Type_Basic && check_representable_as_constant(c, x->value, elem, &x->value)) { - if (check_representable_as_constant(c, x->value, bt, &x->value)) { + if (check_representable_as_constant(c, x->value, type, &x->value)) { return true; } goto check_castable; + } else if (check_is_castable_to(c, x, type)) { + x->value = {}; + x->mode = Addressing_Value; + return true; } return false; -- cgit v1.2.3