diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 86f90c652..f11448c27 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -121,18 +121,6 @@ typedef enum CAST_VECARR, } CastKind; -typedef enum -{ - CAST_OPTION_NONE = 0x00, - CAST_OPTION_SIMPLE_EXPR = 0x01, - -} CastOption; - -typedef enum -{ - CAST_TYPE_NO_ERROR_REPORT = 0x08, - CAST_TYPE_NO_OPTIONAL = 0x02, -} CastType; typedef enum { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 3697fc6d3..ee6ca92b2 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -7,16 +7,10 @@ #pragma clang diagnostic push #pragma ide diagnostic ignored "ConstantFunctionResult" -typedef struct CastOptions_ -{ - bool is_explicit; - bool may_not_be_optional; - bool no_report; -} CastOptions; -static bool cast_may_explicit(Type *from_type, Type *to_type, bool is_const); -static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool report); -static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, CastOptions options); +static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent); +static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool silent, + bool may_not_be_optional); static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type); static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type); static Expr *recursive_may_narrow_float(Expr *expr, Type *type); @@ -453,102 +447,6 @@ CastKind cast_to_bool_kind(Type *type) } -static bool cast_may_explicit(Type *from_type, Type *to_type, bool is_const) -{ - from_type = type_flatten_distinct_optional(from_type); - to_type = type_flatten_distinct_optional(to_type); - - // 2. Same underlying type, always ok - if (from_type == to_type) return true; - - if (type_is_any_arraylike(to_type) && type_is_any_arraylike(from_type)) - { - return cast_may_array(from_type, to_type, true); - } - - TypeKind to_kind = to_type->type_kind; - switch (from_type->type_kind) - { - case TYPE_OPTIONAL_ANY: - return true; - case TYPE_DISTINCT: - case TYPE_TYPEDEF: - case TYPE_OPTIONAL: - UNREACHABLE - case TYPE_POISONED: - case TYPE_INFERRED_ARRAY: - case TYPE_VOID: - case TYPE_TYPEINFO: - case TYPE_FUNC: - case TYPE_FLEXIBLE_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_SCALED_VECTOR: - case TYPE_MEMBER: - return false; - case TYPE_TYPEID: - // May convert to anything pointer sized or larger, no enums - return type_is_pointer_sized_or_more(to_type); - case TYPE_BOOL: - // May convert to any integer / distinct integer / float, no enums - return type_is_integer(to_type) || type_is_float(to_type); - 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)) return false; - if (type_is_integer(to_type)) return true; - return to_type->type_kind == TYPE_ARRAY && type_is_integer(to_type->array.base); - case TYPE_ANYERR: - // May convert to a bool, an error type or an integer - return to_type == type_bool || to_kind == TYPE_FAULTTYPE || type_is_integer(to_type); - case ALL_SIGNED_INTS: - case ALL_UNSIGNED_INTS: - // We don't have to match pointer size if it's a constant. - if (to_kind == TYPE_POINTER && is_const) return true; - if (to_kind == TYPE_POINTER && type_is_pointer_sized(from_type)) return true; - if (to_kind == TYPE_ENUM) return true; - FALLTHROUGH; - case TYPE_ENUM: - // Allow conversion int/enum -> float/bool/int - if (type_is_integer(to_type) || type_is_float(to_type) || to_type == type_bool) return true; - return false; - case ALL_FLOATS: - // Allow conversion float -> float/int/bool/enum - return type_is_integer(to_type) || type_is_float(to_type) || to_type == type_bool || to_kind == TYPE_ENUM; - case TYPE_POINTER: - return type_is_pointer_sized_or_more(to_type) || to_type == type_bool; - case TYPE_ANY: - return to_kind == TYPE_POINTER; - case TYPE_FAULTTYPE: - // Allow MyError.A -> error, to an integer or to bool - return to_type->type_kind == TYPE_ANYERR || type_is_integer(to_type) || to_type == type_bool; - case TYPE_ARRAY: - if (to_kind == TYPE_VECTOR) - { - return to_type->array.len == from_type->array.len && to_type->array.base == from_type->array.base; - } - FALLTHROUGH; - case TYPE_STRUCT: - if (type_is_substruct(from_type)) - { - if (cast_may_explicit(from_type->decl->strukt.members[0]->type, to_type, false)) return true; - } - FALLTHROUGH; - case TYPE_UNION: - return type_is_structurally_equivalent(from_type, to_type); - case TYPE_SUBARRAY: - if (to_kind == TYPE_SUBARRAY && type_is_pointer(to_type->array.base) - && type_is_pointer(from_type->array.base)) return true; - return to_kind == TYPE_POINTER; - case TYPE_VECTOR: - return type_is_structurally_equivalent(type_get_array(from_type->array.base, (uint32_t)from_type->array.len), to_type); - case TYPE_UNTYPED_LIST: - REMINDER("Look at untyped list explicit conversions"); - return false; - } - UNREACHABLE -} - bool type_may_convert_to_anyerr(Type *type) { if (type_is_optional_any(type)) return true; @@ -1115,22 +1013,22 @@ static void recursively_rewrite_untyped_list(Expr *expr, Expr **list) bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) { - return cast_expr_inner(context, expr, to_type, (CastOptions) { .no_report = false }); + return cast_expr_inner(context, expr, to_type, false, false, false); } bool cast_implicit_maybe_optional(SemaContext *context, Expr *expr, Type *to_type, bool may_be_optional) { - return cast_expr_inner(context, expr, to_type, (CastOptions) { .may_not_be_optional = !may_be_optional }); + return cast_expr_inner(context, expr, to_type, false, false, !may_be_optional); } bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type) { - return cast_expr_inner(context, expr, to_type, (CastOptions){ .no_report = true }); + return cast_expr_inner(context, expr, to_type, false, true, false); } bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type) { - if (!cast_expr_inner(context, expr, to_type, (CastOptions) { .is_explicit = true })) return false; + if (!cast_expr_inner(context, expr, to_type, true, false, false)) return false; if (expr_is_const(expr)) expr->const_expr.narrowable = false; return true; } @@ -1142,9 +1040,9 @@ static inline bool cast_with_optional(Expr *expr, Type *to_type, bool add_option return true; } -static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool no_report) +static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent) { - if (no_report) return false; + if (silent) return false; if (may_cast_explicit) { SEMA_ERROR(expr, @@ -1163,31 +1061,31 @@ static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast } -static inline bool cast_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_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: - if (type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) goto CAST; - return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), options.no_report); + if (type_array_element_is_equivalent(from->array.base, to->array.base, is_explicit)) goto CAST; + return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), silent); case TYPE_POINTER: - if (type_array_element_is_equivalent(from->array.base, to->pointer, options.is_explicit)) goto CAST; - return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->pointer, true), options.no_report); + if (type_array_element_is_equivalent(from->array.base, to->pointer, is_explicit)) goto CAST; + return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(from->array.base, to->pointer, true), silent); case TYPE_BOOL: - if (!options.is_explicit) goto CAST_MAY_EXPLICIT; + if (!is_explicit) goto CAST_MAY_EXPLICIT; goto CAST; default: goto CAST_ILLEGAL; } CAST_ILLEGAL: - return sema_error_cannot_convert(expr, to_type, false, options.no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); CAST_MAY_EXPLICIT: - return sema_error_cannot_convert(expr, to_type, true, options.no_report); + return sema_error_cannot_convert(expr, to_type, true, silent); CAST: return cast_with_optional(expr, to_type, add_optional); } -static inline bool cast_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) { bool infer_type = false; switch (to->type_kind) @@ -1203,19 +1101,19 @@ static inline bool cast_array(SemaContext *context, Expr *expr, Type *from, Type case TYPE_STRUCT: if (type_is_structurally_equivalent(from, to)) { - if (options.is_explicit) goto CAST; - if (options.no_report) return false; - return sema_error_cannot_convert(expr, to_type, true, options.no_report); + if (is_explicit) goto CAST; + if (silent) return false; + return sema_error_cannot_convert(expr, to_type, true, silent); } default: goto CAST_ILLEGAL; } CAST_ELEMENT: - if (!type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) + if (!type_array_element_is_equivalent(from->array.base, to->array.base, is_explicit)) { - if (!options.no_report && !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true)) + if (!silent && !is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true)) { - return sema_error_cannot_convert(expr, to_type, true, options.no_report); + return sema_error_cannot_convert(expr, to_type, true, silent); } goto CAST_ILLEGAL; } @@ -1226,7 +1124,7 @@ CAST: } return cast_with_optional(expr, to_type, add_optional); CAST_ILLEGAL: - return sema_error_cannot_convert(expr, to_type, false, options.no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); } static bool cast_may_number_convert(Expr *expr, Type *from, Type *to, bool is_explicit, bool cast_from_bool) @@ -1281,7 +1179,7 @@ static bool cast_may_number_convert(Expr *expr, Type *from, Type *to, bool is_ex if (!is_explicit) return false; return true; } -static inline bool cast_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) { bool is_scaled = from->type_kind == TYPE_SCALED_VECTOR; bool to_vector = type_kind_is_any_vector(to->type_kind); @@ -1309,38 +1207,38 @@ static inline bool cast_vector(SemaContext *context, Expr *expr, Type *from, Typ goto CAST_ILLEGAL; } TRY_CONVERT: - if (cast_may_number_convert(expr, from->array.base, to->array.base, options.is_explicit, to_vector)) goto CAST; - return sema_error_cannot_convert(expr, to, !options.is_explicit && cast_may_number_convert(expr, from->array.base, to->array.base, true, to_vector), options.no_report); + if (cast_may_number_convert(expr, from->array.base, to->array.base, is_explicit, to_vector)) goto CAST; + return sema_error_cannot_convert(expr, to, !is_explicit && cast_may_number_convert(expr, from->array.base, to->array.base, true, to_vector), silent); TRY_CAST: - if (type_array_element_is_equivalent(from->array.base, to->array.base, options.is_explicit)) goto CAST; - if (options.no_report) return false; - return sema_error_cannot_convert(expr, to, !options.is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), true); + if (type_array_element_is_equivalent(from->array.base, to->array.base, is_explicit)) goto CAST; + if (silent) return false; + return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), true); CAST_ILLEGAL: - return sema_error_cannot_convert(expr, to_type, false, options.no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); CAST: if (infer_len) to_type = cast_infer_len(to_type, from); return cast_with_optional(expr, to_type, add_optional); } -static inline bool cast_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) { - bool no_report = options.no_report; + bool no_report = silent; RETRY: switch (to->type_kind) { case ALL_FLOATS: goto CAST; case TYPE_BOOL: - if (options.is_explicit) goto CAST; + if (is_explicit) goto CAST; goto REQUIRE_CAST; case TYPE_ENUM: if (from->type_kind == TYPE_ENUM) break; to = to->decl->enums.type_info->type->canonical; - if (options.is_explicit) to = type_flatten_distinct(to); + if (is_explicit) to = type_flatten_distinct(to); FALLTHROUGH; case ALL_INTS: { - if (options.is_explicit) goto CAST; + if (is_explicit) goto CAST; ByteSize to_size = type_size(to); ByteSize from_size = type_size(from); if (to_size > from_size) goto ONLY_SIMPLE; @@ -1367,7 +1265,7 @@ RETRY: else { if (no_report) return false; - bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, (CastOptions) { .is_explicit = true, .no_report = true }); + bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, true, true, false); if (may_explicit) goto REQUIRE_CAST; break; } @@ -1375,7 +1273,7 @@ RETRY: { if (from->type_kind == TYPE_ENUM) break; bool may_cast = expr_is_const(expr) || type_size(from) >= type_size(type_voidptr); - if (!options.is_explicit) + if (!is_explicit) { if (may_cast) goto REQUIRE_CAST; break; @@ -1406,25 +1304,24 @@ CAST: return cast_with_optional(expr, to_type, add_optional); } -static inline bool cast_float(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_float(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent) { - bool no_report = options.no_report; RETRY: switch (to->type_kind) { case ALL_INTS: case TYPE_BOOL: - if (options.is_explicit) goto CAST; + if (is_explicit) goto CAST; goto REQUIRE_CAST; case ALL_FLOATS: { - if (options.is_explicit) goto CAST; + if (is_explicit) goto CAST; ByteSize to_size = type_size(to); ByteSize from_size = type_size(from); if (to_size > from_size) goto ONLY_SIMPLE; if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind)) { - if (options.no_report) return false; + 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; @@ -1433,7 +1330,7 @@ RETRY: Expr *problem = recursive_may_narrow_float(expr, to); if (problem) { - if (no_report) return false; + if (silent) return false; goto REQUIRE_CAST; } goto CAST; @@ -1446,41 +1343,40 @@ RETRY: } else { - if (no_report) return false; - bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, (CastOptions) { .is_explicit = true, .no_report = true }); + if (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; } default: break; } - return sema_error_cannot_convert(expr, to_type, false, no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); ONLY_SIMPLE: if (expr_is_simple(expr)) goto CAST; - if (no_report) return false; + 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 (no_report) return false; + 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); } -static inline bool cast_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, CastOptions options) +static inline bool cast_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 (to == type_any || to == type_voidptr || (from == type_voidptr && type_is_pointer(to))) return cast_with_optional(expr, to_type, add_optional); Type *pointee = from->pointer; - bool is_explicit = options.is_explicit; pointee = is_explicit ? type_flatten(pointee) : pointee->canonical; TypeKind pointee_kind = pointee->type_kind; switch (to->type_kind) { case ALL_INTS: - if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, options.no_report); + if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, silent); if (type_size(to_type) < type_size(type_iptr)) { SEMA_ERROR(expr, "Casting %s to %s is not allowed because '%s' is smaller than a pointer. " @@ -1506,32 +1402,30 @@ static inline bool cast_pointer(SemaContext *context, Expr *expr, Type *from, Ty { if (type_is_pointer_equivalent(subarray_base, from_base, is_explicit)) return cast_with_optional(expr, to_type, add_optional); } - if (options.no_report) return false; + if (silent) return false; bool would_work_explicit = false; if (!is_explicit) { - options.is_explicit = true; - options.no_report = true; - would_work_explicit = cast_pointer(context, expr_copy(expr), from, to, to_type, add_optional, options); + would_work_explicit = cast_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); } - return sema_error_cannot_convert(expr, to_type, false, options.no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); case TYPE_BOOL: if (is_explicit) return cast_with_optional(expr, to_type, add_optional); - return sema_error_cannot_convert(expr, to_type, true, options.no_report); + return sema_error_cannot_convert(expr, to_type, true, silent); case TYPE_POINTER: if (is_explicit) return cast_with_optional(expr, to_type, add_optional); if (cast_may_implicit_ptr(from->pointer, to->pointer)) { return cast_with_optional(expr, to_type, add_optional); } - return sema_error_cannot_convert(expr, to_type, true, options.no_report); + return sema_error_cannot_convert(expr, to_type, true, silent); case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: UNREACHABLE default: - return sema_error_cannot_convert(expr, to_type, false, options.no_report); + return sema_error_cannot_convert(expr, to_type, false, silent); } } /** @@ -1540,12 +1434,12 @@ static inline bool cast_pointer(SemaContext *context, Expr *expr, Type *from, Ty * 2. String literal conversions * 3. Constant pointer conversions */ -static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, CastOptions options) +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) || options.may_not_be_optional); - bool is_explicit = options.is_explicit; + assert(!type_is_optional(to_type) || may_not_be_optional); Type *to = is_explicit ? type_flatten_distinct_optional(to_type) : type_no_optional(to_type)->canonical; // Step one, cast from optional. @@ -1558,9 +1452,9 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas // *! -> int => ok, gives int! if (from_type == type_anyfail) { - if (options.may_not_be_optional) + if (may_not_be_optional) { - if (options.no_report) return false; + 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; } @@ -1588,7 +1482,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas { if (!is_explicit) { - if (options.no_report) return false; + if (silent) return false; SEMA_ERROR(expr, "A 'void!' can only be cast into %s using an explicit cast. You can try using (%s)", type_quoted_error_string(to_type), type_to_error_string(to_type)); return false; @@ -1597,9 +1491,9 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas return true; } } - if (options.may_not_be_optional) + if (may_not_be_optional) { - if (options.no_report) return false; + 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; @@ -1633,7 +1527,6 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas expr->type = to_type; return true; } - switch (from->type_kind) { case TYPE_UNTYPED_LIST: @@ -1641,6 +1534,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas 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 (to == type_anyerr) return cast(expr, to_type); if (type_is_integer(to) || to == type_bool) goto CAST_IF_EXPLICIT; goto CAST_FAILED; @@ -1651,42 +1545,83 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, Cas } goto CAST_FAILED; case TYPE_POINTER: - return cast_pointer(context, expr, from, to, to_type, add_optional, options); + return cast_pointer(context, expr, from, to, to_type, add_optional, is_explicit, silent); case TYPE_SUBARRAY: - return cast_subarray(context, expr, from, to, to_type, add_optional, options); + return cast_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: case TYPE_SCALED_VECTOR: - return cast_vector(context, expr, from, to, to_type, add_optional, options); + return cast_vector(context, expr, from, to, to_type, add_optional, is_explicit, silent); case TYPE_ARRAY: - return cast_array(context, expr, from, to, to_type, add_optional, options); + return cast_array(context, expr, from, to, to_type, add_optional, is_explicit, silent); case TYPE_ENUM: case ALL_INTS: - return cast_integer(context, expr, from, to, to_type, add_optional, options); + return cast_integer(context, expr, from, to, to_type, add_optional, is_explicit, silent); case ALL_FLOATS: - return cast_float(context, expr, from, to, to_type, add_optional, options); - default: - break; - } - - if (!options.is_explicit && options.no_report) return false; - if (!cast_may_explicit(from_type, to_type, expr_is_const(expr))) - { - if (!options.is_explicit && !options.no_report) - { - 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 cast_float(context, expr, from, to, to_type, add_optional, is_explicit, silent); + case TYPE_POISONED: return false; - } - if (!options.no_report) sema_error_failed_cast(expr, type_no_optional(expr->type), to_type); - return false; + 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_OPTIONAL_ANY: + 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->strukt.members[0]); + 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 (!options.is_explicit) + if (!is_explicit) { - if (options.no_report) return false; + 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)), @@ -1696,9 +1631,9 @@ CAST_IF_EXPLICIT: } return cast(expr, to_type); CAST_FAILED: - if (!options.no_report) + if (!silent) { - if (!options.is_explicit) + 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; @@ -2155,7 +2090,7 @@ bool cast_decay_array_pointers(SemaContext *context, Expr *expr) return cast_expr_inner(context, expr, type_add_optional(type_get_ptr(pointer_type->array.base), IS_OPTIONAL(expr)), - (CastOptions) { .is_explicit = true }); + true, false, false); } void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 71f8b8df5..dfc10bee9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -176,7 +176,6 @@ static inline bool sema_create_const_params(SemaContext *context, Expr *expr, Ty static inline void sema_create_const_membersof(SemaContext *context, Expr *expr, Type *type, AlignSize alignment, AlignSize offset); void expr_insert_widening_type(Expr *expr, Type *infer_type); -static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl); static inline int64_t expr_get_index_max(Expr *expr); static inline bool expr_both_any_integer_or_integer_vector(Expr *left, Expr *right); static inline bool expr_both_any_integer_or_integer_bool_vector(Expr *left, Expr *right); @@ -288,7 +287,7 @@ Expr *sema_ct_eval_expr(SemaContext *c, bool is_type_eval, Expr *inner, bool rep return inner; } -static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl) +Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl) { Expr *embedded_struct = expr_new(EXPR_ACCESS, parent->span); embedded_struct->resolve_status = RESOLVE_DONE; diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 0dbf69e73..3a6b4fc0f 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -81,6 +81,7 @@ void sema_analyze_stage(Module *module, AnalysisStage stage); bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr); bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr); +Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl); bool sema_analyse_ct_expr(SemaContext *context, Expr *expr); Decl *sema_find_operator(SemaContext *context, Expr *expr, OperatorOverload operator_overload); bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments); diff --git a/src/version.h b/src/version.h index a1ef5e27c..68d211713 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.7" \ No newline at end of file +#define COMPILER_VERSION "0.4.8" \ No newline at end of file diff --git a/test/test_suite/cast/cast_struct.c3 b/test/test_suite/cast/cast_struct.c3 index d3a4addfc..35c81a6db 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); + Bar y = (Bar)(x); // #error: The cast 'Foo' to 'Bar' is not allowed Baz z; - int[2] w = (int[2])(z); + int[2] w = (int[2])(z); // #error: The cast 'Baz' to 'int[2]' is not allowed z = (Baz)(w); - BazTwo v = (BazTwo)(z); + BazTwo v = (BazTwo)(z); // #error: The cast 'Baz' to 'BazTwo' is not allowed v = (BazTwo)(w); z = (Baz)(v); w = (int[2])(v); diff --git a/test/test_suite2/cast/cast_struct.c3 b/test/test_suite2/cast/cast_struct.c3 index d3a4addfc..35c81a6db 100644 --- a/test/test_suite2/cast/cast_struct.c3 +++ b/test/test_suite2/cast/cast_struct.c3 @@ -25,12 +25,12 @@ struct BazTwo fn void test() { Foo x; - Bar y = (Bar)(x); + Bar y = (Bar)(x); // #error: The cast 'Foo' to 'Bar' is not allowed Baz z; - int[2] w = (int[2])(z); + int[2] w = (int[2])(z); // #error: The cast 'Baz' to 'int[2]' is not allowed z = (Baz)(w); - BazTwo v = (BazTwo)(z); + BazTwo v = (BazTwo)(z); // #error: The cast 'Baz' to 'BazTwo' is not allowed v = (BazTwo)(w); z = (Baz)(v); w = (int[2])(v);