diff --git a/include/nodes/statement_nodes.hpp b/include/nodes/statement_nodes.hpp index ba3ed8f..011f8a0 100644 --- a/include/nodes/statement_nodes.hpp +++ b/include/nodes/statement_nodes.hpp @@ -219,6 +219,13 @@ public: return std::nullopt; } + std::optional get_type_proxy() const { + if (type_.has_value()) { + return type_.value(); + } + return std::nullopt; + } + // Modifier get_before_modifier() const { return before_modifier_; } diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index a48cf33..b83b563 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -221,7 +221,7 @@ find_type_definition_handle_errors(const std::string &name, const nodes::Node &node, SourcesManager &sources_manager); -std::optional +std::optional find_name_definition_handle_errors(const std::string &name, const nodes::Node &node, SourcesManager &sources_manager); diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index 8c8ba87..61f19f4 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -538,15 +538,112 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression, nodes::TypeCheckResult type_check_name_expression(const nodes::NameExpression &expression, SourcesManager &sources_manager, State &state, - const Arguments &arguments) {} // IN PROGRESS + const Arguments &arguments) { + // TODO: constraints ?? + + // TODO: deal with passed type + + // TODO: check, if there is variable with this name + const auto maybe_function_definition = find_name_definition_handle_errors( + *expression.get_name()->get(), expression, sources_manager); + if (!maybe_function_definition.has_value()) { + return nodes::TypeCheckResult::construct_invalid_result(); + } + const nodes::FunctionDefinition *function_definition = + maybe_function_definition.value(); + + // + 1 - returned type + if (expression.arguments_size() + 1 != + function_definition + ->arguments_size()) { // other, when there is passed type + type_check_error( + "Number of function arguments is different from expected (" + + std::to_string(expression.arguments_size()) + " instead of " + + std::to_string(function_definition->arguments_size()) + ")", + expression, sources_manager); + return nodes::TypeCheckResult::construct_invalid_result(); + // TODO: try return correct type (function return type), when possible + } + + // TODO: define types for generic function + + std::vector function_argument_results; + for (size_t i = 0; i < expression.arguments_size(); + ++i) { // TODO: arguments reordering, based on annotations + const nodes::FunctionDefinition::Argument *argument = + function_definition->get_argument(i); + + if (!argument->get_type().has_value()) { + type_check_error("Function argument type is not defined for argument " + + std::to_string(i), + expression, sources_manager); + continue; + } + + const auto annotation = expression.get_argument_annotation(i); + const auto expected_annotation = argument->get_annotation(); + + if (annotation.has_value() != expected_annotation.has_value()) { + + type_check_error("Wrong function argument annotation: should be " + + std::string{expected_annotation.has_value() + ? *expected_annotation.value() + : "[none]"}, + *expression.get_argument_value(i), sources_manager); + } + + if (annotation.has_value() && + *annotation.value() != *expected_annotation.value()) { + type_check_error( + "Wrong function argument type annotation: " + *annotation.value() + + " instead of " + *expected_annotation.value(), + *expression.get_argument_value(i), sources_manager); + } + + function_argument_results.push_back(type_check_expression( + *expression.get_argument_value(i), sources_manager, state, + Arguments{}.expect(argument->get_type_proxy().value()))); + } + + if (function_definition->arguments_size() == 0) { + type_check_error( + "Function arguments size is zero. Returned type is not defined", + expression, sources_manager); + return nodes::TypeCheckResult::construct_invalid_result(); + } + + { + // returned type + const nodes::FunctionDefinition::Argument *returned = + function_definition->get_argument( + function_definition->arguments_size() - 1); + + // TODO: invert modifier ?? + if (!returned->get_type().has_value()) { + type_check_error( + "Function argument type is not defined for returned type", expression, + sources_manager); + return nodes::TypeCheckResult::construct_invalid_result(); + } + + // TODO: invert modifier ?? + // TODO: generic types should be deduced from arguments + return type_same_to_expected(returned->get_type_proxy().value(), + arguments.get_expected(), expression, + *sources_manager.get_error_log()); + } + + // checks for universal call syntax ?? +} // IN PROGRESS // TODO nodes::TypeCheckResult type_check_constructor(const nodes::Constructor &expression, SourcesManager &sources_manager, State &state, const Arguments &arguments) { - check_no_pass_type_in_arguments(arguments, expression, sources_manager); + // TODO: constraints ?? + // TODO: use pass type const auto maybe_type_definition = find_type_definition_handle_errors( *expression.get_type()->get_name()->get(), expression, sources_manager); if (!maybe_type_definition.has_value()) { @@ -561,37 +658,60 @@ type_check_constructor(const nodes::Constructor &expression, return nodes::TypeCheckResult::construct_invalid_result(); } - // TODO: chack that is not typeclass ?? + // TODO: deal with anniotations, recursive annotations - // TODO: type arguments substitution (deduce argument type values ??) - for (size_t i = 0; i < type_definition->arguments_size(); ++i) { - // TODO: ... - } + // TODO: check that is not typeclass ?? nodes::TypeProxy type = type_definition->get_type().value(); // TODO: work with different parametric types: tuple, variant, ... - if (type.get()->parameters_size() != expression.arguments_size()) { - 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); + if (expression.arguments_size() != + type.get()->parameters_size()) { // other, when there is passed type + type_check_error( + "Number of type constructor arguments is different from expected (" + + std::to_string(expression.arguments_size()) + " instead of " + + std::to_string(type.get()->parameters_size()) + ")", + expression, sources_manager); return nodes::TypeCheckResult::construct_invalid_result(); + // TODO: try return correct type (constructor's type), when possible (not + // generic) } + // TODO: work with generics (type_definition->arguments, ...) + // for tuple - for (size_t i = 0; i < expression.arguments_size(); ++i) { + for (size_t i = 0; i < expression.arguments_size(); + ++i) { // TODO: deduce order by annotations const auto annotation = expression.get_argument_annotation(i); + const auto expected_annotation = + type.get()->get_parameter(i)->get_annotation(); - auto argument_type = type_check_expression( + if (annotation.has_value() != expected_annotation.has_value()) { + + type_check_error( + "Wrong type constructor argument annotation: should be " + + std::string{expected_annotation.has_value() + ? *expected_annotation.value() + : "[none]"}, + *expression.get_argument_value(i), sources_manager); + } + + if (annotation.has_value() && + *annotation.value() != *expected_annotation.value()) { + type_check_error( + "Wrong function argument type annotation: " + *annotation.value() + + " instead of " + *expected_annotation.value(), + *expression.get_argument_value(i), sources_manager); + } + + type_check_expression( *expression.get_argument_value(i), sources_manager, state, - /* TODO: type from definition by annotation */); + Arguments{}.expect(type.get()->get_parameter_proxy(i))); + // TODO: do something with argument type ?? } - // TODO: expect types of arguments by type definition + + // TODO: deduce generic parts in type return type_same_to_expected(expression.get_type_proxy(), arguments.get_expected(), expression, *sources_manager.get_error_log()); diff --git a/src/type_check_utils.cpp b/src/type_check_utils.cpp index d674ba2..0f8d5bb 100644 --- a/src/type_check_utils.cpp +++ b/src/type_check_utils.cpp @@ -56,11 +56,11 @@ find_type_definition_handle_errors(const std::string &name, "Node in name tree is not type definition"); } -std::optional +std::optional find_name_definition_handle_errors(const std::string &name, const nodes::Node &node, SourcesManager &sources_manager) { - return find_statement_handle_errors( + return find_statement_handle_errors( name, node, sources_manager, "No name definition found in name tree", "Node in name tree is not name definition"); }