diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-07-21 21:27:03 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-07-21 21:27:03 +0200 |
| commit | 5cc2947143f2a6ebd4ef1ae4d25ab956b87de808 (patch) | |
| tree | 0d4489b298da3be04ed4bce117f616468146a0f8 /boot/type_check.cc | |
| parent | 44d6e8a27294e5ca7300ab11900011b73d9336d4 (diff) | |
| download | elna-5cc2947143f2a6ebd4ef1ae4d25ab956b87de808.tar.gz | |
Diffstat (limited to 'boot/type_check.cc')
| -rw-r--r-- | boot/type_check.cc | 254 |
1 files changed, 171 insertions, 83 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc index 5d0c7a6..7989925 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -56,72 +56,6 @@ namespace elna::boot + "', because it is constant or contains constant members"; } - field_not_found_error::field_not_found_error(const identifier& field_name, - type composite_type) - : error(field_name.position()), field_name(field_name.name()), composite_type(std::move(composite_type)) - { - } - - std::string field_not_found_error::what() const - { - type const resolved = resolve_underlying_type(composite_type); - bool const is_enum = resolved.get<enumeration_type>() != nullptr; - bool const is_record = resolved.get<record_type>() != nullptr; - - if (is_enum || is_record) - { - std::string message = is_enum ? "Enumeration" : "Record"; - - if (auto alias = composite_type.get<alias_type>()) - { - message += " '" + alias->name + "'"; - } - message += " does not have a "; - message += is_enum ? "member" : "field"; - message += " named '" + field_name + "'"; - return message; - } - return "Type '" + composite_type.to_string() - + "' does not have a field named '" + field_name + "'"; - } - - duplicate_member_error::duplicate_member_error(const boot::identifier& member_name, - type aggregate, std::optional<source_position> original, - std::optional<std::string> base_name) - : error(member_name.position()), member_name(member_name.name()), aggregate(std::move(aggregate)), - original(original), base_name(std::move(base_name)) - { - } - - std::string duplicate_member_error::what() const - { - type const resolved = resolve_underlying_type(aggregate); - bool const is_enum = resolved.get<enumeration_type>() != nullptr; - std::string const kind = is_enum ? "member" : "field"; - std::string message = is_enum ? "Enumeration" : "Record"; - - if (auto alias = aggregate.get<alias_type>()) - { - message += " '" + alias->name + "'"; - } - message += " already has a " + kind + " named '" + member_name + "'"; - - if (base_name.has_value()) - { - message += " (defined in base type '" + *base_name + "')"; - } - return message; - } - - std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const - { - if (original.has_value() && original->start().available()) - { - return std::make_pair("previously declared here", *original); - } - return std::nullopt; - } - cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle, const source_position position) : error(position), cycle(cycle) @@ -189,18 +123,6 @@ namespace elna::boot } } - unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait, - type actual) - : error(trait.position()), actual(std::move(actual)), trait_name(trait.name()) - { - } - - std::string unsupported_trait_type_error::what() const - { - return "Type '" + actual.to_string() - + "' does not support trait '#" + trait_name + "'"; - } - unary_operation_error::unary_operation_error(const source_position position, type actual, unary_operator operation) : error(position), actual(std::move(actual)), op(operation) @@ -215,6 +137,8 @@ namespace elna::boot case reference: return '@'; case negation: + case bitwise_negation: + case logical_negation: return '~'; case minus: return '-'; @@ -368,10 +292,36 @@ namespace elna::boot return verdict::pass; } + 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>(); + + 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 can be added to the element type, but not removed. + if (assignee_element_const != nullptr + && assignee_element_const->unqualified == assignment_slice->base) + { + return verdict::accept; + } + if (assignment_element_const != nullptr && assignee_element_const == nullptr) + { + return verdict::reject; + } + return verdict::pass; + } + bool assign_check::run() { for (auto handler : {&assign_check::guard_const_laundering, &assign_check::check_exact_match, + &assign_check::check_slice_conversion, &assign_check::check_pointer_hatch, &assign_check::check_pointer_conversion}) { @@ -534,10 +484,18 @@ namespace elna::boot { if (expression->base.has_value()) { - type const base_type = resolve_underlying_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol); - if (base_type.get<record_type>() == nullptr) + auto const base_symbol = this->bag.lookup(expression->base.value().name()); + if (base_symbol == nullptr || base_symbol->is_type() == nullptr) { - add_error<base_type_error>(base_type, expression->position()); + add_error<base_type_error>(type(), expression->position()); + } + else + { + type const base_type = resolve_underlying_type(base_symbol->is_type()->symbol); + if (base_type.get<record_type>() == nullptr) + { + add_error<base_type_error>(base_type, expression->position()); + } } } walking_visitor::visit(expression); @@ -571,6 +529,12 @@ namespace elna::boot call->arguments.size(), call->position()); } } + else if (!call->callable().type_decoration.empty()) + { + add_error<type_mismatch_error>(call->position(), + type(std::make_shared<procedure_type>()), + call->callable().type_decoration); + } } void type_analysis_visitor::visit(record_constructor_expression *expression) @@ -660,12 +624,136 @@ namespace elna::boot } else if (operation == unary_operator::negation) { - if (!is_primitive_type(resolved, "Bool") - && !is_integral_type(resolved)) + if (is_primitive_type(resolved, "Bool")) + { + expression->operation(unary_operator::logical_negation); + } + else if (is_integral_type(resolved)) + { + expression->operation(unary_operator::bitwise_negation); + } + else { add_error<unary_operation_error>(expression->position(), expression->operand().type_decoration, operation); } } + else if (operation == unary_operator::reference) + { + auto *designator = expression->operand().is_designator(); + if (designator == nullptr || designator->is_slicing() != nullptr) + { + add_error<unary_operation_error>(expression->position(), + expression->operand().type_decoration, operation); + } + } + } + + binary_operation_error::binary_operation_error(const source_position position, + type left, type right, binary_operator operation) + : error(position), left(std::move(left)), right(std::move(right)), op(operation) + { + } + + std::string binary_operation_error::what() const + { + return "Invalid operands of type '" + left.to_string() + + "' and '" + right.to_string() + + "' for operator " + print_binary_operator(op); + } + + void type_analysis_visitor::visit(binary_expression *expression) + { + walking_visitor::visit(expression); + + auto 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; + + switch (operation) + { + using enum binary_operator; + case sum: + valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved)) + || (is_integral_type(lhs_resolved) && is_any_pointer_type(rhs_resolved)) + || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved); + break; + case subtraction: + valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved)) + || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved)) + || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved); + break; + case division: + case remainder: + case multiplication: + valid = is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved; + break; + case less: + case greater: + case less_equal: + case greater_equal: + valid = (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved) + || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved)); + break; + case conjunction: + case disjunction: + case exclusive_disjunction: + if (is_primitive_type(lhs_resolved, "Bool") && lhs_resolved == rhs_resolved) + { + switch (operation) + { + case conjunction: + expression->operation(logical_conjunction); + break; + case disjunction: + expression->operation(logical_disjunction); + break; + case exclusive_disjunction: + expression->operation(logical_exclusive_disjunction); + break; + default: + break; + } + valid = true; + } + else if (is_integral_type(lhs_resolved) && lhs_resolved == rhs_resolved) + { + switch (operation) + { + case conjunction: + expression->operation(bitwise_conjunction); + break; + case disjunction: + expression->operation(bitwise_disjunction); + break; + case exclusive_disjunction: + expression->operation(bitwise_exclusive_disjunction); + break; + default: + break; + } + valid = true; + } + break; + case equals: + case not_equals: + valid = lhs_resolved == rhs_resolved + || (is_primitive_type(lhs_resolved, "Pointer") && is_any_pointer_type(rhs_resolved)) + || (is_any_pointer_type(lhs_resolved) && is_primitive_type(rhs_resolved, "Pointer")) + || (lhs_resolved.get<slice_type>() && rhs_resolved.get<slice_type>()) + || (lhs_resolved.get<record_type>() && rhs_resolved.get<record_type>()); + break; + case shift_left: + case shift_right: + valid = is_integral_type(lhs_resolved) + && is_primitive_type(rhs_resolved, "Word"); + break; + } + if (!valid) + { + add_error<binary_operation_error>(expression->position(), + expression->lhs().type_decoration, expression->rhs().type_decoration, operation); + } } } |
