From d7f1b6c3770f87c2ca0a16227cb44d21724cad8c Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Thu, 22 Feb 2024 21:57:54 +0300 Subject: [PATCH] part of constuctor typecheck (constructors for different types) --- include/builtin_types.hpp | 3 +- include/nodes/type_nodes.hpp | 15 ++ src/expression_type_check.cpp | 258 ++++++++++++++++++++++++++-------- 3 files changed, 217 insertions(+), 59 deletions(-) diff --git a/include/builtin_types.hpp b/include/builtin_types.hpp index fb8f454..4b3835a 100644 --- a/include/builtin_types.hpp +++ b/include/builtin_types.hpp @@ -177,9 +177,10 @@ inline std::optional get_parameters_count(Type type) { return std::nullopt; case Type::ARRAY: case Type::OPTIONAL: - case Type::RESULT: case Type::ERROR: return 1; + case Type::RESULT: // RESULT[T E] = T | Error[E] + return 2; // -- basic types case Type::FLOAT: case Type::DOUBLE: diff --git a/include/nodes/type_nodes.hpp b/include/nodes/type_nodes.hpp index 560efd8..27f90ff 100644 --- a/include/nodes/type_nodes.hpp +++ b/include/nodes/type_nodes.hpp @@ -243,6 +243,21 @@ public: std::move(parameters))); } + TypeProxy add_error_of(TypeProxy type, Node node = Node()) { + if (type.type_storage_ != this) { + error_handling::handle_general_error( + "TypeStorage: Can't add error of type from another type " + "storage"); + } + + std::vector parameters; + parameters.push_back(type); + + return add_type(Type(Identifier(node, Identifier::SIMPLE_TYPE, + builtin::types::ERROR_IDENTIFIER), + std::move(parameters))); + } + nodes::TypeProxy add_container_of(std::vector &¶meters, builtin::types::Type container, Node node = Node()) { diff --git a/src/expression_type_check.cpp b/src/expression_type_check.cpp index b87fe19..7e89e1b 100644 --- a/src/expression_type_check.cpp +++ b/src/expression_type_check.cpp @@ -541,7 +541,8 @@ type_check_name_expression(const nodes::NameExpression &expression, const Arguments &arguments) { // TODO: constraints ?? - // TODO: deal with passed type + // --- TODO --- deal with passed type --- TODO --- (additional argument) + // TODO: deal with given ->(out) Args (type not expected, but passed into) // TODO: check, if there is variable with this name const auto maybe_function_definition = find_name_definition_handle_errors( @@ -665,13 +666,9 @@ type_check_constructor(const nodes::Constructor &expression, // TODO: work with different parametric types: tuple, variant, ... - 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); + if (expression.arguments_size() == 0) { + type_check_error("Number of type constructor arguments should be > 0", + expression, sources_manager); return nodes::TypeCheckResult::construct_invalid_result(); // TODO: try return correct type (constructor's type), when possible (not // generic) @@ -681,60 +678,205 @@ type_check_constructor(const nodes::Constructor &expression, const auto builtin_type = type.get()->to_builtin(); - switch (builtin_type) { - case builtin::types::Type::TUPLE: - // for tuple - 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(); - - if (annotation.has_value() != expected_annotation.has_value()) { - + { // check arguments size, ets. + switch (builtin_type) { + case builtin::types::Type::TUPLE: + if (expression.arguments_size() != type.get()->parameters_size()) { 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); + "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) } - - 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); + break; + case builtin::types::Type::VARIANT: + case builtin::types::Type::OPTIONAL: + case builtin::types::Type::RESULT: + case builtin::types::Type::ERROR: + case builtin::types::Type::FUNCTION: + case builtin::types::Type::NONE: + if (expression.arguments_size() != 1) { // TODO: better to_string + type_check_error("Number of type constructor arguments should be = 1 " + "(builtin type " + + std::to_string(uint(builtin_type)) + ")", + expression, sources_manager); + return nodes::TypeCheckResult::construct_invalid_result(); + // TODO: try return correct type (constructor's type), when possible + // (not generic) } - - type_check_expression( - *expression.get_argument_value(i), sources_manager, state, - Arguments{}.expect(type.get()->get_parameter_proxy(i))); - // TODO: do something with argument type ?? + break; + default: // array, basic types + break; + } + + if (get_parameters_count(builtin_type).has_value() && + type.get()->parameters_size() != + get_parameters_count(builtin_type).value()) { + type_check_error("Wrong amount of parametars for builtin type", + expression, sources_manager); + + return nodes::TypeCheckResult::construct_invalid_result(); + // TODO: try return correct type (constructor's type), when possible (not + // generic) + } + } + + std::optional chosen_variant_option; // for VARIANT + + { // check annotations + const auto check_same_annotation = + [&expression, &sources_manager]( + size_t i, std::optional expected_annotation, + bool log_errors) { + bool is_same = true; + + const auto annotation = expression.get_argument_annotation(i); + + if (annotation.has_value() != expected_annotation.has_value()) { + if (log_errors) { + 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); + } + is_same = false; + } + + if (annotation.has_value() && + *annotation.value() != *expected_annotation.value()) { + if (log_errors) { + type_check_error("Wrong function argument type annotation: " + + *annotation.value() + " instead of " + + *expected_annotation.value(), + *expression.get_argument_value(i), + sources_manager); + } + + is_same = false; + } + + return is_same; + }; + + const auto check_no_annotation = + [&expression, &sources_manager](size_t i, bool log_errors) { + if (expression.get_argument_annotation(i).has_value()) { + if (log_errors) { + type_check_error( + "Type constructor argument annotation not expected there", + *expression.get_argument_value(i), sources_manager); + } + return false; + } + return true; + }; + + switch (builtin_type) { + case builtin::types::Type::TUPLE: + for (size_t i = 0; i < expression.arguments_size(); ++i) { + check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(), + true /*log errors*/); + } + break; + case builtin::types::Type::VARIANT: + // more then one same annotation ?? + for (size_t i = 0; i < type.get()->parameters_size(); ++i) { + if (check_same_annotation( + 0, type.get()->get_parameter(i)->get_annotation(), + false /*do not log errors*/)) { + chosen_variant_option = i; + break; + } + } + + if (!chosen_variant_option.has_value() && + !check_no_annotation(0, false /*do not log errors*/)) { + type_check_error("Wrong type constructor argument annotation in " + "constructor of variant type", + *expression.get_argument_value(0), sources_manager); + } + break; + case builtin::types::Type::ERROR: // no anotations ?? + check_same_annotation(0, type.get()->get_parameter(0)->get_annotation(), + true /*log errors*/); + break; + case builtin::types::Type::OPTIONAL: + case builtin::types::Type::RESULT: + case builtin::types::Type::FUNCTION: + case builtin::types::Type::NONE: + check_no_annotation(0, true /*log errors*/); + break; + default: // array, basic types + break; + } + } + + { // type check arguments + switch (builtin_type) { + case builtin::types::Type::TUPLE: + for (size_t i = 0; i < expression.arguments_size(); ++i) { + type_check_expression( + *expression.get_argument_value(i), sources_manager, state, + Arguments{}.expect(type.get()->get_parameter_proxy(i))); + } + break; + case builtin::types::Type::VARIANT: + if (chosen_variant_option.has_value()) { + type_check_expression( + *expression.get_argument_value(0), sources_manager, state, + Arguments{}.expect(type.get()->get_parameter_proxy( + chosen_variant_option.value()))); + } else { // TODO: error, if there is more then one possible variant in + // answer + nodes::TypeProxies possible_options; + for (size_t i = 0; i < type.get()->parameters_size(); ++i) { + possible_options.push_back(type.get()->get_parameter_proxy(i)); + } + type_check_expression(*expression.get_argument_value(0), + sources_manager, state, + Arguments{}.expect(possible_options)); + } + break; + case builtin::types::Type::OPTIONAL: + // first parameter or NULL + type_check_expression( + *expression.get_argument_value(0), sources_manager, state, + Arguments{}.expect( + {type.get()->get_parameter_proxy(0), + sources_manager.get_type_storage()->primitive_type( + builtin::types::Type::NULL_OPTION)})); + break; + case builtin::types::Type::RESULT: + // first parameter or ERROR[second parameter] + type_check_expression( + *expression.get_argument_value(0), sources_manager, state, + Arguments{}.expect({type.get()->get_parameter_proxy(0), + sources_manager.get_type_storage()->add_error_of( + type.get()->get_parameter_proxy(1))})); + break; + case builtin::types::Type::ERROR: + // first parameter + type_check_expression( + *expression.get_argument_value(0), sources_manager, state, + Arguments{}.expect(type.get()->get_parameter_proxy(0))); + break; + case builtin::types::Type::FUNCTION: + case builtin::types::Type::NONE: + // type itself + type_check_expression(*expression.get_argument_value(0), sources_manager, + state, Arguments{}.expect(type)); + break; + default: // array, basic types + type_check_error("Type can't be constructed", expression, + sources_manager); + break; } - break; - case builtin::types::Type::VARIANT: - // TODO: expect one of types - break; - case builtin::types::Type::OPTIONAL: - // TODO: expect type (generic) or NULL - break; - case builtin::types::Type::RESULT: - // TODO: expect ERROR or type (generic) - break; - case builtin::types::Type::ERROR: - // TODO: expect type (generic) - break; - case builtin::types::Type::FUNCTION: - // TODO: built from one value (function) - break; - case builtin::types::Type::NONE: - // TODO: built from one value - break; - default: // array, basic types - type_check_error("Type can't be constructed", expression, sources_manager); - break; } // TODO: deduce generic parts in type