From 37bb16cca1ee63f8696766be95c3b9adb78ad0a6 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 10 Sep 2023 23:12:35 +0200 Subject: [PATCH] Updated cast code. --- lib/std/core/builtin.c3 | 11 +- resources/castrules.md | 31 + src/compiler/compiler_internal.h | 16 +- src/compiler/enums.h | 47 +- src/compiler/expr.c | 18 +- src/compiler/llvm_codegen_expr.c | 104 +- src/compiler/sema_casts.c | 3180 ++++++++--------- src/compiler/sema_expr.c | 115 +- src/compiler/sema_initializers.c | 7 +- src/compiler/sema_internal.h | 6 +- src/compiler/sema_stmts.c | 6 +- src/compiler/types.c | 53 +- src/version.h | 2 +- .../test_suite/bitstruct/bitstruct_to_int.c3t | 16 +- test/test_suite/cast/cast_struct.c3 | 6 +- test/test_suite/cast/cast_struct_fails.c3 | 4 +- .../compile_time/untyped_with_inferred.c3 | 6 + test/test_suite/distinct/distinct_slicing.c3 | 2 +- .../casts/cast_enum_const_to_distinct.c3 | 2 +- .../expressions/casts/cast_func_to_various.c3 | 2 +- .../failed_distinct_float_conversions.c3 | 4 +- .../casts/struct_cast_and_distinct.c3 | 4 +- test/test_suite/expressions/negate_int.c3 | 2 +- test/test_suite/expressions/plus_int.c3 | 2 +- .../expressions/pointer_conv_error.c3 | 6 +- test/test_suite/expressions/void_arg.c3 | 2 +- test/test_suite/initialize/initialize_jump.c3 | 2 +- test/test_suite/macros/macro_with_body_err.c3 | 2 +- test/test_suite/struct/member_access.c3 | 2 +- test/test_suite/switch/failable_switch.c3 | 2 +- test/test_suite/symbols/various.c3 | 22 +- .../vector/vector_to_array_cast.c3t | 11 +- .../test_suite/vector/vector_to_array_fail.c3 | 2 +- 33 files changed, 1845 insertions(+), 1852 deletions(-) create mode 100644 resources/castrules.md create mode 100644 test/test_suite/compile_time/untyped_with_inferred.c3 diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index f0c6b2590..e5d8c1c60 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -161,10 +161,13 @@ macro void unsupported(String string = "Unsupported function invoked") @builtin **/ macro bitcast(expr, $Type) @builtin { - usz $size = $sizeof(expr); - $Type x @noinit; - mem::copy(&x, &expr, $size, $Type.alignof, $alignof(expr)); - return x; + $if $Type.alignof <= $alignof(expr): + return *($Type*)&expr; + $else + $Type x @noinit; + $$memcpy(&x, &expr, $sizeof(expr), false, $Type.alignof, $alignof(expr)); + return x; + $endif } /** diff --git a/resources/castrules.md b/resources/castrules.md new file mode 100644 index 000000000..8dab9184c --- /dev/null +++ b/resources/castrules.md @@ -0,0 +1,31 @@ +Some short names: +1. expl - explicit +2. sw/sn - simple widening + subexpression narrowing +3. yes - always allowed +4. explptr - explicit if pointer sized +5. ptrconv - to/from void* is fine, other cast must be explicit +6. saconv - explicit if same element size +7. explbase - explicit to base disregaring sign +8. distel - explicit to same element disregarding distinct +9. inline - implicit if type subtype +10. cond - implicit in cond, explicit otherwise +11. edist - explicit to anything underlying type can convert to, if inline as underlying +12. arve - if array or vec ptr + +| from, to | bool | int | float | pointer | subarr | vec | bits | distc | array | struct | union | any | fault | enum | typeid | +|----------|--------|----------|--------|---------|--------|----------|----------|-------|----------|--------|--------|--------|--------|--------|--------| +| bool | n/a | expl | expl | no | no | expand | no | edist | no | no | no | no | no | no | no | +| int | cond | sw/sn | always | explptr | no | expand | explbase | edist | no | no | no | no | no | edist | no | +| float | cond | expl | sw/sn | no | no | expand | no | edist | no | no | no | no | no | no | no | +| pointer | cond | explptr | no | ptrconv | arve | expand | no | edist | no | no | no | yes | expl | no | expl | +| subarray | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no | +| vec | cond | no | no | no | no | as base | no | edist | expl | no | no | no | no | no | no | +| bits | no | explbase | no | no | no | no | no? | edist | explbase | no | no | no | no | no | no | +| distc | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | +| array | no | no | no | no | no | explbase | explbase | edist | distel | no | no | no | no | no | no | +| struct | inline | inline | inline | inline | inline | inline | inline | edist | inline | inline | inline | inline | inline | inline | inline | +| union | no | no | no | no | no | no | no | edist | no | no | no | no | no | no | no | +| any | cond | no | no | expl | no | no | no | edist | no | no | no | n/a | no | no | no | +| fault | cond | explptr | no | expl | no | no | no | edist | no | no | no | no | anyf | no | no | +| enum | no | expl | no | no | no | expand | no | edist | no | no | no | no | no | no | no | +| typeid | cond | no | no | expl | no | no | no | edist | no | no | no | no | no | no | n/a | diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 76118c699..f9219a18d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2096,16 +2096,13 @@ 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_optional(SemaContext *context, Expr *expr, Type *to_type, bool may_be_optional); bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type); +bool may_cast(SemaContext *cc, Expr *expr, Type *to_type, bool is_explicit); -bool cast(Expr *expr, Type *to_type); - +void cast_no_check(Expr *expr, Type *to_type, bool add_optional); Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type); -bool cast_to_index(Expr *index); - -bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type); +bool cast_to_index(SemaContext *context, Expr *index); CastKind cast_to_bool_kind(Type *type); const char *llvm_codegen(void *context); @@ -2415,7 +2412,7 @@ typedef enum TYPE_ERROR = -1, } TypeCmpResult; -TypeCmpResult type_is_pointer_equivalent(SemaContext *context, Type *pointer1, Type *pointer2, bool flatten_distinct); +TypeCmpResult type_is_pointer_equivalent(SemaContext *context, Type *to_pointer, Type *from_pointer, bool flatten_distinct); TypeCmpResult type_array_element_is_equivalent(SemaContext *context, Type *element1, Type *element2, bool is_explicit); FunctionPrototype *type_get_resolved_prototype(Type *type); const char *type_to_error_string(Type *type); @@ -3427,6 +3424,11 @@ INLINE bool expr_is_const_enum(Expr *expr) return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ENUM; } +INLINE bool expr_is_const_fault(Expr *expr) +{ + return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ERR; +} + INLINE bool expr_is_const_pointer(Expr *expr) { return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 5711ef23d..160edb775 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -81,22 +81,19 @@ typedef enum typedef enum { CAST_ANYPTR, + CAST_ANYBOOL, CAST_APTSA, CAST_ARRVEC, - CAST_ARRBS, CAST_BOOLBOOL, CAST_BOOLFP, CAST_BOOLINT, CAST_BOOLVECINT, - CAST_BSARRY, - CAST_BSINT, - CAST_ERBOOL, CAST_EREU, CAST_ERINT, + CAST_ERPTR, CAST_ERROR, CAST_EUBOOL, CAST_EUER, - CAST_EUINT, CAST_FPBOOL, CAST_FPFP, CAST_FPINT, @@ -104,8 +101,9 @@ typedef enum CAST_INTBOOL, CAST_INTENUM, CAST_INTFP, - CAST_INTBS, - CAST_NUMVEC, + CAST_IDPTR, + CAST_IDBOOL, + CAST_IDINT, CAST_PTRANY, CAST_PTRBOOL, CAST_PTRPTR, @@ -114,12 +112,12 @@ typedef enum CAST_SAPTR, CAST_SASA, CAST_STRPTR, - CAST_STST, + CAST_STINLINE, CAST_VECARR, CAST_VOID, CAST_INTERR, CAST_INTPTR, - CAST_VOIDFERR + CAST_EXPVEC, } CastKind; @@ -678,7 +676,7 @@ typedef enum TYPE_WILDCARD, TYPE_TYPEINFO, TYPE_MEMBER, - TYPE_LAST = TYPE_ANY + TYPE_LAST = TYPE_MEMBER } TypeKind; #define FLATTENED_TYPES TYPE_DISTINCT: case TYPE_OPTIONAL: case TYPE_TYPEDEF @@ -1029,4 +1027,31 @@ typedef enum MAIN_TYPE_NO_ARGS, MAIN_TYPE_ARGS, MAIN_TYPE_WIN, -} MainType; \ No newline at end of file +} MainType; + +typedef enum +{ + CONV_NO = -1, + CONV_VOID = 0, + CONV_WILDCARD, + CONV_BOOL, + CONV_INT, + CONV_FLOAT, + CONV_POINTER, + CONV_SUBARRAY, + CONV_VECTOR, + CONV_BITSTRUCT, + CONV_DISTINCT, + CONV_ARRAY, + CONV_STRUCT, + CONV_UNION, + CONV_ANY, + CONV_FAULT, + CONV_ENUM, + CONV_TYPEID, + CONV_ANYFAULT, + CONV_VOIDPTR, + CONV_VAPTR, + CONV_INFERRED, + CONV_LAST = CONV_INFERRED +} ConvGroup; diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 53a828514..94036e57c 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -336,16 +336,8 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ { case CAST_ERROR: UNREACHABLE - case CAST_VOIDFERR: - return false; - case CAST_BSINT: - case CAST_BSARRY: - case CAST_INTBS: - case CAST_ARRBS: - return true; case CAST_INTENUM: case CAST_ANYPTR: - case CAST_ERBOOL: case CAST_EUBOOL: case CAST_EUER: case CAST_EREU: @@ -361,11 +353,10 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ case CAST_FPINT: case CAST_INTFP: case CAST_SABOOL: - case CAST_STST: + case CAST_STINLINE: case CAST_VECARR: case CAST_ARRVEC: case CAST_BOOLVECINT: - case CAST_NUMVEC: case CAST_INTINT: if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false; return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); @@ -375,13 +366,18 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ case CAST_SAPTR: case CAST_SASA: case CAST_VOID: + case CAST_ANYBOOL: + case CAST_ERPTR: + case CAST_IDPTR: + case CAST_IDBOOL: + case CAST_EXPVEC: return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); case CAST_PTRANY: if (eval_kind == CONSTANT_EVAL_LOCAL_INIT || eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false; return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); - case CAST_EUINT: case CAST_ERINT: case CAST_PTRINT: + case CAST_IDINT: if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false; return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 47a438462..b913846cc 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1231,51 +1231,8 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type llvm_value_set(value, vector, to_type); } -void llvm_emit_voidfail_err(GenContext *c, BEValue *value, Expr *expr) -{ - Expr *inner = exprptr(expr->cast_expr.expr); - if (inner->expr_kind == EXPR_IDENTIFIER) - { - Decl *decl = inner->identifier_expr.decl; - assert(IS_OPTIONAL(decl)); - llvm_value_set_address_abi_aligned(value, decl_optional_ref(decl), expr->type); - return; - } - - if (inner->expr_kind == EXPR_OPTIONAL) - { - llvm_emit_expr(c, value, inner->inner_expr); - value->type = type_lowering(expr->type); - return; - } - - LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "noerr_block"); - - // Store catch/error var - PUSH_OPT(); - - LLVMValueRef error_var = llvm_emit_alloca_aligned(c, expr->type, "error_var"); - llvm_value_set_address_abi_aligned(value, error_var, expr->type); - llvm_store_raw(c, value, llvm_get_zero(c, expr->type)); - c->opt_var = error_var; - c->catch_block = end_block; - - BEValue expr_value; - llvm_emit_expr(c, &expr_value, inner); - llvm_value_fold_optional(c, &expr_value); - - // Restore. - POP_OPT(); - - // Emit success and jump to end block. - llvm_emit_br(c, end_block); - - llvm_emit_block(c, end_block); - -} - -void llvm_emit_num_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) +void llvm_emit_expand_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) { llvm_value_rvalue(c, value); LLVMTypeRef type = llvm_get_type(c, to_type); @@ -1395,10 +1352,8 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu switch (cast_kind) { - case CAST_VOIDFERR: - UNREACHABLE - case CAST_NUMVEC: - llvm_emit_num_to_vec_cast(c, value, to_type, from_type); + case CAST_EXPVEC: + llvm_emit_expand_to_vec_cast(c, value, to_type, from_type); return; case CAST_BOOLVECINT: llvm_emit_bool_to_intvec_cast(c, value, to_type, from_type); @@ -1414,22 +1369,10 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu llvm_value_aggregate_two(c, value, to_type, value->value, typeid.value); return; } - case CAST_ARRBS: - case CAST_BSARRY: - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - llvm_value_rvalue(c, value); - return; - case CAST_BSINT: - case CAST_INTBS: - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - llvm_value_rvalue(c, value); - return; case CAST_VOID: UNREACHABLE; - case CAST_EUINT: case CAST_ERINT: + case CAST_IDINT: to_type = type_lowering(to_type); from_type = type_lowering(from_type); llvm_value_rvalue(c, value); @@ -1445,6 +1388,12 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu } break; + case CAST_ANYBOOL: + llvm_emit_any_pointer(c, value, value); + llvm_value_rvalue(c, value); + value->value = LLVMBuildIsNotNull(c->builder, value->value, "anybool"); + value->kind = BE_BOOLEAN; + break; case CAST_ANYPTR: llvm_emit_any_pointer(c, value, value); break; @@ -1458,7 +1407,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_STRPTR: case CAST_PTRPTR: llvm_value_rvalue(c, value); - value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); break; case CAST_PTRINT: llvm_value_rvalue(c, value); @@ -1467,11 +1415,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_APTSA: llvm_emit_arr_to_subarray_cast(c, value, to_type); break; - case CAST_SASA: - assert(type_is_pointer(value->type->array.base)); - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - break; case CAST_SAPTR: llvm_value_fold_optional(c, value); llvm_emit_subarray_pointer(c, value, value); @@ -1486,11 +1429,11 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_EUER: REMINDER("Improve fault to err comparison"); break; - case CAST_ERBOOL: case CAST_EUBOOL: + case CAST_IDBOOL: { BEValue zero; - llvm_value_set_int(c, &zero, type_anyfault, 0); + llvm_value_set_int(c, &zero, type_iptr, 0); llvm_emit_int_comp(c, value, value, &zero, BINARYOP_NE); break; } @@ -1550,11 +1493,15 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu } value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp"); break; + case CAST_IDPTR: + case CAST_ERPTR: case CAST_INTPTR: llvm_value_rvalue(c, value); value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "intptr"); break; - case CAST_STST: + case CAST_SASA: + // Improve this + case CAST_STINLINE: llvm_value_addr(c, value); value->type = to_type; return; @@ -1618,11 +1565,6 @@ static inline void llvm_emit_cast_expr(GenContext *context, BEValue *be_value, E llvm_emit_ignored_expr(context, exprptr(expr->cast_expr.expr)); return; } - if (expr->cast_expr.kind == CAST_VOIDFERR) - { - llvm_emit_voidfail_err(context, be_value, expr); - return; - } llvm_emit_exprid(context, be_value, expr->cast_expr.expr); llvm_emit_cast(context, expr->cast_expr.kind, @@ -4866,16 +4808,8 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) case CONST_ERR: { Decl *decl = expr->const_expr.enum_err_val; - - LLVMValueRef value; - if (decl) - { - value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyfault), ""); - } - else - { - value = llvm_get_zero(c, type_anyfault); - } + assert(decl); + LLVMValueRef value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyfault), ""); llvm_value_set(be_value, value, type_anyfault); return; } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index f27c15f0f..f42c69bc9 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -8,61 +8,191 @@ #include "sema_internal.h" -#pragma clang diagnostic push -#pragma ide diagnostic ignored "ConstantFunctionResult" +typedef struct +{ + SemaContext *context; + Expr *expr; + Type *from_type; + Type *to_type; + Type *to; + ConvGroup from_group; + ConvGroup to_group; +} CastContext; -static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool silent, bool may_not_be_optional); -static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent); -static bool cast_from_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent); -static bool cast_from_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent); -static bool cast_from_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent); -static bool cast_from_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent); - -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(Expr *expr, Type *type); static void expr_recursively_rewrite_untyped_list(Expr *expr, Expr **list); -static inline bool insert_cast(Expr *expr, CastKind kind, Type *type); -static bool pointer_to_integer(Expr *expr, Type *type); -static bool pointer_to_bool(Expr *expr, Type *type); -static bool pointer_to_pointer(Expr* expr, Type *type); -static bool bool_to_int(Expr *expr, Type *canonical, Type *type); -static bool bool_to_float(Expr *expr, Type *canonical, Type *type); -static bool integer_to_bool(Expr *expr, Type *type); -static bool integer_to_enum(Expr *expr, Type *canonical, Type *type); -static bool integer_to_integer(Expr *expr, Type *canonical, Type *type); -static bool integer_to_pointer(Expr *expr, Type *type); -static bool integer_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type); -static bool float_to_bool(Expr *expr, Type *type); -static bool float_to_float(Expr* expr, Type *canonical, Type *type); -static bool float_to_integer(Expr *expr, Type *canonical, Type *type); -static bool float_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type); -static bool array_to_vector(Expr *expr, Type *to_type); -static bool vector_to_array(Expr *expr, Type *to_type); -static bool vector_to_vector(Expr *expr, Type *to_type); -INLINE bool subarray_to_subarray(Expr *expr, Type *to_type); +static inline bool insert_runtime_cast(Expr *expr, CastKind kind, Type *type); static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type); -static bool cast_vector_element_may_implicitly_convert(Expr *expr, Type *from, Type *to); -static void enum_to_int_lowering(Expr* expr); -static bool voidfail_to_error(Expr *expr, Type *type); +static bool cast_is_allowed(CastContext *cc, bool is_explicit, bool is_silent); INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type); -INLINE bool cast_with_optional(Expr *expr, Type *to_type, bool add_optional); -static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent); + +static bool cast_if_valid(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool is_silent); +INLINE ConvGroup type_to_group(Type *type); +INLINE void cast_context_set_from(CastContext *cc, Type *new_from); +INLINE void cast_context_set_to(CastContext *cc, Type *new_to); +static bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type); + +typedef bool(*CastRule)(CastContext *cc, bool is_explicit, bool is_silent); +typedef void(*CastFunction)(Expr *expr, Type *to_type); +extern CastFunction cast_function[CONV_LAST + 1][CONV_LAST + 1]; +extern CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1]; + /** - * Insert a cast. This will assume that the cast is valid. No typeinfo will be registered. + * Try to make an implicit cast. Optional types are allowed. */ -static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) +bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) { - assert(expr->resolve_status == RESOLVE_DONE); - assert(expr->type); - Expr *inner = expr_copy(expr); - expr->expr_kind = EXPR_CAST; - expr->cast_expr.kind = kind; - expr->cast_expr.expr = exprid(inner); - expr->cast_expr.type_info = 0; - expr->type = type; - return true; + return cast_if_valid(context, expr, to_type, false, false); +} + +/** + * Try to make an explicit cast, Optional types are allowed. + */ +bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type) +{ + return cast_if_valid(context, expr, to_type, true, false); +} + +/** + * Silent implicit casting will attempt a cast, but will silently back out if it fails. + */ +bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type) +{ + return cast_if_valid(context, expr, to_type, false, true); +} + + +bool may_cast(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit) +{ + Type *from_type = expr->type->canonical; + Type *to = to_type->canonical; + CastContext cc = { + .from_group = type_to_group(from_type), + .from_type = from_type, + .to_group = type_to_group(to), + .to = to, + .to_type = to_type, + .expr = expr, + .context = context + }; + return cast_is_allowed(&cc, is_explicit, true); +} + +static bool cast_is_allowed(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from_type = cc->from_type; + assert(from_type == from_type->canonical); + // Check simple equality. + from_type = from_type->canonical; + if (from_type == cc->to) return true; + + // Make sure they have the same group. + ConvGroup from_group = cc->from_group; + ConvGroup to_group = cc->to_group; + CastRule rule = (from_group == CONV_NO || to_group == CONV_NO) ? NULL : cast_rules[from_group][to_group]; + + // No rule => no + if (!rule) + { + if (!is_silent) + { + SEMA_ERROR(cc->expr, "You cannot cast %s to %s.", type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type)); + } + return false; + } + + return rule(cc, is_explicit, is_silent); +} + +/** + * Perform the cast with no additional checks. Casting from untyped not allowed. + */ +void cast_no_check(Expr *expr, Type *to_type, bool add_optional) +{ + Type *to = type_flatten(to_type); + Type *from = type_flatten(expr->type); + if (from == to) + { + expr->type = type_add_optional(to_type, add_optional); + return; + } + ConvGroup to_group = type_to_group(to); + ConvGroup from_group = type_to_group(from); + CastFunction func = cast_function[from_group][to_group]; + if (func) + { + func(expr, to_type); + expr->type = type_add_optional(expr->type, add_optional); + return; + } + error_exit("Trying cast function from %s to %s\n", type_quoted_error_string(expr->type), type_quoted_error_string(to_type)); +} + +/** + * Given lhs and rhs, promote to the maximum bit size, this will retain + * signed/unsigned type of each side. + */ +void cast_to_int_to_max_bit_size(Expr *lhs, Expr *rhs, Type *left_type, Type *right_type) +{ + unsigned bit_size_left = left_type->builtin.bitsize; + unsigned bit_size_right = right_type->builtin.bitsize; + + assert(bit_size_left && bit_size_right); + + // Simple case they are the same size, just return. + if (bit_size_left == bit_size_right) return; + + // Lhs is smaller than rhs, so widen it using the right type + if (bit_size_left < bit_size_right) + { + Type *to = lhs->type->type_kind < TYPE_U8 + ? type_int_signed_by_bitsize(bit_size_right) + : type_int_unsigned_by_bitsize(bit_size_right); + cast_no_check(lhs, to, IS_OPTIONAL(lhs)); + return; + } + + // Rhs is smaller, do the same thing as above but with the rhs. + Type *to = rhs->type->type_kind < TYPE_U8 + ? type_int_signed_by_bitsize(bit_size_left) + : type_int_unsigned_by_bitsize(bit_size_left); + cast_no_check(rhs, to, IS_OPTIONAL(rhs)); +} + +/** + * Perform vararg promotions typical for C style varargs: + * 1. Widen int and bool to C int size + * 2. Widen float and smaller to double + * 3. Turn subarrays into pointers + */ +void cast_promote_vararg(Expr *arg) +{ + // Remove things like distinct, optional, enum etc. + Type *arg_type = type_flatten(arg->type); + + // 1. Promote any integer or bool to at least CInt + if (type_is_promotable_int_bool(arg_type)) + { + cast_no_check(arg, type_cint, IS_OPTIONAL(arg)); + return; + } + + // 2. Promote any float to at least double + if (type_is_promotable_float(arg_type)) + { + cast_no_check(arg, type_double, IS_OPTIONAL(arg)); + return; + } + + // 3. Turn subarrays into pointers + if (arg_type->type_kind == TYPE_SUBARRAY) + { + cast_no_check(arg, type_get_ptr(arg_type->array.base), IS_OPTIONAL(arg)); + return; + } + } /** @@ -74,7 +204,6 @@ bool sema_error_failed_cast(Expr *expr, Type *from, Type *to) return false; } - /** * Create a type by inferring the length. */ @@ -138,529 +267,58 @@ Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type) } } -/** - * Insert a cast on non-const only - */ -INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) +static bool cast_if_valid(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool is_silent) { - if (expr_is_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false; - return insert_cast(expr, kind, type); -} + Type *from_type = expr->type; -/** - * Insert the PTRXI cast, or on const do a rewrite. - */ -static bool pointer_to_integer(Expr *expr, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_PTRINT, type)) return true; - - // Revisit this to support pointers > 64 bits. - expr_rewrite_const_int(expr, type, expr->const_expr.ptr); - return true; -} - -/** - * Insert the PTRBOOL cast or on const do a rewrite. - */ -static bool pointer_to_bool(Expr *expr, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return true; - - // It may be a pointer - if (expr->const_expr.const_kind == CONST_POINTER) + if (to_type->canonical->type_kind == TYPE_POINTER && from_type->canonical->type_kind != TYPE_POINTER + && to_type->canonical->pointer == from_type->canonical && expr->expr_kind == EXPR_IDENTIFIER + && expr->identifier_expr.was_ref) { - expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0); + RETURN_SEMA_ERROR(expr, "A macro ref parameter is a dereferenced pointer ('*&foo'). You can prefix it" + " with '&' to pass it as a pointer."); + } + + if (from_type == to_type) return true; + + bool is_void_silence = to_type == type_void && is_explicit; + bool add_optional = type_is_optional(to_type) || type_is_optional(from_type); + from_type = type_no_optional(from_type); + to_type = type_no_optional(to_type); + + if (from_type == type_untypedlist) + { + return cast_untyped_to_type(context, expr, to_type); + } + + if (is_void_silence) + { + insert_runtime_cast(expr, CAST_VOID, type_void); return true; } - // Or it's a string, in which case it is always true. - assert(expr->const_expr.const_kind == CONST_STRING); - expr_rewrite_const_bool(expr, type, true); - return true; -} - -/** - * Insert a PTRPTR cast or update the pointer type - */ -static bool pointer_to_pointer(Expr* expr, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_PTRPTR, type)) return true; - - // Strings cannot be compile-time folded, so insert a runtime cast. - if (expr->const_expr.const_kind == CONST_STRING) - { - return insert_cast(expr, CAST_PTRPTR, type); - } - - // Insert the cast, this removes the ability to narrow it. - expr->type = type; - expr->const_expr.is_hex = false; - return true; -} - - -/** - * Bool into a signed or unsigned int using CAST_BOOLINT - * or rewrite to 0 / 1 for false / true. - */ -static bool bool_to_int(Expr *expr, Type *canonical, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return true; - - expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0); - return true; -} - - -/** - * Cast bool to float using CAST_BOOLFP - * or rewrite to 0.0 / 1.0 for false / true - */ -static bool bool_to_float(Expr *expr, Type *canonical, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return true; - - assert(expr->const_expr.const_kind == CONST_BOOL); - expr_rewrite_const_float(expr, type, expr->const_expr.b ? 1.0 : 0.0); - return true; -} - -/** - * Insert a cast from `void!` to some fault type - */ -static bool voidfail_to_error(Expr *expr, Type *type) -{ - assert(type->canonical->type_kind == TYPE_FAULTTYPE || type_is_anyfault(type)); - insert_cast(expr, CAST_VOIDFERR, type); - return true; -} - - -/** - * Cast int to bool using CAST_INTBOOL - * or rewrite 0 => false, any other value => true - */ -static bool integer_to_bool(Expr *expr, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_INTBOOL, type)) return true; - - expr_rewrite_const_bool(expr, type, !int_is_zero(expr->const_expr.ixx)); - return true; -} - -/** - * Cast any float to bool using CAST_FPBOOL - * or rewrite 0.0 => false, any other value => true - */ -static bool float_to_bool(Expr *expr, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_FPBOOL, type)) return true; - - expr_rewrite_const_bool(expr, type, expr->const_expr.fxx.f != 0.0); - return true; -} - - -/** - * Convert any fp to another fp type using CAST_FPFP - */ -static bool float_to_float(Expr* expr, Type *canonical, Type *type) -{ - // Change to same type should never enter here. - assert(type_flatten(canonical) != type_flatten(expr->type)); - - // Insert runtime cast if needed. - if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return true; - - // Otherwise rewrite the const, which may cause rounding. - expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f); - return true; -} - -/** - * Convert from any floating point to int using CAST_FPINT - * Const conversion will disable narrowable and hex. - */ -static bool float_to_integer(Expr *expr, Type *canonical, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_FPINT, type)) return true; - - // Run the int->real to and rewrite. - assert(type_is_integer(canonical)); - Real d = expr->const_expr.fxx.f; - expr->const_expr.ixx = int_from_real(d, canonical->type_kind); - expr->const_expr.const_kind = CONST_INTEGER; - expr->type = type; - expr->const_expr.is_hex = false; - return true; -} - - -/** - * Convert from integer to enum using CAST_INTENUM / or do a const conversion. - * This will ensure that the conversion is valid (i.e. in the range 0 .. enumcount - 1) - */ -static bool integer_to_enum(Expr *expr, Type *canonical, Type *type) -{ - assert(canonical->type_kind == TYPE_ENUM); - Decl *enum_decl = canonical->decl; - - assert(type_flatten(type)->type_kind == TYPE_ENUM); - if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return true; - - // Check that the type is within limits. - unsigned max_enums = vec_size(enum_decl->enums.values); - Int to_convert = expr->const_expr.ixx; - - // Negative numbers are always wrong. - if (int_is_neg(to_convert)) - { - SEMA_ERROR(expr, "A negative number cannot be converted to an enum."); - return false; - } - - // Check the max, we don't support more than 4 billion, - // so we can safely use TYPE_U32. - Int max = { .i.low = max_enums, .type = TYPE_U32 }; - if (int_comp(to_convert, max, BINARYOP_GE)) - { - SEMA_ERROR(expr, "This value exceeds the number of enums in %s.", canonical->decl->name); - return false; - } - - // Fold the const into the actual enum. - Decl *decl = enum_decl->enums.values[to_convert.i.low]; - assert(decl->resolve_status == RESOLVE_DONE); - expr->const_expr = (ExprConst) { - .enum_err_val = decl, - .const_kind = CONST_ENUM + from_type = from_type->canonical; + Type *to = to_type->canonical; + CastContext cc = { + .from_group = type_to_group(from_type), + .from_type = from_type, + .to_group = type_to_group(to), + .to = to, + .to_type = to_type, + .expr = expr, + .context = context }; - expr->type = type; - return true; -} - -/** - * Convert between integers: CAST_INTINT - */ -static bool integer_to_integer(Expr *expr, Type *canonical, Type *type) -{ - // Fold pointer casts if narrowing - // So (int)(uptr)&x => (int)&x in the backend. - if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_PTRINT - && type_size(type) <= type_size(expr->type)) + if (!cast_is_allowed(&cc, is_explicit, false)) { - expr->type = type; - return true; + return false; } - // Insert runtime casts on non-const. - if (insert_runtime_cast_unless_const(expr, CAST_INTINT, type)) return true; - - // Hand this off to the int conversion. - expr->const_expr.ixx = int_conv(expr->const_expr.ixx, canonical->type_kind); - expr->const_expr.const_kind = CONST_INTEGER; - expr->type = type; - expr->const_expr.is_hex = false; - return true; -} - -/** - * Convert 1 => { 1, 1, 1, 1 } using CAST_NUMVEC - */ -static bool integer_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type) -{ - // Fold pointer casts if narrowing - Type *base = type_get_indexed_type(type); - cast(expr, base); - return insert_cast(expr, CAST_NUMVEC, type); -} - -/** - * Convert 1.0 => { 1, 1, 1, 1 } using CAST_NUMVEC - */ -static bool float_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type) -{ - // Fold pointer casts if narrowing - Type *base = type_get_indexed_type(type); - cast(expr, base); - return insert_cast(expr, CAST_NUMVEC, type); -} - - -/** - * Cast a signed or unsigned integer -> floating point, using CAST_INTFP - * for runtime, otherwise do const transformation. - */ -static bool integer_to_float(Expr *expr, Type *canonical, Type *type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_INTFP, type)) return true; - - Real f = int_to_real(expr->const_expr.ixx); - expr_rewrite_const_float(expr, type, f); + cast_no_check(expr, to_type, add_optional); return true; } -/** - * Cast any int to a pointer, will use CAST_INTPTR after a conversion to uptr for runtime. - * Compile time it will check that the value fits the pointer size. - */ -static bool integer_to_pointer(Expr *expr, Type *type) -{ - assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating."); - // Handle const: - if (expr_is_const(expr)) - { - // For if the type doesn't fit, insert an error. - if (!int_fits(expr->const_expr.ixx, type_uptr->canonical->type_kind)) - { - SEMA_ERROR(expr, "'0x%s' does not fit in a pointer.", int_to_str(expr->const_expr.ixx, 16)); - return false; - } - // Otherwise just update. - expr->type = type; - expr->const_expr.ptr = expr->const_expr.ixx.i.low; - expr->const_expr.const_kind = CONST_POINTER; - return true; - } - // Insert widening or narrowing cast as needed. - cast(expr, type_uptr); - return insert_cast(expr, CAST_INTPTR, type); -} - -/** - * Convert an enum to its underlying integer. Is a no-op on for enum expressions. - */ -static void enum_to_int_lowering(Expr* expr) -{ - assert(type_flatten(expr->type)->type_kind == TYPE_ENUM); - Type *underlying_type = type_base(expr->type); - if (expr_is_const(expr)) - { - assert(expr->const_expr.const_kind == CONST_ENUM); - expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); - - } - if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_INTENUM) - { - *expr = *exprptr(expr->cast_expr.expr); - return; - } - expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); -} - -/** - * Cast using CAST_ARRVEC, casting an array to a vector. For the constant, this - * is a simple type change. - */ -static bool array_to_vector(Expr *expr, Type *to_type) -{ - // Runtime cast - if (insert_runtime_cast_unless_const(expr, CAST_ARRVEC, to_type)) return true; - - // For the array -> vector this is always a simple rewrite of type. - assert(expr->const_expr.const_kind == CONST_INITIALIZER); - ConstInitializer *list = expr->const_expr.initializer; - list->type = to_type; - expr->type = to_type; - return true; -} - -/** - * We have two cases: - * 1. int[] -> Foo[] where Foo is a distinct or typedef OR it is a constant. Then we can just redefine - * 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast using CAST_SASA. - */ -INLINE bool subarray_to_subarray(Expr *expr, Type *to_type) -{ - Type *to_type_base = type_flatten(type_flatten(to_type)->array.base); - Type *from_type_base = type_flatten(type_flatten(expr->type)->array.base); - if (expr_is_const(expr) || to_type_base == from_type_base || (to_type_base == type_void || from_type_base == type_void)) - { - // Here we assume int[] -> float[] can't happen. - expr->type = to_type; - return true; - } - return insert_cast(expr, CAST_SASA, to_type); -} - -/** - * Bitstruct casts go from its base type to any integer or char array of the same size. - */ -static bool bitstruct_cast(Expr *expr, Type *bitstruct_type, Type *to, Type *to_type) -{ - assert(type_size(to) == type_size(bitstruct_type) && "Only casts to the same width expected."); - - // The case where the bitstruct is backed by an integer - if (type_is_integer(bitstruct_type)) - { - // The same size integer, this is the simple case. - if (type_is_integer(to)) - { - expr->type = to_type; - return true; - } - // Now we expect a char array of the same size. This - // is runtime only. - assert(to->type_kind == TYPE_ARRAY); - return insert_cast(expr, CAST_BSARRY, to_type); - } - - // Converting from a char array. - assert(bitstruct_type->type_kind == TYPE_ARRAY); - - // Converting to a char array is the simple case, just change the type. - if (to->type_kind == TYPE_ARRAY) - { - expr->type = to_type; - return true; - } - - // Converting to an integer, this is a runtime cast. - assert(type_is_integer(to)); - return insert_cast(expr, CAST_BSINT, to_type); -} - -/** - * Cast using CAST_VECARR, casting an array to a vector. For the constant, this - * is a simple type change, see array_to_vector. - */ -static bool vector_to_array(Expr *expr, Type *to_type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_VECARR, to_type)) return true; - - assert(expr->const_expr.const_kind == CONST_INITIALIZER); - ConstInitializer *list = expr->const_expr.initializer; - list->type = to_type; - expr->type = to_type; - return true; -} - -/** - * Convert vector -> vector. This is somewhat complex as there are various functions - * we need to invoke depending on the underlying type. - */ -static bool vector_to_vector(Expr *expr, Type *to_type) -{ - // - if (!expr_is_const(expr)) - { - // Extract indexed types. - Type *from_type = type_flatten(expr->type); - Type *from_element = from_type->array.base; - to_type = type_flatten(to_type); - Type *to_element = to_type->array.base; - - // float vec -> float/int/bool vec - if (type_is_float(from_element)) - { - switch (to_element->type_kind) - { - case ALL_FLOATS: return insert_cast(expr, CAST_FPFP, to_type); - case TYPE_BOOL: return insert_cast(expr, CAST_FPBOOL, to_type); - case ALL_INTS: return insert_cast(expr, CAST_FPINT, to_type); - default: UNREACHABLE; - } - } - - // bool vec -> float vec - if (from_element == type_bool) - { - // Special conversion to retain the sign. - if (type_is_integer(to_element)) return insert_cast(expr, CAST_BOOLVECINT, to_type); - if (type_is_float(to_element)) return insert_cast(expr, CAST_BOOLFP, to_type); - UNREACHABLE; - } - - // The last possibility is int -> bool/int/fp - assert(type_is_integer(from_element)); - switch (to_element->type_kind) - { - case ALL_FLOATS: return insert_cast(expr, CAST_INTFP, to_type); - case TYPE_BOOL: return insert_cast(expr, CAST_INTBOOL, to_type); - case ALL_INTS: return insert_cast(expr, CAST_INTINT, to_type); - default: UNREACHABLE; - } - } - - assert(expr->const_expr.const_kind == CONST_INITIALIZER); - - // For the const initializer we need to change the internal type - ConstInitializer *list = expr->const_expr.initializer; - vector_const_initializer_convert_to_type(list, to_type); - expr->type = to_type; - return true; -} - -/** - * Perform vararg promotions typical for C style varargs: - * 1. Widen int and bool to C int size - * 2. Widen float and smaller to double - * 3. Turn subarrays into pointers - */ -bool cast_promote_vararg(Expr *arg) -{ - // Remove things like distinct, optional, enum etc. - Type *arg_type = type_flatten(arg->type); - - // 1. Promote any integer or bool to at least CInt - if (type_is_promotable_int_bool(arg_type)) return cast(arg, type_cint); - - // 2. Promote any float to at least double - if (type_is_promotable_float(arg_type)) return cast(arg, type_double); - - // 3. Turn subarrays into pointers - if (arg_type->type_kind == TYPE_SUBARRAY) return cast(arg, type_get_ptr(arg_type->array.base)); - - return true; -} -/** - * Cast an untyped list to a particular type. - */ -bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type) -{ - // Recursively set the type of all ConstInitializer inside. - expr_recursively_rewrite_untyped_list(expr, expr->const_expr.untyped_list); - // We can now analyse the list (this is where the actual check happens) - if (!sema_expr_analyse_initializer_list(context, type_flatten(to_type), expr)) return false; - // And set the type. - expr->type = to_type; - return true; -} - -/** - * Given lhs and rhs, promote to the maximum bit size, this will retain - * signed/unsigned type of each side. - */ -void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type) -{ - unsigned bit_size_left = left_type->builtin.bitsize; - unsigned bit_size_right = right_type->builtin.bitsize; - - assert(bit_size_left && bit_size_right); - - // Simple case they are the same size, just return. - if (bit_size_left == bit_size_right) return; - - // Lhs is smaller than rhs, so widen it using the right type - if (bit_size_left < bit_size_right) - { - Type *to = lhs->type->type_kind < TYPE_U8 - ? type_int_signed_by_bitsize(bit_size_right) - : type_int_unsigned_by_bitsize(bit_size_right); - bool success = cast(lhs, to); - assert(success); - return; - } - - // Rhs is smaller, do the same thing as above but with the rhs. - Type *to = rhs->type->type_kind < TYPE_U8 - ? type_int_signed_by_bitsize(bit_size_left) - : type_int_unsigned_by_bitsize(bit_size_left); - bool success = cast(rhs, to); - assert(success); -} /** * For implicit casts to bool, in a conditional, return the type of cast to @@ -673,6 +331,7 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_WILDCARD: case TYPE_BOOL: return CAST_BOOLBOOL; + case TYPE_FAULTTYPE: case TYPE_ANYFAULT: return CAST_EUBOOL; case TYPE_SUBARRAY: @@ -683,8 +342,6 @@ CastKind cast_to_bool_kind(Type *type) return CAST_FPBOOL; case TYPE_POINTER: return CAST_PTRBOOL; - case TYPE_FAULTTYPE: - return CAST_ERBOOL; case TYPE_ENUM: case FLATTENED_TYPES: // These are not possible due to flattening. @@ -885,145 +542,7 @@ CHECK_SIZE: return NULL; } -/** - * Cast to a given type, making it an optional type as needed. - * - */ -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; -} -/** - * Cast a subarray to some other type: - * 1. To another subarray => works if the array elements are equivalent. - * 2. To another pointer => works if the pointer is void* or the array element and pointee is equivalent. - * 3. To bool => explicit cast is ok. - */ -static bool cast_from_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ - switch (to->type_kind) - { - case TYPE_SUBARRAY: - // Casting to another subarray works if the elements are equivalent. - switch (type_array_element_is_equivalent(context, from->array.base, to->array.base, is_explicit)) - { - case TYPE_ERROR: return false; - case TYPE_MISMATCH: return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(context, from->array.base, to->array.base, true) == TYPE_SAME, silent); - case TYPE_SAME: return cast_with_optional(expr, to_type, add_optional); - } - UNREACHABLE; - case TYPE_POINTER: - // Casting to another pointer works if either the pointer is void* or the element and pointee are equivalent. - if (to == type_voidptr) return cast_with_optional(expr, to_type, add_optional); - switch (type_array_element_is_equivalent(context, from->array.base, to->pointer, is_explicit)) - { - case TYPE_MISMATCH: return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(context, from->array.base, to->pointer, true), silent); - case TYPE_ERROR: return false; - case TYPE_SAME: return cast_with_optional(expr, to_type, add_optional); - } - UNREACHABLE - case TYPE_BOOL: - // Only explicit bool casts are allowed. - if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, silent); - return cast_with_optional(expr, to_type, add_optional); - default: - return sema_error_cannot_convert(expr, to_type, false, silent); - } - UNREACHABLE -} - -/** - * Try casting to a pointer. - * 1. Any pointer -> any, any pointer -> void*, void* -> any pointer - always works. - * 2. Pointer -> integer must be explicit and type size >= uptr - * 3. Pointer -> subarray if the pointer points to a vector or array, allow void*[2]* -> int*[2]* (pointer equivalence). - * 4. Pointer -> bool must be explicit (conditionals are treated as a special case. - * 5. Pointer -> pointer explicit always works, otherwise they must have pointer equivalence. - */ -static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ - // pointer -> any, void* -> pointer pointer -> void* - if (type_is_any(to) || to == type_voidptr || (from == type_voidptr && type_is_pointer(to))) return cast_with_optional(expr, to_type, add_optional); - - Type *pointee = from->pointer; - pointee = is_explicit ? type_flatten(pointee) : pointee->canonical; - TypeKind pointee_kind = pointee->type_kind; - switch (to->type_kind) - { - case ALL_INTS: - // Only explicit cast - if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, silent); - // The type must be uptr or bigger. - if (type_size(to_type) < type_size(type_uptr)) - { - 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]* - if (pointee_kind == TYPE_ARRAY || pointee_kind == TYPE_VECTOR) - { - Type *subarray_base = to->array.base->canonical; - Type *from_base = pointee->array.base; - if (is_explicit) - { - subarray_base = type_flatten(subarray_base); - from_base = type_flatten(from_base); - } - // Same base type? E.g. int[2]* -> int[], then we're done. - if (subarray_base == from_base) return cast_with_optional(expr, to_type, add_optional); - - // Otherwise we might have int*[2]* -> void*[], use pointer equivalence. - if (subarray_base->type_kind == TYPE_POINTER && from_base->type_kind == TYPE_POINTER) - { - switch (type_is_pointer_equivalent(context, subarray_base, from_base, is_explicit)) - { - case TYPE_SAME: return cast_with_optional(expr, to_type, add_optional); - case TYPE_ERROR: return false; - default: break; - } - } - // Silent? Then we're done. - if (silent) return false; - // Check if this would work if explicit for a good error message: - bool would_work_explicit = false; - if (!is_explicit) - { - would_work_explicit = cast_from_pointer(context, expr_copy(expr), - from, to, to_type, add_optional, true, true); - } - return sema_error_cannot_convert(expr, to_type, would_work_explicit, false); - } - // All other fails. - return sema_error_cannot_convert(expr, to_type, false, silent); - case TYPE_BOOL: - // Only explicit conversion allowed. - if (is_explicit) return cast_with_optional(expr, to_type, add_optional); - return sema_error_cannot_convert(expr, to_type, true, silent); - case TYPE_POINTER: - // Explicit conversion always works. - if (is_explicit) return cast_with_optional(expr, to_type, add_optional); - // See if the pointee is equivalent. - switch (type_is_pointer_equivalent(context, from, to, false)) - { - case TYPE_SAME: return cast_with_optional(expr, to_type, add_optional); - case TYPE_ERROR: return false; - default: return sema_error_cannot_convert(expr, to_type, true, silent); - } - case TYPE_OPTIONAL: - UNREACHABLE - default: - // All other types are forbidden. - return sema_error_cannot_convert(expr, to_type, false, silent); - } -} static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type) { @@ -1045,53 +564,20 @@ static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *t type_quoted_error_string(to_type)); } - -static inline bool cast_maybe_string_byte_lit(Expr *expr, Type *to_canonical, Type *to_original) +/** + * Cast an untyped list to a particular type. + */ +static bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type) { - if (!expr_is_const(expr)) return false; - bool is_bytes = false; - switch (expr->const_expr.const_kind) - { - case CONST_BYTES: - if (expr->type->type_kind != TYPE_ARRAY) return false; - is_bytes = true; - break; - case CONST_STRING: - if (expr->type != type_string) return false; - break; - default: - return false; - } - Type *flat = type_flatten(to_canonical); - Type *indexed_type = type_get_indexed_type(flat); - if (indexed_type) indexed_type = type_flatten(indexed_type); - size_t len = is_bytes ? expr->const_expr.bytes.len : expr->const_expr.bytes.len; - switch (flat->type_kind) - { - case TYPE_SUBARRAY: - case TYPE_POINTER: - if (indexed_type != type_char && indexed_type != type_ichar) return false; - expr->type = to_original; - return true; - case TYPE_INFERRED_ARRAY: - if (indexed_type != type_char && indexed_type != type_ichar) return false; - expr->type = type_infer_len_from_actual_type(to_original, type_get_array(indexed_type, len)); - return true; - case TYPE_ARRAY: - if (indexed_type != type_char && indexed_type != type_ichar) return false; - { - ArraySize to_len = flat->array.len; - if (len > to_len) return false; - expr->type = to_original; - return true; - } - break; - default: - return false; - } + // Recursively set the type of all ConstInitializer inside. + expr_recursively_rewrite_untyped_list(expr, expr->const_expr.untyped_list); + // We can now analyse the list (this is where the actual check happens) + if (!sema_expr_analyse_initializer_list(context, type_flatten(to_type), expr)) return false; + // And set the type. + expr->type = type_infer_len_from_actual_type(to_type, expr->type); + return true; } - /** * Recursively change a const list to an initializer list. */ @@ -1106,892 +592,8 @@ static void expr_recursively_rewrite_untyped_list(Expr *expr, Expr **list) FOREACH_END(); } -/** - * Try to make an implicit cast. Optional types are allowed. - */ -bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) -{ - return cast_expr_inner(context, expr, to_type, false, false, false); -} -/** - * Try to make an explicit cast, Optional types are allowed. - */ -bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type) -{ - return cast_expr_inner(context, expr, to_type, true, false, false); -} - -/** - * Try to make an implicit cast. If optional is allowed or not depends on the parameter. - * This is mostly used with assignment. - */ -bool cast_implicit_maybe_optional(SemaContext *context, Expr *expr, Type *to_type, bool may_be_optional) -{ - return cast_expr_inner(context, expr, to_type, false, false, !may_be_optional); -} - -/** - * Silent implicit casting will attempt a cast, but will silently back out if it fails. - */ -bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type) -{ - return cast_expr_inner(context, expr, to_type, false, true, false); -} - -/** - * Common error reporting for casts. - */ -static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent) -{ - if (silent) return false; - if (may_cast_explicit) - { - 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))); - } - 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; - -} - -/** - * Attempt casting an array. - * 1. Inferred array / vector => infer type - * 2. Array / vector => ok if len matches. - * 3. Check for array element equivalence. - */ -static bool cast_from_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ - switch (to->type_kind) - { - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - // We infer the target type (note that to and to_type are now of different kinds). - to_type = type_infer_len_from_actual_type(to_type, from); - break; - case TYPE_VECTOR: - case TYPE_ARRAY: - // Len must be checked. - if (to->array.len != from->array.len) return sema_error_cannot_convert(expr, to_type, false, silent); - break; - case TYPE_BITSTRUCT: - if (to->decl->bitstruct.base_type->type->canonical == from) return cast_with_optional(expr, to_type, add_optional); - FALLTHROUGH; - default: - // No other conversions are allowed. - return sema_error_cannot_convert(expr, to_type, false, silent); - } - // Check array element equivalence. - switch (type_array_element_is_equivalent(context, from->array.base, to->array.base, is_explicit)) { - case TYPE_ERROR: - return false; - case TYPE_SAME: - // Insert the cast. - return cast_with_optional(expr, to_type, add_optional); - default: - break; - } - - if (silent) return false; - // Create a good error message, so we can give a hint that maybe you can do an explicit cast. - bool explicit_would_work = !is_explicit && type_array_element_is_equivalent(context, from->array.base, to->array.base, true); - return sema_error_cannot_convert(expr, to_type, explicit_would_work, silent); -} - -/** - * Check a vector element and see if it may implicitly convert to the other type. - */ -static bool cast_vector_element_may_implicitly_convert(Expr *expr, Type *from, Type *to) -{ - from = from->canonical; - to = to->canonical; - - // Same type - we're fine. - if (from == to) return true; - - // If any of the elements are distinct we know it doesn't work, - if (from->type_kind == TYPE_DISTINCT || to->type_kind == TYPE_DISTINCT) return false; - - // Casting from bool always works (for int, float) - if (from == type_bool) return true; - - // Casting to bool never works (for int, float) - if (to == type_bool) return false; - - // Handle floats - if (type_is_float(to)) - { - // Any integer may convert to a float. - if (type_is_integer(from)) return true; - - if (type_is_float(from)) - { - // Explict casts always work - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - // Same size is ok - if (to_size == from_size) return true; - // Widening is ok if the expression is simple. - return to_size > from_size && expr_is_simple(expr); - } - // No other possibility - UNREACHABLE; - } - - // Last case is integer. - assert(type_is_integer(to)); - - // float -> int can't be done implicitly - if (type_is_float(from)) return false; - - assert(type_is_integer(from)); - - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - // Same size is ok - if (to_size == from_size) return true; - // Widening is ok if expression is simple. Narrowing is prohibited. - return to_size > from_size && expr_is_simple(expr); -} - -/** - * Check all casts from vectors: - * 1. To arrays and inferred arrays -> if the array type matches, eg int[<2>] to int[2] - * 2. To vectors and inferred vectors -> if the vector type can be promoted, e.g. int[<2>] to long[<2>] - */ -static bool cast_from_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ - bool not_to_vector = !type_kind_is_any_vector(to->type_kind); - switch (to->type_kind) - { - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - // Update the to_type (but not to!) - to_type = type_infer_len_from_actual_type(to_type, from); - break; - case TYPE_ARRAY: - case TYPE_VECTOR: - // Len must match. - if (to->array.len != from->array.len) return sema_error_cannot_convert(expr, to_type, false, silent); - break; - default: - // All other conversions fail - return sema_error_cannot_convert(expr, to_type, false, silent); - } - Type *from_base = from->array.base; - Type *to_base = to->array.base; - // vector -> array cast. - if (not_to_vector) - { - // Here we do simple array element equivalence, that is int[<2>] -> int[2] is ok, but not int[<2>] -> float[2] - switch (type_array_element_is_equivalent(context, from_base, to_base, is_explicit)) - { - case TYPE_SAME: return cast_with_optional(expr, to_type, add_optional); - case TYPE_ERROR: return false; - default: - // Give us a nice hint in case an explicit conversion would work. - if (silent) return false; - bool may_explicit = !is_explicit && type_array_element_is_equivalent(context, from_base, to_base, true); - return sema_error_cannot_convert(expr, to, may_explicit, true); - } - } - // Vector -> vector cast - // This allows for things like int[<2>] -> float[<2>] conversions. - if (!is_explicit && !cast_vector_element_may_implicitly_convert(expr, from_base, to_base)) - { - if (silent) return false; - // Give us a nice hint that explicit conversion would work. - return sema_error_cannot_convert(expr, to, true, false); - } - return cast_with_optional(expr, to_type, add_optional); -} - - -/** - * Cast from an enum to other types. - * 1. Only explicit casts are allowed. - * 2. Casting to any integer is valid for the explicit cast. - */ -static bool cast_from_enum(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ - if (!is_explicit) - { - bool may_cast = type_is_integer(type_flatten(to)); - sema_error_cannot_convert(expr, to_type, may_cast, silent); - return false; - } - if (!type_is_integer(to)) - { - sema_error_cannot_convert(expr, to_type, false, silent); - return false; - } - return cast_with_optional(expr, to_type, add_optional); -} - -/** - * Cast an integer. Note here that "from" may be an enum. - * 1. Floats -> always works - * 2. Bools -> explicit only - * 3. Vector -> check if the underlying type can be converted. - * 4. Enum -> if from is an enum, then fails, otherwise follow int conversions. - * 5. Int -> any int is ok if explicit or same width, if const, check fits, wider -> only simple, narrow -> check narrowing. - * 6. Distinct -> expr is const, then try as if it was the base type, otherwise fail. - */ -static bool cast_from_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ -RETRY: - switch (to->type_kind) - { - case ALL_FLOATS: - // All floats are ok. - goto CAST; - case TYPE_BOOL: - // Explicit only - if (is_explicit) goto CAST; - goto REQUIRE_CAST; - case TYPE_VECTOR: - // Check underlying type - to = to->array.base->canonical; - goto RETRY; - case TYPE_ENUM: - if (is_explicit) goto CAST; - goto REQUIRE_CAST; - case TYPE_BITSTRUCT: - if (type_flatten(to->decl->bitstruct.base_type->type) != type_flatten(from)) break; - if (is_explicit) goto CAST; - goto REQUIRE_CAST; - case ALL_INTS: - { - // All explicit casts work. - if (is_explicit) goto CAST; - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - // If widening, require simple. - if (to_size > from_size) goto ONLY_SIMPLE; - // If const, check in range. - 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; - } - // Same size => ok - if (to_size == from_size) goto CAST; - assert(to == type_flatten(to)); - // Check if narrowing works - Expr *problem = recursive_may_narrow(expr, to); - if (problem) - { - if (silent) return false; - // If it's an integer that's the problem, zoom in on that one. - if (type_is_integer(type_flatten(problem->type))) expr = problem; - // Otherwise require a cast. - goto REQUIRE_CAST; - } - goto CAST; - } - case TYPE_DISTINCT: - // The only conversion works if the expr is const. - if (expr_is_const(expr) && type_is_integer(from)) - { - to = type_flatten(to); - goto RETRY; - } - // Failure - if (silent) return false; - bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, true, true, false); - 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 (!is_explicit) - { - if (may_cast) goto REQUIRE_CAST; - break; - } - if (!may_cast) - { - if (silent) 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, silent); -ONLY_SIMPLE: - if (expr_is_simple(expr)) goto CAST; - if (silent) 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 (silent) 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); -} - -/** - * Casting from a float - * 1. To ints and bools -> valid with explicit casts. - * 2. To vectors -> valid if the it can cast to vector element type. - * 3. To floats -> narrowing if sub expression can be narrowed. Widening if the expr is simple. - * 4. To distinct -> try as if it was the base type if const, otherwise fail. - */ -static inline bool cast_from_float(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) -{ -RETRY: - switch (to->type_kind) - { - case ALL_INTS: - case TYPE_BOOL: - // Bool and ints? Explicit casts only. - if (is_explicit) goto CAST; - goto REQUIRE_CAST; - case TYPE_VECTOR: - // Check if the underlying element may be cast. - to = to->array.base->canonical; - goto RETRY; - case ALL_FLOATS: - { - // All explicit casts just work. - if (is_explicit) goto CAST; - // If widening, only allow simple expressions. - ByteSize to_size = type_size(to); - ByteSize from_size = type_size(from); - if (to_size > from_size) goto ONLY_SIMPLE; - // If same size, just cast. - if (to_size == from_size) goto CAST; - // If const, check it fits. - if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind)) - { - if (silent) 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; - } - // Otherwise, check if the underlying code may narrow. - Expr *problem = recursive_may_narrow(expr, to); - if (problem) - { - if (silent) return false; - expr = problem; - goto REQUIRE_CAST; - } - // If no problem -> cast. - goto CAST; - } - case TYPE_DISTINCT: - // Ignore distinct if casting from a const. - if (expr_is_const(expr)) - { - to = type_flatten(to); - goto RETRY; - } - else - { - if (silent) return false; - // Give a good error message, suggesting a cast if the cast had worked - bool may_explicit = cast_from_float(context, expr_copy(expr), from, type_flatten(to), to_type, add_optional, true, true); - if (may_explicit) goto REQUIRE_CAST; - break; - } - default: - break; - } - return sema_error_cannot_convert(expr, to_type, false, silent); -ONLY_SIMPLE: - if (expr_is_simple(expr)) goto CAST; - if (silent) 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 (silent) 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); -} - -/** - * 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, bool is_explicit, bool silent, - bool may_not_be_optional) -{ - Type *from_type = expr->type; - - assert(!type_is_optional(to_type) || may_not_be_optional); - - if (to_type->canonical->type_kind == TYPE_POINTER && from_type->canonical->type_kind != TYPE_POINTER - && to_type->canonical->pointer == from_type->canonical && expr->expr_kind == EXPR_IDENTIFIER - && expr->identifier_expr.was_ref) - { - RETURN_SEMA_ERROR(expr, "A macro ref parameter is a dereferenced pointer ('*&foo'). You can prefix it" - " with '&' to pass it as a pointer."); - } - // Allow (void)foo - if (is_explicit && to_type == type_void) - { - return cast(expr, to_type); - } - - Type *to = is_explicit ? type_flatten(to_type) : type_no_optional(to_type)->canonical; - if (!sema_resolve_type_decl(context, to)) return false; - if (!sema_resolve_type_decl(context, from_type)) return false; - - // Step one, cast from optional. - // This handles: *! + type -> type! and stops casts when they may not be optional. - if (type_is_optional(from_type)) - { - Type *opt = from_type->optional; - - // *! -> int => ok, gives int! - if (opt == type_wildcard) - { - if (may_not_be_optional) - { - if (silent) 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; - } - - if (may_not_be_optional) - { - if (silent) 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(from_type) : from_type->canonical; - - // Auto-converting distinct type. - if (from->type_kind == TYPE_DISTINCT && from->decl->is_substruct && from != to) - { - from = type_flatten(from); - } - - // We may already be done. - if (from == to || from == type_wildcard) - { - expr->type = type_add_optional(to_type, add_optional); - return true; - } - - - // Handle strings, these don't actually mess with the underlying data, - // just the type. - if (cast_maybe_string_byte_lit(expr, to, to_type)) return true; - - // For constant pointers cast into anything pointer-like: - if (expr_is_const_pointer(expr) && from == type_voidptr && type_flatten(to)->type_kind == TYPE_POINTER) - { - assert(!add_optional); - expr->type = to_type; - return true; - } - switch (from->type_kind) - { - 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: - // Allow MyError.A -> error, to an integer or to bool - if (type_is_anyfault(to)) return cast(expr, to_type); - if (type_is_integer(to) || to == type_bool) goto CAST_IF_EXPLICIT; - goto CAST_FAILED; - case TYPE_ANYFAULT: - 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_from_pointer(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case TYPE_SUBARRAY: - return cast_from_subarray(context, expr, from, to, to_type, add_optional, is_explicit, silent); - 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: - return cast_from_vector(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case TYPE_ARRAY: - return cast_from_array(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case TYPE_ENUM: - return cast_from_enum(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case ALL_INTS: - return cast_from_integer(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case ALL_FLOATS: - return cast_from_float(context, expr, from, to, to_type, add_optional, is_explicit, silent); - case TYPE_POISONED: - return false; - case TYPE_WILDCARD: - UNREACHABLE - case TYPE_VOID: - case TYPE_INFERRED_ARRAY: - case TYPE_TYPEINFO: - case TYPE_FUNC: - case TYPE_FLEXIBLE_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_MEMBER: - goto CAST_FAILED; - case TYPE_TYPEID: - if (!type_is_pointer_sized_or_more(to_type)) goto CAST_FAILED; - goto CAST_IF_EXPLICIT; - case TYPE_OPTIONAL: - case TYPE_TYPEDEF: - UNREACHABLE; - case TYPE_ANY: - if (to->type_kind != TYPE_POINTER) goto CAST_FAILED; - goto CAST_IF_EXPLICIT; - case TYPE_STRUCT: - if (type_is_substruct(from)) - { - Type *type; - Expr *access = expr_access_inline_member(expr_copy(expr), from->decl); - while (1) - { - type = access->type->canonical; - if (type == to) break; - if (!type_is_substruct(type)) goto CAST_FAILED; - } - expr_replace(expr, access); - return true; - } - goto CAST_FAILED; - case TYPE_UNION: - goto CAST_FAILED; - case TYPE_BITSTRUCT: - // A bitstruct can convert to: - // 1. An int of the same length - // 2. An integer array of the same length - if (type_size(to_type) != type_size(from_type)) goto CAST_FAILED; - if (type_is_integer(to_type)) goto CAST_IF_EXPLICIT; - if (to_type->type_kind == TYPE_ARRAY && type_is_integer(to_type->array.base)) goto CAST_IF_EXPLICIT; - goto CAST_FAILED; - UNREACHABLE - case TYPE_DISTINCT: - assert(!is_explicit); - if (cast_expr_inner(context, expr, to_type, true, true, false)) - { - goto CAST_IF_EXPLICIT; - } - goto CAST_FAILED; - } - UNREACHABLE - -CAST_IF_EXPLICIT: - if (!is_explicit) - { - if (silent) 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; - } - return cast(expr, to_type); -CAST_FAILED: - if (!silent) - { - if (!is_explicit) - { - 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); - } - return false; -} - -static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type) -{ - switch (initializer->kind) - { - case CONST_INIT_ARRAY: - { - Type *element_type = type_flatten(to_type)->array.base; - FOREACH_BEGIN(ConstInitializer *element, initializer->init_array.elements) - vector_const_initializer_convert_to_type(element, element_type); - FOREACH_END(); - break; - } - case CONST_INIT_ARRAY_FULL: - { - Type *element_type = type_flatten(to_type)->array.base; - FOREACH_BEGIN(ConstInitializer *element, initializer->init_array_full) - vector_const_initializer_convert_to_type(element, element_type); - FOREACH_END(); - break; - } - case CONST_INIT_VALUE: - { - Type *to_flat = type_flatten(to_type); - bool is_neg_conversion = to_flat && type_flatten(initializer->type) == type_bool; - if (is_neg_conversion) - { - bool is_true = initializer->init_value->const_expr.b; - initializer->init_value->const_expr.const_kind = CONST_INTEGER; - initializer->init_value->const_expr.ixx = (Int) - { .i = is_true ? (Int128) { UINT64_MAX, UINT64_MAX } : (Int128) { 0, 0 }, - .type = to_flat->type_kind }; - initializer->init_value->type = to_type; - } - else - { - cast(initializer->init_value, to_type); - } - break; - } - case CONST_INIT_ZERO: - break; - case CONST_INIT_UNION: - case CONST_INIT_STRUCT: - UNREACHABLE - case CONST_INIT_ARRAY_VALUE: - vector_const_initializer_convert_to_type(initializer->init_array_value.element, to_type); - break; - } - initializer->type = to_type; -} - - -static bool err_to_anyfault(Expr *expr, Type *to_type) -{ - expr->type = to_type; - return true; -} - -static bool err_to_bool(Expr *expr, Type *to_type) -{ - if (insert_runtime_cast_unless_const(expr, CAST_ERBOOL, to_type)) return true; - - assert(expr->const_expr.const_kind == CONST_ERR); - - expr_rewrite_const_bool(expr, type_bool, expr->const_expr.enum_err_val != NULL); - return true; -} - -static inline bool subarray_to_bool(Expr *expr, Type *type) -{ - if (expr_is_const_initializer(expr)) - { - ConstInitializer *list = expr->const_expr.initializer; - switch (list->kind) - { - case CONST_INIT_ZERO: - expr_rewrite_const_bool(expr, type, false); - return true; - case CONST_INIT_ARRAY: - expr_rewrite_const_bool(expr, type, vec_size(list->init_array.elements) > 0); - return true; - case CONST_INIT_ARRAY_FULL: - expr_rewrite_const_bool(expr, type, vec_size(list->init_array_full) > 0); - return true; - case CONST_INIT_STRUCT: - case CONST_INIT_UNION: - case CONST_INIT_VALUE: - case CONST_INIT_ARRAY_VALUE: - break; - } - } - return insert_cast(expr, CAST_SABOOL, type); -} - -static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) -{ - switch (from_type->type_kind) - { - case TYPE_OPTIONAL: - case TYPE_VOID: - UNREACHABLE - case TYPE_DISTINCT: - case TYPE_FUNC: - case TYPE_TYPEDEF: - case CT_TYPES: - UNREACHABLE - case TYPE_BITSTRUCT: - return bitstruct_cast(expr, type_flatten(from_type->decl->bitstruct.base_type->type), to, to_type); - case TYPE_BOOL: - // Bool may convert into integers and floats but only explicitly. - if (type_is_integer(to)) return bool_to_int(expr, to, to_type); - if (type_is_float(to)) return bool_to_float(expr, to, to_type); - break; - case TYPE_ANYFAULT: - if (to->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type); - if (to->type_kind == TYPE_FAULTTYPE) - { - REMINDER("Improve anyfault -> fault conversion."); - return insert_cast(expr, CAST_EUER, to_type); - } - if (type_is_integer(to)) return insert_cast(expr, CAST_EUINT, to_type); - break; - case ALL_SIGNED_INTS: - if (type_is_integer(to)) return integer_to_integer(expr, to, to_type); - if (type_is_float(to)) return integer_to_float(expr, to, to_type); - if (to == type_bool) return integer_to_bool(expr, to_type); - if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type); - if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type); - if (to->type_kind == TYPE_BITSTRUCT) return insert_cast(expr, CAST_INTBS, to_type); - if (type_kind_is_any_vector(to->type_kind)) return integer_expand_to_vector_conversion(expr, to, to_type); - break; - case ALL_UNSIGNED_INTS: - if (type_is_integer(to)) return integer_to_integer(expr, to, to_type); - if (type_is_float(to)) return integer_to_float(expr, to, to_type); - if (to == type_bool) return integer_to_bool(expr, to_type); - if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type); - if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type); - if (type_kind_is_any_vector(to->type_kind)) return integer_expand_to_vector_conversion(expr, to, to_type); - if (to->type_kind == TYPE_BITSTRUCT) return insert_cast(expr, CAST_INTBS, to_type); - break; - case ALL_FLOATS: - if (type_is_integer(to)) return float_to_integer(expr, to, to_type); - if (to == type_bool) return float_to_bool(expr, to_type); - if (type_is_float(to)) return float_to_float(expr, to, to_type); - if (type_kind_is_any_vector(to->type_kind)) return float_expand_to_vector_conversion(expr, to, to_type); - break; - case TYPE_TYPEID: - case TYPE_POINTER: - if (type_is_integer(to)) return pointer_to_integer(expr, to_type); - if (to->type_kind == TYPE_BOOL) return pointer_to_bool(expr, to_type); - if (to->type_kind == TYPE_POINTER) return pointer_to_pointer(expr, to_type); - if (to->type_kind == TYPE_SUBARRAY) return insert_cast(expr, CAST_APTSA, to_type); - if (to->type_kind == TYPE_ANY || to_type->type_kind == TYPE_ANY) return insert_cast(expr, CAST_PTRANY, to_type); - break; - case TYPE_ANY: - if (to->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_ANYPTR, to_type); - break; - case TYPE_ENUM: - enum_to_int_lowering(expr); - if (type_is_integer(to)) return integer_to_integer(expr, to, to_type); - if (type_is_float(to)) return integer_to_float(expr, to, to_type); - if (to == type_bool) return integer_to_bool(expr, to_type); - if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type); - if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type); - break; - case TYPE_FAULTTYPE: - if (to->type_kind == TYPE_ANYFAULT) return err_to_anyfault(expr, to_type); - if (to == type_bool) return err_to_bool(expr, to_type); - if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type); - break; - case TYPE_FLEXIBLE_ARRAY: - return false; - case TYPE_ARRAY: - if (to->type_kind == TYPE_VECTOR) return array_to_vector(expr, to_type); - if (to->type_kind == TYPE_BITSTRUCT) return insert_cast(expr, CAST_ARRBS, to_type); - FALLTHROUGH; - case TYPE_STRUCT: - case TYPE_UNION: - - if (to->type_kind == TYPE_ARRAY || to->type_kind == TYPE_STRUCT || to->type_kind == TYPE_UNION) - { - return insert_cast(expr, CAST_STST, to_type); - } // Starting in a little while... - break; - case TYPE_SUBARRAY: - if (to->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_SAPTR, to_type); - if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr, to_type); - if (to->type_kind == TYPE_SUBARRAY) return subarray_to_subarray(expr, to_type); - break; - case TYPE_VECTOR: - if (to->type_kind == TYPE_ARRAY) return vector_to_array(expr, to_type); - if (to->type_kind == TYPE_VECTOR) return vector_to_vector(expr, to_type); - break; - } - UNREACHABLE -} - - -bool cast(Expr *expr, Type *to_type) -{ - if (to_type == type_void) - { - insert_cast(expr, CAST_VOID, type_void); - return true; - } - - assert(!type_is_optional(to_type)); - Type *from_type = expr->type; - bool from_is_optional = false; - Type *to = type_flatten(to_type); - - // Special case *! => error - if (type_is_anyfault(to) || to->type_kind == TYPE_FAULTTYPE) - { - if (type_is_optional(from_type)) return voidfail_to_error(expr, to_type); - } - - if (type_is_optional(from_type)) - { - from_type = from_type->optional; - from_is_optional = true; - } - - if (from_type == type_wildcard) - { - expr->type = type_add_optional(to_type, from_is_optional); - return true; - } - - from_type = type_flatten(from_type); - if (type_len_is_inferred(to_type)) - { - to_type = from_type; - to = type_flatten(from_type); - } - if (from_type == to) - { - expr->type = type_add_optional(to_type, from_is_optional); - if (expr_is_const(expr)) - { - expr->const_expr.is_hex = false; - } - return true; - } - - if (!cast_inner(expr, from_type, to, to_type)) return false; - - Type *result_type = expr->type; - if (from_is_optional && !type_is_optional(result_type)) - { - expr->type = type_get_optional(result_type); - } - return true; -} - -bool cast_to_index(Expr *index) +bool cast_to_index(SemaContext *context, Expr *index) { Type *type = index->type->canonical; RETRY: @@ -2001,12 +603,12 @@ bool cast_to_index(Expr *index) case TYPE_I16: case TYPE_I32: case TYPE_I64: - return cast(index, type_isz); + return cast_explicit(context, index, type_isz); case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: - return cast(index, type_usz); + return cast_explicit(context, index, type_usz); case TYPE_U128: SEMA_ERROR(index, "You need to explicitly cast this to a uint or ulong."); return false; @@ -2043,7 +645,6 @@ bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type) return cast_implicit(context, expr, type); } - Type *cast_numeric_arithmetic_promotion(Type *type) { if (!type) return NULL; @@ -2066,7 +667,1332 @@ Type *cast_numeric_arithmetic_promotion(Type *type) } } +static void report_cast_error(CastContext *cc, bool may_cast_explicit) +{ + Expr *expr = cc->expr; + Type *to = cc->to_type; + if (may_cast_explicit) + { + SEMA_ERROR(expr, + "Implicitly casting %s to %s is not permitted, but you may 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))); + } + else + { + SEMA_ERROR(expr, + "It is not possible to cast %s to %s.", + type_quoted_error_string(type_no_optional(expr->type)), type_quoted_error_string(to)); + } +} + +INLINE bool sema_cast_error(CastContext *cc, bool may_cast_explicit, bool is_silent) +{ + if (is_silent) return false; + report_cast_error(cc, may_cast_explicit); + return false; +} + +// RULES ---- + +static TypeCmpResult match_pointers(CastContext *cc, Type *to_ptr, Type *from_ptr, bool flatten, bool is_silent) +{ + if (is_silent) + { + bool old_suppress_err = global_context.suppress_errors; + global_context.suppress_errors = true; + TypeCmpResult res = type_is_pointer_equivalent(cc->context, to_ptr, from_ptr, flatten); + global_context.suppress_errors = old_suppress_err; + return res; + } + return type_is_pointer_equivalent(cc->context, to_ptr, from_ptr, flatten); +} + +static bool rule_ptr_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (is_explicit) return true; + switch (match_pointers(cc, cc->to, cc->from_type, is_silent, false)) + { + case TYPE_SAME: + return true; + case TYPE_ERROR: + return false; + case TYPE_MISMATCH: + return sema_cast_error(cc, true, is_silent); + } + UNREACHABLE +} +static bool rule_all_ok(CastContext *cc, bool is_explicit, bool silent) +{ + return true; +} -#pragma clang diagnostic pop \ No newline at end of file +static bool rule_int_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) +{ + // Handle const: + Expr *expr = cc->expr; + if (expr_is_const(expr)) + { + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + + // For if the type doesn't fit, insert an error. + if (!int_fits(expr->const_expr.ixx, type_uptr->canonical->type_kind)) + { + if (is_silent) return false; + SEMA_ERROR(expr, "'0x%s' does not fit in a pointer.", int_to_str(expr->const_expr.ixx, 16)); + return false; + } + return true; + } + + if (type_size(cc->from_type) < type_size(type_iptr)) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(expr, "You cannot convert an integer smaller than a pointer size to a pointer."); + } + + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + + return true; +} + +static bool rule_ptr_to_int(CastContext *cc, bool is_explicit, bool is_silent) +{ + bool too_small = type_size(cc->to_type) < type_size(type_uptr); + if (!is_explicit) return sema_cast_error(cc, !too_small, is_silent); + + // The type must be uptr or bigger. + if (too_small) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(cc->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(cc->expr->type), type_quoted_error_string(cc->to_type), + type_to_error_string(cc->to_type), type_to_error_string(cc->to_type)); + } + return true; +} + +static bool rule_arrptr_to_sa(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *subarray_base = cc->to->array.base; + Type *from_base = cc->from_type->pointer->array.base; + + // int[<2>]*, int[2]* + if (is_explicit) + { + subarray_base = type_flatten(subarray_base); + from_base = type_flatten(from_base); + } + // Same base type? E.g. int[2]* -> int[], then we're done. + if (from_base == subarray_base) + { + return true; + } + + if (subarray_base->type_kind == TYPE_POINTER && from_base->type_kind == TYPE_POINTER) + { + switch (match_pointers(cc, subarray_base, from_base, is_explicit, is_silent)) + { + case TYPE_SAME: + return true; + case TYPE_ERROR: + return false; + case TYPE_MISMATCH: + break; + default: + UNREACHABLE + } + } + bool may_explicit = !is_silent && rule_arrptr_to_sa(cc, true, true); + return sema_cast_error(cc, may_explicit, is_silent); +} + +static bool rule_sa_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *subarray_base = cc->from_type->array.base->canonical; + Type *natural_ptr = type_get_ptr(subarray_base); + switch (match_pointers(cc, natural_ptr, cc->to, is_explicit, is_silent)) + { + case TYPE_SAME: + return true; + case TYPE_ERROR: + return false; + case TYPE_MISMATCH: + break; + default: + UNREACHABLE + } + bool may_explicit = !is_silent && rule_sa_to_ptr(cc, true, true); + return sema_cast_error(cc, may_explicit, is_silent); +} + +static bool rule_sa_to_sa(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from_type = cc->from_type; + Type *from_base = from_type->array.base; + Type *array_base = cc->to->array.base; + + if (is_explicit) + { + array_base = type_flatten(array_base); + from_base = type_flatten(from_base); + } + // Same base type? Ok + if (from_base == array_base) return true; + + // This is allowed: void*[] -> int*[] and int*[] -> void*[] + if ((from_base == type_voidptr && type_is_pointer(array_base)) || (array_base == type_voidptr && type_is_pointer(from_base))) return true; + + if (is_silent) return false; + + // Allow converting to any type with the same size (and a smaller or same alignment) + if (type_size(array_base) != type_size(from_base)) + { + if (!is_explicit) return sema_cast_error(cc, false, is_silent); + if (is_silent) return false; + RETURN_SEMA_ERROR(cc->expr, "%s cannot be cast to %s as its elements have different size.", + type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type)); + } + if (type_abi_alignment(from_base) < type_abi_alignment(array_base)) + { + if (!is_explicit) return sema_cast_error(cc, false, is_silent); + if (is_silent) return false; + RETURN_SEMA_ERROR(cc->expr, + "%s cannot be cast to %s as its elements has a greater default alignment, but you can use a bitcast.", + type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type)); + } + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + return true; +} + + +static bool rule_arr_to_arr(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (type_size(cc->from_type) != type_size(cc->to)) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(cc->expr, "Arrays of different size may not be converted."); + } + return rule_sa_to_sa(cc, is_explicit, is_silent); +} + +static bool rule_arr_to_vec(CastContext *cc, bool is_explicit, bool is_silent) +{ + ArraySize len = cc->from_type->array.len; + if (len != cc->to_type->array.len) return sema_cast_error(cc, false, is_silent); + Type *base = cc->from_type->array.base; + switch (type_to_group(type_flatten(base))) + { + case CONV_BOOL: + case CONV_INT: + case CONV_FLOAT: + case CONV_POINTER: + case CONV_FAULT: + case CONV_ENUM: + case CONV_TYPEID: + case CONV_ANYFAULT: + case CONV_VOIDPTR: + case CONV_VAPTR: + break; + default: + return sema_cast_error(cc, false, is_silent); + } + cast_context_set_from(cc, type_get_vector(base, len)); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_vec_to_arr(CastContext *cc, bool is_explicit, bool is_silent) +{ + ArraySize len = cc->from_type->array.len; + if (len != cc->to_type->array.len) return sema_cast_error(cc, false, is_silent); + Type *base = cc->from_type->array.base; + cast_context_set_from(cc, type_get_array(base, len)); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_sa_to_vecarr(CastContext *cc, bool is_explicit, bool is_silent) +{ + Expr *expr = cc->expr; + MemberIndex size = sema_len_from_const(expr); + if (size < 0) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(expr, "Conversions from subarrays to arrays or vectors are only permitted on constant subarrays."); + } + if (size == 0) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(expr, "Zero sized subarrays can't be converted to arrays or vectors."); + } + if (cc->to_group == CONV_ARRAY) + { + if (expr_is_const_string(expr) || expr_is_const_bytes(expr)) + { + if (cc->to->array.len > size) size = cc->to->array.len; + } + cast_context_set_from(cc, type_get_array(cc->from_type->array.base, size)); + } + else + { + cast_context_set_from(cc, type_get_vector(cc->from_type->array.base, size)); + } + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_sa_to_infer(CastContext *cc, bool is_explicit, bool is_silent) +{ + Expr *expr = cc->expr; + MemberIndex size = sema_len_from_const(expr); + if (size < 0) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(expr, "Conversions from subarrays to arrays or vectors are only permitted on constant subarrays."); + } + if (size == 0) + { + if (is_silent) return false; + RETURN_SEMA_ERROR(expr, "Zero sized subarrays can't be converted to arrays or vectors."); + } + cast_context_set_from(cc, type_get_array(cc->from_type->array.base, size)); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_vecarr_to_infer(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *new_type = type_infer_len_from_actual_type(cc->from_type, cc->to_type); + cast_context_set_to(cc, new_type); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_ptr_to_infer(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (cc->to_type->type_kind != TYPE_POINTER) return sema_cast_error(cc, false, is_silent); + + Type *new_type = type_infer_len_from_actual_type(cc->from_type, cc->to_type); + cast_context_set_to(cc, new_type->pointer->canonical); + cast_context_set_from(cc, cc->from_type->pointer); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_explicit_ok(CastContext *cc, bool is_explicit, bool silent) +{ + if (is_explicit) return true; + if (!silent) + { + SEMA_ERROR(cc->expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(cc->expr->type), type_quoted_error_string(cc->to_type)); + } + return false; +} + + +static bool rule_widen_narrow(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (is_explicit) return true; + + ByteSize to_size = type_size(cc->to); + ByteSize from_size = type_size(cc->from_type); + + Expr *expr = cc->expr; + // If widening, require simple. + if (to_size > from_size) + { + if (expr_is_simple(cc->expr)) return true; + if (is_silent) 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(cc->to_type)); + } + return false; + } + + // If const, check in range. + if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, cc->to->type_kind)) + { + if (!is_silent) + { + if (cc->to_group != CONV_INT) + { + RETURN_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(cc->to_type)); + } + sema_error_const_int_out_of_range(expr, expr, cc->to_type); + } + return false; + } + + // Allow int <-> uint + if (to_size == from_size) return true; + + // Check if narrowing works + Expr *problem = recursive_may_narrow(expr, cc->to); + if (problem) + { + if (is_silent) return false; + // If it's an integer that's the problem, zoom in on that one. + if (type_is_integer(type_flatten(problem->type))) expr = problem; + // Otherwise require a cast. + 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(cc->to_type)); + return false; + } + return true; +} + +static bool rule_not_applicable(CastContext *cc, bool is_explicit, bool is_silent) +{ + UNREACHABLE +} + +static bool rule_from_distinct(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from_type = cc->from_type; + assert(from_type == from_type->canonical); + + // By default there is no conversion. + if (!is_explicit && !from_type->decl->is_substruct) + { + if (is_silent) return false; + + bool may_explicit = rule_from_distinct(cc, is_explicit, true); + sema_cast_error(cc, may_explicit, is_silent); + } + + cast_context_set_from(cc, type_flatten(from_type)); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_to_distinct(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from_type = cc->from_type; + assert(from_type == from_type->canonical); + Type *flat = type_flatten(cc->to); + ConvGroup flat_group = type_to_group(flat); + if (expr_is_const(cc->expr)) + { + cc->to = flat; + cc->to_group = flat_group; + if (cast_is_allowed(cc, is_explicit, true)) return true; + if (is_silent) return false; + bool may_explicit = !is_explicit && cast_is_allowed(cc, true, true); + return sema_cast_error(cc, may_explicit, is_silent); + } + + cc->to = flat; + cc->to_group = flat_group; + bool may_cast = cast_is_allowed(cc, true, true); + if (may_cast && is_explicit) return true; + return sema_cast_error(cc, may_cast, is_silent); +} + +static bool rule_to_struct_to_distinct(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from = cc->from_type; + // 1. The distinct type is a subtype. + if (type_is_subtype(cc->to, from)) return true; + // 2. We don't check for subtype after this, just use regular "to distinct" rules. + return rule_to_distinct(cc, is_explicit, is_silent); +} + +static bool rule_struct_to_struct(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *from = cc->from_type; + // 1. The distinct type is a subtype. + if (type_is_subtype(cc->to, from)) return true; + + return sema_cast_error(cc, false, is_silent); +} + +static bool rule_vec_to_vec(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (cc->from_type->array.len != cc->to_type->array.len) return sema_cast_error(cc, false, is_silent); + Type *from_base = cc->from_type->array.base; + cast_context_set_to(cc, cc->to->array.base); + // Allow bool vectors to expand to any int. + if (from_base == type_bool && cc->to_group == CONV_INT) return true; + cast_context_set_from(cc, from_base); + return cast_is_allowed(cc, is_explicit, is_silent); +} + +static bool rule_int_to_bits(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *base_type = cc->to->decl->bitstruct.base_type->type; + Type *from_type = cc->from_type; + bool success = type_is_integer(base_type) && type_size(from_type) == type_size(base_type); + if (!is_explicit) sema_cast_error(cc, success, is_silent); + return true; +} + +static bool rule_arr_to_bits(CastContext *cc, bool is_explicit, bool is_silent) +{ + Type *base_type = cc->to->decl->bitstruct.base_type->type; + Type *from_type = cc->from_type; + if (!is_explicit) return sema_cast_error(cc, from_type == base_type, is_silent); + return true; +} + +static bool rule_int_to_enum(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + + if (!expr_is_const(cc->expr)) return true; + + Decl *enum_decl = cc->to->decl; + // Check that the type is within limits. + unsigned max_enums = vec_size(enum_decl->enums.values); + Int to_convert = cc->expr->const_expr.ixx; + + // Negative numbers are always wrong. + if (int_is_neg(to_convert)) + { + if (!is_silent) SEMA_ERROR(cc->expr, "A negative number cannot be converted to an enum."); + return false; + } + + // Check the max, we don't support more than 4 billion, + // so we can safely use TYPE_U32. + Int max = {.i.low = max_enums, .type = TYPE_U32}; + if (int_comp(to_convert, max, BINARYOP_GE)) + { + if (!is_silent) SEMA_ERROR(cc->expr, "This value exceeds the number of enums in %s.", enum_decl->name); + return false; + } + return true; +} + +static bool rule_bits_to_arr(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (is_silent && !is_explicit) return false; + Type *base_type = cc->from_type->decl->bitstruct.base_type->type->canonical; + Type *to_type = cc->to_type; + if (base_type != to_type) return sema_cast_error(cc, false, is_silent); + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + return true; +} + +static bool rule_bits_to_int(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (is_silent && !is_explicit) return false; + Type *base_type = cc->from_type->decl->bitstruct.base_type->type->canonical; + Type *to_type = cc->to_type; + if (base_type != to_type) + { + if (!type_is_integer(base_type) || type_size(to_type) != type_size(base_type)) + { + return sema_cast_error(cc, false, is_silent); + } + } + if (!is_explicit) return sema_cast_error(cc, true, is_silent); + return true; +} + +// CASTS ---- + +/** + * Insert a cast. This will assume that the cast is valid. No typeinfo will be registered. + */ +static inline bool insert_runtime_cast(Expr *expr, CastKind kind, Type *type) +{ + assert(expr->resolve_status == RESOLVE_DONE); + assert(expr->type); + Expr *inner = expr_copy(expr); + expr->expr_kind = EXPR_CAST; + expr->cast_expr.kind = kind; + expr->cast_expr.expr = exprid(inner); + expr->cast_expr.type_info = 0; + expr->type = type; + return true; +} + +static void cast_vaptr_to_sa(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_APTSA, type); } +static void cast_ptr_to_any(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_PTRANY, type); } +static void cast_struct_to_inline(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_STINLINE, type); } +static void cast_fault_to_anyfault(Expr *expr, Type *type) { expr->type = type; }; +static void cast_fault_to_int(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ERINT, type); } +static void cast_fault_to_ptr(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ERPTR, type); } +static void cast_typeid_to_int(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_IDINT, type); } +static void cast_typeid_to_ptr(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_IDPTR, type); } +static void cast_any_to_bool(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ANYBOOL, type); } +static void cast_any_to_ptr(Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ANYPTR, type); } +static void cast_all_to_void(Expr *expr, Type *to_type) { insert_runtime_cast(expr, CAST_VOID, type_void); } +static void cast_retype(Expr *expr, Type *to_type) { expr->type = to_type; } + +/** + * Insert a cast on non-const only + */ +INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) +{ + if (expr_is_const(expr) && expr->const_expr.const_kind != CONST_TYPEID) return false; + return insert_runtime_cast(expr, kind, type); +} + +static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type) +{ + switch (initializer->kind) + { + case CONST_INIT_ARRAY: + { + Type *element_type = type_flatten(to_type)->array.base; + FOREACH_BEGIN(ConstInitializer *element, initializer->init_array.elements) + vector_const_initializer_convert_to_type(element, element_type); + FOREACH_END(); + break; + } + case CONST_INIT_ARRAY_FULL: + { + Type *element_type = type_flatten(to_type)->array.base; + FOREACH_BEGIN(ConstInitializer *element, initializer->init_array_full) + vector_const_initializer_convert_to_type(element, element_type); + FOREACH_END(); + break; + } + case CONST_INIT_VALUE: + { + Type *to_flat = type_flatten(to_type); + bool is_neg_conversion = to_flat && type_flatten(initializer->type) == type_bool; + if (is_neg_conversion) + { + bool is_true = initializer->init_value->const_expr.b; + initializer->init_value->const_expr.const_kind = CONST_INTEGER; + initializer->init_value->const_expr.ixx = (Int) + { .i = is_true ? (Int128) { UINT64_MAX, UINT64_MAX } : (Int128) { 0, 0 }, + .type = to_flat->type_kind }; + initializer->init_value->type = to_type; + } + else + { + cast_no_check(initializer->init_value, to_type, IS_OPTIONAL(initializer->init_value)); + } + break; + } + case CONST_INIT_ZERO: + break; + case CONST_INIT_UNION: + case CONST_INIT_STRUCT: + UNREACHABLE + case CONST_INIT_ARRAY_VALUE: + vector_const_initializer_convert_to_type(initializer->init_array_value.element, to_type); + break; + } + initializer->type = to_type; +} + +/** + * Insert a PTRPTR cast or update the pointer type + */ +static void cast_ptr_to_ptr(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_PTRPTR, type)) return; + + // Strings cannot be compile-time folded, so insert a runtime cast. + if (expr->const_expr.const_kind == CONST_STRING) + { + insert_runtime_cast(expr, CAST_PTRPTR, type); + return; + } + + // Insert the cast, this removes the ability to narrow it. + expr->type = type; + expr->const_expr.is_hex = false; +} + + +/** + * Convert any fp to another fp type using CAST_FPFP + */ +static void cast_float_to_float(Expr *expr, Type *type) +{ + // Change to same type should never enter here. + assert(type_flatten(type) != type_flatten(expr->type)); + + // Insert runtime cast if needed. + if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return; + + // Otherwise rewrite the const, which may cause rounding. + expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f); +} + +/** + * Convert from any floating point to int using CAST_FPINT + * Const conversion will disable narrowable and hex. + */ +static void cast_float_to_int(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_FPINT, type)) return; + + // Run the int->real to and rewrite. + Real d = expr->const_expr.fxx.f; + expr->const_expr.ixx = int_from_real(d, type_flatten(type)->type_kind); + expr->const_expr.const_kind = CONST_INTEGER; + expr->type = type; + expr->const_expr.is_hex = false; +} + + +/** + * Convert from integer to enum using CAST_INTENUM / or do a const conversion. + * This will ensure that the conversion is valid (i.e. in the range 0 .. enumcount - 1) + */ +static void cast_int_to_enum(Expr *expr, Type *type) +{ + Type *canonical = type_flatten(type); + assert(canonical->type_kind == TYPE_ENUM); + if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return; + + Decl *enum_decl = canonical->decl; + // Fold the const into the actual enum. + // Check is already done. + Decl *decl = enum_decl->enums.values[expr->const_expr.ixx.i.low]; + assert(decl->resolve_status == RESOLVE_DONE); + expr->const_expr = (ExprConst) { + .enum_err_val = decl, + .const_kind = CONST_ENUM + }; + expr->type = type; +} + +static inline Type *type_flatten_to_int(Type *type) +{ + while (1) + { + type = type->canonical; + switch (type->type_kind) + { + case TYPE_DISTINCT: + type = type->decl->distinct_decl.base_type; + break; + case TYPE_OPTIONAL: + type = type->optional; + break; + case TYPE_BITSTRUCT: + type = type->decl->bitstruct.base_type->type; + break; + case TYPE_ENUM: + type = type->decl->enums.type_info->type; + break; + case TYPE_TYPEDEF: + UNREACHABLE + default: + assert(type_is_integer(type)); + return type; + } + } +} + +/** + * Convert between integers: CAST_INTINT + */ +static void cast_int_to_int(Expr *expr, Type *type) +{ + // Fold pointer casts if narrowing + // So (int)(uptr)&x => (int)&x in the backend. + if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_PTRINT + && type_size(type) <= type_size(expr->type)) + { + expr->type = type; + return; + } + + // Insert runtime casts on non-const. + if (insert_runtime_cast_unless_const(expr, CAST_INTINT, type)) return; + + Type *flat = type_flatten_to_int(type); + // Hand this off to the int conversion. + expr->const_expr.ixx = int_conv(expr->const_expr.ixx, flat->type_kind); + expr->const_expr.const_kind = CONST_INTEGER; + expr->type = type; + expr->const_expr.is_hex = false; +} + +/** + * Convert 1 => { 1, 1, 1, 1 } using CAST_EXPVEC + */ +static void cast_expand_to_vec(Expr *expr, Type *type) +{ + // Fold pointer casts if narrowing + Type *base = type_get_indexed_type(type); + cast_no_check(expr, base, IS_OPTIONAL(expr)); + insert_runtime_cast(expr, CAST_EXPVEC, type); +} + +/** + * Cast a signed or unsigned integer -> floating point, using CAST_INTFP + * for runtime, otherwise do const transformation. + */ +static void cast_int_to_float(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_INTFP, type)) return; + + Real f = int_to_real(expr->const_expr.ixx); + expr_rewrite_const_float(expr, type, f); +} + +static void cast_enum_to_int(Expr* expr, Type *to_type) +{ + assert(type_flatten(expr->type)->type_kind == TYPE_ENUM); + Type *underlying_type = type_base(expr->type); + if (expr_is_const(expr)) + { + assert(expr->const_expr.const_kind == CONST_ENUM); + expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); + } + if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_INTENUM) + { + *expr = *exprptr(expr->cast_expr.expr); + } + expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); + cast_int_to_int(expr, to_type); +} + +/** + * Cast using CAST_VECARR, casting an array to a vector. For the constant, this + * is a simple type change, see array_to_vec. + */ +static void cast_vec_to_arr(Expr *expr, Type *to_type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_VECARR, to_type)) return; + + assert(expr->const_expr.const_kind == CONST_INITIALIZER); + ConstInitializer *list = expr->const_expr.initializer; + list->type = to_type; + expr->type = to_type; +} + +/** + * Convert vector -> vector. This is somewhat complex as there are various functions + * we need to invoke depending on the underlying type. + */ +static void cast_vec_to_vec(Expr *expr, Type *to_type) +{ + if (!expr_is_const(expr)) + { + // Extract indexed types. + Type *from_type = type_flatten(expr->type); + Type *from_element = from_type->array.base; + to_type = type_flatten(to_type); + Type *to_element = to_type->array.base; + + // float vec -> float/int/bool vec + if (type_is_float(from_element)) + { + switch (to_element->type_kind) + { + case ALL_FLOATS: + insert_runtime_cast(expr, CAST_FPFP, to_type); + return; + case TYPE_BOOL: + insert_runtime_cast(expr, CAST_FPBOOL, to_type); + return; + case ALL_INTS: + insert_runtime_cast(expr, CAST_FPINT, to_type); + return; + default: + UNREACHABLE; + } + } + + // bool vec -> float vec + if (from_element == type_bool) + { + // Special conversion to retain the sign. + if (type_is_integer(to_element)) + { + insert_runtime_cast(expr, CAST_BOOLVECINT, to_type); + return; + } + if (type_is_float(to_element)) + { + insert_runtime_cast(expr, CAST_BOOLFP, to_type); + return; + } + UNREACHABLE; + } + + if (type_is_integer(from_element)) + { + switch (to_element->type_kind) + { + case ALL_FLOATS: + insert_runtime_cast(expr, CAST_INTFP, to_type); + return; + case TYPE_BOOL: + insert_runtime_cast(expr, CAST_INTBOOL, to_type); + return; + case ALL_INTS: + insert_runtime_cast(expr, CAST_INTINT, to_type); + return; + case TYPE_POINTER: + case TYPE_TYPEID: + case TYPE_ANYFAULT: + case TYPE_FAULTTYPE: + insert_runtime_cast(expr, CAST_INTPTR, to_type); + default: + UNREACHABLE; + } + } + // The rest will be different pointer types + switch (to_element->type_kind) + { + case ALL_FLOATS: + UNREACHABLE + return; + case TYPE_BOOL: + insert_runtime_cast(expr, CAST_PTRBOOL, to_type); + return; + case ALL_INTS: + insert_runtime_cast(expr, CAST_INTPTR, to_type); + return; + case TYPE_POINTER: + case TYPE_TYPEID: + case TYPE_ANYFAULT: + case TYPE_FAULTTYPE: + insert_runtime_cast(expr, CAST_PTRPTR, to_type); + default: + UNREACHABLE; + } + } + + assert(expr->const_expr.const_kind == CONST_INITIALIZER); + + // For the const initializer we need to change the internal type + ConstInitializer *list = expr->const_expr.initializer; + vector_const_initializer_convert_to_type(list, to_type); + expr->type = to_type; +} + + +static void cast_anyfault_to_fault(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_EUER, type) && expr->const_expr.const_kind == CONST_ERR) return; + Decl *value = expr->const_expr.enum_err_val; + if (value->type != type) + { + expr->const_expr.const_kind = CONST_POINTER; + expr->const_expr.ptr = 0; + } + assert(value->type == type); + expr->type = type; +} + +static void cast_sa_to_ptr(Expr *expr, Type *type) +{ + if (expr_is_const_string(expr) || expr_is_const_bytes(expr)) + { + expr->type = type; + return; + } + insert_runtime_cast(expr, CAST_SAPTR, type); +} + +/** + * Cast any int to a pointer, will use CAST_INTPTR after a conversion to uptr for runtime. + * Compile time it will check that the value fits the pointer size. + */ +static void cast_int_to_ptr(Expr *expr, Type *type) +{ + assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating."); + + // Handle const: + if (expr_is_const(expr)) + { + expr->type = type; + expr->const_expr.ptr = expr->const_expr.ixx.i.low; + expr->const_expr.const_kind = CONST_POINTER; + return; + } + // This may be a narrowing + cast_no_check(expr, type_uptr, IS_OPTIONAL(expr)); + insert_runtime_cast(expr, CAST_INTPTR, type); +} + +/** + * Bool into a signed or unsigned int using CAST_BOOLINT + * or rewrite to 0 / 1 for false / true. + */ +static void cast_bool_to_int(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return; + + expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0); +} + + +/** + * Cast bool to float using CAST_BOOLFP + * or rewrite to 0.0 / 1.0 for false / true + */ +static void cast_bool_to_float(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return; + + assert(expr->const_expr.const_kind == CONST_BOOL); + expr_rewrite_const_float(expr, type, expr->const_expr.b ? 1.0 : 0.0); +} + +/** + * Cast int to bool using CAST_INTBOOL + * or rewrite 0 => false, any other value => true + */ +static void cast_int_to_bool(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_INTBOOL, type)) return; + + expr_rewrite_const_bool(expr, type, !int_is_zero(expr->const_expr.ixx)); +} + +/** + * Cast any float to bool using CAST_FPBOOL + * or rewrite 0.0 => false, any other value => true + */ +static void cast_float_to_bool(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_FPBOOL, type)) return; + + expr_rewrite_const_bool(expr, type, expr->const_expr.fxx.f != 0.0); +} + +/** + * Insert the PTRXI cast, or on const do a rewrite. + */ +static void cast_ptr_to_int(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_PTRINT, type)) return; + + // Revisit this to support pointers > 64 bits. + expr_rewrite_const_int(expr, type, expr->const_expr.ptr); +} + +/** + * Insert the PTRBOOL cast or on const do a rewrite. + */ +static void cast_ptr_to_bool(Expr *expr, Type *type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return; + + // It may be a pointer + if (expr->const_expr.const_kind == CONST_POINTER) + { + expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0); + return; + } + + // Or it's a string, in which case it is always true. + assert(expr->const_expr.const_kind == CONST_STRING); + expr_rewrite_const_bool(expr, type, true); +} + +static void cast_sa_to_bool(Expr *expr, Type *type) +{ + if (expr_is_const_initializer(expr)) + { + ConstInitializer *list = expr->const_expr.initializer; + switch (list->kind) + { + case CONST_INIT_ZERO: + expr_rewrite_const_bool(expr, type, false); + return; + case CONST_INIT_ARRAY: + expr_rewrite_const_bool(expr, type, vec_size(list->init_array.elements) > 0); + return; + case CONST_INIT_ARRAY_FULL: + expr_rewrite_const_bool(expr, type, vec_size(list->init_array_full) > 0); + return; + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + case CONST_INIT_VALUE: + case CONST_INIT_ARRAY_VALUE: + break; + } + } + insert_runtime_cast(expr, CAST_SABOOL, type); +} + +/** + * We have two cases: + * 1. int[] -> Foo[] where Foo is a distinct or typedef or pointer. Then we can just redefine + * 2. The second case is something like int[] -> float[] for this case we need to make a bitcast using CAST_SASA. + */ +static void cast_sa_to_sa(Expr *expr, Type *to_type) +{ + Type *to_type_base = type_flatten(type_flatten(to_type)->array.base); + Type *from_type_base = type_flatten(type_flatten(expr->type)->array.base); + if (expr_is_const(expr) || to_type_base == from_type_base || (type_is_pointer(to_type_base) && type_is_pointer(from_type_base))) + { + expr->type = to_type; + return; + } + insert_runtime_cast(expr, CAST_SASA, to_type); +} + +static void cast_sa_to_vecarr(Expr *expr, Type *to_type) +{ + assert(expr_is_const(expr)); + expr->type = to_type; + return; +} + +static void cast_sa_to_infer(Expr *expr, Type *to_type) +{ + assert(expr_is_const(expr)); + Type *index = type_get_indexed_type(to_type); + MemberIndex size = sema_len_from_const(expr); + assert(size > 0); + if (type_flatten(to_type)->type_kind == TYPE_VECTOR) + { + expr->type = type_get_vector(index, size); + } + else + { + expr->type = type_get_array(index, size); + } +} + +static void cast_vecarr_to_infer(Expr *expr, Type *to_type) +{ + to_type = type_infer_len_from_actual_type(to_type, type_flatten(expr->type)); + cast_no_check(expr, to_type, false); +} + +static void cast_ptr_to_infer(Expr *expr, Type *to_type) +{ + to_type = type_infer_len_from_actual_type(to_type, type_flatten(expr->type)); + cast_no_check(expr, to_type, false); +} + + +/** + * Cast using CAST_ARRVEC, casting an array to a vector. For the constant, this + * is a simple type change. + */ +static void cast_arr_to_vec(Expr *expr, Type *to_type) +{ + Type *index_vec = type_flatten(type_get_indexed_type(to_type)); + Type *index_arr = type_flatten(type_get_indexed_type(expr->type)); + Type *to_temp = index_vec == index_arr ? to_type : type_get_vector(index_arr, type_flatten(expr->type)->array.len); + if (expr_is_const(expr)) + { + // For the array -> vector this is always a simple rewrite of type. + assert(expr->const_expr.const_kind == CONST_INITIALIZER); + ConstInitializer *list = expr->const_expr.initializer; + list->type = to_temp; + expr->type = to_temp; + } + else + { + insert_runtime_cast(expr, CAST_ARRVEC, to_temp); + } + if (to_temp != to_type) + { + cast_vec_to_vec(expr, to_type); + } +} + +static void cast_arr_to_arr(Expr *expr, Type *to_type) +{ + assert(type_size(to_type) == type_size(expr->type)); + expr->type = to_type; +} + + +static void cast_anyfault_to_bool(Expr *expr, Type *to_type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_EUBOOL, to_type)) return; + + assert(expr->const_expr.const_kind == CONST_ERR); + expr_rewrite_const_bool(expr, type_bool, expr->const_expr.enum_err_val != NULL); +} + +static void cast_typeid_to_bool(Expr *expr, Type *to_type) +{ + if (insert_runtime_cast_unless_const(expr, CAST_IDBOOL, to_type)) return; + + assert(expr->const_expr.const_kind == CONST_TYPEID); + expr_rewrite_const_bool(expr, type_bool, expr->const_expr.typeid != NULL); +} + +#define XX2XX &cast_retype +#define EX2VC &cast_expand_to_vec +#define BO2IN &cast_bool_to_int +#define BO2FP &cast_bool_to_float +#define IN2BO &cast_int_to_bool +#define IN2IN &cast_int_to_int +#define IN2FP &cast_int_to_float +#define IN2PT &cast_int_to_ptr +#define IN2EN &cast_int_to_enum +#define EN2IN &cast_enum_to_int +#define FP2BO &cast_float_to_bool +#define FP2IN &cast_float_to_int +#define FP2FP &cast_float_to_float +#define PT2BO &cast_ptr_to_bool +#define PT2IN &cast_ptr_to_int +#define PT2PT &cast_ptr_to_ptr +#define PT2AY &cast_ptr_to_any +#define AP2SA &cast_vaptr_to_sa +#define SA2BO &cast_sa_to_bool +#define SA2PT &cast_sa_to_ptr +#define SA2SA &cast_sa_to_sa +#define VC2AR &cast_vec_to_arr +#define VC2VC &cast_vec_to_vec +#define AR2VC &cast_arr_to_vec +#define AR2AR &cast_arr_to_arr +#define ST2LN &cast_struct_to_inline +#define AY2BO &cast_any_to_bool +#define AY2PT &cast_any_to_ptr +#define FA2IN &cast_fault_to_int +#define FA2PT &cast_fault_to_ptr +#define FA2AF &cast_fault_to_anyfault +#define TI2BO &cast_typeid_to_bool +#define TI2IN &cast_typeid_to_int +#define TI2PT &cast_typeid_to_ptr +#define AF2BO &cast_anyfault_to_bool +#define AF2FA &cast_anyfault_to_fault +#define SA2VA &cast_sa_to_vecarr +#define XX2VO &cast_all_to_void +#define SA2FE &cast_sa_to_infer +#define VA2FE &cast_vecarr_to_infer +#define PT2FE &cast_ptr_to_infer + +#define _NO__ NULL /* No */ +#define RXXDI &rule_to_distinct /* Type -> distinct (match + is explicit) */ +#define REXPL &rule_explicit_ok /* Is explicit */ +#define _NA__ &rule_not_applicable /* "Not applicable" - should not be seen. */ +#define RIFIF &rule_widen_narrow /* Widen / narrow conversion of int/float */ +#define ROKOK &rule_all_ok /* Always works */ +#define RINPT &rule_int_to_ptr /* Int -> ptr (explicit + size match) */ +#define RPTIN &rule_ptr_to_int /* Ptr -> int (explicit + size match) */ +#define RINBS &rule_int_to_bits /* Int -> bits (explicit + int + size match) */ +#define RARBS &rule_arr_to_bits /* Char[*] -> bits (explicit + base match) */ +#define RINEN &rule_int_to_enum /* Int -> enum (explicit, range check const) */ +#define RPTPT &rule_ptr_to_ptr /* Ptr -> ptr (explicit or ptr match) */ +#define RAPSA &rule_arrptr_to_sa /* Arrptr -> Subarray (explicit flattens distinct, pointer match) */ +#define RSAPT &rule_sa_to_ptr /* Subarray -> ptr (explicit flatens distinct, pointer match) */ +#define RSASA &rule_sa_to_sa /* Subarray -> subarray (explicit same size, align safe, match base otherwise) void* <-> int* match. */ +#define RSAVA &rule_sa_to_vecarr /* Subarray -> vec/arr (if const, convert to vec/arr, check) */ +#define RVCVC &rule_vec_to_vec /* Vec -> vec (as underlying type) */ +#define RBSAR &rule_bits_to_arr /* Bits -> arr (explicit + base match) */ +#define RBSIN &rule_bits_to_int /* Bits -> int (explicit + size match) */ +#define RDIXX &rule_from_distinct /* Distinct -> internal (explicit or inline) */ +#define RARVC &rule_arr_to_vec /* Arr -> Vec (len matches, valid elements, flatten if explicit) */ +#define RVCAR &rule_vec_to_arr /* Vec -> Arr (len matches, if base can be converted, flatten if explicit) */ +#define RARAR &rule_arr_to_arr /* Array to array conversion (like subarray, but len must match) */ +#define RSTST &rule_struct_to_struct /* Struct -> struct (if inline) */ +#define RSTDI &rule_to_struct_to_distinct /* Struct -> inline (struct inline = distinct, distinct inline = struct if explicit flatten) */ +#define RSAFE &rule_sa_to_infer /* Subarray -> infer (only if subarray is constant or can infer) */ +#define RVAFE &rule_vecarr_to_infer /* Vec/arr -> infer (if base matches) */ +#define RPTFE &rule_ptr_to_infer /* Ptr -> infer (if pointee may infer) */ + +CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { +// void, wildc, bool, int, float, ptr, sarr, vec, bitst, distc, array, strct, union, any, fault, enum, typid, afaul, voidp, arrpt, infer (to) + {_NA__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // VOID (from) + {ROKOK, _NA__, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, ROKOK, _NO__}, // WILDCARD + {REXPL, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BOOL + {REXPL, _NO__, REXPL, RIFIF, ROKOK, RINPT, _NO__, ROKOK, RINBS, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RINEN, _NO__, _NO__, RINPT, RINPT, _NO__}, // INT + {REXPL, _NO__, REXPL, REXPL, RIFIF, _NO__, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // FLOAT + {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE}, // PTR + {REXPL, _NO__, REXPL, _NO__, _NO__, RSAPT, RSASA, RSAVA, _NO__, RXXDI, RSAVA, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, RSAPT, RSAFE}, // SARRAY + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVCVC, _NO__, RXXDI, RVCAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE}, // VECTOR + {REXPL, _NO__, _NO__, RBSIN, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, RBSAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // BITSTRUCT + {REXPL, _NO__, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX, RDIXX}, // DISTINCT + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RARVC, RARBS, RXXDI, RARAR, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RVAFE}, // ARRAY + {REXPL, _NO__, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTDI, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, RSTST, _NO__}, // STRUCT + {REXPL, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // UNION + {REXPL, _NO__, REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, RXXDI, _NO__, _NO__, _NO__, _NA__, _NO__, _NO__, _NO__, _NO__, REXPL, REXPL, _NO__}, // ANY + {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, REXPL, REXPL, _NO__}, // FAULT + {REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // ENUM + {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NA__, _NO__, REXPL, REXPL, _NO__}, // TYPEID + {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, REXPL, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__}, // ANYFAULT + {REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__, _NO__, _NA__, ROKOK, _NO__}, // VOIDPTR + {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, RAPSA, ROKOK, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE}, // ARRPTR + {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // INFERRED +}; + +CastFunction cast_function[CONV_LAST + 1][CONV_LAST + 1] = { +//void, wildcd, bool, int, float, ptr, sarr, vec, bitst, dist, array, struct,union, any, fault, enum, typeid,anyfa, vptr, aptr, ulist, infer(to) + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // VOID (from) + {XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, XX2XX, 0 }, // WILDCARD + {XX2VO, 0, 0, BO2IN, BO2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BOOL + {XX2VO, 0, IN2BO, IN2IN, IN2FP, IN2PT, 0, EX2VC, XX2XX, 0, 0, 0, 0, 0, 0, IN2EN, 0, 0, IN2PT, IN2PT, 0 }, // INT + {XX2VO, 0, FP2BO, FP2IN, FP2FP, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // FLOAT + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE }, // PTR + {XX2VO, 0, SA2BO, 0, 0, SA2PT, SA2SA, SA2VA, 0, 0, SA2VA, 0, 0, 0, 0, 0, 0, 0, SA2PT, SA2PT, SA2FE }, // SARRAY + {XX2VO, 0, 0, 0, 0, 0, 0, VC2VC, 0, 0, VC2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE }, // VECTOR + {XX2VO, 0, 0, XX2XX, 0, 0, 0, 0, 0, 0, XX2XX, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // BITSTRUCT + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // DISTINCT + {XX2VO, 0, 0, 0, 0, 0, 0, AR2VC, XX2XX, 0, AR2AR, 0, 0, 0, 0, 0, 0, 0, 0, 0, VA2FE }, // ARRAY + {XX2VO, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, ST2LN, 0 }, // STRUCT + {XX2VO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // UNION + {XX2VO, 0, AY2BO, 0, 0, AY2PT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AY2PT, AY2PT, 0 }, // ANY + {XX2VO, 0, AF2BO, FA2IN, 0, FA2PT, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, FA2AF, FA2PT, FA2PT, 0 }, // FAULT + {XX2VO, 0, 0, EN2IN, 0, 0, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // ENUM + {XX2VO, 0, TI2BO, TI2IN, 0, TI2PT, 0, EX2VC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TI2PT, TI2PT, 0 }, // TYPEID + {XX2VO, 0, AF2BO, FA2IN, 0, FA2IN, 0, EX2VC, 0, 0, 0, 0, 0, 0, AF2FA, 0, 0, 0, FA2IN, FA2IN, 0 }, // ANYFAULT + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, 0, EX2VC, 0, 0, 0, 0, 0, PT2AY, 0, 0, 0, 0, 0, PT2PT, 0 }, // VOIDPTR + {XX2VO, 0, PT2BO, PT2IN, 0, PT2PT, AP2SA, EX2VC, 0, 0, 0, 0, 0, PT2AY, 0, 0, 0, 0, PT2PT, PT2PT, PT2FE }, // ARRAYPTR + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // INFERRED +}; + +static ConvGroup group_from_type[TYPE_LAST + 1] = { + [TYPE_POISONED] = CONV_NO, + [TYPE_VOID] = CONV_VOID, + [TYPE_BOOL] = CONV_BOOL, + [TYPE_I8] = CONV_INT, + [TYPE_I16] = CONV_INT, + [TYPE_I32] = CONV_INT, + [TYPE_I64] = CONV_INT, + [TYPE_I128] = CONV_INT, + [TYPE_U8] = CONV_INT, + [TYPE_U16] = CONV_INT, + [TYPE_U32] = CONV_INT, + [TYPE_U64] = CONV_INT, + [TYPE_U128] = CONV_INT, + [TYPE_F16] = CONV_FLOAT, + [TYPE_BF16] = CONV_FLOAT, + [TYPE_F32] = CONV_FLOAT, + [TYPE_F64] = CONV_FLOAT, + [TYPE_F128] = CONV_FLOAT, + [TYPE_ANY] = CONV_ANY, + [TYPE_ANYFAULT] = CONV_ANYFAULT, + [TYPE_TYPEID] = CONV_TYPEID, + [TYPE_POINTER] = CONV_POINTER, + [TYPE_ENUM] = CONV_ENUM, + [TYPE_FUNC] = CONV_NO, + [TYPE_STRUCT] = CONV_STRUCT, + [TYPE_UNION] = CONV_UNION, + [TYPE_BITSTRUCT] = CONV_BITSTRUCT, + [TYPE_FAULTTYPE] = CONV_FAULT, + [TYPE_TYPEDEF] = CONV_NO, + [TYPE_DISTINCT] = CONV_DISTINCT, + [TYPE_ARRAY] = CONV_ARRAY, + [TYPE_SUBARRAY] = CONV_SUBARRAY, + [TYPE_FLEXIBLE_ARRAY] = CONV_NO, + [TYPE_INFERRED_ARRAY] = CONV_NO, + [TYPE_VECTOR] = CONV_VECTOR, + [TYPE_INFERRED_VECTOR] = CONV_NO, + [TYPE_UNTYPED_LIST] = CONV_NO, + [TYPE_OPTIONAL] = CONV_NO, + [TYPE_WILDCARD] = CONV_WILDCARD, + [TYPE_TYPEINFO] = CONV_NO, + [TYPE_MEMBER] = CONV_NO, +}; + +INLINE ConvGroup type_to_group(Type *type) +{ + type = type->canonical; + if (type == type_voidptr) return CONV_VOIDPTR; + if (type->type_kind == TYPE_POINTER && (type->pointer->type_kind == TYPE_ARRAY || type->pointer->type_kind == TYPE_VECTOR)) return CONV_VAPTR; + if (type_len_is_inferred(type)) return CONV_INFERRED; + return group_from_type[type->type_kind]; +} + +INLINE void cast_context_set_from(CastContext *cc, Type *new_from) +{ + cc->from_group = type_to_group(cc->from_type = new_from); +} + +INLINE void cast_context_set_to(CastContext *cc, Type *new_to) +{ + cc->to_group = type_to_group(cc->to = new_to); +} diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 669937eba..fda73470d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -794,7 +794,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) if (expr_is_constant_eval(cond, true)) { Expr *copy = copy_expr_single(cond); - cast(copy, type_bool); + cast_no_check(copy, type_bool, false); assert(expr_is_const(cond)); path = cond->const_expr.b ? 1 : 0; } @@ -1487,7 +1487,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call type_quoted_error_string(val->type)); return false; } - if (!cast_promote_vararg(val)) return false; + cast_promote_vararg(val); } // Set the argument at the location. @@ -2615,7 +2615,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (!sema_analyse_expr(context, len_expr)) return false; Expr *index_copy = expr_copy(index); if (!sema_analyse_expr(context, index_copy)) return false; - if (!cast(index_copy, len_expr->type)) return false; + if (!cast_explicit(context, index_copy, len_expr->type)) return false; expr_rewrite_to_binary(index, len_expr, index_copy, BINARYOP_SUB); index->resolve_status = RESOLVE_NOT_DONE; if (!sema_analyse_expr(context, index)) return false; @@ -2634,7 +2634,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } // Cast to an appropriate type for index. - if (!cast_to_index(index)) return false; + if (!cast_to_index(context, index)) return false; // Check range bool remove_from_back = false; @@ -2745,8 +2745,8 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) if (end && !sema_analyse_expr(context, end)) return false; // Fix index sizes - if (!cast_to_index(start)) return false; - if (end && !cast_to_index(end)) return false; + if (!cast_to_index(context, start)) return false; + if (end && !cast_to_index(context, end)) return false; if (end && end->type != start->type) { Type *common = type_find_max_type(start->type, end->type); @@ -3990,7 +3990,7 @@ CHECK_DEEPER: { if (flat_type->type_kind == TYPE_ENUM) { - if (!cast(current_parent, type->decl->enums.type_info->type)) return false; + if (!cast_explicit(context, current_parent, type->decl->enums.type_info->type)) return false; expr_replace(expr, current_parent); return true; } @@ -4351,12 +4351,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr) SEMA_ERROR(type_info, "Casting to an optional type is not allowed."); return false; } - if (inner->type == type_untypedlist) - { - if (!cast_untyped_to_type(context, inner, target_type)) return false; - expr_replace(expr, inner); - return true; - } + if (!cast_explicit(context, inner, target_type)) return expr_poison(expr); expr_replace(expr, inner); return true; @@ -4724,7 +4719,11 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr * BITSTRUCT_OK: // 5. Cast the right hand side to the one on the left if (!sema_analyse_expr(context, right)) return false; - if (!cast_implicit_maybe_optional(context, right, no_fail, IS_OPTIONAL(left))) return false; + if (!cast_implicit(context, right, no_fail)) return false; + if (IS_OPTIONAL(right) && !IS_OPTIONAL(left)) + { + RETURN_SEMA_ERROR(right, "The expression may not be optional."); + } // 6. Check for zero in case of div or mod. if (expr_is_const(right)) { @@ -4875,12 +4874,12 @@ static void sema_binary_unify_voidptr(Expr *left, Expr *right, Type **left_type_ if (*left_type_ref == *right_type_ref) return; if (*left_type_ref == type_voidptr) { - cast(left, *right_type_ref); + cast_no_check(left, *right_type_ref, IS_OPTIONAL(left)); *left_type_ref = *right_type_ref; } if (*right_type_ref == type_voidptr) { - cast(right, *left_type_ref); + cast_no_check(right, *left_type_ref, IS_OPTIONAL(right)); *right_type_ref = *left_type_ref; } } @@ -4920,8 +4919,8 @@ static bool sema_expr_analyse_enum_add_sub(SemaContext *context, Expr *expr, Exp return false; } Type *underlying_type = left_type->decl->enums.type_info->type; - if (!cast(left, underlying_type)) return false; - if (!cast(right, underlying_type)) return false; + if (!cast_explicit(context, left, underlying_type)) return false; + if (!cast_explicit(context, right, underlying_type)) return false; expr->type = type_add_optional(underlying_type, IS_OPTIONAL(left) || IS_OPTIONAL(right)); if (expr_both_const(left, right)) { @@ -4940,9 +4939,8 @@ static bool sema_expr_analyse_enum_add_sub(SemaContext *context, Expr *expr, Exp } // Enum - value / Enum + value Type *underlying_type = left_type->decl->enums.type_info->type; - if (!cast_implicit(context, right, underlying_type)) return false; - if (!cast(left, underlying_type)) return false; - if (!cast(right, underlying_type)) return false; + if (!cast_explicit(context, left, underlying_type)) return false; + if (!cast_explicit(context, right, underlying_type)) return false; expr->type = type_add_optional(left_type, IS_OPTIONAL(left) || IS_OPTIONAL(right)); if (expr_both_const(left, right)) { @@ -5063,7 +5061,7 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left, if (cast_to_iptr) { expr->resolve_status = RESOLVE_DONE; - return cast(expr, cast_to_iptr); + return cast_explicit(context, expr, cast_to_iptr); } return true; @@ -5236,7 +5234,7 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left, if (cast_to_iptr) { expr->resolve_status = RESOLVE_DONE; - return cast(expr, cast_to_iptr); + return cast_explicit(context, expr, cast_to_iptr); } return true; } @@ -5687,7 +5685,7 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, || (type_is_signed(left_type) && type_is_unsigned(right_type))) { // 2a. Resize so that both sides have the same bit width. This will always work. - cast_to_int_to_max_bit_size(context, left, right, left_type, right_type); + cast_to_int_to_max_bit_size(left, right, left_type, right_type); goto DONE; } @@ -5759,8 +5757,8 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, // 6. Do the implicit cast. bool success = true; - if (!cast_implicit(context, left, max)) success = cast(left, max); - if (!cast_implicit(context, right, max)) success = success && cast(right, max); + if (!cast_implicit(context, left, max)) success = cast_explicit(context, left, max); + if (!cast_implicit(context, right, max)) success = success && cast_explicit(context, right, max); assert(success); DONE: @@ -7360,8 +7358,7 @@ static inline bool sema_expr_analyse_embed(SemaContext *context, Expr *expr, boo .bytes.len = len, }; expr->expr_kind = EXPR_CONST; - Type *type = type_get_array(type_char, len); - expr->type = type; + expr->type = type_get_subarray(type_char); return true; } @@ -7502,7 +7499,7 @@ static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *target_t expr->type = type_get_ptr(decl->type); // If it's a distinct type we have to make a cast. expr->resolve_status = RESOLVE_DONE; - if (target_type && expr->type != target_type && !cast(expr, target_type)) return false; + if (target_type && expr->type != target_type && !cast_explicit(context, expr, target_type)) return false; if (multiple) { vec_add(original->func_decl.generated_lambda, decl); @@ -8071,23 +8068,71 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo RETURN_SEMA_ERROR(expr, "Slice length mismatch, expected %u but got %u.", to_canonical->array.len, len); } // Given x[3..7] -> (int[5]*)x[3..7] - cast(expr, type_get_ptr(type_get_array(element, len))); + cast_no_check(expr, type_get_ptr(type_get_array(element, len)), IS_OPTIONAL(expr)); // Deref expr_rewrite_insert_deref(expr); - cast(expr, to); + cast_no_check(expr, to, IS_OPTIONAL(expr)); return true; } NO_SLICE:; - if (to && !cast_implicit_maybe_optional(context, expr, to, allow_optional)) return false; + if (to && !cast_implicit(context, expr, to)) return false; if (!allow_optional && IS_OPTIONAL(expr)) { - SEMA_ERROR(expr, "You cannot have an optional here."); - return false; + RETURN_SEMA_ERROR(expr, "It is not possible to cast from %s to %s.", type_quoted_error_string(expr->type), + type_quoted_error_string(type_no_optional(expr->type))); } return true; } - +static MemberIndex len_from_const_initializer(ConstInitializer *init) +{ + switch (init->kind) + { + case CONST_INIT_ZERO: + return 0; + case CONST_INIT_STRUCT: + case CONST_INIT_UNION: + case CONST_INIT_VALUE: + case CONST_INIT_ARRAY_VALUE: + return -1; + case CONST_INIT_ARRAY: + { + MemberIndex max = 0; + FOREACH_BEGIN(ConstInitializer *element, init->init_array.elements) + assert(element->kind == CONST_INIT_ARRAY_VALUE); + if (element->init_array_value.index > max) max = element->init_array_value.index; + FOREACH_END(); + return max; + } + case CONST_INIT_ARRAY_FULL: + return vec_size(init->init_array_full); + } + UNREACHABLE +} +MemberIndex sema_len_from_const(Expr *expr_maybe_const) +{ + if (!expr_is_const(expr_maybe_const)) return -1; + switch (expr_maybe_const->const_expr.const_kind) + { + case CONST_FLOAT: + case CONST_INTEGER: + case CONST_BOOL: + case CONST_ENUM: + case CONST_ERR: + case CONST_POINTER: + case CONST_TYPEID: + case CONST_MEMBER: + return -1; + case CONST_BYTES: + case CONST_STRING: + return expr_maybe_const->const_expr.bytes.len; + case CONST_INITIALIZER: + return len_from_const_initializer(expr_maybe_const->const_expr.initializer); + case CONST_UNTYPED_LIST: + return vec_size(expr_maybe_const->const_expr.untyped_list); + } + UNREACHABLE +} static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr) { Decl *decl = expr->ct_ident_expr.decl; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index dec0525e2..743496760 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -300,7 +300,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex optional = optional || IS_OPTIONAL(element); continue; } - if (!cast_implicit_maybe_optional(context, element, inner_type, true)) return false; + if (!cast_implicit(context, element, inner_type)) return false; + optional = optional || IS_OPTIONAL(element); } else { @@ -596,7 +597,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex expr->resolve_status = RESOLVE_DONE; expr_insert_addr(expr); if (!sema_analyse_expr(context, expr)) return false; - return cast(expr, to); + return cast_explicit(context, expr, to); } case TYPE_POINTER: if (is_zero_init) @@ -1103,7 +1104,7 @@ static MemberIndex sema_analyse_designator_index(SemaContext *context, Expr *ind } // Unless we already have type_usz, cast to type_isz; - if (!cast_to_index(index)) + if (!cast_to_index(context, index)) { return -1; } diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index d52203053..b92e6c3ac 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -81,9 +81,11 @@ int sema_check_comp_time_bool(SemaContext *context, Expr *expr); bool sema_expr_check_assign(SemaContext *c, Expr *expr); bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, CallABI abi, Signature *signature, bool is_real_function); bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type); -bool cast_promote_vararg(Expr *arg); +MemberIndex sema_len_from_const(Expr *expr_maybe_const); + +void cast_promote_vararg(Expr *arg); Type *cast_numeric_arithmetic_promotion(Type *type); -void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); +void cast_to_int_to_max_bit_size(Expr *lhs, Expr *rhs, Type *left_type, Type *right_type); bool sema_decl_if_cond(SemaContext *context, Decl *decl); bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr); Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 58eafda7d..82d7cfa8e 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1610,7 +1610,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen Ast *declare_ast = new_ast(AST_DECLARE_STMT, var->span); declare_ast->declare_stmt = index; Expr *load_idx = expr_variable(idx_decl); - if (!cast(load_idx, index_var_type)) return false; + if (!cast_explicit(context, load_idx, index_var_type)) return false; index->var.init_expr = load_idx; ast_append(&succ, declare_ast); } @@ -2292,7 +2292,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc ? real_type->pointer : real_type, any_switch->span), VARDECL_LOCAL); Expr *var_result = expr_variable(var_holder); - if (!cast(var_result, real_type)) return false; + if (!cast_explicit(context, var_result, real_type)) return false; if (any_switch->is_deref) { expr_rewrite_insert_deref(var_result); @@ -2310,7 +2310,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc type_info_new_base(type, expr->span), VARDECL_LOCAL); Expr *ident_converted = expr_variable(var_holder); - if (!cast(ident_converted, type)) return false; + if (!cast_explicit(context, ident_converted, type)) return false; alias->var.init_expr = ident_converted; alias->var.shadow = true; Ast *decl_ast = new_ast(AST_DECLARE_STMT, alias->span); diff --git a/src/compiler/types.c b/src/compiler/types.c index 5d6856010..f728c3505 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1749,53 +1749,60 @@ TypeCmpResult type_array_element_is_equivalent(SemaContext *context, Type *eleme } } -TypeCmpResult type_is_pointer_equivalent(SemaContext *context, Type *pointer1, Type *pointer2, bool flatten_distinct) +TypeCmpResult type_is_pointer_equivalent(SemaContext *context, Type *to_pointer, Type *from_pointer, bool flatten_distinct) { RETRY: if (flatten_distinct) { - pointer1 = type_flatten(pointer1); - pointer2 = type_flatten(pointer2); + to_pointer = type_flatten(to_pointer); + from_pointer = type_flatten(from_pointer); } - if (pointer1 == pointer2) return TYPE_SAME; - if (pointer1 == type_voidptr || pointer2 == type_voidptr) return TYPE_SAME; - Type *pointee1 = pointer1->pointer->canonical; - Type *pointee2 = pointer2->pointer->canonical; + // Are they the same? + if (to_pointer == from_pointer) return TYPE_SAME; + + // Is one of them a void*? + if (to_pointer == type_voidptr || from_pointer == type_voidptr) return TYPE_SAME; + + // Look at the pointees. + Type *to_pointee = to_pointer->pointer->canonical; + Type *from_pointee = from_pointer->pointer->canonical; if (flatten_distinct) { - pointee1 = type_flatten(pointee1); - pointee2 = type_flatten(pointee2); + to_pointee = type_flatten(to_pointee); + from_pointee = type_flatten(from_pointee); } - if (pointee1 == pointee2) return TYPE_SAME; - if (type_is_subtype(pointee2, pointee1)) return TYPE_SAME; - if (pointee1->type_kind != pointee2->type_kind) + // Are pointees same after flattening? + if (to_pointee == from_pointee) return TYPE_SAME; + if (type_is_subtype(to_pointee, from_pointee)) return TYPE_SAME; + + if (to_pointee->type_kind != from_pointee->type_kind) { - if (type_is_any_arraylike(pointee1)) + if (type_is_any_arraylike(from_pointee)) { // Try array equivalence. - if (type_is_any_arraylike(pointee2)) + if (type_is_any_arraylike(to_pointee)) { - TypeCmpResult res = type_array_is_equivalent(context, pointee1, pointee2, flatten_distinct); + TypeCmpResult res = type_array_is_equivalent(context, to_pointee, from_pointee, flatten_distinct); if (res != TYPE_MISMATCH) return res; } // A possible int[4]* -> int* decay? - return type_is_pointer_equivalent(context, type_get_ptr(pointee1->array.base), pointer2, flatten_distinct); + return type_is_pointer_equivalent(context, type_get_ptr(from_pointee->array.base), to_pointer, flatten_distinct); } // Not arraylike and no array decay. Failure. return TYPE_MISMATCH; } - if (pointee1->type_kind == TYPE_FUNC && pointee2->type_kind == TYPE_FUNC) + if (to_pointee->type_kind == TYPE_FUNC && from_pointee->type_kind == TYPE_FUNC) { - if (!sema_resolve_type_decl(context, pointee1)) return TYPE_ERROR; - if (!sema_resolve_type_decl(context, pointee2)) return TYPE_ERROR; - return pointee1->function.prototype->raw_type == pointee2->function.prototype->raw_type; + if (!sema_resolve_type_decl(context, to_pointee)) return TYPE_ERROR; + if (!sema_resolve_type_decl(context, from_pointee)) return TYPE_ERROR; + return to_pointee->function.prototype->raw_type == from_pointee->function.prototype->raw_type; } - if (pointee1->type_kind == TYPE_POINTER) + if (to_pointee->type_kind == TYPE_POINTER) { - pointer1 = pointee1; - pointer2 = pointee2; + to_pointer = to_pointee; + from_pointer = from_pointee; goto RETRY; } return false; diff --git a/src/version.h b/src/version.h index 99aab61f1..d1d0ddbc8 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.641" \ No newline at end of file +#define COMPILER_VERSION "0.4.642" \ No newline at end of file diff --git a/test/test_suite/bitstruct/bitstruct_to_int.c3t b/test/test_suite/bitstruct/bitstruct_to_int.c3t index c23d532ed..2632d6aea 100644 --- a/test/test_suite/bitstruct/bitstruct_to_int.c3t +++ b/test/test_suite/bitstruct/bitstruct_to_int.c3t @@ -22,7 +22,7 @@ fn void test() { Foo b = {}; int x = (int)b; - char[4] y = (char[4])b; + char[4] y = bitcast(b, char[4]); Foo *c = &b; c.x; int* x2 = (int*)c; @@ -32,7 +32,7 @@ fn void test() fn void test2() { Foo2 b = { 3, 2, -1 }; - int x = (int)b; + int x = bitcast(b, int); char[4] y = (char[4])b; Foo2 *c = &b; printf("%d\n", c.x); @@ -53,14 +53,16 @@ entry: %b = alloca i32, align 4 %x = alloca i32, align 4 %y = alloca [4 x i8], align 1 + %expr = alloca i32, align 4 %c = alloca ptr, align 8 %x2 = alloca ptr, align 8 %y2 = alloca ptr, align 8 store i32 0, ptr %b, align 4 %0 = load i32, ptr %b, align 4 store i32 %0, ptr %x, align 4 - %1 = load [4 x i8], ptr %b, align 4 - store [4 x i8] %1, ptr %y, align 1 + %1 = load i32, ptr %b, align 4 + store i32 %1, ptr %expr, align 4 + call void @llvm.memcpy.p0.p0.i32(ptr align 1 %y, ptr align 1 %expr, i32 4, i1 false) store ptr %b, ptr %c, align 8 %2 = load ptr, ptr %c, align 8 %3 = load i32, ptr %2, align 4 @@ -78,12 +80,16 @@ define void @foo.test2() #0 { entry: %b = alloca [4 x i8], align 1 %x = alloca i32, align 4 + %expr = alloca [4 x i8], align 1 + %x1 = alloca i32, align 4 %y = alloca [4 x i8], align 1 %c = alloca ptr, align 8 %x2 = alloca ptr, align 8 %y2 = alloca ptr, align 8 store [4 x i8] c"\06\90\00\00", ptr %b, align 1 - %0 = load i32, ptr %b, align 1 + call void @llvm.memcpy.p0.p0.i32(ptr align 1 %expr, ptr align 1 %b, i32 4, i1 false) + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x1, ptr align 1 %expr, i64 4, i1 false) + %0 = load i32, ptr %x1, align 4 store i32 %0, ptr %x, align 4 call void @llvm.memcpy.p0.p0.i32(ptr align 1 %y, ptr align 1 %b, i32 4, i1 false) store ptr %b, ptr %c, align 8 diff --git a/test/test_suite/cast/cast_struct.c3 b/test/test_suite/cast/cast_struct.c3 index 35c81a6db..210ae5045 100644 --- a/test/test_suite/cast/cast_struct.c3 +++ b/test/test_suite/cast/cast_struct.c3 @@ -25,12 +25,12 @@ struct BazTwo fn void test() { Foo x; - Bar y = (Bar)(x); // #error: The cast 'Foo' to 'Bar' is not allowed + Bar y = (Bar)(x); // #error: 'Foo' to 'Bar' Baz z; - int[2] w = (int[2])(z); // #error: The cast 'Baz' to 'int[2]' is not allowed + int[2] w = (int[2])(z); // #error: 'Baz' to 'int[2]' z = (Baz)(w); - BazTwo v = (BazTwo)(z); // #error: The cast 'Baz' to 'BazTwo' is not allowed + BazTwo v = (BazTwo)(z); // #error: 'Baz' to 'BazTwo' v = (BazTwo)(w); z = (Baz)(v); w = (int[2])(v); diff --git a/test/test_suite/cast/cast_struct_fails.c3 b/test/test_suite/cast/cast_struct_fails.c3 index 244ae1cfc..85e4a08b4 100644 --- a/test/test_suite/cast/cast_struct_fails.c3 +++ b/test/test_suite/cast/cast_struct_fails.c3 @@ -25,11 +25,11 @@ struct BazTwo fn void test1() { Foo x; - Bar z = (Baz)(x); // #error: cast 'Foo' to 'Baz' + Bar z = (Baz)(x); // #error: 'Foo' to 'Baz' } fn void test2() { Baz x; - BazTwo z = (BazTwo)(x); // #error: cast 'Baz' to 'BazTwo' + BazTwo z = (BazTwo)(x); // #error: 'Baz' to 'BazTwo' } diff --git a/test/test_suite/compile_time/untyped_with_inferred.c3 b/test/test_suite/compile_time/untyped_with_inferred.c3 new file mode 100644 index 000000000..a9715e18d --- /dev/null +++ b/test/test_suite/compile_time/untyped_with_inferred.c3 @@ -0,0 +1,6 @@ + +fn void main() +{ + var $x = { 1, 1.0 }; + double[*] z = $x; +} diff --git a/test/test_suite/distinct/distinct_slicing.c3 b/test/test_suite/distinct/distinct_slicing.c3 index 263c6b22f..c3920c71f 100644 --- a/test/test_suite/distinct/distinct_slicing.c3 +++ b/test/test_suite/distinct/distinct_slicing.c3 @@ -6,5 +6,5 @@ fn void main() Foo y = x; Foo z = x[0:2]; Foo w = x[1..2]; - double[] yekf = x[1..1]; // #error: Implicitly casting 'Foo' to 'double[]' is not permitted + double[] yekf = x[1..1]; // #error: 'Foo' to 'double[]' } diff --git a/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 b/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 index dca990bf2..016194eaf 100644 --- a/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 +++ b/test/test_suite/expressions/casts/cast_enum_const_to_distinct.c3 @@ -5,5 +5,5 @@ enum Foo def Abc = distinct int; fn void main() { - Abc d = Foo.ABC; // #error: Implicitly casting + Abc d = Foo.ABC; // #error: to 'Abc' } 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 b3c3536d6..3c3989eb6 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 @@ def FuncSame = fn void(int); fn void test1(Func arg) { bool a = (bool)(arg); - bool b = arg; // #error: 'Func' (fn void(int)) to 'bool' + bool b = arg; // #error: to 'bool' } fn void test2(Func arg) diff --git a/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 b/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 index af536b51f..c3a147cde 100644 --- a/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 +++ b/test/test_suite/expressions/casts/failed_distinct_float_conversions.c3 @@ -3,7 +3,7 @@ def Bar = distinct void*; fn int main() { float f = 1; - Foo foo = f; // #error: you may use a cast - Bar bar = f; // #error: It is not possible to convert + Foo foo = f; // #error: explicit cast + Bar bar = f; // #error: 'float' to 'Bar' return 1; } \ No newline at end of file diff --git a/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 index bf48d9c2d..d94d4aba6 100644 --- a/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 +++ b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 @@ -5,7 +5,7 @@ def Foo = distinct int; fn void test1() { int[2][*] x = { { 2, 3}, { 5, 6 }}; - Foo[2][2] y = x; // #error: can do an explicit + Foo[2][2] y = x; // #error: explicit cast } fn void test2() @@ -18,7 +18,7 @@ fn void test2() fn void test3() { int[2][*] x = { { 2, 3}, { 5, 6 }}; - Foo[2][2]* y = &x; // #error: can do an explicit + Foo[2][2]* y = &x; // #error: explicit cast } struct Bar { int x; } diff --git a/test/test_suite/expressions/negate_int.c3 b/test/test_suite/expressions/negate_int.c3 index 737aa2529..cf7c367d8 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; @ok(-a); - short b = -a; // #error: 'int!' to 'short'. + short b = -a; // #error: 'short!' to 'short'. } fn void test2() diff --git a/test/test_suite/expressions/plus_int.c3 b/test/test_suite/expressions/plus_int.c3 index 7a377dc7d..f29a78c09 100644 --- a/test/test_suite/expressions/plus_int.c3 +++ b/test/test_suite/expressions/plus_int.c3 @@ -2,7 +2,7 @@ fn void test1() { short! a = 1; @ok(+a); - short b = +a; // #error: 'int!' to 'short'. + short b = +a; // #error: 'short!' 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 94ad43d44..c742f8dde 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*' + int* p1 = myInt; // #error: integer smaller } fn void test2() { uint myUInt = 1; - int* p2 = myUInt; // #error: 'int*' + int* p2 = myUInt; // #error: integer smaller } fn void test3() { uint myUInt = 1; - int* p2 = (int*)(myUInt); // #error: iptr + int* p2 = (int*)(myUInt); // #error: integer smaller } diff --git a/test/test_suite/expressions/void_arg.c3 b/test/test_suite/expressions/void_arg.c3 index 74fa5bc75..6acfdbbf3 100644 --- a/test/test_suite/expressions/void_arg.c3 +++ b/test/test_suite/expressions/void_arg.c3 @@ -7,7 +7,7 @@ fn void test1() fn void test2() { - bar(test2()); // #error: You cannot cast 'void' into 'int' even with an explicit cast + bar(test2()); // #error: You cannot cast 'void' to 'int' } fn void test3() diff --git a/test/test_suite/initialize/initialize_jump.c3 b/test/test_suite/initialize/initialize_jump.c3 index 4c254d2ee..199cb8d93 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: It is not possible to convert 'int' to 'void' + return 123; // #error: cannot implicitly } \ No newline at end of file diff --git a/test/test_suite/macros/macro_with_body_err.c3 b/test/test_suite/macros/macro_with_body_err.c3 index cb37bb456..ccd565972 100644 --- a/test/test_suite/macros/macro_with_body_err.c3 +++ b/test/test_suite/macros/macro_with_body_err.c3 @@ -17,7 +17,7 @@ fn int Foo.mutate(Foo *foo) macro @macro_with_body(foo, &x; @body(x, y)) { *x = foo.x; - @body(foo.mutate(), x); // #error: Implicitly casting + @body(foo.mutate(), x); // #error: 'int*' to 'int' } diff --git a/test/test_suite/struct/member_access.c3 b/test/test_suite/struct/member_access.c3 index c434fef35..5753cc1d3 100644 --- a/test/test_suite/struct/member_access.c3 +++ b/test/test_suite/struct/member_access.c3 @@ -71,7 +71,7 @@ struct Aa1 fn void test_conversion_struct() { Aa1 a1; - int aa = a1.bb; // #error: 'bb' into 'int' + int aa = a1.bb; // #error: 'bb' to 'int' } struct Struct diff --git a/test/test_suite/switch/failable_switch.c3 b/test/test_suite/switch/failable_switch.c3 index edac2e92b..52489999d 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: cannot be converted + case MyError.FOO? : // #error: 'int!' to 'int' 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 1ba7188e2..e42525be9 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -81,8 +81,8 @@ enum Enum : int fn void test11() { - int a = Enum.A; // #error: Implicitly casting - ichar b = Enum.B; // #error: Implicitly casting + int a = Enum.A; // #error: implicitly be converted + ichar b = Enum.B; // #error: implicitly be converted } fn void test12() @@ -157,15 +157,15 @@ fn void foo() {} fn void test22() { - ichar a = foo(); // #error: 'void' into 'ichar' - short b = foo(); // #error: 'void' into 'short' - int c = foo(); // #error: 'void' into 'int' - long d = foo(); // #error: 'void' into 'long' - char e = foo(); // #error: 'void' into 'char' - ushort f = foo(); // #error: 'void' into 'ushort' - uint g = foo(); // #error: 'void' into 'uint' - ulong h = foo(); // #error: 'void' into 'ulong' - bool i = foo(); // #error: 'void' into 'bool' + ichar a = foo(); // #error: 'void' to 'ichar' + short b = foo(); // #error: 'void' to 'short' + int c = foo(); // #error: 'void' to 'int' + long d = foo(); // #error: 'void' to 'long' + char e = foo(); // #error: 'void' to 'char' + ushort f = foo(); // #error: 'void' to 'ushort' + uint g = foo(); // #error: 'void' to 'uint' + ulong h = foo(); // #error: 'void' to 'ulong' + bool i = foo(); // #error: 'void' to 'bool' } diff --git a/test/test_suite/vector/vector_to_array_cast.c3t b/test/test_suite/vector/vector_to_array_cast.c3t index 03e226515..bf46f3753 100644 --- a/test/test_suite/vector/vector_to_array_cast.c3t +++ b/test/test_suite/vector/vector_to_array_cast.c3t @@ -9,6 +9,7 @@ fn void tester() { int[<2>] x = { 1, 2 }; int[2] y = (int[2])(x); + double[<2>] zz = y; x = (int[<2>])(y); } @@ -21,6 +22,7 @@ define void @test.tester() #0 { entry: %x = alloca <2 x i32>, align 8 %y = alloca [2 x i32], align 4 + %zz = alloca <2 x double>, align 16 store <2 x i32> , ptr %x, align 8 %0 = load <2 x i32>, ptr %x, align 8 %1 = extractelement <2 x i32> %0, i64 0 @@ -33,6 +35,13 @@ entry: %7 = insertelement <2 x i32> undef, i32 %6, i64 0 %8 = extractvalue [2 x i32] %5, 1 %9 = insertelement <2 x i32> %7, i32 %8, i64 1 - store <2 x i32> %9, ptr %x, align 8 + %sifp = sitofp <2 x i32> %9 to <2 x double> + store <2 x double> %sifp, ptr %zz, align 16 + %10 = load [2 x i32], ptr %y, align 4 + %11 = extractvalue [2 x i32] %10, 0 + %12 = insertelement <2 x i32> undef, i32 %11, i64 0 + %13 = extractvalue [2 x i32] %10, 1 + %14 = insertelement <2 x i32> %12, i32 %13, i64 1 + store <2 x i32> %14, ptr %x, align 8 ret void } diff --git a/test/test_suite/vector/vector_to_array_fail.c3 b/test/test_suite/vector/vector_to_array_fail.c3 index e35b9a947..2fc0c366d 100644 --- a/test/test_suite/vector/vector_to_array_fail.c3 +++ b/test/test_suite/vector/vector_to_array_fail.c3 @@ -9,5 +9,5 @@ fn void main() int[<*>] z = x; int[<*>] w = y; double[<2>] ww = x; - double[<2>] www = y; // #error: 'int[2]' to 'double[<2>]' + short[<2>] www = y; // #error: implicitly be converted } \ No newline at end of file