stop compilation after checker errors

This commit is contained in:
2026-07-22 02:13:12 +02:00
parent 8e153fa84e
commit c389c19a81
2 changed files with 69 additions and 65 deletions
+17
View File
@@ -29,6 +29,15 @@ write_escaped_c_string :: proc(builder: ^strings.Builder, value: string) {
}
}
has_errors :: proc(diagnostics: ^source.Diagnostics) -> bool {
for diagnostic in diagnostics.items {
if diagnostic.severity == .Error {
return true
}
}
return false
}
compile_package :: proc(
input_path, output_path: string,
link_arguments: []linker.Argument = nil,
@@ -142,6 +151,10 @@ compile_package :: proc(
vmem.arena_free_all(&lexer_arena)
hir_module := checker.check(&ast_module, &diagnostics, &symbols, selected, vmem.arena_allocator(&checker_arena))
vmem.arena_free_all(&parser_arena)
if has_errors(&diagnostics) {
source.print_all(&diagnostics)
return 1
}
ir_module := lower.lower(&hir_module, vmem.arena_allocator(&lower_arena))
vmem.arena_free_all(&checker_arena)
opt.run(&ir_module)
@@ -149,6 +162,10 @@ compile_package :: proc(
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
defer delete(llvm_text)
vmem.arena_free_all(&lower_arena)
if has_errors(&diagnostics) {
source.print_all(&diagnostics)
return 1
}
llvm_path := fmt.tprintf("%s.brolang-%d.ll", output_path, os2.get_pid())
defer _ = os.remove(llvm_path)
if err := os.write_entire_file_or_err(llvm_path, transmute([]byte)llvm_text); err != nil {
+52 -65
View File
@@ -5094,6 +5094,24 @@ run_executable :: proc(path: string) -> os2.Process_State {
return state
}
@(test)
checker_errors_skip_ir_output_and_backend :: proc(t: ^testing.T) {
directory := "/tmp/brolang-test-checker-error-stop"
main_path := "/tmp/brolang-test-checker-error-stop/main.bro"
text := `main func() i32 {
return missing
}
`
_ = os2.remove_all(directory)
defer _ = os2.remove_all(directory)
testing.expect(t, os.make_directory(directory) == nil)
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
// If compilation reaches temporary IR creation, this nonexistent parent changes
// the result to an infrastructure failure instead of the expected source error.
status := compiler_core.compile_package(directory, "/definitely/not/brolang-output")
testing.expect_value(t, status, 1)
}
@(test)
valid_program_compiles_and_runs :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-valid"
@@ -7459,8 +7477,7 @@ unsupported_c_header_members_diagnose_only_when_referenced :: proc(t: ^testing.T
c_options := cimport.Options{include_paths=[]string{"examples/interop/header/include"}}
status := compiler_core.compile_package("examples/interop/header_unsupported", output, nil, target.DEFAULT, c_options)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -7631,23 +7648,21 @@ checked_runtime_negation_traps_for_every_signed_width :: proc(t: ^testing.T) {
}
@(test)
constant_that_does_not_fit_context_produces_trap_executable :: proc(t: ^testing.T) {
constant_that_does_not_fit_context_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-constant-context-error"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/constant_context_error", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
constant_beyond_i64_produces_trap_executable :: proc(t: ^testing.T) {
constant_beyond_i64_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-constant-i64-overflow"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/constant_i64_overflow", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -7666,13 +7681,12 @@ same_line_statements_are_diagnosed :: proc(t: ^testing.T) {
}
@(test)
missing_main_produces_trap_executable :: proc(t: ^testing.T) {
missing_main_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-missing-main"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/missing_main", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9093,13 +9107,12 @@ mutable_local_reassignment_uses_runtime_storage :: proc(t: ^testing.T) {
}
@(test)
implicit_narrowing_produces_trap_executable :: proc(t: ^testing.T) {
implicit_narrowing_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-narrowing"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/narrowing_error", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9287,8 +9300,7 @@ unused_global_cycle_is_deferred :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/cycle_unused", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9297,18 +9309,16 @@ used_global_cycle_traps :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/cycle_used", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
malformed_typed_values_still_produce_executable :: proc(t: ^testing.T) {
malformed_typed_values_stop_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-malformed-typed"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/malformed_typed_recovery", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9327,8 +9337,7 @@ used_invalid_function_is_diagnosed_and_traps :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/invalid_used_function", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9337,8 +9346,7 @@ function_mediated_problematic_global_is_deferred :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/function_global_unused", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9347,8 +9355,7 @@ function_mediated_problematic_global_traps_when_used :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/programs/function_global_used", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9404,24 +9411,16 @@ unused_missing_package_does_not_trap :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/missing_unused/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
referenced_missing_package_traps_at_reference :: proc(t: ^testing.T) {
referenced_missing_package_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-package-missing-used"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/missing_used/app", output)
testing.expect_value(t, status, 1)
state, stdout, stderr, _ := os2.process_exec(
os2.Process_Desc{command=[]string{output}},
context.allocator,
)
defer delete(stdout)
defer delete(stderr)
testing.expect(t, !state.success)
testing.expect(t, strings.contains(string(stderr), "/missing_used/app/main.bro:4:6"))
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9430,8 +9429,7 @@ imports_are_file_local :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/file_local/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9564,13 +9562,12 @@ same_package_can_be_imported_under_distinct_aliases :: proc(t: ^testing.T) {
}
@(test)
duplicate_same_file_import_keeps_first_binding :: proc(t: ^testing.T) {
duplicate_same_file_import_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-package-duplicate"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/duplicate/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 2)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9589,8 +9586,7 @@ imports_do_not_reexport_members :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/non_transitive/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9750,13 +9746,12 @@ self_import_via_dot_is_valid :: proc(t: ^testing.T) {
}
@(test)
unused_absolute_import_is_diagnosed_without_trapping :: proc(t: ^testing.T) {
absolute_import_error_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-package-absolute"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/absolute/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9765,8 +9760,7 @@ unreferenced_problematic_imported_global_is_deferred :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/problematic_unused/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9785,8 +9779,7 @@ cross_package_global_initialization_cycle_traps_when_used :: proc(t: ^testing.T)
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/global_cycle/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9940,8 +9933,7 @@ imported_main_does_not_satisfy_root_main_requirement :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/missing_root_main/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9977,8 +9969,7 @@ invalid_default_alias_requires_an_explicit_alias :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/default_alias_invalid/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -9992,13 +9983,12 @@ explicit_alias_allows_invalid_directory_basename :: proc(t: ^testing.T) {
}
@(test)
import_alias_conflict_is_diagnosed_without_trapping :: proc(t: ^testing.T) {
import_alias_conflict_stops_before_backend :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-package-alias-conflict"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/alias_conflict/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 7)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -10007,8 +9997,7 @@ empty_imported_package_is_a_source_diagnostic :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/empty_import/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -10017,8 +10006,7 @@ non_directory_import_is_a_source_diagnostic :: proc(t: ^testing.T) {
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/file_import/app", output)
testing.expect_value(t, status, 1)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
testing.expect(t, !os.exists(output))
}
@(test)
@@ -13933,8 +13921,7 @@ main func() void { use(1, 2) }
testing.expect(t, os.make_directory(directory) == nil)
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)cases[1].text))
testing.expect_value(t, compiler_core.compile_package(directory, output), 1)
state := run_executable(output)
testing.expect(t, !state.success)
testing.expect(t, !os.exists(output))
}
@(test)