From d696abc97143061bf2abb05922188e12b59306c1 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 14 Aug 2026 17:22:17 +0200 Subject: Use the new .is_a() for literal kind checks in the evaluator --- boot/type_check.cc | 184 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 105 insertions(+), 79 deletions(-) (limited to 'boot/type_check.cc') diff --git a/boot/type_check.cc b/boot/type_check.cc index b1739d9..07e563f 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -100,14 +100,7 @@ namespace elna::boot { using T = std::decay_t; - if constexpr (std::is_same_v) - { - return "Trait #" + this->trait_name + " expects " - + std::to_string(payload.expected) + " argument" - + (payload.expected != 1 ? "s" : "") + ", got " - + std::to_string(payload.actual); - } - else if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { return "The second argument to the #" + this->trait_name + " trait must be a field name"; @@ -170,41 +163,50 @@ namespace elna::boot return "The number " + payload.overflow.to_string() + " does not fit into the type '" + actual.to_string() + "'"; } - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) { - switch (payload) - { - using enum kind; - case record_base: - return "Expected a record type, but got '" - + this->actual.to_string() + "'"; - case for_range: - return "Expected an array or slice type, but got '" - + this->actual.to_string() + "'"; - case condition: - return "Condition must be a boolean expression, but got '" - + this->actual.to_string() + "'"; - case constant_assignment: - return "Cannot assign to a value of type '" + this->actual.to_string() - + "', because it is constant or contains constant members"; - case array_index: - return "Array index must be an integral type, but got '" - + this->actual.to_string() + "'"; - case non_indexable: - return "Indexing is not allowed on type '" - + this->actual.to_string() + "'"; - case dereference_of_non_pointer: - return "Type '" + this->actual.to_string() - + "' cannot be dereferenced, it is not a pointer"; - default: - __builtin_unreachable(); - } + return "Cannot assign to a value of type '" + this->actual.to_string() + + "', because it is constant or contains constant members"; } }, this->payload); } - cyclic_declaration_error::cyclic_declaration_error(const std::vector& cycle, - const source_position position) + type_requirement_error::type_requirement_error(const source_position position, + type actual, kind kind) + : error(position), actual(std::move(actual)), m_kind(kind) + { + } + + std::string type_requirement_error::what() const + { + switch (this->m_kind) + { + using enum kind; + case record_base: + return "Expected a record type, but got '" + + this->actual.to_string() + "'"; + case for_range: + return "Expected an array or slice type, but got '" + + this->actual.to_string() + "'"; + case condition: + return "Condition must be a boolean expression, but got '" + + this->actual.to_string() + "'"; + case array_index: + return "Array index must be an integral type, but got '" + + this->actual.to_string() + "'"; + case non_indexable: + return "Indexing is not allowed on type '" + + this->actual.to_string() + "'"; + case dereference_of_non_pointer: + return "Type '" + this->actual.to_string() + + "' cannot be dereferenced, it is not a pointer"; + default: + __builtin_unreachable(); + } + } + + cyclic_declaration_error::cyclic_declaration_error(const source_position position, + const std::vector& cycle) : error(position), cycle(cycle) { } @@ -222,24 +224,35 @@ namespace elna::boot return message; } - argument_count_error::argument_count_error(std::size_t expected, std::size_t actual, - const source_position position) - : error(position), expected(expected), actual(actual) + argument_count_error::argument_count_error(const source_position position, kind kind, + std::string applicand, std::size_t expected, std::size_t actual) + : error(position), m_kind(kind), applicand(std::move(applicand)), expected(expected), actual(actual) { } std::string argument_count_error::what() const { - if (actual > expected) + std::string entity; + + switch (this->m_kind) { - return "Too many arguments, expected " + std::to_string(expected) - + ", got " + std::to_string(actual); + using enum kind; + case trait: + entity = '#' + this->applicand; + break; + case call: + entity = '\'' + this->applicand + '\''; + break; + case array: + entity = "array initializer '" + this->applicand + "'"; + break; } - else - { - return "Too few arguments, expected " + std::to_string(expected) + const std::string noun = this->m_kind == kind::array ? "elements" : "arguments"; + const std::string quantifier = actual > expected ? "many" : "few"; + + return "Too " + quantifier + " " + noun + " for " + entity + + ", expected " + std::to_string(expected) + ", got " + std::to_string(actual); - } } static bool contains_constant_member(const type& checked) @@ -302,8 +315,8 @@ namespace elna::boot condition.accept(this); if (!is_primitive_type(condition.type_decoration, "Bool")) { - add_error(condition.position(), - condition.type_decoration, type_mismatch_error::kind::condition); + add_error(condition.position(), + condition.type_decoration, type_requirement_error::kind::condition); } } @@ -516,7 +529,7 @@ namespace elna::boot if (contains_constant_member(statement->lvalue().type_decoration)) { add_error(statement->position(), statement->lvalue().type_decoration, - type_mismatch_error::kind::constant_assignment); + type_mismatch_error::constant_assignment{}); } else if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration)) { @@ -574,8 +587,8 @@ namespace elna::boot if (!get_range_base_type(resolved_range)) { - add_error(statement->range().position(), - statement->range().type_decoration, type_mismatch_error::kind::for_range); + add_error(statement->range().position(), + statement->range().type_decoration, type_requirement_error::kind::for_range); } this->bag.enter(statement->symbols); for (auto *body_statement : statement->body) @@ -647,7 +660,7 @@ namespace elna::boot if (!check_unresolved_symbol(unresolved_type, alias_path)) { - add_error(alias_path, declaration->position()); + add_error(declaration->position(), alias_path); } else { @@ -662,16 +675,16 @@ namespace elna::boot auto const base_symbol = this->bag.lookup(expression->base.value().name()); if (base_symbol == nullptr || base_symbol->is_type() == nullptr) { - add_error(expression->position(), - type(), type_mismatch_error::kind::record_base); + add_error(expression->position(), + type(), type_requirement_error::kind::record_base); } else { type const base_type = resolve_underlying_type(base_symbol->is_type()->symbol); if (base_type.get() == nullptr) { - add_error(expression->position(), - base_type, type_mismatch_error::kind::record_base); + add_error(expression->position(), + base_type, type_requirement_error::kind::record_base); } } } @@ -703,8 +716,18 @@ namespace elna::boot } if (call->arguments.size() != procedure->parameters.size()) { - add_error(procedure->parameters.size(), - call->arguments.size(), call->position()); + if (auto *procedure_name = call->callable().is_named()) + { + add_error(call->position(), + argument_count_error::kind::call, procedure_name->name, + procedure->parameters.size(), call->arguments.size()); + } + else + { + add_error(call->position(), + argument_count_error::kind::call, call->callable().type_decoration.to_string(), + procedure->parameters.size(), call->arguments.size()); + } } } else if (!call->callable().type_decoration.empty()) @@ -757,8 +780,9 @@ namespace elna::boot } if (expression->elements.size() > array->size) { - add_error(array->size, expression->elements.size(), - expression->position()); + add_error(expression->position(), + argument_count_error::kind::array, expression->type_decoration.to_string(), + array->size, expression->elements.size()); return; } for (auto *element : expression->elements) @@ -778,13 +802,13 @@ namespace elna::boot if (!is_integral_type(resolve_underlying_type(expression->start().type_decoration))) { - add_error(expression->start().position(), - expression->start().type_decoration, type_mismatch_error::kind::array_index); + add_error(expression->start().position(), + expression->start().type_decoration, type_requirement_error::kind::array_index); } if (!is_integral_type(resolve_underlying_type(expression->end().type_decoration))) { - add_error(expression->end().position(), - expression->end().type_decoration, type_mismatch_error::kind::array_index); + add_error(expression->end().position(), + expression->end().type_decoration, type_requirement_error::kind::array_index); } } @@ -796,13 +820,13 @@ namespace elna::boot if (resolved_base.get() == nullptr && resolved_base.get() == nullptr) { - add_error(expression->position(), - expression->base().type_decoration, type_mismatch_error::kind::non_indexable); + add_error(expression->position(), + expression->base().type_decoration, type_requirement_error::kind::non_indexable); } if (!is_integral_type(resolve_underlying_type(expression->index().type_decoration))) { - add_error(expression->index().position(), - expression->index().type_decoration, type_mismatch_error::kind::array_index); + add_error(expression->index().position(), + expression->index().type_decoration, type_requirement_error::kind::array_index); } } @@ -867,9 +891,8 @@ namespace elna::boot if (resolve_underlying_type(expression->base().type_decoration).get() == nullptr) { - add_error(expression->position(), - expression->base().type_decoration, - type_mismatch_error::kind::dereference_of_non_pointer); + add_error(expression->position(), expression->base().type_decoration, + type_requirement_error::kind::dereference_of_non_pointer); } } @@ -994,16 +1017,18 @@ namespace elna::boot { if (trait->arguments.size() != 1) { - add_error(trait->position(), trait->name.name(), - trait_error::argument_count{ .expected = 1, .actual = trait->arguments.size() }); + add_error(trait->position(), + argument_count_error::kind::trait, trait->name.name(), + 1, trait->arguments.size()); } } else if ((trait->name == "min" || trait->name == "max") && !trait->type_decoration.empty()) { if (trait->arguments.size() != 1) { - add_error(trait->position(), trait->name.name(), - trait_error::argument_count{ .expected = 1, .actual = trait->arguments.size() }); + add_error(trait->position(), + argument_count_error::kind::trait, trait->name.name(), + 1, trait->arguments.size()); } else { @@ -1022,8 +1047,9 @@ namespace elna::boot { if (trait->arguments.size() != 2) { - add_error(trait->position(), trait->name.name(), - trait_error::argument_count{ .expected = 2, .actual = trait->arguments.size() }); + add_error(trait->position(), + argument_count_error::kind::trait, trait->name.name(), + 2, trait->arguments.size()); } else if (trait->arguments.at(1)->is_named() == nullptr) { -- cgit v1.2.3