aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/symbol.cc18
-rw-r--r--boot/type_check.cc55
2 files changed, 66 insertions, 7 deletions
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 466715b..55f91ea 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -401,6 +401,24 @@ namespace elna::boot
std::vector<std::string>{ "condition" });
result->enter("assert", assert_info);
+ const type load_parameter = type(std::make_shared<parameter_type>("T"));
+ procedure_type volatile_load_symbol{ procedure_type::return_t(load_parameter) };
+ volatile_load_symbol.parameters.emplace_back(std::make_shared<pointer_type>(load_parameter));
+ std::shared_ptr<procedure_info> const volatile_load_info =
+ std::make_shared<procedure_info>(volatile_load_symbol, std::vector<std::string>{ "source" });
+ volatile_load_info->parameters.push_back(load_parameter);
+ result->enter("volatile_load", volatile_load_info);
+
+ const type store_parameter = type(std::make_shared<parameter_type>("T"));
+ procedure_type volatile_store_symbol{ procedure_type::return_t() };
+ volatile_store_symbol.parameters.emplace_back(std::make_shared<pointer_type>(store_parameter));
+ volatile_store_symbol.parameters.push_back(store_parameter);
+ std::shared_ptr<procedure_info> const volatile_store_info =
+ std::make_shared<procedure_info>(volatile_store_symbol,
+ std::vector<std::string>{ "target", "value" });
+ volatile_store_info->parameters.push_back(store_parameter);
+ result->enter("volatile_store", volatile_store_info);
+
return result;
}
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>())