type check error function

This commit is contained in:
ProgramSnail 2024-02-16 16:12:22 +03:00
parent 61fa3a19a0
commit 1a9408c2f6
4 changed files with 83 additions and 84 deletions

View file

@ -186,7 +186,8 @@ private:
class ContextHolder {
public:
ContextHolder(State &state, const nodes::Node &node,
error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy* context_exit_type)
error_handling::ErrorLog &error_log,
nodes::MaybeTypeProxy *context_exit_type)
: state_(state), context_exit_type_(context_exit_type) {
state.enter_context(node, error_log);
}
@ -198,16 +199,16 @@ public:
ContextHolder &operator=(ContextHolder &&) = delete;
~ContextHolder() {
if (context_exit_type_) {
*context_exit_type_ = state_.exit_context();
} else {
state_.exit_context();
}
if (context_exit_type_) {
*context_exit_type_ = state_.exit_context();
} else {
state_.exit_context();
}
}
private:
State &state_;
nodes::MaybeTypeProxy* context_exit_type_;
nodes::MaybeTypeProxy *context_exit_type_;
};
nodes::TypeCheckResult type_same_to_expected(
@ -225,4 +226,7 @@ find_name_definition_handle_errors(const std::string &name,
const nodes::Node &node,
SourcesManager &sources_manager);
void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager);
} // namespace type_check

View file

@ -11,3 +11,19 @@ inline void handle_general_error(const std::string &message) {
}
} // namespace error_handling
namespace utils {
// in std from c++23
[[noreturn]] inline void unreachable() {
// Uses compiler specific extensions if possible.
// Even if no extension is used, undefined behavior is still raised by
// an empty function body and the noreturn attribute.
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
__assume(false);
#else // GCC, Clang
__builtin_unreachable();
#endif
}
} // namespace utils

View file

@ -11,6 +11,7 @@
// IN PROGRESS
// TODO: typecheck pass in all functions
// TODO: assign types in nodes
namespace type_check {
@ -78,6 +79,8 @@ type_check_expression(const nodes::Expression &expression,
sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::UNIT));
}
utils::unreachable();
}
// --- flow control
@ -91,10 +94,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
// x :=/=: ...
if (value_result.is_invalid()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Match value is invalid",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Match value is invalid", expression, sources_manager);
}
std::optional<nodes::TypeCheckResult> expression_result;
@ -139,11 +139,11 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
}
}
if (at_least_one_case_with_expression && at_least_one_case_without_expression) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "all cases should be with or without expression at the same time",
error_handling::ErrorType::TYPE_CHECK));
if (at_least_one_case_with_expression &&
at_least_one_case_without_expression) {
type_check_error(
"All cases should be with or without expression at the same time",
expression, sources_manager);
expression_result = nodes::TypeCheckResult::construct_invalid_result();
}
@ -191,10 +191,8 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
}
if (!expression_result.has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "There should be at least one case in if statement",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("There should be at least one case in if statement",
expression, sources_manager);
expression_result = nodes::TypeCheckResult::construct_invalid_result();
}
@ -221,10 +219,10 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
case nodes::Loop::LOOP: // infinity loop, no params
break;
case nodes::Loop::WHILE:
type_check_expression(
*expression.get_condition().value(), sources_manager, state,
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
sources_manager));
type_check_expression(*expression.get_condition().value(), sources_manager,
state,
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
sources_manager));
// --- type check is independent from loop itself ---
// if (condition_result.value().is_invalid()) {
@ -285,21 +283,16 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression,
last_expression_result = expression_result;
} else {
if (last_expression_result.value().get() != expression_result.get()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
*expression.get_expression(i),
"Elements in array should have same type",
error_handling::ErrorType::TYPE_CHECK));
// return nodes::TypeCheckResult::construct_invalid_result(); // max possible checks, so no return
type_check_error("Elements in array should have same type",
*expression.get_expression(i), sources_manager);
// return nodes::TypeCheckResult::construct_invalid_result(); // max
// possible checks, so no return
}
}
}
if (!last_expression_result.has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Array with zero elements",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Array with zero elements", expression, sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
@ -316,9 +309,9 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
nodes::MaybeTypeProxy context_exit_type;
{
ContextHolder context_holder(state, expression,
*sources_manager.get_error_log(),
&context_exit_type); // TODO: is brought type returned
ContextHolder context_holder(
state, expression, *sources_manager.get_error_log(),
&context_exit_type); // TODO: is brought type returned
for (size_t i = 0; i < expression.expressions_size(); ++i) {
// result types in block are discarded
@ -368,19 +361,15 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
switch (expression.get_type()) {
case nodes::Return::BRING:
if (state.bring_type(returned_result.get())) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Different brought type to current one",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Different brought type to current one", expression,
sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
break;
case nodes::Return::RETURN:
if (!state.return_type(returned_result.get())) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Different returned type to current one",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Different returned type to current one", expression,
sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
break;
@ -397,10 +386,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
SourcesManager &sources_manager, State &state,
const Arguments &arguments) {
if (!arguments.get_passed().has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Can't deduce type of new variable from context",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Can't deduce type of new variable from context",
expression, sources_manager);
}
// assigned type shold be one of <-, <>, -- (can't be ->)
@ -408,10 +395,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
if (nodes::utils::modifier_contains_OUT(
variable_type.get()
->get_modifier())) { // TODO: utils::modifier_contains_OUT
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Variabla cant be asignet from out (->) value",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Variable can't be assigned from out (->) value",
expression, sources_manager);
}
// variable accessible by reference by default ??
@ -420,10 +405,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
if (!state.insert_variable(*expression.get_name()->get(), variable_type,
expression.get_modifier())) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Variable is already defined in this context",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Variable is already defined in this context", expression,
sources_manager);
}
// Return BOOL as any := / =: expression
@ -535,10 +518,8 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression,
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
break;
default:
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Can unwrap only Optional or Result",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Can unwrap only Optional or Result", expression,
sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
} else {
@ -572,11 +553,9 @@ type_check_constructor(const nodes::Constructor &expression,
const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
if (!type_definition->get_type().has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression,
"Type defenition for constructor type not found (declaration only)",
error_handling::ErrorType::TYPE_CHECK));
type_check_error(
"Type defenition for constructor type not found (declaration only)",
expression, sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
@ -592,16 +571,13 @@ type_check_constructor(const nodes::Constructor &expression,
// TODO: work with different parametric types: tuple, variant, ...
if (type.get()->parameters_size() != expression.arguments_size()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression,
"Constructor arguments count is " +
std::string{expression.arguments_size() <
type.get()->parameters_size()
? "less"
: "more"} +
" then type fields count",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Constructor arguments count is " +
std::string{expression.arguments_size() <
type.get()->parameters_size()
? "less"
: "more"} +
" then type fields count",
expression, sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
}
@ -627,18 +603,14 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression,
State &state,
const Arguments &arguments) {
if (!arguments.get_expected().has_value()) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Can't deduce type of lambda function from context",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Can't deduce type of lambda function from context",
expression, sources_manager);
}
const auto expected_type = arguments.get_expected().value();
if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
expression, "Type of lambda function should be function",
error_handling::ErrorType::TYPE_CHECK));
type_check_error("Type of lambda function should be function", expression,
sources_manager);
}
// TODO: define vars

View file

@ -65,4 +65,11 @@ find_name_definition_handle_errors(const std::string &name,
"Node in name tree is not name definition");
}
void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager) {
sources_manager.get_error_log()->add_error(
error_handling::ErrorLog::ErrorMessage(
node, message, error_handling::ErrorType::TYPE_CHECK));
}
} // namespace type_check