aboutsummaryrefslogtreecommitdiff
path: root/boot/type_check.cc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-09-14 21:11:03 +0200
committerEugen Wissner <belka@caraus.de>2026-09-14 21:11:03 +0200
commit52c8ca2c06da93c8d14e80a256e8996c1fa1e885 (patch)
tree3579cffe682bb2d2270e5d892f26ae3c197880e6 /boot/type_check.cc
parent49e6a0518eb6b7b09938b562ef270028337508bf (diff)
downloadelna-52c8ca2c06da93c8d14e80a256e8996c1fa1e885.tar.gz
Implement volatile operations
Diffstat (limited to 'boot/type_check.cc')
-rw-r--r--boot/type_check.cc55
1 files changed, 48 insertions, 7 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc
index eee5b42..2b82bec 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -142,6 +142,11 @@ namespace elna::boot
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 '"
+ + this->generic_name + "', it is not a scalar type";
+ }
else if constexpr (std::is_same_v<T, constant_argument>)
{
return "Constant type '" + payload.actual.to_string()
@@ -1217,23 +1222,50 @@ namespace elna::boot
return true;
}
+ /*
+ * The volatile builtins take the pointee as their type argument, so the
+ * rule applies to what is loaded or stored rather than to a pointer.
+ */
+ static argument_rule builtin_argument_rule(const std::string& name)
+ {
+ if (name == "volatile_load")
+ {
+ return argument_rule::scalar;
+ }
+ if (name == "volatile_store")
+ {
+ return argument_rule::mutable_scalar;
+ }
+ return argument_rule::pointer;
+ }
+
void type_analysis_visitor::check_arguments(const named_expression& reference,
- const std::vector<type>& arguments)
+ const std::vector<type>& arguments, const argument_rule rule)
{
for (const type& argument : arguments)
{
- const type resolved = resolve_aliases(argument);
+ if (argument.empty())
+ {
+ continue;
+ }
+ const type underlying = resolve_underlying_type(argument);
- if (resolved.get<constant_type>() != nullptr)
+ if (rule != argument_rule::scalar
+ && resolve_aliases(argument).get<constant_type>() != nullptr)
{
add_error<generic_error>(reference.position(), reference.name,
generic_error::constant_argument{ argument });
}
- else if (!argument.empty() && !is_any_pointer_type(resolve_underlying_type(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))
+ {
+ add_error<generic_error>(reference.position(), reference.name,
+ generic_error::argument_not_scalar{ argument });
+ }
}
}
@@ -1261,7 +1293,8 @@ namespace elna::boot
}
else if (!expression->arguments.empty())
{
- check_arguments(*expression, expression->argument_types);
+ check_arguments(*expression, expression->argument_types,
+ builtin_argument_rule(expression->name));
}
return;
}
@@ -1284,7 +1317,7 @@ namespace elna::boot
}
else
{
- check_arguments(*expression, expression->argument_types);
+ check_arguments(*expression, expression->argument_types, argument_rule::pointer);
}
}
else if (std::shared_ptr<generic_type> const generic = unwrap_generic(denoted))
@@ -1335,7 +1368,7 @@ namespace elna::boot
return type();
}
}
- check_arguments(reference, bindings);
+ check_arguments(reference, bindings, builtin_argument_rule(reference.name));
return substitute(type(std::make_shared<procedure_type>(procedure.symbol)),
procedure.parameters, bindings);
@@ -1396,6 +1429,14 @@ namespace elna::boot
}
inferred = procedure;
callable_type = infer_call(*call, *reference, *procedure);
+
+ // 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>())
+ {
+ call->type_decoration = substituted->return_type.proper_type;
+ }
}
}
if (auto procedure = callable_type.get<procedure_type>())