diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 2163d07b9..0c740a3dc 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -54,6 +54,32 @@ fn List* List.temp_init(&self, usz initial_capacity = 16) return self.new_init(initial_capacity, allocator::temp()) @inline; } +/** + * Initialize a new list with an array. + * + * @param [in] values `The values to initialize the list with.` + * @require self.size == 0 "The List must be empty" + **/ +fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap()) +{ + self.new_init(values.len, allocator) @inline; + self.add_array(values) @inline; + return self; +} + +/** + * Initialize a temporary list with an array. + * + * @param [in] values `The values to initialize the list with.` + * @require self.size == 0 "The List must be empty" + **/ +fn List* List.temp_init_with_array(&self, Type[] values) +{ + self.temp_init(values.len) @inline; + self.add_array(values) @inline; + return self; +} + /** * @require self.size == 0 "The List must be empty" **/ @@ -192,6 +218,12 @@ fn Type[] List.array_view(&self) return self.entries[:self.size]; } +/** + * Add the values of an array to this list. + * + * @param [in] array + * @ensure self.size >= array.len + **/ fn void List.add_array(&self, Type[] array) { if (!array.len) return; diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 3fb4c9834..014af8c2c 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -384,7 +384,7 @@ File stderr_file; fn void putchar(char c) @inline { - (void)stdout_file.putc(c); + (void)stdout_file.write_byte(c); } fn File* stdout() diff --git a/lib/std/io/os/temp_directory.c3 b/lib/std/io/os/temp_directory.c3 index 766876727..0e0d06794 100644 --- a/lib/std/io/os/temp_directory.c3 +++ b/lib/std/io/os/temp_directory.c3 @@ -24,6 +24,7 @@ fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env: } module std::io::os @if(env::NO_LIBC); +import std::io::path; macro Path! native_temp_directory(Allocator allocator = allocator::heap()) { diff --git a/lib/std/math/math_nolibc/__tan.c3 b/lib/std/math/math_nolibc/__tan.c3 index a44cbc193..2dead46f9 100644 --- a/lib/std/math/math_nolibc/__tan.c3 +++ b/lib/std/math/math_nolibc/__tan.c3 @@ -60,7 +60,7 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip w = x + r; if (big) { - s = 1 - 2 * odd; + s = (double)(1 - 2 * odd); v = s - 2.0 * (x + (r - w*w/(w + s))); return sign ? -v : v; } diff --git a/lib/std/math/math_nolibc/rempi.c3 b/lib/std/math/math_nolibc/rempi.c3 index 7ecf8ab98..8e5715779 100644 --- a/lib/std/math/math_nolibc/rempi.c3 +++ b/lib/std/math/math_nolibc/rempi.c3 @@ -63,7 +63,7 @@ fn int __rem_pio2f(float x, double *y) if (ix >= 0x7f800000) { // x is inf or NaN */ - *y = x-x; + *y = x - (double)x; return 0; } /* scale x into [2^23, 2^24-1] */ diff --git a/releasenotes.md b/releasenotes.md index 09a1b9d07..384047d26 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -22,6 +22,7 @@ - Macro `$case` statements now pick the first match and does not evaluate the rest. - `manifest.json` is now checked for incorrect keys. - Added `--list-manifest-properties` to list the available properties in `manifest.json`. +- Indexing into a constant array / struct now works at compile time. ### Fixes - Error with unsigned compare in `@ensure` when early returning 0 #1207. @@ -45,6 +46,8 @@ - Bitstructs in structs would not be correctly be handled in some cases. - Fix problem where a $$FUNC would return "" when evaluated for a static in a function #1236. - `ordinal` is no longer a valid associated value name for enums. +- Constants defined by indexing into another constant could fail codegen. +- Stdlib nolibc code bugs fixed. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. @@ -55,6 +58,7 @@ - Updated sorting API. - Insertion sort and counting sort added. - Added missing `mem` and `mem::allocator` functions for aligned allocations. +- Added `new_init_with_array` and `temp_init_with_array` for List. ## 0.6.0 Change list diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index a0e9e4f69..014c2d71b 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2252,6 +2252,7 @@ bool expr_is_simple(Expr *expr, bool to_float); bool expr_is_pure(Expr *expr); bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); bool expr_is_compile_time(Expr *ast); +bool range_is_const(Range *range); Expr *expr_generate_decl(Decl *decl, Expr *assign); void expr_insert_addr(Expr *original); void expr_rewrite_insert_deref(Expr *original); @@ -2347,6 +2348,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr, CondResult *result bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref); ArrayIndex sema_get_initializer_const_array_size(SemaContext *context, Expr *initializer, bool *may_be_array, bool *is_const_size); bool sema_analyse_expr(SemaContext *context, Expr *expr); +bool sema_cast_const(Expr *expr); bool sema_expr_check_discard(SemaContext *context, Expr *expr); bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr); diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 65df9bb72..5e4338434 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -268,7 +268,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) if (expr->slice_expr.end && !exprid_is_constant_eval(expr->slice_expr.end, CONSTANT_EVAL_FOLDABLE)) return false; return exprid_is_constant_eval(expr->slice_expr.expr, eval_kind);*/ case EXPR_SUBSCRIPT: - if (!exprid_is_constant_eval(expr->subscript_expr.range.start, eval_kind)) return false; + if (!range_is_const(&expr->subscript_expr.range)) return false; expr = exprptr(expr->subscript_expr.expr); goto RETRY; case EXPR_SUBSCRIPT_ADDR: diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 6665a4f2b..4f31046a6 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -71,7 +71,7 @@ static bool sema_check_builtin_args_const(SemaContext *context, Expr **args, siz { for (size_t i = 0; i < arg_len; i++) { - if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "Expected a compile time constant value for this argument."); + if (!sema_cast_const(args[i])) RETURN_SEMA_ERROR(args[i], "Expected a compile time constant value for this argument."); } return true; } @@ -238,11 +238,9 @@ static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr) for (int i = 3; i < 5; i++) { if (!sema_analyse_expr_rhs(context, type_bool, args[i], false, NULL)) return false; - if (!expr_is_const(args[i])) + if (!sema_cast_const(args[i])) { - SEMA_ERROR(args[i], "Expected a constant boolean value."); - return false; - } + RETURN_SEMA_ERROR(args[i], "Expected a constant boolean value.");} } for (int i = 5; i < 7; i++) { @@ -579,7 +577,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { RETURN_SEMA_ERROR(args[2], "Expected a 'double', but was %s.", type_quoted_error_string(args[2]->type)); } - if (!expr_is_const(args[2])) + if (!sema_cast_const(args[2])) { RETURN_SEMA_ERROR(args[2], "This value must be a constant."); } @@ -640,7 +638,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER, BA_INTEGER}, 3)) return false; for (unsigned i = 1; i < 3; i++) { - if (!expr_is_const(args[i])) RETURN_SEMA_ERROR(args[i], "A constant value is required."); + if (!sema_cast_const(args[i])) RETURN_SEMA_ERROR(args[i], "A constant value is required."); if (!cast_implicit(context, args[i], type_int)) return false; } if (!expr_in_int_range(args[1], 0, 1)) @@ -815,8 +813,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_BOOL, BA_INTEGER}, 3)) return false; Type *original = type_flatten(args[0]->type); if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer."); - if (!expr_is_const(args[1])) RETURN_SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[1])) RETURN_SEMA_ERROR(args[1], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[2])) return false; switch (args[2]->const_expr.ixx.i.low) { @@ -892,8 +890,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) } if (!cast_implicit(context, args[1], original->pointer)) return false; } - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[3])) return false; switch (args[3]->const_expr.ixx.i.low) { @@ -916,8 +914,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { if (!cast_implicit(context, args[1], original->pointer)) return false; } - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[3])) return false; switch (args[3]->const_expr.ixx.i.low) { @@ -939,8 +937,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) } Type *val = type_flatten(args[1]->type); if (!type_is_atomic(val)) RETURN_SEMA_ERROR(args[1], "%s exceeds pointer size.", val); - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[3])) return false; switch (args[3]->const_expr.ixx.i.low) { @@ -963,8 +961,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { if (!cast_implicit(context, args[1], original->pointer)) return false; } - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[3])) return false; switch (args[3]->const_expr.ixx.i.low) { @@ -985,8 +983,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { if (!cast_implicit(context, args[1], original->pointer)) return false; } - if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); - if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); + if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant."); + if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant."); if (!is_valid_atomicity(context, args[3])) return false; switch (args[3]->const_expr.ixx.i.low) { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index ea76d39be..4482a485d 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -710,7 +710,7 @@ static bool rule_int_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) { // Handle const: Expr *expr = cc->expr; - if (expr_is_const(expr)) + if (sema_cast_const(expr)) { if (!is_explicit) return sema_cast_error(cc, true, is_silent); @@ -1123,7 +1123,7 @@ static bool rule_widen_narrow(CastContext *cc, bool is_explicit, bool is_silent) } // If const, check in range. - if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, cc->to->type_kind)) + if (sema_cast_const(expr) && expr_const_will_overflow(&expr->const_expr, cc->to->type_kind)) { if (!is_silent) { @@ -1186,7 +1186,7 @@ static bool rule_to_distinct(CastContext *cc, bool is_explicit, bool is_silent) assert(from_type == from_type->canonical); Type *flat = type_flatten(cc->to); ConvGroup flat_group = type_to_group(flat); - if (expr_is_const(cc->expr)) + if (sema_cast_const(cc->expr)) { cc->to = flat; cc->to_group = flat_group; @@ -1280,7 +1280,7 @@ static bool rule_int_to_enum(CastContext *cc, bool is_explicit, bool is_silent) { if (!is_explicit) return sema_cast_error(cc, true, is_silent); - if (!expr_is_const(cc->expr)) return true; + if (!sema_cast_const(cc->expr)) return true; Decl *enum_decl = cc->to->decl; // Check that the type is within limits. @@ -1367,7 +1367,7 @@ static void cast_retype(SemaContext *context, Expr *expr, Type *to_type) { expr- */ INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) { - if (expr_is_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false; + if (sema_cast_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false; return insert_runtime_cast(expr, kind, type); } @@ -1605,7 +1605,7 @@ static void cast_enum_to_int(SemaContext *context, Expr* expr, Type *to_type) { assert(type_flatten(expr->type)->type_kind == TYPE_ENUM); Type *underlying_type = type_base(expr->type); - if (expr_is_const(expr)) + if (sema_cast_const(expr)) { assert(expr->const_expr.const_kind == CONST_ENUM); expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); @@ -1638,7 +1638,7 @@ static void cast_vec_to_arr(SemaContext *context, Expr *expr, Type *to_type) */ static void cast_vec_to_vec(SemaContext *context, Expr *expr, Type *to_type) { - if (!expr_is_const(expr)) + if (!sema_cast_const(expr)) { // Extract indexed types. Type *from_type = type_flatten(expr->type); @@ -1781,7 +1781,7 @@ static void cast_int_to_ptr(SemaContext *context, Expr *expr, Type *type) assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating."); // Handle const: - if (expr_is_const(expr)) + if (sema_cast_const(expr)) { expr->type = type; expr->const_expr.ptr = expr->const_expr.ixx.i.low; @@ -1905,7 +1905,7 @@ static void cast_slice_to_slice(SemaContext *context, Expr *expr, Type *to_type) { Type *to_type_base = type_flatten(type_flatten(to_type)->array.base); Type *from_type_base = type_flatten(type_flatten(expr->type)->array.base); - if (expr_is_const(expr) || to_type_base == from_type_base || (type_is_pointer(to_type_base) && type_is_pointer(from_type_base))) + if (sema_cast_const(expr) || to_type_base == from_type_base || (type_is_pointer(to_type_base) && type_is_pointer(from_type_base))) { expr->type = to_type; return; @@ -1915,7 +1915,7 @@ static void cast_slice_to_slice(SemaContext *context, Expr *expr, Type *to_type) static void cast_slice_to_vecarr(SemaContext *context, Expr *expr, Type *to_type) { - if (!expr_is_const(expr)) + if (!sema_cast_const(expr)) { switch (expr->expr_kind) { @@ -1973,7 +1973,7 @@ static void cast_arr_to_vec(SemaContext *context, Expr *expr, Type *to_type) Type *index_vec = type_flatten(type_get_indexed_type(to_type)); Type *index_arr = type_flatten(type_get_indexed_type(expr->type)); Type *to_temp = index_vec == index_arr ? to_type : type_get_vector(index_arr, type_flatten(expr->type)->array.len); - if (expr_is_const(expr)) + if (sema_cast_const(expr)) { // For the array -> vector this is always a simple rewrite of type. assert(expr->const_expr.const_kind == CONST_INITIALIZER); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index d637af4bc..e87610dbc 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -798,7 +798,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *par if (!sema_analyse_expr(context, start)) return false; // Check for negative, non integer or non const values. - if (!expr_is_const(start) || !type_is_integer(start->type) || int_is_neg(start->const_expr.ixx)) + if (!sema_cast_const(start) || !type_is_integer(start->type) || int_is_neg(start->const_expr.ixx)) { SEMA_ERROR(start, "This must be a constant non-negative integer value."); return false; @@ -819,7 +819,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *par { // Analyse the end if (!sema_analyse_expr(context, start)) return false; - if (!expr_is_const(end) || !type_is_integer(end->type) || int_is_neg(end->const_expr.ixx)) + if (!sema_cast_const(end) || !type_is_integer(end->type) || int_is_neg(end->const_expr.ixx)) { SEMA_ERROR(end, "This must be a constant non-negative integer value."); return false; @@ -2522,7 +2522,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_IF: if (!expr) RETURN_SEMA_ERROR(attr, "'@if' requires a boolean argument."); if (!sema_analyse_expr(context, expr)) return false; - if (expr->type->canonical != type_bool || !expr_is_const(expr)) + if (expr->type->canonical != type_bool || !sema_cast_const(expr)) { RETURN_SEMA_ERROR(expr, "Expected a boolean compile time constant value."); } @@ -3626,6 +3626,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (!type_info) { if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl); + if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); if (global_level_var && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT)) { SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time."); @@ -3731,6 +3732,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) SEMA_ERROR(init_expr, "The expression must be a constant value."); return decl_poison(decl); } + if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); if (expr_is_const(init_expr)) { init_expr->const_expr.is_hex = false; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index fda43dca0..a54f2476b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -192,7 +192,8 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier, bool *missing_ref); static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier, bool *missing_ref); static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member); -static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr); +static inline bool sema_expr_fold_to_index(Expr *expr, Expr *parent, Range range); +static inline void sema_expr_flatten_const_ident(Expr *expr); static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool is_dead); @@ -200,7 +201,7 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *, Expr *expr, bool static inline bool sema_constant_fold_ops(Expr *expr) { - if (!expr_is_const(expr)) return false; + if (!sema_cast_const(expr)) return false; switch (expr->const_expr.const_kind) { case CONST_INTEGER: @@ -304,7 +305,7 @@ Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, uns if (report_error) SEMA_ERROR(index_expr, "Expected the argument index here, but found a value of type %s.", type_quoted_error_string(index_expr->type)); return poisoned_expr; } - if (!expr_is_const(index_expr)) + if (!sema_cast_const(index_expr)) { if (report_error) SEMA_ERROR(index_expr, "Vararg functions need a constant argument, but this is a runtime value."); return poisoned_expr; @@ -1423,7 +1424,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, RETURN_NOTE_FUNC_DEFINITION; } } - if (expr_is_const(arg)) + if (sema_cast_const(arg)) { switch (param->var.kind) { @@ -2048,11 +2049,11 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s if (no_match_ref) goto NO_MATCH_REF; RETURN_SEMA_ERROR(call_expr, "Too many parameters for the macro body, expected %d.", expected_body_params); } - for (unsigned i = 0; i < expected_body_params; i++) + for (unsigned j = 0; j < expected_body_params; j++) { - Decl *body_param = macro_body_params[i]; + Decl *body_param = macro_body_params[j]; assert(body_param->resolve_status == RESOLVE_DONE); - Decl *body_arg = body_params[i]; + Decl *body_arg = body_params[j]; VarDeclKind kind_of_expected = body_param->var.kind; if (kind_of_expected != body_arg->var.kind) { @@ -2543,7 +2544,7 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr, bool static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *len_expr, bool from_end, bool *remove_from_end) { assert(type == type->canonical); - if (!expr_is_const(len_expr)) return true; + if (!sema_cast_const(len_expr)) return true; Int const_len = len_expr->const_expr.ixx; if (!int_fits(const_len, TYPE_I64)) @@ -2601,7 +2602,7 @@ static bool sema_slice_len_is_in_range(SemaContext *context, Type *type, Expr *l static bool sema_slice_index_is_in_range(SemaContext *context, Type *type, Expr *index_expr, bool end_index, bool from_end, bool *remove_from_end) { assert(type == type->canonical); - if (!expr_is_const(index_expr)) return true; + if (!sema_cast_const(index_expr)) return true; Int index = index_expr->const_expr.ixx; if (!int_fits(index, TYPE_I64)) @@ -2929,10 +2930,10 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } else { - if (sema_flattened_expr_is_const(context, index)) + if (sema_cast_const(index)) { assert(expr_is_const_int(index)); - sema_expr_flatten_const(context, current_expr); + sema_expr_flatten_const_ident(current_expr); bool is_const_initializer = expr_is_const_initializer(current_expr); if (is_const_initializer || expr_is_const_string(current_expr) || expr_is_const_bytes(current_expr)) { @@ -2992,7 +2993,7 @@ static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr * bool is_optional = IS_OPTIONAL(pointer) || IS_OPTIONAL(offset); // 4. Possibly constant fold - if (!vec_len && expr_is_const(pointer) && expr_is_const(offset)) + if (!vec_len && sema_cast_const(pointer) && sema_cast_const(offset)) { assert(!is_optional); Int mul = { .i.low = type_size(type_flatten(pointer->type)->pointer), .type = offset->const_expr.ixx.type }; @@ -3091,7 +3092,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) end_from_end = expr->subscript_expr.range.end_from_end = false; } - if (start && end && expr_is_const(start) && expr_is_const(end)) + if (start && end && sema_cast_const(start) && sema_cast_const(end)) { if (!is_lenrange && start_from_end && end_from_end) { @@ -3793,7 +3794,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp { TypeProperty property = type_property_by_name(kw); - if (sema_flattened_expr_is_const(context, typeid)) + if (sema_cast_const(typeid)) { Type *type = typeid->const_expr.typeid; if (!sema_type_property_is_valid_for_type(type, property)) return false; @@ -3839,6 +3840,101 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp return false; } +static inline bool sema_expr_fold_to_index(Expr *expr, Expr *parent, Range range) +{ + ConstInitializer *init = parent->const_expr.initializer; + ConstInitializer *result; + assert(!range.start_from_end); + ArrayIndex start = exprptr(range.start)->const_expr.ixx.i.low; + int len = range_const_len(&range); + ArrayIndex end = start + (len == -1 ? 1 : len); + switch (init->kind) + { + case CONST_INIT_ZERO: + result = init; + goto EVAL; + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + case CONST_INIT_VALUE: + case CONST_INIT_ARRAY_VALUE: + UNREACHABLE + case CONST_INIT_ARRAY: + { + ConstInitializer **new = NULL; + FOREACH(ConstInitializer *, e, init->init_array.elements) + { + ArrayIndex index = e->init_array_value.index; + if (index < start || index >= end) continue; + if (len == -1) + { + result = e->init_array_value.element; + goto EVAL; + } + vec_add(new, e->init_array_value.element); + } + result = CALLOCS(ConstInitializer); + result->type = expr->type; + if (new) + { + result->kind = CONST_INIT_ARRAY; + result->init_array.elements = new; + } + else + { + result->kind = CONST_INIT_ZERO; + } + goto EVAL; + } + case CONST_INIT_ARRAY_FULL: + { + if (len == -1) + { + result = init->init_array_full[start]; + goto EVAL; + } + ConstInitializer **new = NULL; + for (ArrayIndex i = start; i < end; i++) + { + vec_add(new, init->init_array_full[i]); + } + FOREACH(ConstInitializer *, e, init->init_array.elements) + { + ArrayIndex index = e->init_array_value.index; + if (index < start || index >= end) continue; + vec_add(new, e->init_array_value.element); + } + result = CALLOCS(ConstInitializer); + assert(new); + result->kind = CONST_INIT_ARRAY; + result->init_array.elements = new; + result->type = expr->type; + goto EVAL; + } + } + UNREACHABLE +EVAL: + switch (result->kind) + { + case CONST_INIT_ZERO: + expr_rewrite_to_const_zero(expr, result->type); + break; + case CONST_INIT_ARRAY: + case CONST_INIT_ARRAY_FULL: + expr->const_expr.const_kind = CONST_INITIALIZER; + expr->const_expr.initializer = init; + expr->type = init->type; + break; + case CONST_INIT_ARRAY_VALUE: + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + UNREACHABLE + case CONST_INIT_VALUE: + expr_replace(expr, result->init_value); + break; + } + return true; + +} static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member) { ConstInitializer *init = parent->const_expr.initializer; @@ -3881,9 +3977,10 @@ EVAL: case CONST_INIT_UNION: case CONST_INIT_ARRAY: case CONST_INIT_ARRAY_FULL: + expr->expr_kind = EXPR_CONST; expr->const_expr.const_kind = CONST_INITIALIZER; - expr->const_expr.initializer = init; - expr->type = init->type; + expr->const_expr.initializer = result; + expr->type = result->type; break; case CONST_INIT_ARRAY_VALUE: UNREACHABLE @@ -4118,8 +4215,51 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *context, Expr *expr context->active_scope.is_dead = false; return success; } +static bool sema_expr_flatten_assign(Expr *expr) +{ + assert(expr->resolve_status == RESOLVE_DONE); + switch (expr->expr_kind) + { + case EXPR_ACCESS: + case EXPR_BITACCESS: + { + Expr *parent = expr->access_expr.parent; + Type *flat = type_flatten(parent->type); + switch (flat->type_kind) + { + case TYPE_UNION: + case TYPE_UNTYPED_LIST: + case TYPE_BITSTRUCT: + case TYPE_STRUCT: + break; + default: + return false; + } + if (!sema_expr_flatten_assign(expr->access_expr.parent)) return false; + if (!sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref)) return false; + return true; -static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr) + } + case EXPR_SUBSCRIPT: + { + if (!range_is_const(&expr->subscript_expr.range)) return false; + Expr *parent = exprptr(expr->subscript_expr.expr); + Type *flat_type = type_flatten(parent->type); + if (!type_is_any_arraylike(flat_type) || flat_type->type_kind == TYPE_UNTYPED_LIST) return false; + if (!sema_expr_flatten_assign(parent)) return false; + return sema_expr_fold_to_index(expr, parent, expr->subscript_expr.range); + } + case EXPR_IDENTIFIER: + sema_expr_flatten_const_ident(expr); + return expr_is_const(expr); + case EXPR_CONST: + return true; + default: + return false; + } +} + +static inline void sema_expr_flatten_const_ident(Expr *expr) { if (expr->expr_kind != EXPR_IDENTIFIER) return; Decl *ident = expr->identifier_expr.decl; @@ -4146,19 +4286,13 @@ static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr) } Expr *init_expr = ident->var.init_expr; if (!init_expr) return; - sema_expr_flatten_const(context, init_expr); + sema_expr_flatten_const_ident(init_expr); if (expr_is_const(init_expr)) { expr_replace(expr, expr_copy(init_expr)); } } -bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr) -{ - sema_expr_flatten_const(context, expr); - return expr_is_const(expr); -} - /** * Analyse "x.y" */ @@ -4275,7 +4409,7 @@ CHECK_DEEPER: if (flat_type->type_kind == TYPE_SLICE) { // Handle literal "foo".len which is now a slice. - sema_expr_flatten_const(context, parent); + sema_expr_flatten_const_ident(parent); if (expr_is_const_string(parent)) { expr_rewrite_const_int(expr, type_isz, parent->const_expr.bytes.len); @@ -4340,7 +4474,7 @@ CHECK_DEEPER: { assert(flat_type->decl->resolve_status == RESOLVE_DONE); - if (sema_flattened_expr_is_const(context, current_parent)) + if (sema_cast_const(current_parent)) { if (current_parent->const_expr.const_kind == CONST_POINTER) { @@ -4359,7 +4493,7 @@ CHECK_DEEPER: { if (flat_type->type_kind == TYPE_ENUM) { - if (sema_flattened_expr_is_const(context, current_parent)) + if (sema_cast_const(current_parent)) { expr_rewrite_to_string(expr, current_parent->const_expr.enum_err_val->name); return true; @@ -4372,7 +4506,7 @@ CHECK_DEEPER: } if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYFAULT) { - if (expr_is_const(current_parent)) + if (sema_cast_const(current_parent)) { expr_rewrite_to_string(expr, current_parent->const_expr.enum_err_val->name); return true; @@ -4415,7 +4549,7 @@ CHECK_DEEPER: Decl *decl = type->decl; Decl *member = sema_decl_stack_find_decl_member(decl, kw); - if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && expr_is_const(parent)) + if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && sema_cast_const(parent)) { if (!sema_analyse_decl(context, decl)) return false; assert(parent->const_expr.const_kind == CONST_ENUM); @@ -4721,6 +4855,14 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool return true; } +bool range_is_const(Range *range) +{ + Expr *start = exprptr(range->start); + Expr *end = exprptrzero(range->end); + if (end && !expr_is_const(end)) return false; + if (start && !expr_is_const(start)) return false; + return true; +} static inline IndexDiff range_const_len(Range *range) { Expr *start = exprptr(range->start); @@ -5025,10 +5167,9 @@ static bool sema_binary_analyse_ct_common_assign(SemaContext *context, Expr *exp if (!sema_expr_analyse_binary(context, expr)) return false; - if (!expr_is_const(expr)) + if (!sema_cast_const(expr)) { - SEMA_ERROR(exprptr(expr->binary_expr.right), "Expected a constant expression."); - return false; + RETURN_SEMA_ERROR(exprptr(expr->binary_expr.right), "Expected a constant expression."); } left->ct_ident_expr.decl->var.init_expr = expr; @@ -5081,7 +5222,7 @@ BITSTRUCT_OK: RETURN_SEMA_ERROR(right, "The expression may not be optional."); } // 6. Check for zero in case of div or mod. - if (expr_is_const(right)) + if (sema_cast_const(right)) { if (expr->binary_expr.operator == BINARYOP_DIV_ASSIGN) { @@ -5678,7 +5819,7 @@ static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left, if (!sema_binary_analyse_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false)) return false; // 2. Check for a constant 0 on the rhs. - if (expr_is_const(right)) + if (sema_cast_const(right)) { switch (right->const_expr.const_kind) { @@ -5736,7 +5877,7 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left, if (type_is_float(flat)) { // 3. a % 0 is not valid, so detect it. - if (expr_is_const(right) && right->const_expr.fxx.f == 0.0) + if (sema_cast_const(right) && right->const_expr.fxx.f == 0.0) { RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero."); } @@ -5753,7 +5894,7 @@ static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left, { assert(type_is_integer(flat)); // 3. a % 0 is not valid, so detect it. - if (expr_is_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero."); + if (sema_cast_const(right) && int_is_zero(right->const_expr.ixx)) RETURN_SEMA_ERROR(right, "Cannot perform %% with a constant zero."); // 4. Constant fold if (expr_both_const(left, right) && sema_constant_fold_ops(left)) @@ -5858,7 +5999,7 @@ static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left if (!cast_implicit(context, left, cast_numeric_arithmetic_promotion(type_no_optional(left->type)))) return false; // 4. For a constant rhs side we will make a series of checks. - if (expr_is_const(right)) + if (sema_cast_const(right)) { // 4a. Make sure the value does not exceed the bitsize of // the left hand side. We ignore this check for lhs being a constant. @@ -5878,7 +6019,7 @@ static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left } // 5. Fold constant expressions. - if (expr_is_const(left)) + if (sema_cast_const(left)) { bool shr = expr->binary_expr.operator == BINARYOP_SHR; expr_replace(expr, left); @@ -5921,7 +6062,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp if (!expr_both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(context, expr); // 4. For a constant right hand side we will make a series of checks. - if (expr_is_const(right)) + if (sema_cast_const(right)) { // 4a. Make sure the value does not exceed the bitsize of // the left hand side. @@ -5980,7 +6121,7 @@ static bool sema_binary_is_unsigned_always_same_comparison(SemaContext *context, Type *lhs_type, Type *rhs_type) { if (context->active_scope.flags & (SCOPE_MACRO | SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) return true; - if (!expr_is_const(left) && !expr_is_const(right)) return true; + if (!sema_cast_const(left) && !sema_cast_const(right)) return true; if (!type_is_integer(left->type)) return true; if (expr_is_const(left) && type_is_unsigned(rhs_type)) { @@ -6163,7 +6304,7 @@ static inline bool sema_expr_analyse_deref(SemaContext *context, Expr *expr, boo } // 3. This could be a constant, in which case it is a null which is an error. - if (expr_is_const(inner)) + if (sema_cast_const(inner)) { if (failed_ref) goto ON_FAILED; RETURN_SEMA_ERROR(inner, "Dereferencing null is not allowed, did you do it by mistake?"); @@ -6435,7 +6576,7 @@ static inline bool sema_expr_analyse_bit_not(SemaContext *context, Expr *expr) } VALID_VEC: - if (is_bitstruct && expr_is_const(inner)) + if (is_bitstruct && sema_cast_const(inner)) { expr_replace(expr, inner); sema_invert_bitstruct_const_initializer(expr->const_expr.initializer); @@ -6509,7 +6650,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) expr->type = type_add_optional(type_bool, IS_OPTIONAL(inner)); - if (expr_is_const(inner)) + if (sema_cast_const(inner)) { bool success = cast_explicit(context, inner, expr->type); assert(success); @@ -7240,7 +7381,7 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat { RETURN_SEMA_ERROR(inner, "Expected an integer index."); } - if (!sema_flattened_expr_is_const(context, inner)) + if (!sema_cast_const(inner)) { RETURN_SEMA_ERROR(inner, "Expected a constant index."); } @@ -8455,7 +8596,7 @@ static inline bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *conca { Expr *single_expr = exprs[i]; if (!sema_analyse_expr(context, single_expr)) return false; - if (!expr_is_const(single_expr)) RETURN_SEMA_ERROR(single_expr, "Expected this to evaluate to a constant value."); + if (!sema_cast_const(single_expr)) RETURN_SEMA_ERROR(single_expr, "Expected this to evaluate to a constant value."); if (concat == CONCAT_UNKNOWN) { element_type = single_expr->type; @@ -8599,7 +8740,7 @@ static inline bool sema_expr_analyse_ct_append(SemaContext *context, Expr *appen } if (!sema_analyse_expr(context, list)) return false; - if (!expr_is_const(list)) RETURN_SEMA_ERROR(list, "Expected the list to evaluate to a constant value."); + if (!sema_cast_const(list)) RETURN_SEMA_ERROR(list, "Expected the list to evaluate to a constant value."); Expr **untyped_list = NULL; switch (list->const_expr.const_kind) { @@ -8622,7 +8763,7 @@ static inline bool sema_expr_analyse_ct_append(SemaContext *context, Expr *appen { Expr *element = exprs[i]; if (!sema_analyse_expr(context, element)) return false; - if (!expr_is_const(element)) RETURN_SEMA_ERROR(element, "Expected the element to evaluate to a constant value."); + if (!sema_cast_const(element)) RETURN_SEMA_ERROR(element, "Expected the element to evaluate to a constant value."); vec_add(untyped_list, element); } append_expr->expr_kind = EXPR_CONST; @@ -8770,7 +8911,7 @@ static inline bool sema_expr_analyse_retval(SemaContext *context, Expr *expr) } } assert(return_value); - if (sema_flattened_expr_is_const(context, return_value)) + if (expr_is_constant_eval(return_value, CONSTANT_EVAL_GLOBAL_INIT)) { expr_replace(expr, copy_expr_single(return_value)); } @@ -8993,7 +9134,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo if (to && allow_optional && to_canonical != rhs_type_canonical && rhs_type_canonical->type_kind == TYPE_FAULTTYPE) { Type *flat = type_flatten(to); - if (flat != type_anyfault && flat->type_kind != TYPE_FAULTTYPE && expr_is_const(expr)) + if (flat != type_anyfault && flat->type_kind != TYPE_FAULTTYPE && sema_cast_const(expr)) { if (no_match_ref) goto NO_MATCH_REF; print_error_after(expr->span, "You need to add a trailing '?' here to make this an optional."); @@ -9067,7 +9208,7 @@ static ArrayIndex len_from_const_initializer(ConstInitializer *init) ArrayIndex sema_len_from_const(Expr *expr) { // We also handle the case where we have a cast from a const array. - if (!expr_is_const(expr)) + if (!sema_cast_const(expr)) { if (type_flatten(expr->type)->type_kind != TYPE_SLICE) return -1; if (expr->expr_kind == EXPR_SLICE) @@ -9079,7 +9220,7 @@ ArrayIndex sema_len_from_const(Expr *expr) Expr *inner = exprptr(expr->cast_expr.expr); if (inner->expr_kind != EXPR_UNARY || inner->unary_expr.operator != UNARYOP_ADDR) return -1; inner = inner->unary_expr.expr; - if (!expr_is_const(inner)) return -1; + if (!sema_cast_const(inner)) return -1; expr = inner; } switch (expr->const_expr.const_kind) @@ -9109,10 +9250,10 @@ static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr) Expr *copy = copy_expr_single(decl->var.init_expr); if (!copy) { - SEMA_ERROR(expr, "'%s' was not yet initialized to any value, assign a value to it before use.", decl->name); - return false; + RETURN_SEMA_ERROR(expr, "'%s' was not yet initialized to any value, assign a value to it before use.", decl->name); } if (!sema_analyse_expr(context, copy)) return false; + sema_cast_const(copy); expr_replace(expr, copy); return true; } @@ -9144,11 +9285,8 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr) return false; } // We may have kept FOO.x.y as a reference, fold it now if y is not an aggregate. - if (!type_is_abi_aggregate(expr->type) && sema_flattened_expr_is_const(context, expr->access_expr.parent)) - { - return sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref); - } - break; + sema_expr_flatten_const_ident(expr->access_expr.parent); + return true; case EXPR_TYPEINFO: RETURN_SEMA_ERROR(expr, "A type must be followed by either (...) or '.'."); case EXPR_CT_IDENT: @@ -9195,10 +9333,9 @@ bool sema_analyse_ct_expr(SemaContext *context, Expr *expr) expr->type = type_typeid; } if (!sema_cast_rvalue(context, expr)) return false; - if (!sema_flattened_expr_is_const(context, expr)) + if (!sema_cast_const(expr)) { - SEMA_ERROR(expr, "Expected a compile time expression."); - return false; + RETURN_SEMA_ERROR(expr, "Expected a compile time expression."); } return true; } @@ -9294,6 +9431,11 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr) return sema_analyse_expr_lvalue(context, expr) && sema_cast_rvalue(context, expr); } +bool sema_cast_const(Expr *expr) +{ + return sema_expr_flatten_assign(expr); +} + static inline int64_t expr_get_index_max(Expr *expr) { if (expr_is_const_untyped_list(expr)) @@ -9496,7 +9638,7 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member) { // Don't check non-consts and non integers. - if (!expr_is_const(right) || !type_is_integer(right->type)) return true; + if (!sema_cast_const(right) || !type_is_integer(right->type)) return true; unsigned bits = member->var.end_bit - member->var.start_bit + 1; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index d3da02fe0..429b737cf 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -383,7 +383,7 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E FOREACH(Expr *, element, init_list) { if (!sema_analyse_expr(context, element)) return false; - if (!expr_is_const(element)) + if (!sema_cast_const(element)) { RETURN_SEMA_ERROR(element, "An untyped list can only have " "constant elements, you can try " diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 1c0f466cb..7660b5cfc 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -95,7 +95,6 @@ void cast_promote_vararg(SemaContext *context, Expr *arg); Type *cast_numeric_arithmetic_promotion(Type *type); void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); bool sema_decl_if_cond(SemaContext *context, Decl *decl); -bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr); Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params); Type *sema_resolve_type_get_func(Signature *signature, CallABI abi); INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result); diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 6fb703610..31aca217d 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -368,7 +368,7 @@ void sema_analysis_pass_register_conditional_units(Module *module) } Expr *expr = if_attr->exprs[0]; if (!sema_analyse_ct_expr(&context, expr)) goto FAIL_CONTEXT; - if (!expr_is_const(expr) || expr->type->canonical != type_bool) + if (!sema_cast_const(expr) || expr->type->canonical != type_bool) { PRINT_ERROR_AT(expr, "Expected a constant boolean expression."); goto FAIL_CONTEXT; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 0e77f4c53..84e2c310f 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -127,7 +127,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement // If it's ensure (and an error) we print an error. if (!context->active_scope.jump_end && !context->active_scope.is_dead) { - if (message_expr && expr_is_const(message_expr) && vec_size(statement->assert_stmt.args)) + if (message_expr && sema_cast_const(message_expr) && vec_size(statement->assert_stmt.args)) { RETURN_SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr)); } @@ -350,7 +350,7 @@ static inline bool sema_return_optional_check_is_valid_in_scope(SemaContext *con if (!IS_OPTIONAL(ret_expr) || !context->call_env.opt_returns) return true; if (ret_expr->expr_kind != EXPR_OPTIONAL) return true; Expr *inner = ret_expr->inner_expr; - if (!expr_is_const(inner)) return true; + if (!sema_cast_const(inner)) return true; assert(ret_expr->inner_expr->const_expr.const_kind == CONST_ERR); Decl *fault = ret_expr->inner_expr->const_expr.enum_err_val; FOREACH(Decl *, opt, context->call_env.opt_returns) @@ -374,7 +374,7 @@ static bool sema_analyse_macro_constant_ensures(SemaContext *context, Expr *ret_ // If the return expression can't be flattened to a constant value, then // we won't be able to do any constant ensure checks anyway, so skip. - if (!sema_flattened_expr_is_const(context, ret_expr)) return true; + if (!sema_cast_const(ret_expr)) return true; AstId doc_directive = context->current_macro->func_decl.docs; // We store the old return_expr for retval @@ -2108,7 +2108,7 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) { if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue; Expr *expr = exprptr(case_stmt->case_stmt.expr); - if (expr_is_const(expr) && expr->const_expr.typeid == type) + if (sema_cast_const(expr) && expr->const_expr.typeid == type) { statement->nextcase_stmt.case_switch_stmt = astid(case_stmt); return true; @@ -2124,13 +2124,13 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer, true); - if (expr_is_const(value)) + if (sema_cast_const(value)) { FOREACH(Ast *, case_stmt, parent->switch_stmt.cases) { Expr *from = exprptr(case_stmt->case_stmt.expr); if (case_stmt->ast_kind == AST_DEFAULT_STMT) continue; - if (!expr_is_const(from)) goto VARIABLE_JUMP; + if (!sema_cast_const(from)) goto VARIABLE_JUMP; ExprConst *const_expr = &from->const_expr; ExprConst *to_const_expr = case_stmt->case_stmt.to_expr ? &exprptr(case_stmt->case_stmt.to_expr)->const_expr : const_expr; if (expr_const_in_range(&value->const_expr, const_expr, to_const_expr)) @@ -2242,7 +2242,7 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type, Expr *expr = exprptr(case_stmt->case_stmt.expr); if (!sema_analyse_expr_rhs(context, type_typeid, expr, false, NULL)) return false; - if (expr_is_const(expr)) + if (sema_cast_const(expr)) { Type *my_type = expr->const_expr.typeid; for (unsigned i = 0; i < index; i++) @@ -2250,7 +2250,7 @@ static inline bool sema_check_type_case(SemaContext *context, Type *switch_type, Ast *other = cases[i]; if (other->ast_kind != AST_CASE_STMT) continue; Expr *other_expr = exprptr(other->case_stmt.expr); - if (expr_is_const(other_expr) && other_expr->const_expr.typeid == my_type) + if (sema_cast_const(other_expr) && other_expr->const_expr.typeid == my_type) { SEMA_ERROR(case_stmt, "The same type appears more than once."); SEMA_NOTE(other, "Here is the case with that type."); @@ -2272,13 +2272,13 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type if (to_expr && !sema_analyse_expr_rhs(context, switch_type, to_expr, false, NULL)) return false; bool is_range = to_expr != NULL; - bool first_is_const = expr_is_const(expr); + bool first_is_const = sema_cast_const(expr); if (!is_range && !first_is_const) { *if_chained = true; return true; } - if (is_range && (!expr_is_const_int(expr) || !expr_is_const(to_expr))) + if (is_range && (!expr_is_const_int(expr) || !sema_cast_const(to_expr))) { sema_error_at(context, extend_span_with_token(expr->span, to_expr->span), "Ranges must be constant integers."); return false; @@ -2309,7 +2309,7 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type Ast *other = cases[i]; if (other->ast_kind != AST_CASE_STMT) continue; Expr *other_expr = exprptr(other->case_stmt.expr); - if (!expr_is_const(other_expr)) continue; + if (!sema_cast_const(other_expr)) continue; ExprConst *other_const = &other_expr->const_expr; ExprConst *other_to_const = other->case_stmt.to_expr ? &exprptr(other->case_stmt.to_expr)->const_expr : other_const; if (expr_const_in_range(const_expr, other_const, other_to_const)) @@ -2439,7 +2439,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL; PUSH_NEXT(next, statement); Ast *body = stmt->case_stmt.body; - if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && expr_is_const(exprptr(stmt->case_stmt.expr))) + if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && sema_cast_const(exprptr(stmt->case_stmt.expr))) { if (any_switch->is_assign) { @@ -2570,7 +2570,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem if (!sema_analyse_expr_rhs(context, type, expr, false, NULL)) goto FAILED; if (to_expr && !sema_analyse_expr_rhs(context, type, to_expr, false, NULL)) goto FAILED; } - if (!expr_is_const(expr)) + if (!sema_cast_const(expr)) { SEMA_ERROR(expr, "The $case must have a constant expression."); goto FAILED; @@ -2581,7 +2581,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem if (matched_case == case_count) matched_case = (int)i; continue; } - if (to_expr && !expr_is_const(to_expr)) + if (to_expr && !sema_cast_const(to_expr)) { SEMA_ERROR(to_expr, "The $case must have a constant expression."); goto FAILED; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index c27a7022a..0f679bdb3 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -40,7 +40,7 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra if (!sema_analyse_expr(context, len_expr)) return type_info_poison(type_info); // A constant expression is assumed. - if (!expr_is_const(len_expr)) + if (!sema_cast_const(len_expr)) { SEMA_ERROR(len_expr, "Expected a constant value as length."); return type_info_poison(type_info); @@ -186,7 +186,7 @@ static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, default: UNREACHABLE } - assert(!type->array.len || expr_is_const(type->array.len)); + assert(!type->array.len || sema_cast_const(type->array.len)); type->resolve_status = RESOLVE_DONE; return true; } @@ -328,7 +328,7 @@ INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info) { Expr *expr = type_info->unresolved_type_expr; if (!sema_analyse_expr(context, expr)) return false; - if (!expr_is_const(expr) || expr->const_expr.const_kind != CONST_TYPEID) + if (!sema_cast_const(expr) || expr->const_expr.const_kind != CONST_TYPEID) { RETURN_SEMA_ERROR(expr, "Expected a constant typeid value."); } diff --git a/test/unit/stdlib/collections/list.c3 b/test/unit/stdlib/collections/list.c3 index cc17a6c03..cbb6af2c2 100644 --- a/test/unit/stdlib/collections/list.c3 +++ b/test/unit/stdlib/collections/list.c3 @@ -92,6 +92,22 @@ fn void! remove_if() assert(test.array_view() == int[]{11, 10, 20}); } +fn void! init_with_array() +{ + IntList foo; + foo.new_init_with_array({ 1, 2, 3}); + assert(foo.len() == 3); + assert(foo[2] == 3); +} + +fn void! init_with_temp_array() +{ + IntList foo; + foo.temp_init_with_array({ 1, 2, 3}); + assert(foo.len() == 3); + assert(foo[2] == 3); +} + fn void! remove_using_test() { IntList test;