diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-30 02:08:45 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-30 02:08:45 +0200 |
| commit | 491e62664394a8689a3f8904fbe8dbc3dea05524 (patch) | |
| tree | 7142cf8d94fc6f9cf953d42d9c136b77f65d8034 /boot/type_check.cc | |
| parent | 08d9c4292ebba3e320c1dbaca4fa06c83f6fc7fb (diff) | |
| download | elna-491e62664394a8689a3f8904fbe8dbc3dea05524.tar.gz | |
Fix ICEs with recursive type declarations
Diffstat (limited to 'boot/type_check.cc')
| -rw-r--r-- | boot/type_check.cc | 141 |
1 files changed, 47 insertions, 94 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc index ad27337..8f7a30f 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -18,7 +18,6 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/type_check.h" #include "elna/boot/evaluator.h" -#include <algorithm> #include <utility> namespace elna::boot @@ -222,25 +221,6 @@ namespace elna::boot } } - cyclic_declaration_error::cyclic_declaration_error(const source_position position, - const std::vector<std::string>& cycle) - : diagnostic(position), cycle(cycle) - { - } - - std::string cyclic_declaration_error::what() const - { - auto segment = std::cbegin(this->cycle); - std::string message = "Type declaration forms a cycle: " + *segment; - - ++segment; - for (; segment != std::cend(this->cycle); ++segment) - { - message += " -> " + *segment; - } - return message; - } - argument_count_error::argument_count_error(const source_position position, kind kind, std::string applicand, std::size_t expected, std::size_t actual) : diagnostic(position), m_kind(kind), applicand(std::move(applicand)), expected(expected), actual(actual) @@ -301,7 +281,9 @@ namespace elna::boot /* * Finds the first opaque type in a value position, following aliases, - * qualifiers, arrays, slices, records and procedures but not pointers. + * qualifiers, arrays, records and procedures but not pointers or slices. + * Pointers and slices don't store their base type by value, so an opaque + * behind them is only reachable as a transient value. */ static std::optional<type> find_opaque_type(const type& checked) { @@ -326,10 +308,6 @@ namespace elna::boot { return find_opaque_type(array->base); } - else if (auto slice = referent.get<slice_type>()) - { - return find_opaque_type(slice->base); - } else if (auto procedure = referent.get<procedure_type>()) { for (const type& parameter : procedure->parameters) @@ -387,22 +365,6 @@ namespace elna::boot || (resolved_left.get<record_type>() && resolved_right.get<record_type>()); } - bool type_analysis_visitor::check_unresolved_symbol(const std::shared_ptr<alias_type>& alias, - std::vector<std::string>& alias_path) - { - if (std::ranges::find(alias_path, alias->name) != std::cend(alias_path)) - { - return false; - } - alias_path.push_back(alias->name); - - if (auto another_alias = alias->referent.get<alias_type>()) - { - return check_unresolved_symbol(another_alias, alias_path); - } - return true; - } - void type_analysis_visitor::visit_and_validate_condition(expression& condition) { condition.accept(this); @@ -797,78 +759,69 @@ namespace elna::boot void type_analysis_visitor::visit(type_declaration *declaration) { - std::vector<std::string> alias_path; + walking_visitor::visit(declaration); auto unresolved_type = this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>(); + const type referent = resolve_aliases(unresolved_type->referent); - if (!check_unresolved_symbol(unresolved_type, alias_path)) - { - add_error<cyclic_declaration_error>(declaration->position(), alias_path); - } - else + if (auto record = referent.get<record_type>()) { - walking_visitor::visit(declaration); - const type referent = resolve_aliases(unresolved_type->referent); - - if (auto record = referent.get<record_type>()) + for (const auto& [field_name, field_type] : record->fields) { - for (const auto& [field_name, field_type] : record->fields) + if (auto opaque = find_opaque_type(field_type)) { - if (auto opaque = find_opaque_type(field_type)) - { - add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_field); - } - else if (has_zero_size(field_type, this->target)) - { - add_error<type_requirement_error>(declaration->position(), - field_type, type_requirement_error::kind::zero_sized); - } + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_field); } - } - else if (auto array = referent.get<array_type>()) - { - if (auto opaque = find_opaque_type(array->base)) + else if (has_zero_size(field_type, this->target)) { add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_element); + field_type, type_requirement_error::kind::zero_sized); } } - else if (auto slice = referent.get<slice_type>()) + } + else if (auto array = referent.get<array_type>()) + { + if (auto opaque = find_opaque_type(array->base)) + { + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_element); + } + } + else if (auto slice = referent.get<slice_type>()) + { + if (auto opaque = find_opaque_type(slice->base)) { - if (auto opaque = find_opaque_type(slice->base)) + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_element); + } + } + else if (auto procedure = referent.get<procedure_type>()) + { + for (const type& parameter : procedure->parameters) + { + if (auto opaque = find_opaque_type(parameter)) + { + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_parameter); + } + else if (has_zero_size(parameter, this->target)) { add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_element); + parameter, type_requirement_error::kind::zero_sized); } } - else if (auto procedure = referent.get<procedure_type>()) + if (!procedure->return_type.proper_type.empty()) { - for (const type& parameter : procedure->parameters) + if (auto opaque = find_opaque_type(procedure->return_type.proper_type)) { - if (auto opaque = find_opaque_type(parameter)) - { - add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_parameter); - } - else if (has_zero_size(parameter, this->target)) - { - add_error<type_requirement_error>(declaration->position(), - parameter, type_requirement_error::kind::zero_sized); - } + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_return); } - if (!procedure->return_type.proper_type.empty()) + else if (has_zero_size(procedure->return_type.proper_type, this->target)) { - if (auto opaque = find_opaque_type(procedure->return_type.proper_type)) - { - add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_return); - } - else if (has_zero_size(procedure->return_type.proper_type, this->target)) - { - add_error<type_requirement_error>(declaration->position(), - procedure->return_type.proper_type, - type_requirement_error::kind::zero_sized); - } + add_error<type_requirement_error>(declaration->position(), + procedure->return_type.proper_type, + type_requirement_error::kind::zero_sized); } } } |
