mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-06 06:58:46 +00:00
type check error function
This commit is contained in:
parent
61fa3a19a0
commit
1a9408c2f6
4 changed files with 83 additions and 84 deletions
|
|
@ -186,7 +186,8 @@ private:
|
||||||
class ContextHolder {
|
class ContextHolder {
|
||||||
public:
|
public:
|
||||||
ContextHolder(State &state, const nodes::Node &node,
|
ContextHolder(State &state, const nodes::Node &node,
|
||||||
error_handling::ErrorLog &error_log, nodes::MaybeTypeProxy* context_exit_type)
|
error_handling::ErrorLog &error_log,
|
||||||
|
nodes::MaybeTypeProxy *context_exit_type)
|
||||||
: state_(state), context_exit_type_(context_exit_type) {
|
: state_(state), context_exit_type_(context_exit_type) {
|
||||||
state.enter_context(node, error_log);
|
state.enter_context(node, error_log);
|
||||||
}
|
}
|
||||||
|
|
@ -198,16 +199,16 @@ public:
|
||||||
ContextHolder &operator=(ContextHolder &&) = delete;
|
ContextHolder &operator=(ContextHolder &&) = delete;
|
||||||
|
|
||||||
~ContextHolder() {
|
~ContextHolder() {
|
||||||
if (context_exit_type_) {
|
if (context_exit_type_) {
|
||||||
*context_exit_type_ = state_.exit_context();
|
*context_exit_type_ = state_.exit_context();
|
||||||
} else {
|
} else {
|
||||||
state_.exit_context();
|
state_.exit_context();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
State &state_;
|
State &state_;
|
||||||
nodes::MaybeTypeProxy* context_exit_type_;
|
nodes::MaybeTypeProxy *context_exit_type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes::TypeCheckResult type_same_to_expected(
|
nodes::TypeCheckResult type_same_to_expected(
|
||||||
|
|
@ -225,4 +226,7 @@ find_name_definition_handle_errors(const std::string &name,
|
||||||
const nodes::Node &node,
|
const nodes::Node &node,
|
||||||
SourcesManager &sources_manager);
|
SourcesManager &sources_manager);
|
||||||
|
|
||||||
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
|
SourcesManager &sources_manager);
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,19 @@ inline void handle_general_error(const std::string &message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace error_handling
|
} // namespace error_handling
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
// in std from c++23
|
||||||
|
[[noreturn]] inline void unreachable() {
|
||||||
|
// Uses compiler specific extensions if possible.
|
||||||
|
// Even if no extension is used, undefined behavior is still raised by
|
||||||
|
// an empty function body and the noreturn attribute.
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||||
|
__assume(false);
|
||||||
|
#else // GCC, Clang
|
||||||
|
__builtin_unreachable();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
// IN PROGRESS
|
// IN PROGRESS
|
||||||
|
|
||||||
// TODO: typecheck pass in all functions
|
// TODO: typecheck pass in all functions
|
||||||
|
// TODO: assign types in nodes
|
||||||
|
|
||||||
namespace type_check {
|
namespace type_check {
|
||||||
|
|
||||||
|
|
@ -78,6 +79,8 @@ type_check_expression(const nodes::Expression &expression,
|
||||||
sources_manager.get_type_storage()->primitive_type(
|
sources_manager.get_type_storage()->primitive_type(
|
||||||
builtin::types::Type::UNIT));
|
builtin::types::Type::UNIT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- flow control
|
// --- flow control
|
||||||
|
|
@ -91,10 +94,7 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
|
||||||
|
|
||||||
// x :=/=: ...
|
// x :=/=: ...
|
||||||
if (value_result.is_invalid()) {
|
if (value_result.is_invalid()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Match value is invalid", expression, sources_manager);
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
|
||||||
expression, "Match value is invalid",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nodes::TypeCheckResult> expression_result;
|
std::optional<nodes::TypeCheckResult> expression_result;
|
||||||
|
|
@ -139,11 +139,11 @@ nodes::TypeCheckResult type_check_match(const nodes::Match &expression,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (at_least_one_case_with_expression && at_least_one_case_without_expression) {
|
if (at_least_one_case_with_expression &&
|
||||||
sources_manager.get_error_log()->add_error(
|
at_least_one_case_without_expression) {
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
type_check_error(
|
||||||
expression, "all cases should be with or without expression at the same time",
|
"All cases should be with or without expression at the same time",
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
expression, sources_manager);
|
||||||
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,10 +191,8 @@ nodes::TypeCheckResult type_check_condition(const nodes::Condition &expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expression_result.has_value()) {
|
if (!expression_result.has_value()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("There should be at least one case in if statement",
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
expression, sources_manager);
|
||||||
expression, "There should be at least one case in if statement",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
expression_result = nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,10 +219,10 @@ nodes::TypeCheckResult type_check_loop(const nodes::Loop &expression,
|
||||||
case nodes::Loop::LOOP: // infinity loop, no params
|
case nodes::Loop::LOOP: // infinity loop, no params
|
||||||
break;
|
break;
|
||||||
case nodes::Loop::WHILE:
|
case nodes::Loop::WHILE:
|
||||||
type_check_expression(
|
type_check_expression(*expression.get_condition().value(), sources_manager,
|
||||||
*expression.get_condition().value(), sources_manager, state,
|
state,
|
||||||
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
|
Arguments{}.expect_builtin(builtin::types::Type::BOOL,
|
||||||
sources_manager));
|
sources_manager));
|
||||||
|
|
||||||
// --- type check is independent from loop itself ---
|
// --- type check is independent from loop itself ---
|
||||||
// if (condition_result.value().is_invalid()) {
|
// if (condition_result.value().is_invalid()) {
|
||||||
|
|
@ -285,21 +283,16 @@ nodes::TypeCheckResult type_check_array(const nodes::Container &expression,
|
||||||
last_expression_result = expression_result;
|
last_expression_result = expression_result;
|
||||||
} else {
|
} else {
|
||||||
if (last_expression_result.value().get() != expression_result.get()) {
|
if (last_expression_result.value().get() != expression_result.get()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Elements in array should have same type",
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
*expression.get_expression(i), sources_manager);
|
||||||
*expression.get_expression(i),
|
// return nodes::TypeCheckResult::construct_invalid_result(); // max
|
||||||
"Elements in array should have same type",
|
// possible checks, so no return
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
// return nodes::TypeCheckResult::construct_invalid_result(); // max possible checks, so no return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last_expression_result.has_value()) {
|
if (!last_expression_result.has_value()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Array with zero elements", expression, sources_manager);
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
|
||||||
expression, "Array with zero elements",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,9 +309,9 @@ nodes::TypeCheckResult type_check_block(const nodes::Container &expression,
|
||||||
nodes::MaybeTypeProxy context_exit_type;
|
nodes::MaybeTypeProxy context_exit_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
ContextHolder context_holder(state, expression,
|
ContextHolder context_holder(
|
||||||
*sources_manager.get_error_log(),
|
state, expression, *sources_manager.get_error_log(),
|
||||||
&context_exit_type); // TODO: is brought type returned
|
&context_exit_type); // TODO: is brought type returned
|
||||||
|
|
||||||
for (size_t i = 0; i < expression.expressions_size(); ++i) {
|
for (size_t i = 0; i < expression.expressions_size(); ++i) {
|
||||||
// result types in block are discarded
|
// result types in block are discarded
|
||||||
|
|
@ -368,19 +361,15 @@ nodes::TypeCheckResult type_check_return(const nodes::Return &expression,
|
||||||
switch (expression.get_type()) {
|
switch (expression.get_type()) {
|
||||||
case nodes::Return::BRING:
|
case nodes::Return::BRING:
|
||||||
if (state.bring_type(returned_result.get())) {
|
if (state.bring_type(returned_result.get())) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Different brought type to current one", expression,
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
sources_manager);
|
||||||
expression, "Different brought type to current one",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nodes::Return::RETURN:
|
case nodes::Return::RETURN:
|
||||||
if (!state.return_type(returned_result.get())) {
|
if (!state.return_type(returned_result.get())) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Different returned type to current one", expression,
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
sources_manager);
|
||||||
expression, "Different returned type to current one",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -397,10 +386,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
||||||
SourcesManager &sources_manager, State &state,
|
SourcesManager &sources_manager, State &state,
|
||||||
const Arguments &arguments) {
|
const Arguments &arguments) {
|
||||||
if (!arguments.get_passed().has_value()) {
|
if (!arguments.get_passed().has_value()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Can't deduce type of new variable from context",
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
expression, sources_manager);
|
||||||
expression, "Can't deduce type of new variable from context",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// assigned type shold be one of <-, <>, -- (can't be ->)
|
// assigned type shold be one of <-, <>, -- (can't be ->)
|
||||||
|
|
@ -408,10 +395,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
||||||
if (nodes::utils::modifier_contains_OUT(
|
if (nodes::utils::modifier_contains_OUT(
|
||||||
variable_type.get()
|
variable_type.get()
|
||||||
->get_modifier())) { // TODO: utils::modifier_contains_OUT
|
->get_modifier())) { // TODO: utils::modifier_contains_OUT
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Variable can't be assigned from out (->) value",
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
expression, sources_manager);
|
||||||
expression, "Variabla cant be asignet from out (->) value",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// variable accessible by reference by default ??
|
// variable accessible by reference by default ??
|
||||||
|
|
@ -420,10 +405,8 @@ type_check_name_definition(const nodes::NameDefinition &expression,
|
||||||
|
|
||||||
if (!state.insert_variable(*expression.get_name()->get(), variable_type,
|
if (!state.insert_variable(*expression.get_name()->get(), variable_type,
|
||||||
expression.get_modifier())) {
|
expression.get_modifier())) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Variable is already defined in this context", expression,
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
sources_manager);
|
||||||
expression, "Variable is already defined in this context",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return BOOL as any := / =: expression
|
// Return BOOL as any := / =: expression
|
||||||
|
|
@ -535,10 +518,8 @@ type_check_modifier_expression(const nodes::ModifierExpression &expression,
|
||||||
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
|
modified_result.set(modified_result.get().get()->get_parameter_proxy(0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Can unwrap only Optional or Result", expression,
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
sources_manager);
|
||||||
expression, "Can unwrap only Optional or Result",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -572,11 +553,9 @@ type_check_constructor(const nodes::Constructor &expression,
|
||||||
const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
|
const nodes::TypeDefinition *type_definition = maybe_type_definition.value();
|
||||||
|
|
||||||
if (!type_definition->get_type().has_value()) {
|
if (!type_definition->get_type().has_value()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error(
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
"Type defenition for constructor type not found (declaration only)",
|
||||||
expression,
|
expression, sources_manager);
|
||||||
"Type defenition for constructor type not found (declaration only)",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,16 +571,13 @@ type_check_constructor(const nodes::Constructor &expression,
|
||||||
// TODO: work with different parametric types: tuple, variant, ...
|
// TODO: work with different parametric types: tuple, variant, ...
|
||||||
|
|
||||||
if (type.get()->parameters_size() != expression.arguments_size()) {
|
if (type.get()->parameters_size() != expression.arguments_size()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Constructor arguments count is " +
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
std::string{expression.arguments_size() <
|
||||||
expression,
|
type.get()->parameters_size()
|
||||||
"Constructor arguments count is " +
|
? "less"
|
||||||
std::string{expression.arguments_size() <
|
: "more"} +
|
||||||
type.get()->parameters_size()
|
" then type fields count",
|
||||||
? "less"
|
expression, sources_manager);
|
||||||
: "more"} +
|
|
||||||
" then type fields count",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
return nodes::TypeCheckResult::construct_invalid_result();
|
return nodes::TypeCheckResult::construct_invalid_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -627,18 +603,14 @@ nodes::TypeCheckResult type_check_lambda(const nodes::Lambda &expression,
|
||||||
State &state,
|
State &state,
|
||||||
const Arguments &arguments) {
|
const Arguments &arguments) {
|
||||||
if (!arguments.get_expected().has_value()) {
|
if (!arguments.get_expected().has_value()) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Can't deduce type of lambda function from context",
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
expression, sources_manager);
|
||||||
expression, "Can't deduce type of lambda function from context",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto expected_type = arguments.get_expected().value();
|
const auto expected_type = arguments.get_expected().value();
|
||||||
if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) {
|
if (!expected_type.get()->is_builtin(builtin::types::Type::FUNCTION)) {
|
||||||
sources_manager.get_error_log()->add_error(
|
type_check_error("Type of lambda function should be function", expression,
|
||||||
error_handling::ErrorLog::ErrorMessage(
|
sources_manager);
|
||||||
expression, "Type of lambda function should be function",
|
|
||||||
error_handling::ErrorType::TYPE_CHECK));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: define vars
|
// TODO: define vars
|
||||||
|
|
|
||||||
|
|
@ -65,4 +65,11 @@ find_name_definition_handle_errors(const std::string &name,
|
||||||
"Node in name tree is not name definition");
|
"Node in name tree is not name definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void type_check_error(const std::string &message, const nodes::Node &node,
|
||||||
|
SourcesManager &sources_manager) {
|
||||||
|
sources_manager.get_error_log()->add_error(
|
||||||
|
error_handling::ErrorLog::ErrorMessage(
|
||||||
|
node, message, error_handling::ErrorType::TYPE_CHECK));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace type_check
|
} // namespace type_check
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue