Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions src/cli/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ fn rocRun(allocs: *Allocators, args: cli_args.RunArgs) !void {

// Set up shared memory with ModuleEnv
std.log.debug("Setting up shared memory for Roc file: {s}", .{args.path});
const shm_result = setupSharedMemoryWithModuleEnv(allocs, args.path) catch |err| {
const shm_result = setupSharedMemoryWithModuleEnv(allocs, args.path, args.allow_errors) catch |err| {
std.log.err("Failed to set up shared memory with ModuleEnv: {}", .{err});
return err;
};
Expand Down Expand Up @@ -1458,7 +1458,7 @@ fn writeToWindowsSharedMemory(data: []const u8, total_size: usize) !SharedMemory
/// This parses, canonicalizes, and type-checks all modules, with the resulting ModuleEnvs
/// ending up in shared memory because all allocations were done into shared memory.
/// Platform type modules have their e_anno_only expressions converted to e_hosted_lambda.
pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []const u8) !SharedMemoryResult {
pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []const u8, allow_errors: bool) !SharedMemoryResult {
// Create shared memory with SharedMemoryAllocator
const page_size = try SharedMemoryAllocator.getSystemPageSize();
var shm = try SharedMemoryAllocator.create(SHARED_MEMORY_SIZE, page_size);
Expand Down Expand Up @@ -1686,10 +1686,39 @@ pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []cons
app_env.module_name = app_module_name;
try app_env.common.calcLineStarts(shm_allocator);

var error_count: usize = 0;

var app_parse_ast = try parse.parse(&app_env.common, allocs.gpa);
defer app_parse_ast.deinit(allocs.gpa);
app_parse_ast.store.emptyScratch();
if (app_parse_ast.hasErrors()) {
const stderr = stderrWriter();
defer stderr.flush() catch {};
for (app_parse_ast.tokenize_diagnostics.items) |diagnostic| {
error_count += 1;
var report = app_parse_ast.tokenizeDiagnosticToReport(diagnostic, allocs.gpa, roc_file_path) catch continue;
defer report.deinit();
reporting.renderReportToTerminal(&report, stderr, ColorPalette.ANSI, reporting.ReportingConfig.initColorTerminal()) catch continue;
}
for (app_parse_ast.parse_diagnostics.items) |diagnostic| {
error_count += 1;
var report = app_parse_ast.parseDiagnosticToReport(&app_env.common, diagnostic, allocs.gpa, roc_file_path) catch continue;
defer report.deinit();
reporting.renderReportToTerminal(&report, stderr, ColorPalette.ANSI, reporting.ReportingConfig.initColorTerminal()) catch continue;
}
// If errors are not allowed then we should not move past parsing. return early and let caller handle error/exit
if (!allow_errors) {
return SharedMemoryResult{
.handle = SharedMemoryHandle{
.fd = shm.handle,
.ptr = shm.base_ptr,
.size = shm.getUsedSize(),
},
.error_count = error_count,
};
}
}

app_parse_ast.store.emptyScratch();
try app_env.initCIRFields(app_module_name);

var app_module_envs_map = std.AutoHashMap(base.Ident.Idx, Can.AutoImportedType).init(allocs.gpa);
Expand Down Expand Up @@ -1845,7 +1874,7 @@ pub fn setupSharedMemoryWithModuleEnv(allocs: *Allocators, roc_file_path: []cons
// Render all type problems (errors and warnings) exactly as roc check would
// Count errors so the caller can decide whether to proceed with execution
// Skip rendering in test mode to avoid polluting test output
const error_count = if (!builtin.is_test)
error_count += if (!builtin.is_test)
renderTypeProblems(allocs.gpa, &app_checker, &app_env, roc_file_path)
else
0;
Expand Down
27 changes: 25 additions & 2 deletions src/cli/test/fx_platform_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ test "fx platform issue8433" {
}
}

test "run aborts on errors by default" {
test "run aborts on type errors by default" {
// Tests that roc run aborts when there are type errors (without --allow-errors)
const allocator = testing.allocator;

Expand All @@ -1039,7 +1039,30 @@ test "run aborts on errors by default" {
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "UNDEFINED VARIABLE") != null);
}

test "run with --allow-errors attempts execution despite errors" {
test "run aborts on parse errors by default" {
// Tests that roc run aborts when there are parse errors (without --allow-errors)
const allocator = testing.allocator;

try ensureRocBinary(allocator);

const run_result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &[_][]const u8{
"./zig-out/bin/roc",
"test/fx/parse_error.roc",
},
});
defer allocator.free(run_result.stdout);
defer allocator.free(run_result.stderr);

// Should fail with type errors
try checkFailure(run_result);

// Should show the errors
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "PARSE ERROR") != null);
}

test "run with --allow-errors attempts execution despite type errors" {
// Tests that roc run --allow-errors attempts to execute even with type errors
const allocator = testing.allocator;

Expand Down
6 changes: 3 additions & 3 deletions src/cli/test_shared_memory_system.zig
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ test "integration - shared memory setup and parsing" {
const roc_path = "test/int/app.roc";

// Test that we can set up shared memory with ModuleEnv
const shm_result = try main.setupSharedMemoryWithModuleEnv(&allocs, roc_path);
const shm_result = try main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true);
const shm_handle = shm_result.handle;

// Clean up shared memory resources
Expand Down Expand Up @@ -170,7 +170,7 @@ test "integration - compilation pipeline for different platforms" {

for (test_apps) |roc_path| {
// Test the full compilation pipeline (parse -> canonicalize -> typecheck)
const shm_result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path) catch |err| {
const shm_result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true) catch |err| {
std.log.warn("Failed to set up shared memory for {s}: {}\n", .{ roc_path, err });
continue;
};
Expand Down Expand Up @@ -212,7 +212,7 @@ test "integration - error handling for non-existent file" {
const roc_path = "test/nonexistent/app.roc";

// This should fail because the file doesn't exist
const result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path);
const result = main.setupSharedMemoryWithModuleEnv(&allocs, roc_path, true);

// We expect this to fail - the important thing is that it doesn't crash
if (result) |shm_result| {
Expand Down
8 changes: 8 additions & 0 deletions test/fx/parse_error.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
app [main!] {
pf: platform "./platform/main.roc",
}
import pf.Stdout
main! = |_args| {
Stdout.line!("Hello world")
Ok({})
}}
Loading