From 5cdaceb77af6a1d98145f8afb34ce6884e21a3d6 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 26 Jul 2026 19:47:59 +0200 Subject: Type check traits properly --- boot/type_check.cc | 68 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 20 deletions(-) (limited to 'boot/type_check.cc') diff --git a/boot/type_check.cc b/boot/type_check.cc index c88a7d1..2bb0ddd 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -22,14 +22,30 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { - non_constant_initializer_error::non_constant_initializer_error(const source_position position) - : error(position) + trait_error::trait_error(const source_position position, const std::string& trait_name, + payload_type payload) + : error(position), trait_name(trait_name), m_payload(payload) { } - std::string non_constant_initializer_error::what() const + std::string trait_error::what() const { - return "Variable initializers must be constant expressions"; + return std::visit([this](auto&& payload) -> std::string + { + 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 + { + return "The second argument to the #" + this->trait_name + " trait must be a field name"; + } + }, this->m_payload); } type_mismatch_error::type_mismatch_error(const source_position position, @@ -453,22 +469,6 @@ namespace elna::boot { return; } - evaluator constant_evaluator(this->bag, this->target, this->evaluated_initializers); - if (!constant_evaluator.evaluate(*declaration->initializer)) - { - add_error(declaration->initializer->position()); - return; - } - // Record const variable initializers so later declarations - // can chain through them. - for (const auto& identifier : declaration->identifiers) - { - if (auto var = this->bag.lookup(identifier.name())->is_variable(); - resolve_aliases(var->symbol).get() != nullptr) - { - this->evaluated_initializers[identifier.name()] = declaration->initializer; - } - } for (const identifier_definition& variable_identifier : declaration->identifiers) { auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable(); @@ -864,4 +864,32 @@ namespace elna::boot expression->lhs().type_decoration, expression->rhs().type_decoration, operation); } } + + void type_analysis_visitor::visit(traits_expression *trait) + { + walking_visitor::visit(trait); + + if (trait->name == "size" || trait->name == "alignment" + || trait->name == "min" || trait->name == "max") + { + if (trait->arguments.size() != 1) + { + add_error(trait->position(), trait->name.name(), + trait_error::argument_count{ .expected = 1, .actual = trait->arguments.size() }); + } + } + else if (trait->name == "offset") + { + if (trait->arguments.size() != 2) + { + add_error(trait->position(), trait->name.name(), + trait_error::argument_count{ .expected = 2, .actual = trait->arguments.size() }); + } + else if (trait->arguments.at(1)->is_named() == nullptr) + { + add_error(trait->arguments.at(1)->position(), trait->name.name(), + trait_error::offset_not_field_name{}); + } + } + } } -- cgit v1.2.3