From 7be372282483187dcef40896527f90fb4cbc5bf2 Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Sun, 8 Sep 2024 23:40:51 +0300 Subject: [PATCH] Typecheck: build working --- lang/nodes/include/nodes_storage.hpp | 4 +- .../include/expression_type_check.hpp | 13 +- lang/type_check/include/type_check_utils.hpp | 19 +- lang/type_check/src/basic_type_check.cpp | 3 +- lang/type_check/src/expression_type_check.cpp | 448 ++++++++++-------- lang/type_check/src/type_check_utils.cpp | 2 +- lang/type_check/xmake.lua | 14 +- 7 files changed, 287 insertions(+), 216 deletions(-) diff --git a/lang/nodes/include/nodes_storage.hpp b/lang/nodes/include/nodes_storage.hpp index 9408afd..30591cb 100644 --- a/lang/nodes/include/nodes_storage.hpp +++ b/lang/nodes/include/nodes_storage.hpp @@ -82,12 +82,12 @@ public: // - template T &part() { return NodePart::data_[id_]; } + // template T &part() { return NodePart::data_[id_]; } template const T &part() const { return NodePart::data_[id_]; } - template T &get() { return std::get(data_[id_].value); } + // template T &get() { return std::get(data_[id_].value); } template const T &get() const { return std::get(data_[id_].value); } diff --git a/lang/type_check/include/expression_type_check.hpp b/lang/type_check/include/expression_type_check.hpp index c77eb85..dcd3e08 100644 --- a/lang/type_check/include/expression_type_check.hpp +++ b/lang/type_check/include/expression_type_check.hpp @@ -8,10 +8,17 @@ namespace type_check { template <> -struct CheckTask : public CheckTaskBase { - using CheckTaskBase::CheckTaskBase; +struct CheckTask : public CheckTaskBase { + using CheckTaskBase::CheckTaskBase; - Result operator()(const nodes::ExprData &expr, const Args &args) override; + Result operator()(const nodes::NodeId &expr, const Args &args) override; +}; + +template <> +struct CheckTask : public CheckTaskBase { + using CheckTaskBase::CheckTaskBase; + + Result operator()(const nodes::NodeData &expr, const Args &args) override; }; // --- flow control diff --git a/lang/type_check/include/type_check_utils.hpp b/lang/type_check/include/type_check_utils.hpp index 306c146..1adccdd 100644 --- a/lang/type_check/include/type_check_utils.hpp +++ b/lang/type_check/include/type_check_utils.hpp @@ -163,14 +163,17 @@ private: using Exprs = nodes::NodeStorage; using Types = nodes::TypeStorage; using Names = names::NameTree; +using Positions = core::DependentStorage; -using Executor = utils::Executor; +using Executor = utils::Executor; + +using Node = nodes::Node_>; // class Args { public: - Args() = default; + Args(storage::Id current_id) : current_id(current_id) {}; Args expect_builtin(builtin::Type type, Executor &executor) const { Args copy(*this); @@ -222,6 +225,9 @@ public: // TODO: add check, that there is no passed type for some nodes ?? // TODO: args builder ?? +public: + storage::Id current_id; + private: nodes::Types expected_types_; nodes::MaybeType passed_type_; @@ -357,6 +363,15 @@ template struct CheckTaskBase : public Task { CheckTask task(this->executor); return task(node, args); } + + Node Ext(storage::Id id) { + return Node(id, this->template state(), + this->template state()); + } + + utils::Pos PosOf(storage::Id id) { + return Ext(id).template part(); + } }; } // namespace type_check diff --git a/lang/type_check/src/basic_type_check.cpp b/lang/type_check/src/basic_type_check.cpp index fbf3892..2b197f0 100644 --- a/lang/type_check/src/basic_type_check.cpp +++ b/lang/type_check/src/basic_type_check.cpp @@ -40,7 +40,8 @@ nodes::Type get_literal_type(const nodes::Literal &literal, Result CheckTask::operator()(const nodes::Literal &literal, const Args &args) { auto const type = get_literal_type(literal, this->executor); - return type_same_to_expected(type, args, literal, this->executor); + return type_same_to_expected(type, args, {}, + this->executor); // TODO: add pos ?? } } // namespace type_check diff --git a/lang/type_check/src/expression_type_check.cpp b/lang/type_check/src/expression_type_check.cpp index bb6a2dd..ab08d0f 100644 --- a/lang/type_check/src/expression_type_check.cpp +++ b/lang/type_check/src/expression_type_check.cpp @@ -11,22 +11,37 @@ namespace type_check { -Result CheckTask::operator()(const nodes::ExprData &expr, +Result CheckTask::operator()(const nodes::NodeId &expr, + const Args &args) { + return Run(*Ext(expr), args); +} + +Result CheckTask::operator()(const nodes::NodeData &expr, const Args &args) { return std::visit( - [this, &args](const auto &node) -> Result { return Run(node, args); }, - expr.get_any()); + [this, &args](const auto &node) -> Result { + using T = std::decay_t; + if constexpr (std::is_same_v) { + utils::Assert(false, "No type check for nodes::Match::Case"); + utils::unreachable(); + } else { + return Run(node, args); + } + }, + expr.value); } // --- flow control Result CheckTask::operator()(const nodes::Match &expr, const Args &args) { - Result value_result = Run(*expr.get_value(), {}); + const auto current_pos = PosOf(args.current_id); + + Result value_result = Run(expr.value, {expr.value}); // x :=/=: ... if (value_result.is_invalid()) { - type_check_error("Match value is invalid", expr, executor); + type_check_error("Match value is invalid", current_pos, executor); } MaybeResult expression_result; @@ -34,31 +49,33 @@ Result CheckTask::operator()(const nodes::Match &expr, bool at_least_one_case_with_expression = false; bool at_least_one_case_without_expression = false; - for (size_t i = 0; i < expr.cases_size(); ++i) { - const nodes::Match::Case *current_case = expr.get_case(i); + for (const auto ¤t_case_id : expr.cases) { + const nodes::Match::Case ¤t_case = + Ext(current_case_id).get(); // :=/=: x ... - Run(*current_case->get_value(), - Args{} + Run(current_case.value, + Args{current_case.value} .expect_builtin(builtin::Type::BOOL, executor) .pass(value_result.is_invalid() ? nodes::MaybeType{} : expression_result.value().get())); // TODO: use type modifiers ?? // ... ?? x ... - if (current_case->get_condition().has_value()) { - Run(*current_case->get_condition().value(), - Args{}.expect_builtin(builtin::Type::BOOL, executor)); + if (current_case.condition.has_value()) { + Run(current_case.condition.value(), + Args{current_case.condition.value()}.expect_builtin( + builtin::Type::BOOL, executor)); } // ... -> x - if (current_case->get_expression().has_value()) { + if (current_case.expr.has_value()) { at_least_one_case_with_expression = true; - Result case_result = - Run(*current_case->get_condition().value(), - Args{}.expect(expression_result.has_value() - ? expression_result.value().get() - : nodes::MaybeType{})); + Result case_result = Run(current_case.expr.value(), + Args{current_case.expr.value()}.expect( + expression_result.has_value() + ? expression_result.value().get() + : nodes::MaybeType{})); if (!expression_result.has_value() && !case_result.is_invalid()) { expression_result = std::move(case_result); @@ -71,8 +88,8 @@ Result CheckTask::operator()(const nodes::Match &expr, if (at_least_one_case_with_expression && at_least_one_case_without_expression) { type_check_error( - "All cases should be with or without expression at the same time", expr, - executor); + "All cases should be with or without expression at the same time", + current_pos, executor); expression_result = Result::invalid(); } @@ -81,62 +98,67 @@ Result CheckTask::operator()(const nodes::Match &expr, } return type_check_from_args( - state().add_array_of(expression_result.value().get()), args, expr, - executor); + state().add_array_of(expression_result.value().get()), args, + current_pos, executor); } Result CheckTask::operator()(const nodes::Condition &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + MaybeResult expression_result; - for (size_t i = 0; i < expr.cases_size(); ++i) { - Run(*expr.get_case(i).first, - Args{}.expect_builtin(builtin::Type::BOOL, executor)); + for (const auto ¤t_case : expr.cases) { + Run(current_case.first, + Args{current_case.first}.expect_builtin(builtin::Type::BOOL, executor)); - Result case_result = Run(*expr.get_case(i).first, - Args{}.expect(expression_result.has_value() - ? expression_result.value().get() - : nodes::MaybeType{})); + Result case_result = + Run(current_case.second, + Args{current_case.second}.expect( + expression_result.has_value() ? expression_result.value().get() + : nodes::MaybeType{})); if (!expression_result.has_value() && !case_result.is_invalid()) { expression_result = std::move(case_result); } } - if (expr.get_else_case().has_value()) { - Run(*expr.get_else_case().value(), - Args{}.expect(expression_result.has_value() - ? expression_result.value().get() - : nodes::MaybeType{})); + if (expr.else_case.has_value()) { + Run(expr.else_case.value(), + Args{expr.else_case.value()}.expect( + expression_result.has_value() ? expression_result.value().get() + : nodes::MaybeType{})); } if (!expression_result.has_value()) { - type_check_error("There should be at least one case in if statement", expr, - executor); + type_check_error("There should be at least one case in if statement", + current_pos, executor); expression_result = Result::invalid(); } return type_check_from_args( - state().add_array_of(expression_result.value().get()), args, expr, - executor); + state().add_array_of(expression_result.value().get()), args, + current_pos, executor); } Result CheckTask::operator()(const nodes::Loop &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + // TODO: ranges ?? MaybeResult interval_result; MaybeResult variable_result; - Result expression_result = Run(*expr.get_expression(), {}); + Result expression_result = Run(expr.expr, {expr.expr}); - switch (expr.get_type()) { + switch (expr.kind) { case nodes::Loop::LOOP: // infinity loop, no params break; case nodes::Loop::WHILE: - Run(*expr.get_condition().value(), - Args{}.expect_builtin(builtin::Type::BOOL, executor)); + Run(expr.condition.value(), Args{expr.condition.value()}.expect_builtin( + builtin::Type::BOOL, executor)); // --- type check is independent from loop itself --- // if (condition_result.value().is_invalid()) { @@ -147,8 +169,8 @@ Result CheckTask::operator()(const nodes::Loop &expr, case nodes::Loop::FOR: // TODO: expect range ?? interval_result = - Run(*expr.get_interval().value(), - Args{}.expect_builtin(builtin::Type::ARRAY, executor)); + Run(expr.interval.value(), Args{expr.interval.value()}.expect_builtin( + builtin::Type::ARRAY, executor)); if (interval_result.value().is_invalid()) { // --- type check is independent from loop itself --- @@ -157,8 +179,8 @@ Result CheckTask::operator()(const nodes::Loop &expr, } variable_result = - Run(*expr.get_variable().value(), - Args{}.expect( + Run(expr.variable.value(), + Args{expr.variable.value()}.expect( interval_result.value().get().get()->get_parameter_proxy(0))); // --- type check is independent from loop itself --- @@ -175,7 +197,7 @@ Result CheckTask::operator()(const nodes::Loop &expr, // TODO: modifier checks ??, modifiers ?? return type_check_from_args( - state().add_array_of(expression_result.get()), args, expr, + state().add_array_of(expression_result.get()), args, current_pos, executor); } // IN PROGRESS @@ -183,46 +205,50 @@ Result CheckTask::operator()(const nodes::Loop &expr, Result CheckTask::CheckArray(const nodes::Container &expr, const Args &args) { - MaybeResult last_expression_result; + const auto current_pos = PosOf(args.current_id); - for (size_t i = 0; i < expr.expressions_size(); ++i) { + MaybeResult last_expr_result; + + for (const auto &elem_expr : expr.exprs) { // elements should have same type, but type is not expected - auto expression_result = Run(*expr.get_expression(i), {}); + auto expr_result = Run(elem_expr, {elem_expr}); - if (!last_expression_result.has_value()) { - last_expression_result = expression_result; + if (!last_expr_result.has_value()) { + last_expr_result = expr_result; } else { - if (last_expression_result.value().get() != expression_result.get()) { + if (last_expr_result.value().get() != expr_result.get()) { type_check_error("Elements in array should have same type", - *expr.get_expression(i), executor); + PosOf(args.current_id), executor); // return TypeCheckResult::construct_invalid_result(); // max // possible checks, so no return } } } - if (!last_expression_result.has_value()) { - type_check_error("Array with zero elements", expr, executor); + if (!last_expr_result.has_value()) { + type_check_error("Array with zero elements", current_pos, executor); return Result::invalid(); } return type_check_from_args( - state().add_array_of(last_expression_result.value().get()), args, - expr, executor); + state().add_array_of(last_expr_result.value().get()), args, + current_pos, executor); } Result CheckTask::CheckBlock(const nodes::Container &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + nodes::MaybeType context_exit_type; { ContextHolder context_holder( - state(), expr, + state(), current_pos, &context_exit_type); // TODO: is brought type returned - for (size_t i = 0; i < expr.expressions_size(); ++i) { + for (const auto &elem_expr : expr.exprs) { // result types in block are discarded - Run(*expr.get_expression(i), {}); + Run(elem_expr, {elem_expr}); } } @@ -232,13 +258,13 @@ Result CheckTask::CheckBlock(const nodes::Container &expr, : Result(state().primitive(builtin::Type::UNIT)); return type_check_from_args( - state().add_array_of(block_brought_type.get()), args, expr, + state().add_array_of(block_brought_type.get()), args, current_pos, executor); } Result CheckTask::operator()(const nodes::Container &expr, const Args &args) { - switch (expr.get_type()) { + switch (expr.kind) { case nodes::Container::ARRAY: return CheckArray(expr, args); case nodes::Container::BLOCK: @@ -250,22 +276,25 @@ Result CheckTask::operator()(const nodes::Container &expr, Result CheckTask::operator()(const nodes::Return &expr, const Args &args) { - auto returned_result = Run(*expr.get_expression(), {}); + const auto current_pos = PosOf(args.current_id); + + auto returned_result = Run(expr.expr, {expr.expr}); if (returned_result.is_invalid()) { return returned_result; } - switch (expr.get_type()) { + switch (expr.kind) { case nodes::Return::BRING: if (state().bring_type(returned_result.get())) { - type_check_error("Different brought type to current one", expr, executor); + type_check_error("Different brought type to current one", current_pos, + executor); return Result::invalid(); } break; case nodes::Return::RETURN: if (!state().return_type(returned_result.get())) { - type_check_error("Different returned type to current one", expr, + type_check_error("Different returned type to current one", current_pos, executor); return Result::invalid(); } @@ -273,16 +302,18 @@ Result CheckTask::operator()(const nodes::Return &expr, } return type_check_from_args(state().primitive(builtin::Type::UNIT), - args, expr, executor); + args, current_pos, executor); } // TODO: warning if name is same to package prefix, function prefix, etc. ?? Result CheckTask::operator()(const nodes::NameDefinition &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + if (!args.get_passed().has_value()) { - type_check_error("Can't deduce type of new variable from context", expr, - executor); + type_check_error("Can't deduce type of new variable from context", + current_pos, executor); } // assigned type shold be one of <-, <>, -- (can't be ->) @@ -290,31 +321,35 @@ CheckTask::operator()(const nodes::NameDefinition &expr, if (nodes::utils::modifier_contains_OUT( variable_type.get() ->get_modifier())) { // TODO: utils::modifier_contains_OUT - type_check_error("Variable can't be assigned from out (->) value", expr, - executor); + type_check_error("Variable can't be assigned from out (->) value", + current_pos, executor); } // variable accessible by reference by default ?? state().add_modification_of(variable_type, nodes::Modifier::REF); - if (!state().insert_variable(*expr.get_name()->get(), variable_type, - expr.get_modifier())) { - type_check_error("Variable is already defined in this context", expr, + if (!state().insert_variable(expr.name.value, variable_type, + expr.kind)) { + type_check_error("Variable is already defined in this context", current_pos, executor); } // Return BOOL as any := / =: expression return type_check_from_args(state().primitive(builtin::Type::BOOL), - args, expr, executor); + args, current_pos, executor); } Result CheckTask::CheckArrayAccess(const nodes::Access &expr, const Args &args) { - auto index_result = Run( - *expr.get_index(), Args{}.expect_builtin(builtin::Type::INDEX, executor)); + const auto current_pos = PosOf(args.current_id); - auto value_result = Run( - *expr.get_value(), Args{}.expect_builtin(builtin::Type::ARRAY, executor)); + auto index_result = + Run(expr.index, + Args{expr.index}.expect_builtin(builtin::Type::INDEX, executor)); + + auto value_result = + Run(expr.value, + Args{expr.value}.expect_builtin(builtin::Type::ARRAY, executor)); if (index_result.is_invalid()) { return index_result; @@ -327,34 +362,36 @@ Result CheckTask::CheckArrayAccess(const nodes::Access &expr, // TODO: modifier checks ?? return type_check_from_args(value_result.get().get()->get_parameter_proxy(0), - args, expr, executor); + args, current_pos, executor); } Result CheckTask::CheckTupleAccess(const nodes::Access &expr, const Args &args) { - auto value_result = Run( - *expr.get_value(), Args{}.expect_builtin(builtin::Type::TUPLE, executor)); + const auto current_pos = PosOf(args.current_id); + + auto value_result = + Run(expr.value, + Args{expr.value}.expect_builtin(builtin::Type::TUPLE, executor)); if (value_result.is_invalid()) { return value_result; } - size_t index = *expr.get_index() - ->get() - .value() - ->get() // Index type + size_t index = *Ext(expr.index) + .get() + .get() // Index type .value(); // TODO: modifier checks ?? return type_check_from_args( - value_result.get().get()->get_parameter_proxy(index), args, expr, + value_result.get().get()->get_parameter_proxy(index), args, current_pos, executor); } Result CheckTask::operator()(const nodes::Access &expr, const Args &args) { - switch (expr.get_type()) { + switch (expr.kind) { case nodes::Access::ARRAY: return CheckArrayAccess(expr, args); case nodes::Access::TUPLE: @@ -364,24 +401,28 @@ Result CheckTask::operator()(const nodes::Access &expr, Result CheckTask::operator()(const nodes::LoopControl &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + return type_check_from_args(state().primitive(builtin::Type::UNIT), - args, expr, executor); + args, current_pos, executor); } Result CheckTask::operator()( const nodes::ModifierExpression &expr, const Args &args) { - auto modified_result = Run(*expr.get_expression(), {}); + const auto current_pos = PosOf(args.current_id); + + auto modified_result = Run(expr.expr, {expr.expr}); if (modified_result.is_invalid()) { return Result::invalid(); } if (nodes::utils::is_suffix_modifier( - expr.get_modifier())) { // optional, result - // '?' - open optional / result in -> - // (execute or not execute pattern - // matching expression) / (value / - // return) (TODO: alternative for bring) + expr.modifier)) { // optional, result + // '?' - open optional / result in -> + // (execute or not execute pattern + // matching expression) / (value / + // return) (TODO: alternative for bring) // '!' - open optional / result -> value / panic @@ -392,16 +433,18 @@ Result CheckTask::operator()( modified_result.set(modified_result.get().get()->get_parameter_proxy(0)); break; default: - type_check_error("Can unwrap only Optional or Result", expr, executor); + type_check_error("Can unwrap only Optional or Result", current_pos, + executor); return Result::invalid(); } } else { // TODO: check that modifier can be applied modified_result.set(state().add_modification_of( - modified_result.get(), expr.get_modifier())); + modified_result.get(), expr.modifier)); } - return type_check_from_args(modified_result.get(), args, expr, executor); + return type_check_from_args(modified_result.get(), args, current_pos, + executor); } // IN PROGRESS // --- other @@ -410,12 +453,14 @@ Result CheckTask::operator()( Result CheckTask::operator()(const nodes::NameExpression &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + // TODO: constraints ?? - const auto name = expr.get_name(); + const auto name = expr.name; { - const auto fragments = name->get_fragments(); + const auto fragments = name.get_fragments(); nodes::Identifier current_prefix = fragments.front(); std::optional maybe_variable; size_t i = 0; @@ -425,7 +470,7 @@ CheckTask::operator()(const nodes::NameExpression &expr, current_prefix.append_after(fragments[i]); } - maybe_variable = state().find_variable(*current_prefix.get()); + maybe_variable = state().find_variable(current_prefix.value); if (maybe_variable.has_value()) { break; @@ -449,8 +494,8 @@ CheckTask::operator()(const nodes::NameExpression &expr, // TODO: switch by type types: Variant, Tuple, ... // Tuple -> try to find field // Others -> try to open / builtin fields ? - const auto maybe_field_type = - get_field_type_by_name(type, *fragments[i].get(), expr, executor); + const auto maybe_field_type = get_field_type_by_name( + type, fragments[i].value, current_pos, executor); if (maybe_field_type.has_value()) { type = maybe_field_type.value(); @@ -472,7 +517,7 @@ CheckTask::operator()(const nodes::NameExpression &expr, // TODO: check, if there is variable with this name // TODO: check var + fields const auto maybe_function_definition = - find_name_definition(*name->get(), expr, executor); + find_name_definition(name.value, current_pos, executor); if (!maybe_function_definition.has_value()) { return Result::invalid(); } @@ -482,8 +527,8 @@ CheckTask::operator()(const nodes::NameExpression &expr, // TODO: count passed type, if needed // TODO: manage situation with one out type at any position // TODO + 1 - returned type - somtimes (can be ==) - const auto args_given = expr.args_size(); - const auto args_defined = function_definition->args_size(); + const auto args_given = expr.args.size(); + const auto args_defined = function_definition->args.size(); if (args_given + 1 < args_defined || args_given > args_defined) { // other, when there is passed type type_check_error( @@ -494,7 +539,7 @@ CheckTask::operator()(const nodes::NameExpression &expr, ? (" or " + std::to_string(args_defined - 1)) : ""} + ")", - expr, executor); + current_pos, executor); return Result::invalid(); // TODO: try return correct type (function return type), when possible } @@ -504,64 +549,64 @@ CheckTask::operator()(const nodes::NameExpression &expr, std::vector function_argument_results; for (size_t i = 0; i < args_given; ++i) { // TODO: pass types with oud modifier - const nodes::FunctionDefinition::Argument *argument = - function_definition->get_argument(i); + const nodes::FunctionDefinition::Argument &argument = + function_definition->args.at(i); - if (!argument->get_type().has_value()) { + if (!argument.type.has_value()) { type_check_error("Function argument type is not defined for argument " + std::to_string(i), - expr, executor); + current_pos, executor); continue; } - const auto annotation = expr.get_argument_annotation(i); - const auto expected_annotation = argument->get_annotation(); + const auto annotation = expr.args.at(i).first; + const auto expected_annotation = argument.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() + ? expected_annotation.value() : "[none]"}, - *expr.get_argument_value(i), executor); + PosOf(expr.args.at(i).second), executor); } if (annotation.has_value() && - *annotation.value() != *expected_annotation.value()) { + annotation.value() != expected_annotation.value()) { type_check_error( - "Wrong function argument type annotation: " + *annotation.value() + - " instead of " + *expected_annotation.value(), - *expr.get_argument_value(i), executor); + "Wrong function argument type annotation: " + annotation.value() + + " instead of " + expected_annotation.value(), + PosOf(expr.args.at(i).second), executor); } function_argument_results.push_back( - Run(*expr.get_argument_value(i), - Args{}.expect(argument->get_type_proxy().value()))); + Run(expr.args.at(i).second, + Args{expr.args.at(i).second}.expect(argument.type.value()))); } - if (function_definition->args_size() == 0) { + if (function_definition->args.size() == 0) { type_check_error( - "Function arguments size is zero. Returned type is not defined", expr, - executor); + "Function arguments size is zero. Returned type is not defined", + current_pos, executor); return Result::invalid(); } // TODO: check condition if (args_given + 1 == args_defined) { // returned type - const nodes::FunctionDefinition::Argument *returned = - function_definition->get_argument(function_definition->args_size() - 1); + const nodes::FunctionDefinition::Argument &returned = + function_definition->args.back(); // TODO: invert modifier ?? - if (!returned->get_type().has_value()) { + if (!returned.type.has_value()) { type_check_error( - "Function argument type is not defined for returned type", expr, - executor); + "Function argument type is not defined for returned type", + current_pos, executor); return Result::invalid(); } // TODO: invert modifier ?? // TODO: generic types should be deduced from args - return type_check_from_args(returned->get_type_proxy().value(), args, expr, + return type_check_from_args(returned.type.value(), args, current_pos, executor); } @@ -573,20 +618,22 @@ CheckTask::operator()(const nodes::NameExpression &expr, // TODO Result CheckTask::operator()(const nodes::Constructor &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + // TODO: constraints ?? // TODO: use pass type - const auto maybe_type_definition = - find_type_definition(*expr.get_type()->get_name()->get(), expr, executor); + const auto maybe_type_definition = find_type_definition( + expr.type.get()->get_name()->value, current_pos, executor); if (!maybe_type_definition.has_value()) { return Result::invalid(); } const nodes::TypeDefinition *type_definition = maybe_type_definition.value(); - if (!type_definition->get_type().has_value()) { + if (!type_definition->type.has_value()) { type_check_error( "Type defenition for constructor type not found (declaration only)", - expr, executor); + current_pos, executor); return Result::invalid(); } @@ -594,13 +641,13 @@ Result CheckTask::operator()(const nodes::Constructor &expr, // TODO: check that is not typeclass ?? - nodes::Type type = type_definition->get_type().value(); + nodes::Type type = type_definition->type.value(); // TODO: work with different parametric types: tuple, variant, ... - if (expr.args_size() == 0) { - type_check_error("Number of type constructor arguments should be > 0", expr, - executor); + if (expr.args.size() == 0) { + type_check_error("Number of type constructor arguments should be > 0", + current_pos, executor); return Result::invalid(); // TODO: try return correct type (constructor's type), when possible (not // generic) @@ -613,13 +660,13 @@ Result CheckTask::operator()(const nodes::Constructor &expr, { // check args size, ets. switch (builtin_type) { case builtin::Type::TUPLE: - if (expr.args_size() != type.get()->parameters_size()) { + if (expr.args.size() != type.get()->parameters_size()) { type_check_error( "Number of type constructor arguments is different from expected " "(" + - std::to_string(expr.args_size()) + " instead of " + + std::to_string(expr.args.size()) + " instead of " + std::to_string(type.get()->parameters_size()) + ")", - expr, executor); + current_pos, executor); return Result::invalid(); // TODO: try return correct type (constructor's type), when possible // (not generic) @@ -631,11 +678,11 @@ Result CheckTask::operator()(const nodes::Constructor &expr, case builtin::Type::ERROR: case builtin::Type::FUNCTION: case builtin::Type::NONE: - if (expr.args_size() != 1) { // TODO: better to_string + if (expr.args.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)) + ")", - expr, executor); + current_pos, executor); return Result::invalid(); // TODO: try return correct type (constructor's type), when possible // (not generic) @@ -648,8 +695,8 @@ Result CheckTask::operator()(const nodes::Constructor &expr, if (builtin::types::get_parameters_count(builtin_type).has_value() && type.get()->parameters_size() != builtin::types::get_parameters_count(builtin_type).value()) { - type_check_error("Wrong amount of parametars for builtin type", expr, - executor); + type_check_error("Wrong amount of parametars for builtin type", + current_pos, executor); return Result::invalid(); // TODO: try return correct type (constructor's type), when possible (not @@ -661,12 +708,12 @@ Result CheckTask::operator()(const nodes::Constructor &expr, { // check annotations const auto check_same_annotation = - [&expr, &executor = this->executor]( - size_t i, std::optional expected_annotation, - bool log_errors) { + [&expr, this](size_t i, + std::optional expected_annotation, + bool log_errors) { bool is_same = true; - const auto annotation = expr.get_argument_annotation(i); + const auto annotation = expr.args.at(i).first; if (annotation.has_value() != expected_annotation.has_value()) { if (log_errors) { @@ -675,18 +722,18 @@ Result CheckTask::operator()(const nodes::Constructor &expr, std::string{expected_annotation.has_value() ? *expected_annotation.value() : "[none]"}, - *expr.get_argument_value(i), executor); + PosOf(expr.args.at(i).second), executor); } is_same = false; } if (annotation.has_value() && - *annotation.value() != *expected_annotation.value()) { + annotation.value() != *expected_annotation.value()) { if (log_errors) { type_check_error("Wrong function argument type annotation: " + - *annotation.value() + " instead of " + + annotation.value() + " instead of " + *expected_annotation.value(), - *expr.get_argument_value(i), executor); + PosOf(expr.args.at(i).second), executor); } is_same = false; @@ -695,22 +742,21 @@ Result CheckTask::operator()(const nodes::Constructor &expr, return is_same; }; - const auto check_no_annotation = - [&expr, &executor = this->executor](size_t i, bool log_errors) { - if (expr.get_argument_annotation(i).has_value()) { - if (log_errors) { - type_check_error( - "Type constructor argument annotation not expected there", - *expr.get_argument_value(i), executor); - } - return false; - } - return true; - }; + const auto check_no_annotation = [&expr, this](size_t i, bool log_errors) { + if (expr.args.at(i).first.has_value()) { + if (log_errors) { + type_check_error( + "Type constructor argument annotation not expected there", + PosOf(expr.args.at(i).second), executor); + } + return false; + } + return true; + }; switch (builtin_type) { case builtin::Type::TUPLE: - for (size_t i = 0; i < expr.args_size(); ++i) { + for (size_t i = 0; i < expr.args.size(); ++i) { check_same_annotation(i, type.get()->get_parameter(i)->get_annotation(), true /*log errors*/); } @@ -730,7 +776,7 @@ Result CheckTask::operator()(const nodes::Constructor &expr, !check_no_annotation(0, false /*do not log errors*/)) { type_check_error("Wrong type constructor argument annotation in " "constructor of variant type", - *expr.get_argument_value(0), executor); + PosOf(expr.args.front().second), executor); } break; case builtin::Type::ERROR: // no anotations ?? @@ -751,57 +797,60 @@ Result CheckTask::operator()(const nodes::Constructor &expr, { // type check args switch (builtin_type) { case builtin::Type::TUPLE: - for (size_t i = 0; i < expr.args_size(); ++i) { - Run(*expr.get_argument_value(i), - Args{}.expect(type.get()->get_parameter_proxy(i))); + for (size_t i = 0; i < expr.args.size(); ++i) { + Run(expr.args.at(i).second, Args{expr.args.at(i).second}.expect( + type.get()->get_parameter_proxy(i))); } break; case builtin::Type::VARIANT: if (chosen_variant_option.has_value()) { - Run(*expr.get_argument_value(0), - Args{}.expect(type.get()->get_parameter_proxy( - chosen_variant_option.value()))); + Run(expr.args.front().second, Args{expr.args.front().second}.expect( + type.get()->get_parameter_proxy( + chosen_variant_option.value()))); } else { // TODO: error, if there is more then one possible variant in // answer nodes::Types possible_options; for (size_t i = 0; i < type.get()->parameters_size(); ++i) { possible_options.push_back(type.get()->get_parameter_proxy(i)); } - Run(*expr.get_argument_value(0), Args{}.expect(possible_options)); + Run(expr.args.front().second, + Args{expr.args.front().second}.expect(possible_options)); } break; case builtin::Type::OPTIONAL: // first parameter or NULL - Run(*expr.get_argument_value(0), - Args{}.expect( + Run(expr.args.front().second, + Args{expr.args.front().second}.expect( {type.get()->get_parameter_proxy(0), state().primitive(builtin::Type::NULL_OPTION)})); break; case builtin::Type::RESULT: // first parameter or ERROR[second parameter] - Run(*expr.get_argument_value(0), - Args{}.expect({type.get()->get_parameter_proxy(0), - state().add_error_of( - type.get()->get_parameter_proxy(1))})); + Run(expr.args.front().second, + Args{expr.args.front().second}.expect( + {type.get()->get_parameter_proxy(0), + state().add_error_of( + type.get()->get_parameter_proxy(1))})); break; case builtin::Type::ERROR: // first parameter - Run(*expr.get_argument_value(0), - Args{}.expect(type.get()->get_parameter_proxy(0))); + Run(expr.args.front().second, Args{expr.args.front().second}.expect( + type.get()->get_parameter_proxy(0))); break; case builtin::Type::FUNCTION: case builtin::Type::NONE: // type itself - Run(*expr.get_argument_value(0), Args{}.expect(type)); + Run(expr.args.front().second, + Args{expr.args.front().second}.expect(type)); break; default: // array, basic types - type_check_error("Type can't be constructed", expr, executor); + type_check_error("Type can't be constructed", current_pos, executor); break; } } // TODO: deduce generic parts in type - return type_check_from_args(expr.get_type_proxy(), args, expr, executor); + return type_check_from_args(expr.type, args, current_pos, executor); // TODO: add <- modifiier to type ?? } // IN PROGRESS @@ -809,27 +858,29 @@ Result CheckTask::operator()(const nodes::Constructor &expr, // TODO Result CheckTask::operator()(const nodes::Lambda &expr, const Args &args) { + const auto current_pos = PosOf(args.current_id); + if (args.get_expected().empty()) { type_check_error("Can't deduce type of lambda function from context: no " "one type expected", - expr, executor); + current_pos, executor); } if (args.get_expected().size() != 1) { // TODO: check if only one function argument type_check_error("Can't deduce type of lambda function from context; too " "much possible types", - expr, executor); + current_pos, executor); } const auto expected_type = args.get_expected().front(); if (!expected_type.get()->is_builtin(builtin::Type::FUNCTION)) { - type_check_error("Type of lambda function should be function", expr, + type_check_error("Type of lambda function should be function", current_pos, executor); } // TODO: deal with return type (+1 sometimes), etc - const auto args_given = expr.args_size(); + const auto args_given = expr.args.size(); const auto args_defined = expected_type.get()->parameters_size(); if (args_given != args_defined) { type_check_error( @@ -840,41 +891,38 @@ Result CheckTask::operator()(const nodes::Lambda &expr, ? (" or " + std::to_string(args_defined - 1)) : ""} + ")", - expr, executor); + current_pos, executor); } // TODO: set another context (for expression typecheck and vars) for (size_t i = 0; i < args_given; ++i) { if (!state().insert_variable( - *expr.get_argument(i)->get(), - expected_type.get()->get_parameter_proxy(i), + expr.args.at(i).value, expected_type.get()->get_parameter_proxy(i), nodes::NameDefinition::Kind::LET)) { // TODO: which modifier ?? - type_check_error("Variable is already defined in this context", expr, - executor); + type_check_error("Variable is already defined in this context", + current_pos, executor); } } // TODO: out type is can be not last if (args_given + 1 == args_defined) { - Run(*expr.get_expression(), - Args{}.expect( + Run(expr.expr, + Args{expr.expr}.expect( expected_type.get()->get_parameter_proxy(args_defined - 1))); } // TODO: needed ?? (only passed type check required ??) - return type_check_from_args(expected_type, args, expr, executor); + return type_check_from_args(expected_type, args, current_pos, executor); } // IN PROGRESS Result CheckTask::operator()(const nodes::Extra &, const Args &) { - return Result(state().primitive(builtin::Type::UNIT)); } Result CheckTask::operator()(const nodes::EmptyLines &, const Args &) { - return Result(state().primitive(builtin::Type::UNIT)); } diff --git a/lang/type_check/src/type_check_utils.cpp b/lang/type_check/src/type_check_utils.cpp index 852da79..722d8e2 100644 --- a/lang/type_check/src/type_check_utils.cpp +++ b/lang/type_check/src/type_check_utils.cpp @@ -200,7 +200,7 @@ void type_check_error(const std::string &message, const utils::Pos &, return; } - logc.Error({{message}} /* TODO: node */); + logc.Error({{message}} /* TODO: use pos */); } } // namespace type_check diff --git a/lang/type_check/xmake.lua b/lang/type_check/xmake.lua index 039f03e..08e52b8 100644 --- a/lang/type_check/xmake.lua +++ b/lang/type_check/xmake.lua @@ -3,10 +3,10 @@ includes("../nodes/xmake.lua") set_languages("c++20") --- target("lang.type_check") --- set_kind("static") --- add_includedirs("include", {public = true}) --- add_files("src/**.cpp") --- add_deps("lang.utils", "lang.nodes") --- set_warnings("allextra") -- , "error") --- set_rundir("$(projectdir)") +target("lang.type_check") + set_kind("static") + add_includedirs("include", {public = true}) + add_files("src/**.cpp") + add_deps("lang.utils", "lang.nodes") + set_warnings("allextra") -- , "error") + set_rundir("$(projectdir)")