diff --git a/releasenotes.md b/releasenotes.md index 013607d30..74550aaff 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -10,6 +10,7 @@ - Improved error messages on missing qualifier on enum value. #2260 - Add `--echo-prefix` to edit the prefix with `$echo` statements. Supports {FILE} and {LINE} - Catch accidental `foo == BAR;` where `foo = BAR;` was most likely intended. #2274 +- Improve error message when doing a rethrow in a function that doesn't return an optional. ### Fixes - mkdir/rmdir would not work properly with substring paths on non-windows platforms. @@ -31,6 +32,7 @@ - Make `to_float` more tolerant to spaces. - Fixes to thread local pointer handling. - Fixes to JSON parsing and Object. +- Array indices are now using int64 internally. ### Stdlib changes diff --git a/src/compiler/c_codegen.c b/src/compiler/c_codegen.c index 75654010f..d02587438 100644 --- a/src/compiler/c_codegen.c +++ b/src/compiler/c_codegen.c @@ -257,7 +257,7 @@ static bool c_emit_type_decl(GenContext *c, Type *type) if (prev) return false; c_emit_type_decl(c, type->array.base); int id = ++c->typename; - PRINTF("typedef struct { %s ptr[%u]; } __c3_array%d;\n", c_type_name(c, type->array.base), type->array.len, id); + PRINTF("typedef struct { %s ptr[%llu]; } __c3_array%d;\n", c_type_name(c, type->array.base), (unsigned long long)type->array.len, id); scratch_buffer_clear(); scratch_buffer_printf(" __c3_array%d", id); htable_set(&c->gen_decl, type, scratch_buffer_copy()); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 6df722ed3..d149d86d5 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -16,11 +16,11 @@ typedef double Real; typedef uint64_t ByteSize; typedef uint32_t TypeSize; typedef int32_t IndexDiff; -typedef int32_t ArrayIndex; +typedef int64_t ArrayIndex; typedef uint16_t StructIndex; typedef uint32_t AlignSize; typedef int32_t ScopeId; -typedef uint32_t ArraySize; +typedef uint64_t ArraySize; typedef uint64_t BitSize; typedef uint16_t FileId; @@ -34,7 +34,7 @@ typedef uint16_t FileId; #define UINT12_MAX 4095 #define UINT20_MAX 1048575U -#define MAX_ARRAYINDEX INT32_MAX +#define MAX_ARRAYINDEX INT64_MAX #define MAX_FIXUPS 0xFFFFF #define MAX_HASH_SIZE (512 * 1024 * 1024) #define INVALID_SPAN ((SourceSpan){ .row = 0 }) @@ -72,6 +72,15 @@ typedef uint16_t FileId; #define TABLE_MAX_LOAD 0.5 #define OUTF(...) do { if (!compiler.build.silent) printf(__VA_ARGS__); } while(0) #define OUTN(str__) do { if (!compiler.build.silent) puts(str__); } while(0) +#ifdef NDEBUG +#define ASSERT_SPANF(node__, check__, format__, ...) do { (void)(check__); } while(0) +#define ASSERT_SPAN(node__, check__) do { (void)(check__); } while(0) +#define ASSERT_AT(span__, check__) do { (void)(check__);} while(0) +#else +#define ASSERT_SPANF(node__, check__, format__, ...) do { if (!(check__)) { assert_print_line((node__)->span); eprintf(format__, __VA_ARGS__); ASSERT(check__); } } while(0) +#define ASSERT_SPAN(node__, check__) do { if (!(check__)) { assert_print_line((node__)->span); ASSERT(check__); } } while(0) +#define ASSERT_AT(span__, check__) do { if (!(check__)) { assert_print_line(span__); ASSERT(check__); } } while(0) +#endif #define INVALID_PTR ((void*)(uintptr_t)0xAAAAAAAAAAAAAAAA) @@ -704,7 +713,7 @@ typedef enum RangeType typedef struct { ResolveStatus status : 3; - RangeType range_type; + RangeType range_type : 4; bool start_from_end : 1; bool end_from_end : 1; bool is_len : 1; @@ -2021,6 +2030,8 @@ INLINE bool compile_asserts(void) return safe_mode_enabled() || compiler.build.testing; } +void assert_print_line(SourceSpan span); + bool ast_is_not_empty(Ast *ast); bool ast_is_compile_time(Ast *ast); @@ -2945,6 +2956,7 @@ INLINE TypeInfoId type_info_id_new_base(Type *type, SourceSpan span) return type_infoid(type_info_new_base(type, span)); } + INLINE Type *type_new(TypeKind kind, const char *name) { Type *type = CALLOCS(Type); @@ -4236,16 +4248,12 @@ INLINE bool check_module_name(Path *path) return true; } -#ifdef NDEBUG -#define ASSERT_SPANF(node__, check__, format__, ...) do { (void)(check__); } while(0) -#define ASSERT_SPAN(node__, check__) do { (void)(check__); } while(0) -#define ASSERT_AT(span__, check__) do { (void)(check__);} while(0) -#else -#define ASSERT_SPANF(node__, check__, format__, ...) do { if (!(check__)) { assert_print_line((node__)->span); eprintf(format__, __VA_ARGS__); ASSERT(check__); } } while(0) -#define ASSERT_SPAN(node__, check__) do { if (!(check__)) { assert_print_line((node__)->span); ASSERT(check__); } } while(0) -#define ASSERT_AT(span__, check__) do { if (!(check__)) { assert_print_line(span__); ASSERT(check__); } } while(0) -#endif -void assert_print_line(SourceSpan span); +INLINE bool expr_is_valid_index(Expr *expr) +{ + ASSERT_SPAN(expr, expr_is_const_int(expr)); + return int_fits(expr->const_expr.ixx, TYPE_I64); +} + const char *default_c_compiler(void); diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 5de9beabb..0ea399c8f 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -203,7 +203,7 @@ static void header_print_type(HeaderContext *c, Type *type) case TYPE_ARRAY: PRINTF("struct { "); header_print_type(c, type->array.base); - PRINTF(" arr[%d]; }", type->array.len); + PRINTF(" arr[%llu]; }", (unsigned long long)type->array.len); return; case TYPE_ANY: case TYPE_INTERFACE: @@ -227,7 +227,7 @@ static void header_print_type(HeaderContext *c, Type *type) default: UNREACHABLE; } - PRINTF("%dx%d", (int)type_bit_size(type->array.base), type->array.len); + PRINTF("%dx%llu", (int)type_bit_size(type->array.base), (unsigned long long)type->array.len); return; } } @@ -345,7 +345,7 @@ static void header_gen_members(HeaderContext *c, int indent, Decl **members) { case TYPE_ARRAY: header_print_type(c, type->array.base); - PRINTF(" %s[%d];\n", member->name, type->array.len); + PRINTF(" %s[%llu];\n", member->name, (unsigned long long)type->array.len); break; case TYPE_FLEXIBLE_ARRAY: header_print_type(c, type->array.base); @@ -574,7 +574,7 @@ RETRY: header_print_type(c, flat_type); PRINTF(" "); header_print_type(c, type); - PRINTF(" __attribute__((vector_size(%d)));\n", (int)type_size(flat_type) * type->array.len); + PRINTF(" __attribute__((vector_size(%llu)));\n", (int)type_size(flat_type) * (unsigned long long)type->array.len); return; } } diff --git a/src/compiler/number.c b/src/compiler/number.c index 5c7ce8e4f..4607fb778 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -491,7 +491,7 @@ const char *expr_const_to_error_string(const ExprConst *expr) case CONST_FLOAT: return str_printf("%g", expr->fxx.f); case CONST_STRING: - return str_printf("\"%*.s\"", expr->bytes.len, expr->bytes.ptr); + return str_printf("\"%*.s\"", (int)expr->bytes.len, expr->bytes.ptr); case CONST_BYTES: return ""; case CONST_REF: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 255b98f18..a94238f50 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3989,8 +3989,7 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, { SourceSpan span = start->span; span = extend_span_with_token(span, end->span); - sema_error_at(context, span, "No common type can be found between start and end index."); - return false; + RETURN_SEMA_ERROR_AT(span, "No common type can be found between start and end index."); } if (!cast_implicit(context, start, common, false) || !cast_implicit(context, end, common, false)) return false; } @@ -4013,12 +4012,12 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, if (end && sema_cast_const(end)) { // Only ArrayIndex sized - if (!int_fits(end->const_expr.ixx, TYPE_I64)) + if (!expr_is_valid_index(end)) { RETURN_SEMA_ERROR(end, "The index cannot be stored in a 64-signed integer, which isn't supported."); } - int64_t end_index = int_to_i64(end->const_expr.ixx); + ArrayIndex end_index = int_to_i64(end->const_expr.ixx); if (range->end_from_end) { @@ -4026,11 +4025,11 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, // Something like 1 .. ^4 with an unknown length. if (len < 0) return true; // Otherwise we fold the "from end" - end_index = len - end_index; - if (end_index < 0) + if (end_index > len) { - RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", end_index); + RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", len - end_index); } + end_index = len - end_index; range->end_from_end = false; } if (end_index < 0 && env != RANGE_PTR) @@ -4038,8 +4037,7 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", end_index); } // No more analysis - if (end_index > MAX_ARRAYINDEX || end_index < -MAX_ARRAYINDEX) return true; - range->const_end = (ArrayIndex)end_index; + range->const_end = end_index; range->range_type = range->is_len ? RANGE_CONST_LEN : RANGE_CONST_END; } else if (!end && len > 0) @@ -4052,24 +4050,23 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, if (sema_cast_const(start)) { // Only ArrayIndex sized - if (!int_fits(start->const_expr.ixx, TYPE_I64)) + if (!expr_is_valid_index(start)) { RETURN_SEMA_ERROR(end, "The index cannot be stored in a 64-signed integer, which isn't supported."); } // Only ArrayIndex sized - int64_t start_index = int_to_i64(start->const_expr.ixx); + ArrayIndex start_index = int_to_i64(start->const_expr.ixx); if (range->start_from_end) { if (start_index < 0) RETURN_SEMA_ERROR(end, "Negative numbers are not allowed when indexing from the end."); // Something like ^1 .. 4 with an unknown length. if (len < 0) return true; // Otherwise we fold the "from end" - start_index = len - start_index; - if (start_index < 0) + if (len < start_index) { - RETURN_SEMA_ERROR(start, "An index may only be negative for pointers (it was: %lld).", start_index); + RETURN_SEMA_ERROR(start, "An index may only be negative for pointers (it was: %lld).", len - start_index); } - if (start_index > MAX_ARRAYINDEX || start_index < -MAX_ARRAYINDEX) return true; + start_index = len - start_index; range->start_from_end = false; } if (start_index < 0 && env != RANGE_PTR) @@ -4083,20 +4080,19 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range, } if (range->range_type == RANGE_CONST_END) { - int64_t end_index = range->const_end; + ArrayIndex end_index = range->const_end; if (end_index < start_index) RETURN_SEMA_ERROR(start, "The start index (%lld) should not be greater than the end index (%lld).", start_index, end_index); - if (start_index > MAX_ARRAYINDEX) return true; - range->const_end = (ArrayIndex)(end_index + 1 - start_index); + range->const_end = end_index + 1 - start_index; range->range_type = RANGE_CONST_LEN; range->is_len = true; } if (range->range_type == RANGE_CONST_LEN) { - int64_t end_index = range->const_end; + ArrayIndex end_index = range->const_end; range->range_type = RANGE_CONST_RANGE; - range->start_index = (ArrayIndex)start_index; - range->len_index = (ArrayIndex)end_index; + range->start_index = start_index; + range->len_index = end_index; } } if (len > -1) @@ -9002,8 +8998,10 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) expr->rethrow_expr.in_block = NULL; if (context->rtype && context->rtype->type_kind != TYPE_OPTIONAL) { - RETURN_SEMA_ERROR(expr, "This expression implicitly returns with an optional result, " - "but the function does not allow optional results. Did you mean to use '!!' instead?"); + RETURN_SEMA_ERROR(expr, "This expression is doing a rethrow, " + "but '%s' returns %s, which isn't an optional type. Did you intend to use '!!' instead?", + context->call_env.current_function->name, + type_quoted_error_string(context->rtype)); } } return true; diff --git a/src/compiler/types.c b/src/compiler/types.c index 6286d07cf..c86b6f860 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1130,13 +1130,13 @@ static Type *type_create_array(Type *element_type, ArraySize len, bool vector, b Type *vec_arr; if (vector) { - vec_arr = type_new(TYPE_VECTOR, str_printf("%s[<%u>]", element_type->name, len)); + vec_arr = type_new(TYPE_VECTOR, str_printf("%s[<%llu>]", element_type->name, (unsigned long long)len)); vec_arr->array.base = element_type; vec_arr->array.len = len; } else { - vec_arr = type_new(TYPE_ARRAY, str_printf("%s[%u]", element_type->name, len)); + vec_arr = type_new(TYPE_ARRAY, str_printf("%s[%llu]", element_type->name, (unsigned long long)len)); vec_arr->array.base = element_type; vec_arr->array.len = len; } diff --git a/test/test_suite/errors/rethrow_no_err.c3 b/test/test_suite/errors/rethrow_no_err.c3 index 9244ddf8c..1763e67ff 100644 --- a/test/test_suite/errors/rethrow_no_err.c3 +++ b/test/test_suite/errors/rethrow_no_err.c3 @@ -5,8 +5,8 @@ fn void test() int i = 0; if (i!) return; // #error: No optional to rethrow before '!' in the expression, please remove '!' int? j = 0; - if (j!) return; // #error: This expression implicitly returns with an optional result, but the function - if ((j!)!) return; // #error: This expression implicitly returns with an optional result, but the function + if (j!) return; // #error: This expression is doing a rethrow + if ((j!)!) return; // #error: This expression is doing a rethrow } fn void? test2() diff --git a/test/test_suite/errors/rethrow_optional_in_non_opt.c3 b/test/test_suite/errors/rethrow_optional_in_non_opt.c3 new file mode 100644 index 000000000..5efe904eb --- /dev/null +++ b/test/test_suite/errors/rethrow_optional_in_non_opt.c3 @@ -0,0 +1,9 @@ +module test; +import std; +fn int? test() => 1; + +fn int main() +{ + test()!; // #error: This expression is doing a rethrow + return 0; +}