From 8a9edc02b6646b0a2369a226cb5435e51408b09d Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 11 Jan 2025 03:23:03 +0100 Subject: [PATCH] Fix bug preventing compile time slices from being iterated over with `$foreach`. --- releasenotes.md | 1 + src/compiler/sema_stmts.c | 87 +++++++++++-------- .../compile_time/compile_time_utf32.c3 | 4 + 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index 04d0b6f93..896474bbb 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -73,6 +73,7 @@ - Change ordering to simplify adding methods to type in conditional modules. - `#foo` style arguments were not type checked when given a type. #1790 - Bug when using +++ on value build a slice or array: the rhs cast was not done. +- Fix bug preventing compile time slices from being iterated over with `$foreach`. ### Stdlib changes - Increase BitWriter.write_bits limit up to 32 bits. diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 8decd6faa..667327cf1 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2672,54 +2672,70 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state unsigned ct_context = sema_context_push_ct_stack(context); Expr *collection = exprptr(statement->ct_foreach_stmt.expr); if (!sema_analyse_ct_expr(context, collection)) return false; - if (!expr_is_const_untyped_list(collection) && !expr_is_const_initializer(collection) - && !expr_is_const_string(collection) && !expr_is_const_bytes(collection)) - { - SEMA_ERROR(collection, "Expected a list to iterate over"); - goto FAILED; - } + if (!expr_is_const(collection)) goto FAILED_NO_LIST; unsigned count; ConstInitializer *initializer = NULL; Expr **expressions = NULL; Type *const_list_type = NULL; const char *bytes = NULL; Type *bytes_type; - if (expr_is_const_initializer(collection)) + switch (collection->const_expr.const_kind) { - initializer = collection->const_expr.initializer; - ConstInitType init_type = initializer->kind; - const_list_type = type_flatten(collection->type); - if (const_list_type->type_kind == TYPE_ARRAY || const_list_type->type_kind == TYPE_VECTOR) - { - count = const_list_type->array.len; - } - else - { - // Empty list - if (init_type == CONST_INIT_ZERO) + case CONST_FLOAT: + case CONST_INTEGER: + case CONST_BOOL: + case CONST_ENUM: + case CONST_ERR: + case CONST_POINTER: + case CONST_TYPEID: + case CONST_REF: + case CONST_MEMBER: + goto FAILED_NO_LIST; + case CONST_SLICE: + if (!collection->const_expr.slice_init) { sema_context_pop_ct_stack(context, ct_context); statement->ast_kind = AST_NOP_STMT; return true; } - if (init_type != CONST_INIT_ARRAY_FULL) + initializer = collection->const_expr.slice_init; + goto INITIALIZER; + case CONST_INITIALIZER: + initializer = collection->const_expr.initializer; + INITIALIZER:; + ConstInitType init_type = initializer->kind; + const_list_type = type_flatten(collection->type); + if (const_list_type->type_kind == TYPE_ARRAY || const_list_type->type_kind == TYPE_VECTOR) { - SEMA_ERROR(collection, "Only regular arrays are allowed here."); - goto FAILED; + count = const_list_type->array.len; } - count = vec_size(initializer->init_array_full); - } - } - else if (expr_is_const_untyped_list(collection)) - { - expressions = collection->const_expr.untyped_list; - count = vec_size(expressions); - } - else - { - bytes = collection->const_expr.bytes.ptr; - count = collection->const_expr.bytes.len; - bytes_type = type_get_indexed_type(collection->type); + else + { + // Empty list + if (init_type == CONST_INIT_ZERO) + { + sema_context_pop_ct_stack(context, ct_context); + statement->ast_kind = AST_NOP_STMT; + return true; + } + if (init_type != CONST_INIT_ARRAY_FULL) + { + SEMA_ERROR(collection, "Only regular arrays are allowed here."); + goto FAILED; + } + count = vec_size(initializer->init_array_full); + } + break; + case CONST_UNTYPED_LIST: + expressions = collection->const_expr.untyped_list; + count = vec_size(expressions); + break; + case CONST_BYTES: + case CONST_STRING: + bytes = collection->const_expr.bytes.ptr; + count = collection->const_expr.bytes.len; + bytes_type = type_get_indexed_type(collection->type); + break; } Decl *index = declptrzero(statement->ct_foreach_stmt.index); @@ -2771,6 +2787,9 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state statement->ast_kind = AST_COMPOUND_STMT; statement->compound_stmt = (AstCompoundStmt) { .first_stmt = start }; return true; +FAILED_NO_LIST: + SEMA_ERROR(collection, "Expected a list to iterate over, but this was a non-list expression of type %s.", + type_quoted_error_string(collection->type)); FAILED: sema_context_pop_ct_stack(context, ct_context); return false; diff --git a/test/test_suite/compile_time/compile_time_utf32.c3 b/test/test_suite/compile_time/compile_time_utf32.c3 index e8dbd6db0..0d5ea9501 100644 --- a/test/test_suite/compile_time/compile_time_utf32.c3 +++ b/test/test_suite/compile_time/compile_time_utf32.c3 @@ -61,6 +61,10 @@ macro Char32[] conv_utf8_to_char32($source) @const import std; fn void main(String[] args) { + Char32[] $chars = conv_utf8_to_char32("🐉 eats 🌎"); + $foreach($v : $chars) + io::printn($v); + $endforeach Char32[] chars = conv_utf8_to_char32 ("🐉 eats 🌎"); io::printn(chars); foreach (c : chars)