diff --git a/src/check_type.cpp b/src/check_type.cpp index da4479f6e..5889cbcd0 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2834,6 +2834,111 @@ gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_ return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Dynamic); } +gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { + ast_node(at, ArrayType, e); + if (at->count != nullptr) { + Operand o = {}; + i64 count = check_array_count(ctx, &o, at->count); + Type *generic_type = nullptr; + + Type *elem = check_type_expr(ctx, at->elem, nullptr); + + if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { + generic_type = o.type; + } else if (o.mode == Addressing_Type && is_type_enum(o.type)) { + Type *index = o.type; + Type *bt = base_type(index); + GB_ASSERT(bt->kind == Type_Enum); + + Type *t = alloc_type_enumerated_array(elem, index, bt->Enum.min_value, bt->Enum.max_value, bt->Enum.fields.count, Token_Invalid); + + bool is_sparse = false; + if (at->tag != nullptr) { + GB_ASSERT(at->tag->kind == Ast_BasicDirective); + String name = at->tag->BasicDirective.name.string; + if (name == "sparse") { + is_sparse = true; + } else { + error(at->tag, "Invalid tag applied to an enumerated array, got #%.*s", LIT(name)); + } + } + + if (!is_sparse && t->EnumeratedArray.count > bt->Enum.fields.count) { + error(e, "Non-contiguous enumeration used as an index in an enumerated array"); + long long ea_count = cast(long long)t->EnumeratedArray.count; + long long enum_count = cast(long long)bt->Enum.fields.count; + error_line("\tenumerated array length: %lld\n", ea_count); + error_line("\tenum field count: %lld\n", enum_count); + error_line("\tSuggestion: prepend #sparse to the enumerated array to allow for non-contiguous elements\n"); + if (2*enum_count < ea_count) { + error_line("\tWarning: the number of named elements is much smaller than the length of the array, are you sure this is what you want?\n"); + error_line("\t this warning will be removed if #sparse is applied\n"); + } + } + t->EnumeratedArray.is_sparse = is_sparse; + + *type = t; + + return; + } + + if (count < 0) { + error(at->count, "? can only be used in conjuction with compound literals"); + count = 0; + } + + + if (at->tag != nullptr) { + GB_ASSERT(at->tag->kind == Ast_BasicDirective); + String name = at->tag->BasicDirective.name.string; + if (name == "soa") { + *type = make_soa_struct_fixed(ctx, e, at->elem, elem, count, generic_type); + } else if (name == "simd") { + if (!is_type_valid_vector_elem(elem) && !is_type_polymorphic(elem)) { + gbString str = type_to_string(elem); + error(at->elem, "Invalid element type for #simd, expected an integer, float, or boolean with no specific endianness, got '%s'", str); + gb_string_free(str); + *type = alloc_type_array(elem, count, generic_type); + return; + } + + if (generic_type != nullptr) { + // Ignore + } else if (count < 1 || !is_power_of_two(count)) { + error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count); + *type = alloc_type_array(elem, count, generic_type); + return; + } + + *type = alloc_type_simd_vector(count, elem, generic_type); + + if (count > SIMD_ELEMENT_COUNT_MAX) { + error(at->count, "#simd support a maximum element count of %d, got %lld", SIMD_ELEMENT_COUNT_MAX, cast(long long)count); + } + } else { + error(at->tag, "Invalid tag applied to array, got #%.*s", LIT(name)); + *type = alloc_type_array(elem, count, generic_type); + } + } else { + *type = alloc_type_array(elem, count, generic_type); + } + } else { + Type *elem = check_type(ctx, at->elem); + + if (at->tag != nullptr) { + GB_ASSERT(at->tag->kind == Ast_BasicDirective); + String name = at->tag->BasicDirective.name.string; + if (name == "soa") { + *type = make_soa_struct_slice(ctx, e, at->elem, elem); + } else { + error(at->tag, "Invalid tag applied to array, got #%.*s", LIT(name)); + *type = alloc_type_slice(elem); + } + } else { + *type = alloc_type_slice(elem); + } + } +} gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { GB_ASSERT_NOT_NULL(type); if (e == nullptr) { @@ -3072,109 +3177,7 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_end; case_ast_node(at, ArrayType, e); - if (at->count != nullptr) { - Operand o = {}; - i64 count = check_array_count(ctx, &o, at->count); - Type *generic_type = nullptr; - - Type *elem = check_type_expr(ctx, at->elem, nullptr); - - if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { - generic_type = o.type; - } else if (o.mode == Addressing_Type && is_type_enum(o.type)) { - Type *index = o.type; - Type *bt = base_type(index); - GB_ASSERT(bt->kind == Type_Enum); - - Type *t = alloc_type_enumerated_array(elem, index, bt->Enum.min_value, bt->Enum.max_value, bt->Enum.fields.count, Token_Invalid); - - bool is_sparse = false; - if (at->tag != nullptr) { - GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name.string; - if (name == "sparse") { - is_sparse = true; - } else { - error(at->tag, "Invalid tag applied to an enumerated array, got #%.*s", LIT(name)); - } - } - - if (!is_sparse && t->EnumeratedArray.count > bt->Enum.fields.count) { - error(e, "Non-contiguous enumeration used as an index in an enumerated array"); - long long ea_count = cast(long long)t->EnumeratedArray.count; - long long enum_count = cast(long long)bt->Enum.fields.count; - error_line("\tenumerated array length: %lld\n", ea_count); - error_line("\tenum field count: %lld\n", enum_count); - error_line("\tSuggestion: prepend #sparse to the enumerated array to allow for non-contiguous elements\n"); - if (2*enum_count < ea_count) { - error_line("\tWarning: the number of named elements is much smaller than the length of the array, are you sure this is what you want?\n"); - error_line("\t this warning will be removed if #sparse is applied\n"); - } - } - t->EnumeratedArray.is_sparse = is_sparse; - - *type = t; - - goto array_end; - } - - if (count < 0) { - error(at->count, "? can only be used in conjuction with compound literals"); - count = 0; - } - - - if (at->tag != nullptr) { - GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name.string; - if (name == "soa") { - *type = make_soa_struct_fixed(ctx, e, at->elem, elem, count, generic_type); - } else if (name == "simd") { - if (!is_type_valid_vector_elem(elem) && !is_type_polymorphic(elem)) { - gbString str = type_to_string(elem); - error(at->elem, "Invalid element type for #simd, expected an integer, float, or boolean with no specific endianness, got '%s'", str); - gb_string_free(str); - *type = alloc_type_array(elem, count, generic_type); - goto array_end; - } - - if (generic_type != nullptr) { - // Ignore - } else if (count < 1 || !is_power_of_two(count)) { - error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count); - *type = alloc_type_array(elem, count, generic_type); - goto array_end; - } - - *type = alloc_type_simd_vector(count, elem, generic_type); - - if (count > SIMD_ELEMENT_COUNT_MAX) { - error(at->count, "#simd support a maximum element count of %d, got %lld", SIMD_ELEMENT_COUNT_MAX, cast(long long)count); - } - } else { - error(at->tag, "Invalid tag applied to array, got #%.*s", LIT(name)); - *type = alloc_type_array(elem, count, generic_type); - } - } else { - *type = alloc_type_array(elem, count, generic_type); - } - } else { - Type *elem = check_type(ctx, at->elem); - - if (at->tag != nullptr) { - GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name.string; - if (name == "soa") { - *type = make_soa_struct_slice(ctx, e, at->elem, elem); - } else { - error(at->tag, "Invalid tag applied to array, got #%.*s", LIT(name)); - *type = alloc_type_slice(elem); - } - } else { - *type = alloc_type_slice(elem); - } - } - array_end: + check_array_type_internal(ctx, e, type, named_type); set_base_type(named_type, *type); return true; case_end; @@ -3349,6 +3352,10 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) ERROR_BLOCK(); error(e, "'%s' is not a type", err_str); + type = t_invalid; + + + // NOTE(bill): Check for common mistakes from C programmers e.g. T[] and T[N] Ast *node = unparen_expr(e); if (node && node->kind == Ast_IndexExpr) { gbString index_str = nullptr; @@ -3361,9 +3368,14 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) defer (gb_string_free(type_str)); error_line("\tSuggestion: Did you mean '[%s]%s'?", index_str ? index_str : "", type_str); + + // NOTE(bill): Minimize error propagation of bad array syntax by treating this like a type + if (node->IndexExpr.expr != nullptr) { + Ast *pseudo_array_expr = ast_array_type(e->file(), ast_token(node->IndexExpr.expr), node->IndexExpr.index, node->IndexExpr.expr); + check_array_type_internal(ctx, pseudo_array_expr, &type, nullptr); + } } - type = t_invalid; } if (type == nullptr) {