diff --git a/releasenotes.md b/releasenotes.md index 84e480646..d2620038b 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Improve error reporting when using type names as the function argument #1750. - Improve ordering of method registration to support adding methods to generic modules with method constraints #1746 - Support experimental `@operator(construct)` operator overload. +- Allow using 'var' to declare lambdas in functions. ### Fixes - Fix case trying to initialize a `char[*]*` from a String. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 042393ee0..aefc97b1a 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4005,60 +4005,60 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) SEMA_ERROR(decl, "Constants need to have an initial value."); return decl_poison(decl); } - if (kind == VARDECL_LOCAL && !context_is_macro(context)) + ASSERT0(!decl->var.no_init); + if (kind == VARDECL_LOCAL && !context_is_macro(context) && init_expr->expr_kind != EXPR_LAMBDA) { - SEMA_ERROR(decl, "Defining a variable using 'var %s = ...' is only allowed inside a macro.", decl->name); + SEMA_ERROR(decl, "Defining a variable using 'var %s = ...' is only allowed inside a macro, or when defining a lambda.", decl->name); return decl_poison(decl); } - ASSERT0(!decl->var.no_init); - if (!type_info) + if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl); + if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); + if (global_level_var && !expr_is_runtime_const(init_expr)) { - if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl); - if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); - if (global_level_var && !expr_is_runtime_const(init_expr)) - { - SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time."); - return decl_poison(decl); - } - decl->type = init_expr->type; - switch (sema_resolve_storage_type(context, init_expr->type)) - { - case STORAGE_ERROR: - return decl_poison(decl); - case STORAGE_NORMAL: - break; - case STORAGE_WILDCARD: - SEMA_ERROR(init_expr, "No type can be inferred from the optional result."); - return decl_poison(decl); - case STORAGE_VOID: - SEMA_ERROR(init_expr, "You cannot initialize a value to 'void'."); - return decl_poison(decl); - case STORAGE_COMPILE_TIME: - if (init_expr->type == type_untypedlist) - { - SEMA_ERROR(init_expr, "The type of an untyped list cannot be inferred, you can try adding an explicit type to solve this."); - return decl_poison(decl); - } - if (decl->var.kind == VARDECL_CONST) - { - SEMA_ERROR(init_expr, "You cannot initialize a constant to %s, but you can assign the expression to a compile time variable.", type_invalid_storage_type_name(init_expr->type)); - return decl_poison(decl); - } - SEMA_ERROR(init_expr, "You can't store a compile time type in a variable."); - return decl_poison(decl); - case STORAGE_UNKNOWN: - SEMA_ERROR(init_expr, "You cannot initialize a value to %s as it has unknown size.", - type_quoted_error_string(init_expr->type)); - return decl_poison(decl); - } - if (!decl->alignment) - { - if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false; - } - if (!sema_analyse_variable_type(context, decl->type, init_expr->span)) return decl_poison(decl); - // Skip further evaluation. - goto EXIT_OK; + SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time."); + return decl_poison(decl); } + decl->type = init_expr->type; + switch (sema_resolve_storage_type(context, init_expr->type)) + { + case STORAGE_ERROR: + return decl_poison(decl); + case STORAGE_NORMAL: + break; + case STORAGE_WILDCARD: + SEMA_ERROR(init_expr, "No type can be inferred from the optional result."); + return decl_poison(decl); + case STORAGE_VOID: + SEMA_ERROR(init_expr, "You cannot initialize a value to 'void'."); + return decl_poison(decl); + case STORAGE_COMPILE_TIME: + if (init_expr->type == type_untypedlist) + { + SEMA_ERROR(init_expr, + "The type of an untyped list cannot be inferred, you can try adding an explicit type to solve this."); + return decl_poison(decl); + } + if (decl->var.kind == VARDECL_CONST) + { + SEMA_ERROR(init_expr, + "You cannot initialize a constant to %s, but you can assign the expression to a compile time variable.", + type_invalid_storage_type_name(init_expr->type)); + return decl_poison(decl); + } + SEMA_ERROR(init_expr, "You can't store a compile time type in a variable."); + return decl_poison(decl); + case STORAGE_UNKNOWN: + SEMA_ERROR(init_expr, "You cannot initialize a value to %s as it has unknown size.", + type_quoted_error_string(init_expr->type)); + return decl_poison(decl); + } + if (!decl->alignment) + { + if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false; + } + if (!sema_analyse_variable_type(context, decl->type, init_expr->span)) return decl_poison(decl); + // Skip further evaluation. + goto EXIT_OK; } if (!sema_resolve_type_info(context, type_info, diff --git a/test/test_suite/lambda/var_lambda.c3 b/test/test_suite/lambda/var_lambda.c3 new file mode 100644 index 000000000..44d0530a5 --- /dev/null +++ b/test/test_suite/lambda/var_lambda.c3 @@ -0,0 +1,8 @@ +module test; +import std; +fn void main() +{ + var x = fn int(int y) { return y * 2; }; + io::printn(x(4)); + io::printn(x(3)); +} \ No newline at end of file