diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index e122f298d..ed42e3084 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -18,7 +18,7 @@ struct TempAllocator } -private const usz PAGE_IS_ALIGNED = (usz)isz.max + 1; +private const usz PAGE_IS_ALIGNED = (usz)isz.max + 1u; struct TempAllocatorPage diff --git a/lib/std/math_i128.c3 b/lib/std/math_i128.c3 index cdddf7fae..e16586e3c 100644 --- a/lib/std/math_i128.c3 +++ b/lib/std/math_i128.c3 @@ -215,17 +215,17 @@ private macro fixuint(a) const EXPONENT_BITS = 15; const SIGNIFICANT_BITS = 112; $endswitch; - const MAX_EXPONENT = 1 << EXPONENT_BITS - 1; - const EXPONENT_BIAS = MAX_EXPONENT >> 1; - const ONE_REP = (ulong)EXPONENT_BIAS << SIGNIFICANT_BITS; - const SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS); - const ABS_MASK = SIGN_BIT - 1; - const IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS; - const SIGNIFICANT_MASK = IMPLICIT_BIT - 1; - const EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK; - const QUIET_BIT = IMPLICIT_BIT >> 1; - const QNAN_REP = EXPONENT_MASK | QUIET_BIT; - const INF_REP = EXPONENT_MASK; + const $Rep MAX_EXPONENT = ($Rep)1 << EXPONENT_BITS - 1u; + const $Rep EXPONENT_BIAS = MAX_EXPONENT >> 1u; + const $Rep ONE_REP =EXPONENT_BIAS << SIGNIFICANT_BITS; + const $Rep SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS); + const $Rep ABS_MASK = SIGN_BIT - 1u; + const $Rep IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS; + const $Rep SIGNIFICANT_MASK = IMPLICIT_BIT - 1u; + const $Rep EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK; + const $Rep QUIET_BIT = IMPLICIT_BIT >> 1; + const $Rep QNAN_REP = EXPONENT_MASK | QUIET_BIT; + const $Rep INF_REP = EXPONENT_MASK; $Rep rep = bitcast(a, $Rep); $Rep abs = rep & ABS_MASK; @@ -259,17 +259,17 @@ private macro fixint(a) const EXPONENT_BITS = 15; const SIGNIFICANT_BITS = 112; $endswitch; - const MAX_EXPONENT = 1 << EXPONENT_BITS - 1; - const EXPONENT_BIAS = MAX_EXPONENT >> 1; - const ONE_REP = (ulong)EXPONENT_BIAS << SIGNIFICANT_BITS; - const SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS); - const ABS_MASK = SIGN_BIT - 1; - const IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS; - const SIGNIFICANT_MASK = IMPLICIT_BIT - 1; - const EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK; - const QUIET_BIT = IMPLICIT_BIT >> 1; - const QNAN_REP = EXPONENT_MASK | QUIET_BIT; - const INF_REP = EXPONENT_MASK; + const $Rep MAX_EXPONENT = ($Rep)1 << EXPONENT_BITS - 1u; + const $Rep EXPONENT_BIAS = MAX_EXPONENT >> 1u; + const $Rep ONE_REP = EXPONENT_BIAS << SIGNIFICANT_BITS; + const $Rep SIGN_BIT = ($Rep)1 << (EXPONENT_BITS + SIGNIFICANT_BITS); + const $Rep ABS_MASK = SIGN_BIT - 1u; + const $Rep IMPLICIT_BIT = ($Rep)1 << SIGNIFICANT_BITS; + const $Rep SIGNIFICANT_MASK = IMPLICIT_BIT - 1u; + const $Rep EXPONENT_MASK = ABS_MASK ^ SIGNIFICANT_MASK; + const $Rep QUIET_BIT = IMPLICIT_BIT >> 1; + const $Rep QNAN_REP = EXPONENT_MASK | QUIET_BIT; + const $Rep INF_REP = EXPONENT_MASK; $Rep rep = bitcast(a, $Rep); $Rep abs = rep & ABS_MASK; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index f22f17baf..00692eceb 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -961,7 +961,6 @@ typedef struct typedef struct { CastKind kind : 8; - bool implicit : 1; ExprId expr; TypeInfoId type_info; } ExprCast; @@ -2027,10 +2026,14 @@ INLINE AsmRegister *asm_reg_by_index(unsigned index); AsmRegister *asm_reg_by_index(unsigned index); +bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type); bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type); +bool cast_implicit_maybe_failable(SemaContext *context, Expr *expr, Type *to_type, bool may_be_failable); +bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type); + bool cast(Expr *expr, Type *to_type); -bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option); -bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const); +bool cast_may_bool_convert(Type *type); + Type *cast_infer_len(Type *to_infer, Type *actual_type); bool cast_to_index(Expr *index); @@ -2312,6 +2315,9 @@ bool type_flat_is_boolintlike(Type *type); bool type_flat_is_numlike(Type *type); bool type_may_have_sub_elements(Type *type); bool type_may_have_method(Type *type); + +bool type_is_pointer_equivalent(Type *pointer1, Type *pointer2, bool flatten_distinct); +bool type_array_element_is_equivalent(Type *element1, Type *element2, bool is_explicit); const char *type_to_error_string(Type *type); const char *type_quoted_error_string(Type *type); INLINE bool type_may_negate(Type *type); @@ -3214,6 +3220,11 @@ INLINE bool expr_is_const_string(Expr *expr) return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_STRING; } +INLINE bool expr_is_const_pointer(Expr *expr) +{ + return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER; +} + INLINE bool expr_is_const_initializer(Expr *expr) { return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 03883f854..9f7fa9b18 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -125,9 +125,14 @@ typedef enum { CAST_OPTION_NONE = 0x00, CAST_OPTION_SIMPLE_EXPR = 0x01, - CAST_OPTION_ALLOW_OPTIONAL = 0x02, + } CastOption; +typedef enum +{ + CAST_TYPE_NO_ERROR_REPORT = 0x08, + CAST_TYPE_NO_OPTIONAL = 0x02, +} CastType; typedef enum { diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 2d016f044..a2c3e4f48 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -774,22 +774,6 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value) } -void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value) -{ - value->value = llvm_value; - value->alignment = type_abi_alignment(type_bool); - value->kind = BE_BOOLEAN; - value->type = type_bool; -} - -void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type) -{ - value->value = llvm_value; - value->alignment = type_abi_alignment(type); - value->kind = BE_BOOLVECTOR; - value->type = type; -} - void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i) { llvm_value_set(value, llvm_const_int(c, type, i), type); diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index aae561bb9..cf5db496e 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -384,7 +384,7 @@ static void llvm_emit_overflow_builtin(GenContext *c, BEValue *be_value, Expr *e LLVMValueRef failed = llvm_emit_extract_value(c, result, 1); LLVMValueRef value = llvm_emit_extract_value(c, result, 0); llvm_store_raw(c, &ref, value); - llvm_value_set_bool(be_value, failed); + llvm_value_set(be_value, failed, type_bool); } static void llvm_emit_wrap_builtin(GenContext *c, BEValue *result_value, Expr *expr, BuiltinFunction func) @@ -508,7 +508,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin UNREACHABLE } } - llvm_value_set_bool_vector(value, res, expr->type); + llvm_value_set(value, res, expr->type); return; } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index a51bf0b53..1ccefdf8b 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -189,7 +189,7 @@ static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLV } unsigned intrinsic = is_equals ? intrinsic_id.vector_reduce_and : intrinsic_id.vector_reduce_or; LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &llvm_type, 1, &val, 1); - llvm_value_set_bool(be_value, result); + llvm_value_set(be_value, result, type_bool); } static LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTypeRef coerce_type, AlignSize target_alignment, AlignSize *resulting_alignment) @@ -776,7 +776,7 @@ static inline void llvm_extract_bool_bit_from_array(GenContext *c, BEValue *be_v // Truncate to i1. element = LLVMBuildTrunc(c->builder, element, c->bool_type, ""); // Done! - llvm_value_set_bool(be_value, element); + llvm_value_set(be_value, element, type_bool); } static inline LLVMValueRef llvm_bswap_non_integral(GenContext *c, LLVMValueRef value, unsigned bitsize) @@ -2383,7 +2383,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type)); UNREACHABLE } - llvm_value_set_bool(value, llvm_value); + llvm_value_set(value, llvm_value, type_bool); return; case UNARYOP_BITNEG: llvm_emit_expr(c, value, inner); @@ -2897,7 +2897,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp if (!lhs_end_block) { // Just set any value. - llvm_value_set_bool(be_value, result_on_skip); + llvm_value_set(be_value, result_on_skip, type_bool); return; } @@ -2932,7 +2932,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp // One possibility here is that a return happens inside of the expression. if (!rhs_end_block) { - llvm_value_set_bool(be_value, result_on_skip); + llvm_value_set(be_value, result_on_skip, type_bool); return; } LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val"); @@ -2940,7 +2940,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp LLVMBasicBlockRef blocks[2] = { lhs_end_block, rhs_end_block }; LLVMAddIncoming(phi, logic_values, blocks, 2); - llvm_value_set_bool(be_value, phi); + llvm_value_set(be_value, phi, type_bool); } void llvm_emit_int_comp_zero(GenContext *c, BEValue *result, BEValue *lhs, BinaryOp binary_op) @@ -3060,7 +3060,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type llvm_convert_vector_comparison(c, result, value, lhs_type, binary_op == BINARYOP_EQ); return; } - llvm_value_set_bool(result, value); + llvm_value_set(result, value, type_bool); return; } @@ -3101,7 +3101,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type llvm_convert_vector_comparison(c, result, comp_value, lhs_type, binary_op == BINARYOP_EQ); return; } - llvm_value_set_bool(result, comp_value); + llvm_value_set(result, comp_value, type_bool); return; } @@ -3147,7 +3147,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type llvm_convert_vector_comparison(c, result, comp_value, lhs_type, BINARYOP_EQ == binary_op); return; } - llvm_value_set_bool(result, comp_value); + llvm_value_set(result, comp_value, type_bool); } static void llvm_emit_ptr_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) @@ -3180,7 +3180,7 @@ static void llvm_emit_ptr_comparison(GenContext *c, BEValue *result, BEValue *lh default: UNREACHABLE } - llvm_value_set_bool(result, val); + llvm_value_set(result, val, type_bool); } static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right, SourceSpan loc) @@ -3282,9 +3282,13 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l LLVMBasicBlockRef blocks[3] = { all_match_block, no_match_block, match_fail_block }; LLVMAddIncoming(phi, logic_values, blocks, 3); - llvm_value_set_bool(be_value, phi); + llvm_value_set(be_value, phi, type_bool); +} +static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) +{ + TODO } static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op, Type *vector_type) @@ -3324,7 +3328,7 @@ static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, llvm_convert_vector_comparison(c, be_value, val, vector_type, BINARYOP_EQ == binary_op); return; } - llvm_value_set_bool(be_value, val); + llvm_value_set(be_value, val, type_bool); } void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op) @@ -3365,6 +3369,11 @@ void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, } return; } + if (lhs->type->type_kind == TYPE_ARRAY) + { + llvm_emit_array_comp(c, result, lhs, rhs, binary_op); + return; + } TODO } @@ -3432,7 +3441,7 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr) { LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val"); LLVMAddIncoming(phi, logic_values, blocks, 2); - llvm_value_set_bool(be_value, phi); + llvm_value_set(be_value, phi, type_bool); return; } LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val"); @@ -3703,16 +3712,6 @@ void llvm_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs UNREACHABLE } assert(val); - if (lhs.type == type_bool) - { - llvm_value_set_bool(be_value, val); - return; - } - if (lhs.kind == BE_BOOLVECTOR) - { - llvm_value_set_bool_vector(be_value, val, expr->type); - return; - } llvm_value_set(be_value, val, expr->type); } @@ -3787,7 +3786,7 @@ void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_valu LLVMBasicBlockRef blocks[2] = { success_block, catch_block }; LLVMAddIncoming(phi, logic_values, blocks, 2); - llvm_value_set_bool(be_value, phi); + llvm_value_set(be_value, phi, type_bool); } @@ -4078,14 +4077,7 @@ static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *exp llvm_emit_expr(c, &right, else_expr); llvm_value_rvalue(c, &right); LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs, right.value, "elvis"); - if (right.type == type_bool) - { - llvm_value_set_bool(value, val); - } - else - { - llvm_value_set(value, val, right.type); - } + llvm_value_set(value, val, right.type); return; } @@ -4176,14 +4168,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_expr(c, &right, else_expr); llvm_value_rvalue(c, &right); LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs_value, right.value, "ternary"); - if (right.type == type_bool) - { - llvm_value_set_bool(value, val); - } - else - { - llvm_value_set(value, val, right.type); - } + llvm_value_set(value, val, right.type); return; } @@ -4228,24 +4213,14 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) if (!rhs_exit) { if (!lhs_value) lhs_value = LLVMGetUndef(llvm_get_type(c, expr->type)); - if (LLVMTypeOf(lhs_value) == c->bool_type) - { - llvm_value_set_bool(value, lhs_value); - return; - } - llvm_value_set(value, lhs_value, type_flatten(expr->type)); + llvm_value_set(value, lhs_value, expr->type); return; } if (!lhs_exit) { if (!rhs_value) rhs_value = LLVMGetUndef(llvm_get_type(c, expr->type)); - if (LLVMTypeOf(rhs_value) == c->bool_type) - { - llvm_value_set_bool(value, rhs_value); - return; - } - llvm_value_set(value, rhs_value, type_flatten(expr->type)); + llvm_value_set(value, rhs_value, expr->type); return; } @@ -4255,11 +4230,6 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) LLVMValueRef logic_values[2] = { lhs_value, rhs_value }; LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit }; LLVMAddIncoming(phi, logic_values, blocks, 2); - if (expr_type == type_bool) - { - llvm_value_set_bool(value, phi); - return; - } llvm_value_set(value, phi, expr_type); } static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f) @@ -4346,7 +4316,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) } return; case CONST_BOOL: - llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0)); + llvm_value_set(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0), type_bool); return; case CONST_STRING: { @@ -5672,7 +5642,7 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp LLVMValueRef fail_ref = decl_optional_ref(expr->try_unwrap_expr.decl); LLVMValueRef errv = llvm_load(c, llvm_get_type(c, type_anyerr), fail_ref, type_abi_alignment(type_anyerr), "load.err"); LLVMValueRef result = LLVMBuildICmp(c->builder, LLVMIntEQ, errv, llvm_get_zero(c, type_anyerr), "result"); - llvm_value_set_bool(value, result); + llvm_value_set(value, result, type_bool); return; } BEValue addr; @@ -5914,7 +5884,7 @@ void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr) LLVMBasicBlockRef blocks[2] = { next_block, fail_block }; LLVMAddIncoming(chain_result, logic_values, blocks, 2); - llvm_value_set_bool(value, chain_result); + llvm_value_set(value, chain_result, type_bool); } @@ -5958,7 +5928,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp // Check if zero: BEValue cond; - llvm_value_set_bool(&cond, LLVMBuildICmp(c->builder, LLVMIntEQ, count, llvm_get_zero(c, argc_value.type), "")); + llvm_value_set(&cond, LLVMBuildICmp(c->builder, LLVMIntEQ, count, llvm_get_zero(c, argc_value.type), ""), type_bool); LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "exit_loop"); LLVMBasicBlockRef pre_loop_block = llvm_basic_block_new(c, "pre_loop"); @@ -6006,7 +5976,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp // Add index LLVMValueRef index_plus = LLVMBuildNUWAdd(c->builder, index_var, llvm_const_int(c, type_usize, 1), ""); - llvm_value_set_bool(&cond, LLVMBuildICmp(c->builder, LLVMIntULT, index_plus, size, "")); + llvm_value_set(&cond, LLVMBuildICmp(c->builder, LLVMIntULT, index_plus, size, ""), type_bool); llvm_emit_cond_br(c, &cond, body_block, exit_block); LLVMValueRef values[2] = { index_plus, zero }; LLVMBasicBlockRef blocks[2] = { body_block, pre_loop_block }; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 11eaed70e..d62235a5f 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -258,8 +258,6 @@ static inline bool llvm_value_is_addr(BEValue *value) { return value->kind == BE static inline bool llvm_value_is_bool(BEValue *value) { return value->kind == BE_BOOLEAN; } bool llvm_value_is_const(BEValue *value); void llvm_value_rvalue(GenContext *context, BEValue *value); -void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value); -void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type); void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type); void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i); void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index b076408ea..0173bb8f7 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -141,7 +141,7 @@ void llvm_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr *expr LLVMValueRef decl_value = llvm_get_ref(context, last->decl_expr); if (bool_cast && last->decl_expr->var.unwrap) { - llvm_value_set_bool(be_value, LLVMConstInt(context->bool_type, 1, false)); + llvm_value_set(be_value, LLVMConstInt(context->bool_type, 1, false), type_bool); return; } llvm_value_set_address_abi_aligned(be_value, decl_value, type); @@ -638,7 +638,7 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, llvm_emit_comp(c, &le, &be_value, switch_value, BINARYOP_LE); BEValue ge; llvm_emit_comp(c, &ge, &to_value, switch_value, BINARYOP_GE); - llvm_value_set_bool(&equals, llvm_emit_and(c, &le, &ge)); + llvm_value_set(&equals, llvm_emit_and(c, &le, &ge), type_bool); } else { @@ -1344,7 +1344,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani LLVMBasicBlockRef panic_block = llvm_basic_block_new(c, "panic"); LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "checkok"); BEValue be_value; - llvm_value_set_bool(&be_value, value); + llvm_value_set(&be_value, value, type_bool); llvm_emit_cond_br(c, &be_value, panic_block, ok_block); llvm_emit_block(c, panic_block); llvm_emit_panic(c, panic_name, loc); diff --git a/src/compiler/llvm_codegen_value.c b/src/compiler/llvm_codegen_value.c index 9161c280a..e1b471b48 100644 --- a/src/compiler/llvm_codegen_value.c +++ b/src/compiler/llvm_codegen_value.c @@ -8,6 +8,26 @@ void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type) value->alignment = type_abi_alignment(type); value->kind = BE_VALUE; value->type = type; + + if (type == type_bool) + { + LLVMTypeRef llvm_type = LLVMTypeOf(llvm_value); + LLVMContextRef context = LLVMGetTypeContext(llvm_type); + if (llvm_type == LLVMIntTypeInContext(context, 1)) + { + value->kind = BE_BOOLEAN; + } + } + if (type_kind_is_any_vector(type->type_kind) && type->array.base == type_bool) + { + LLVMTypeRef llvm_type = LLVMTypeOf(llvm_value); + LLVMTypeRef element = LLVMGetElementType(llvm_type); + LLVMContextRef context = LLVMGetTypeContext(llvm_type); + if (element == LLVMIntTypeInContext(context, 1)) + { + value->kind = BE_BOOLVECTOR; + } + } } void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment) diff --git a/src/compiler/number.c b/src/compiler/number.c index d6bcef421..0b2a4eb2b 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -171,20 +171,30 @@ bool expr_const_float_fits_type(const ExprConst *expr_const, TypeKind kind) bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind) { - switch (kind) + switch (expr->const_kind) { - case ALL_INTS: - return !int_fits(expr->ixx, kind); - case TYPE_F16: - case TYPE_F32: - case TYPE_F64: - case TYPE_F128: + case CONST_FLOAT: return !expr_const_float_fits_type(expr, kind); - case TYPE_BOOL: + case CONST_INTEGER: + return !int_fits(expr->ixx, kind); + case CONST_BOOL: return false; - default: - UNREACHABLE + case CONST_ENUM: + { + Int i = { .i = { .low = expr->enum_err_val->var.index }, .type = type_flatten(expr->enum_err_val->type)->type_kind }; + return !int_fits(i, kind); + } + case CONST_ERR: + case CONST_BYTES: + case CONST_STRING: + case CONST_POINTER: + case CONST_TYPEID: + case CONST_INITIALIZER: + case CONST_UNTYPED_LIST: + case CONST_MEMBER: + UNREACHABLE; } + UNREACHABLE; } const char *expr_const_to_error_string(const ExprConst *expr) diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index c4d3c649b..575ca451f 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -7,6 +7,16 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "ConstantFunctionResult" +typedef struct CastOptions_ +{ + bool is_explicit; + bool may_not_be_optional; + bool no_report; +} CastOptions; + +static bool cast_may_explicit(Type *from_type, Type *to_type, bool is_const); +static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool report); +static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, CastOptions options); static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type); static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type); static Expr *recursive_may_narrow_float(Expr *expr, Type *type); @@ -14,7 +24,6 @@ static Expr *recursive_may_narrow_int(Expr *expr, Type *type); static void recursively_rewrite_untyped_list(Expr *expr, Expr **list); static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee); static inline bool cast_may_array(Type *from, Type *to, bool is_explicit); -static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option); static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) { @@ -35,22 +44,22 @@ bool sema_error_failed_cast(Expr *expr, Type *from, Type *to) return false; } + Type *cast_infer_len(Type *to_infer, Type *actual_type) { Type *may_infer = to_infer->canonical; Type *actual = actual_type->canonical; if (may_infer == actual) return to_infer; bool canonical_same_kind = may_infer->type_kind == to_infer->type_kind; + assert(type_is_arraylike(actual_type)); if (may_infer->type_kind == TYPE_INFERRED_ARRAY) { - assert(actual_type->type_kind == TYPE_ARRAY); Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->array.base, actual->array.base); return type_get_array(base_type, actual->array.len); } if (may_infer->type_kind == TYPE_INFERRED_VECTOR) { - assert(actual_type->type_kind == TYPE_VECTOR || actual->type_kind == TYPE_SCALED_VECTOR); Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->array.base, actual->array.base); if (actual_type->type_kind == TYPE_SCALED_VECTOR) { @@ -444,35 +453,14 @@ CastKind cast_to_bool_kind(Type *type) } -bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const) +static bool cast_may_explicit(Type *from_type, Type *to_type, bool is_const) { - // 1. failable -> non-failable can't be cast unless we ignore failability. - // *or* we're converting a void! to an error code - if (type_is_optional(from_type) && !type_is_optional(to_type)) - { - if (from_type->failable == type_void || !from_type->failable) - { - // void! x; anyerr y = (anyerr)(x); - if (to_type->type_kind == TYPE_FAULTTYPE || to_type->type_kind == TYPE_ANYERR) return true; - } - if (!ignore_failability) return false; - } - - // 2. Remove failability and flatten distinct - from_type = type_no_optional(from_type); - to_type = type_no_optional(to_type); - - // 3. We flatten the distinct types, since they should be freely convertible from_type = type_flatten_distinct_optional(from_type); to_type = type_flatten_distinct_optional(to_type); // 2. Same underlying type, always ok if (from_type == to_type) return true; - if (type_kind_is_any_vector(to_type->type_kind) && type_kind_is_any_vector(from_type->type_kind)) - { - return cast_may_vector(from_type, to_type, true, is_const, CAST_OPTION_NONE); - } if (type_is_any_arraylike(to_type) && type_is_any_arraylike(from_type)) { return cast_may_array(from_type, to_type, true); @@ -528,12 +516,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, // Allow conversion float -> float/int/bool/enum return type_is_integer(to_type) || type_is_float(to_type) || to_type == type_bool || to_kind == TYPE_ENUM; case TYPE_POINTER: - // Allow conversion ptr -> int (min pointer size)/bool/pointer/vararray - if ((type_is_integer(to_type) && type_size(to_type) >= type_size(type_iptr)) || to_type == type_bool || to_kind == TYPE_POINTER) return true; - // Special subarray conversion: someType[N]* -> someType[] - if (to_kind == TYPE_SUBARRAY && from_type->pointer->type_kind == TYPE_ARRAY && from_type->pointer->array.base == to_type->array.base) return true; - // Special function pointer conversion - return false; + UNREACHABLE case TYPE_ANY: return to_kind == TYPE_POINTER; case TYPE_FAULTTYPE: @@ -548,7 +531,7 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, case TYPE_STRUCT: if (type_is_substruct(from_type)) { - if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type, false, false)) return true; + if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type, false)) return true; } FALLTHROUGH; case TYPE_UNION: @@ -573,25 +556,6 @@ bool type_may_convert_to_anyerr(Type *type) return type->failable->canonical == type_void; } -static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option) -{ - if (to->array.len != from->array.len) return false; - Type *to_inner = to->array.base; - Type *from_inner = from->array.base; - if (is_explicit) - { - to_inner = type_flatten(to_inner); - from_inner = type_flatten(from_inner); - } - if (to_inner == from_inner) return true; - if (from_inner == type_bool && type_is_integer(to_inner)) return true; - if (is_explicit) - { - return cast_may_explicit(from_inner, to_inner, true, is_const); - } - return cast_may_implicit(from_inner, to_inner, option); -} - static inline bool cast_may_array(Type *from, Type *to, bool is_explicit) { RETRY:; @@ -742,182 +706,22 @@ static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee) return type_is_subtype(to_pointee, from_pointee); } -/** - * Can the conversion occur implicitly? - */ -bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option) +bool cast_may_bool_convert(Type *type) { - Type *to = to_type->canonical; - - // First handle void! => any error - if (to == type_anyerr && type_may_convert_to_anyerr(from_type)) return true; - - // any! => may implicitly to convert to any. - if (type_is_optional_any(from_type)) return (CAST_OPTION_ALLOW_OPTIONAL & option) != 0; - - // Check if optional was allowed - Type *from = from_type->canonical; - if (type_is_optional_type(from_type)) + switch (type_flatten_distinct(type)->type_kind) { - if (!(CAST_OPTION_ALLOW_OPTIONAL & option)) return false; - from = from_type->failable->canonical; - } - - // Same canonical type - we're fine. - if (from == to) return true; - - // Handle floats - if (type_is_float(to)) - { - // 2a. Any integer may convert to a float. - if (type_is_integer(from)) return true; - - // 2b. Any narrower float - if (type_is_float(from)) - { - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - if (to_size == from_size) return true; - return to_size > from_size && (option & CAST_OPTION_SIMPLE_EXPR); - } - return false; - } - - // Handle ints - if (type_is_integer(to)) - { - // For an enum, lower to the underlying enum type. - if (from->type_kind == TYPE_ENUM) - { - from = from->decl->enums.type_info->type->canonical; - } - - // 3a. Any narrower int may convert to a wider or same int, regardless of signedness. - if (type_is_integer(from)) - { - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - if (to_size == from_size) return true; - return to_size > from_size && (option & CAST_OPTION_SIMPLE_EXPR); - } - return false; - } - - // Convert any fault to anyerr - if (to == type_anyerr && from->type_kind == TYPE_FAULTTYPE) return true; - - // Handle pointers - if (type_is_pointer(to)) - { - // Assigning a subarray to a pointer - if (from->type_kind == TYPE_SUBARRAY) - { - // Casting to a void* always works. - if (to == type_voidptr) return true; - - // Compare as if it was a pointer. - return cast_may_implicit_ptr(from->array.base, to_type->pointer); - } - - // Assigning a pointer to a pointer - if (from->type_kind == TYPE_POINTER) - { - // Casting to or from a void* always works. - if (to == type_voidptr || from == type_voidptr) return true; - - return cast_may_implicit_ptr(from->pointer, to->pointer); - } - return false; - } - - if (type_kind_is_any_vector(to->type_kind) && to->type_kind == from->type_kind) - { - return cast_may_vector(from, to, false, false, option); - } - - if (type_is_any_arraylike(to) && type_is_any_arraylike(from)) - { - return cast_may_array(from, to, false); - } - - // 5. Handle sub arrays - if (to->type_kind == TYPE_SUBARRAY) - { - // 5a. char[] foo = "test" - Type *base = to->array.base; - - // 5b. Assign sized array pointer int[] = int[4]* - if (type_is_pointer(from)) - { - return from->pointer->type_kind == TYPE_ARRAY && from->pointer->array.base == base; - } - - // Allow casting void*[] to int*[] - if (from->type_kind == TYPE_SUBARRAY && from->array.base == type_voidptr && type_is_pointer(to->array.base)) - { - return true; - } - // Allow casting int*[] -> void*[] - if (from->type_kind == TYPE_SUBARRAY && to->array.base == type_voidptr && type_is_pointer(from->array.base)) - { - return true; - } - return false; - } - - - - // 8. Check if we may cast this to bool. It is safe for many types. - if (to->type_kind == TYPE_BOOL) - { - return cast_to_bool_kind(from) != CAST_ERROR; - } - - // 9. Any cast - if (to->type_kind == TYPE_ANY) - { - return from->type_kind == TYPE_POINTER; - } - - - // 11. Substruct cast, if the first member is inline, see if we can cast to this member. - if (type_is_substruct(from)) - { - return cast_may_implicit(from->decl->strukt.members[0]->type, to, option); - } - - return false; -} - -bool may_convert_float_const_implicit(Expr *expr, Type *to_type) -{ - if (!expr_const_float_fits_type(&expr->const_expr, type_flatten(to_type)->type_kind)) - { - SEMA_ERROR(expr, "The value '%g' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.fxx.f, type_quoted_error_string(to_type)); - return false; - } - return true; -} - - -bool may_convert_int_const_implicit(Expr *expr, Type *to_type) -{ - Type *to_type_flat = type_flatten(to_type); - switch (to_type_flat->type_kind) - { - case ALL_FLOATS: case TYPE_BOOL: - return true; case ALL_INTS: - break; + case ALL_FLOATS: + case TYPE_SUBARRAY: + case TYPE_POINTER: + case TYPE_ANY: + case TYPE_FAULTTYPE: + case TYPE_ANYERR: + return true; default: return false; } - if (expr_const_will_overflow(&expr->const_expr, to_type_flat->type_kind)) - { - sema_error_const_int_out_of_range(expr, expr, to_type); - return false; - } return true; } @@ -1012,11 +816,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) return recursive_may_narrow_floatid(expr->ternary_expr.else_expr, type); } case EXPR_CAST: - if (expr->cast_expr.implicit) - { - return recursive_may_narrow_floatid(expr->cast_expr.expr, type); - } - return type_size(expr->type) > type_size(type) ? expr : NULL; + return recursive_may_narrow_floatid(expr->cast_expr.expr, type); case EXPR_CONST: if (!expr->const_expr.narrowable) { @@ -1188,17 +988,9 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) return recursive_may_narrow_intid(expr->ternary_expr.else_expr, type); } case EXPR_CAST: - if (expr->cast_expr.implicit) - { - return recursive_may_narrow_intid(expr->cast_expr.expr, type); - } - return type_size(expr->type) > type_size(type) ? expr : NULL; + return recursive_may_narrow_intid(expr->cast_expr.expr, type); case EXPR_CONST: - if (!expr->const_expr.narrowable) - { - return type_size(expr->type) > type_size(type) ? expr : NULL; - } - assert(expr->const_expr.const_kind == CONST_INTEGER); + assert(expr->const_expr.const_kind == CONST_INTEGER || expr->const_expr.const_kind == CONST_ENUM); if (expr_const_will_overflow(&expr->const_expr, type_flatten(type)->type_kind)) { return expr; @@ -1268,21 +1060,20 @@ static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *t SEMA_ERROR(problem, "The unicode character U+%04x cannot fit in a %s.", (uint32_t)expr->const_expr.ixx.i.low, type_quoted_error_string(to_type)); return; } + if (expr->const_expr.const_kind == CONST_ENUM) + { + SEMA_ERROR(problem, "The ordinal '%d' is out of range for %s, so you need an explicit cast to truncate the value.", + expr->const_expr.enum_err_val->var.index, + type_quoted_error_string(to_type)); + return; + } const char *error_value = expr->const_expr.is_hex ? int_to_str(expr->const_expr.ixx, 16) : expr_const_to_error_string(&expr->const_expr); SEMA_ERROR(problem, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", error_value, type_quoted_error_string(to_type)); } -static inline bool cast_maybe_null_to_distinct_voidptr(Expr *expr, Type *expr_canonical, Type *to_canonical) -{ - if (expr->expr_kind != EXPR_CONST || expr->const_expr.const_kind != CONST_POINTER) return false; - if (expr_canonical != type_voidptr) return false; - if (expr->const_expr.ptr) return false; - if (to_canonical->type_kind != TYPE_DISTINCT) return false; - return to_canonical->decl->distinct_decl.base_type->canonical->type_kind == TYPE_POINTER; -} -static inline bool cast_maybe_string_lit_to_char_array(Expr *expr, Type *expr_canonical, Type *to_canonical) +static inline bool cast_maybe_string_lit_to_char_array(Expr *expr, Type *expr_canonical, Type *to_canonical, Type *to_original) { if (expr->expr_kind != EXPR_CONST || expr->const_expr.const_kind != CONST_STRING) return false; if (expr_canonical->type_kind != TYPE_POINTER) return false; @@ -1291,11 +1082,13 @@ static inline bool cast_maybe_string_lit_to_char_array(Expr *expr, Type *expr_ca Type *pointer = expr_canonical->pointer; if (pointer->type_kind != TYPE_ARRAY) return false; if (pointer->array.base != type_char) return false; + assert(!type_is_optional(expr->type)); if (to_canonical->type_kind == TYPE_INFERRED_ARRAY) { - to_canonical = type_get_array(to_canonical->array.base, pointer->array.len); + assert(to_original->type_kind == TYPE_INFERRED_ARRAY); + to_original = type_get_array(to_original->array.base, pointer->array.len); } - expr->type = to_canonical; + expr->type = to_original; return true; } @@ -1322,129 +1115,599 @@ static void recursively_rewrite_untyped_list(Expr *expr, Expr **list) bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) { - assert(!type_is_optional(to_type)); - Type *expr_type = expr->type; - Type *expr_canonical = expr_type->canonical; - Type *to_canonical = to_type->canonical; - if (cast_maybe_string_lit_to_char_array(expr, expr_canonical, to_canonical)) + return cast_expr_inner(context, expr, to_type, (CastOptions) { .no_report = false }); +} + +bool cast_implicit_maybe_failable(SemaContext *context, Expr *expr, Type *to_type, bool may_be_failable) +{ + return cast_expr_inner(context, expr, to_type, (CastOptions) { .may_not_be_optional = !may_be_failable }); +} + +bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type) +{ + return cast_expr_inner(context, expr, to_type, (CastOptions){ .no_report = true }); +} + +bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type) +{ + if (!cast_expr_inner(context, expr, to_type, (CastOptions) { .is_explicit = true })) return false; + if (expr_is_const(expr)) expr->const_expr.narrowable = false; + return true; +} + +static inline bool cast_with_optional(Expr *expr, Type *to_type, bool add_optional) +{ + if (!cast(expr, to_type)) return false; + if (add_optional) expr->type = type_add_optional(expr->type, true); + return true; +} + +static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool no_report) +{ + if (no_report) return false; + if (may_cast_explicit) { - expr_type = expr->type; - expr_canonical = expr_type->canonical; + SEMA_ERROR(expr, + "Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.", + type_quoted_error_string(type_no_optional(expr->type)), + type_quoted_error_string(to), + type_to_error_string(type_no_optional(to))); } - if (cast_maybe_null_to_distinct_voidptr(expr, expr_canonical, to_canonical)) + else { + SEMA_ERROR(expr, + "It is not possible to convert %s to %s.", + type_quoted_error_string(type_no_optional(expr->type)), type_quoted_error_string(to)); + } + return false; + +} + +static inline bool cast_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + switch (to->type_kind) + { + case TYPE_SUBARRAY: + if (type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) goto CAST; + return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), options.no_report); + case TYPE_POINTER: + if (type_array_element_is_equivalent(from->array.base, to->pointer, options.is_explicit)) goto CAST; + return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->pointer, true), options.no_report); + case TYPE_BOOL: + if (!options.is_explicit) goto CAST_MAY_EXPLICIT; + goto CAST; + default: + goto CAST_ILLEGAL; + } +CAST_ILLEGAL: + return sema_error_cannot_convert(expr, to_type, false, options.no_report); +CAST_MAY_EXPLICIT: + return sema_error_cannot_convert(expr, to_type, true, options.no_report); +CAST: + return cast_with_optional(expr, to_type, add_optional); +} + +static inline bool cast_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + bool infer_type = false; + switch (to->type_kind) + { + case TYPE_INFERRED_ARRAY: + case TYPE_INFERRED_VECTOR: + infer_type = true; + goto CAST_ELEMENT; + case TYPE_VECTOR: + case TYPE_ARRAY: + if (to->array.len != from->array.len) goto CAST_ILLEGAL; + goto CAST_ELEMENT; + case TYPE_STRUCT: + if (type_is_structurally_equivalent(from, to)) + { + if (options.is_explicit) goto CAST; + if (options.no_report) return false; + return sema_error_cannot_convert(expr, to_type, true, options.no_report); + } + default: + goto CAST_ILLEGAL; + } +CAST_ELEMENT: + if (!type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) + { + if (!options.no_report && !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true)) + { + return sema_error_cannot_convert(expr, to_type, true, options.no_report); + } + goto CAST_ILLEGAL; + } +CAST: + if (infer_type) + { + to_type = cast_infer_len(to_type, from); + } + return cast_with_optional(expr, to_type, add_optional); +CAST_ILLEGAL: + return sema_error_cannot_convert(expr, to_type, false, options.no_report); +} + +static bool cast_may_number_convert(Expr *expr, Type *from, Type *to, bool is_explicit, bool cast_from_bool) +{ + // Same canonical type - we're fine. + if (from == to) return true; + + if (from->type_kind == TYPE_DISTINCT || to->type_kind == TYPE_DISTINCT) return false; + + // Handle floats + if (type_is_float(to)) + { + // Any integer may convert to a float. + if (type_is_integer(from)) return true; + + // Cast from bool if explicit or cast from bool. + if (from == type_bool) return cast_from_bool || is_explicit; + + // Any narrower float + if (type_is_float(from)) + { + if (is_explicit) return true; + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size == from_size) return true; + return to_size > from_size && expr_is_simple(expr); + } + + UNREACHABLE; + } + + // Handle ints + if (type_is_integer(to)) + { + if (type_is_float(from)) return is_explicit; + + // Cast from bool if explicit or cast from bool. + if (from == type_bool) return cast_from_bool || is_explicit; + + if (type_is_integer(from)) + { + if (is_explicit) return true; + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size == from_size) return true; + return to_size > from_size && expr_is_simple(expr); + } + + UNREACHABLE + } + assert(to == type_bool); + if (!is_explicit) return false; + return true; +} +static inline bool cast_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + bool is_scaled = from->type_kind == TYPE_SCALED_VECTOR; + bool to_vector = type_kind_is_any_vector(to->type_kind); + bool infer_len = false; + switch (to->type_kind) + { + case TYPE_INFERRED_ARRAY: + infer_len = true; + if (is_scaled) goto CAST_ILLEGAL; + goto TRY_CAST; + case TYPE_INFERRED_VECTOR: + infer_len = true; + if (is_scaled) goto CAST_ILLEGAL; + goto TRY_CONVERT; + case TYPE_ARRAY: + if (is_scaled || to->array.len != from->array.len) goto CAST_ILLEGAL; + goto TRY_CAST; + case TYPE_VECTOR: + if (is_scaled || to->array.len != from->array.len) goto CAST_ILLEGAL; + goto TRY_CONVERT; + case TYPE_SCALED_VECTOR: + if (!is_scaled) goto CAST_ILLEGAL; + goto TRY_CONVERT; + default: + goto CAST_ILLEGAL; + } +TRY_CONVERT: + if (cast_may_number_convert(expr, from->array.base, to->array.base, options.is_explicit, to_vector)) goto CAST; + return sema_error_cannot_convert(expr, to, !options.is_explicit && cast_may_number_convert(expr, from->array.base, to->array.base, true, to_vector), options.no_report); +TRY_CAST: + if (type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) goto CAST; + if (options.no_report) return false; + return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), true); +CAST_ILLEGAL: + return sema_error_cannot_convert(expr, to_type, false, options.no_report); +CAST: + if (infer_len) to_type = cast_infer_len(to_type, from); + return cast_with_optional(expr, to_type, add_optional); +} + +static inline bool cast_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + bool no_report = options.no_report; +RETRY: + switch (to->type_kind) + { + case ALL_FLOATS: + goto CAST; + case TYPE_BOOL: + if (options.is_explicit) goto CAST; + goto REQUIRE_CAST; + case TYPE_ENUM: + if (from->type_kind == TYPE_ENUM) break; + to = to->decl->enums.type_info->type->canonical; + if (options.is_explicit) to = type_flatten_distinct(to); + FALLTHROUGH; + case ALL_INTS: + { + if (options.is_explicit) goto CAST; + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size > from_size) goto ONLY_SIMPLE; + if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind)) + { + sema_error_const_int_out_of_range(expr, expr, to_type); + return false; + } + if (to_size == from_size) goto CAST; + Expr *problem = recursive_may_narrow_int(expr, to); + if (problem) + { + if (no_report) return false; + goto REQUIRE_CAST; + } + goto CAST; + } + case TYPE_DISTINCT: + if (expr_is_const(expr)) + { + to = type_flatten_distinct(to); + goto RETRY; + } + else + { + if (no_report) return false; + bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, (CastOptions) { .is_explicit = true, .no_report = true }); + if (may_explicit) goto REQUIRE_CAST; + break; + } + case TYPE_POINTER: + { + if (from->type_kind == TYPE_ENUM) break; + bool may_cast = expr_is_const(expr) || type_size(from) >= type_size(type_voidptr); + if (!options.is_explicit) + { + if (may_cast) goto REQUIRE_CAST; + break; + } + if (!may_cast) + { + if (no_report) return false; + SEMA_ERROR(expr, "You cannot cast from a type smaller than %s.", + type_quoted_error_string(type_iptr)); + return false; + } + goto CAST; + } + default: + break; + } + return sema_error_cannot_convert(expr, to_type, false, no_report); +ONLY_SIMPLE: + if (expr_is_simple(expr)) goto CAST; + if (no_report) return false; + SEMA_ERROR(expr, "This conversion requires an explicit cast to %s, because the widening of the expression may be done in more than one way.", type_quoted_error_string(to_type)); + return false; +REQUIRE_CAST: + if (no_report) return false; + SEMA_ERROR(expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); + return false; +CAST: + return cast_with_optional(expr, to_type, add_optional); +} + +static inline bool cast_float(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + bool no_report = options.no_report; +RETRY: + switch (to->type_kind) + { + case ALL_INTS: + case TYPE_BOOL: + if (options.is_explicit) goto CAST; + goto REQUIRE_CAST; + case ALL_FLOATS: + { + if (options.is_explicit) goto CAST; + ByteSize to_size = type_size(to); + ByteSize from_size = type_size(from); + if (to_size > from_size) goto ONLY_SIMPLE; + if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind)) + { + if (options.no_report) return false; + SEMA_ERROR(expr, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", expr_const_to_error_string(&expr->const_expr), + type_quoted_error_string(to_type)); + return false; + } + if (to_size == from_size) goto CAST; + Expr *problem = recursive_may_narrow_float(expr, to); + if (problem) + { + if (no_report) return false; + goto REQUIRE_CAST; + } + goto CAST; + } + case TYPE_DISTINCT: + if (expr_is_const(expr)) + { + to = type_flatten_distinct(to); + goto RETRY; + } + else + { + if (no_report) return false; + bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, (CastOptions) { .is_explicit = true, .no_report = true }); + if (may_explicit) goto REQUIRE_CAST; + break; + } + default: + break; + } + return sema_error_cannot_convert(expr, to_type, false, no_report); +ONLY_SIMPLE: + if (expr_is_simple(expr)) goto CAST; + if (no_report) return false; + SEMA_ERROR(expr, "This conversion requires an explicit cast to %s, because the widening of the expression may be done in more than one way.", type_quoted_error_string(to_type)); + return false; +REQUIRE_CAST: + if (no_report) return false; + SEMA_ERROR(expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); + return false; +CAST: + return cast_with_optional(expr, to_type, add_optional); +} + +static inline bool cast_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +{ + // pointer -> any, void* -> pointer pointer -> void* + if (to == type_any || to == type_voidptr || from == type_voidptr) return cast_with_optional(expr, to_type, add_optional); + + Type *pointee = from->pointer; + bool is_explicit = options.is_explicit; + pointee = is_explicit ? type_flatten(pointee) : pointee->canonical; + TypeKind pointee_kind = pointee->type_kind; + switch (to->type_kind) + { + case ALL_INTS: + if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, options.no_report); + if (type_size(to_type) < type_size(type_iptr)) + { + SEMA_ERROR(expr, "Casting %s to %s is not allowed because '%s' is smaller than a pointer. " + "Use (%s)(iptr) if you want this lossy cast.", + type_quoted_error_string(expr->type), type_quoted_error_string(to_type), + type_to_error_string(to_type), type_to_error_string(to_type)); + return false; + } + return cast_with_optional(expr, to_type, add_optional); + case TYPE_SUBARRAY: + // int[<2>], int[2], int[<*>] + if (pointee_kind == TYPE_ARRAY || pointee_kind == TYPE_VECTOR || pointee_kind == TYPE_SCALED_VECTOR) + { + Type *subarray_base = to->array.base->canonical; + Type *from_base = pointee->array.base; + if (is_explicit) + { + subarray_base = type_flatten_distinct(subarray_base); + from_base = type_flatten_distinct(from_base); + } + if (subarray_base == from_base) return cast_with_optional(expr, to_type, add_optional); + if (subarray_base->type_kind == TYPE_POINTER && from_base->type_kind == TYPE_POINTER) + { + if (type_is_pointer_equivalent(subarray_base, from_base, is_explicit)) return cast_with_optional(expr, to_type, add_optional); + } + if (options.no_report) return false; + bool would_work_explicit = false; + if (!is_explicit) + { + options.is_explicit = true; + options.no_report = true; + would_work_explicit = cast_pointer(context, expr_copy(expr), from, to, to_type, add_optional, options); + } + return sema_error_cannot_convert(expr, to_type, would_work_explicit, false); + } + return sema_error_cannot_convert(expr, to_type, false, options.no_report); + case TYPE_BOOL: + if (is_explicit) return cast_with_optional(expr, to_type, add_optional); + return sema_error_cannot_convert(expr, to_type, true, options.no_report); + case TYPE_POINTER: + if (is_explicit) return cast_with_optional(expr, to_type, add_optional); + if (cast_may_implicit_ptr(from->pointer, to->pointer)) + { + return cast_with_optional(expr, to_type, add_optional); + } + return sema_error_cannot_convert(expr, to_type, true, options.no_report); + case TYPE_FAILABLE_ANY: + case TYPE_OPTIONAL: + UNREACHABLE + default: + return sema_error_cannot_convert(expr, to_type, false, options.no_report); + } +} +/** + * Do the following: + * 1. Special optional conversions. + * 2. String literal conversions + * 3. Constant pointer conversions + */ +static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, CastOptions options) +{ + Type *from_type = expr->type; + + assert(!type_is_optional(to_type) || options.may_not_be_optional); + bool is_explicit = options.is_explicit; + Type *to = is_explicit ? type_flatten_distinct_optional(to_type) : type_no_optional(to_type)->canonical; + + // Step one, cast from optional. + // This handles: + // 1. *! -> any type + // 2. void! -> anyerr + // 3. void! -> SomeFault (explicit) + if (type_is_optional(from_type)) + { + // *! -> int => ok, gives int! + if (from_type == type_anyfail) + { + if (options.may_not_be_optional) + { + if (options.no_report) return false; + SEMA_ERROR(expr, "An optional value cannot be converted to a non-optional %s.", type_quoted_error_string(to_type)); + return false; + } + // Just add the optional. + expr->type = type_add_optional(to_type, true); + return true; + } + + // Here we have something like int! + assert(from_type->type_kind == TYPE_OPTIONAL); + + // If it is void!, then there are special rules: + if (from_type->failable == type_void) + { + // void! x; anyerr y = x; + if (!type_is_optional(to_type) && to == type_anyerr) + { + cast(expr, to_type); + return true; + } + + // void! x; FooFault y = (FooFault)x; + // Only allowed if explicit. + if (to->type_kind == TYPE_FAULTTYPE) + { + if (!is_explicit) + { + if (options.no_report) return false; + SEMA_ERROR(expr, "A 'void!' can only be cast into %s using an explicit cast. You can try using (%s)", + type_quoted_error_string(to_type), type_to_error_string(to_type)); + return false; + } + cast(expr, to_type); + return true; + } + } + if (options.may_not_be_optional) + { + if (options.no_report) return false; + char *format = is_explicit ? "Cannot cast an optional %s to %s." : "Cannot convert an optional %s to %s."; + SEMA_ERROR(expr, format, type_quoted_error_string(from_type), type_quoted_error_string(to_type)); + return false; + } + } + + // We're now done and can remove the optional + bool add_optional = type_is_optional(to_type) || type_is_optional(from_type); + to_type = type_no_optional(to_type); + from_type = type_no_optional(from_type); + + // Grab the underlying expression type. + Type *from = is_explicit ? type_flatten_distinct(from_type) : from_type->canonical; + + // We may already be done. + if (from == to) + { + expr->type = type_add_optional(to_type, add_optional); return true; } - if (expr_canonical == to_canonical) return true; - if (expr_type == type_untypedlist) + + + // Handle strings, these don't actually mess with the underlying data, + // just the type. + if (cast_maybe_string_lit_to_char_array(expr, from, to, to_type)) return true; + + // For constant pointers cast into anything pointer-like: + if (expr_is_const_pointer(expr) && from == type_voidptr && type_flatten_distinct(to)->type_kind == TYPE_POINTER) { - return cast_untyped_to_type(context, expr, to_type); + assert(!add_optional); + expr->type = to_type; + return true; } - CastOption option = CAST_OPTION_ALLOW_OPTIONAL; - if (expr_is_simple(expr)) option |= CAST_OPTION_SIMPLE_EXPR; - - if (!cast_may_implicit(expr_canonical, to_canonical, option)) + switch (from->type_kind) { - if (!cast_may_explicit(expr_canonical, to_canonical, false, expr->expr_kind == EXPR_CONST)) + case TYPE_UNTYPED_LIST: + if (!cast_untyped_to_type(context, expr, to_type)) return false; + if (add_optional) expr->type = type_add_optional(expr->type, true); + return true; + case TYPE_FAULTTYPE: + if (to == type_anyerr) return cast(expr, to_type); + if (type_is_integer(to) || to == type_bool) goto CAST_IF_EXPLICIT; + goto CAST_FAILED; + case TYPE_ANYERR: + if (to_type == type_bool || to->type_kind == TYPE_FAULTTYPE || type_is_integer(to)) + { + goto CAST_IF_EXPLICIT; + } + goto CAST_FAILED; + case TYPE_POINTER: + return cast_pointer(context, expr, from, to, to_type, add_optional, options); + case TYPE_SUBARRAY: + return cast_subarray(context, expr, from, to, to_type, add_optional, options); + case TYPE_BOOL: + // Bool may convert into integers and floats but only explicitly. + if (type_is_integer(to) || type_is_float(to)) goto CAST_IF_EXPLICIT; + goto CAST_FAILED; + case TYPE_VECTOR: + case TYPE_SCALED_VECTOR: + return cast_vector(context, expr, from, to, to_type, add_optional, options); + case TYPE_ARRAY: + return cast_array(context, expr, from, to, to_type, add_optional, options); + case TYPE_ENUM: + case ALL_INTS: + return cast_integer(context, expr, from, to, to_type, add_optional, options); + case ALL_FLOATS: + return cast_float(context, expr, from, to, to_type, add_optional, options); + default: + break; + } + + if (!options.is_explicit && options.no_report) return false; + if (!cast_may_explicit(from_type, to_type, expr_is_const(expr))) + { + if (!options.is_explicit && !options.no_report) { - if (expr_canonical->type_kind == TYPE_OPTIONAL && to_canonical->type_kind != TYPE_OPTIONAL) - { - SEMA_ERROR(expr, "An optional %s cannot be converted to %s.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); - return false; - } - if (to_canonical->type_kind == TYPE_ANY) - { - SEMA_ERROR(expr, "You can only convert pointers to 'variant', take the address of this expression first."); - return false; - } SEMA_ERROR(expr, "You cannot cast %s into %s even with an explicit cast, so this looks like an error.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); return false; } - bool is_narrowing = type_size(expr_canonical) >= type_size(to_canonical); - if (expr->expr_kind == EXPR_CONST && expr->const_expr.narrowable && is_narrowing) - { - Type *expr_flatten = type_flatten_distinct(expr_canonical); - Type *to_flatten = type_flatten_distinct(to_canonical); - if (type_is_integer(expr_flatten) && type_is_integer(to_flatten)) - { - Expr *problem = recursive_may_narrow_int(expr, to_canonical); - if (problem) - { - sema_error_const_int_out_of_range(expr, problem, to_type); - return false; - } - goto OK; - } - if (type_is_float(expr_flatten) && type_is_float(to_flatten)) - { - Expr *problem = recursive_may_narrow_float(expr, to_canonical); - if (problem) - { - SEMA_ERROR(problem, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", expr_const_to_error_string(&expr->const_expr), - type_quoted_error_string(to_type)); - return false; - } - goto OK; - } - } - if (type_is_integer(expr_canonical) && type_is_integer(to_canonical) && is_narrowing) - { - Expr *problem = recursive_may_narrow_int(expr, to_canonical); - if (problem) - { - SEMA_ERROR(problem, "Cannot narrow %s to %s.", type_quoted_error_string(problem->type), - type_quoted_error_string(to_type)); - return false; - } - goto OK; - } - if (type_is_float(expr_canonical) && type_is_float(to_canonical) && is_narrowing) - { - Expr *problem = recursive_may_narrow_float(expr, to_canonical); - if (problem) - { - if (problem->expr_kind == EXPR_CONST) - { - SEMA_ERROR(problem, "The value '%s' is out of range for %s.", expr_const_to_error_string(&problem->const_expr), - type_quoted_error_string(to_type)); - } - else - { - SEMA_ERROR(problem, "This expression cannot be implicitly narrowed."); - } - return false; - } - goto OK; - } - SEMA_ERROR(expr, "Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.", type_quoted_error_string( - type_no_optional(expr->type)), type_quoted_error_string(type_no_optional(to_type)), + if (!options.no_report) sema_error_failed_cast(expr, type_no_optional(expr->type), to_type); + return false; + } +CAST_IF_EXPLICIT: + if (!options.is_explicit) + { + if (options.no_report) return false; + SEMA_ERROR(expr, + "Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.", + type_quoted_error_string(type_no_optional(from_type)), + type_quoted_error_string(type_no_optional(to_type)), type_to_error_string(to_type)); return false; } - - OK: - // Additional checks for compile time values. - if (expr->expr_kind == EXPR_CONST && expr->const_expr.narrowable) + return cast(expr, to_type); +CAST_FAILED: + if (!options.no_report) { - if (type_is_float(expr->type)) + if (!options.is_explicit) { - if (!may_convert_float_const_implicit(expr, to_type)) return false; - } - else if (type_is_integer(expr->type)) - { - if (!may_convert_int_const_implicit(expr, to_type)) return false; + SEMA_ERROR(expr, "You cannot cast %s into %s even with an explicit cast, so this looks like an error.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); + return false; } + return sema_error_failed_cast(expr, expr->type, to_type); } - cast(expr, to_type); - // Allow narrowing after widening - if (type_is_numeric(to_type) && expr->expr_kind == EXPR_CONST && type_size(expr_canonical) < type_size(to_canonical)) - { - expr->const_expr.narrowable = true; - } - if (expr->expr_kind == EXPR_CAST) expr->cast_expr.implicit = true; - return true; + return false; } + static bool arr_to_vec(Expr *expr, Type *to_type) { if (insert_runtime_cast_unless_const(expr, CAST_ARRVEC, to_type)) return true; @@ -1626,7 +1889,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) { case TYPE_FAILABLE_ANY: case TYPE_OPTIONAL: - UNREACHABLE case TYPE_VOID: UNREACHABLE case TYPE_DISTINCT: @@ -1683,6 +1945,12 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (type_is_float(to)) return enum_to_float(expr, from_type, to, to_type); if (to == type_bool) return enum_to_bool(expr, from_type, to_type); if (to->type_kind == TYPE_POINTER) return enum_to_pointer(expr, from_type, to_type); + if (to->type_kind == TYPE_ENUM) + { + Type *temp = type_flatten(to); + if (!enum_to_integer(expr, from_type, temp, temp)) return false; + return integer_to_enum(expr, to, to_type); + } break; case TYPE_FAULTTYPE: if (to->type_kind == TYPE_ANYERR) return err_to_anyerr(expr, to_type); @@ -1823,8 +2091,8 @@ bool cast_to_index(Expr *index) bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type) { - Type *to = type; - Type *from = expr->type; + Type *to = type_no_optional(type); + Type *from = type_no_optional(expr->type); RETRY: if (type_is_integer(from) && type_is_integer(to)) goto CONVERT_IF_BIGGER; if (type_is_float(from) && type_is_float(to)) goto CONVERT_IF_BIGGER; @@ -1884,7 +2152,10 @@ bool cast_decay_array_pointers(SemaContext *context, Expr *expr) { CanonicalType *pointer_type = type_pointer_type(type_no_optional(expr->type)); if (!pointer_type || !type_is_arraylike(pointer_type)) return true; - return cast_implicit(context, expr, type_add_optional(type_get_ptr(pointer_type->array.base), IS_OPTIONAL(expr))); + return cast_expr_inner(context, + expr, + type_add_optional(type_get_ptr(pointer_type->array.base), IS_OPTIONAL(expr)), + (CastOptions) { .is_explicit = true }); } void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e4d07b298..ded2b8519 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -910,7 +910,25 @@ static inline bool sema_binary_promote_top_down(SemaContext *context, Expr *bina static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *binary, Expr *left, Expr *right) { - return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right); + if (right->expr_kind == EXPR_INITIALIZER_LIST) + { + if (!sema_analyse_expr(context, left)) return false; + if (type_kind_is_any_vector(type_flatten(left->type)->type_kind)) + { + return sema_analyse_inferred_expr(context, left->type, right); + } + return sema_analyse_expr(context, right); + } + if (left->expr_kind == EXPR_INITIALIZER_LIST) + { + if (!sema_analyse_expr(context, right)) return false; + if (type_kind_is_any_vector(type_flatten(right->type)->type_kind)) + { + return sema_analyse_inferred_expr(context, right->type, right); + } + return sema_analyse_expr(context, left); + } + return sema_analyse_expr(context, left) && sema_analyse_expr(context, right); } static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed) @@ -1804,14 +1822,13 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s inferred_len = false; } } - if (!cast_may_implicit(type, rtype, CAST_OPTION_SIMPLE_EXPR | (may_failable ? CAST_OPTION_ALLOW_OPTIONAL : 0)) || inferred_len) + bool success = cast_implicit_silent(context, ret_expr, rtype); + if (inferred_len || (!may_failable && IS_OPTIONAL(ret_expr)) || !success) { SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype), type_quoted_error_string(type)); return SCOPE_POP_ERROR(); } - bool success = cast_implicit(context, ret_expr, rtype); - assert(success); if (may_failable) ret_expr->type = type_add_optional(ret_expr->type, may_failable); } call_expr->type = type_add_optional(rtype, failable); @@ -2523,7 +2540,12 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) if (end && end->type != start->type) { Type *common = type_find_max_type(start->type, end->type); - if (!common || !cast_implicit(context, start, common) || !cast_implicit(context, end, common)) return false; + if (!common) + { + SEMA_ERROR(expr, "No common type can be found between start and end index."); + return false; + } + if (!cast_implicit(context, start, common) || !cast_implicit(context, end, common)) return false; } bool start_from_end = expr->subscript_expr.range.start_from_end; @@ -3816,14 +3838,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr) expr_replace(expr, inner); return true; } - if (!cast_may_explicit(inner->type, target_type, true, inner->expr_kind == EXPR_CONST)) - { - return sema_error_failed_cast(expr, type_no_optional(inner->type), target_type); - } - if (!cast(inner, target_type)) - { - return expr_poison(expr); - } + if (!cast_explicit(context, inner, target_type)) return expr_poison(expr); expr_replace(expr, inner); return true; } @@ -3853,8 +3868,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ Range *left_range = &left->subscript_expr.range; Range *right_range = &right->subscript_expr.range; if (!sema_analyse_expr(context, right)) return false; - if (cast_may_implicit(right->type, base, CAST_OPTION_SIMPLE_EXPR)) goto ASSIGN; - if (!cast_implicit(context, right, left_type)) return false; + if (!cast_implicit_silent(context, right, left_type)) goto ASSIGN; IndexDiff left_len = range_const_len(left_range); IndexDiff right_len = range_const_len(right_range); if (left_len >= 0 && right_len >= 0 && left_len != right_len) @@ -3885,8 +3899,9 @@ bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type } // 1. Evaluate right side to required type. - if (!sema_analyse_expr_rhs(context, left_type, right, true)) return false; - if (IS_OPTIONAL(right) && !type_is_optional(left_type)) + bool to_optional = left_type && type_is_optional(left_type); + if (!sema_analyse_expr_rhs(context, left_type, right, is_unwrapped || to_optional)) return false; + if (IS_OPTIONAL(right) && !to_optional) { if (is_unwrapped) { @@ -4112,12 +4127,7 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr * // 5. Cast the right hand side to the one on the left if (!sema_analyse_expr(context, right)) return false; - if (!cast_implicit(context, right, no_fail)) return false; - if (IS_OPTIONAL(right) && !IS_OPTIONAL(left)) - { - SEMA_ERROR(right, "This expression cannot be failable, since the assigned variable isn't."); - return false; - } + if (!cast_implicit_maybe_failable(context, right, no_fail, IS_OPTIONAL(left))) return false; // 6. Check for zero in case of div or mod. if (right->expr_kind == EXPR_CONST) { @@ -4252,7 +4262,8 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E SEMA_ERROR(parent, error_message, type_quoted_error_string(left->type), type_quoted_error_string(right->type)); return false; } - return cast_implicit(context, left, max) && cast_implicit(context, right, max); + return cast_implicit(context, left, max) && + cast_implicit(context, right, max); } static void sema_binary_unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref) @@ -4276,8 +4287,7 @@ static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff) // (iptr)((char*)(ptr) +- 1) if (maybe_pointer->expr_kind == EXPR_CAST && maybe_pointer->cast_expr.kind == CAST_PTRXI - && type_flatten(maybe_pointer->type) == type_flatten(type_iptr) - && cast_may_implicit(maybe_diff->type, maybe_diff->type, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL)) + && type_flatten(maybe_pointer->type) == type_flatten(type_iptr)) { Type *cast_to_iptr = maybe_pointer->type; maybe_pointer->cast_expr.kind = CAST_PTRPTR; @@ -4858,7 +4868,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp static bool sema_expr_analyse_and_or(SemaContext *context, Expr *expr, Expr *left, Expr *right) { if (!sema_binary_analyse_subexpr(context, expr, left, right)) return false; - if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false; + if (!cast_explicit(context, left, type_bool) || !cast_explicit(context, right, type_bool)) return false; if (expr_both_const(left, right)) { @@ -5330,17 +5340,35 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) // 2. Check whether the type is a vector Type *type = type_no_optional(inner->type); - if (type_flat_is_vector(type)) + Type *flat = type_flatten_distinct(type); + if (type_kind_is_any_vector(flat->type_kind)) { - // 3. This always works, so we're done. - expr->type = type_add_optional(type_get_vector_bool(type), IS_OPTIONAL(inner)); - return true; + // This may be some form of bool vector. + if (type_flatten(flat->array.base) == type_bool) + { + // If so then we're done. + expr->type = type; + return true; + } + Type *canonical = type->canonical; + switch (canonical->type_kind) + { + case TYPE_VECTOR: + expr->type = type_get_vector(type_bool, canonical->array.len); + return true; + case TYPE_SCALED_VECTOR: + expr->type = type_get_scaled_vector(type_bool); + return true; + case TYPE_INFERRED_VECTOR: + UNREACHABLE; + default: + break; + } } - // 4. Let's see if it's possible to cast it implicitly - if (!cast_may_implicit(type, type_bool, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL)) + if (!cast_may_bool_convert(type)) { - SEMA_ERROR(expr, "The use of '!' on %s is not allowed as it can't be converted to a boolean value.", type_quoted_error_string(inner->type)); + SEMA_ERROR(expr, "The %s can't be converted to a boolean value.", type_quoted_error_string(inner->type)); return false; } @@ -5348,7 +5376,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) if (inner->expr_kind == EXPR_CONST) { - bool success = cast_implicit(context, inner, expr->type); + bool success = cast_explicit(context, inner, expr->type); assert(success); assert(inner->const_expr.const_kind == CONST_BOOL); expr->const_expr.const_kind = CONST_BOOL; @@ -6856,7 +6884,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr) type_quoted_error_string(expr->type)); return false; } - return cast_implicit(context, expr, type_bool); + return cast_explicit(context, expr, type_bool); } @@ -6877,7 +6905,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo return false; } } - if (to && !cast_implicit(context, expr, to)) return false; + if (to && !cast_implicit_maybe_failable(context, expr, to, allow_failable)) return false; if (!allow_failable && IS_OPTIONAL(expr)) { SEMA_ERROR(expr, "You cannot have a failable here."); diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 38a7bb8f4..e4df5d8e1 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -27,6 +27,12 @@ #define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK() #define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST) +typedef enum +{ + REPORT_ERROR, + REPORT_NONE, +} ReportType; + typedef enum { SPLIT_PATH_IDENT, diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 55314e81f..1e0e5106b 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -898,21 +898,16 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType } return true; } - // 3a. Check for failables in case of an expression. + // 3a. Check for optional in case of an expression. if (IS_OPTIONAL(last)) { - if (!cast_to_bool || cast_may_implicit(type_no_optional(last->type), type_bool, CAST_OPTION_NONE)) - { - SEMA_ERROR(last, "The expression may not be a failable, but was %s.", type_quoted_error_string(last->type)); - return false; - } - sema_error_failed_cast(last, type_no_optional(last->type), type_bool); + SEMA_ERROR(last, "The expression may not be an optional, but was %s.", type_quoted_error_string(last->type)); return false; } // 3b. Cast to bool if that is needed if (cast_to_bool) { - if (!cast_implicit(context, last, type_bool)) return false; + if (!cast_explicit(context, last, type_bool)) return false; } return true; } diff --git a/src/compiler/types.c b/src/compiler/types.c index 739280012..4435b0c80 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1633,6 +1633,71 @@ Type *type_from_token(TokenType type) } } +bool type_array_element_is_equivalent(Type *element1, Type *element2, bool is_explicit) +{ + RETRY: + if (is_explicit) + { + element1 = type_flatten_distinct(element1); + element2 = type_flatten_distinct(element2); + } + else + { + element1 = element1->canonical; + element2 = element2->canonical; + } + if (element1 == element2) return true; + switch (element1->type_kind) + { + case TYPE_POINTER: + if (element2->type_kind != TYPE_POINTER) return false; + return type_is_pointer_equivalent(element1, element2, is_explicit); + case TYPE_ARRAY: + if (element2->type_kind != TYPE_INFERRED_ARRAY && element1->array.len != element2->array.len) return false; + element1 = element1->array.base; + element2 = element2->array.base; + goto RETRY; + case TYPE_VECTOR: + if (element2->type_kind != TYPE_INFERRED_VECTOR && element1->array.len != element2->array.len) return false; + element1 = element1->array.base; + element2 = element2->array.base; + goto RETRY; + case TYPE_STRUCT: + if (is_explicit) return type_is_structurally_equivalent(element1, element2); + return false; + default: + return false; + } +} + +bool type_is_pointer_equivalent(Type *pointer1, Type *pointer2, bool flatten_distinct) +{ +RETRY: + if (flatten_distinct) + { + pointer1 = type_flatten_distinct(pointer1); + pointer2 = type_flatten_distinct(pointer2); + } + if (pointer1 == type_voidptr || pointer2 == type_voidptr) return true; + Type *pointee1 = pointer1->pointer->canonical; + Type *pointee2 = pointer2->pointer->canonical; + if (flatten_distinct) + { + pointee1 = type_flatten_distinct(pointee1); + pointee2 = type_flatten_distinct(pointee2); + } + if (pointee1->type_kind != pointee2->type_kind) return false; + if (pointee1->type_kind == TYPE_POINTER) + { + pointer1 = pointee1; + pointer2 = pointee2; + goto RETRY; + } + if (!type_is_arraylike(pointee1)) return false; + if (pointee1->array.len != pointee2->array.len) return false; + return type_array_element_is_equivalent(pointee1->array.base, pointer2->array.base, flatten_distinct); +} + bool type_may_have_method(Type *type) { DECL_TYPE_KIND_REAL(kind, type) diff --git a/test/test_suite/arrays/array_invalid_casts.c3 b/test/test_suite/arrays/array_invalid_casts.c3 index a197e4fd3..869499795 100644 --- a/test/test_suite/arrays/array_invalid_casts.c3 +++ b/test/test_suite/arrays/array_invalid_casts.c3 @@ -8,5 +8,5 @@ fn void test() fn void test2() { int[3] x; - double[] z = &x; // #error: 'int[3]*' into 'double[]' + double[] z = &x; // #error: 'int[3]*' to 'double[]' } \ No newline at end of file diff --git a/test/test_suite/cast/top_down_cast_fails.c3 b/test/test_suite/cast/top_down_cast_fails.c3 index 092c9cbf5..2cd1e3938 100644 --- a/test/test_suite/cast/top_down_cast_fails.c3 +++ b/test/test_suite/cast/top_down_cast_fails.c3 @@ -3,27 +3,27 @@ fn void test() int x; int y; long z = x * y; - z = x * y + z; // #error: 'int' to 'long' - z = x * y + x; // #error: 'int' to 'long' + z = x * y + z; // #error: 'long' + z = x * y + x; // #error: 'long' z = x / y; z = x + y; z = x - y; z = x % y; - z = x / y + z; // #error: 'int' to 'long' - z = x + y + z; // #error: 'int' to 'long' - z = x - y + z; // #error: 'int' to 'long' - z = x % y + z; // #error: 'int' to 'long' - z = x / y + x; // #error: 'int' to 'long' - z = x + y + x; // #error: 'int' to 'long' - z = x - y + x; // #error: 'int' to 'long' - z = x % y + x; // #error: 'int' to 'long' + z = x / y + z; // #error: 'long' + z = x + y + z; // #error: 'long' + z = x - y + z; // #error: 'long' + z = x % y + z; // #error: 'long' + z = x / y + x; // #error: 'long' + z = x + y + x; // #error: 'long' + z = x - y + x; // #error: 'long' + z = x % y + x; // #error: 'long' - z = x << y + x; // #error: 'int' to 'long' - z = x >> y + x; // #error: 'int' to 'long' - z = x << y + z; // #error: 'int' to 'long' - z = x >> y + z; // #error: 'int' to 'long' - z = ~x + x; // #error: 'int' to 'long' - z = ~x + z; // #error: 'int' to 'long' - z = -x + z; // #error: 'int' to 'long' + z = x << y + x; // #error: 'long' + z = x >> y + x; // #error: 'long' + z = x << y + z; // #error: 'long' + z = x >> y + z; // #error: 'long' + z = ~x + x; // #error: 'long' + z = ~x + z; // #error: 'long' + z = -x + z; // #error: 'long' z = x + z; } \ No newline at end of file diff --git a/test/test_suite/compile_time/ct_switch_errors.c3 b/test/test_suite/compile_time/ct_switch_errors.c3 index 25f8e381a..19bc289d8 100644 --- a/test/test_suite/compile_time/ct_switch_errors.c3 +++ b/test/test_suite/compile_time/ct_switch_errors.c3 @@ -28,7 +28,7 @@ fn void test3() $switch (3): $case 3: return; - $case 123.0: // #error: Implicitly casting 'double' to 'int' is not permitted + $case 123.0: // #error: 'int' return; $default: return; diff --git a/test/test_suite/compile_time/typeof_from_literal.c3 b/test/test_suite/compile_time/typeof_from_literal.c3 index f4bbb82e4..e5deaa514 100644 --- a/test/test_suite/compile_time/typeof_from_literal.c3 +++ b/test/test_suite/compile_time/typeof_from_literal.c3 @@ -3,12 +3,12 @@ module foo; fn void a() { $typeof(9146744073709551615i64) ef; - int fffx = ef; // #error: 'long' to 'int' + int fffx = ef; // #error: 'long' } fn void b() { $typeof(9223372036854775809u64) ef; - int fffx = ef; // #error: 'ulong' to 'int' + int fffx = ef; // #error: 'ulong' } diff --git a/test/test_suite/constants/constants.c3t b/test/test_suite/constants/constants.c3t index ece162a23..b91366f98 100644 --- a/test/test_suite/constants/constants.c3t +++ b/test/test_suite/constants/constants.c3t @@ -13,7 +13,7 @@ private uint z2 = DD; fn void test() { - int xx = FOO; + int xx = (int)FOO; uint* yy = &&FOO; } diff --git a/test/test_suite/distinct/test_errors.c3 b/test/test_suite/distinct/test_errors.c3 index ccea22f84..e90141453 100644 --- a/test/test_suite/distinct/test_errors.c3 +++ b/test/test_suite/distinct/test_errors.c3 @@ -7,5 +7,5 @@ fn void test() Int2 a = 1; a = a + 1; int b; - a = b; // #error: 'int' to 'Int2' + a = b; // #error: 'Int2' } \ No newline at end of file diff --git a/test/test_suite/errors/illegal_use_of_failable.c3 b/test/test_suite/errors/illegal_use_of_failable.c3 index b5604fb0a..1ffdf8a56 100644 --- a/test/test_suite/errors/illegal_use_of_failable.c3 +++ b/test/test_suite/errors/illegal_use_of_failable.c3 @@ -1,12 +1,12 @@ fn void syntaxErrors() { int! i = 0; - while (i + 1) {} // #error: The expression may not be a failable, but was 'int!' - if (i + 1) {} // #error: The expression may not be a failable, but was 'int!' + while (i + 1) {} // #error: optional, but was 'int!' + if (i + 1) {} // #error: optional, but was 'int!' for (int x = i;;) {} // #error: 'int!' to 'int' - for (int x = 0; x < i + 1;) {} // #error: The expression may not be a failable, but was 'bool!' + for (int x = 0; x < i + 1;) {} // #error: optional, but was 'bool!'. for (int x = 0; x < 10; x += i + 1) {} // #error: Cannot assign a failable value to a non-failable - switch (i + 1) // #error: The expression may not be a failable, but was 'int!' + switch (i + 1) // #error: optional, but was 'int!' { default: i + 1; diff --git a/test/test_suite/expressions/call_arg_types.c3 b/test/test_suite/expressions/call_arg_types.c3 index b260c3732..405b175be 100644 --- a/test/test_suite/expressions/call_arg_types.c3 +++ b/test/test_suite/expressions/call_arg_types.c3 @@ -8,11 +8,11 @@ fn void test1() test2(c); int a = 1; - test2(a); // #error: 'int' to 'ichar' - test2(100 + a); // #error: 'int' to 'ichar' + test2(a); // #error: 'ichar' + test2(100 + a); // #error: 'ichar' const int X = 120; - test2(X); // #error: 'int' to 'ichar' + test2(X); test2(100 + 100); // #error: '200' is out of range for 'ichar' } diff --git a/test/test_suite/expressions/casts/cast_const.c3 b/test/test_suite/expressions/casts/cast_const.c3 index b109f700c..1e9f68455 100644 --- a/test/test_suite/expressions/casts/cast_const.c3 +++ b/test/test_suite/expressions/casts/cast_const.c3 @@ -2,5 +2,5 @@ fn void test1() { ichar a = (ichar)(256 + 1); ushort b = (ushort)(65536+1); - ichar c = (ushort)(65536+400); // #error: 'ushort' to 'ichar' + ichar c = (ushort)(65536+400); // #error: truncate the value } diff --git a/test/test_suite/expressions/casts/cast_enum_to_various.c3 b/test/test_suite/expressions/casts/cast_enum_to_various.c3 index 2da5c9758..343719a6f 100644 --- a/test/test_suite/expressions/casts/cast_enum_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_enum_to_various.c3 @@ -1,6 +1,3 @@ - - - struct Struct { int x; @@ -24,16 +21,17 @@ fn void test1(Enum e) char b = (char)(e); uint c = (uint)(e); float d = (float)(e); - uint* f = (uint*)(e); // #error: cast 'Enum' to 'uint*' + uint* f = (uint*)(e); // #error: 'uint*' } fn void test2(Enum e) { - Struct* g = (Struct*)(e); // #error: cast 'Enum' to 'Struct*' + Struct* g = (Struct*)(e); // #error: 'Struct*' } fn void test3(Enum e) { - EnumB h = (EnumB)(e); // #error: 'Enum' to 'EnumB' is not allowed - Func i = (Func)(e); // #error: cast 'Enum' to 'Func' + EnumB h = (EnumB)(e); // #error: 'EnumB' + Func i = (Func)(e); // #error: 'Func' } + diff --git a/test/test_suite/expressions/casts/cast_func_to_various.c3 b/test/test_suite/expressions/casts/cast_func_to_various.c3 index 66cc71069..1a7acb57b 100644 --- a/test/test_suite/expressions/casts/cast_func_to_various.c3 +++ b/test/test_suite/expressions/casts/cast_func_to_various.c3 @@ -16,7 +16,7 @@ define FuncSame = fn void(int); fn void test1(Func arg) { bool a = (bool)(arg); - bool b = arg; + bool b = arg; // #error: 'Func' (fn void(int)) to 'bool' } fn void test2(Func arg) diff --git a/test/test_suite/expressions/casts/explicit_cast.c3 b/test/test_suite/expressions/casts/explicit_cast.c3 index 4743e41ae..b374f02fe 100644 --- a/test/test_suite/expressions/casts/explicit_cast.c3 +++ b/test/test_suite/expressions/casts/explicit_cast.c3 @@ -1,15 +1,16 @@ define Number8 = char; define Number32 = int; - +define DNumber32 = distinct int; fn void test1() { int a = (ichar)(10); int b = (ichar)(200); int c = (int)(200); - ichar d = (int)(200); // #error: 'int' to 'ichar' + ichar d = (int)(200); // #error: truncate the value } fn void test2() { - char e = (Number32)(200); // #error: 'Number32' (int) to 'char' + char e = (Number32)(200); + char f = (DNumber32)(200); // #error: DNumber32 } \ No newline at end of file diff --git a/test/test_suite/expressions/negate_int.c3 b/test/test_suite/expressions/negate_int.c3 index 258fbbd1b..da6a0702a 100644 --- a/test/test_suite/expressions/negate_int.c3 +++ b/test/test_suite/expressions/negate_int.c3 @@ -2,7 +2,7 @@ fn void test1() { short! a = 1; try(-a); - short b = -a; // #error: 'int!' cannot be converted to 'short' + short b = -a; // #error: 'int!' to 'short'. } fn void test2() diff --git a/test/test_suite/expressions/pointer_conv_error.c3 b/test/test_suite/expressions/pointer_conv_error.c3 index 40e59f04e..94ad43d44 100644 --- a/test/test_suite/expressions/pointer_conv_error.c3 +++ b/test/test_suite/expressions/pointer_conv_error.c3 @@ -1,18 +1,18 @@ fn void test1() { int myInt = 1; - int* p1 = myInt; // #error: 'int' into 'int*' + int* p1 = myInt; // #error: 'int*' } fn void test2() { uint myUInt = 1; - int* p2 = myUInt; // #error: 'uint' into 'int*' + int* p2 = myUInt; // #error: 'int*' } fn void test3() { uint myUInt = 1; - int* p2 = (int*)(myUInt); // #error: 'uint' to 'int*' + int* p2 = (int*)(myUInt); // #error: iptr } diff --git a/test/test_suite/globals/global_init.c3 b/test/test_suite/globals/global_init.c3 index b258a909f..b3cd2bd2c 100644 --- a/test/test_suite/globals/global_init.c3 +++ b/test/test_suite/globals/global_init.c3 @@ -5,8 +5,7 @@ char[] str3 = "hello"; int[2] a1 = { 1, 2 }; -int[2] a2 = 30; // #error: 'int' into 'int[2]' -// TODO int[2] a3 = a1; +int[2] a2 = 30; // #error: 'int' to 'int[2]' ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers diff --git a/test/test_suite/initialize/initialize_jump.c3 b/test/test_suite/initialize/initialize_jump.c3 index 51b46420a..4c254d2ee 100644 --- a/test/test_suite/initialize/initialize_jump.c3 +++ b/test/test_suite/initialize/initialize_jump.c3 @@ -5,5 +5,5 @@ static initialize static initialize { - return 123; // #error: You cannot cast 'int' into 'void' even with an explicit cast, so this looks like an error. + return 123; // #error: It is not possible to convert 'int' to 'void' } \ No newline at end of file diff --git a/test/test_suite/macros/macro_rtype.c3 b/test/test_suite/macros/macro_rtype.c3 index 8a32d3490..394d71612 100644 --- a/test/test_suite/macros/macro_rtype.c3 +++ b/test/test_suite/macros/macro_rtype.c3 @@ -1,6 +1,6 @@ macro int frob() { - return 0.0; // #error: Implicitly casting 'double' to 'int' is not permitted + return 0.0; // #error: int } fn void test1() diff --git a/test/test_suite/statements/binary_fail.c3 b/test/test_suite/statements/binary_fail.c3 index cb243ba8b..4e124de8d 100644 --- a/test/test_suite/statements/binary_fail.c3 +++ b/test/test_suite/statements/binary_fail.c3 @@ -4,6 +4,5 @@ fn void test() float b; int *c; int *d; - if ((a + c) // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here - + (b + d)) return; // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here + if (a + c) return; // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here } \ No newline at end of file diff --git a/test/test_suite/statements/foreach_errors.c3 b/test/test_suite/statements/foreach_errors.c3 index 004dc950f..f0f7e6e0e 100644 --- a/test/test_suite/statements/foreach_errors.c3 +++ b/test/test_suite/statements/foreach_errors.c3 @@ -49,6 +49,6 @@ fn void test7() fn void test8() { - foreach (int a : { z }) foo(); // #error: 'int[3]' into 'int' + foreach (int a : { z }) foo(); // #error: 'int[3]' to 'int' } diff --git a/test/test_suite/statements/foreach_r_errors.c3 b/test/test_suite/statements/foreach_r_errors.c3 index 47047b375..c3c667e82 100644 --- a/test/test_suite/statements/foreach_r_errors.c3 +++ b/test/test_suite/statements/foreach_r_errors.c3 @@ -49,6 +49,6 @@ fn void test7() fn void test8() { - foreach_r (int a : { z }) foo(); // #error: 'int[3]' into 'int' + foreach_r (int a : { z }) foo(); // #error: 'int[3]' to 'int' } diff --git a/test/test_suite/statements/if_while_do_error.c3 b/test/test_suite/statements/if_while_do_error.c3 index c0cd3312a..5cd3fe3b7 100644 --- a/test/test_suite/statements/if_while_do_error.c3 +++ b/test/test_suite/statements/if_while_do_error.c3 @@ -2,8 +2,8 @@ module test; fn void test1() { - bool! x = 0; - if (x) // #error: The expression may not be a failable, but was 'bool!' + bool! x = false; + if (x) // #error: optional, but was 'bool! { x = 100; } @@ -11,8 +11,8 @@ fn void test1() fn void test2() { - bool! x = 0; - while (x) // #error: The expression may not be a failable, but was 'bool!' + bool! x = false; + while (x) // #error: optional, but was 'bool! { x = false; } @@ -20,7 +20,7 @@ fn void test2() fn void test3() { - bool! x = 0; + bool! x = false; double y = 1; do { diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index 995dcd023..43a401ead 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -18,7 +18,7 @@ fn void test_other_enum() break; case B: break; - case Bar.B: // #error: 'Bar' into 'Foo' + case Bar.B: // #error: to 'Foo' break; } } diff --git a/test/test_suite/subarrays/sub_array_init.c3 b/test/test_suite/subarrays/sub_array_init.c3 index 4becdc105..72b6d5698 100644 --- a/test/test_suite/subarrays/sub_array_init.c3 +++ b/test/test_suite/subarrays/sub_array_init.c3 @@ -2,6 +2,6 @@ fn void test2() { int[2] a = { 1, 2 }; - int[2] b = 30; // #error: 'int' into 'int[2]' + int[2] b = 30; // #error: 'int[2]' int[2] c = a; } diff --git a/test/test_suite/switch/failable_switch.c3 b/test/test_suite/switch/failable_switch.c3 index 79cc80b4d..4bc2d2197 100644 --- a/test/test_suite/switch/failable_switch.c3 +++ b/test/test_suite/switch/failable_switch.c3 @@ -8,7 +8,7 @@ fn void test() int x = 0; switch (x) { - case MyError.FOO!: // #error: You cannot have a failable here + case MyError.FOO!: // #error: cannot be converted x = x + 1; } } \ No newline at end of file diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index 1ab385fa5..2dd2fe1e9 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -18,7 +18,7 @@ fn void test3() { ichar a = 1; int b = 2; - ichar c = a + b; // #error: 'int' to 'ichar' + ichar c = a + b; // #error: 'ichar' } fn void test4() @@ -54,7 +54,7 @@ define Number = int; fn void test8() { Number a = 10; - ichar c = a; // #error: 'Number' (int) to 'ichar' + ichar c = a; // #error: 'Number' (int) } @@ -82,19 +82,19 @@ enum Enum : int fn void test11() { int a = Enum.A; - ichar b = Enum.B; // #error: 'Enum' to 'ichar' + ichar b = Enum.B; } fn void test12() { float f = 3.14; - ichar a = f; // #error: 'float' to 'ichar' + ichar a = f; // #error: 'ichar' } fn void test13() { int a = 1; - ichar b = a; // #error: 'int' to 'ichar' + ichar b = a; // #error: 'ichar' } fn void test14() @@ -118,14 +118,14 @@ fn void test16() ichar c = 1 ? 'c' : 'd'; ichar d = 1 ? 'c' : i; - ichar e = 1 ? i : 0; // #error: 'int' to 'ichar' - int g = 1 ? i : f; // #error: 'float' to 'int' + ichar e = 1 ? i : 0; // #error: 'ichar' + int g = 1 ? i : f; // #error: 'float' int a = f ? 1 : 0; } fn void test17() { - int a = "test"; // #error: 'char[4]*' into 'int' + int a = "test"; // #error: 'char[4]*' to 'int' } fn void test18() @@ -175,15 +175,12 @@ fn void test23() { int a = num; int b = test::num; - char c = test::num; // #error: 'int' to 'char' + char c = test::num; // #error: 'char' } int[2][3] b123; fn void test24() { - int a = b123; // #error: 'int[2][3]' into 'int' + int a = b123; // #error: 'int[2][3]' to 'int' } - - - diff --git a/test/test_suite/types/typedefs.c3 b/test/test_suite/types/typedefs.c3 index 354e99554..893061592 100644 --- a/test/test_suite/types/typedefs.c3 +++ b/test/test_suite/types/typedefs.c3 @@ -5,7 +5,7 @@ Arr a = { 3, 4, 5, 6 }; fn void test1() { Arr b = { 3, 4, 5, 6 }; - int c = b; // #error: 'Arr' (int[4]) into 'int' - int d = a; // #error: 'Arr' (int[4]) into 'int' + int c = b; // #error: 'Arr' (int[4]) to 'int' + int d = a; // #error: 'Arr' (int[4]) to 'int' } diff --git a/test/test_suite/vector/vector_to_array_fail.c3 b/test/test_suite/vector/vector_to_array_fail.c3 new file mode 100644 index 000000000..e35b9a947 --- /dev/null +++ b/test/test_suite/vector/vector_to_array_fail.c3 @@ -0,0 +1,13 @@ +module test; +import std::io; +fn void main() +{ + int[<2>] x = { 4, 7 }; + int[2] y = x; + int[*] y1 = y; + int[*] y2 = x; + int[<*>] z = x; + int[<*>] w = y; + double[<2>] ww = x; + double[<2>] www = y; // #error: 'int[2]' to 'double[<2>]' +} \ No newline at end of file diff --git a/test/test_suite2/arrays/array_invalid_casts.c3 b/test/test_suite2/arrays/array_invalid_casts.c3 index a197e4fd3..869499795 100644 --- a/test/test_suite2/arrays/array_invalid_casts.c3 +++ b/test/test_suite2/arrays/array_invalid_casts.c3 @@ -8,5 +8,5 @@ fn void test() fn void test2() { int[3] x; - double[] z = &x; // #error: 'int[3]*' into 'double[]' + double[] z = &x; // #error: 'int[3]*' to 'double[]' } \ No newline at end of file diff --git a/test/test_suite2/cast/top_down_cast_fails.c3 b/test/test_suite2/cast/top_down_cast_fails.c3 index 092c9cbf5..2cd1e3938 100644 --- a/test/test_suite2/cast/top_down_cast_fails.c3 +++ b/test/test_suite2/cast/top_down_cast_fails.c3 @@ -3,27 +3,27 @@ fn void test() int x; int y; long z = x * y; - z = x * y + z; // #error: 'int' to 'long' - z = x * y + x; // #error: 'int' to 'long' + z = x * y + z; // #error: 'long' + z = x * y + x; // #error: 'long' z = x / y; z = x + y; z = x - y; z = x % y; - z = x / y + z; // #error: 'int' to 'long' - z = x + y + z; // #error: 'int' to 'long' - z = x - y + z; // #error: 'int' to 'long' - z = x % y + z; // #error: 'int' to 'long' - z = x / y + x; // #error: 'int' to 'long' - z = x + y + x; // #error: 'int' to 'long' - z = x - y + x; // #error: 'int' to 'long' - z = x % y + x; // #error: 'int' to 'long' + z = x / y + z; // #error: 'long' + z = x + y + z; // #error: 'long' + z = x - y + z; // #error: 'long' + z = x % y + z; // #error: 'long' + z = x / y + x; // #error: 'long' + z = x + y + x; // #error: 'long' + z = x - y + x; // #error: 'long' + z = x % y + x; // #error: 'long' - z = x << y + x; // #error: 'int' to 'long' - z = x >> y + x; // #error: 'int' to 'long' - z = x << y + z; // #error: 'int' to 'long' - z = x >> y + z; // #error: 'int' to 'long' - z = ~x + x; // #error: 'int' to 'long' - z = ~x + z; // #error: 'int' to 'long' - z = -x + z; // #error: 'int' to 'long' + z = x << y + x; // #error: 'long' + z = x >> y + x; // #error: 'long' + z = x << y + z; // #error: 'long' + z = x >> y + z; // #error: 'long' + z = ~x + x; // #error: 'long' + z = ~x + z; // #error: 'long' + z = -x + z; // #error: 'long' z = x + z; } \ No newline at end of file diff --git a/test/test_suite2/compile_time/ct_switch_errors.c3 b/test/test_suite2/compile_time/ct_switch_errors.c3 index 25f8e381a..19bc289d8 100644 --- a/test/test_suite2/compile_time/ct_switch_errors.c3 +++ b/test/test_suite2/compile_time/ct_switch_errors.c3 @@ -28,7 +28,7 @@ fn void test3() $switch (3): $case 3: return; - $case 123.0: // #error: Implicitly casting 'double' to 'int' is not permitted + $case 123.0: // #error: 'int' return; $default: return; diff --git a/test/test_suite2/compile_time/typeof_from_literal.c3 b/test/test_suite2/compile_time/typeof_from_literal.c3 index f4bbb82e4..e5deaa514 100644 --- a/test/test_suite2/compile_time/typeof_from_literal.c3 +++ b/test/test_suite2/compile_time/typeof_from_literal.c3 @@ -3,12 +3,12 @@ module foo; fn void a() { $typeof(9146744073709551615i64) ef; - int fffx = ef; // #error: 'long' to 'int' + int fffx = ef; // #error: 'long' } fn void b() { $typeof(9223372036854775809u64) ef; - int fffx = ef; // #error: 'ulong' to 'int' + int fffx = ef; // #error: 'ulong' } diff --git a/test/test_suite2/constants/constants.c3t b/test/test_suite2/constants/constants.c3t index 882be8e03..9f4fdb99b 100644 --- a/test/test_suite2/constants/constants.c3t +++ b/test/test_suite2/constants/constants.c3t @@ -13,7 +13,7 @@ private uint z2 = DD; fn void test() { - int xx = FOO; + int xx = (int)FOO; uint* yy = &&FOO; } diff --git a/test/test_suite2/distinct/test_errors.c3 b/test/test_suite2/distinct/test_errors.c3 index ccea22f84..e90141453 100644 --- a/test/test_suite2/distinct/test_errors.c3 +++ b/test/test_suite2/distinct/test_errors.c3 @@ -7,5 +7,5 @@ fn void test() Int2 a = 1; a = a + 1; int b; - a = b; // #error: 'int' to 'Int2' + a = b; // #error: 'Int2' } \ No newline at end of file diff --git a/test/test_suite2/errors/illegal_use_of_optional.c3 b/test/test_suite2/errors/illegal_use_of_optional.c3 index b5604fb0a..1ffdf8a56 100644 --- a/test/test_suite2/errors/illegal_use_of_optional.c3 +++ b/test/test_suite2/errors/illegal_use_of_optional.c3 @@ -1,12 +1,12 @@ fn void syntaxErrors() { int! i = 0; - while (i + 1) {} // #error: The expression may not be a failable, but was 'int!' - if (i + 1) {} // #error: The expression may not be a failable, but was 'int!' + while (i + 1) {} // #error: optional, but was 'int!' + if (i + 1) {} // #error: optional, but was 'int!' for (int x = i;;) {} // #error: 'int!' to 'int' - for (int x = 0; x < i + 1;) {} // #error: The expression may not be a failable, but was 'bool!' + for (int x = 0; x < i + 1;) {} // #error: optional, but was 'bool!'. for (int x = 0; x < 10; x += i + 1) {} // #error: Cannot assign a failable value to a non-failable - switch (i + 1) // #error: The expression may not be a failable, but was 'int!' + switch (i + 1) // #error: optional, but was 'int!' { default: i + 1; diff --git a/test/test_suite2/expressions/call_arg_types.c3 b/test/test_suite2/expressions/call_arg_types.c3 index b260c3732..405b175be 100644 --- a/test/test_suite2/expressions/call_arg_types.c3 +++ b/test/test_suite2/expressions/call_arg_types.c3 @@ -8,11 +8,11 @@ fn void test1() test2(c); int a = 1; - test2(a); // #error: 'int' to 'ichar' - test2(100 + a); // #error: 'int' to 'ichar' + test2(a); // #error: 'ichar' + test2(100 + a); // #error: 'ichar' const int X = 120; - test2(X); // #error: 'int' to 'ichar' + test2(X); test2(100 + 100); // #error: '200' is out of range for 'ichar' } diff --git a/test/test_suite2/expressions/casts/cast_const.c3 b/test/test_suite2/expressions/casts/cast_const.c3 index b109f700c..1e9f68455 100644 --- a/test/test_suite2/expressions/casts/cast_const.c3 +++ b/test/test_suite2/expressions/casts/cast_const.c3 @@ -2,5 +2,5 @@ fn void test1() { ichar a = (ichar)(256 + 1); ushort b = (ushort)(65536+1); - ichar c = (ushort)(65536+400); // #error: 'ushort' to 'ichar' + ichar c = (ushort)(65536+400); // #error: truncate the value } diff --git a/test/test_suite2/expressions/casts/cast_enum_to_various.c3 b/test/test_suite2/expressions/casts/cast_enum_to_various.c3 index 2da5c9758..343719a6f 100644 --- a/test/test_suite2/expressions/casts/cast_enum_to_various.c3 +++ b/test/test_suite2/expressions/casts/cast_enum_to_various.c3 @@ -1,6 +1,3 @@ - - - struct Struct { int x; @@ -24,16 +21,17 @@ fn void test1(Enum e) char b = (char)(e); uint c = (uint)(e); float d = (float)(e); - uint* f = (uint*)(e); // #error: cast 'Enum' to 'uint*' + uint* f = (uint*)(e); // #error: 'uint*' } fn void test2(Enum e) { - Struct* g = (Struct*)(e); // #error: cast 'Enum' to 'Struct*' + Struct* g = (Struct*)(e); // #error: 'Struct*' } fn void test3(Enum e) { - EnumB h = (EnumB)(e); // #error: 'Enum' to 'EnumB' is not allowed - Func i = (Func)(e); // #error: cast 'Enum' to 'Func' + EnumB h = (EnumB)(e); // #error: 'EnumB' + Func i = (Func)(e); // #error: 'Func' } + diff --git a/test/test_suite2/expressions/casts/cast_func_to_various.c3 b/test/test_suite2/expressions/casts/cast_func_to_various.c3 index 2d358af62..31fcb3154 100644 --- a/test/test_suite2/expressions/casts/cast_func_to_various.c3 +++ b/test/test_suite2/expressions/casts/cast_func_to_various.c3 @@ -16,7 +16,7 @@ define FuncSame = fn void(int); fn void test1(Func arg) { bool a = (bool)(arg); - bool b = arg; + bool b = arg; // #error: 'Func' (fn void(int)) to 'bool' } fn void test2(Func arg) diff --git a/test/test_suite2/expressions/casts/explicit_cast.c3 b/test/test_suite2/expressions/casts/explicit_cast.c3 index 4743e41ae..b374f02fe 100644 --- a/test/test_suite2/expressions/casts/explicit_cast.c3 +++ b/test/test_suite2/expressions/casts/explicit_cast.c3 @@ -1,15 +1,16 @@ define Number8 = char; define Number32 = int; - +define DNumber32 = distinct int; fn void test1() { int a = (ichar)(10); int b = (ichar)(200); int c = (int)(200); - ichar d = (int)(200); // #error: 'int' to 'ichar' + ichar d = (int)(200); // #error: truncate the value } fn void test2() { - char e = (Number32)(200); // #error: 'Number32' (int) to 'char' + char e = (Number32)(200); + char f = (DNumber32)(200); // #error: DNumber32 } \ No newline at end of file diff --git a/test/test_suite2/expressions/negate_int.c3 b/test/test_suite2/expressions/negate_int.c3 index 258fbbd1b..da6a0702a 100644 --- a/test/test_suite2/expressions/negate_int.c3 +++ b/test/test_suite2/expressions/negate_int.c3 @@ -2,7 +2,7 @@ fn void test1() { short! a = 1; try(-a); - short b = -a; // #error: 'int!' cannot be converted to 'short' + short b = -a; // #error: 'int!' to 'short'. } fn void test2() diff --git a/test/test_suite2/expressions/pointer_conv_error.c3 b/test/test_suite2/expressions/pointer_conv_error.c3 index 40e59f04e..94ad43d44 100644 --- a/test/test_suite2/expressions/pointer_conv_error.c3 +++ b/test/test_suite2/expressions/pointer_conv_error.c3 @@ -1,18 +1,18 @@ fn void test1() { int myInt = 1; - int* p1 = myInt; // #error: 'int' into 'int*' + int* p1 = myInt; // #error: 'int*' } fn void test2() { uint myUInt = 1; - int* p2 = myUInt; // #error: 'uint' into 'int*' + int* p2 = myUInt; // #error: 'int*' } fn void test3() { uint myUInt = 1; - int* p2 = (int*)(myUInt); // #error: 'uint' to 'int*' + int* p2 = (int*)(myUInt); // #error: iptr } diff --git a/test/test_suite2/globals/global_init.c3 b/test/test_suite2/globals/global_init.c3 index b258a909f..b3cd2bd2c 100644 --- a/test/test_suite2/globals/global_init.c3 +++ b/test/test_suite2/globals/global_init.c3 @@ -5,8 +5,7 @@ char[] str3 = "hello"; int[2] a1 = { 1, 2 }; -int[2] a2 = 30; // #error: 'int' into 'int[2]' -// TODO int[2] a3 = a1; +int[2] a2 = 30; // #error: 'int' to 'int[2]' ichar[*] a; // #error: Inferred array types can only be used in declarations with initializers diff --git a/test/test_suite2/initialize/initialize_jump.c3 b/test/test_suite2/initialize/initialize_jump.c3 index 51b46420a..4c254d2ee 100644 --- a/test/test_suite2/initialize/initialize_jump.c3 +++ b/test/test_suite2/initialize/initialize_jump.c3 @@ -5,5 +5,5 @@ static initialize static initialize { - return 123; // #error: You cannot cast 'int' into 'void' even with an explicit cast, so this looks like an error. + return 123; // #error: It is not possible to convert 'int' to 'void' } \ No newline at end of file diff --git a/test/test_suite2/macros/macro_rtype.c3 b/test/test_suite2/macros/macro_rtype.c3 index 8a32d3490..394d71612 100644 --- a/test/test_suite2/macros/macro_rtype.c3 +++ b/test/test_suite2/macros/macro_rtype.c3 @@ -1,6 +1,6 @@ macro int frob() { - return 0.0; // #error: Implicitly casting 'double' to 'int' is not permitted + return 0.0; // #error: int } fn void test1() diff --git a/test/test_suite2/statements/binary_fail.c3 b/test/test_suite2/statements/binary_fail.c3 index cb243ba8b..4e124de8d 100644 --- a/test/test_suite2/statements/binary_fail.c3 +++ b/test/test_suite2/statements/binary_fail.c3 @@ -4,6 +4,5 @@ fn void test() float b; int *c; int *d; - if ((a + c) // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here - + (b + d)) return; // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here + if (a + c) return; // #error: A value of type 'float' cannot be added to 'int*', an integer was expected here } \ No newline at end of file diff --git a/test/test_suite2/statements/foreach_errors.c3 b/test/test_suite2/statements/foreach_errors.c3 index 004dc950f..f0f7e6e0e 100644 --- a/test/test_suite2/statements/foreach_errors.c3 +++ b/test/test_suite2/statements/foreach_errors.c3 @@ -49,6 +49,6 @@ fn void test7() fn void test8() { - foreach (int a : { z }) foo(); // #error: 'int[3]' into 'int' + foreach (int a : { z }) foo(); // #error: 'int[3]' to 'int' } diff --git a/test/test_suite2/statements/foreach_r_errors.c3 b/test/test_suite2/statements/foreach_r_errors.c3 index 47047b375..c3c667e82 100644 --- a/test/test_suite2/statements/foreach_r_errors.c3 +++ b/test/test_suite2/statements/foreach_r_errors.c3 @@ -49,6 +49,6 @@ fn void test7() fn void test8() { - foreach_r (int a : { z }) foo(); // #error: 'int[3]' into 'int' + foreach_r (int a : { z }) foo(); // #error: 'int[3]' to 'int' } diff --git a/test/test_suite2/statements/if_while_do_error.c3 b/test/test_suite2/statements/if_while_do_error.c3 index c0cd3312a..5cd3fe3b7 100644 --- a/test/test_suite2/statements/if_while_do_error.c3 +++ b/test/test_suite2/statements/if_while_do_error.c3 @@ -2,8 +2,8 @@ module test; fn void test1() { - bool! x = 0; - if (x) // #error: The expression may not be a failable, but was 'bool!' + bool! x = false; + if (x) // #error: optional, but was 'bool! { x = 100; } @@ -11,8 +11,8 @@ fn void test1() fn void test2() { - bool! x = 0; - while (x) // #error: The expression may not be a failable, but was 'bool!' + bool! x = false; + while (x) // #error: optional, but was 'bool! { x = false; } @@ -20,7 +20,7 @@ fn void test2() fn void test3() { - bool! x = 0; + bool! x = false; double y = 1; do { diff --git a/test/test_suite2/statements/switch_errors.c3 b/test/test_suite2/statements/switch_errors.c3 index 995dcd023..43a401ead 100644 --- a/test/test_suite2/statements/switch_errors.c3 +++ b/test/test_suite2/statements/switch_errors.c3 @@ -18,7 +18,7 @@ fn void test_other_enum() break; case B: break; - case Bar.B: // #error: 'Bar' into 'Foo' + case Bar.B: // #error: to 'Foo' break; } } diff --git a/test/test_suite2/subarrays/sub_array_init.c3 b/test/test_suite2/subarrays/sub_array_init.c3 index 4becdc105..72b6d5698 100644 --- a/test/test_suite2/subarrays/sub_array_init.c3 +++ b/test/test_suite2/subarrays/sub_array_init.c3 @@ -2,6 +2,6 @@ fn void test2() { int[2] a = { 1, 2 }; - int[2] b = 30; // #error: 'int' into 'int[2]' + int[2] b = 30; // #error: 'int[2]' int[2] c = a; } diff --git a/test/test_suite2/switch/failable_switch.c3 b/test/test_suite2/switch/failable_switch.c3 index 79cc80b4d..4bc2d2197 100644 --- a/test/test_suite2/switch/failable_switch.c3 +++ b/test/test_suite2/switch/failable_switch.c3 @@ -8,7 +8,7 @@ fn void test() int x = 0; switch (x) { - case MyError.FOO!: // #error: You cannot have a failable here + case MyError.FOO!: // #error: cannot be converted x = x + 1; } } \ No newline at end of file diff --git a/test/test_suite2/symbols/various.c3 b/test/test_suite2/symbols/various.c3 index f45cd0c93..db36e6479 100644 --- a/test/test_suite2/symbols/various.c3 +++ b/test/test_suite2/symbols/various.c3 @@ -18,7 +18,7 @@ fn void test3() { ichar a = 1; int b = 2; - ichar c = a + b; // #error: 'int' to 'ichar' + ichar c = a + b; // #error: 'ichar' } fn void test4() @@ -54,7 +54,7 @@ define Number = int; fn void test8() { Number a = 10; - ichar c = a; // #error: 'Number' (int) to 'ichar' + ichar c = a; // #error: 'Number' (int) } @@ -82,19 +82,19 @@ enum Enum : int fn void test11() { int a = Enum.A; - ichar b = Enum.B; // #error: 'Enum' to 'ichar' + ichar b = Enum.B; } fn void test12() { float f = 3.14; - ichar a = f; // #error: 'float' to 'ichar' + ichar a = f; // #error: 'ichar' } fn void test13() { int a = 1; - ichar b = a; // #error: 'int' to 'ichar' + ichar b = a; // #error: 'ichar' } fn void test14() @@ -118,14 +118,14 @@ fn void test16() ichar c = 1 ? 'c' : 'd'; ichar d = 1 ? 'c' : i; - ichar e = 1 ? i : 0; // #error: 'int' to 'ichar' - int g = 1 ? i : f; // #error: 'float' to 'int' + ichar e = 1 ? i : 0; // #error: 'ichar' + int g = 1 ? i : f; // #error: 'float' int a = f ? 1 : 0; } fn void test17() { - int a = "test"; // #error: 'char[4]*' into 'int' + int a = "test"; // #error: 'char[4]*' to 'int' } fn void test18() @@ -175,12 +175,15 @@ fn void test23() { int a = num; int b = test::num; - char c = test::num; // #error: 'int' to 'char' + char c = test::num; // #error: 'char' } int[2][3] b123; fn void test24() { - int a = b123; // #error: 'int[2][3]' into 'int' + int a = b123; // #error: 'int[2][3]' to 'int' } + + + diff --git a/test/test_suite2/types/typedefs.c3 b/test/test_suite2/types/typedefs.c3 index 354e99554..893061592 100644 --- a/test/test_suite2/types/typedefs.c3 +++ b/test/test_suite2/types/typedefs.c3 @@ -5,7 +5,7 @@ Arr a = { 3, 4, 5, 6 }; fn void test1() { Arr b = { 3, 4, 5, 6 }; - int c = b; // #error: 'Arr' (int[4]) into 'int' - int d = a; // #error: 'Arr' (int[4]) into 'int' + int c = b; // #error: 'Arr' (int[4]) to 'int' + int d = a; // #error: 'Arr' (int[4]) to 'int' } diff --git a/test/test_suite2/vector/vector_to_array_fail.c3 b/test/test_suite2/vector/vector_to_array_fail.c3 new file mode 100644 index 000000000..e35b9a947 --- /dev/null +++ b/test/test_suite2/vector/vector_to_array_fail.c3 @@ -0,0 +1,13 @@ +module test; +import std::io; +fn void main() +{ + int[<2>] x = { 4, 7 }; + int[2] y = x; + int[*] y1 = y; + int[*] y2 = x; + int[<*>] z = x; + int[<*>] w = y; + double[<2>] ww = x; + double[<2>] www = y; // #error: 'int[2]' to 'double[<2>]' +} \ No newline at end of file diff --git a/test/unit/regression/vector_conversion.c3 b/test/unit/regression/vector_conversion.c3 new file mode 100644 index 000000000..9b281ca61 --- /dev/null +++ b/test/unit/regression/vector_conversion.c3 @@ -0,0 +1,17 @@ +module test; + +fn void! vector_array_inferred() @test +{ + int[<2>] x = { 4, 7 }; + int[2] y = x; + int[*] y1 = y; + int[*] y2 = x; + int[<*>] z = x; + int[<*>] w = y; + double[<2>] ww = x; + assert((int[<2>])y == int[<2>]{ 4, 7}); + assert((int[<2>])y1 == int[<2>] { 4, 7 }); + assert((int[<2>])y2 == int[<2>] { 4, 7 }); + assert(z == int[<2>] { 4, 7 }); + assert(w == int[<2>] { 4, 7 }); +} \ No newline at end of file diff --git a/test/unit/regression/vector_ops.c3 b/test/unit/regression/vector_ops.c3 index 0b1a4d104..299dc0b40 100644 --- a/test/unit/regression/vector_ops.c3 +++ b/test/unit/regression/vector_ops.c3 @@ -86,13 +86,13 @@ fn void! testi() @test w = z << y; assert(w == { 4, 8, 16, -1600 }); w = $$veccompgt(z, y); - assert(w == { -1, 0, 0, -1}); + assert(w == { -1, 0, 0, 0}); w = $$veccompge(z, y); - assert(w == { -1, -1, 0, -1 }); + assert(w == { -1, -1, 0, 0 }); w = $$veccomplt(z, y); - assert(w == { 0, 0, -1, 0 }); + assert(w == { 0, 0, -1, -1 }); w = $$veccomple(z, y); - assert(w == { 0, -1, -1, 0 }); + assert(w == { 0, -1, -1, -1 }); w = $$veccompeq(z, y); assert(w == { 0, -1, 0, 0 }); w = $$veccompne(z, y);