From 9424bba49fa6af033e65911ea5dcd077e2de8206 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 12 Oct 2022 11:12:05 +0200 Subject: [PATCH] Version bump. More generous wildcard length matching and conversions. --- src/compiler/compiler_internal.h | 61 +++- src/compiler/enums.h | 7 + src/compiler/sema_casts.c | 279 ++++++++++++++---- src/compiler/sema_decls.c | 11 +- src/compiler/sema_expr.c | 8 +- src/compiler/sema_initializers.c | 120 +++++--- src/compiler/sema_stmts.c | 2 +- src/compiler/sema_types.c | 15 +- src/version.h | 2 +- .../cast/implicit_infer_len_cast.c3t | 66 +++++ .../casts/struct_cast_and_distinct.c3 | 32 ++ .../cast/implicit_infer_len_cast.c3t | 56 ++++ .../casts/struct_cast_and_distinct.c3 | 32 ++ 13 files changed, 565 insertions(+), 126 deletions(-) create mode 100644 test/test_suite/cast/implicit_infer_len_cast.c3t create mode 100644 test/test_suite/expressions/casts/struct_cast_and_distinct.c3 create mode 100644 test/test_suite2/cast/implicit_infer_len_cast.c3t create mode 100644 test/test_suite2/expressions/casts/struct_cast_and_distinct.c3 diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index bf7a69d2b..40731bbd6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2016,8 +2016,9 @@ AsmRegister *asm_reg_by_index(unsigned index); bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type); bool cast(Expr *expr, Type *to_type); -bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool failable_allowed); +bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option); bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const); +Type *cast_infer_len(Type *to_infer, Type *actual_type); bool cast_to_index(Expr *index); bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type); @@ -2304,6 +2305,8 @@ INLINE Type *type_new(TypeKind kind, const char *name); INLINE bool type_is_pointer_sized(Type *type); INLINE bool type_is_pointer_sized_or_more(Type *type); INLINE Type *type_add_optional(Type *type, bool make_optional); +INLINE Type *type_from_inferred(Type *flattened, Type *element_type, unsigned count); +INLINE bool type_len_is_inferred(Type *type); INLINE bool type_is_substruct(Type *type); INLINE Type *type_flatten_for_bitstruct(Type *type); INLINE bool type_is_float(Type *type); @@ -2316,9 +2319,11 @@ INLINE bool type_is_integer_unsigned(Type *type); INLINE bool type_is_integer_signed(Type *type); INLINE bool type_is_integer_or_bool_kind(Type *type); INLINE bool type_is_numeric(Type *type); +INLINE bool type_is_len_inferred(Type *type); INLINE bool type_underlying_is_numeric(Type *type); INLINE bool type_is_pointer(Type *type); INLINE bool type_is_arraylike(Type *type); +INLINE bool type_is_any_arraylike(Type *type); INLINE bool type_is_promotable_float(Type *type); INLINE bool type_is_promotable_integer(Type *type); INLINE bool type_is_signed(Type *type); @@ -2387,11 +2392,49 @@ INLINE Type *type_add_optional(Type *type, bool make_optional) return type_get_optional(type); } +INLINE Type *type_from_inferred(Type *flattened, Type *element_type, unsigned count) +{ + switch (flattened->type_kind) + { + case TYPE_INFERRED_VECTOR: + return type_get_vector(element_type, count); + break; + case TYPE_INFERRED_ARRAY: + return type_get_array(element_type, count); + break; + default: + UNREACHABLE + } +} INLINE bool type_len_is_inferred(Type *type) { if (!type) return true; DECL_TYPE_KIND_REAL(kind, type); - return kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY; + while (1) + { + switch (type->type_kind) + { + case TYPE_TYPEDEF: + type = type->canonical; + continue; + case TYPE_ARRAY: + case TYPE_SUBARRAY: + case TYPE_FLEXIBLE_ARRAY: + case TYPE_VECTOR: + case TYPE_SCALED_VECTOR: + type = type->array.base; + continue; + case TYPE_INFERRED_ARRAY: + case TYPE_INFERRED_VECTOR: + return true; + case TYPE_POINTER: + type = type->pointer; + continue; + default: + return false; + } + UNREACHABLE; + } } INLINE bool type_is_optional(Type *type) @@ -2452,6 +2495,14 @@ INLINE bool type_is_arraylike(Type *type) return kind == TYPE_ARRAY || kind == TYPE_VECTOR || kind == TYPE_FLEXIBLE_ARRAY || kind == TYPE_SCALED_VECTOR; } +INLINE bool type_is_any_arraylike(Type *type) +{ + DECL_TYPE_KIND_REAL(kind, type); + return kind == TYPE_ARRAY || kind == TYPE_VECTOR + || kind == TYPE_FLEXIBLE_ARRAY || kind == TYPE_SCALED_VECTOR + || kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY; +} + INLINE CanonicalType *type_pointer_type(Type *type) { CanonicalType *res = type->canonical; @@ -2672,6 +2723,12 @@ bool type_is_scalar(Type *type); INLINE bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I8 && type->type_kind < TYPE_U8; } +INLINE bool type_is_len_inferred(Type *type) +{ + TypeKind kind = type->type_kind; + return kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY; +} + INLINE bool type_is_numeric(Type *type) { DECL_TYPE_KIND_REAL(kind, type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index d154fe017..1bde64389 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -118,6 +118,13 @@ typedef enum CAST_VECARR, } CastKind; +typedef enum +{ + CAST_OPTION_NONE = 0x00, + CAST_OPTION_SIMPLE_EXPR = 0x01, + CAST_OPTION_ALLOW_OPTIONAL = 0x02, +} CastOption; + typedef enum { diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 4b3ab8c1f..e95bbaaeb 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -12,6 +12,8 @@ static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *t static Expr *recursive_may_narrow_float(Expr *expr, Type *type); static Expr *recursive_may_narrow_int(Expr *expr, Type *type); static void recursively_rewrite_untyped_list(Expr *expr, Expr **list); +static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee); +static inline bool cast_may_array(Type *from, Type *to, bool is_explicit); static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) { @@ -32,6 +34,38 @@ bool sema_error_failed_cast(Expr *expr, Type *from, Type *to) return false; } +Type *cast_infer_len(Type *to_infer, Type *actual_type) +{ + Type *may_infer = to_infer->canonical; + Type *actual = actual_type->canonical; + if (may_infer == actual) return to_infer; + bool canonical_same_kind = may_infer->type_kind == to_infer->type_kind; + if (may_infer->type_kind == TYPE_INFERRED_ARRAY) + { + assert(actual_type->type_kind == TYPE_ARRAY); + Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : + may_infer->array.base, actual->array.base); + return type_get_array(base_type, actual->array.len); + } + if (may_infer->type_kind == TYPE_INFERRED_VECTOR) + { + assert(actual_type->type_kind == TYPE_VECTOR || actual->type_kind == TYPE_SCALED_VECTOR); + Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->array.base, actual->array.base); + if (actual_type->type_kind == TYPE_SCALED_VECTOR) + { + return type_get_scaled_vector(base_type); + } + return type_get_vector(base_type, actual->array.len); + } + if (may_infer->type_kind == TYPE_POINTER) + { + assert(actual->type_kind == TYPE_POINTER); + Type *base_type = cast_infer_len(canonical_same_kind ? to_infer->array.base : may_infer->pointer, actual->pointer); + return type_get_ptr(base_type); + } + UNREACHABLE +} + static inline bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type) { if (expr->expr_kind == EXPR_CONST) return false; @@ -406,6 +440,7 @@ CastKind cast_to_bool_kind(Type *type) UNREACHABLE } + bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const) { // 1. failable -> non-failable can't be cast unless we ignore failability. @@ -431,15 +466,9 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, // 2. Same underlying type, always ok if (from_type == to_type) return true; - if (to_type->type_kind == TYPE_INFERRED_ARRAY) + if (type_is_any_arraylike(to_type) && type_is_any_arraylike(from_type)) { - if (from_type->type_kind == TYPE_ARRAY && type_flatten_distinct(from_type->array.base) == type_flatten_distinct(to_type->array.base)) return true; - return false; - } - if (to_type->type_kind == TYPE_INFERRED_VECTOR) - { - if (from_type->type_kind == TYPE_VECTOR && type_flatten_distinct(from_type->array.base) == type_flatten_distinct(to_type->array.base)) return true; - return false; + return cast_may_array(from_type, to_type, true); } TypeKind to_kind = to_type->type_kind; @@ -534,30 +563,183 @@ bool type_may_convert_to_anyerr(Type *type) if (!type_is_optional_type(type)) return false; return type->failable->canonical == type_void; } + + +static inline bool cast_may_array(Type *from, Type *to, bool is_explicit) +{ + RETRY:; + assert(!type_is_optional(from) && !type_is_optional(to) && "Optional should already been handled"); + + bool compare_len = true; + if (from->type_kind != to->type_kind) + { + switch (to->type_kind) + { + case TYPE_INFERRED_ARRAY: + switch (from->type_kind) + { + case TYPE_INFERRED_VECTOR: + case TYPE_VECTOR: + if (!is_explicit) return false; + FALLTHROUGH; + case TYPE_ARRAY: + compare_len = false; + break; + default: + return false; + } + break; + case TYPE_ARRAY: + switch (from->type_kind) + { + case TYPE_INFERRED_VECTOR: + compare_len = false; + FALLTHROUGH; + case TYPE_VECTOR: + if (!is_explicit) return false; + break; + case TYPE_INFERRED_ARRAY: + compare_len = false; + break; + default: + return false; + } + break; + case TYPE_INFERRED_VECTOR: + switch (from->type_kind) + { + case TYPE_INFERRED_ARRAY: + case TYPE_ARRAY: + if (!is_explicit) return false; + FALLTHROUGH; + case TYPE_VECTOR: + case TYPE_SCALED_VECTOR: + compare_len = false; + break; + default: + return false; + } + break; + case TYPE_VECTOR: + switch (from->type_kind) + { + case TYPE_INFERRED_ARRAY: + compare_len = false; + FALLTHROUGH; + case TYPE_ARRAY: + if (!is_explicit) return false; + break; + case TYPE_INFERRED_VECTOR: + compare_len = false; + break; + default: + return false; + } + break; + case TYPE_SCALED_VECTOR: + if (from->type_kind != TYPE_INFERRED_VECTOR) return false; + compare_len = false; + break; + default: + return false; + } + } + if (compare_len && to->array.len != from->array.len) return false; + + Type *from_base = from->array.base; + Type *to_base = to->array.base; + if (is_explicit) + { + from_base = type_flatten(from_base); + to_base = type_flatten(to_base); + } + + if (from_base == to_base) return true; + + switch (to_base->type_kind) + { + case TYPE_POINTER: + if (from_base->type_kind == TYPE_POINTER) + { + if (is_explicit) return true; + return cast_may_implicit_ptr(to_base->pointer, from_base->pointer); + } + return false; + case TYPE_ARRAY: + case TYPE_INFERRED_ARRAY: + case TYPE_VECTOR: + case TYPE_INFERRED_VECTOR: + to = to_base; + from = from_base; + goto RETRY; + default: + return is_explicit && type_is_structurally_equivalent(to_base, from_base); + } +} + +static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee) +{ + assert(!type_is_optional(from_pointee) && !type_is_optional(to_pointee) && "Optional should already been handled"); + if (from_pointee == to_pointee) return true; + + // For void* on either side, no checks. + if (to_pointee == type_voidptr || from_pointee == type_voidptr) return true; + + // Step through all *: + while (from_pointee->type_kind == TYPE_POINTER && to_pointee->type_kind == TYPE_POINTER) + { + if (from_pointee == type_voidptr || to_pointee == type_voidptr) return true; + from_pointee = from_pointee->pointer; + to_pointee = to_pointee->pointer; + } + + assert(to_pointee != from_pointee); + + // Functions compare raw types. + if (from_pointee->type_kind == TYPE_FUNC && to_pointee->type_kind == TYPE_FUNC) + { + return to_pointee->function.prototype->raw_type == from_pointee->function.prototype->raw_type; + } + + // Special handling of int* = int[4]* (so we have int[4] -> int) + if (type_is_arraylike(from_pointee)) + { + if (cast_may_implicit_ptr(to_pointee, from_pointee->array.base)) return true; + } + + if (type_is_any_arraylike(to_pointee) || type_is_any_arraylike(from_pointee)) + { + return cast_may_array(from_pointee, to_pointee, false); + } + // Use subtype matching + return type_is_subtype(to_pointee, from_pointee); +} + /** * Can the conversion occur implicitly? */ -bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool failable_allowed) +bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option) { Type *to = to_type->canonical; - // 1. First handle void! => any error + // First handle void! => any error if (to == type_anyerr && type_may_convert_to_anyerr(from_type)) return true; - // 2. any! => may implicitly to convert to any. - if (type_is_optional_any(from_type)) return failable_allowed; + // any! => may implicitly to convert to any. + if (type_is_optional_any(from_type)) return (CAST_OPTION_ALLOW_OPTIONAL & option) != 0; + // Check if optional was allowed Type *from = from_type->canonical; if (type_is_optional_type(from_type)) { - if (!failable_allowed) return false; + if (!(CAST_OPTION_ALLOW_OPTIONAL & option)) return false; from = from_type->failable->canonical; } - // 4. Same canonical type - we're fine. + // Same canonical type - we're fine. if (from == to) return true; - // 2. Handle floats + // Handle floats if (type_is_float(to)) { // 2a. Any integer may convert to a float. @@ -569,14 +751,12 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool ByteSize to_size = type_size(to); ByteSize from_size = type_size(from); if (to_size == from_size) return true; - return to_size > from_size && is_simple_expr; + return to_size > from_size && (option & CAST_OPTION_SIMPLE_EXPR); } return false; } - if (to == type_anyerr && from->type_kind == TYPE_FAULTTYPE) return true; - - // 3. Handle ints + // Handle ints if (type_is_integer(to)) { // For an enum, lower to the underlying enum type. @@ -591,61 +771,41 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool ByteSize to_size = type_size(to); ByteSize from_size = type_size(from); if (to_size == from_size) return true; - return to_size > from_size && is_simple_expr; + return to_size > from_size && (option & CAST_OPTION_SIMPLE_EXPR); } return false; } - // 4. Handle pointers + // Convert any fault to anyerr + if (to == type_anyerr && from->type_kind == TYPE_FAULTTYPE) return true; + + // Handle pointers if (type_is_pointer(to)) { - // 4a. Assigning a subarray to a pointer of the same base type is fine + // Assigning a subarray to a pointer if (from->type_kind == TYPE_SUBARRAY) { - // void* conversion always work. + // Casting to a void* always works. if (to == type_voidptr) return true; - // Use subtype matching - return type_is_subtype(to->pointer->canonical, from->array.base->canonical); + // Compare as if it was a pointer. + return cast_may_implicit_ptr(from->array.base, to_type->pointer); } - // 4b. Assigning a pointer + // Assigning a pointer to a pointer if (from->type_kind == TYPE_POINTER) { - // For void* on either side, no checks. + // Casting to or from a void* always works. if (to == type_voidptr || from == type_voidptr) return true; - Type *from_pointee = from->pointer; - - if (from_pointee->type_kind == TYPE_FUNC && to->type_kind == TYPE_POINTER && to->pointer->type_kind == TYPE_FUNC) - { - return to->pointer->function.prototype->raw_type == from_pointee->function.prototype->raw_type; - } - // Special handling of int* = int[4]* - if (from_pointee->type_kind == TYPE_ARRAY || from_pointee->type_kind == TYPE_FLEXIBLE_ARRAY) - { - if (type_is_subtype(to->pointer, from_pointee->array.base)) - { - return true; - } - } - - // Use subtype matching - return type_is_subtype(to->pointer, from_pointee); + return cast_may_implicit_ptr(from->pointer, to->pointer); } - return false; } - if (to_type->type_kind == TYPE_INFERRED_ARRAY) + if (type_is_any_arraylike(to) && type_is_any_arraylike(from)) { - if (from->type_kind == TYPE_ARRAY && type_flatten_distinct(from->array.base) == type_flatten_distinct(to_type->array.base)) return true; - return false; - } - if (to_type->type_kind == TYPE_INFERRED_VECTOR) - { - if (from->type_kind == TYPE_VECTOR && type_flatten_distinct(from->array.base) == type_flatten_distinct(to_type->array.base)) return true; - return false; + return cast_may_array(from, to, false); } // 5. Handle sub arrays @@ -680,7 +840,7 @@ bool cast_may_implicit(Type *from_type, Type *to_type, bool is_simple_expr, bool // 11. Substruct cast, if the first member is inline, see if we can cast to this member. if (type_is_substruct(from)) { - return cast_may_implicit(from->decl->strukt.members[0]->type, to, is_simple_expr, failable_allowed); + return cast_may_implicit(from->decl->strukt.members[0]->type, to, option); } return false; @@ -1135,8 +1295,10 @@ bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) return cast_untyped_to_type(context, expr, to_type); } - bool is_simple = expr_is_simple(expr); - if (!cast_may_implicit(expr_canonical, to_canonical, is_simple, true)) + CastOption option = CAST_OPTION_ALLOW_OPTIONAL; + if (expr_is_simple(expr)) option |= CAST_OPTION_SIMPLE_EXPR; + + if (!cast_may_implicit(expr_canonical, to_canonical, option)) { if (!cast_may_explicit(expr_canonical, to_canonical, false, expr->expr_kind == EXPR_CONST)) { @@ -1209,8 +1371,9 @@ bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type) } goto OK; } - SEMA_ERROR(expr, "Implicitly casting %s to %s is not permitted, but you can do an explicit cast using '()(value)'.", type_quoted_error_string( - type_no_optional(expr->type)), type_quoted_error_string(type_no_optional(to_type))); + SEMA_ERROR(expr, "Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.", type_quoted_error_string( + type_no_optional(expr->type)), type_quoted_error_string(type_no_optional(to_type)), + type_to_error_string(to_type)); return false; } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 5adc4e33f..0cecae814 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2446,15 +2446,12 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (infer_len) { - Type *right_side_type = init->type->canonical; - if (right_side_type->type_kind == TYPE_ARRAY) + if (type_is_len_inferred(init->type)) { - decl->type = type_get_array(decl->type->array.base, right_side_type->array.len); - } - else - { - decl->type = type_get_vector(decl->type->array.base, right_side_type->array.len); + SEMA_ERROR(decl->var.type_info, "You cannot use [*] and [<*>] underlying types with initializers."); + return false; } + decl->type = cast_infer_len(decl->type, init->type); } Expr *init_expr = decl->var.init_expr; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 158c88cb3..7e76d6ae6 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1797,7 +1797,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s inferred_len = false; } } - if (!cast_may_implicit(type, rtype, true, may_failable) || inferred_len) + if (!cast_may_implicit(type, rtype, CAST_OPTION_SIMPLE_EXPR | (may_failable ? CAST_OPTION_ALLOW_OPTIONAL : 0)) || inferred_len) { SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype), type_quoted_error_string(type)); @@ -3820,7 +3820,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ Range *left_range = &left->subscript_expr.range; Range *right_range = &right->subscript_expr.range; if (!sema_analyse_expr(context, right)) return false; - if (cast_may_implicit(right->type, base, true, false)) goto ASSIGN; + if (cast_may_implicit(right->type, base, CAST_OPTION_SIMPLE_EXPR)) goto ASSIGN; if (!cast_implicit(context, right, left_type)) return false; IndexDiff left_len = range_const_len(left_range); IndexDiff right_len = range_const_len(right_range); @@ -4248,7 +4248,7 @@ static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff) if (maybe_pointer->expr_kind == EXPR_CAST && maybe_pointer->cast_expr.kind == CAST_PTRXI && type_flatten(maybe_pointer->type) == type_flatten(type_iptr) - && cast_may_implicit(maybe_diff->type, maybe_diff->type, true, true)) + && cast_may_implicit(maybe_diff->type, maybe_diff->type, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL)) { Type *cast_to_iptr = maybe_pointer->type; maybe_pointer->cast_expr.kind = CAST_PTRPTR; @@ -5301,7 +5301,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) } // 4. Let's see if it's possible to cast it implicitly - if (!cast_may_implicit(type, type_bool, true, true)) + if (!cast_may_implicit(type, type_bool, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL)) { SEMA_ERROR(expr, "The use of '!' on %s is not allowed as it can't be converted to a boolean value.", type_quoted_error_string(inner->type)); return false; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 7dea1896b..750032fc6 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -5,11 +5,13 @@ #include "sema_internal.h" static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer); -static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Expr *initializer); +static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened, + Expr *initializer); static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer); -static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Expr *initializer); +static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened, + Expr *initializer); static inline void sema_not_enough_elements_error(Expr *initializer, int element); -static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *external_type, Type *assigned, Expr *expr); +static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr); static void sema_create_const_initializer_value(ConstInitializer *const_init, Expr *value); static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer); static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **elements, unsigned *index); @@ -218,16 +220,27 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte * Perform analysis for a plain initializer, that is one initializing all fields. * @return true if analysis succeeds. */ -static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Expr *initializer) +static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened, + Expr *initializer) { Expr **elements = initializer->initializer_list; + bool inferred_len = type_len_is_inferred(flattened); + // We have the case where "Foo = int[*]" + if (inferred_len && !type_len_is_inferred(assigned)) + { + assert(assigned->type_kind == TYPE_TYPEDEF); + assert(assigned->decl->decl_kind == DECL_TYPEDEF); + while (assigned->type_kind == TYPE_TYPEDEF) assigned = assigned->decl->type; + assert(type_len_is_inferred(assigned)); + } + // Prefer the typedef index: define Bar = int; Bar[1] => Bar and not int Type *inner_type = type_get_indexed_type(assigned); assert(inner_type); unsigned size = vec_size(elements); - unsigned expected_members = assigned->array.len; - if (assigned->type_kind != TYPE_ARRAY && assigned->type_kind != TYPE_VECTOR) expected_members = size; + unsigned expected_members = flattened->array.len; + if (type_is_len_inferred(flattened)) expected_members = size; assert(size > 0 && "We should already have handled the size == 0 case."); if (expected_members == 0) @@ -238,7 +251,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex } bool failable = false; - VECEACH(elements, i) + unsigned count = vec_size(elements); + for (unsigned i = 0; i < count; i++) { Expr *element = elements[i]; if (i >= expected_members) @@ -246,10 +260,19 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members); return false; } - if (!sema_analyse_expr_rhs(context, inner_type, element, true)) return false; + Type *element_type = type_no_optional(element->type); failable = failable || IS_OPTIONAL(element); } + if (inferred_len) + { + initializer->type = type_from_inferred(flattened, inner_type, count); + } + else + { + initializer->type = assigned; + } + assert(initializer->type); if (failable) initializer->type = type_get_optional(initializer->type); @@ -303,14 +326,17 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E return true; } -static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Expr *initializer) +static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened, + Expr *initializer) { Expr **init_expressions = initializer->designated_init_list; - Type *original = assigned->canonical; + Type *original = flattened->canonical; bool is_bitstruct = original->type_kind == TYPE_BITSTRUCT; bool is_structlike = type_is_union_or_strukt(original) || is_bitstruct; MemberIndex max_index = -1; bool failable = false; + Type *inner_type = NULL; + bool is_inferred = type_is_len_inferred(flattened); VECEACH(init_expressions, i) { Expr *expr = init_expressions[i]; @@ -325,11 +351,19 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type } failable = failable || IS_OPTIONAL(value); expr->resolve_status = RESOLVE_DONE; + if (!inner_type) + { + inner_type = type_no_optional(value->type); + continue; + } } - - if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY) + if (!is_structlike && is_inferred) { - initializer->type = sema_type_lower_by_size(initializer->type, (ArraySize)(max_index + 1)); + initializer->type = type_from_inferred(flattened, type_get_indexed_type(assigned), (ArraySize)(max_index + 1)); + } + else + { + initializer->type = assigned; } initializer->resolve_status = RESOLVE_DONE; if (expr_is_constant_eval(initializer, env_eval_type(context))) @@ -342,17 +376,21 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type } -static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *external_type, Type *assigned, Expr *expr) +static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr) { // Note at this point this we either have // EXPR_DESIGNATED_INITIALIZER_LIST // or EXPR_INITIALIZER_LIST + if (type_len_is_inferred(flattened) && type_len_is_inferred(type_get_indexed_type(flattened))) + { + SEMA_ERROR(expr, "Initializers cannot be used with inferred length element types (e.g. %s).", type_quoted_error_string(type_get_indexed_type(flattened))); + return false; + } // 1. Designated initializer is separately evaluated. if (expr->expr_kind == EXPR_DESIGNATED_INITIALIZER_LIST) { - expr->type = external_type; - return sema_expr_analyse_designated_initializer(context, assigned, expr); + return sema_expr_analyse_designated_initializer(context, assigned_type, flattened, expr); } assert(expr->expr_kind == EXPR_INITIALIZER_LIST); @@ -369,45 +407,37 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ext // 3. Zero size init will initialize to empty. if (init_expression_count == 0) { - if (type_len_is_inferred(external_type)) + if (type_len_is_inferred(assigned_type)) { SEMA_ERROR(expr, "Zero length arrays / vectors are not permitted."); return false; } - external_type = sema_type_lower_by_size(external_type, 0); - expr->type = external_type; ConstInitializer *initializer = CALLOCS(ConstInitializer); initializer->kind = CONST_INIT_ZERO; - initializer->type = type_flatten(expr->type); - expr_rewrite_const_initializer(expr, expr->type, initializer); + initializer->type = flattened; + expr_rewrite_const_initializer(expr, assigned_type, initializer); return true; } - - // 4. If we have an inferred array, we need to set the size. - external_type = sema_type_lower_by_size(external_type, init_expression_count); - assigned = sema_type_lower_by_size(assigned, init_expression_count); - - // 5. Set the type. - expr->type = external_type; - - // 6. We might have a complist, because were analyzing $foo = { ... } or similar. - if (external_type == type_untypedlist) + // 4. We might have a complist, because were analyzing $foo = { ... } or similar. + if (assigned_type == type_untypedlist) { return sema_expr_analyse_untyped_initializer(context, expr); } - // 7. If not, then we see if we have an array. - if (assigned->type_kind == TYPE_UNTYPED_LIST || - assigned->type_kind == TYPE_ARRAY || - assigned->type_kind == TYPE_INFERRED_ARRAY || - assigned->type_kind == TYPE_INFERRED_VECTOR || - assigned->type_kind == TYPE_SUBARRAY || - assigned->type_kind == TYPE_VECTOR) + + // 5. If not, then we see if we have an array. + if (flattened->type_kind == TYPE_UNTYPED_LIST || + flattened->type_kind == TYPE_ARRAY || + flattened->type_kind == TYPE_INFERRED_ARRAY || + flattened->type_kind == TYPE_INFERRED_VECTOR || + flattened->type_kind == TYPE_SUBARRAY || + flattened->type_kind == TYPE_VECTOR) { - return sema_expr_analyse_array_plain_initializer(context, assigned, expr); + return sema_expr_analyse_array_plain_initializer(context, assigned_type, flattened, expr); } - return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr); + expr->type = assigned_type; + return sema_expr_analyse_struct_plain_initializer(context, flattened->decl, expr); } /** @@ -434,8 +464,8 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex { if (!to) to = type_untypedlist; assert(to); - Type *assigned = type_flatten(to); - switch (assigned->type_kind) + Type *flattened = type_flatten(to); + switch (flattened->type_kind) { case TYPE_UNTYPED_LIST: case TYPE_STRUCT: @@ -445,7 +475,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: case TYPE_VECTOR: - return sema_expr_analyse_initializer(context, to, assigned, expr); + return sema_expr_analyse_initializer(context, to, flattened, expr); case TYPE_SUBARRAY: { if (expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list)) @@ -453,11 +483,11 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex expr->expr_kind = EXPR_CONST; expr->const_expr.const_kind = CONST_POINTER; expr->const_expr.ptr = 0; - expr->type = assigned; + expr->type = flattened; return true; } // Resolve this as an inferred array. - Type *type = type_get_inferred_array(assigned->array.base); + Type *type = type_get_inferred_array(flattened->array.base); if (!sema_expr_analyse_initializer(context, type, type, expr)) return false; expr->resolve_status = RESOLVE_DONE; expr_insert_addr(expr); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 475e7a14a..62ac76b90 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -901,7 +901,7 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType // 3a. Check for failables in case of an expression. if (IS_OPTIONAL(last)) { - if (!cast_to_bool || cast_may_implicit(type_no_optional(last->type), type_bool, false, false)) + if (!cast_to_bool || cast_may_implicit(type_no_optional(last->type), type_bool, CAST_OPTION_NONE)) { SEMA_ERROR(last, "The expression may not be a failable, but was %s.", type_quoted_error_string(last->type)); return false; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 5cd9b3b71..b0f3a1557 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -4,9 +4,9 @@ #include "sema_internal.h" -static inline bool sema_resolve_ptr_type(SemaContext *context, TypeInfo *type_info) +static inline bool sema_resolve_ptr_type(SemaContext *context, TypeInfo *type_info, bool allow_inferred) { - if (!sema_resolve_type_shallow(context, type_info->pointer, false, true)) + if (!sema_resolve_type_shallow(context, type_info->pointer, allow_inferred, true)) { return type_info_poison(type_info); } @@ -77,18 +77,18 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra } // TODO cleanup. -static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, bool shallow) +static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, bool allow_inferred, bool shallow) { if (type->kind == TYPE_INFO_SUBARRAY || shallow) { - if (!sema_resolve_type_shallow(context, type->array.base, false, true)) + if (!sema_resolve_type_shallow(context, type->array.base, allow_inferred, true)) { return type_info_poison(type); } } else { - if (!sema_resolve_type_info(context, type->array.base)) + if (!sema_resolve_type_info_maybe_inferred(context, type->array.base, allow_inferred)) { return type_info_poison(type); } @@ -271,7 +271,6 @@ bool sema_resolve_type_shallow(SemaContext *context, TypeInfo *type_info, bool a TypeInfoCompressedKind kind = type_info->subtype; if (kind != TYPE_COMPRESSED_NONE) { - allow_inferred_type = false; in_shallow = true; } switch (type_info->kind) @@ -366,10 +365,10 @@ bool sema_resolve_type_shallow(SemaContext *context, TypeInfo *type_info, bool a case TYPE_INFO_SUBARRAY: case TYPE_INFO_ARRAY: case TYPE_INFO_VECTOR: - if (!sema_resolve_array_type(context, type_info, in_shallow)) return false; + if (!sema_resolve_array_type(context, type_info, allow_inferred_type, in_shallow)) return false; break; case TYPE_INFO_POINTER: - if (!sema_resolve_ptr_type(context, type_info)) return false; + if (!sema_resolve_ptr_type(context, type_info, allow_inferred_type)) return false; break; } APPEND_QUALIFIERS: diff --git a/src/version.h b/src/version.h index d6f773936..e26afee2a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.80" \ No newline at end of file +#define COMPILER_VERSION "0.3.81" \ No newline at end of file diff --git a/test/test_suite/cast/implicit_infer_len_cast.c3t b/test/test_suite/cast/implicit_infer_len_cast.c3t new file mode 100644 index 000000000..b12a4ce60 --- /dev/null +++ b/test/test_suite/cast/implicit_infer_len_cast.c3t @@ -0,0 +1,66 @@ +// #target: macos-x64 +module test; + +macro int test(int[*][*]* y) +{ + $typeof(*y) z = *y; + return z[1][1]; +} +fn void main() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + int[<2>][*] y = { { 1, 3 }}; + int[<*>][*] z = y; + int[<2>][1] w = z; + int[<2>][] aa = { { 1, 3 }}; + int[][*] bb = { { 1, 3 } }; + test(&x); +} +/* #expect: test.ll + + %x = alloca [2 x [2 x i32]], align 16 + %y = alloca [1 x <2 x i32>], align 8 + %z = alloca [1 x <2 x i32>], align 8 + %w = alloca [1 x <2 x i32>], align 8 + %aa = alloca %"int[<2>][]", align 8 + %literal = alloca [1 x <2 x i32>], align 8 + %bb = alloca [1 x %"int[]"], align 16 + %literal1 = alloca [2 x i32], align 4 + %y2 = alloca [2 x [2 x i32]]*, align 8 + %z3 = alloca [2 x [2 x i32]], align 16 + %0 = bitcast [2 x [2 x i32]]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %0, i8* align 16 bitcast ([2 x [2 x i32]]* @.__const to i8*), i32 16, i1 false) + %1 = bitcast [1 x <2 x i32>]* %y to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 bitcast ([1 x <2 x i32>]* @.__const.1 to i8*), i32 8, i1 false) + %2 = bitcast [1 x <2 x i32>]* %z to i8* + %3 = bitcast [1 x <2 x i32>]* %y to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %2, i8* align 8 %3, i32 8, i1 false) + %4 = bitcast [1 x <2 x i32>]* %w to i8* + %5 = bitcast [1 x <2 x i32>]* %z to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 8, i1 false) + %6 = getelementptr inbounds [1 x <2 x i32>], [1 x <2 x i32>]* %literal, i64 0, i64 0 + %7 = getelementptr inbounds <2 x i32>, <2 x i32>* %6, i64 0, i64 0 + store i32 1, i32* %7, align 4 + %8 = getelementptr inbounds <2 x i32>, <2 x i32>* %6, i64 0, i64 1 + store i32 3, i32* %8, align 4 + %9 = bitcast [1 x <2 x i32>]* %literal to <2 x i32>* + %10 = insertvalue %"int[<2>][]" undef, <2 x i32>* %9, 0 + %11 = insertvalue %"int[<2>][]" %10, i64 1, 1 + store %"int[<2>][]" %11, %"int[<2>][]"* %aa, align 8 + %12 = getelementptr inbounds [1 x %"int[]"], [1 x %"int[]"]* %bb, i64 0, i64 0 + %13 = getelementptr inbounds [2 x i32], [2 x i32]* %literal1, i64 0, i64 0 + store i32 1, i32* %13, align 4 + %14 = getelementptr inbounds [2 x i32], [2 x i32]* %literal1, i64 0, i64 1 + store i32 3, i32* %14, align 4 + %15 = bitcast [2 x i32]* %literal1 to i32* + %16 = insertvalue %"int[]" undef, i32* %15, 0 + %17 = insertvalue %"int[]" %16, i64 2, 1 + store %"int[]" %17, %"int[]"* %12, align 16 + store [2 x [2 x i32]]* %x, [2 x [2 x i32]]** %y2, align 8 + %18 = load [2 x [2 x i32]]*, [2 x [2 x i32]]** %y2, align 8 + %19 = bitcast [2 x [2 x i32]]* %z3 to i8* + %20 = bitcast [2 x [2 x i32]]* %18 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %19, i8* align 8 %20, i32 16, i1 false) + %21 = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* %z3, i64 0, i64 1 + %22 = getelementptr inbounds [2 x i32], [2 x i32]* %21, i64 0, i64 1 + ret void diff --git a/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 new file mode 100644 index 000000000..816212d51 --- /dev/null +++ b/test/test_suite/expressions/casts/struct_cast_and_distinct.c3 @@ -0,0 +1,32 @@ +module test; + +define Foo = distinct int; + +fn void test1() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2] y = x; // #error: can do an explicit +} + +fn void test2() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2] y = (Foo[2][2])x; +} + + +fn void test3() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2]* y = &x; // #error: can do an explicit +} + +struct Bar { int x; } + +struct Baz { int x; } + +fn void test4() +{ + Baz[2][*] x = { { { 2 } , { 3 } }, {{5}, {6} }}; + Bar[*][*] y = (Bar[2][2])x; +} diff --git a/test/test_suite2/cast/implicit_infer_len_cast.c3t b/test/test_suite2/cast/implicit_infer_len_cast.c3t new file mode 100644 index 000000000..945a96145 --- /dev/null +++ b/test/test_suite2/cast/implicit_infer_len_cast.c3t @@ -0,0 +1,56 @@ +// #target: macos-x64 +module test; + +macro int test(int[*][*]* y) +{ + $typeof(*y) z = *y; + return z[1][1]; +} +fn void main() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + int[<2>][*] y = { { 1, 3 }}; + int[<*>][*] z = y; + int[<2>][1] w = z; + int[<2>][] aa = { { 1, 3 }}; + int[][*] bb = { { 1, 3 } }; + test(&x); +} +/* #expect: test.ll + + %x = alloca [2 x [2 x i32]], align 16 + %y = alloca [1 x <2 x i32>], align 8 + %z = alloca [1 x <2 x i32>], align 8 + %w = alloca [1 x <2 x i32>], align 8 + %aa = alloca %"int[<2>][]", align 8 + %literal = alloca [1 x <2 x i32>], align 8 + %bb = alloca [1 x %"int[]"], align 16 + %literal1 = alloca [2 x i32], align 4 + %y2 = alloca ptr, align 8 + %z3 = alloca [2 x [2 x i32]], align 16 + call void @llvm.memcpy.p0.p0.i32(ptr align 16 %x, ptr align 16 @.__const, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %y, ptr align 8 @.__const.1, i32 8, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %z, ptr align 8 %y, i32 8, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %w, ptr align 8 %z, i32 8, i1 false) + %0 = getelementptr inbounds [1 x <2 x i32>], ptr %literal, i64 0, i64 0 + %1 = getelementptr inbounds <2 x i32>, ptr %0, i64 0, i64 0 + store i32 1, ptr %1, align 4 + %2 = getelementptr inbounds <2 x i32>, ptr %0, i64 0, i64 1 + store i32 3, ptr %2, align 4 + %3 = insertvalue %"int[<2>][]" undef, ptr %literal, 0 + %4 = insertvalue %"int[<2>][]" %3, i64 1, 1 + store %"int[<2>][]" %4, ptr %aa, align 8 + %5 = getelementptr inbounds [1 x %"int[]"], ptr %bb, i64 0, i64 0 + %6 = getelementptr inbounds [2 x i32], ptr %literal1, i64 0, i64 0 + store i32 1, ptr %6, align 4 + %7 = getelementptr inbounds [2 x i32], ptr %literal1, i64 0, i64 1 + store i32 3, ptr %7, align 4 + %8 = insertvalue %"int[]" undef, ptr %literal1, 0 + %9 = insertvalue %"int[]" %8, i64 2, 1 + store %"int[]" %9, ptr %5, align 16 + store ptr %x, ptr %y2, align 8 + %10 = load ptr, ptr %y2, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 16 %z3, ptr align 8 %10, i32 16, i1 false) + %11 = getelementptr inbounds [2 x [2 x i32]], ptr %z3, i64 0, i64 1 + %12 = getelementptr inbounds [2 x i32], ptr %11, i64 0, i64 1 + ret void diff --git a/test/test_suite2/expressions/casts/struct_cast_and_distinct.c3 b/test/test_suite2/expressions/casts/struct_cast_and_distinct.c3 new file mode 100644 index 000000000..816212d51 --- /dev/null +++ b/test/test_suite2/expressions/casts/struct_cast_and_distinct.c3 @@ -0,0 +1,32 @@ +module test; + +define Foo = distinct int; + +fn void test1() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2] y = x; // #error: can do an explicit +} + +fn void test2() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2] y = (Foo[2][2])x; +} + + +fn void test3() +{ + int[2][*] x = { { 2, 3}, { 5, 6 }}; + Foo[2][2]* y = &x; // #error: can do an explicit +} + +struct Bar { int x; } + +struct Baz { int x; } + +fn void test4() +{ + Baz[2][*] x = { { { 2 } , { 3 } }, {{5}, {6} }}; + Bar[*][*] y = (Bar[2][2])x; +}