diff --git a/.gitignore b/.gitignore index 039dbd9..0b4b183 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ cmake-build-debug .idea .cache +.ccls-cache diff --git a/include/type_check_utils.hpp b/include/type_check_utils.hpp index 7e8e079..f069fae 100644 --- a/include/type_check_utils.hpp +++ b/include/type_check_utils.hpp @@ -17,8 +17,8 @@ class State { public: struct VariableInfo { - nodes::TypeProxy type; - nodes::NameDefinition::Modifier modifier; + nodes::TypeProxy type; + nodes::NameDefinition::Modifier modifier; }; public: @@ -29,11 +29,12 @@ public: "Insert variable into contexts_ with zero elements in State"); } - return contexts_.back().variables.insert({name, VariableInfo{type, modifier}}).second; + return contexts_.back() + .variables.insert({name, VariableInfo{type, modifier}}) + .second; } - std::optional - find_variable(const std::string &name) { + std::optional find_variable(const std::string &name) { for (ssize_t i = contexts_.size(); i >= 0; --i) { auto iter = contexts_[i].variables.find(name); if (iter != contexts_[i].variables.end()) { @@ -134,8 +135,7 @@ public: public: nodes::MaybeTypeProxy brought_type; nodes::MaybeTypeProxy returned_type; - std::unordered_map - variables; + std::unordered_map variables; private: const nodes::Node &node; @@ -266,6 +266,15 @@ find_name_definition_handle_errors(const std::string &name, const nodes::Node &node, SourcesManager &sources_manager); +std::optional +unfold_user_defined_type_handle_errors(nodes::TypeProxy type, + const nodes::Node &node, + SourcesManager &sources_manager); + +std::optional get_field_type_by_name_handle_errors( + nodes::TypeProxy type, const std::string &field, const nodes::Node &node, + SourcesManager &sources_manager); + void type_check_error(const std::string &message, const nodes::Node &node, SourcesManager &sources_manager); diff --git a/src/type_check_utils.cpp b/src/type_check_utils.cpp index 95d3db3..5e552e4 100644 --- a/src/type_check_utils.cpp +++ b/src/type_check_utils.cpp @@ -1,4 +1,5 @@ #include "type_check_utils.hpp" +#include "builtin_types.hpp" #include namespace type_check { @@ -32,19 +33,22 @@ bool check_no_pass_type_in_arguments(const Arguments &arguments, return true; } -nodes::TypeCheckResult -type_same_to_expected(nodes::TypeProxy type, - const Arguments& arguments, - const nodes::Node &node, SourcesManager &sources_manager, - const std::string &message) { - const auto& expected = arguments.get_expected(); +nodes::TypeCheckResult type_same_to_expected(nodes::TypeProxy type, + const Arguments &arguments, + const nodes::Node &node, + SourcesManager &sources_manager, + const std::string &message) { + const auto &expected = arguments.get_expected(); if (expected.empty()) { return nodes::TypeCheckResult{type}; } // TODO: use 'can cast to' (for modifiers), instead '==' - if (std::all_of(expected.begin(), expected.end(), [type](nodes::TypeProxy expected_type) { return type != expected_type; })) { + if (std::all_of(expected.begin(), expected.end(), + [type](nodes::TypeProxy expected_type) { + return type != expected_type; + })) { type_check_error(message, node, sources_manager); } @@ -95,6 +99,78 @@ find_name_definition_handle_errors(const std::string &name, "Node in name tree is not name definition"); } +std::optional +unfold_user_defined_type_handle_errors(nodes::TypeProxy type, + const nodes::Node &node, + SourcesManager &sources_manager) { + const auto maybe_type_definition = find_type_definition_handle_errors( + *type.get()->get_name()->get(), node, sources_manager); + + if (!maybe_type_definition.has_value()) { + return std::nullopt; + } + + if (maybe_type_definition.value()->get_type().has_value()) { + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + node, + "Only type declaration found for type " + + *type.get()->get_name()->get() + " (type is not defined)", + error_handling::ErrorType::TYPE_CHECK)); + return std::nullopt; + } + + // TODO: perform type arguments substitution + error_handling::ensure(type.get()->parameters_size() == 0, + "Unfold of generic type is not supported (yet)"); + // + return maybe_type_definition.value()->get_type().value(); +} + +std::optional get_field_type_by_name_handle_errors( + nodes::TypeProxy type, const std::string &field, const nodes::Node &node, + SourcesManager &sources_manager) { + switch (type.get()->to_builtin()) { + case builtin::types::Type::TUPLE: { // access field + + const auto maybe_field = type.get()->get_parameter_proxy_by_name(field); + + if (!maybe_field.has_value()) { + + // TODO: pass unfolded type name to log it ?? + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + node, "Type has no defined field " + field, + error_handling::ErrorType::TYPE_CHECK)); + } + return maybe_field.value(); + } + case builtin::types::Type::NONE: { // user defined type, trying to unfold, and + // then repeat access + + // remove recursion ?? + const auto maybe_internal_type = + unfold_user_defined_type_handle_errors(type, node, sources_manager); + if (!maybe_internal_type.has_value()) { + return std::nullopt; + } + + return get_field_type_by_name_handle_errors(maybe_internal_type.value(), + field, node, sources_manager); + } + default: // variant, function, optional, result, error (TODO: add message + // field?), array (TODO: add length field ?), basic types + + sources_manager.get_error_log()->add_error( + error_handling::ErrorLog::ErrorMessage( + node, + "Type " + builtin::types::to_string(type.get()->to_builtin()) + + " has no accessible fields by definition", + error_handling::ErrorType::TYPE_CHECK)); + return std::nullopt; + } +} + void type_check_error(const std::string &message, const nodes::Node &node, SourcesManager &sources_manager) { sources_manager.get_error_log()->add_error(