mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Const initializer refactoring. Improve error on "Foo![]" #1477
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
27
test/test_suite/errors/type_optional_declaration_order.c3
Normal file
27
test/test_suite/errors/type_optional_declaration_order.c3
Normal 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>]!
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user