From: Brendan Hansen Date: Tue, 23 May 2023 03:22:09 +0000 (-0500) Subject: bugfixes and `Result` is now a `union` X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=22400f7f0dc4d60b02dee0fde0e425e20e6efdfe;p=onyx.git bugfixes and `Result` is now a `union` --- diff --git a/compiler/src/astnodes.c b/compiler/src/astnodes.c index 01558e5c..b832ea85 100644 --- a/compiler/src/astnodes.c +++ b/compiler/src/astnodes.c @@ -1603,6 +1603,8 @@ AstStructLiteral* make_optional_literal_some(bh_allocator a, AstTyped *expr, Typ opt_lit->type = opt_type; opt_lit->args.values[0]->type = opt_type->Union.tag_type; + + opt_lit->flags |= Ast_Flag_Has_Been_Checked; return opt_lit; } diff --git a/compiler/src/doc.c b/compiler/src/doc.c index 23115947..742c1c59 100644 --- a/compiler/src/doc.c +++ b/compiler/src/doc.c @@ -278,10 +278,18 @@ static void write_type_node(bh_buffer *buffer, void *vnode) { bh_buffer_write_string(buffer, ((AstStructType *) node)->name); return; + case Ast_Kind_Union_Type: + bh_buffer_write_string(buffer, ((AstUnionType *) node)->name); + return; + case Ast_Kind_Poly_Struct_Type: bh_buffer_write_string(buffer, ((AstPolyStructType *) node)->name); return; + case Ast_Kind_Poly_Union_Type: + bh_buffer_write_string(buffer, ((AstPolyUnionType *) node)->name); + return; + case Ast_Kind_Poly_Call_Type: if (((AstPolyCallType *) node)->callee == (AstType *) builtin_optional_type) { bh_buffer_write_string(buffer, "? "); diff --git a/compiler/src/polymorph.h b/compiler/src/polymorph.h index ca1f84e9..0baea789 100644 --- a/compiler/src/polymorph.h +++ b/compiler/src/polymorph.h @@ -987,6 +987,18 @@ b32 potentially_convert_function_to_polyproc(AstFunction *func) { break; } + case Ast_Kind_Poly_Union_Type: { + AutoPolymorphVariable apv; + apv.idx = param_idx; + apv.base_type = param->local->type_node; + apv.variable_count = bh_arr_length(((AstPolyUnionType *) param_type)->poly_params); + apv.replace = to_replace; + + bh_arr_push(auto_vars, apv); + done = 1; + break; + } + default: done = 1; break; } } @@ -1013,7 +1025,8 @@ b32 potentially_convert_function_to_polyproc(AstFunction *func) { AstType *dealiased_base_type = (AstType *) strip_aliases((AstNode *) apv->base_type); - if (dealiased_base_type->kind == Ast_Kind_Poly_Struct_Type) { + if (dealiased_base_type->kind == Ast_Kind_Poly_Struct_Type + || dealiased_base_type->kind == Ast_Kind_Poly_Union_Type) { pp.type_expr = (AstType *) pcall; } else { pp.type_expr = apv->base_type; diff --git a/core/container/result.onyx b/core/container/result.onyx index d3836b29..2ef516d4 100644 --- a/core/container/result.onyx +++ b/core/container/result.onyx @@ -18,50 +18,49 @@ use core {Optional} of type T, or an Err value of type E. `status` contains either .Ok, or .Err depending on which is currently held. """ -@conv.Custom_Format.{ #solidify format {T=Ok_Type, E=Err_Type} } -Result :: struct (Ok_Type: type_expr, Err_Type: type_expr) { - status: Result_Status; - __data: Result_Data(Ok_Type, Err_Type); -} - -#doc """ - The type of Result(T, E).status -""" -Result_Status :: enum { - Ok :: 1; - Err :: 2; -} - -#local -Result_Data :: struct (T: type_expr, E: type_expr) { - value: T; - error: E; +Result :: union (Ok_Type: type_expr, Err_Type: type_expr) { + Err: Err_Type; + Ok: Ok_Type; } #inject Result { #doc "Quick way to return an Ok from a procedure." - return_ok :: macro (x: $T) do return .{ .Ok, .{ value = x } }; + return_ok :: macro (x: $T) do return .{ Ok = x }; #doc "Quick way to return an Err from a procedure." - return_err :: macro (x: $T) do return .{ .Err, .{ error = x } }; + return_err :: macro (x: $T) do return .{ Err = x }; #doc "Returns true if the result contains an Ok value." - is_ok :: (r: #Self) => r.status == .Ok; + is_ok :: (r: #Self) { + switch r { + case .Ok do return true; + case #default do return false; + } + } #doc "Returns true if the result contains an Err value." - is_err :: (r: #Self) => !r.status == .Err; + is_err :: (r: #Self) { + switch r { + case .Err do return true; + case #default do return false; + } + } #doc "Returns an Optional of the Ok type." ok :: (r: #Self) -> Optional(r.Ok_Type) { - if r.status == .Ok do return Optional.make(r.__data.value); - return .{}; + switch r { + case .Ok => v do return v; + case #default do return .{}; + } } #doc "Returns an Optional of the Err type." err :: (r: #Self) -> Optional(r.Err_Type) { - if r.status == .Err do return Optional.make(r.__data.error); - return .{}; + switch r { + case .Err => v do return v; + case #default do return .{}; + } } #doc """ @@ -69,13 +68,14 @@ Result_Data :: struct (T: type_expr, E: type_expr) { result contains an Err, an assertion is thrown. """ unwrap :: (r: #Self) -> r.Ok_Type { - if r.status == .Err { - msg := tprintf("Unwrapping Result with error '{}'.", r.__data.error); - assert(false, msg); - return .{}; + switch r { + case .Ok => v do return v; + case #default { + msg := tprintf("Unwrapping Result with error '{}'.", r.__data.error); + assert(false, msg); + return .{}; + } } - - return r.__data.value; } #doc """ @@ -83,9 +83,10 @@ Result_Data :: struct (T: type_expr, E: type_expr) { result contains an Err, the empty .{} value is returned. """ unwrap_or_default :: (r: #Self) -> r.Ok_Type { - if r.status == .Err do return .{}; - - return r.__data.value; + switch r { + case .Ok => v do return v; + case #default do return .{}; + } } #doc """ @@ -93,12 +94,12 @@ Result_Data :: struct (T: type_expr, E: type_expr) { result contains an Err, a custom assertion message is thrown. """ expect :: (r: #Self, msg: str) -> r.Ok_Type { - if r.status == .Err { - assert(false, msg); - return .{}; + switch r { + case .Ok => v do return v; + case #default { + assert(false, msg); + } } - - return r.__data.value; } #doc """ @@ -107,20 +108,26 @@ Result_Data :: struct (T: type_expr, E: type_expr) { Err(e) => Err(e) """ transform :: (r: Result($T, $E), f: (T) -> $R) -> Result(R, E) { - if r.status == .Err do return .{ .Err, .{ error = r.error } }; - return .{ .Ok, .{ value = f(r.__data.value) } }; + switch r { + case .Ok => v do return .{ Ok = f(v) }; + case .Err => v do return .{ Err = v }; + } } #doc "Monadic chaining operation." and_then :: (r: #Self, f: (r.Ok_Type) -> Result($R, r.Err_Type)) -> Result(R, r.Err_Type) { - if r.status == .Err do return r; - return .{ .Ok, .{ value = f(r.__data.value) } }; + switch r { + case .Ok => v do return f(v); + case .Err => v do return .{ Err = v }; + } } #doc "If the Result contains Err, generate is called to make a value" or_else :: (r: #Self, generate: () -> typeof r) => { - if r.status == .Ok do return r; - return .{}; + switch r { + case .Ok => v do return v; + case #default do return generate(); + } } #doc """ @@ -140,10 +147,10 @@ Result_Data :: struct (T: type_expr, E: type_expr) { } """ forward_err :: macro (r: Result($T, $E)) -> T { - res := r; - if res.status == .Ok do return res.__data.value; - - return return .{ .Err, .{ error = res.__data.error } }; + switch res := r; res { + case .Ok => v do return v; + case .Err => v do return return .{ Err = v }; + } } #doc """ @@ -151,10 +158,10 @@ Result_Data :: struct (T: type_expr, E: type_expr) { enclosing procedure. Otherwise, the Ok value is returned. """ or_return :: macro (r: Result($T, $E), v: $V) -> T { - res := r; - if res.status == .Ok do return res.__data.value; - - return return v; + switch res := r; res { + case .Ok => v do return v; + case .Err do return return v; + } } #doc """ @@ -166,37 +173,31 @@ Result_Data :: struct (T: type_expr, E: type_expr) { This procedure is subject to change. """ catch :: macro (r: Result($T, $E), on_err: Code) -> T { - res := r; - if res.status == .Ok do return res.__data.value; - - #unquote on_err; - } - - format :: (o: &conv.Format_Output, format: &conv.Format, res: &Result($T, $E)) { - if res.status == .Ok { - conv.format(o, "{}({\"})", res.status, res.__data.value); - } else { - conv.format(o, "{}({\"})", res.status, res.__data.error); + switch res := r; res { + case .Ok => v do return v; + case .Err { + #unquote on_err; + } } } } #overload -__implicit_bool_cast :: macro (r: Result($O, $E)) => r.status == .Ok; +__implicit_bool_cast :: macro (r: Result($O, $E)) => cast(Result(O, E).tag_enum, r) == .Ok; #operator ? macro (r: Result($T, $E)) -> T { - res := r; - if r.status == .Ok do return r.__data.value; - - return return .{ .Err, .{ error = res.__data.error } }; + switch res := r; res { + case .Ok => v do return v; + case .Err => v do return return .{ Err = v }; + } } #operator ?? macro (r: Result($T, $E), v: T) -> T { - r_ = r; - if r_.status == .Ok do return r_.__data.value; - - return v; + switch res := r; res { + case .Ok => v do return v; + case .Err do return v; + } } diff --git a/core/conv/format.onyx b/core/conv/format.onyx index f16b97c9..eb15333b 100644 --- a/core/conv/format.onyx +++ b/core/conv/format.onyx @@ -739,7 +739,9 @@ format_any :: (output: &Format_Output, formatting: &Format, v: any) { output->write(variant.name); if variant.type != void { output->write("("); - format_any(output, formatting, any.{ cast([&] u8) v.data + u.alignment, variant.type }); + format := *formatting; + format.quote_strings = true; + format_any(output, &format, any.{ cast([&] u8) v.data + u.alignment, variant.type }); output->write(")"); } } diff --git a/core/os/file.onyx b/core/os/file.onyx index db2077ea..c0e694e4 100644 --- a/core/os/file.onyx +++ b/core/os/file.onyx @@ -79,11 +79,11 @@ open :: (path: str, mode := OpenMode.Read) -> Result(File, os.FileError) { }; file_data, error := fs.__file_open(path, mode); - if error != .None do return .{ .Err, .{error=error} }; + if error != .None do return .{ Err = error }; file.data = file_data; file.vtable = &fs.__file_stream_vtable; - return .{ .Ok, .{value=file} }; + return .{ Ok = file }; } close :: (file: &File) { @@ -158,10 +158,10 @@ file_logger_open :: (filename: str, allocator := context.allocator) -> Result(&F raw_free(allocator, file_logger.file); raw_free(allocator, file_logger); - return return .{ .Err, .{error = "Unable to open file for logging."} }; + return return .{ Err = "Unable to open file for logging." }; }); - return .{ .Ok, .{ value=file_logger } }; + return .{ Ok = file_logger }; } file_logger_use :: (logger: &File_Logger) { diff --git a/tests/tagged_unions.onyx b/tests/tagged_unions.onyx index 50917f1e..92b03cc9 100644 --- a/tests/tagged_unions.onyx +++ b/tests/tagged_unions.onyx @@ -5,13 +5,21 @@ create_optional :: () -> ? i32 { return .{ Some = 123 }; } -new_optional_test :: () { +create_result :: () -> Result(i32, str) { + return .{ Ok = 987 }; + // return .{ Err = "oh no there was error :(" }; +} + +new_optional_test :: () -> Result(void, str) { v := create_optional(); - v2 := Optional(str).{ None = .{} }; + v2: ?str = "asdf"; println(v); println(v2); println(v->unwrap()); + + r := create_result()?; + println(r); } union_is :: macro (u: $U, $variant: U.tag_enum) -> bool { @@ -87,7 +95,7 @@ simple_test :: () { println(u); } -main :: () {simple_test(); link_test(); new_optional_test();} +main :: () {simple_test(); link_test(); new_optional_test()->err()? |> println();} Link :: union { End: void; @@ -97,15 +105,15 @@ Link :: union { } } -print_links :: (l: Link) { +print_links :: (l: &Link) { walker := l; while true { - switch walker { + switch *walker { case .End do break break; case .Next => &next { printf("{}\n", next.data); - walker = *next.next; + walker = next.next; } } } @@ -124,7 +132,7 @@ link_test :: () { } }; - print_links(l); + print_links(&l); } // main :: () { link_test(); }