Updates to file:: and path::, Path is now passed an allocator. path::traverse function. mkdir / rmdir / chdir works directly with strings. Strings get file_basepath, path_dirname. Test suite runner now uses lib7. Bug when printing a parameter declaration error. Fix optional jumps in expression lists, #1942.

This commit is contained in:
Christoffer Lerno
2025-02-25 00:40:28 +01:00
committed by Christoffer Lerno
parent 1dfc24822e
commit 062a67fe75
11 changed files with 410 additions and 300 deletions

View File

@@ -95,7 +95,7 @@ jobs:
- name: run compiler tests
run: |
cd test
..\build\${{ matrix.build_type }}\c3c.exe compile-run -O1 src/test_suite_runner.c3 --enable-new-generics -- ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
..\build\${{ matrix.build_type }}\c3c.exe compile-run -O1 src/test_suite_runner.c3 --stdlib ..\lib7 --enable-new-generics -- ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
- name: Test python script
run: |
@@ -168,7 +168,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c.exe compile --target windows-x64 -O1 src/test_suite_runner.c3 --enable-new-generics
../build/c3c.exe compile --target windows-x64 -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
./test_suite_runner.exe ../build/c3c.exe test_suite/
build-msys2-clang:
@@ -220,7 +220,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c.exe compile-run -O1 src/test_suite_runner.c3 --enable-new-generics
../build/c3c.exe compile-run -O1 --stdlib ../lib7 src/test_suite_runner.c3 --enable-new-generics
build-linux:
runs-on: ubuntu-22.04
@@ -381,7 +381,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --enable-new-generics -- ../build/c3c test_suite/
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
@@ -502,7 +502,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --enable-new-generics -- ../build/c3c test_suite/
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
@@ -606,7 +606,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --enable-new-generics -- ../build/c3c test_suite/
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite/
build-mac:
runs-on: macos-latest
@@ -686,13 +686,13 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile -O1 src/test_suite_runner.c3 --enable-new-generics
../build/c3c compile -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
./test_suite_runner ../build/c3c test_suite/
- name: run build test suite runner
run: |
cd test
../build/c3c compile -O1 src/test_suite_runner.c3 --enable-new-generics
../build/c3c compile -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC

View File

@@ -21,7 +21,7 @@ fn File! open_path(Path path, String mode)
fn bool exists(String file) => @pool()
{
return path::exists(path::tnew(file)) ?? false;
return os::native_file_or_dir_exists(file);
}
fn File from_handle(CFile file)
@@ -34,12 +34,20 @@ fn bool is_file(String path)
return os::native_is_file(path);
}
fn bool is_dir(String path)
{
return os::native_is_dir(path);
}
fn usz! get_size(String path)
{
return os::native_file_size(path);
}
fn void! delete(String filename) => os::native_remove(filename) @inline;
fn void! delete(String filename)
{
return os::native_remove(filename) @inline;
}
<*

View File

@@ -2,7 +2,7 @@ module std::io::path;
import std::collections::list, std::io::os;
import std::os::win32;
const PathEnv DEFAULT_PATH_ENV = env::WIN32 ? PathEnv.WIN32 : PathEnv.POSIX;
const PathEnv DEFAULT_ENV = env::WIN32 ? PathEnv.WIN32 : PathEnv.POSIX;
const char PREFERRED_SEPARATOR_WIN32 = '\\';
const char PREFERRED_SEPARATOR_POSIX = '/';
const char PREFERRED_SEPARATOR = env::WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
@@ -21,6 +21,7 @@ struct PathImp (Printable)
{
String path_string;
PathEnv env;
Allocator allocator;
}
enum PathEnv
@@ -42,24 +43,35 @@ fn bool is_file(Path path) => os::native_is_file(path.str_view());
fn usz! file_size(Path path) => os::native_file_size(path.str_view());
fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view());
fn Path! tcwd() => cwd(tmem()) @inline;
fn void! chdir(Path path) => os::native_chdir(path) @inline;
<*
@require @is_pathlike(path) : "Expected a Path or String to chdir"
*>
macro void! chdir(path)
{
$if @typeis(path, String):
@pool()
{
return os::native_chdir(tnew(path));
};
$else
return os::native_chdir(path) @inline;
$endif
}
fn Path! temp_directory(Allocator allocator) => os::native_temp_directory(allocator);
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV)
macro bool @is_pathlike(#path) => @typeis(#path, String) || @typeis(#path, Path);
macro bool is_separator(char c, PathEnv path_env = DEFAULT_ENV)
{
return c == '/' || (c == '\\' && path_env == PathEnv.WIN32);
}
macro bool is_posix_separator(char c)
{
return c == '/' || c == '\\';
}
macro bool is_win32_separator(char c)
{
return c == '/' || c == '\\';
}
macro bool is_posix_separator(char c) => c == '/';
macro bool is_win32_separator(char c) => c == '/' || c == '\\';
fn PathList! ls(Allocator allocator, Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "")
{
@@ -81,35 +93,35 @@ enum MkdirPermissions
Create a directory on a given path, optionally recursive.
@param path `The path to create`
@require @is_pathlike(path) : "Expected a Path or String to chdir"
@param recursive `If directories in between should be created if they're missing, defaults to false`
@param permissions `The permissions to set on the directory`
*>
fn bool! mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL)
macro bool! mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL)
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
if (is_dir(path)) return false;
if (exists(path)) return IoError.FILE_NOT_DIR?;
if (recursive)
{
if (try parent = path.parent()) mkdir(parent, true, permissions)!;
$if @typeis(path, String):
@pool() { return _mkdir(tnew(path), recursive, permissions); };
$else
return _mkdir(path, recursive, permissions);
$endif
}
if (!is_dir(path.parent()) ?? false) return IoError.CANNOT_READ_DIR?;
return os::native_mkdir(path, permissions);
}
<*
Tries to delete directory, which must be empty.
@param path `The path to delete`
@require @is_pathlike(path) : "Expected a Path or String to chdir"
@return `true if there was a directory to delete, false otherwise`
@return! PathResult.INVALID_PATH `if the path was invalid`
*>
fn bool! rmdir(Path path)
macro bool! rmdir(path)
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
return os::native_rmdir(path);
$if @typeis(path, String):
@pool() { return _rmdir(tnew(path)); };
$else
return _mkdir(path);
$endif
}
<*
@@ -130,9 +142,9 @@ fn void! rmtree(Path path)
@return! PathResult.INVALID_PATH `if the path was invalid`
*>
fn Path! new(Allocator allocator, String path, PathEnv path_env = DEFAULT_PATH_ENV)
fn Path! new(Allocator allocator, String path, PathEnv path_env = DEFAULT_ENV)
{
return { normalize(path.copy(allocator), path_env), path_env };
return { normalize(path.copy(allocator), path_env), path_env, allocator };
}
<*
@@ -140,7 +152,7 @@ fn Path! new(Allocator allocator, String path, PathEnv path_env = DEFAULT_PATH_E
@return! PathResult.INVALID_PATH `if the path was invalid`
*>
fn Path! tnew(String path, PathEnv path_env = DEFAULT_PATH_ENV)
fn Path! tnew(String path, PathEnv path_env = DEFAULT_ENV)
{
return new(tmem(), path, path_env);
}
@@ -181,33 +193,37 @@ fn Path! Path.append(self, Allocator allocator, String filename)
dstr.append(self.path_string);
dstr.append(PREFERRED_SEPARATOR);
dstr.append(filename);
return { normalize(dstr.copy_str(allocator), self.env), self.env };
return new(allocator, dstr.str_view(), self.env);
};
}
fn Path! Path.tappend(self, String filename) => self.append(tmem(), filename);
fn usz Path.start_of_base_name(self) @local
fn usz! start_of_base_name(String str, PathEnv path_env) @local
{
String path_str = self.path_string;
if (!path_str.len) return 0;
if (self.env == PathEnv.WIN32)
{
if (try index = path_str.rindex_of_char('\\'))
if (!str.len) return PathResult.INVALID_PATH?;
usz! start_slash = str.rindex_of_char('/');
if (path_env != PathEnv.WIN32) return start_slash + 1 ?? 0;
if (try index = str.rindex_of_char('\\'))
{
if (try start_slash && start_slash > index) return start_slash + 1;
// c:\ style path, we're done!
if (path_str[0] != '\\') return index + 1;
if (str[0] != '\\') return index + 1;
// Handle \\server\foo
// Find the \ before "foo"
usz last_index = 2 + path_str[2..].index_of_char('\\')!!;
usz last_index = 2 + str[2..].index_of_char('\\')!;
// If they don't match, we're done
assert(last_index <= index, "Invalid normalized, path %d vs %s in %s", last_index, index, path_str);
if (last_index > index) return PathResult.INVALID_PATH?;
if (last_index != index) return index + 1;
// Otherwise just default to the volume length.
}
return volume_name_len(path_str, self.env)!!;
return volume_name_len(str, path_env)!!;
}
return path_str.rindex_of_char('/') + 1 ?? 0;
fn bool! String.is_absolute_path(self) => @pool()
{
return tnew(self).is_absolute();
}
fn bool! Path.is_absolute(self)
@@ -220,8 +236,13 @@ fn bool! Path.is_absolute(self)
}
fn Path! String.to_absolute_path(self, Allocator allocator) => @pool(allocator)
{
return tnew(self).absolute(allocator);
}
<*
@require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths"
@require self.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn Path! Path.absolute(self, Allocator allocator)
{
@@ -236,34 +257,47 @@ fn Path! Path.absolute(self, Allocator allocator)
return new(allocator, cwd, self.env);
};
}
$if DEFAULT_PATH_ENV == WIN32:
$if DEFAULT_ENV == WIN32:
@pool(allocator)
{
const usz BUFFER_LEN = 4096;
WString buffer = (WString)mem::temp_alloc_array(Char16, BUFFER_LEN);
buffer = win32::_wfullpath(buffer, path_str.to_wstring_tcopy()!, BUFFER_LEN);
if (!buffer) return PathResult.INVALID_PATH?;
return { string::new_from_wstring(allocator, buffer), WIN32 };
return { string::new_from_wstring(allocator, buffer), WIN32, allocator };
};
$else
String cwd = os::getcwd(tmem())!;
return (Path){ cwd, self.env }.append(allocator, path_str)!;
return (Path){ cwd, self.env, tmem() }.append(allocator, path_str)!;
$endif
}
fn String! String.file_basename(self, Allocator allocator) => @pool(allocator)
{
return tnew(self).basename().copy(allocator);
}
fn String! String.file_tbasename(self) => self.file_basename(tmem());
fn String Path.basename(self)
{
usz basename_start = self.start_of_base_name();
usz basename_start = start_of_base_name(self.path_string, self.env)!!;
String path_str = self.path_string;
if (basename_start == path_str.len) return "";
return path_str[basename_start..];
}
fn String! String.path_tdirname(self) => self.path_dirname(tmem());
fn String! String.path_dirname(self, Allocator allocator) => @pool(allocator)
{
return tnew(self).dirname().copy(allocator);
}
fn String Path.dirname(self)
{
usz basename_start = self.start_of_base_name();
String path_str = self.path_string;
usz basename_start = start_of_base_name(path_str, self.env)!!;
if (basename_start == 0) return ".";
usz start = volume_name_len(path_str, self.env)!!;
if (basename_start <= start + 1)
@@ -277,6 +311,7 @@ fn String Path.dirname(self)
return path_str[:basename_start - 1];
}
<*
Test if the path has the given extension, so given the path /foo/bar.c3
this would be true matching the extension "c3"
@@ -310,6 +345,16 @@ fn String Path.volume_name(self)
return self.path_string[:len];
}
fn Path! String.to_path(self, Allocator allocator)
{
return new(allocator, self);
}
fn Path! String.to_tpath(self)
{
return new(tmem(), self);
}
fn usz! volume_name_len(String path, PathEnv path_env) @local
{
usz len = path.len;
@@ -360,13 +405,13 @@ fn Path! Path.parent(self)
{
if (is_separator(c, self.env))
{
return { self.path_string[:i], self.env };
return { self.path_string[:i], self.env, null };
}
}
return PathResult.NO_PARENT?;
}
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
{
if (!path_str.len) return path_str;
usz path_start = volume_name_len(path_str, path_env)!;
@@ -517,7 +562,7 @@ def PathWalker = fn bool! (Path, bool is_dir, void*);
<*
Walk the path recursively. PathWalker is run on every file and
directory found. Return true to abort the walk.
@require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths"
@require self.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn bool! Path.walk(self, PathWalker w, void* data)
{
@@ -538,6 +583,35 @@ fn bool! Path.walk(self, PathWalker w, void* data)
return false;
}
def TraverseCallback = fn bool! (Path, bool is_dir, any data);
<*
Walk the path recursively. TraverseCallback is run for every file and
directory found. Return true to abort the walk.
@require path.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn bool! traverse(Path path, TraverseCallback callback, any data)
{
const PATH_MAX = 512;
@stack_mem(PATH_MAX; Allocator allocator)
{
Path abs = path.absolute(allocator)!;
PathList files = ls(allocator, abs)!;
foreach (f : files)
{
if (f.str_view() == "." || f.str_view() == "..") continue;
@stack_mem(128; Allocator smem)
{
f = abs.append(smem, f.str_view())!;
bool is_directory = is_dir(f);
if (callback(f, is_directory, data)!) return true;
if (is_directory && traverse(f, callback, data)!) return true;
};
}
};
return false;
}
fn String Path.str_view(self) @inline
{
return self.path_string;
@@ -549,26 +623,19 @@ fn bool Path.has_suffix(self, String str)
return self.str_view().ends_with(str);
}
fn void Path.free_with_allocator(self, Allocator allocator)
{
allocator::free(allocator, self.path_string.ptr);
}
<*
@require self.allocator != null : "This Path should never be freed"
*>
fn void Path.free(self)
{
free(self.path_string.ptr);
allocator::free(self.allocator, self.path_string.ptr);
}
fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.print(self.str_view());
}
fn String Path.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic
{
return self.str_view().copy(allocator);
}
const bool[256] RESERVED_PATH_CHAR_POSIX = {
[0] = true,
@@ -592,9 +659,29 @@ macro bool is_reserved_win32_path_char(char c)
return RESERVED_PATH_CHAR_WIN32[c];
}
macro bool is_reserved_path_char(char c, PathEnv path_env = DEFAULT_PATH_ENV)
macro bool is_reserved_path_char(char c, PathEnv path_env = DEFAULT_ENV)
{
return path_env == PathEnv.WIN32
? RESERVED_PATH_CHAR_WIN32[c]
: RESERVED_PATH_CHAR_POSIX[c];
}
fn bool! _mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL) @private
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
if (is_dir(path)) return false;
if (exists(path)) return IoError.FILE_NOT_DIR?;
if (recursive)
{
if (try parent = path.parent()) mkdir(parent, true, permissions)!;
}
if (!is_dir(path.parent()) ?? false) return IoError.CANNOT_READ_DIR?;
return os::native_mkdir(path, permissions);
}
fn bool! _rmdir(Path path) @private
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
return os::native_rmdir(path);
}

View File

@@ -61,7 +61,7 @@ in llvmPackages.stdenv.mkDerivation (finalAttrs: {
checkPhase = ''
runHook preCheck
( cd ../resources/testproject; ../../build/c3c build --trust=full )
( cd ../test; ../build/c3c compile-run -O1 src/test_suite_runner.c3 --enable-new-generics -- ../build/c3c test_suite )
( cd ../test; ../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite )
runHook postCheck
'';

View File

@@ -23,6 +23,7 @@
- Aliases are now correctly handled as if they were variables/functions in regards to namespacing and accept `@builtin`.
- Correctly handle in/out when interacting with inout.
- Don't delete .o files not produced by the compiler.
- Fix optional jumps in expression lists, #1942.
### Stdlib changes

View File

@@ -30,7 +30,7 @@ static inline bool create_module_or_check_name(CompilationUnit *unit, Path *modu
if (!module->is_generic) goto DONE;
if (vec_size(parameters) != vec_size(module->parameters))
{
PRINT_ERROR_AT(module_name, "The parameter declarations of the generic module '%s' don't match.", module->name);
PRINT_ERROR_AT(module_name, "The parameter declarations of the generic module '%s' don't match.", module_name->module);
SEMA_NOTE(module->name, "A different definition can be found here.");
return false;
}
@@ -39,7 +39,7 @@ static inline bool create_module_or_check_name(CompilationUnit *unit, Path *modu
bool is_type = str_is_type(name);
if (is_type != str_is_type(module->parameters[idx]))
{
PRINT_ERROR_AT(module_name, "The parameter declarations of the generic module '%s' don't match.", module->name);
PRINT_ERROR_AT(module_name, "The parameter declarations of the generic module '%s' don't match.", module_name->module);
SEMA_NOTE(module->name, "The other definition is here.");
return false;
}

View File

@@ -5876,10 +5876,15 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr)
{
FOREACH(Expr *, e, expr->expression_list)
Expr **list = expr->expression_list;
unsigned count = vec_size(list);
assert(count);
unsigned last = count - 1;
for (unsigned i = 0; i < last; i++)
{
llvm_emit_expr(c, be_value, e);
llvm_emit_ignored_expr(c, list[i]);
}
llvm_emit_expr(c, be_value, list[last]);
}
static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type *type, AstId current, BlockExit **block_exit)

View File

@@ -21,14 +21,14 @@ fn void main(String[] args)
print_to_file = !io::stdout().isatty();
// Retain our current path.
start_cwd = path::temp_cwd()!!;
start_cwd = path::tcwd()!!;
// Create our test path, note that this prevents us from doing tests in parallell
test_dir = start_cwd.temp_append("_c3test_")!!;
test_dir = start_cwd.tappend("_c3test_")!!;
defer (void)path::rmtree(test_dir);
// Find the compiler
Path! path = start_cwd.temp_append(args[1]);
Path! path = start_cwd.tappend(args[1]);
if (catch path) arg_error_exit(appname, "Invalid compiler path: %s", args[1]);
// Is it a valid file?
if (!path::is_file(path))
@@ -58,7 +58,7 @@ fn void main(String[] args)
{
error_exit(appname, "Stdlib directory '%s' cannot be found.", stdlib);
}
stdlib = start_cwd.temp_append(stdlib).str_view()!!;
stdlib = start_cwd.tappend(stdlib).str_view()!!;
default:
arg_error_exit(appname, "Unknown option '%s'.", args[i]);
}
@@ -66,7 +66,7 @@ fn void main(String[] args)
if (only_skipped && args[3] != "-s" && args[3] != "--skipped") usage(appname);
// Get the directory or file to test
Path! file = path::temp_new(args[2]);
Path! file = args[2].to_tpath();
if (catch file) arg_error_exit(appname, "Invalid path: '%s'.", args[2]);
// Now just run all tests recursively.
@@ -129,17 +129,14 @@ fn void RunFile.add_line(&self, String line)
fn RunFile*! create_input_file(String filename)
{
File file = file::open_path(test_dir.temp_append(filename), "wb")!;
File file = file::open_path(test_dir.tappend(filename), "wb")!;
RunFile *run_file = mem::temp_new(RunFile, { .name = filename, .file = file, .is_output = false });
run_file.warnings.temp_init();
run_file.errors.temp_init();
return run_file;
}
fn RunFile*! create_output_file(String filename)
{
RunFile *run_file = mem::temp_new(RunFile, { .name = filename, .is_output = true });
run_file.expected_lines.temp_init();
return run_file;
}
@@ -168,7 +165,7 @@ fn bool check_line(RunSettings* settings, String type, String file, String line_
int line = line_str.to_int()!!;
// Get the base name
String basename = path::temp_new(file).basename()!!;
String basename = file.file_tbasename()!!;
// Loop through our input files (usually only 1!)
foreach (f : settings.input_files)
@@ -232,7 +229,7 @@ fn bool parse_result(DString out, RunSettings settings)
io::printn("FAILED\n\n Unexpected compilation errors:");
io::printn(" ------------------------------");
}
io::printf(" %d. %s at %s:%s: ", ++errors, parts[0], path::temp_new(parts[1]).basename()!!, parts[2]);
io::printf(" %d. %s at %s:%s: ", ++errors, parts[0], parts[1].file_tbasename()!!, parts[2]);
io::printfn(`"%s"`, parts[4]);
success = false;
}
@@ -389,9 +386,6 @@ fn void test_file(Path file_path)
}
defer (void)f.close();
RunSettings settings;
settings.opts.temp_init();
settings.input_files.temp_init();
settings.output_files.temp_init();
settings.current_file = create_input_file(file_path.basename()[..^(single ? 4 : 5)].tconcat(".c3"))!!;
settings.input_files.push(settings.current_file);
int line_no = 1;
@@ -413,7 +407,6 @@ fn void test_file(Path file_path)
// Construct the compile line
List{String} cmdline;
cmdline.temp_init();
cmdline.push(compiler_path.str_view());
cmdline.push("compile-only");
cmdline.push("--test");
@@ -448,7 +441,7 @@ fn void test_file(Path file_path)
SubProcess compilation = process::create(cmdline.array_view(), { .search_user_path, .no_window, .inherit_environment })!!;
defer compilation.destroy();
CInt result = compilation.join()!!;
DString out = dstring::temp_new();
DString out;
io::copy_to(&&compilation.stderr(), &out)!!;
if (result != 0 && result != 1)
{
@@ -501,12 +494,12 @@ fn void test_file(Path file_path)
fn void! test_path(Path file_path)
{
(void)path::chdir(start_cwd);
foreach (file : path::temp_ls(file_path)!!)
foreach (file : path::ls(tmem(), file_path)!!)
{
@pool()
{
(void)path::chdir(start_cwd);
file = file_path.temp_append(file.str_view())!;
file = file_path.tappend(file.str_view())!;
switch
{
case path::is_dir(file):

View File

@@ -25,11 +25,11 @@ entry:
%retparam = alloca i32, align 4
%.anon1 = alloca i32, align 4
%anon.f2 = alloca i64, align 8
%.anon18 = alloca i32, align 4
%anon.f19 = alloca i64, align 8
%retparam20 = alloca i32, align 4
%.anon27 = alloca i32, align 4
%anon.f28 = alloca i64, align 8
%.anon15 = alloca i32, align 4
%anon.f16 = alloca i64, align 8
%retparam17 = alloca i32, align 4
%.anon22 = alloca i32, align 4
%anon.f23 = alloca i64, align 8
%0 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 100)
%1 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam, ptr @test.m, i32 3)
%not_err = icmp eq i64 %1, 0
@@ -38,7 +38,7 @@ entry:
assign_optional: ; preds = %entry
store i64 %1, ptr %anon.f, align 8
br label %optional_assign_jump
br label %after_assign
after_check: ; preds = %entry
%3 = load i32, ptr %retparam, align 4
@@ -46,12 +46,7 @@ after_check: ; preds = %entry
store i64 0, ptr %anon.f, align 8
br label %after_assign
optional_assign_jump: ; preds = %assign_optional
%reload_err = load i64, ptr %anon.f, align 8
store i64 %reload_err, ptr %x.f, align 8
br label %after_assign17
after_assign: ; preds = %after_check
after_assign: ; preds = %after_check, %assign_optional
%optval = load i64, ptr %anon.f, align 8
%not_err3 = icmp eq i64 %optval, 0
%4 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
@@ -59,7 +54,7 @@ after_assign: ; preds = %after_check
assign_optional4: ; preds = %after_assign
store i64 %optval, ptr %anon.f2, align 8
br label %optional_assign_jump6
br label %after_assign6
after_check5: ; preds = %after_assign
%5 = load i32, ptr %.anon, align 4
@@ -67,113 +62,96 @@ after_check5: ; preds = %after_assign
store i32 %sub, ptr %.anon, align 4
store i32 %5, ptr %.anon1, align 4
store i64 0, ptr %anon.f2, align 8
br label %after_assign8
br label %after_assign6
optional_assign_jump6: ; preds = %assign_optional4
%reload_err7 = load i64, ptr %anon.f2, align 8
store i64 %reload_err7, ptr %x.f, align 8
br label %after_assign17
after_assign6: ; preds = %after_check5, %assign_optional4
%optval7 = load i64, ptr %anon.f, align 8
%not_err8 = icmp eq i64 %optval7, 0
%6 = call i1 @llvm.expect.i1(i1 %not_err8, i1 true)
br i1 %6, label %after_check9, label %voiderr
after_assign8: ; preds = %after_check5
%optval9 = load i64, ptr %anon.f, align 8
%not_err10 = icmp eq i64 %optval9, 0
%6 = call i1 @llvm.expect.i1(i1 %not_err10, i1 true)
br i1 %6, label %after_check12, label %assign_optional11
assign_optional11: ; preds = %after_assign8
store i64 %optval9, ptr %x.f, align 8
br label %after_assign17
after_check12: ; preds = %after_assign8
after_check9: ; preds = %after_assign6
%7 = load i32, ptr %.anon, align 4
%8 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 %7)
%optval13 = load i64, ptr %anon.f2, align 8
%not_err14 = icmp eq i64 %optval13, 0
%9 = call i1 @llvm.expect.i1(i1 %not_err14, i1 true)
br i1 %9, label %after_check16, label %assign_optional15
br label %voiderr
assign_optional15: ; preds = %after_check12
store i64 %optval13, ptr %x.f, align 8
br label %after_assign17
voiderr: ; preds = %after_check9, %after_assign6
%optval10 = load i64, ptr %anon.f2, align 8
%not_err11 = icmp eq i64 %optval10, 0
%9 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true)
br i1 %9, label %after_check13, label %assign_optional12
after_check16: ; preds = %after_check12
assign_optional12: ; preds = %voiderr
store i64 %optval10, ptr %x.f, align 8
br label %after_assign14
after_check13: ; preds = %voiderr
%10 = load i32, ptr %.anon1, align 4
store i32 %10, ptr %x, align 4
store i64 0, ptr %x.f, align 8
br label %after_assign17
br label %after_assign14
after_assign17: ; preds = %after_check16, %assign_optional15, %assign_optional11, %optional_assign_jump6, %optional_assign_jump
%11 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam20, ptr @test.m, i32 3)
%not_err21 = icmp eq i64 %11, 0
%12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true)
br i1 %12, label %after_check23, label %assign_optional22
after_assign14: ; preds = %after_check13, %assign_optional12
%11 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam17, ptr @test.m, i32 3)
%not_err18 = icmp eq i64 %11, 0
%12 = call i1 @llvm.expect.i1(i1 %not_err18, i1 true)
br i1 %12, label %after_check20, label %assign_optional19
assign_optional22: ; preds = %after_assign17
store i64 %11, ptr %anon.f19, align 8
br label %optional_assign_jump24
assign_optional19: ; preds = %after_assign14
store i64 %11, ptr %anon.f16, align 8
br label %after_assign21
after_check23: ; preds = %after_assign17
%13 = load i32, ptr %retparam20, align 4
store i32 %13, ptr %.anon18, align 4
store i64 0, ptr %anon.f19, align 8
br label %after_assign26
after_check20: ; preds = %after_assign14
%13 = load i32, ptr %retparam17, align 4
store i32 %13, ptr %.anon15, align 4
store i64 0, ptr %anon.f16, align 8
br label %after_assign21
optional_assign_jump24: ; preds = %assign_optional22
%reload_err25 = load i64, ptr %anon.f19, align 8
store i64 %reload_err25, ptr %x.f, align 8
br label %after_assign44
after_assign21: ; preds = %after_check20, %assign_optional19
%optval24 = load i64, ptr %anon.f16, align 8
%not_err25 = icmp eq i64 %optval24, 0
%14 = call i1 @llvm.expect.i1(i1 %not_err25, i1 true)
br i1 %14, label %after_check27, label %assign_optional26
after_assign26: ; preds = %after_check23
%optval29 = load i64, ptr %anon.f19, align 8
%not_err30 = icmp eq i64 %optval29, 0
%14 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true)
br i1 %14, label %after_check32, label %assign_optional31
assign_optional26: ; preds = %after_assign21
store i64 %optval24, ptr %anon.f23, align 8
br label %after_assign28
assign_optional31: ; preds = %after_assign26
store i64 %optval29, ptr %anon.f28, align 8
br label %optional_assign_jump33
after_check32: ; preds = %after_assign26
%15 = load i32, ptr %.anon18, align 4
after_check27: ; preds = %after_assign21
%15 = load i32, ptr %.anon15, align 4
%add = add i32 %15, 1
store i32 %add, ptr %.anon18, align 4
store i32 %add, ptr %.anon27, align 4
store i64 0, ptr %anon.f28, align 8
br label %after_assign35
store i32 %add, ptr %.anon15, align 4
store i32 %add, ptr %.anon22, align 4
store i64 0, ptr %anon.f23, align 8
br label %after_assign28
optional_assign_jump33: ; preds = %assign_optional31
%reload_err34 = load i64, ptr %anon.f28, align 8
store i64 %reload_err34, ptr %x.f, align 8
br label %after_assign44
after_assign28: ; preds = %after_check27, %assign_optional26
%optval29 = load i64, ptr %anon.f16, align 8
%not_err30 = icmp eq i64 %optval29, 0
%16 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true)
br i1 %16, label %after_check31, label %voiderr32
after_assign35: ; preds = %after_check32
%optval36 = load i64, ptr %anon.f19, align 8
%not_err37 = icmp eq i64 %optval36, 0
%16 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true)
br i1 %16, label %after_check39, label %assign_optional38
assign_optional38: ; preds = %after_assign35
store i64 %optval36, ptr %x.f, align 8
br label %after_assign44
after_check39: ; preds = %after_assign35
%17 = load i32, ptr %.anon18, align 4
after_check31: ; preds = %after_assign28
%17 = load i32, ptr %.anon15, align 4
%18 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 %17)
%optval40 = load i64, ptr %anon.f28, align 8
%not_err41 = icmp eq i64 %optval40, 0
%19 = call i1 @llvm.expect.i1(i1 %not_err41, i1 true)
br i1 %19, label %after_check43, label %assign_optional42
br label %voiderr32
assign_optional42: ; preds = %after_check39
store i64 %optval40, ptr %x.f, align 8
br label %after_assign44
voiderr32: ; preds = %after_check31, %after_assign28
%optval33 = load i64, ptr %anon.f23, align 8
%not_err34 = icmp eq i64 %optval33, 0
%19 = call i1 @llvm.expect.i1(i1 %not_err34, i1 true)
br i1 %19, label %after_check36, label %assign_optional35
after_check43: ; preds = %after_check39
%20 = load i32, ptr %.anon27, align 4
assign_optional35: ; preds = %voiderr32
store i64 %optval33, ptr %x.f, align 8
br label %after_assign37
after_check36: ; preds = %voiderr32
%20 = load i32, ptr %.anon22, align 4
store i32 %20, ptr %x, align 4
store i64 0, ptr %x.f, align 8
br label %after_assign44
br label %after_assign37
after_assign44: ; preds = %after_check43, %assign_optional42, %assign_optional38, %optional_assign_jump33, %optional_assign_jump24
after_assign37: ; preds = %after_check36, %assign_optional35
ret void
}

View File

@@ -0,0 +1,60 @@
// #target: macos-x64
module test;
fn void main()
{
int! n;
for (n += 1, 1 + 1; false;);
}
/* #expect: test.ll
; ModuleID = 'test'
source_filename = "test"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"
; Function Attrs: nounwind uwtable
define void @test.main() #0 {
entry:
%n = alloca i32, align 4
%n.f = alloca i64, align 8
store i64 0, ptr %n.f, align 8
store i32 0, ptr %n, align 4
%optval = load i64, ptr %n.f, align 8
%not_err = icmp eq i64 %optval, 0
%0 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %0, label %after_check, label %voiderr
after_check: ; preds = %entry
%1 = load i32, ptr %n, align 4
%add = add i32 %1, 1
store i32 %add, ptr %n, align 4
br label %voiderr
voiderr: ; preds = %after_check, %entry
ret void
}
; Function Attrs: nounwind uwtable
define i32 @main(i32 %0, ptr %1) #0 {
entry:
call void @test.main()
ret i32 0
}
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
declare i1 @llvm.expect.i1(i1, i1) #1
attributes #0 = { nounwind uwtable "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(none) }
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 2, !"wchar_size", i32 4}
!3 = !{i32 4, !"PIC Level", i32 2}
!4 = !{i32 1, !"uwtable", i32 2}
!5 = !{i32 2, !"frame-pointer", i32 2}

View File

@@ -2,7 +2,7 @@
module test;
import std;
def Abc = HashMap(<int, int>);
def Abc = HashMap{int, int};
Abc m;
fn void main()
{
@@ -25,11 +25,11 @@ entry:
%retparam = alloca i32, align 4
%.anon1 = alloca i32, align 4
%anon.f2 = alloca i64, align 8
%.anon18 = alloca i32, align 4
%anon.f19 = alloca i64, align 8
%retparam20 = alloca i32, align 4
%.anon27 = alloca i32, align 4
%anon.f28 = alloca i64, align 8
%.anon15 = alloca i32, align 4
%anon.f16 = alloca i64, align 8
%retparam17 = alloca i32, align 4
%.anon22 = alloca i32, align 4
%anon.f23 = alloca i64, align 8
%0 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 100)
%1 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam, ptr @test.m, i32 3)
%not_err = icmp eq i64 %1, 0
@@ -38,7 +38,7 @@ entry:
assign_optional: ; preds = %entry
store i64 %1, ptr %anon.f, align 8
br label %optional_assign_jump
br label %after_assign
after_check: ; preds = %entry
%3 = load i32, ptr %retparam, align 4
@@ -46,12 +46,7 @@ after_check: ; preds = %entry
store i64 0, ptr %anon.f, align 8
br label %after_assign
optional_assign_jump: ; preds = %assign_optional
%reload_err = load i64, ptr %anon.f, align 8
store i64 %reload_err, ptr %x.f, align 8
br label %after_assign17
after_assign: ; preds = %after_check
after_assign: ; preds = %after_check, %assign_optional
%optval = load i64, ptr %anon.f, align 8
%not_err3 = icmp eq i64 %optval, 0
%4 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
@@ -59,7 +54,7 @@ after_assign: ; preds = %after_check
assign_optional4: ; preds = %after_assign
store i64 %optval, ptr %anon.f2, align 8
br label %optional_assign_jump6
br label %after_assign6
after_check5: ; preds = %after_assign
%5 = load i32, ptr %.anon, align 4
@@ -67,113 +62,96 @@ after_check5: ; preds = %after_assign
store i32 %sub, ptr %.anon, align 4
store i32 %5, ptr %.anon1, align 4
store i64 0, ptr %anon.f2, align 8
br label %after_assign8
br label %after_assign6
optional_assign_jump6: ; preds = %assign_optional4
%reload_err7 = load i64, ptr %anon.f2, align 8
store i64 %reload_err7, ptr %x.f, align 8
br label %after_assign17
after_assign6: ; preds = %after_check5, %assign_optional4
%optval7 = load i64, ptr %anon.f, align 8
%not_err8 = icmp eq i64 %optval7, 0
%6 = call i1 @llvm.expect.i1(i1 %not_err8, i1 true)
br i1 %6, label %after_check9, label %voiderr
after_assign8: ; preds = %after_check5
%optval9 = load i64, ptr %anon.f, align 8
%not_err10 = icmp eq i64 %optval9, 0
%6 = call i1 @llvm.expect.i1(i1 %not_err10, i1 true)
br i1 %6, label %after_check12, label %assign_optional11
assign_optional11: ; preds = %after_assign8
store i64 %optval9, ptr %x.f, align 8
br label %after_assign17
after_check12: ; preds = %after_assign8
after_check9: ; preds = %after_assign6
%7 = load i32, ptr %.anon, align 4
%8 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 %7)
%optval13 = load i64, ptr %anon.f2, align 8
%not_err14 = icmp eq i64 %optval13, 0
%9 = call i1 @llvm.expect.i1(i1 %not_err14, i1 true)
br i1 %9, label %after_check16, label %assign_optional15
br label %voiderr
assign_optional15: ; preds = %after_check12
store i64 %optval13, ptr %x.f, align 8
br label %after_assign17
voiderr: ; preds = %after_check9, %after_assign6
%optval10 = load i64, ptr %anon.f2, align 8
%not_err11 = icmp eq i64 %optval10, 0
%9 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true)
br i1 %9, label %after_check13, label %assign_optional12
after_check16: ; preds = %after_check12
assign_optional12: ; preds = %voiderr
store i64 %optval10, ptr %x.f, align 8
br label %after_assign14
after_check13: ; preds = %voiderr
%10 = load i32, ptr %.anon1, align 4
store i32 %10, ptr %x, align 4
store i64 0, ptr %x.f, align 8
br label %after_assign17
br label %after_assign14
after_assign17: ; preds = %after_check16, %assign_optional15, %assign_optional11, %optional_assign_jump6, %optional_assign_jump
%11 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam20, ptr @test.m, i32 3)
%not_err21 = icmp eq i64 %11, 0
%12 = call i1 @llvm.expect.i1(i1 %not_err21, i1 true)
br i1 %12, label %after_check23, label %assign_optional22
after_assign14: ; preds = %after_check13, %assign_optional12
%11 = call i64 @"std_collections_map$int$int$.HashMap.get"(ptr %retparam17, ptr @test.m, i32 3)
%not_err18 = icmp eq i64 %11, 0
%12 = call i1 @llvm.expect.i1(i1 %not_err18, i1 true)
br i1 %12, label %after_check20, label %assign_optional19
assign_optional22: ; preds = %after_assign17
store i64 %11, ptr %anon.f19, align 8
br label %optional_assign_jump24
assign_optional19: ; preds = %after_assign14
store i64 %11, ptr %anon.f16, align 8
br label %after_assign21
after_check23: ; preds = %after_assign17
%13 = load i32, ptr %retparam20, align 4
store i32 %13, ptr %.anon18, align 4
store i64 0, ptr %anon.f19, align 8
br label %after_assign26
after_check20: ; preds = %after_assign14
%13 = load i32, ptr %retparam17, align 4
store i32 %13, ptr %.anon15, align 4
store i64 0, ptr %anon.f16, align 8
br label %after_assign21
optional_assign_jump24: ; preds = %assign_optional22
%reload_err25 = load i64, ptr %anon.f19, align 8
store i64 %reload_err25, ptr %x.f, align 8
br label %after_assign44
after_assign21: ; preds = %after_check20, %assign_optional19
%optval24 = load i64, ptr %anon.f16, align 8
%not_err25 = icmp eq i64 %optval24, 0
%14 = call i1 @llvm.expect.i1(i1 %not_err25, i1 true)
br i1 %14, label %after_check27, label %assign_optional26
after_assign26: ; preds = %after_check23
%optval29 = load i64, ptr %anon.f19, align 8
%not_err30 = icmp eq i64 %optval29, 0
%14 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true)
br i1 %14, label %after_check32, label %assign_optional31
assign_optional26: ; preds = %after_assign21
store i64 %optval24, ptr %anon.f23, align 8
br label %after_assign28
assign_optional31: ; preds = %after_assign26
store i64 %optval29, ptr %anon.f28, align 8
br label %optional_assign_jump33
after_check32: ; preds = %after_assign26
%15 = load i32, ptr %.anon18, align 4
after_check27: ; preds = %after_assign21
%15 = load i32, ptr %.anon15, align 4
%add = add i32 %15, 1
store i32 %add, ptr %.anon18, align 4
store i32 %add, ptr %.anon27, align 4
store i64 0, ptr %anon.f28, align 8
br label %after_assign35
store i32 %add, ptr %.anon15, align 4
store i32 %add, ptr %.anon22, align 4
store i64 0, ptr %anon.f23, align 8
br label %after_assign28
optional_assign_jump33: ; preds = %assign_optional31
%reload_err34 = load i64, ptr %anon.f28, align 8
store i64 %reload_err34, ptr %x.f, align 8
br label %after_assign44
after_assign28: ; preds = %after_check27, %assign_optional26
%optval29 = load i64, ptr %anon.f16, align 8
%not_err30 = icmp eq i64 %optval29, 0
%16 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true)
br i1 %16, label %after_check31, label %voiderr32
after_assign35: ; preds = %after_check32
%optval36 = load i64, ptr %anon.f19, align 8
%not_err37 = icmp eq i64 %optval36, 0
%16 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true)
br i1 %16, label %after_check39, label %assign_optional38
assign_optional38: ; preds = %after_assign35
store i64 %optval36, ptr %x.f, align 8
br label %after_assign44
after_check39: ; preds = %after_assign35
%17 = load i32, ptr %.anon18, align 4
after_check31: ; preds = %after_assign28
%17 = load i32, ptr %.anon15, align 4
%18 = call i8 @"std_collections_map$int$int$.HashMap.set"(ptr @test.m, i32 3, i32 %17)
%optval40 = load i64, ptr %anon.f28, align 8
%not_err41 = icmp eq i64 %optval40, 0
%19 = call i1 @llvm.expect.i1(i1 %not_err41, i1 true)
br i1 %19, label %after_check43, label %assign_optional42
br label %voiderr32
assign_optional42: ; preds = %after_check39
store i64 %optval40, ptr %x.f, align 8
br label %after_assign44
voiderr32: ; preds = %after_check31, %after_assign28
%optval33 = load i64, ptr %anon.f23, align 8
%not_err34 = icmp eq i64 %optval33, 0
%19 = call i1 @llvm.expect.i1(i1 %not_err34, i1 true)
br i1 %19, label %after_check36, label %assign_optional35
after_check43: ; preds = %after_check39
%20 = load i32, ptr %.anon27, align 4
assign_optional35: ; preds = %voiderr32
store i64 %optval33, ptr %x.f, align 8
br label %after_assign37
after_check36: ; preds = %voiderr32
%20 = load i32, ptr %.anon22, align 4
store i32 %20, ptr %x, align 4
store i64 0, ptr %x.f, align 8
br label %after_assign44
br label %after_assign37
after_assign44: ; preds = %after_check43, %assign_optional42, %assign_optional38, %optional_assign_jump33, %optional_assign_jump24
after_assign37: ; preds = %after_check36, %assign_optional35
ret void
}