From 7c8dfd4cff47c97f626cf01aa24c6a02beb933c4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 1 Oct 2026 01:30:38 +0100 Subject: [PATCH] Improve mixed order ternary type inference and poly-determination diagnostics --- src/check_expr.cpp | 23 +++++++++++++++++------ src/check_type.cpp | 32 ++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3e1810e15..6ff54a624 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10551,19 +10551,30 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - check_expr_as_value_for_ternary(c, &x, te->x, type_hint); - node->viral_state_flags |= te->x->viral_state_flags; - if (te->y != nullptr) { + if (te->y == nullptr) { + check_expr_as_value_for_ternary(c, &x, te->x, type_hint); + node->viral_state_flags |= te->x->viral_state_flags; + error(node, "A ternary expression must have an else clause"); + return kind; + } + + if (type_hint == nullptr && arg_is_deferrable_untyped_expr(te->x)) { + check_expr_as_value_for_ternary(c, &y, te->y, nullptr); + node->viral_state_flags |= te->y->viral_state_flags; + Type *th = is_type_typed(y.type) ? y.type : nullptr; + check_expr_as_value_for_ternary(c, &x, te->x, th); + node->viral_state_flags |= te->x->viral_state_flags; + } else { + check_expr_as_value_for_ternary(c, &x, te->x, type_hint); + node->viral_state_flags |= te->x->viral_state_flags; + Type *th = type_hint; if (type_hint == nullptr && is_type_typed(x.type)) { th = x.type; } check_expr_as_value_for_ternary(c, &y, te->y, th); node->viral_state_flags |= te->y->viral_state_flags; - } else { - error(node, "A ternary expression must have an else clause"); - return kind; } if (te->x->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 6ea164e3f..b4819979e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2752,15 +2752,21 @@ gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *pol ERROR_BLOCK(); gbString pts = type_to_string(poly_type); - gbString ots = type_to_string(operand.type, true); defer (gb_string_free(pts)); - defer (gb_string_free(ots)); - error(operand.expr, "Cannot determine polymorphic type from parameter: '%s' to '%s'", ots, pts); - - if (operand.mode == Addressing_Type) { - error_line("\tSuggestion: Are you trying to pass a type to a value parameter?\n"); + if (operand.deferred_untyped_arg) { + // An untyped argument (`{...}`, `.Member`, a both-untyped ternary) whose type is not + // pinned by any other argument, so the polymorphic type cannot be inferred from it. + set_caret_label("untyped; its type cannot be determined here"); + error(operand.expr, "Cannot infer the polymorphic type '%s' from this argument", pts); + error_line("\tname the type explicitly (e.g. 'T{...}'), or determine '%s' from another argument\n", pts); + } else { + gbString ots = type_to_string(operand.type, true); + defer (gb_string_free(ots)); + error(operand.expr, "Cannot determine polymorphic type from parameter: '%s' to '%s'", ots, pts); + if (operand.mode == Addressing_Type) { + error_line("\tSuggestion: Are you trying to pass a type to a value parameter?\n"); + } } - } return t_invalid; } @@ -2825,7 +2831,17 @@ gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *pol gbString ots = type_to_string(operand.type, true); defer (gb_string_free(pts)); defer (gb_string_free(ots)); - error(operand.expr, "Cannot determine polymorphic type from parameter: '%s' to '%s'", ots, pts); + if (poly_type->kind == Type_Generic && poly_type->Generic.specialized != nullptr) { + // Constrained generic (`$T/Constraint`): the argument's type does not satisfy the constraint. + gbString cs = type_to_string(poly_type->Generic.specialized); + gbString cl = gb_string_append_fmt(gb_string_make(heap_allocator(), ""), "'%s' is not a '%s'", ots, cs); + set_caret_label(cl); + error(operand.expr, "Argument's type '%s' does not satisfy the polymorphic constraint '%s'", ots, cs); + gb_string_free(cl); + gb_string_free(cs); + } else { + error(operand.expr, "Cannot determine polymorphic type from parameter: '%s' to '%s'", ots, pts); + } Type *pt = poly_type; while (pt && pt->kind == Type_Generic && pt->Generic.specialized) {