$defined returns an error when assigning a struct initializer with an incorrect type #2449

This commit is contained in:
Christoffer Lerno
2025-09-01 10:44:19 +02:00
parent 176fb47c23
commit af4309b286
7 changed files with 135 additions and 77 deletions

View File

@@ -93,6 +93,7 @@
- Compiler hangs on == overload if other is generic #2443
- Fix missing end of line when encountering errors in project creation.
- Const enum methods are not being recognized. #2445
- $defined returns an error when assigning a struct initializer with an incorrect type #2449
### Stdlib changes
- Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`.

View File

@@ -2416,7 +2416,7 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr);
bool sema_cast_const(Expr *expr);
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref);
bool sema_analyse_decl(SemaContext *context, Decl *decl);
bool sema_analyse_method_register(SemaContext *context, Decl *method);
@@ -2429,7 +2429,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement);
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right,
bool is_unwrapped_var, bool is_declaration, bool *failed_ref);
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr);
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref);
Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs);
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional,

View File

@@ -1690,7 +1690,7 @@ ERR:
bool sema_analyse_const_enum_constant_val(SemaContext *context, Decl *decl)
{
Expr *value = decl->enum_constant.value;
if (!sema_analyse_inferred_expr(context, decl->type, value)) return decl_poison(decl);
if (!sema_analyse_inferred_expr(context, decl->type, value,NULL)) return decl_poison(decl);
if (!expr_is_runtime_const(value))
{
SEMA_ERROR(value, "Expected an constant enum value.");
@@ -3612,7 +3612,7 @@ static inline bool sema_analyse_custom_attribute(SemaContext *context, ResolvedA
if (!sema_resolve_type_info(context, type_infoptr(param->var.type_info), RESOLVE_TYPE_DEFAULT)) return false;
Type *type = typeget(param->var.type_info);
ASSERT_SPAN(decl, type);
if (!sema_analyse_inferred_expr(context, type, expr)) goto ERR;
if (!sema_analyse_inferred_expr(context, type, expr, NULL)) goto ERR;
if (!cast_implicit(context, expr, type, false)) goto ERR;
if (!sema_cast_const(expr))
{

View File

@@ -51,7 +51,7 @@ static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr *
static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, CheckType check);
static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bool *missing_ref, CheckType check,
bool lvalue);
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr);
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr, bool *no_match_ref);
static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error);
static inline bool sema_expr_analyse_binary(SemaContext *context, Type *infer_type, Expr *expr, bool *failed_ref);
static inline bool sema_expr_resolve_ct_eval(SemaContext *context, Expr *expr);
@@ -1365,7 +1365,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr
if (!sema_analyse_expr(context, left)) return false;
if (type_kind_is_any_vector(type_flatten(left->type)->type_kind))
{
return sema_analyse_inferred_expr(context, left->type, right);
return sema_analyse_inferred_expr(context, left->type, right, NULL);
}
return sema_analyse_expr(context, right);
}
@@ -1374,7 +1374,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr
if (!sema_analyse_expr(context, right)) return false;
if (type_kind_is_any_vector(type_flatten(right->type)->type_kind))
{
return sema_analyse_inferred_expr(context, right->type, left);
return sema_analyse_inferred_expr(context, right->type, left, NULL);
}
return sema_analyse_expr(context, left);
}
@@ -1386,7 +1386,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr
{
case TYPE_ENUM:
case TYPE_CONST_ENUM:
return sema_analyse_inferred_expr(context, left->type, right);
return sema_analyse_inferred_expr(context, left->type, right, NULL);
default:
return sema_analyse_expr(context, right);
}
@@ -1405,7 +1405,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left,
{
case TYPE_ENUM:
case TYPE_CONST_ENUM:
return sema_analyse_inferred_expr(context, left->type, right);
return sema_analyse_inferred_expr(context, left->type, right, NULL);
default:
break;
}
@@ -1418,7 +1418,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left,
{
case TYPE_ENUM:
case TYPE_CONST_ENUM:
return sema_analyse_inferred_expr(context, right->type, left);
return sema_analyse_inferred_expr(context, right->type, left, NULL);
default:
break;
}
@@ -1428,7 +1428,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left,
if (!sema_analyse_expr(context, left)) return false;
if (type_kind_is_any_vector(type_flatten(left->type)->type_kind))
{
return sema_analyse_inferred_expr(context, left->type, right);
return sema_analyse_inferred_expr(context, left->type, right, NULL);
}
return sema_analyse_expr(context, right);
}
@@ -1437,7 +1437,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left,
if (!sema_analyse_expr(context, right)) return false;
if (type_kind_is_any_vector(type_flatten(right->type)->type_kind))
{
return sema_analyse_inferred_expr(context, right->type, left);
return sema_analyse_inferred_expr(context, right->type, left, NULL);
}
return sema_analyse_expr(context, left);
}
@@ -3820,7 +3820,7 @@ static inline bool sema_expr_resolve_subscript_index(SemaContext *context, Expr
if (overload)
{
index_type = overload->func_decl.signature.params[1]->type;
if (!sema_analyse_inferred_expr(context, index_type, index))
if (!sema_analyse_inferred_expr(context, index_type, index, NULL))
{
expr_poison(index);
return false;
@@ -5984,10 +5984,10 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *context, Expr *expr
{
if (!is_dead || context->active_scope.is_dead)
{
return infer_type ? sema_analyse_inferred_expr(context, infer_type, expr) : sema_analyse_expr(context, expr);
return infer_type ? sema_analyse_inferred_expr(context, infer_type, expr, NULL) : sema_analyse_expr(context, expr);
}
context->active_scope.is_dead = true;
bool success = infer_type ? sema_analyse_inferred_expr(context, infer_type, expr) : sema_analyse_expr(context, expr);
bool success = infer_type ? sema_analyse_inferred_expr(context, infer_type, expr, NULL) : sema_analyse_expr(context, expr);
context->active_scope.is_dead = false;
return success;
}
@@ -6579,7 +6579,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool
{
expr->expr_kind = EXPR_COMPOUND_LITERAL;
expr->expr_compound_literal = (ExprCompoundLiteral) { .initializer = inner, .type_info = type_info };
return sema_expr_analyse_compound_literal(context, expr);
return sema_expr_analyse_compound_literal(context, expr, invalid_cast_ref);
}
bool success = sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_INFER);
if (!sema_analyse_expr(context, inner) || !success) return false;
@@ -6613,7 +6613,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ
Type *base = left_flat->array.base;
if (right->expr_kind == EXPR_SLICE || (compiler.build.old_slice_copy && right->expr_kind == EXPR_INITIALIZER_LIST && right->initializer_list))
{
if (!sema_analyse_inferred_expr(context, left_type, right)) return false;
if (!sema_analyse_inferred_expr(context, left_type, right, NULL)) return false;
if (left_flat == type_flatten(right->type) || right->type == type_untypedlist) goto SLICE_COPY;
}
else
@@ -6637,7 +6637,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ
type_quoted_error_string(base));
}
}
if (!sema_analyse_inferred_expr(context, base, right)) return false;
if (!sema_analyse_inferred_expr(context, base, right, NULL)) return false;
}
Type *right_type = right->type->canonical;
if (base->canonical != right_type && (type_is_arraylike(right_type) || right_type->type_kind == TYPE_SLICE))
@@ -6719,7 +6719,7 @@ static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *e
ASSERT_SPAN(left, left->resolve_status == RESOLVE_DONE);
// Evaluate right side to using inference from last type.
if (!sema_analyse_inferred_expr(context, left->type, right)) return false;
if (!sema_analyse_inferred_expr(context, left->type, right, NULL)) return false;
if (!expr_is_runtime_const(right))
{
@@ -6926,7 +6926,7 @@ static bool sema_binary_analyse_ct_subscript_op_assign(SemaContext *context, Exp
static BoolErr sema_insert_overload_in_op_assign_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right, BinaryOp operator, Type *lhs_type)
{
assert(type_is_user_defined(lhs_type));
if (!sema_analyse_inferred_expr(context, lhs_type, right)) return BOOL_ERR;
if (!sema_analyse_inferred_expr(context, lhs_type, right, NULL)) return BOOL_ERR;
static OperatorOverload MAP[BINARYOP_LAST + 1] = {
[BINARYOP_ADD_ASSIGN] = OVERLOAD_PLUS_ASSIGN,
[BINARYOP_SUB_ASSIGN] = OVERLOAD_MINUS_ASSIGN,
@@ -7208,7 +7208,7 @@ BITSTRUCT_OK:
}
else
{
if (!sema_analyse_inferred_expr(context, left->type, right)) return false;
if (!sema_analyse_inferred_expr(context, left->type, right, NULL)) return false;
}
// 3. Copy type & set properties.
@@ -9100,7 +9100,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
}
else
{
if (!sema_analyse_inferred_expr(context, infer_type, left)) return false;
if (!sema_analyse_inferred_expr(context, infer_type, left, NULL)) return false;
}
Type *type = left->type;
@@ -9118,7 +9118,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
EndJump active_scope_jump = context->active_scope.end_jump;
// First we analyse the "else" and try to implictly cast.
if (!sema_analyse_inferred_expr(context, infer_type, right)) return false;
if (!sema_analyse_inferred_expr(context, infer_type, right, NULL)) return false;
if (left->expr_kind == EXPR_OPTIONAL)
{
@@ -10585,10 +10585,16 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
success = false;
}
break;
case EXPR_COMPOUND_LITERAL:
if (!sema_expr_analyse_compound_literal(context, main_expr, &failed))
{
if (!failed) goto FAIL;
success = false;
}
break;
case EXPR_CT_ARG:
case EXPR_BITACCESS:
case EXPR_BITASSIGN:
case EXPR_COMPOUND_LITERAL:
case EXPR_EMBED:
case EXPR_GENERIC_IDENT:
case EXPR_MACRO_BODY:
@@ -10695,7 +10701,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty
// Not found, so generate a new.
if (!decl)
{
if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false;
if (!sema_analyse_inferred_expr(context, infer_type, arg_expr, NULL)) return false;
switch (sema_resolve_storage_type(context, arg_expr->type))
{
case STORAGE_ERROR:
@@ -10721,14 +10727,14 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty
// An expr argument, this means we copy and evaluate.
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg), NULL), false);
expr_replace(expr, copy_expr_single(arg_expr));
return sema_analyse_inferred_expr(context, infer_type, expr);
return sema_analyse_inferred_expr(context, infer_type, expr, NULL);
}
case TOKEN_CT_VACONST:
{
// An expr argument, this means we copy and evaluate.
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg), NULL), false);
arg_expr = copy_expr_single(arg_expr);
if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false;
if (!sema_analyse_inferred_expr(context, infer_type, arg_expr, NULL)) return false;
if (!sema_cast_const(arg_expr))
{
RETURN_SEMA_ERROR(arg_expr, "This argument needs to be a compile time constant.");
@@ -10801,7 +10807,7 @@ static inline bool sema_expr_analyse_assignable(SemaContext *context, Expr *expr
}
if (!type) RETURN_SEMA_ERROR(type_expr, "Expected a type or constant typeid here.");
Expr *inner = exprptr(expr->assignable_expr.expr);
if (!sema_analyse_inferred_expr(context, type, inner)) goto FAILED;
if (!sema_analyse_inferred_expr(context, type, inner, NULL)) goto FAILED;
bool ok = may_cast(context, inner, type, false, true);
expr_rewrite_const_bool(expr, type_bool, ok);
context->call_env.in_no_eval = in_no_eval;
@@ -10980,7 +10986,7 @@ static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, b
return true;
}
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr)
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr, bool *no_match_ref)
{
TypeInfo *type_info = expr->expr_compound_literal.type_info;
// We allow infering the size of arrays.
@@ -10991,7 +10997,7 @@ static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr
RETURN_SEMA_ERROR(type_info, "The type here should always be written as a plain type and not an optional, please remove the '?'.");
}
if (!sema_resolve_type_structure(context, type)) return false;
if (!sema_expr_analyse_initializer_list(context, type, expr->expr_compound_literal.initializer)) return false;
if (!sema_expr_analyse_initializer_list(context, type, expr->expr_compound_literal.initializer, no_match_ref)) return false;
expr_replace(expr, expr->expr_compound_literal.initializer);
return true;
}
@@ -11153,7 +11159,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
case EXPR_FORCE_UNWRAP:
return sema_expr_analyse_force_unwrap(context, expr);
case EXPR_COMPOUND_LITERAL:
return sema_expr_analyse_compound_literal(context, expr);
return sema_expr_analyse_compound_literal(context, expr, NULL);
case EXPR_RETHROW:
return sema_expr_analyse_rethrow(context, expr, NULL);
case EXPR_CONST:
@@ -11187,7 +11193,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
return sema_expr_analyse_access(context, expr, NULL, check, false);
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
return sema_expr_analyse_initializer_list(context, type_untypedlist, expr);
return sema_expr_analyse_initializer_list(context, type_untypedlist, expr, NULL);
case EXPR_CAST:
return sema_expr_analyse_cast(context, expr, NULL);
case EXPR_EXPRESSION_LIST:
@@ -11229,7 +11235,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo
}
else
{
if (!sema_analyse_inferred_expr(context, to, expr)) return false;
if (!sema_analyse_inferred_expr(context, to, expr, no_match_ref)) return false;
}
if (!sema_cast_rvalue(context, expr, true)) return false;
if (to) to = type_no_optional(to);
@@ -11761,7 +11767,7 @@ bool sema_cast_const(Expr *expr)
UNREACHABLE
}
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr)
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref)
{
Type *original_type = to;
to = type_no_optional(to);
@@ -11796,13 +11802,13 @@ RETRY:
InliningSpan *old_span = context->inlined_at;
context->inlined_at = new_span;
expr_replace(expr, expr->expr_other_context.inner);
bool success = sema_analyse_inferred_expr(context, original_type, expr);
bool success = sema_analyse_inferred_expr(context, original_type, expr, no_match_ref);
context->inlined_at = old_span;
return success;
}
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_INITIALIZER_LIST:
if (!sema_expr_analyse_initializer_list(context, to, expr)) return expr_poison(expr);
if (!sema_expr_analyse_initializer_list(context, to, expr, no_match_ref)) return expr_poison(expr);
break;
case EXPR_UNRESOLVED_IDENTIFIER:
if (!sema_expr_analyse_identifier(context, to, expr)) return expr_poison(expr);
@@ -11828,7 +11834,7 @@ RETRY:
case EXPR_UNARY:
if (to && expr->unary_expr.operator == UNARYOP_TADDR && to->canonical->type_kind == TYPE_POINTER && to->canonical != type_voidptr)
{
if (!sema_analyse_inferred_expr(context, type_get_indexed_type(to), expr->unary_expr.expr)) return expr_poison(expr);
if (!sema_analyse_inferred_expr(context, type_get_indexed_type(to), expr->unary_expr.expr,NULL)) return expr_poison(expr);
}
FALLTHROUGH;
default:

View File

@@ -4,14 +4,14 @@
#include "sema_internal.h"
static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer);
static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer, bool *no_match_ref);
static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened,
Expr *initializer);
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer);
Expr *initializer, bool *no_match_ref);
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer, bool *no_match_ref);
static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened,
Expr *initializer);
Expr *initializer, bool *no_match_ref);
static inline void sema_not_enough_elements_error(SemaContext *context, Expr *initializer, int element);
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr);
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr, bool *no_match_ref);
static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer);
static Decl *sema_resolve_element_for_name(SemaContext *context, Decl **decls, DesignatorElement ***elements_ref, unsigned *index, bool is_substruct);
static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, Expr *expr, ArrayIndex *max_index, Decl **member_ptr);
@@ -182,7 +182,7 @@ static inline void sema_not_enough_elements_error(SemaContext *context, Expr *in
* Perform analysis for a plain initializer, that is one initializing all fields.
* @return true if analysis succeeds.
*/
static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer)
static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer, bool *no_match_ref)
{
ASSERT(assigned->resolve_status == RESOLVE_DONE);
Expr **elements = initializer->initializer_list;
@@ -198,6 +198,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
// 2. We don't support this actually, but we used to. Maybe we will in the future.
if (elements_needed == 0)
{
if (no_match_ref) goto NO_MATCH;
// Generate a nice error message for zero.
RETURN_SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
}
@@ -222,6 +223,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
// user pinpoint where they put the double elements.
if (i >= elements_needed)
{
if (no_match_ref) goto NO_MATCH;
ASSERT(i < size);
RETURN_SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", elements_needed);
}
@@ -245,6 +247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
}
if (i >= size)
{
if (!no_match_ref) goto NO_MATCH;
sema_not_enough_elements_error(context, initializer, (int)i);
return false;
}
@@ -265,12 +268,13 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
}
if (i >= size)
{
if (!no_match_ref) goto NO_MATCH;
sema_not_enough_elements_error(context, initializer, i);
return false;
}
Expr *element = elements[i];
// 6. We know the required type, so resolve the expression.
if (!sema_analyse_expr_rhs(context, members[i]->type, element, true, NULL, false)) return false;
if (!sema_analyse_expr_rhs(context, members[i]->type, element, true, no_match_ref, false)) return false;
if (member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER)
{
if (!sema_bit_assignment_check(context, element, members[i])) return false;
@@ -302,7 +306,9 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
// 7. Done!
return true;
NO_MATCH:;
*no_match_ref = true;
return false;
}
Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs)
@@ -316,7 +322,7 @@ Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Ex
* @return true if analysis succeeds.
*/
static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened,
Expr *initializer)
Expr *initializer, bool *no_match_ref)
{
Expr **elements = initializer->initializer_list;
bool inferred_len = type_len_is_inferred(flattened);
@@ -338,9 +344,9 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
if (expected_members == 0 && !inferred_len)
{
if (no_match_ref) goto NO_MATCH;
// Generate a nice error message for zero.
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
return false;
RETURN_SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
}
bool optional = false;
@@ -353,12 +359,12 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
Expr *element = elements[i];
if (!inferred_len && i >= expected_members)
{
SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members);
return false;
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members);
}
if (is_vector)
{
if (!sema_analyse_inferred_expr(context, inner_type, element)) return false;
if (!sema_analyse_inferred_expr(context, inner_type, element, no_match_ref)) return false;
Type *element_type = element->type;
Type *element_flat = type_flatten(element_type);
if (element_flat->type_kind == TYPE_VECTOR
@@ -367,8 +373,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
unsigned len = element_flat->array.len;
if (!inferred_len && i + len > expected_members)
{
SEMA_ERROR(element, "Too many elements in initializer when expanding, expected only %d.", expected_members);
return false;
RETURN_SEMA_ERROR(element, "Too many elements in initializer when expanding, expected only %d.", expected_members);
}
Expr *expr_two = expr_new_expr(EXPR_TWO, element);
Decl *decl = decl_new_generated_var(element_type, VARDECL_LOCAL, element->span);
@@ -394,19 +399,19 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
optional = optional || IS_OPTIONAL(element);
continue;
}
if (!cast_implicit(context, element, inner_type, false)) return false;
if (!cast_implicit_checked(context, element, inner_type, false, no_match_ref)) return false;
optional = optional || IS_OPTIONAL(element);
}
else
{
if (!sema_analyse_expr_rhs(context, inner_type, element, true, NULL, false)) return false;
if (!sema_analyse_expr_rhs(context, inner_type, element, true, no_match_ref, false)) return false;
if (inner_is_inferred)
{
if (inferred_element)
{
if (!cast_implicit(context, element, inferred_element, false))
if (!cast_implicit_checked(context, element, inferred_element, false, no_match_ref))
{
SEMA_NOTE(elements[0], "Type inferred from here.");
if (!no_match_ref) SEMA_NOTE(elements[0], "Type inferred from here.");
return false;
}
}
@@ -422,8 +427,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
{
if (!inferred_element)
{
SEMA_ERROR(initializer, "Zero sized elements are not allowed when inferring size.");
return false;
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(initializer, "Zero sized elements are not allowed when inferring size.");
}
inner_type = inferred_element;
}
@@ -441,8 +446,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
if (!inferred_len && expected_members > count)
{
SEMA_ERROR(elements[count - 1], "Too few elements in initializer, %d elements are needed.", expected_members);
return false;
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(elements[count - 1], "Too few elements in initializer, %d elements are needed.", expected_members);
}
initializer->resolve_status = RESOLVE_DONE;
@@ -464,9 +469,12 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
// 7. Done!
return true;
NO_MATCH:;
*no_match_ref = true;
return false;
}
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer)
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer, bool *no_match_ref)
{
Expr **init_list = initializer->initializer_list;
FOREACH(Expr *, element, init_list)
@@ -474,6 +482,11 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E
if (!sema_analyse_expr(context, element)) return false;
if (!sema_cast_const(element))
{
if (no_match_ref)
{
*no_match_ref = true;
return false;
}
RETURN_SEMA_ERROR(element, "An untyped list can only have "
"constant elements, you can try "
"to type the list by prefixing the type and possibly enclosing it in parentheses, "
@@ -488,7 +501,7 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E
}
static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened,
Expr *initializer)
Expr *initializer, bool *no_match_ref)
{
Expr **init_expressions = initializer->designated_init_list;
Type *original = flattened->canonical;
@@ -513,7 +526,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
bitmember_count_without_value += 1;
}
if (!value) RETURN_SEMA_ERROR(expr, "This initializer needs a value.");
if (!sema_analyse_expr_rhs(context, result, value, true, NULL, false)) return false;
if (!sema_analyse_expr_rhs(context, result, value, true, no_match_ref, false)) return false;
if (is_bitmember)
{
if (!sema_bit_assignment_check(context, value, member)) return false;
@@ -525,7 +538,8 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
inner_type = type_no_optional(value->type);
}
}
if (bitmember_count_without_value != 0 && bitmember_count_without_value != vec_size(init_expressions)) {
if (bitmember_count_without_value != 0 && bitmember_count_without_value != vec_size(init_expressions))
{
RETURN_SEMA_ERROR(initializer, "Mixing the omission of initializers is not permitted.");
}
Type *type;
@@ -549,7 +563,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
}
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr)
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr, bool *no_match_ref)
{
// Note at this point this we either have
// EXPR_DESIGNATED_INITIALIZER_LIST
@@ -559,13 +573,13 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass
// 1. Designated initializer is separately evaluated.
if (expr->expr_kind == EXPR_DESIGNATED_INITIALIZER_LIST)
{
return sema_expr_analyse_designated_initializer(context, assigned_type, flattened, expr);
return sema_expr_analyse_designated_initializer(context, assigned_type, flattened, expr,NULL);
}
if (expr->expr_kind == EXPR_CONST)
{
ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER);
return cast_implicit(context, expr, assigned_type, false);
return cast_implicit_checked(context, expr, assigned_type, false, no_match_ref);
}
ASSERT(expr->expr_kind == EXPR_INITIALIZER_LIST);
@@ -583,8 +597,8 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass
{
if (type_len_is_inferred(assigned_type))
{
SEMA_ERROR(expr, "Zero length arrays / vectors are not permitted.");
return false;
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(expr, "Zero length arrays / vectors are not permitted.");
}
if (flattened == type_untypedlist)
{
@@ -598,7 +612,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass
// 4. We might have a complist, because were analyzing $foo = { ... } or similar.
if (assigned_type == type_untypedlist)
{
return sema_expr_analyse_untyped_initializer(context, expr);
return sema_expr_analyse_untyped_initializer(context, expr, no_match_ref);
}
// 5. If not, then we see if we have an array.
@@ -609,11 +623,14 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass
flattened->type_kind == TYPE_SLICE ||
flattened->type_kind == TYPE_VECTOR)
{
return sema_expr_analyse_array_plain_initializer(context, assigned_type, flattened, expr);
return sema_expr_analyse_array_plain_initializer(context, assigned_type, flattened, expr, no_match_ref);
}
expr->type = assigned_type;
return sema_expr_analyse_struct_plain_initializer(context, flattened->decl, expr);
return sema_expr_analyse_struct_plain_initializer(context, flattened->decl, expr, no_match_ref);
NO_MATCH:;
*no_match_ref = true;
return false;
}
/**
@@ -773,7 +790,7 @@ ConstInitializer *sema_merge_bitstruct_const_initializers(ConstInitializer *lhs,
return lhs;
}
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr)
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref)
{
if (!to) to = type_untypedlist;
@@ -801,7 +818,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
case TYPE_INFERRED_ARRAY:
case TYPE_INFERRED_VECTOR:
case TYPE_VECTOR:
return sema_expr_analyse_initializer(context, to, flattened, expr);
return sema_expr_analyse_initializer(context, to, flattened, expr, no_match_ref);
case TYPE_SLICE:
{
if (is_zero_init)
@@ -811,7 +828,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
}
// Resolve this as an inferred array.
Type *type = type_get_inferred_array(flattened->array.base);
if (!sema_expr_analyse_initializer(context, type, type, expr)) return false;
if (!sema_expr_analyse_initializer(context, type, type, expr, no_match_ref)) return false;
if (expr_is_const_initializer(expr))
{
ConstInitializer *init = expr->const_expr.initializer;
@@ -823,6 +840,11 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
expr->resolve_status = RESOLVE_DONE;
expr_insert_addr(expr);
if (!sema_analyse_expr(context, expr)) return false;
if (no_match_ref)
{
if (!cast_explicit_silent(context, expr, to)) goto NO_MATCH;
return true;
}
return cast_explicit(context, expr, to);
}
case TYPE_POINTER:
@@ -832,6 +854,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
expr_rewrite_to_const_zero(expr, to);
return true;
}
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array.");
case TYPE_VOID:
case TYPE_POISONED:
@@ -840,6 +863,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
case TYPE_OPTIONAL:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(expr, "You cannot use %s with an initializer list.", type_quoted_error_string(to));
default:
if (is_zero_init)
@@ -850,7 +874,11 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
}
break;
}
if (no_match_ref) goto NO_MATCH;
RETURN_SEMA_ERROR(expr, "You cannot use %s with a non-empty initializer list.", type_quoted_error_string(to));
NO_MATCH:
*no_match_ref = true;
return false;
}
void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value)

View File

@@ -1494,7 +1494,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
if (variable_type_info)
{
if (!sema_analyse_inferred_expr(context, inferred_type, enumerator)) return SCOPE_POP_ERROR();
if (!sema_analyse_inferred_expr(context, inferred_type, enumerator,NULL)) return SCOPE_POP_ERROR();
}
else
{

View File

@@ -0,0 +1,23 @@
// #target: macos-x64
module test;
struct Test
{
int a;
String b;
}
fn int main()
{
bool a = $defined(Test a = {"hello"});
bool b = $defined((Test){"hello"});
return 0;
}
/* #expect: test.ll
define i32 @main() #0 {
entry:
%a = alloca i8, align 1
%b = alloca i8, align 1
store i8 0, ptr %a, align 1
store i8 0, ptr %b, align 1
ret i32 0
}