Allow type inference on enum comparisons. Add chdir. Fix bug when command was missing. Allow {} on basic types.

This commit is contained in:
Christoffer Lerno
2023-03-13 16:25:03 +01:00
parent fb761b0cc5
commit 1b27264f07
10 changed files with 109 additions and 8 deletions

42
lib/std/io/os/chdir.c3 Normal file
View File

@@ -0,0 +1,42 @@
module std::io::os;
import libc;
$if (!env::COMPILER_LIBC_AVAILABLE):
fn void! native_chdir(Path path)
{
unreachable("'getcwd' not available");
}
$elif (env::OS_TYPE == OsType.WIN32):
macro void! native_chdir(Path path)
{
@pool()
{
if (files::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return;
};
return IoError.GENERAL_ERROR!;
}
$else:
extern fn int _chdir(ZString) @extern("chdir");
macro void! native_chdir(Path p)
{
if (_chdir((ZString)p.as_str()))
{
switch (libc::errno())
{
case errno::EACCES: return IoError.NO_PERMISSION!;
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG!;
case errno::ENOTDIR: return IoError.FILE_NOT_DIR!;
case errno::ENOENT: return IoError.FILE_NOT_FOUND!;
case errno::ELOOP: return IoError.SYMLINK_FAILED!;
default: return IoError.GENERAL_ERROR!;
}
}
}
$endif;

View File

@@ -40,6 +40,7 @@ fn bool is_file(Path path) => os::native_is_file(path.as_str());
fn usz! file_size(Path path) => os::native_file_size(path.as_str());
fn bool exists(Path path) => os::native_file_or_dir_exists(path.as_str());
fn Path! tgetcwd() => getcwd(mem::temp()) @inline;
fn void! chdir(Path path) => os::native_chdir(path) @inline;
fn Path! temp_directory(Allocator* using = mem::heap()) => os::native_temp_directory(using);
macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV)

View File

@@ -27,6 +27,7 @@ struct Win32_FILE_ATTRIBUTE_DATA
extern fn bool win32_GetFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @extern("GetFileAttributesExW");
extern fn bool win32_PathFileExistsW(Win32_LPCWSTR) @extern("PathFileExistsW");
extern fn Win32_DWORD win32_GetTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @extern("GetTempPathW");
extern fn bool win32_SetCurrentDirectoryW(Win32_LPCTSTR buffer) @extern("SetCurrentDirectoryW");
/*
extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW");

View File

@@ -898,6 +898,10 @@ BuildOptions parse_arguments(int argc, const char *argv[])
}
FAIL_WITH_ERR("Found the unexpected argument \"%s\".", current_arg);
}
if (build_options.command == COMMAND_MISSING)
{
FAIL_WITH_ERR("Missing a compiler command such as 'compile' or 'build'.");
}
return build_options;
}

View File

@@ -931,6 +931,24 @@ static inline bool sema_binary_promote_top_down(SemaContext *context, Expr *bina
static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *binary, Expr *left, Expr *right)
{
// Special handling of f = FOO_BAR
if (right->expr_kind == EXPR_IDENTIFIER && right->identifier_expr.is_const)
{
if (!sema_analyse_expr(context, left)) return false;
if (type_flatten(left->type)->type_kind == TYPE_ENUM)
{
return sema_analyse_inferred_expr(context, left->type, right);
}
}
// Special handling of f = FOO_BAR
if (left->expr_kind == EXPR_IDENTIFIER && left->identifier_expr.is_const)
{
if (!sema_analyse_expr(context, right)) return false;
if (type_flatten(right->type)->type_kind == TYPE_ENUM)
{
return sema_analyse_inferred_expr(context, right->type, left);
}
}
if (right->expr_kind == EXPR_INITIALIZER_LIST)
{
if (!sema_analyse_expr(context, left)) return false;
@@ -2103,11 +2121,11 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
case EXPR_TYPEINFO:
if (func_expr->type_expr->resolve_status == RESOLVE_DONE)
{
SEMA_ERROR(expr, "A type cannot be followed by (), if you intended a cast, use (type)(expression).");
SEMA_ERROR(expr, "A type cannot be followed by (), if you intended a cast, use '(type) expression'.");
}
else
{
SEMA_ERROR(expr, "A type cannot be followed by (), did you mean to use {}?");
SEMA_ERROR(expr, "A type cannot be followed by (), did you mean to use 'type {}'?");
}
return false;
default:

View File

@@ -528,6 +528,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
if (!to) to = type_untypedlist;
assert(to);
Type *flattened = type_flatten(to);
bool is_zero_init = expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list);
switch (flattened->type_kind)
{
case TYPE_UNTYPED_LIST:
@@ -541,7 +542,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
return sema_expr_analyse_initializer(context, to, flattened, expr);
case TYPE_SUBARRAY:
{
if (expr->expr_kind == EXPR_INITIALIZER_LIST && !vec_size(expr->initializer_list))
if (is_zero_init)
{
expr->expr_kind = EXPR_CONST;
expr->const_expr.const_kind = CONST_POINTER;
@@ -561,12 +562,31 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex
SEMA_ERROR(expr, "Scaled vectors cannot be initialized using an initializer list, since the length is not known at compile time.");
return false;
case TYPE_POINTER:
if (is_zero_init)
{
expr_rewrite_to_const_zero(expr, to);
return true;
}
SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array.");
return false;
case TYPE_VOID:
case TYPE_POISONED:
case TYPE_FUNC:
case TYPE_TYPEDEF:
case TYPE_OPTIONAL_ANY:
case TYPE_OPTIONAL:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
break;
default:
if (is_zero_init)
{
expr_rewrite_to_const_zero(expr, flattened);
expr->type = to;
return true;
}
break;
}
// Fix error on compound literals
SEMA_ERROR(expr, "'%s' cannot use compound literal initialization, did you intend to use a cast?", type_to_error_string(to));
return false;
}

View File

@@ -367,7 +367,7 @@ static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *state
}
else
{
if (block_type && block_type != type_void)
if (block_type && type_no_optional(block_type) != type_void)
{
SEMA_ERROR(statement, "Expected a return value of type %s here.", type_quoted_error_string(block_type));
return false;
@@ -966,9 +966,24 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
}
return true;
}
// 3a. Check for optional in case of an expression.
if (IS_OPTIONAL(last))
{
if (type_no_optional(last->type) == type_void && cast_to_bool)
{
Expr *catch = expr_new_expr(EXPR_CATCH, last);
catch->expr_kind = EXPR_CATCH;
catch->inner_expr = expr_copy(last);
catch->type = type_anyerr;
catch->resolve_status = RESOLVE_DONE;
catch->inner_expr->resolve_status = RESOLVE_DONE;
last->expr_kind = EXPR_UNARY;
last->unary_expr.operator = UNARYOP_NOT;
last->unary_expr.expr = catch;
last->type = type_bool;
return true;
}
SEMA_ERROR(last, "The expression may not be an optional, but was %s.", type_quoted_error_string(last->type));
return false;
}

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.107"
#define COMPILER_VERSION "0.4.108"

View File

@@ -7,7 +7,7 @@ fn void test2()
fn void test3()
{
int x = int(32); // #error: A type cannot be followed by (), if you intended a cast, use (type)(expression)
int x = int(32); // #error: A type cannot be followed by (), if you intended a cast, use '(type) expression'
}

View File

@@ -4,5 +4,5 @@ struct Foo { int a; }
fn void test1()
{
(Foo)({ 32 });
Foo({ 32 }); // #error: A type cannot be followed by (), if you intended a cast, use (type)(expression)
Foo({ 32 }); // #error: A type cannot be followed by (), if you intended a cast, use '(type) expression'
}