From 15662bd32faab90c7b66b17bcf33078d08af5ce3 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 12 Dec 2025 20:57:32 +0100 Subject: [PATCH] Typedefs and structs with inline types supporting lengthof would not work with lengthof #2641. --- releasenotes.md | 1 + src/compiler/sema_expr.c | 19 ++++++++++++++++++- test/unit/regression/lenof.c3 | 13 +++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/releasenotes.md b/releasenotes.md index ecc984f38..58a251c78 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -16,6 +16,7 @@ - Subscripting of constant slices would sometimes be considered non-constant #2635. - Compiler crash when concatenating structs and arrays to an untyped list. - Strings assigned to longer arrays would crash codegen, e.g. `char[10] x = "abcd`. +- Typedefs and structs with inline types supporting lengthof would not work with lengthof #2641. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index ea625c115..6315fd38f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3855,7 +3855,7 @@ RETRY:; { if (len == 0) { - if (missing_ref) return *missing_ref = true, false; + if (missing_ref) return *missing_ref = true, false; RETURN_SEMA_ERROR(index_expr, "Cannot index into a zero size list."); } if (missing_ref) return *missing_ref = true, false; @@ -10888,8 +10888,16 @@ static bool sema_expr_analyse_lenof(SemaContext *context, Expr *expr, bool *miss { return sema_insert_method_call(context, expr, len, inner, NULL, false); } +RETRY: switch (canonical->type_kind) { + case TYPE_UNTYPED_LIST: + ASSERT_SPAN(expr, expr_is_const_untyped_list(expr)); + expr_rewrite_const_int(expr, type_isz, vec_size(expr->const_expr.untyped_list)); + return true; + case TYPE_TYPEDEF: + canonical = canonical->decl->distinct->type; + goto RETRY; case TYPE_ARRAY: case VECTORS: expr_rewrite_const_int(expr, type_isz, canonical->array.len); @@ -10897,6 +10905,15 @@ static bool sema_expr_analyse_lenof(SemaContext *context, Expr *expr, bool *miss case TYPE_SLICE: expr_rewrite_slice_len(expr, inner, type_isz); return true; + case TYPE_STRUCT: + if (canonical->decl->is_substruct) + { + Expr *expr_access = expr_access_inline_member(copy_expr_single(expr), canonical->decl); + *expr = *expr_access; + canonical = expr->type->canonical; + goto RETRY; + } + FALLTHROUGH; default: if (missing_ref) { diff --git a/test/unit/regression/lenof.c3 b/test/unit/regression/lenof.c3 index 0cae821c6..bf622feca 100644 --- a/test/unit/regression/lenof.c3 +++ b/test/unit/regression/lenof.c3 @@ -1,6 +1,19 @@ module regression; import std; +struct Foo +{ + inline int[2] a; +} + +fn void lengthof_aggregates() @test +{ + Foo g; + g.len; + String foo = "abc"; + test::eq(lengthof(g), 2); + test::eq(lengthof(foo), 3); +} fn void lenof_test() @test {