From f547dae96d770cc7bc27d3790d0d87bb8e37963d Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 7 Oct 2026 10:15:16 +0200 Subject: Make procedure pointers compatible with normal pointers --- boot/name_analysis.cc | 11 +++++++++- boot/symbol.cc | 1 - boot/type_check.cc | 57 +++++++++++++++++++++------------------------------ 3 files changed, 33 insertions(+), 36 deletions(-) (limited to 'boot') diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 1a87927..12a14c3 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -152,6 +152,8 @@ namespace elna::boot return "const must be written before the array size, not after"; case duplicate: return "Duplicate 'const' qualifier is not allowed"; + case constant_procedure: + return "Procedure types are always constant, 'const' is not allowed"; case module_entry: return "Program entry point should have no or one argument"; default: @@ -583,6 +585,11 @@ namespace elna::boot add_error(expression->position(), declaration_format_error::kind::duplicate); } + else if (qualified_base.get() != nullptr) + { + add_error(expression->position(), + declaration_format_error::kind::constant_procedure); + } this->current_type = qualified_base.empty() ? type() : type(std::make_shared(qualified_base)); @@ -807,7 +814,9 @@ namespace elna::boot void resolving_visitor::visit(procedure_call *call) { call->callable().accept(this); - if (const auto procedure = call->callable().type_decoration.get()) + const type callable_type = resolve_underlying_type(call->callable().type_decoration); + + if (const auto procedure = callable_type.get()) { call->type_decoration = procedure->return_type; } diff --git a/boot/symbol.cc b/boot/symbol.cc index 4828070..fa423e0 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -808,7 +808,6 @@ namespace elna::boot bool is_any_pointer_type(const type& checked) { return checked.get() != nullptr - || checked.get() != nullptr || is_primitive_type(checked, "Pointer"); } diff --git a/boot/type_check.cc b/boot/type_check.cc index 82c910f..d8a9170 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -233,6 +233,10 @@ namespace elna::boot std::string type_requirement_error::what() const { + const bool is_procedure = resolve_underlying_type(this->actual).get() != nullptr; + const std::string opaque_subject = (is_procedure ? "Procedure type '" : "Opaque type '") + + this->actual.to_string(); + switch (this->m_kind) { using enum kind; @@ -255,26 +259,19 @@ namespace elna::boot return "Type '" + this->actual.to_string() + "' cannot be dereferenced, it is not a pointer"; case opaque_variable: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used to declare a variable"; + return opaque_subject + "' cannot be used to declare a variable"; case opaque_parameter: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as a procedure parameter"; + return opaque_subject + "' cannot be used as a procedure parameter"; case opaque_return: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as a return type"; + return opaque_subject + "' cannot be used as a return type"; case opaque_field: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as a record field type"; + return opaque_subject + "' cannot be used as a record field type"; case opaque_element: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as an array or slice element type"; + return opaque_subject + "' cannot be used as an array or slice element type"; case opaque_cast: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as a cast target type"; + return opaque_subject + "' cannot be used as a cast target type"; case opaque_arithmetic: - return "Opaque type '" + this->actual.to_string() - + "' cannot be used as an element type in pointer arithmetic"; + return opaque_subject + "' cannot be used as an element type in pointer arithmetic"; case dereference_of_parameter: return "Type parameter '" + this->actual.to_string() + "' cannot be dereferenced, its pointee is unknown"; @@ -342,7 +339,7 @@ namespace elna::boot { const type referent = resolve_aliases(checked); - if (referent.get() != nullptr) + if (referent.get() != nullptr || referent.get() != nullptr) { return true; } @@ -367,7 +364,8 @@ 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, slices and records but not pointers. A procedure is + * opaque too: it has no size and is only reachable through a pointer. * A pointer doesn't store its base type by value, so an opaque behind it * is only reachable as a transient value. A slice does: indexing, slicing * and taking an element's address all scale by the element size. @@ -377,7 +375,8 @@ namespace elna::boot const type underlying = resolve_underlying_type(checked); if (underlying.get() != nullptr - || underlying.get() != nullptr) + || underlying.get() != nullptr + || underlying.get() != nullptr) { return checked; } @@ -402,26 +401,13 @@ namespace elna::boot { return find_opaque_type(slice->base); } - else if (const auto procedure = referent.get()) - { - for (const type& parameter : procedure->parameters) - { - if (const auto opaque = find_opaque_type(parameter)) - { - return opaque; - } - } - return !procedure->return_type.empty() - ? find_opaque_type(procedure->return_type) - : std::nullopt; - } return std::nullopt; } /* * Scaling an offset needs the pointee size, which neither an opaque type * nor a type parameter has. Only a pointer_type scales; the generic - * Pointer and procedure values advance byte-wise. + * Pointer advances byte-wise. */ static std::optional find_arithmetic_violation(binary_operator operation, const type& lhs, const type& rhs) @@ -1403,7 +1389,9 @@ namespace elna::boot { const type resolved = resolve_underlying_type(argument.type_decoration); - if (resolved.get() != nullptr || resolved.get() != nullptr) + if (resolved.get() != nullptr + || resolved.get() != nullptr + || resolved.get() != nullptr) { add_error(argument.position(), argument.type_decoration, type_requirement_error::kind::variadic_argument); @@ -1435,7 +1423,7 @@ namespace elna::boot call->callable().accept(this); this->in_callable_position = false; - type callable_type = call->callable().type_decoration; + type callable_type = resolve_underlying_type(call->callable().type_decoration); std::shared_ptr inferred; if (reference != nullptr && reference->arguments.empty()) @@ -1770,7 +1758,8 @@ namespace elna::boot break; case equals: case not_equals: - valid = is_equality_compatible(lhs_resolved, rhs_resolved); + valid = lhs_resolved.get() == nullptr + && is_equality_compatible(lhs_resolved, rhs_resolved); break; case shift_left: case shift_right: -- cgit v1.2.3