favor return over return _ (void return); newline/closing terminates

This commit is contained in:
2026-07-14 19:07:37 +02:00
parent eac5b32738
commit 471896b48a
19 changed files with 92266 additions and 94923 deletions
+91 -1
View File
@@ -2289,7 +2289,7 @@ return_sink_and_unconsumed_values_have_distinct_hir :: proc(t: ^testing.T) {
return 1
}
done func() void {
return _
return
}
main func() void {
done()
@@ -2327,6 +2327,96 @@ main func() void {
testing.expect_value(t, hir_module.statements[main.body[2]].kind, hir.Stmt_Kind.Trap)
}
@(test)
bare_returns_and_strict_yields :: proc(t: ^testing.T) {
text := `Failure :: enum { bad }
noop func() void {}
newline_return func() void {
return
}
inline_return func() void { return }
fallible_return func() void ! Failure { return }
split_return func() i32 {
return
1
}
old_return func() void { return _ }
missing_yield func() i32 {
value :: {
yield
1
}
return value
}
missing_labeled_yield func() i32 {
value :: block: {
yield :block
}
return value
}
void_yield func() i32 {
value :: { yield noop() }
return value
}
sink_yield func() i32 {
value :: { yield _ }
return value
}
void_context func() void {
fallible_return() catch |_| { yield 1 }
}
bad_comptime :: ${ yield noop() }
main func() void {
newline_return()
inline_return()
fallible_return() catch |_| {}
_ = split_return()
old_return()
_ = missing_yield()
_ = missing_labeled_yield()
_ = void_yield()
_ = sink_yield()
void_context()
}
`
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
ast_module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&ast_module)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
testing.expect_value(t, ast_module.statements[ast_module.functions[1].body[0]].expr, ast.INVALID_EXPR)
testing.expect_value(t, ast_module.statements[ast_module.functions[2].body[0]].expr, ast.INVALID_EXPR)
testing.expect_value(t, ast_module.statements[ast_module.functions[3].body[0]].expr, ast.INVALID_EXPR)
testing.expect_value(t, len(ast_module.functions[4].body), 2)
missing_value := false
non_void_function := false
void_yields := 0
sink_read := false
void_context := false
for diagnostic in diagnostics.items {
missing_value = missing_value || strings.contains(diagnostic.message, "'yield' must produce a value")
non_void_function = non_void_function || strings.contains(diagnostic.message, "non-void function must return a value")
if strings.contains(diagnostic.message, "'yield' expression must produce a non-void value") {
void_yields += 1
}
sink_read = sink_read || strings.contains(diagnostic.message, "'_' is a write-only sink and cannot be read")
void_context = void_context || strings.contains(diagnostic.message, "void value context must fall through instead of yielding")
}
testing.expect(t, missing_value)
testing.expect(t, non_void_function)
testing.expect(t, void_yields >= 2)
testing.expect(t, sink_read)
testing.expect(t, void_context)
}
@(test)
unused_locals_and_params_warn_without_traps :: proc(t: ^testing.T) {
text := `warn_only func(value i32, unused i32) i32 {