diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index 5472c6b..3166c23 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -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 diff --git a/include/utils.hpp b/include/utils.hpp index ed16dd0..5803658 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -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 diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index f81b316..9d6f042 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -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 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 diff --git a/src/type_check_utils.cpp b/src/type_check_utils.cpp index 1bcff70..a9b52d2 100644 --- a/src/type_check_utils.cpp +++ b/src/type_check_utils.cpp @@ -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