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.cc184
1 files changed, 105 insertions, 79 deletions
diff --git a/boot/type_check.cc b/boot/type_check.cc
index b1739d9..07e563f 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -100,14 +100,7 @@ namespace elna::boot
{
using T = std::decay_t<decltype(payload)>;
- if constexpr (std::is_same_v<T, argument_count>)
- {
- return "Trait #" + this->trait_name + " expects "
- + std::to_string(payload.expected) + " argument"
- + (payload.expected != 1 ? "s" : "") + ", got "
- + std::to_string(payload.actual);
- }
- else if constexpr (std::is_same_v<T, offset_not_field_name>)
+ if constexpr (std::is_same_v<T, offset_not_field_name>)
{
return "The second argument to the #" + this->trait_name
+ " trait must be a field name";
@@ -170,41 +163,50 @@ namespace elna::boot
return "The number " + payload.overflow.to_string()
+ " does not fit into the type '" + actual.to_string() + "'";
}
- else if constexpr (std::is_same_v<T, kind>)
+ else if constexpr (std::is_same_v<T, constant_assignment>)
{
- switch (payload)
- {
- using enum kind;
- case record_base:
- return "Expected a record type, but got '"
- + this->actual.to_string() + "'";
- case for_range:
- return "Expected an array or slice type, but got '"
- + this->actual.to_string() + "'";
- case condition:
- return "Condition must be a boolean expression, but got '"
- + this->actual.to_string() + "'";
- case constant_assignment:
- return "Cannot assign to a value of type '" + this->actual.to_string()
- + "', because it is constant or contains constant members";
- case array_index:
- return "Array index must be an integral type, but got '"
- + this->actual.to_string() + "'";
- case non_indexable:
- return "Indexing is not allowed on type '"
- + this->actual.to_string() + "'";
- case dereference_of_non_pointer:
- return "Type '" + this->actual.to_string()
- + "' cannot be dereferenced, it is not a pointer";
- default:
- __builtin_unreachable();
- }
+ return "Cannot assign to a value of type '" + this->actual.to_string()
+ + "', because it is constant or contains constant members";
}
}, this->payload);
}
- cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
- const source_position position)
+ type_requirement_error::type_requirement_error(const source_position position,
+ type actual, kind kind)
+ : error(position), actual(std::move(actual)), m_kind(kind)
+ {
+ }
+
+ std::string type_requirement_error::what() const
+ {
+ switch (this->m_kind)
+ {
+ using enum kind;
+ case record_base:
+ return "Expected a record type, but got '"
+ + this->actual.to_string() + "'";
+ case for_range:
+ return "Expected an array or slice type, but got '"
+ + this->actual.to_string() + "'";
+ case condition:
+ return "Condition must be a boolean expression, but got '"
+ + this->actual.to_string() + "'";
+ case array_index:
+ return "Array index must be an integral type, but got '"
+ + this->actual.to_string() + "'";
+ case non_indexable:
+ return "Indexing is not allowed on type '"
+ + this->actual.to_string() + "'";
+ case dereference_of_non_pointer:
+ return "Type '" + this->actual.to_string()
+ + "' cannot be dereferenced, it is not a pointer";
+ default:
+ __builtin_unreachable();
+ }
+ }
+
+ cyclic_declaration_error::cyclic_declaration_error(const source_position position,
+ const std::vector<std::string>& cycle)
: error(position), cycle(cycle)
{
}
@@ -222,24 +224,35 @@ namespace elna::boot
return message;
}
- argument_count_error::argument_count_error(std::size_t expected, std::size_t actual,
- const source_position position)
- : error(position), expected(expected), actual(actual)
+ argument_count_error::argument_count_error(const source_position position, kind kind,
+ std::string applicand, std::size_t expected, std::size_t actual)
+ : error(position), m_kind(kind), applicand(std::move(applicand)), expected(expected), actual(actual)
{
}
std::string argument_count_error::what() const
{
- if (actual > expected)
+ std::string entity;
+
+ switch (this->m_kind)
{
- return "Too many arguments, expected " + std::to_string(expected)
- + ", got " + std::to_string(actual);
+ using enum kind;
+ case trait:
+ entity = '#' + this->applicand;
+ break;
+ case call:
+ entity = '\'' + this->applicand + '\'';
+ break;
+ case array:
+ entity = "array initializer '" + this->applicand + "'";
+ break;
}
- else
- {
- return "Too few arguments, expected " + std::to_string(expected)
+ const std::string noun = this->m_kind == kind::array ? "elements" : "arguments";
+ const std::string quantifier = actual > expected ? "many" : "few";
+
+ return "Too " + quantifier + " " + noun + " for " + entity
+ + ", expected " + std::to_string(expected)
+ ", got " + std::to_string(actual);
- }
}
static bool contains_constant_member(const type& checked)
@@ -302,8 +315,8 @@ namespace elna::boot
condition.accept(this);
if (!is_primitive_type(condition.type_decoration, "Bool"))
{
- add_error<type_mismatch_error>(condition.position(),
- condition.type_decoration, type_mismatch_error::kind::condition);
+ add_error<type_requirement_error>(condition.position(),
+ condition.type_decoration, type_requirement_error::kind::condition);
}
}
@@ -516,7 +529,7 @@ namespace elna::boot
if (contains_constant_member(statement->lvalue().type_decoration))
{
add_error<type_mismatch_error>(statement->position(), statement->lvalue().type_decoration,
- type_mismatch_error::kind::constant_assignment);
+ type_mismatch_error::constant_assignment{});
}
else if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration))
{
@@ -574,8 +587,8 @@ namespace elna::boot
if (!get_range_base_type(resolved_range))
{
- add_error<type_mismatch_error>(statement->range().position(),
- statement->range().type_decoration, type_mismatch_error::kind::for_range);
+ add_error<type_requirement_error>(statement->range().position(),
+ statement->range().type_decoration, type_requirement_error::kind::for_range);
}
this->bag.enter(statement->symbols);
for (auto *body_statement : statement->body)
@@ -647,7 +660,7 @@ namespace elna::boot
if (!check_unresolved_symbol(unresolved_type, alias_path))
{
- add_error<cyclic_declaration_error>(alias_path, declaration->position());
+ add_error<cyclic_declaration_error>(declaration->position(), alias_path);
}
else
{
@@ -662,16 +675,16 @@ namespace elna::boot
auto const base_symbol = this->bag.lookup(expression->base.value().name());
if (base_symbol == nullptr || base_symbol->is_type() == nullptr)
{
- add_error<type_mismatch_error>(expression->position(),
- type(), type_mismatch_error::kind::record_base);
+ add_error<type_requirement_error>(expression->position(),
+ type(), type_requirement_error::kind::record_base);
}
else
{
type const base_type = resolve_underlying_type(base_symbol->is_type()->symbol);
if (base_type.get<record_type>() == nullptr)
{
- add_error<type_mismatch_error>(expression->position(),
- base_type, type_mismatch_error::kind::record_base);
+ add_error<type_requirement_error>(expression->position(),
+ base_type, type_requirement_error::kind::record_base);
}
}
}
@@ -703,8 +716,18 @@ namespace elna::boot
}
if (call->arguments.size() != procedure->parameters.size())
{
- add_error<argument_count_error>(procedure->parameters.size(),
- call->arguments.size(), call->position());
+ if (auto *procedure_name = call->callable().is_named())
+ {
+ add_error<argument_count_error>(call->position(),
+ argument_count_error::kind::call, procedure_name->name,
+ procedure->parameters.size(), call->arguments.size());
+ }
+ else
+ {
+ add_error<argument_count_error>(call->position(),
+ argument_count_error::kind::call, call->callable().type_decoration.to_string(),
+ procedure->parameters.size(), call->arguments.size());
+ }
}
}
else if (!call->callable().type_decoration.empty())
@@ -757,8 +780,9 @@ namespace elna::boot
}
if (expression->elements.size() > array->size)
{
- add_error<argument_count_error>(array->size, expression->elements.size(),
- expression->position());
+ add_error<argument_count_error>(expression->position(),
+ argument_count_error::kind::array, expression->type_decoration.to_string(),
+ array->size, expression->elements.size());
return;
}
for (auto *element : expression->elements)
@@ -778,13 +802,13 @@ namespace elna::boot
if (!is_integral_type(resolve_underlying_type(expression->start().type_decoration)))
{
- add_error<type_mismatch_error>(expression->start().position(),
- expression->start().type_decoration, type_mismatch_error::kind::array_index);
+ add_error<type_requirement_error>(expression->start().position(),
+ expression->start().type_decoration, type_requirement_error::kind::array_index);
}
if (!is_integral_type(resolve_underlying_type(expression->end().type_decoration)))
{
- add_error<type_mismatch_error>(expression->end().position(),
- expression->end().type_decoration, type_mismatch_error::kind::array_index);
+ add_error<type_requirement_error>(expression->end().position(),
+ expression->end().type_decoration, type_requirement_error::kind::array_index);
}
}
@@ -796,13 +820,13 @@ namespace elna::boot
if (resolved_base.get<array_type>() == nullptr
&& resolved_base.get<slice_type>() == nullptr)
{
- add_error<type_mismatch_error>(expression->position(),
- expression->base().type_decoration, type_mismatch_error::kind::non_indexable);
+ add_error<type_requirement_error>(expression->position(),
+ expression->base().type_decoration, type_requirement_error::kind::non_indexable);
}
if (!is_integral_type(resolve_underlying_type(expression->index().type_decoration)))
{
- add_error<type_mismatch_error>(expression->index().position(),
- expression->index().type_decoration, type_mismatch_error::kind::array_index);
+ add_error<type_requirement_error>(expression->index().position(),
+ expression->index().type_decoration, type_requirement_error::kind::array_index);
}
}
@@ -867,9 +891,8 @@ namespace elna::boot
if (resolve_underlying_type(expression->base().type_decoration).get<pointer_type>() == nullptr)
{
- add_error<type_mismatch_error>(expression->position(),
- expression->base().type_decoration,
- type_mismatch_error::kind::dereference_of_non_pointer);
+ add_error<type_requirement_error>(expression->position(), expression->base().type_decoration,
+ type_requirement_error::kind::dereference_of_non_pointer);
}
}
@@ -994,16 +1017,18 @@ namespace elna::boot
{
if (trait->arguments.size() != 1)
{
- add_error<trait_error>(trait->position(), trait->name.name(),
- trait_error::argument_count{ .expected = 1, .actual = trait->arguments.size() });
+ add_error<argument_count_error>(trait->position(),
+ argument_count_error::kind::trait, trait->name.name(),
+ 1, trait->arguments.size());
}
}
else if ((trait->name == "min" || trait->name == "max") && !trait->type_decoration.empty())
{
if (trait->arguments.size() != 1)
{
- add_error<trait_error>(trait->position(), trait->name.name(),
- trait_error::argument_count{ .expected = 1, .actual = trait->arguments.size() });
+ add_error<argument_count_error>(trait->position(),
+ argument_count_error::kind::trait, trait->name.name(),
+ 1, trait->arguments.size());
}
else
{
@@ -1022,8 +1047,9 @@ namespace elna::boot
{
if (trait->arguments.size() != 2)
{
- add_error<trait_error>(trait->position(), trait->name.name(),
- trait_error::argument_count{ .expected = 2, .actual = trait->arguments.size() });
+ add_error<argument_count_error>(trait->position(),
+ argument_count_error::kind::trait, trait->name.name(),
+ 2, trait->arguments.size());
}
else if (trait->arguments.at(1)->is_named() == nullptr)
{