ERROR type, check of passed type, many expected types in Arguments

This commit is contained in:
ProgramSnail 2024-02-22 18:46:01 +03:00
parent a5fc0c7ee7
commit 005fb6aaf3
7 changed files with 200 additions and 112 deletions

View file

@ -2,6 +2,7 @@
#include "basic_nodes.hpp" #include "basic_nodes.hpp"
#include "sources_manager.hpp" #include "sources_manager.hpp"
#include "type_check_utils.hpp"
namespace type_check { namespace type_check {
@ -9,6 +10,6 @@ namespace type_check {
nodes::TypeCheckResult nodes::TypeCheckResult
type_check_literal(const nodes::Literal &literal, type_check_literal(const nodes::Literal &literal,
SourcesManager &sources_manager, SourcesManager &sources_manager,
nodes::MaybeTypeProxy expected_type); const Arguments& arguments);
} // namespace type_check } // namespace type_check

View file

@ -21,6 +21,8 @@ const static std::string OPTIONAL_IDENTIFIER = "Optional";
const static std::string RESULT_IDENTIFIER = "Result"; const static std::string RESULT_IDENTIFIER = "Result";
const static std::string ERROR_IDENTIFIER = "Error";
// -- basic types // -- basic types
const static std::string FLOAT_IDENTIFIER = "Float"; const static std::string FLOAT_IDENTIFIER = "Float";
@ -56,6 +58,7 @@ enum class Type {
ARRAY, ARRAY,
OPTIONAL, OPTIONAL,
RESULT, RESULT,
ERROR,
// -- basic types // -- basic types
FLOAT, FLOAT,
DOUBLE, DOUBLE,
@ -86,6 +89,8 @@ inline std::string to_string(Type type) {
return OPTIONAL_IDENTIFIER; return OPTIONAL_IDENTIFIER;
case Type::RESULT: case Type::RESULT:
return RESULT_IDENTIFIER; return RESULT_IDENTIFIER;
case Type::ERROR:
return ERROR_IDENTIFIER;
// -- basic types // -- basic types
case Type::FLOAT: case Type::FLOAT:
return FLOAT_IDENTIFIER; return FLOAT_IDENTIFIER;
@ -127,6 +132,7 @@ inline Type to_type(const std::string &str) {
builtin_types[ARRAY_IDENTIFIER] = Type::ARRAY; builtin_types[ARRAY_IDENTIFIER] = Type::ARRAY;
builtin_types[OPTIONAL_IDENTIFIER] = Type::OPTIONAL; builtin_types[OPTIONAL_IDENTIFIER] = Type::OPTIONAL;
builtin_types[RESULT_IDENTIFIER] = Type::RESULT; builtin_types[RESULT_IDENTIFIER] = Type::RESULT;
builtin_types[ERROR_IDENTIFIER] = Type::ERROR;
// -- basic types // -- basic types
builtin_types[FLOAT_IDENTIFIER] = Type::FLOAT; builtin_types[FLOAT_IDENTIFIER] = Type::FLOAT;
@ -172,6 +178,7 @@ inline std::optional<size_t> get_parameters_count(Type type) {
case Type::ARRAY: case Type::ARRAY:
case Type::OPTIONAL: case Type::OPTIONAL:
case Type::RESULT: case Type::RESULT:
case Type::ERROR:
return 1; return 1;
// -- basic types // -- basic types
case Type::FLOAT: case Type::FLOAT:

View file

@ -40,6 +40,7 @@ private:
}; };
using MaybeTypeProxy = std::optional<TypeProxy>; using MaybeTypeProxy = std::optional<TypeProxy>;
using TypeProxies = std::vector<TypeProxy>;
class Type { class Type {
public: public:

View file

@ -147,8 +147,9 @@ public:
Arguments expect_builtin(builtin::types::Type type, Arguments expect_builtin(builtin::types::Type type,
SourcesManager &sources_manager) const { SourcesManager &sources_manager) const {
Arguments copy(*this); Arguments copy(*this);
copy.expected_type_ = copy.expected_types_ = {
sources_manager.get_type_storage()->primitive_type(type); sources_manager.get_type_storage()->primitive_type(type)};
return copy;
} }
Arguments pass_builtin(builtin::types::Type type, Arguments pass_builtin(builtin::types::Type type,
@ -159,9 +160,15 @@ public:
return copy; return copy;
} }
Arguments expect(nodes::TypeProxies types) const {
Arguments copy(*this);
copy.expected_types_ = types;
return copy;
}
Arguments expect(nodes::MaybeTypeProxy type) const { Arguments expect(nodes::MaybeTypeProxy type) const {
Arguments copy(*this); Arguments copy(*this);
copy.expected_type_ = type; copy.expected_types_ = (type.has_value() ? nodes::TypeProxies{type.value()} : nodes::TypeProxies{});
return copy; return copy;
} }
@ -171,7 +178,19 @@ public:
return copy; return copy;
} }
nodes::MaybeTypeProxy get_expected() const { return expected_type_; }; Arguments without_expect() const {
Arguments copy(*this);
copy.expected_types_ = {};
return copy;
}
Arguments without_pass() const {
Arguments copy(*this);
copy.passed_type_ = {};
return copy;
}
nodes::TypeProxies get_expected() const { return expected_types_; };
nodes::MaybeTypeProxy get_passed() const { return passed_type_; }; nodes::MaybeTypeProxy get_passed() const { return passed_type_; };
@ -179,8 +198,8 @@ public:
// TODO: arguments builder ?? // TODO: arguments builder ??
private: private:
nodes::MaybeTypeProxy expected_type_ = {}; nodes::TypeProxies expected_types_;
nodes::MaybeTypeProxy passed_type_ = {}; nodes::MaybeTypeProxy passed_type_;
}; };
class ContextHolder { class ContextHolder {
@ -211,11 +230,25 @@ private:
nodes::MaybeTypeProxy *context_exit_type_; nodes::MaybeTypeProxy *context_exit_type_;
}; };
nodes::TypeProxy check_same_to_pass_type_in_arguments(
nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
SourcesManager &sources_manager,
const std::string &message = "Different type with passed one");
// bool check_no_pass_type_in_arguments(
// const Arguments &arguments, const nodes::Node &node,
// SourcesManager &sources_manager,
// const std::string &message = "Type can't be passed to this node");
nodes::TypeCheckResult type_same_to_expected( nodes::TypeCheckResult type_same_to_expected(
nodes::TypeProxy type, nodes::MaybeTypeProxy expected_type, nodes::TypeProxy type, const Arguments& argumensr,
const nodes::Node &node, error_handling::ErrorLog &error_log, const nodes::Node &node, SourcesManager &sources_manager,
const std::string &message = "Different type with expected one"); const std::string &message = "Different type with expected one");
nodes::TypeCheckResult type_check_from_arguments(
nodes::TypeProxy type, const Arguments& arguments,
const nodes::Node &node, SourcesManager &sources_manager);
std::optional<const nodes::TypeDefinition *> std::optional<const nodes::TypeDefinition *>
find_type_definition_handle_errors(const std::string &name, find_type_definition_handle_errors(const std::string &name,
const nodes::Node &node, const nodes::Node &node,
@ -229,8 +262,4 @@ find_name_definition_handle_errors(const std::string &name,
void type_check_error(const std::string &message, const nodes::Node &node, void type_check_error(const std::string &message, const nodes::Node &node,
SourcesManager &sources_manager); SourcesManager &sources_manager);
bool check_no_pass_type_in_arguments(const Arguments &arguments,
const nodes::Node &node,
SourcesManager &sources_manager);
} // namespace type_check } // namespace type_check

View file

@ -51,13 +51,9 @@ nodes::TypeProxy get_literal_type(const nodes::Literal &literal,
nodes::TypeCheckResult type_check_literal(const nodes::Literal &literal, nodes::TypeCheckResult type_check_literal(const nodes::Literal &literal,
SourcesManager &sources_manager, SourcesManager &sources_manager,
nodes::MaybeTypeProxy expected_type) { const Arguments &arguments) {
auto const type = get_literal_type(literal, sources_manager); auto const type = get_literal_type(literal, sources_manager);
if (expected_type.has_value() && type != expected_type.value()) { return type_same_to_expected(type, arguments, literal, sources_manager);
return nodes::TypeCheckResult::construct_invalid_result();
// nodes::TypeCheckResult::fail_with(type, expected_type, literal); // TODO: create error ??
}
return nodes::TypeCheckResult(type);
} }
} // namespace type_check } // namespace type_check

View file

@ -68,7 +68,7 @@ type_check_expression(const nodes::Expression &expression,
case 12: // Literal case 12: // Literal
// TODO // TODO
return type_check_literal(*expression.get<nodes::Literal>().value(), return type_check_literal(*expression.get<nodes::Literal>().value(),
sources_manager, arguments.get_expected()); sources_manager, arguments);
// --- empty lines // --- empty lines
case 13: // Extra case 13: // Extra
return nodes::TypeCheckResult( return nodes::TypeCheckResult(
@ -153,10 +153,10 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
builtin::types::Type::UNIT)}; builtin::types::Type::UNIT)};
} }
return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( return type_check_from_arguments(
expression_result.value().get()), sources_manager.get_type_storage()->add_array_of(
arguments.get_expected(), expression, expression_result.value().get()),
*sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression, nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
@ -196,10 +196,10 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
expression_result = nodes::TypeCheckResult::construct_invalid_result(); expression_result = nodes::TypeCheckResult::construct_invalid_result();
} }
return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( return type_check_from_arguments(
expression_result.value().get()), sources_manager.get_type_storage()->add_array_of(
arguments.get_expected(), expression, expression_result.value().get()),
*sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression, nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
@ -261,9 +261,9 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
// TODO: modifier checks ??, modifiers ?? // TODO: modifier checks ??, modifiers ??
return type_same_to_expected( return type_check_from_arguments(
sources_manager.get_type_storage()->add_array_of(expression_result.get()), sources_manager.get_type_storage()->add_array_of(expression_result.get()),
arguments.get_expected(), expression, *sources_manager.get_error_log()); arguments, expression, sources_manager);
} // IN PROGRESS } // IN PROGRESS
// --- containers // --- containers
@ -296,10 +296,10 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression,
return nodes::TypeCheckResult::construct_invalid_result(); return nodes::TypeCheckResult::construct_invalid_result();
} }
return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( return type_check_from_arguments(
last_expression_result.value().get()), sources_manager.get_type_storage()->add_array_of(
arguments.get_expected(), expression, last_expression_result.value().get()),
*sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult type_check_block(const nodes::Container &expression, nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
@ -327,10 +327,10 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
sources_manager.get_type_storage()->primitive_type( sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::UNIT)); builtin::types::Type::UNIT));
return type_same_to_expected(sources_manager.get_type_storage()->add_array_of( return type_check_from_arguments(
block_brought_type.get()), sources_manager.get_type_storage()->add_array_of(
arguments.get_expected(), expression, block_brought_type.get()),
*sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult type_check_container(const nodes::Container &expression, nodes::TypeCheckResult type_check_container(const nodes::Container &expression,
@ -375,10 +375,10 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
break; break;
} }
return type_same_to_expected( return type_check_from_arguments(
sources_manager.get_type_storage()->primitive_type( sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::UNIT), builtin::types::Type::UNIT),
arguments.get_expected(), expression, *sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult nodes::TypeCheckResult
@ -410,10 +410,10 @@ type_check_name_definition(const nodes::NameDefinition &expression,
} }
// Return BOOL as any := / =: expression // Return BOOL as any := / =: expression
return type_same_to_expected( return type_check_from_arguments(
sources_manager.get_type_storage()->primitive_type( sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::BOOL), builtin::types::Type::BOOL),
arguments.get_expected(), expression, *sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression, nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression,
@ -439,9 +439,9 @@ nodes::TypeCheckResult type_check_array_access(const nodes::Access &expression,
// TODO: modifier checks ?? // TODO: modifier checks ??
return type_same_to_expected(value_result.get().get()->get_parameter_proxy(0), return type_check_from_arguments(
arguments.get_expected(), expression, value_result.get().get()->get_parameter_proxy(0), arguments, expression,
*sources_manager.get_error_log()); sources_manager);
} }
nodes::TypeCheckResult type_check_tuple_access(const nodes::Access &expression, nodes::TypeCheckResult type_check_tuple_access(const nodes::Access &expression,
@ -464,9 +464,9 @@ nodes::TypeCheckResult type_check_tuple_access(const nodes::Access &expression,
// TODO: modifier checks ?? // TODO: modifier checks ??
return type_same_to_expected( return type_check_from_arguments(
value_result.get().get()->get_parameter_proxy(index), value_result.get().get()->get_parameter_proxy(index), arguments,
arguments.get_expected(), expression, *sources_manager.get_error_log()); expression, sources_manager);
} }
nodes::TypeCheckResult type_check_access(const nodes::Access &expression, nodes::TypeCheckResult type_check_access(const nodes::Access &expression,
@ -487,10 +487,10 @@ nodes::TypeCheckResult
type_check_loop_control(const nodes::LoopControl &expression, type_check_loop_control(const nodes::LoopControl &expression,
SourcesManager &sources_manager, State &, SourcesManager &sources_manager, State &,
const Arguments &arguments) { const Arguments &arguments) {
return type_same_to_expected( return type_check_from_arguments(
sources_manager.get_type_storage()->primitive_type( sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::UNIT), builtin::types::Type::UNIT),
arguments.get_expected(), expression, *sources_manager.get_error_log()); arguments, expression, sources_manager);
} }
nodes::TypeCheckResult nodes::TypeCheckResult
@ -528,8 +528,8 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression,
modified_result.get(), expression.get_modifier())); modified_result.get(), expression.get_modifier()));
} }
return type_same_to_expected(modified_result.get(), arguments.get_expected(), return type_check_from_arguments(modified_result.get(), arguments, expression,
expression, *sources_manager.get_error_log()); sources_manager);
} // IN PROGRESS } // IN PROGRESS
// --- other // --- other
@ -628,9 +628,8 @@ type_check_name_expression(const nodes::NameExpression &expression,
// TODO: invert modifier ?? // TODO: invert modifier ??
// TODO: generic types should be deduced from arguments // TODO: generic types should be deduced from arguments
return type_same_to_expected(returned->get_type_proxy().value(), return type_check_from_arguments(returned->get_type_proxy().value(),
arguments.get_expected(), expression, arguments, expression, sources_manager);
*sources_manager.get_error_log());
} }
// checks for universal call syntax ?? // checks for universal call syntax ??
@ -680,41 +679,67 @@ type_check_constructor(const nodes::Constructor &expression,
// TODO: work with generics (type_definition->arguments, ...) // TODO: work with generics (type_definition->arguments, ...)
// for tuple const auto builtin_type = type.get()->to_builtin();
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()) { 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();
type_check_error( if (annotation.has_value() != expected_annotation.has_value()) {
"Wrong type constructor argument annotation: should be " +
std::string{expected_annotation.has_value() type_check_error(
? *expected_annotation.value() "Wrong type constructor argument annotation: should be " +
: "[none]"}, std::string{expected_annotation.has_value()
*expression.get_argument_value(i), sources_manager); ? *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,
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
// TODO: do something with argument type ??
} }
break;
if (annotation.has_value() && case builtin::types::Type::VARIANT:
*annotation.value() != *expected_annotation.value()) { // TODO: expect one of types
type_check_error( break;
"Wrong function argument type annotation: " + *annotation.value() + case builtin::types::Type::OPTIONAL:
" instead of " + *expected_annotation.value(), // TODO: expect type (generic) or NULL
*expression.get_argument_value(i), sources_manager); break;
} case builtin::types::Type::RESULT:
// TODO: expect ERROR or type (generic)
type_check_expression( break;
*expression.get_argument_value(i), sources_manager, state, case builtin::types::Type::ERROR:
Arguments{}.expect(type.get()->get_parameter_proxy(i))); // TODO: expect type (generic)
// TODO: do something with argument type ?? 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 // TODO: deduce generic parts in type
return type_same_to_expected(expression.get_type_proxy(), return type_check_from_arguments(expression.get_type_proxy(), arguments,
arguments.get_expected(), expression, expression, sources_manager);
*sources_manager.get_error_log());
// TODO: add <- modifiier to type ?? // TODO: add <- modifiier to type ??
} // IN PROGRESS } // IN PROGRESS
@ -724,12 +749,19 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression,
SourcesManager &sources_manager, SourcesManager &sources_manager,
State &state, State &state,
const Arguments &arguments) { const Arguments &arguments) {
if (!arguments.get_expected().has_value()) { if (arguments.get_expected().empty()) {
type_check_error("Can't deduce type of lambda function from context", type_check_error("Can't deduce type of lambda function from context: no "
"one type expected",
expression, sources_manager); expression, sources_manager);
} }
const auto expected_type = arguments.get_expected().value(); if (arguments.get_expected().size() != 1) {
type_check_error("Can't deduce type of lambda function from context; too "
"much possible types",
expression, sources_manager);
}
const auto expected_type = arguments.get_expected().front();
if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) { if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) {
type_check_error("Type of lambda function should be function", expression, type_check_error("Type of lambda function should be function", expression,
sources_manager); sources_manager);
@ -742,7 +774,10 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression,
// auto returned_type = type_check_expression( // auto returned_type = type_check_expression(
// *expression.get_expression(), sources_manager, state, Arguments{}); // *expression.get_expression(), sources_manager, state, Arguments{});
return nodes::TypeCheckResult{expected_type}; // TODO: same to expected ?? // TODO: needed ?? (only passed type check required ??)
return type_check_from_arguments(
expected_type, arguments, expression,
sources_manager); // TODO: same to expected ??
} // IN PROGRESS } // IN PROGRESS
} // namespace type_check } // namespace type_check

View file

@ -1,24 +1,54 @@
#include "type_check_utils.hpp" #include "type_check_utils.hpp"
#include <algorithm>
namespace type_check { namespace type_check {
nodes::TypeCheckResult type_same_to_expected( // pass type -> compare types, return bool
nodes::TypeProxy type, nodes::MaybeTypeProxy expected_type, // no pass type -> return type
const nodes::Node &node, error_handling::ErrorLog &error_log, nodes::TypeProxy check_same_to_pass_type_in_arguments(
const std::string &message) { nodes::TypeProxy type, const Arguments &arguments, const nodes::Node &node,
if (!expected_type.has_value()) { SourcesManager &sources_manager, const std::string &message) {
if (!arguments.get_passed().has_value()) {
return type;
}
if (type != arguments.get_passed().value()) {
type_check_error(message, node, sources_manager);
}
return sources_manager.get_type_storage()->primitive_type(
builtin::types::Type::BOOL);
}
bool check_no_pass_type_in_arguments(const Arguments &arguments,
const nodes::Node &node,
SourcesManager &sources_manager,
const std::string &message) {
if (arguments.get_passed().has_value()) {
type_check_error(message, node, sources_manager);
return false;
}
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();
if (expected.empty()) {
return nodes::TypeCheckResult{type}; return nodes::TypeCheckResult{type};
} }
if (type != expected_type.value()) {
error_log.add_error(error_handling::ErrorLog::ErrorMessage(
node, message, error_handling::ErrorType::TYPE_CHECK));
return nodes::TypeCheckResult::construct_invalid_result();
}
// TODO: use 'can cast to' (for modifiers), instead '==' // TODO: use 'can cast to' (for modifiers), instead '=='
return nodes::TypeCheckResult{ if (std::all_of(expected.begin(), expected.end(), [type](nodes::TypeProxy expected_type) { return type != expected_type; })) {
expected_type.value()}; // TODO: retern type or expected type ?? type_check_error(message, node, sources_manager);
}
return nodes::TypeCheckResult{expected.front()}; // any can be choosen
} }
template <typename T> template <typename T>
@ -72,15 +102,4 @@ void type_check_error(const std::string &message, const nodes::Node &node,
node, message, error_handling::ErrorType::TYPE_CHECK)); node, message, error_handling::ErrorType::TYPE_CHECK));
} }
bool check_no_pass_type_in_arguments(const Arguments &arguments,
const nodes::Node &node,
SourcesManager &sources_manager) {
if (arguments.get_passed().has_value()) {
type_check_error("Type can't be passed to this node", node,
sources_manager);
return false;
}
return true;
}
} // namespace type_check } // namespace type_check