error inference in fallible functions
This commit is contained in:
@@ -3167,6 +3167,50 @@ main func() int ! Error { return try value() }
|
||||
Error :: enum { failed }
|
||||
fail func() void ! Error { return .failed }
|
||||
main func(_ process.Init) void ! Error { try fail() }
|
||||
`,
|
||||
exit_code=1,
|
||||
},
|
||||
{
|
||||
name="inferred-main-try",
|
||||
source=`Error :: enum { failed }
|
||||
fail func() void ! Error { return .failed }
|
||||
main func() void! { try fail() }
|
||||
`,
|
||||
exit_code=1,
|
||||
},
|
||||
{
|
||||
name="inferred-main-typed-return",
|
||||
source=`Error :: enum { failed }
|
||||
main func() void! {
|
||||
err Error := .failed
|
||||
return err
|
||||
}
|
||||
`,
|
||||
exit_code=1,
|
||||
},
|
||||
{
|
||||
name="inferred-hidden-sum",
|
||||
source=`A :: enum { a }
|
||||
B :: enum { b }
|
||||
fail_a func() void ! A { return .a }
|
||||
fail_b func() void ! B { return .b }
|
||||
hide dispatch func(selector i32) void! {
|
||||
if selector == 1 {
|
||||
try fail_a()
|
||||
return
|
||||
}
|
||||
try fail_b()
|
||||
}
|
||||
main func() void! { try dispatch(2) }
|
||||
`,
|
||||
exit_code=1,
|
||||
},
|
||||
{
|
||||
name="inferred-process-main",
|
||||
source=`process :: import "@std/process"
|
||||
Error :: enum { failed }
|
||||
fail func() void ! Error { return .failed }
|
||||
main func(_ process.Init) void! { try fail() }
|
||||
`,
|
||||
exit_code=1,
|
||||
},
|
||||
@@ -3202,6 +3246,64 @@ main func(_ process.Init) void ! Error { try fail() }
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
inferred_error_channels_reject_unstable_or_untyped_contracts :: proc(t: ^testing.T) {
|
||||
Case :: struct {
|
||||
source: string,
|
||||
message: string,
|
||||
}
|
||||
cases := [?]Case{
|
||||
{
|
||||
source=`Error :: enum { failed }
|
||||
fail func() void ! Error { return .failed }
|
||||
visible func() void! { try fail() }
|
||||
main func() void {}
|
||||
`,
|
||||
message="inferred error channels are only allowed on hidden functions and root main",
|
||||
},
|
||||
{
|
||||
source=`Error :: enum { failed }
|
||||
fail func() void ! Error { return .failed }
|
||||
hide untyped func(flag bool) void! {
|
||||
if flag {
|
||||
try fail()
|
||||
return
|
||||
}
|
||||
return .failed
|
||||
}
|
||||
main func() void { untyped(false) catch |_| {} }
|
||||
`,
|
||||
message="inferred error returns require a concretely typed error value",
|
||||
},
|
||||
{
|
||||
source=`hide empty func() void! {}
|
||||
main func() void { empty() catch |_| {} }
|
||||
`,
|
||||
message="could not infer a named error channel for 'empty'",
|
||||
},
|
||||
}
|
||||
for test_case in cases {
|
||||
source_file := source.Source{path="test.bro", text=test_case.source}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
symbols := symbol.init_table()
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
|
||||
found := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found = found || strings.contains(diagnostic.message, test_case.message)
|
||||
}
|
||||
testing.expect(t, found)
|
||||
|
||||
hir.destroy_module(&hir_module)
|
||||
ast.destroy_module(&ast_module)
|
||||
delete(stream.items)
|
||||
symbol.destroy_table(&symbols)
|
||||
source.destroy_diagnostics(&diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
milestone_33_injects_explicit_io_provider_and_runs_std_io :: proc(t: ^testing.T) {
|
||||
sources := source.init_store()
|
||||
|
||||
Reference in New Issue
Block a user