diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-09-24 00:39:51 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-09-24 00:39:51 +0200 |
| commit | f7b035a505e86ad916a43ab1dc1a662a6066b011 (patch) | |
| tree | a54369ae8ad56352d148c4583ab568f7d4869d30 /boot/type_check.cc | |
| parent | 74e75e41fe12f19e5365a3152ffafa1a29376240 (diff) | |
| download | elna-f7b035a505e86ad916a43ab1dc1a662a6066b011.tar.gz | |
Move module heading to the top
Diffstat (limited to 'boot/type_check.cc')
| -rw-r--r-- | boot/type_check.cc | 197 |
1 files changed, 100 insertions, 97 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc index 5d5bc59..7be236d 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -44,7 +44,7 @@ namespace elna::boot __builtin_unreachable(); } - static std::string print_binary_operator(const binary_operator operation) + static std::string_view print_binary_operator(const binary_operator operation) { switch (operation) { @@ -215,7 +215,7 @@ namespace elna::boot { return "Invalid operands of type '" + this->actual.to_string() + "' and '" + payload.right.to_string() - + "' for operator " + print_binary_operator(payload.operation); + + "' for operator " + std::string(print_binary_operator(payload.operation)); } else if constexpr (std::is_same_v<T, invalid_cast>) { @@ -345,13 +345,13 @@ namespace elna::boot static bool contains_constant_member(const type& checked) { - auto referent = resolve_aliases(checked); + const type referent = resolve_aliases(checked); if (referent.get<constant_type>() != nullptr) { return true; } - else if (auto record = referent.get<record_type>()) + else if (const auto record = referent.get<record_type>()) { for (const auto& [field_name, field] : record->fields) { @@ -363,7 +363,7 @@ namespace elna::boot return !record->base.empty() && contains_constant_member(resolve_underlying_type(record->base)); } - else if (auto array = referent.get<array_type>()) + else if (const auto array = referent.get<array_type>()) { return contains_constant_member(array->base); } @@ -385,30 +385,30 @@ namespace elna::boot } const type referent = resolve_aliases(checked); - if (auto record = referent.get<record_type>()) + if (const auto record = referent.get<record_type>()) { for (const auto& [field_name, field] : record->fields) { - if (auto opaque = find_opaque_type(field.field_type)) + if (const auto opaque = find_opaque_type(field.field_type)) { return opaque; } } return !record->base.empty() ? find_opaque_type(record->base) : std::nullopt; } - else if (auto array = referent.get<array_type>()) + else if (const auto array = referent.get<array_type>()) { return find_opaque_type(array->base); } - else if (auto slice = referent.get<slice_type>()) + else if (const auto slice = referent.get<slice_type>()) { return find_opaque_type(slice->base); } - else if (auto procedure = referent.get<procedure_type>()) + else if (const auto procedure = referent.get<procedure_type>()) { for (const type& parameter : procedure->parameters) { - if (auto opaque = find_opaque_type(parameter)) + if (const auto opaque = find_opaque_type(parameter)) { return opaque; } @@ -446,7 +446,7 @@ namespace elna::boot { return std::nullopt; } - if (auto pointer = (lhs_integral ? rhs : lhs).get<pointer_type>()) + if (const auto pointer = (lhs_integral ? rhs : lhs).get<pointer_type>()) { return find_opaque_type(pointer->base); } @@ -456,7 +456,8 @@ namespace elna::boot // Checks whether the type has zero size. static bool has_zero_size(const type& checked, const target_info& target) { - auto properties = get_type_properties(resolve_underlying_type(checked), target); + const std::optional<type_properties> properties = + get_type_properties(resolve_underlying_type(checked), target); return properties.has_value() && properties->size == 0; } @@ -469,7 +470,7 @@ namespace elna::boot { return checked; } - if (auto record = resolve_aliases(checked).get<record_type>()) + if (const auto record = resolve_aliases(checked).get<record_type>()) { for (const auto& [field_name, field] : record->fields) { @@ -520,23 +521,18 @@ namespace elna::boot } } - /* - * Checks whether derived has base in its record parent chain. - * - * Base record type must not be null. Derived record type may be null. - */ assign_check::verdict assign_check::guard_const_laundering() const { if (!is_primitive_type(ctx.aliased_assignee, "Pointer")) { return verdict::pass; } - if (auto ptr = ctx.aliased_assignment.get<pointer_type>(); + if (const auto ptr = ctx.aliased_assignment.get<pointer_type>(); ptr != nullptr && resolve_aliases(ptr->base).get<constant_type>() != nullptr) { return verdict::reject; } - if (auto const_assign = ctx.aliased_assignment.get<constant_type>(); + if (const auto const_assign = ctx.aliased_assignment.get<constant_type>(); const_assign != nullptr && is_primitive_type(const_assign->unqualified, "Pointer")) { return verdict::reject; @@ -566,15 +562,16 @@ namespace elna::boot assign_check::verdict assign_check::check_pointer_conversion() const { - auto assignee_ptr = ctx.resolved_assignee.get<pointer_type>(); - auto assignment_ptr = ctx.resolved_assignment.get<pointer_type>(); + const std::shared_ptr<pointer_type> assignee_ptr = ctx.resolved_assignee.get<pointer_type>(); + const std::shared_ptr<pointer_type> assignment_ptr = ctx.resolved_assignment.get<pointer_type>(); if (assignee_ptr == nullptr || assignment_ptr == nullptr) { return verdict::pass; } - auto assignee_pointee_const = resolve_aliases(assignee_ptr->base).get<constant_type>(); - auto assignment_pointee_const = resolve_aliases(assignment_ptr->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignee_pointee_const = + resolve_aliases(assignee_ptr->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignment_pointee_const = resolve_aliases(assignment_ptr->base).get<constant_type>(); // Constness can be added at the first indirection level, but not removed. if (assignee_pointee_const != nullptr @@ -599,15 +596,17 @@ namespace elna::boot assign_check::verdict assign_check::check_slice_conversion() const { - auto assignee_slice = ctx.resolved_assignee.get<slice_type>(); - auto assignment_slice = ctx.resolved_assignment.get<slice_type>(); + const std::shared_ptr<slice_type> assignee_slice = ctx.resolved_assignee.get<slice_type>(); + const std::shared_ptr<slice_type> assignment_slice = ctx.resolved_assignment.get<slice_type>(); if (assignee_slice == nullptr || assignment_slice == nullptr) { return verdict::pass; } - auto assignee_element_const = resolve_aliases(assignee_slice->base).get<constant_type>(); - auto assignment_element_const = resolve_aliases(assignment_slice->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignee_element_const = + resolve_aliases(assignee_slice->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignment_element_const = + resolve_aliases(assignment_slice->base).get<constant_type>(); // Const can be added to the element type, but not removed. if (assignee_element_const != nullptr @@ -624,16 +623,18 @@ namespace elna::boot assign_check::verdict assign_check::check_array_conversion() const { - auto assignee_array = ctx.resolved_assignee.get<array_type>(); - auto assignment_array = ctx.resolved_assignment.get<array_type>(); + const std::shared_ptr<array_type> assignee_array = ctx.resolved_assignee.get<array_type>(); + const std::shared_ptr<array_type> assignment_array = ctx.resolved_assignment.get<array_type>(); if (assignee_array == nullptr || assignment_array == nullptr || assignee_array->size != assignment_array->size) { return verdict::pass; } - auto assignee_element_const = resolve_aliases(assignee_array->base).get<constant_type>(); - auto assignment_element_const = resolve_aliases(assignment_array->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignee_element_const = + resolve_aliases(assignee_array->base).get<constant_type>(); + const std::shared_ptr<constant_type> assignment_element_const = + resolve_aliases(assignment_array->base).get<constant_type>(); // An array is copied by value, so const can be added to the element type, // but not removed. Writing to such an array is rejected on the lvalue. @@ -651,7 +652,7 @@ namespace elna::boot bool assign_check::run() { - auto const assign_handlers = { + const std::initializer_list assign_handlers = { &assign_check::guard_const_laundering, &assign_check::check_exact_match, &assign_check::check_slice_conversion, @@ -659,7 +660,7 @@ namespace elna::boot &assign_check::check_pointer_hatch, &assign_check::check_pointer_conversion }; - for (auto handler : assign_handlers) + for (const auto handler : assign_handlers) { switch ((this->*handler)()) { @@ -804,7 +805,6 @@ namespace elna::boot this->current_procedure = this->bag.lookup("")->is_procedure(); this->bag.enter(this->current_procedure->scope); walking_visitor::visit_entry_point(unit); - check_return(unit->entry_point.value(), unit->entry_position.value(), ""); this->bag.leave(); this->current_procedure.reset(); } @@ -815,14 +815,15 @@ namespace elna::boot for (const auto& variable_identifier : declaration->identifiers) { - auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable(); + const std::shared_ptr<variable_info> variable_symbol = + this->bag.lookup(variable_identifier.name())->is_variable(); - if (auto opaque = find_opaque_type(variable_symbol->symbol)) + if (const auto opaque = find_opaque_type(variable_symbol->symbol)) { add_error<type_requirement_error>(variable_identifier.id().position(), opaque.value(), type_requirement_error::kind::opaque_variable); } - else if (auto found = find_zero_sized(variable_symbol->symbol, this->target)) + else if (const auto found = find_zero_sized(variable_symbol->symbol, this->target)) { add_error<type_requirement_error>(variable_identifier.id().position(), found.value(), type_requirement_error::kind::zero_sized); @@ -834,7 +835,9 @@ namespace elna::boot } for (const auto& variable_identifier : declaration->identifiers) { - auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable(); + const std::shared_ptr<variable_info> variable_symbol = + this->bag.lookup(variable_identifier.name())->is_variable(); + if (!is_assignable_from(variable_symbol->symbol, declaration->initializer->type_decoration)) { add_error<type_mismatch_error>(declaration->initializer->position(), @@ -869,7 +872,7 @@ namespace elna::boot void type_analysis_visitor::visit(for_statement *statement) { statement->range().accept(this); - auto resolved_range = resolve_underlying_type(statement->range().type_decoration); + const type resolved_range = resolve_underlying_type(statement->range().type_decoration); if (!get_range_base_type(resolved_range)) { @@ -923,9 +926,10 @@ namespace elna::boot void type_analysis_visitor::visit(type_declaration *declaration) { walking_visitor::visit(declaration); - auto unresolved_type = this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>(); + const std::shared_ptr<alias_type> unresolved_type = + this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>(); - if (auto generic = unresolved_type->referent.get<generic_type>()) + if (const auto generic = unresolved_type->referent.get<generic_type>()) { check_parameters_used(declaration->position(), declaration->identifier.name(), generic->parameters, generic->referent); @@ -933,11 +937,11 @@ namespace elna::boot } const type referent = resolve_aliases(unresolved_type->referent); - if (auto record = referent.get<record_type>()) + if (const auto record = referent.get<record_type>()) { for (const auto& [field_name, field] : record->fields) { - if (auto opaque = find_opaque_type(field.field_type)) + if (const auto opaque = find_opaque_type(field.field_type)) { add_error<type_requirement_error>(declaration->position(), opaque.value(), type_requirement_error::kind::opaque_field); @@ -949,27 +953,27 @@ namespace elna::boot } } } - else if (auto array = referent.get<array_type>()) + else if (const auto array = referent.get<array_type>()) { - if (auto opaque = find_opaque_type(array->base)) + if (const 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>()) + else if (const auto slice = referent.get<slice_type>()) { - if (auto opaque = find_opaque_type(slice->base)) + if (const 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>()) + else if (const auto procedure = referent.get<procedure_type>()) { for (const type& parameter : procedure->parameters) { - if (auto opaque = find_opaque_type(parameter)) + if (const auto opaque = find_opaque_type(parameter)) { add_error<type_requirement_error>(declaration->position(), opaque.value(), type_requirement_error::kind::opaque_parameter); @@ -982,7 +986,7 @@ namespace elna::boot } if (!procedure->return_type.proper_type.empty()) { - if (auto opaque = find_opaque_type(procedure->return_type.proper_type)) + if (const 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); @@ -1001,7 +1005,8 @@ namespace elna::boot { if (expression->base.has_value()) { - auto const base_symbol = this->bag.lookup(expression->base.value().name()); + const std::shared_ptr<info> base_symbol = this->bag.lookup(expression->base.value().name()); + if (base_symbol == nullptr || base_symbol->is_type() == nullptr) { add_error<type_requirement_error>(expression->position(), @@ -1009,7 +1014,7 @@ namespace elna::boot } else { - type const base_type = erase_generic(base_symbol->is_type()->symbol); + const type base_type = erase_generic(base_symbol->is_type()->symbol); if (base_type.get<record_type>() == nullptr) { add_error<type_requirement_error>(expression->position(), @@ -1032,23 +1037,23 @@ namespace elna::boot { return true; } - if (auto pointer = subject.get<pointer_type>()) + else if (const auto pointer = subject.get<pointer_type>()) { return occurs_in(parameter, pointer->base); } - if (auto slice = subject.get<slice_type>()) + else if (const auto slice = subject.get<slice_type>()) { return occurs_in(parameter, slice->base); } - if (auto array = subject.get<array_type>()) + else if (const auto array = subject.get<array_type>()) { return occurs_in(parameter, array->base); } - if (auto qualified = subject.get<constant_type>()) + else if (const auto qualified = subject.get<constant_type>()) { return occurs_in(parameter, qualified->unqualified); } - if (auto record = subject.get<record_type>()) + else if (const auto record = subject.get<record_type>()) { for (const auto& [field_name, field] : record->fields) { @@ -1059,7 +1064,7 @@ namespace elna::boot } return !record->base.empty() && occurs_in(parameter, record->base); } - if (auto procedure = subject.get<procedure_type>()) + else if (const auto procedure = subject.get<procedure_type>()) { for (const type& parameter_type : procedure->parameters) { @@ -1071,7 +1076,7 @@ namespace elna::boot return !procedure->return_type.proper_type.empty() && occurs_in(parameter, procedure->return_type.proper_type); } - if (auto instance = subject.get<instantiated_type>()) + else if (const auto instance = subject.get<instantiated_type>()) { for (const type& argument : instance->arguments) { @@ -1112,7 +1117,7 @@ namespace elna::boot const type left = resolve_aliases(declared); const type right = resolve_aliases(actual); - if (auto parameter = left.get<parameter_type>()) + if (const auto parameter = left.get<parameter_type>()) { for (std::size_t i = 0; i < parameters.size(); ++i) { @@ -1125,40 +1130,40 @@ namespace elna::boot } return true; } - if (auto left_pointer = left.get<pointer_type>()) + else if (const auto left_pointer = left.get<pointer_type>()) { - auto right_pointer = right.get<pointer_type>(); + const std::shared_ptr<pointer_type> right_pointer = right.get<pointer_type>(); return right_pointer != nullptr && bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base); } - if (auto left_slice = left.get<slice_type>()) + else if (const auto left_slice = left.get<slice_type>()) { - auto right_slice = right.get<slice_type>(); + const std::shared_ptr<slice_type> right_slice = right.get<slice_type>(); return right_slice != nullptr && bind_arguments(parameters, bindings, left_slice->base, right_slice->base); } - if (auto left_array = left.get<array_type>()) + else if (const auto left_array = left.get<array_type>()) { - auto right_array = right.get<array_type>(); + const std::shared_ptr<array_type> right_array = right.get<array_type>(); return right_array != nullptr && bind_arguments(parameters, bindings, left_array->base, right_array->base); } - if (auto left_constant = left.get<constant_type>()) + else if (const auto left_constant = left.get<constant_type>()) { - auto right_constant = right.get<constant_type>(); + const std::shared_ptr<constant_type> right_constant = right.get<constant_type>(); return right_constant != nullptr - && bind_arguments(parameters, bindings, - left_constant->unqualified, right_constant->unqualified); + && bind_arguments(parameters, bindings, left_constant->unqualified, right_constant->unqualified); } - if (auto left_instance = left.get<instantiated_type>()) + else if (const auto left_instance = left.get<instantiated_type>()) { for (type candidate = right; !candidate.empty(); candidate = base_of(candidate)) { - auto right_instance = resolve_aliases(candidate).get<instantiated_type>(); + const std::shared_ptr<instantiated_type> right_instance = + resolve_aliases(candidate).get<instantiated_type>(); if (right_instance == nullptr || !(left_instance->generic == right_instance->generic) @@ -1178,9 +1183,9 @@ namespace elna::boot } return false; } - if (auto left_procedure = left.get<procedure_type>()) + else if (const auto left_procedure = left.get<procedure_type>()) { - auto right_procedure = right.get<procedure_type>(); + const std::shared_ptr<procedure_type> right_procedure = right.get<procedure_type>(); if (right_procedure == nullptr || left_procedure->parameters.size() != right_procedure->parameters.size()) @@ -1281,7 +1286,7 @@ namespace elna::boot } const type denoted = expression->type_decoration; - if (auto instance = denoted.get<instantiated_type>()) + if (const auto instance = denoted.get<instantiated_type>()) { std::shared_ptr<generic_type> const generic = unwrap_generic(instance->generic); @@ -1404,7 +1409,7 @@ namespace elna::boot { // Inference reads the argument types, so they are decorated // before the parameter types they will be checked against exist. - for (expression *argument : call->arguments) + for (expression *const argument : call->arguments) { argument->accept(this); } @@ -1414,13 +1419,13 @@ namespace elna::boot // Name analysis decorated the call with the declared return // type, which still mentions the parameters inference has // just bound. - if (auto substituted = callable_type.get<procedure_type>()) + if (const auto substituted = callable_type.get<procedure_type>()) { call->type_decoration = substituted->return_type.proper_type; } } } - if (auto procedure = callable_type.get<procedure_type>()) + if (const auto procedure = callable_type.get<procedure_type>()) { std::vector<expression *>::const_iterator argument_iterator = std::cbegin(call->arguments); std::vector<type>::const_iterator type_iterator = std::cbegin(procedure->parameters); @@ -1455,7 +1460,7 @@ namespace elna::boot if (call->arguments.size() < procedure->parameters.size() || (!procedure->variadic && call->arguments.size() > procedure->parameters.size())) { - if (auto *procedure_name = call->callable().is_named()) + if (const auto *procedure_name = call->callable().is_named()) { add_error<argument_count_error>(call->position(), argument_count_error::kind::call, procedure_name->name, @@ -1480,7 +1485,7 @@ namespace elna::boot void type_analysis_visitor::visit(record_constructor_expression *expression) { - auto record = erase_generic(expression->type_decoration).get<record_type>(); + const std::shared_ptr<record_type> record = erase_generic(expression->type_decoration).get<record_type>(); if (record == nullptr) { @@ -1507,7 +1512,8 @@ namespace elna::boot void type_analysis_visitor::visit(array_constructor_expression *expression) { - auto array = resolve_underlying_type(expression->type_decoration).get<array_type>(); + const std::shared_ptr<array_type> array = + resolve_underlying_type(expression->type_decoration).get<array_type>(); if (array == nullptr) { @@ -1518,7 +1524,7 @@ namespace elna::boot } // The first element of the array literal determines the array type and // does not have to be checked. - for (auto *element : expression->elements | std::views::drop(1)) + for (const auto *element : expression->elements | std::views::drop(1)) { if (!is_assignable_from(array->base, element->type_decoration)) { @@ -1548,7 +1554,7 @@ namespace elna::boot { walking_visitor::visit(expression); - auto resolved_base = resolve_underlying_type(expression->base().type_decoration); + const type resolved_base = resolve_underlying_type(expression->base().type_decoration); if (resolved_base.get<array_type>() == nullptr && resolved_base.get<slice_type>() == nullptr) { @@ -1566,7 +1572,7 @@ namespace elna::boot { walking_visitor::visit(expression); - auto operation = expression->operation(); + const unary_operator operation = expression->operation(); type const resolved = resolve_underlying_type(expression->operand().type_decoration); if (operation == unary_operator::plus || operation == unary_operator::minus) @@ -1595,14 +1601,11 @@ namespace elna::boot type_mismatch_error::unary{ .operation = operation }); } } - else if (operation == unary_operator::reference) + else if (operation == unary_operator::reference && !is_addressable(expression->operand())) { - if (!is_addressable(expression->operand())) - { - add_error<type_requirement_error>(expression->position(), - expression->operand().type_decoration, - type_requirement_error::kind::not_addressable); - } + add_error<type_requirement_error>(expression->position(), + expression->operand().type_decoration, + type_requirement_error::kind::not_addressable); } } @@ -1634,8 +1637,8 @@ namespace elna::boot opaque.value(), type_requirement_error::kind::opaque_cast); return; } - auto source = resolve_underlying_type(expression->value().type_decoration); - auto target = resolve_underlying_type(expression->type_decoration); + const type source = resolve_underlying_type(expression->value().type_decoration); + const type target = resolve_underlying_type(expression->type_decoration); if (source != target // const cast. && (!is_scalar_type(source) || !is_scalar_type(target)) @@ -1651,7 +1654,7 @@ namespace elna::boot { walking_visitor::visit(expression); - auto operation = expression->operation(); + const binary_operator operation = expression->operation(); type const lhs_resolved = resolve_underlying_type(expression->lhs().type_decoration); type const rhs_resolved = resolve_underlying_type(expression->rhs().type_decoration); bool valid = false; @@ -1804,7 +1807,7 @@ namespace elna::boot add_error<trait_error>(trait->name.position(), trait->name.name(), trait_error::unsupported_type{ trait->types.front() }); } - else if (auto *field = trait->arguments.at(1)->is_named()) + else if (const auto *field = trait->arguments.at(1)->is_named()) { if (erase_generic(trait->types.front()).get<record_type>() == nullptr) { |
