aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-10-03 20:51:22 +0200
committerEugen Wissner <belka@caraus.de>2026-10-03 20:51:22 +0200
commite4ce7f658741a7428597da4872435a1b0bae944c (patch)
tree50f65abf6fa4468db7bc93a6ae61d623a2dd8566 /boot
parent5d808dd4c4003968bbdf180e1e1193231db5d43b (diff)
downloadelna-e4ce7f658741a7428597da4872435a1b0bae944c.tar.gz
Rework generics for parameters to be plain types
Diffstat (limited to 'boot')
-rw-r--r--boot/symbol.cc1
-rw-r--r--boot/type_check.cc102
2 files changed, 70 insertions, 33 deletions
diff --git a/boot/symbol.cc b/boot/symbol.cc
index e247bdb..4828070 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -809,7 +809,6 @@ namespace elna::boot
{
return checked.get<pointer_type>() != nullptr
|| checked.get<procedure_type>() != nullptr
- || checked.get<parameter_type>() != nullptr
|| is_primitive_type(checked, "Pointer");
}
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 42e7227..82c910f 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -137,11 +137,6 @@ namespace elna::boot
return "Type parameter '" + payload.parameter + "' of '"
+ this->generic_name + "' is not used";
}
- else if constexpr (std::is_same_v<T, argument_not_pointer>)
- {
- return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '"
- + this->generic_name + "', it is not a pointer type";
- }
else if constexpr (std::is_same_v<T, argument_not_scalar>)
{
return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '"
@@ -379,7 +374,10 @@ namespace elna::boot
*/
static std::optional<type> find_opaque_type(const type& checked)
{
- if (resolve_underlying_type(checked).get<extern_type>() != nullptr)
+ const type underlying = resolve_underlying_type(checked);
+
+ if (underlying.get<extern_type>() != nullptr
+ || underlying.get<parameter_type>() != nullptr)
{
return checked;
}
@@ -935,27 +933,59 @@ namespace elna::boot
const std::shared_ptr<alias_type> unresolved_type =
this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>();
- if (const auto generic = unresolved_type->referent.get<generic_type>())
+ type referent = unresolved_type->referent;
+ if (const auto generic = referent.get<generic_type>())
{
check_parameters_used(declaration->position(), declaration->identifier.name(),
generic->parameters, generic->referent);
- return;
+ referent = generic->referent;
}
- const type referent = resolve_aliases(unresolved_type->referent);
+ referent = resolve_aliases(referent);
if (const auto record = referent.get<record_type>())
{
- for (const auto& [field_name, field] : record->fields)
+ const record_type_expression *record_expression = declaration->underlying_type().is_record();
+
+ if (record_expression != nullptr)
{
- if (const auto opaque = find_opaque_type(field.field_type))
+ for (const field_declaration& field : record_expression->fields)
{
- add_error<type_requirement_error>(declaration->position(),
- opaque.value(), type_requirement_error::kind::opaque_field);
+ if (field.first.empty())
+ {
+ continue;
+ }
+ const auto field_entry = record->fields.find(field.first.front().name());
+
+ if (field_entry == record->fields.end())
+ {
+ continue;
+ }
+ if (const auto opaque = find_opaque_type(field_entry->second.field_type))
+ {
+ add_error<type_requirement_error>(field.second->position(),
+ opaque.value(), type_requirement_error::kind::opaque_field);
+ }
+ else if (has_zero_size(field_entry->second.field_type, this->target))
+ {
+ add_error<type_requirement_error>(field.second->position(),
+ field_entry->second.field_type, type_requirement_error::kind::zero_sized);
+ }
}
- else if (has_zero_size(field.field_type, this->target))
+ }
+ else
+ {
+ for (const auto& [field_name, field] : record->fields)
{
- add_error<type_requirement_error>(declaration->position(),
- field.field_type, type_requirement_error::kind::zero_sized);
+ 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);
+ }
+ else if (has_zero_size(field.field_type, this->target))
+ {
+ add_error<type_requirement_error>(declaration->position(),
+ field.field_type, type_requirement_error::kind::zero_sized);
+ }
}
}
}
@@ -1137,10 +1167,17 @@ namespace elna::boot
}
else if (const auto left_pointer = left.get<pointer_type>())
{
- const std::shared_ptr<pointer_type> right_pointer = right.get<pointer_type>();
+ if (is_primitive_type(right, "Pointer"))
+ {
+ return true;
+ }
+ else
+ {
+ 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);
+ return right_pointer != nullptr
+ && bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base);
+ }
}
else if (const auto left_slice = left.get<slice_type>())
{
@@ -1227,7 +1264,7 @@ namespace elna::boot
{
return argument_rule::mutable_scalar;
}
- return argument_rule::pointer;
+ return argument_rule::opaque;
}
void type_analysis_visitor::check_arguments(const named_expression& reference,
@@ -1241,18 +1278,13 @@ namespace elna::boot
}
const type underlying = resolve_underlying_type(argument);
- if (rule != argument_rule::scalar
+ if (rule == argument_rule::mutable_scalar
&& resolve_aliases(argument).get<constant_type>() != nullptr)
{
add_error<generic_error>(reference.position(), reference.name,
generic_error::constant_argument{ argument });
}
- else if (rule == argument_rule::pointer && !is_any_pointer_type(underlying))
- {
- add_error<generic_error>(reference.position(), reference.name,
- generic_error::argument_not_pointer{ argument });
- }
- else if (rule != argument_rule::pointer && !is_scalar_type(underlying))
+ else if (rule != argument_rule::opaque && !is_scalar_type(underlying))
{
add_error<generic_error>(reference.position(), reference.name,
generic_error::argument_not_scalar{ argument });
@@ -1308,7 +1340,7 @@ namespace elna::boot
}
else
{
- check_arguments(*expression, expression->argument_types, argument_rule::pointer);
+ check_arguments(*expression, expression->argument_types, argument_rule::opaque);
}
}
else if (std::shared_ptr<generic_type> const generic = unwrap_generic(denoted))
@@ -1619,12 +1651,18 @@ namespace elna::boot
const type resolved_base = resolve_underlying_type(expression->base().type_decoration);
- if (resolved_base.get<parameter_type>() != nullptr)
+ if (const auto pointer = resolved_base.get<pointer_type>())
{
- add_error<type_requirement_error>(expression->position(), expression->base().type_decoration,
- type_requirement_error::kind::dereference_of_parameter);
+ if (const auto opaque = find_opaque_type(pointer->base))
+ {
+ if (opaque->get<parameter_type>() != nullptr)
+ {
+ add_error<type_requirement_error>(expression->position(), *opaque,
+ type_requirement_error::kind::dereference_of_parameter);
+ }
+ }
}
- else if (resolved_base.get<pointer_type>() == nullptr)
+ else
{
add_error<type_requirement_error>(expression->position(), expression->base().type_decoration,
type_requirement_error::kind::dereference_of_non_pointer);