Const initializer refactoring. Improve error on "Foo![]" #1477

This commit is contained in:
Christoffer Lerno
2024-09-24 18:04:39 +02:00
parent d4832812ef
commit 01b087238a
7 changed files with 144 additions and 40 deletions

View File

@@ -3202,6 +3202,7 @@ bool const_init_local_init_may_be_global(ConstInitializer *init);
ConstInitializer *const_init_new_zero(Type *type);
ConstInitializer *const_init_new_value(Expr *value);
ConstInitializer *const_init_new_array(Type *type, ConstInitializer **elements);
ConstInitializer *const_init_new_struct(Type *type, Expr **elements);
ConstInitializer *const_init_new_array_full(Type *type, ConstInitializer **elements);
ConstInitializer *const_init_new_zero_array_value(Type *type, ArrayIndex index);
void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value);

View File

@@ -6,6 +6,7 @@
#include "parser_internal.h"
typedef Expr *(*ParseFn)(ParseContext *context, Expr *);
static Expr *parse_subscript_expr(ParseContext *c, Expr *left);
typedef struct
{
@@ -110,11 +111,10 @@ static Expr *parse_rethrow_expr(ParseContext *c, Expr *left_side)
{
assert(expr_ok(left_side));
advance_and_verify(c, TOKEN_BANG);
Expr *expr_ternary = expr_new_expr(EXPR_RETHROW, left_side);
expr_ternary->rethrow_expr.inner = left_side;
RANGE_EXTEND_PREV(expr_ternary);
return expr_ternary;
Expr *expr = expr_new_expr(EXPR_RETHROW, left_side);
expr->rethrow_expr.inner = left_side;
RANGE_EXTEND_PREV(expr);
return expr;
}
/**

View File

@@ -652,6 +652,68 @@ TypeInfo *parse_type(ParseContext *c)
return parse_type_with_base(c, base);
}
typedef enum DiscardedSubscript_
{
DISCARD_ERR,
DISCARD_WILDCARD,
DISCARD_SLICE,
DISCARD_EXPR
} DiscardedSubscript;
static DiscardedSubscript parse_discarded_subscript(ParseContext *c, TokenType end)
{
if (end == TOKEN_RBRACKET && try_consume(c, end)) return DISCARD_SLICE;
if (try_consume(c, TOKEN_STAR))
{
CONSUME_OR_RET(end, DISCARD_ERR);
return DISCARD_WILDCARD;
}
ASSIGN_EXPR_OR_RET(Expr *ex, parse_expr(c), DISCARD_ERR);
(void)ex;
CONSUME_OR_RET(end, DISCARD_ERR);
return DISCARD_EXPR;
}
INLINE bool parse_rethrow_bracket(ParseContext *c, SourceSpan start)
{
if (try_consume(c, TOKEN_LBRACKET))
{
switch (parse_discarded_subscript(c, TOKEN_RBRACKET))
{
case DISCARD_ERR:
return false;
case DISCARD_WILDCARD:
print_error_at(extend_span_with_token(start, c->prev_span), "When declaring an optional array, the '[*]' should appear before the '!', e.g 'Foo[*]!'.");
return false;
case DISCARD_SLICE:
print_error_at(extend_span_with_token(start, c->prev_span),
"When declaring an optional slice the '[]' should appear before the '!', e.g 'Foo[]!'.");
return false;
case DISCARD_EXPR:
print_error_at(extend_span_with_token(start, c->prev_span), "When declaring an optional array, the '[...]' should appear before the '!', e.g 'Foo[4]!'.");
return false;
}
UNREACHABLE
}
if (try_consume(c, TOKEN_LVEC))
{
switch (parse_discarded_subscript(c, TOKEN_RVEC))
{
case DISCARD_ERR:
return false;
case DISCARD_WILDCARD:
print_error_at(extend_span_with_token(start, c->span), "When declaring an optional vector, the '[<*>]' should appear before the '!', e.g 'Foo[<*>]!'.");
return false;
case DISCARD_SLICE:
UNREACHABLE
case DISCARD_EXPR:
print_error_at(extend_span_with_token(start, c->span), "When declaring an optional vector, the '[<...>]' should appear before the '!', e.g 'Foo[<4>]!'.");
return false;
}
UNREACHABLE
}
return true;
}
/**
* optional_type ::= type '!'?
* @param c
@@ -663,6 +725,7 @@ TypeInfo *parse_optional_type(ParseContext *c)
ASSIGN_TYPE_OR_RET(info, parse_type_with_base(c, info), poisoned_type_info);
if (try_consume(c, TOKEN_BANG))
{
if (!parse_rethrow_bracket(c, info->span)) return poisoned_type_info;
assert(!info->optional);
info->optional = true;
if (info->resolve_status == RESOLVE_DONE)

View File

@@ -3707,7 +3707,7 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl)
{
if (!sema_analyse_expr(context, init)) goto FAIL;
// Check it is constant.
if (!sema_cast_const(init))
if (!expr_is_runtime_const(init))
{
SEMA_ERROR(init, "Expected a constant expression assigned to %s.", decl->name);
goto FAIL;

View File

@@ -3909,7 +3909,9 @@ static inline bool sema_create_const_paramsof(SemaContext *context, Expr *expr,
Decl *decl = sig->params[i];
Expr *name_expr = expr_new_const_string(span, decl->name ? decl->name : "");
Expr *type_expr = expr_new_const_typeid(span, decl->type->canonical);
Expr *values[] = { name_expr, type_expr };
Expr **values = NULL;
vec_add(values, name_expr);
vec_add(values, type_expr);
Expr *struct_value = sema_create_struct_from_expressions(type_reflected_param->decl, expr->span, values);
vec_add(param_exprs, struct_value);
}

View File

@@ -103,6 +103,42 @@ ConstInitializer *const_init_new_array_full(Type *type, ConstInitializer **eleme
return init;
}
ConstInitializer *const_init_new_struct(Type *type, Expr **elements)
{
ConstInitializer *init = CALLOCS(ConstInitializer);
init->kind = CONST_INIT_STRUCT;
init->type = type_flatten(type);
ConstInitializer **values = NULL;
FOREACH(Expr *, expr, elements)
{
if (expr_is_const_initializer(expr))
{
vec_add(values, expr->const_expr.initializer);
continue;
}
vec_add(values, const_init_new_value(expr));
}
init->init_struct = values;
return init;
}
ConstInitializer *const_init_new_union(Type *type, ArrayIndex index, Expr *value)
{
ConstInitializer *init = CALLOCS(ConstInitializer);
init->type = type_flatten(type);
init->kind = CONST_INIT_UNION;
init->init_union.index = index;
if (expr_is_const_initializer(value))
{
init->init_union.element = value->const_expr.initializer;
}
else
{
init->init_union.element = const_init_new_value(value);
}
return init;
}
ConstInitializer *const_init_new_zero_array_value(Type *type, ArrayIndex index)
{
ConstInitializer *init = CALLOCS(ConstInitializer);
@@ -246,35 +282,17 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
{
bool is_union = type_flatten(initializer->type)->type_kind == TYPE_UNION;
assert(!is_union || vec_size(elements) == 1);
ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = is_union ? CONST_INIT_UNION : CONST_INIT_STRUCT;
const_init->type = type_flatten(initializer->type);
ConstInitializer *init;
if (is_union)
{
Expr *expr = elements[0];
const_init->init_union.index = 0;
if (expr_is_const_initializer(expr))
{
const_init->init_union.element = expr->const_expr.initializer;
}
else
{
const_init->init_union.element = const_init_new_value(expr);
}
expr_rewrite_const_initializer(initializer, initializer->type, const_init);
return true;
init = const_init_new_union(initializer->type, 0, expr);
}
const_init->init_struct = NULL;
FOREACH(Expr *, expr, elements)
else
{
if (expr_is_const_initializer(expr))
{
vec_add(const_init->init_struct, expr->const_expr.initializer);
continue;
}
vec_add(const_init->init_struct, const_init_new_value(expr));
init = const_init_new_struct(initializer->type, elements);
}
expr_rewrite_const_initializer(initializer, initializer->type, const_init);
expr_rewrite_const_initializer(initializer, initializer->type, init);
}
// 7. Done!
@@ -284,15 +302,8 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte
Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs)
{
ConstInitializer *init = CALLOCS(ConstInitializer);
init->kind = CONST_INIT_STRUCT;
init->type = struct_decl->type;
unsigned params = vec_size(struct_decl->strukt.members);
for (unsigned i = 0; i < params; i++)
{
vec_add(init->init_struct, const_init_new_value(exprs[i]));
}
return expr_new_const_initializer(span, struct_decl->type, init);
return expr_new_const_initializer(span, struct_decl->type,
const_init_new_struct(struct_decl->type, exprs));
}
/**
@@ -899,7 +910,7 @@ static inline void sema_update_const_initializer_with_designator_struct(ConstIni
assert(const_init->kind == CONST_INIT_STRUCT);
// Find the ConstInitializer to change
ConstInitializer *sub_element = const_init->init_struct[element->index];
ConstInitializer *sub_element = const_init->init_struct[element->index]; // NOLINT
// If this isn't the last element, we recurse.
if (!is_last_path_element)

View File

@@ -0,0 +1,27 @@
import std::io;
fn void! test1()
{
CallbackResult![] result = 123; // #error: Foo[]!
}
fn void! test2()
{
CallbackResult![*] result = 123; // #error: Foo[*]!
}
fn void! test3()
{
CallbackResult![4 + 5] result = 123; // #error: Foo[4]!
}
fn void! test4()
{
CallbackResult![<*>] result = 123; // #error: Foo[<*>]!
}
fn void! test5()
{
CallbackResult![<FOO>] result = 123; // #error: Foo[<4>]!
}