aboutsummaryrefslogtreecommitdiff
path: root/boot/type_check.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/type_check.cc')
-rw-r--r--boot/type_check.cc57
1 files changed, 23 insertions, 34 deletions
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<procedure_type>() != 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<constant_type>() != nullptr)
+ if (referent.get<constant_type>() != nullptr || referent.get<procedure_type>() != 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<extern_type>() != nullptr
- || underlying.get<parameter_type>() != nullptr)
+ || underlying.get<parameter_type>() != nullptr
+ || underlying.get<procedure_type>() != nullptr)
{
return checked;
}
@@ -402,26 +401,13 @@ namespace elna::boot
{
return find_opaque_type(slice->base);
}
- else if (const auto procedure = referent.get<procedure_type>())
- {
- 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<type> 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<array_type>() != nullptr || resolved.get<slice_type>() != nullptr)
+ if (resolved.get<array_type>() != nullptr
+ || resolved.get<slice_type>() != nullptr
+ || resolved.get<procedure_type>() != nullptr)
{
add_error<type_requirement_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<procedure_info> 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<procedure_type>() == nullptr
+ && is_equality_compatible(lhs_resolved, rhs_resolved);
break;
case shift_left:
case shift_right: