part of constuctor typecheck (constructors for different types)

This commit is contained in:
ProgramSnail 2024-02-22 21:57:54 +03:00
parent 005fb6aaf3
commit d7f1b6c377
3 changed files with 217 additions and 59 deletions

View file

@ -177,9 +177,10 @@ inline std::optional<size_t> get_parameters_count(Type type) {
return std::nullopt; return std::nullopt;
case Type::ARRAY: case Type::ARRAY:
case Type::OPTIONAL: case Type::OPTIONAL:
case Type::RESULT:
case Type::ERROR: case Type::ERROR:
return 1; return 1;
case Type::RESULT: // RESULT[T E] = T | Error[E]
return 2;
// -- basic types // -- basic types
case Type::FLOAT: case Type::FLOAT:
case Type::DOUBLE: case Type::DOUBLE:

View file

@ -243,6 +243,21 @@ public:
std::move(parameters))); 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<nodes::TypeProxy> 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<TypeProxy> &&parameters, nodes::TypeProxy add_container_of(std::vector<TypeProxy> &&parameters,
builtin::types::Type container, builtin::types::Type container,
Node node = Node()) { Node node = Node()) {

View file

@ -541,7 +541,8 @@ type_check_name_expression(const nodes::NameExpression &expression,
const Arguments &arguments) { const Arguments &arguments) {
// TODO: constraints ?? // 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 // TODO: check, if there is variable with this name
const auto maybe_function_definition = find_name_definition_handle_errors( const auto maybe_function_definition = find_name_definition_handle_errors(
@ -665,12 +666,8 @@ type_check_constructor(const nodes::Constructor &expression,
// TODO: work with different parametric types: tuple, variant, ... // TODO: work with different parametric types: tuple, variant, ...
if (expression.arguments_size() != if (expression.arguments_size() == 0) {
type.get()->parameters_size()) { // other, when there is passed type type_check_error("Number of type constructor arguments should be > 0",
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); expression, sources_manager);
return nodes::TypeCheckResult::construct_invalid_result(); return nodes::TypeCheckResult::construct_invalid_result();
// TODO: try return correct type (constructor's type), when possible (not // TODO: try return correct type (constructor's type), when possible (not
@ -681,17 +678,66 @@ type_check_constructor(const nodes::Constructor &expression,
const auto builtin_type = type.get()->to_builtin(); const auto builtin_type = type.get()->to_builtin();
{ // check arguments size, ets.
switch (builtin_type) { switch (builtin_type) {
case builtin::types::Type::TUPLE: case builtin::types::Type::TUPLE:
// for tuple if (expression.arguments_size() != type.get()->parameters_size()) {
for (size_t i = 0; i < expression.arguments_size(); type_check_error(
++i) { // TODO: deduce order by annotations "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)
}
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)
}
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<size_t> chosen_variant_option; // for VARIANT
{ // check annotations
const auto check_same_annotation =
[&expression, &sources_manager](
size_t i, std::optional<const std::string *> expected_annotation,
bool log_errors) {
bool is_same = true;
const auto annotation = expression.get_argument_annotation(i); 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()) { if (annotation.has_value() != expected_annotation.has_value()) {
if (log_errors) {
type_check_error( type_check_error(
"Wrong type constructor argument annotation: should be " + "Wrong type constructor argument annotation: should be " +
std::string{expected_annotation.has_value() std::string{expected_annotation.has_value()
@ -699,43 +745,139 @@ type_check_constructor(const nodes::Constructor &expression,
: "[none]"}, : "[none]"},
*expression.get_argument_value(i), sources_manager); *expression.get_argument_value(i), sources_manager);
} }
is_same = false;
}
if (annotation.has_value() && if (annotation.has_value() &&
*annotation.value() != *expected_annotation.value()) { *annotation.value() != *expected_annotation.value()) {
type_check_error( if (log_errors) {
"Wrong function argument type annotation: " + *annotation.value() + type_check_error("Wrong function argument type annotation: " +
" instead of " + *expected_annotation.value(), *annotation.value() + " instead of " +
*expression.get_argument_value(i), sources_manager); *expected_annotation.value(),
*expression.get_argument_value(i),
sources_manager);
} }
type_check_expression( is_same = false;
*expression.get_argument_value(i), sources_manager, state, }
Arguments{}.expect(type.get()->get_parameter_proxy(i)));
// TODO: do something with argument type ?? 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; break;
case builtin::types::Type::VARIANT: case builtin::types::Type::VARIANT:
// TODO: expect one of types // 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; break;
case builtin::types::Type::OPTIONAL: case builtin::types::Type::OPTIONAL:
// TODO: expect type (generic) or NULL
break;
case builtin::types::Type::RESULT: 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: case builtin::types::Type::FUNCTION:
// TODO: built from one value (function)
break;
case builtin::types::Type::NONE: case builtin::types::Type::NONE:
// TODO: built from one value check_no_annotation(0, true /*log errors*/);
break; break;
default: // array, basic types default: // array, basic types
type_check_error("Type can't be constructed", expression, sources_manager);
break; 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;
}
}
// TODO: deduce generic parts in type // TODO: deduce generic parts in type
return type_check_from_arguments(expression.get_type_proxy(), arguments, return type_check_from_arguments(expression.get_type_proxy(), arguments,