mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Cleanup of untyped lists.
This commit is contained in:
committed by
Christoffer Lerno
parent
46c182f3d1
commit
52f3948026
@@ -1763,7 +1763,7 @@ extern Type *type_iptr, *type_uptr, *type_iptrdiff, *type_uptrdiff;
|
||||
extern Type *type_u128, *type_i128;
|
||||
extern Type *type_typeid, *type_anyerr, *type_typeinfo;
|
||||
extern Type *type_any;
|
||||
extern Type *type_complist;
|
||||
extern Type *type_untypedlist;
|
||||
extern Type *type_anyfail;
|
||||
extern Type *type_cint;
|
||||
extern Type *type_cuint;
|
||||
|
||||
@@ -2092,7 +2092,7 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
|
||||
SEMA_ERROR(first_param, "The first parameter must be a regular or ref (&) type.");
|
||||
return false;
|
||||
}
|
||||
return unit_add_method_like(context->unit, parent_type, decl);
|
||||
return unit_add_method_like(context->unit, parent_type->canonical, decl);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
|
||||
@@ -1021,6 +1021,11 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
|
||||
else if (variadic == VARIADIC_ANY)
|
||||
{
|
||||
if (!sema_analyse_expr(context, arg)) return false;
|
||||
if (arg->type == type_untypedlist)
|
||||
{
|
||||
SEMA_ERROR(arg, "An untyped list cannot be passed as a variadic argument.");
|
||||
return false;
|
||||
}
|
||||
expr_insert_addr(arg);
|
||||
}
|
||||
vec_add(*varargs_ref, arg);
|
||||
@@ -1276,6 +1281,11 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
|
||||
if (!sema_analyse_expr_lvalue(context, arg)) return false;
|
||||
if (!sema_expr_check_assign(context, arg)) return false;
|
||||
if (!sema_call_check_inout_param_match(context, param, arg)) return false;
|
||||
if (arg->type == type_untypedlist)
|
||||
{
|
||||
SEMA_ERROR(arg, "An untyped list cannot be passed by reference.");
|
||||
return false;
|
||||
}
|
||||
if (type && type->canonical != arg->type->canonical)
|
||||
{
|
||||
SEMA_ERROR(arg, "'%s' cannot be implicitly cast to '%s'.", type_to_error_string(arg->type), type_to_error_string(type));
|
||||
@@ -1297,7 +1307,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
|
||||
// foo
|
||||
if (!sema_analyse_expr_rhs(context, type, arg, true)) return false;
|
||||
if (IS_OPTIONAL(arg)) *failable = true;
|
||||
if (arg->type == type_complist)
|
||||
if (arg->type == type_untypedlist)
|
||||
{
|
||||
SEMA_ERROR(arg, "An untyped list can only be passed as a compile time parameter.");
|
||||
return false;
|
||||
@@ -2171,7 +2181,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
|
||||
int64_t index_value = -1;
|
||||
bool start_from_end = expr->subscript_expr.range.start_from_end;
|
||||
if (expr_is_const_int(index) && (current_type->type_kind == TYPE_ARRAY || current_type == type_complist))
|
||||
if (expr_is_const_int(index) && (current_type->type_kind == TYPE_ARRAY || current_type == type_untypedlist))
|
||||
{
|
||||
// 4c. And that it's in range.
|
||||
if (int_is_neg(index->const_expr.ixx))
|
||||
@@ -2179,9 +2189,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
SEMA_ERROR(index, "The index may not be negative.");
|
||||
return false;
|
||||
}
|
||||
int64_t size = current_type == type_complist ? vec_size(current_expr->initializer_list) : current_type->array.len;
|
||||
int64_t size = current_type == type_untypedlist ? vec_size(current_expr->const_expr.list->init_array_full) : current_type->array.len;
|
||||
assert(size >= 0 && "Unexpected overflow");
|
||||
if (!int_fits(index->const_expr.ixx, TYPE_I64))
|
||||
if (!int_fits(index->const_expr.ixx, TYPE_I64) || size == 0)
|
||||
{
|
||||
SEMA_ERROR(index, "The index is out of range.", size);
|
||||
return false;
|
||||
@@ -2215,7 +2225,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
}
|
||||
}
|
||||
// 4. If we are indexing into a complist
|
||||
if (current_type == type_complist)
|
||||
if (current_type == type_untypedlist)
|
||||
{
|
||||
if (is_addr)
|
||||
{
|
||||
@@ -2225,7 +2235,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
// 4a. This may either be an initializer list or a CT value
|
||||
while (current_expr->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
|
||||
|
||||
assert(current_expr->expr_kind == EXPR_INITIALIZER_LIST);
|
||||
assert(expr_is_const_list(current_expr));
|
||||
|
||||
// 4b. Now we need to check that we actually have a valid type.
|
||||
if (index_value < 0)
|
||||
@@ -2233,10 +2243,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
SEMA_ERROR(index, "To subscript a compile time list a compile time integer index is needed.");
|
||||
return false;
|
||||
}
|
||||
Expr *indexed_expr = current_expr->initializer_list[index_value];
|
||||
if (!sema_cast_rvalue(context, indexed_expr)) return false;
|
||||
expr_replace(expr, indexed_expr);
|
||||
return true;
|
||||
return expr_rewrite_to_const_initializer_index(type_untypedlist, current_expr->const_expr.list, expr, index_value);
|
||||
}
|
||||
|
||||
if (!sema_cast_rvalue(context, current_expr)) return false;
|
||||
@@ -3487,7 +3494,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr)
|
||||
SEMA_ERROR(type_info, "Casting to a failable type is not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (inner->type == type_complist)
|
||||
if (inner->type == type_untypedlist)
|
||||
{
|
||||
// We don't support: (Foo)(x > 0 ? { 1, 2 } : { 3, 4 })
|
||||
// just write this: x > 0 ? Foo { 1, 2 } : Foo { 3, 4 }
|
||||
@@ -5110,6 +5117,11 @@ static inline bool sema_expr_analyse_taddr(SemaContext *context, Expr *expr)
|
||||
Expr *inner = expr->unary_expr.expr;
|
||||
if (!sema_analyse_expr(context, inner)) return false;
|
||||
|
||||
if (inner->type == type_untypedlist)
|
||||
{
|
||||
SEMA_ERROR(expr, "It is not possible to take the address of an untyped list.");
|
||||
return false;
|
||||
}
|
||||
// 2. The type is the resulting type of the expression.
|
||||
expr->type = type_get_ptr_recurse(inner->type);
|
||||
return true;
|
||||
@@ -6448,7 +6460,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
return sema_expr_analyse_access(context, expr);
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
return sema_expr_analyse_initializer_list(context, type_complist, expr);
|
||||
return sema_expr_analyse_initializer_list(context, type_untypedlist, expr);
|
||||
case EXPR_CAST:
|
||||
return sema_expr_analyse_cast(context, expr);
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
|
||||
@@ -11,7 +11,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
|
||||
static inline void sema_not_enough_elements_error(Expr *initializer, int element);
|
||||
static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *external_type, Type *assigned, Expr *expr);
|
||||
static void sema_create_const_initializer_value(ConstInitializer *const_init, Expr *value);
|
||||
static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer);
|
||||
static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer);
|
||||
static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **elements, unsigned *index);
|
||||
static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, Expr *expr, MemberIndex *max_index, Decl **member_ptr);
|
||||
INLINE bool sema_initializer_list_is_empty(Expr *value);
|
||||
@@ -282,40 +282,30 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex
|
||||
|
||||
static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer)
|
||||
{
|
||||
Expr **elements = initializer->initializer_list;
|
||||
|
||||
Type *element_type = NULL;
|
||||
bool no_common_elements = false;
|
||||
unsigned element_count = vec_size(elements);
|
||||
bool is_const = true;
|
||||
Expr *failable_expr = NULL;
|
||||
for (unsigned i = 0; i < element_count; i++)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
ConstInitializer **inits = NULL;
|
||||
FOREACH_BEGIN(Expr *element, initializer->initializer_list)
|
||||
if (!sema_analyse_expr(context, element)) return false;
|
||||
if (is_const && element->expr_kind != EXPR_CONST) is_const = false;
|
||||
if (!failable_expr && IS_OPTIONAL(element)) failable_expr = element;
|
||||
if (no_common_elements) continue;
|
||||
Type *current_element_type = type_no_optional(element->type);
|
||||
if (element_type == NULL)
|
||||
if (!expr_is_const(element))
|
||||
{
|
||||
element_type = element->type;
|
||||
continue;
|
||||
SEMA_ERROR(element, "An untyped list can only have constant elements, you can try to type the list by prefixing the type, e.g. 'int[2] { a, b }'.");
|
||||
return false;
|
||||
}
|
||||
element_type = type_find_max_type(element->type, current_element_type);
|
||||
if (!element_type) no_common_elements = true;
|
||||
}
|
||||
if (no_common_elements && failable_expr)
|
||||
ConstInitializer *init = CALLOCS(ConstInitializer);
|
||||
sema_create_const_initializer_value(init, element);
|
||||
vec_add(inits, init);
|
||||
FOREACH_END();
|
||||
ConstInitializer *untyped_list = CALLOCS(ConstInitializer);
|
||||
initializer->expr_kind = EXPR_CONST;
|
||||
initializer->const_expr = (ExprConst) { .const_kind = CONST_LIST, .list = untyped_list };
|
||||
untyped_list->type = type_untypedlist;
|
||||
initializer->type = type_untypedlist;
|
||||
if (!inits)
|
||||
{
|
||||
SEMA_ERROR(failable_expr, "An untyped initializer can't have failable values.");
|
||||
return false;
|
||||
}
|
||||
if (no_common_elements || is_const)
|
||||
{
|
||||
initializer->type = type_complist;
|
||||
untyped_list->kind = CONST_INIT_ZERO;
|
||||
return true;
|
||||
}
|
||||
initializer->type = type_add_optional(type_get_array(element_type, element_count), failable_expr != NULL);
|
||||
untyped_list->kind = CONST_INIT_ARRAY_FULL;
|
||||
untyped_list->init_array_full = inits;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -351,7 +341,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
|
||||
if (expr_is_constant_eval(initializer, context->current_function ? CONSTANT_EVAL_LOCAL_INIT : CONSTANT_EVAL_GLOBAL_INIT))
|
||||
{
|
||||
ConstInitializer *const_init = MALLOCS(ConstInitializer);
|
||||
sema_create_const_initializer(const_init, initializer);
|
||||
sema_create_const_initializer_from_designated_init(const_init, initializer);
|
||||
expr_rewrite_const_list(initializer, initializer->type, const_init);
|
||||
}
|
||||
return true;
|
||||
@@ -408,7 +398,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
|
||||
expr->type = external_type;
|
||||
|
||||
// 6. We might have a complist, because were analyzing $foo = { ... } or similar.
|
||||
if (external_type == type_complist)
|
||||
if (external_type == type_untypedlist)
|
||||
{
|
||||
return sema_expr_analyse_untyped_initializer(context, expr);
|
||||
}
|
||||
@@ -429,7 +419,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext
|
||||
/**
|
||||
* Create a const initializer.
|
||||
*/
|
||||
static void sema_create_const_initializer(ConstInitializer *const_init, Expr *initializer)
|
||||
static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer)
|
||||
{
|
||||
const_init->kind = CONST_INIT_ZERO;
|
||||
// Flatten the type since the external type might be typedef or a distinct type.
|
||||
@@ -448,7 +438,7 @@ static void sema_create_const_initializer(ConstInitializer *const_init, Expr *in
|
||||
|
||||
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr)
|
||||
{
|
||||
if (!to) to = type_complist;
|
||||
if (!to) to = type_untypedlist;
|
||||
assert(to);
|
||||
Type *assigned = type_flatten(to);
|
||||
switch (assigned->type_kind)
|
||||
|
||||
@@ -10,7 +10,7 @@ static struct
|
||||
Type u8, u16, u32, u64, u128;
|
||||
Type f16, f32, f64, f128, fxx;
|
||||
Type usz, isz, uptr, iptr, uptrdiff, iptrdiff;
|
||||
Type voidstar, typeid, anyerr, typeinfo, ctlist;
|
||||
Type voidstar, typeid, anyerr, typeinfo, untyped_list;
|
||||
Type any, anyfail;
|
||||
} t;
|
||||
|
||||
@@ -41,7 +41,7 @@ Type *type_uptr = &t.uptr;
|
||||
Type *type_uptrdiff = &t.uptrdiff;
|
||||
Type *type_usize = &t.usz;
|
||||
Type *type_anyerr = &t.anyerr;
|
||||
Type *type_complist = &t.ctlist;
|
||||
Type *type_untypedlist = &t.untyped_list;
|
||||
Type *type_anyfail = &t.anyfail;
|
||||
Type *type_chars = NULL;
|
||||
|
||||
@@ -1351,7 +1351,7 @@ void type_setup(PlatformTarget *target)
|
||||
type_init_int("void", &t.u0, TYPE_VOID, BITS8);
|
||||
|
||||
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
|
||||
type_create("complist", &t.ctlist, TYPE_UNTYPED_LIST, 1, 1, 1);
|
||||
type_create("untyped_list", &t.untyped_list, TYPE_UNTYPED_LIST, 1, 1, 1);
|
||||
type_create("void!", &t.anyfail, TYPE_FAILABLE_ANY, 1, 1, 1);
|
||||
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
|
||||
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.55"
|
||||
#define COMPILER_VERSION "0.3.56"
|
||||
@@ -11,10 +11,16 @@ fault MyErr
|
||||
|
||||
extern fn int printf(char *c, ...);
|
||||
|
||||
fn void main()
|
||||
fn void foo()
|
||||
{
|
||||
int z = 2;
|
||||
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
|
||||
}
|
||||
|
||||
fn void foo2()
|
||||
{
|
||||
int! z = 2;
|
||||
Foo*! w = &&{ z, 0 }; // #error: A failable 'int[2]*!' cannot be converted to 'Foo*'
|
||||
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
|
||||
}
|
||||
|
||||
fn void test()
|
||||
|
||||
@@ -11,10 +11,16 @@ fault MyErr
|
||||
|
||||
extern fn int printf(char *c, ...);
|
||||
|
||||
fn void main()
|
||||
fn void foo()
|
||||
{
|
||||
int z = 2;
|
||||
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
|
||||
}
|
||||
|
||||
fn void foo2()
|
||||
{
|
||||
int! z = 2;
|
||||
Foo*! w = &&{ z, 0 }; // #error: A failable 'int[2]*!' cannot be converted to 'Foo*'
|
||||
Foo*! w = &&{ z, 0 }; // #error: An untyped list can only have constant elements
|
||||
}
|
||||
|
||||
fn void test()
|
||||
|
||||
Reference in New Issue
Block a user