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 { class ContextHolder {
public: public:
ContextHolder(State &state, const nodes::Node &node, 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_(state), context_exit_type_(context_exit_type) {
state.enter_context(node, error_log); state.enter_context(node, error_log);
} }
@ -225,4 +226,7 @@ find_name_definition_handle_errors(const std::string &name,
const nodes::Node &node, const nodes::Node &node,
SourcesManager &sources_manager); SourcesManager &sources_manager);
void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager);
} // namespace type_check } // namespace type_check

View file

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