From 52f3948026f18d6ea2ac79adfa910397002b2983 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 23 Sep 2022 10:40:13 +0200 Subject: [PATCH] Cleanup of untyped lists. --- src/compiler/compiler_internal.h | 2 +- src/compiler/sema_decls.c | 2 +- src/compiler/sema_expr.c | 36 ++++++++---- src/compiler/sema_initializers.c | 56 ++++++++----------- src/compiler/types.c | 6 +- src/version.h | 2 +- .../errors/optional_untyped_list.c3 | 10 +++- .../errors/optional_untyped_list.c3 | 10 +++- 8 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7a52915c6..286c5738a 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 06e2b064d..00d732f51 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -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) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e3a15d168..eb504e0d9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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: diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 5a20aca50..fcb39ac80 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -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) diff --git a/src/compiler/types.c b/src/compiler/types.c index 23ef0e444..2712529f3 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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); diff --git a/src/version.h b/src/version.h index c01d9a41c..cd9337347 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.55" \ No newline at end of file +#define COMPILER_VERSION "0.3.56" \ No newline at end of file diff --git a/test/test_suite/errors/optional_untyped_list.c3 b/test/test_suite/errors/optional_untyped_list.c3 index 3af5e5a82..c4c2f9581 100644 --- a/test/test_suite/errors/optional_untyped_list.c3 +++ b/test/test_suite/errors/optional_untyped_list.c3 @@ -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() diff --git a/test/test_suite2/errors/optional_untyped_list.c3 b/test/test_suite2/errors/optional_untyped_list.c3 index 3af5e5a82..c4c2f9581 100644 --- a/test/test_suite2/errors/optional_untyped_list.c3 +++ b/test/test_suite2/errors/optional_untyped_list.c3 @@ -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()