diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/symbol.cc | 18 | ||||
| -rw-r--r-- | boot/type_check.cc | 55 |
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>()) |
