From 39d5f44863aafa77163b2a7e32f2553a589dbb2c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 2 Feb 2018 14:26:14 -0500 Subject: [PATCH] *WI* error sets - basic support working --- TODO | 13 ++++- src/analyze.cpp | 4 +- src/analyze.hpp | 4 +- src/ir.cpp | 83 ++++++++++++++++++---------- std/debug/index.zig | 3 +- std/fmt/index.zig | 33 ++++++----- std/math/index.zig | 6 +- test/cases/cast.zig | 32 +++++------ test/cases/enum_with_members.zig | 2 +- test/cases/error.zig | 14 ++--- test/cases/ir_block_deps.zig | 2 +- test/cases/misc.zig | 8 +-- test/cases/reflection.zig | 2 +- test/cases/switch.zig | 2 +- test/cases/switch_prong_err_enum.zig | 4 +- test/cases/try.zig | 4 +- test/cases/union.zig | 2 +- test/cases/while.zig | 8 +-- 18 files changed, 134 insertions(+), 92 deletions(-) diff --git a/TODO b/TODO index 838aaba485..963169d5aa 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,15 @@ -sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find .. -name "*.zig") +sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find . -name "*.zig") -comptime assert(error{} ! i32 == i32); +the literal translation of `%T` to this new code is `error!T`. +however this would not take advantage of error sets. It's +recommended to generally have all your functions which return possible +errors to use error set inference, like this: + +fn foo() !void { + +} + +then you can return void, or any error, and the error set is inferred. // TODO this is an explicit cast and should actually coerce the type erorr set casting diff --git a/src/analyze.cpp b/src/analyze.cpp index ac504a3ea5..8ed5706a27 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3367,7 +3367,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so } ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { - ConstCastOnly result = {0}; + ConstCastOnly result = {}; result.id = ConstCastResultIdOk; if (expected_type == actual_type) @@ -3465,7 +3465,7 @@ ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_t if (result.id == ConstCastResultIdOk) { result.id = ConstCastResultIdErrSet; } - result.data.error_set.errors.append(contained_error_entry); + result.data.error_set.missing_errors.append(contained_error_entry); } } free(errors); diff --git a/src/analyze.hpp b/src/analyze.hpp index 551b892791..b7869d3a79 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -214,6 +214,8 @@ struct ConstCastErrSetMismatch { ZigList missing_errors; }; +struct ConstCastOnly; + struct ConstCastArg { size_t arg_index; ConstCastOnly *child; @@ -238,6 +240,6 @@ struct ConstCastOnly { } data; }; -bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type); +ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 00bde702d2..2e4a13927b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6424,12 +6424,23 @@ enum ImplicitCastMatchResult { static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, TypeTableEntry *actual_type, IrInstruction *value) { - if (types_match_const_cast_only(ira->codegen, expected_type, actual_type)) { + ConstCastOnly const_cast_result = types_match_const_cast_only(ira->codegen, expected_type, actual_type); + if (const_cast_result.id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } // if we got here with error sets, make an error showing the incompatibilities - if (expected_typek + if (const_cast_result.id == ConstCastResultIdErrSet) { + ErrorMsg *msg = ir_add_error(ira, value, + buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); + for (size_t i = 0; i < const_cast_result.data.error_set.missing_errors.length; i += 1) { + ErrorTableEntry *error_entry = const_cast_result.data.error_set.missing_errors.at(i); + add_error_note(ira->codegen, msg, error_entry->decl_node, + buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name))); + } + + return ImplicitCastMatchResultReportedError; + } // implicit conversion from anything to var if (expected_type->id == TypeTableEntryIdVar) { @@ -6508,7 +6519,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } @@ -6527,7 +6538,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *array_type = actual_type->data.pointer.child_type; if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type).id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } @@ -6543,7 +6554,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } @@ -6558,7 +6569,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } @@ -6638,7 +6649,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, // implicitly take a const pointer to something if (!type_requires_comptime(actual_type)) { TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); - if (types_match_const_cast_only(ira->codegen, expected_type, const_ptr_actual)) { + if (types_match_const_cast_only(ira->codegen, expected_type, const_ptr_actual).id == ConstCastResultIdOk) { return ImplicitCastMatchResultYes; } } @@ -6742,20 +6753,31 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod if (cur_is_superset) { err_set_type = cur_type; prev_inst = cur_inst; + assert(errors != nullptr); continue; } // neither of them are supersets. so we invent a new error set type that is a union of both of them err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type); + assert(errors != nullptr); continue; } else if (cur_type->id == TypeTableEntryIdErrorUnion) { + if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) { + prev_inst = cur_inst; + continue; + } + TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; + if (cur_err_set_type == ira->codegen->builtin_types.entry_global_error_set) { + err_set_type = ira->codegen->builtin_types.entry_global_error_set; + prev_inst = cur_inst; + continue; + } // test if err_set_type is a subset of cur_type's error set // unset everything in errors for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; errors[error_entry->value] = nullptr; } - TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; errors[error_entry->value] = error_entry; @@ -6772,12 +6794,14 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod if (cur_is_superset) { err_set_type = cur_err_set_type; prev_inst = cur_inst; + assert(errors != nullptr); continue; } // not a subset. invent new error set type, union of both of them err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type); prev_inst = cur_inst; + assert(errors != nullptr); continue; } else { prev_inst = cur_inst; @@ -6820,15 +6844,16 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod } // not a subset. invent new error set type, union of both of them err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type); + assert(errors != nullptr); continue; } } - if (types_match_const_cast_only(ira->codegen, prev_type, cur_type)) { + if (types_match_const_cast_only(ira->codegen, prev_type, cur_type).id == ConstCastResultIdOk) { continue; } - if (types_match_const_cast_only(ira->codegen, cur_type, prev_type)) { + if (types_match_const_cast_only(ira->codegen, cur_type, prev_type).id == ConstCastResultIdOk) { prev_inst = cur_inst; continue; } @@ -6851,26 +6876,26 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod } if (prev_type->id == TypeTableEntryIdErrorUnion && - types_match_const_cast_only(ira->codegen, prev_type->data.error_union.payload_type, cur_type)) + types_match_const_cast_only(ira->codegen, prev_type->data.error_union.payload_type, cur_type).id == ConstCastResultIdOk) { continue; } if (cur_type->id == TypeTableEntryIdErrorUnion && - types_match_const_cast_only(ira->codegen, cur_type->data.error_union.payload_type, prev_type)) + types_match_const_cast_only(ira->codegen, cur_type->data.error_union.payload_type, prev_type).id == ConstCastResultIdOk) { prev_inst = cur_inst; continue; } if (prev_type->id == TypeTableEntryIdMaybe && - types_match_const_cast_only(ira->codegen, prev_type->data.maybe.child_type, cur_type)) + types_match_const_cast_only(ira->codegen, prev_type->data.maybe.child_type, cur_type).id == ConstCastResultIdOk) { continue; } if (cur_type->id == TypeTableEntryIdMaybe && - types_match_const_cast_only(ira->codegen, cur_type->data.maybe.child_type, prev_type)) + types_match_const_cast_only(ira->codegen, cur_type->data.maybe.child_type, prev_type).id == ConstCastResultIdOk) { prev_inst = cur_inst; continue; @@ -6908,7 +6933,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && cur_type->data.array.len != prev_type->data.array.len && - types_match_const_cast_only(ira->codegen, cur_type->data.array.child_type, prev_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, cur_type->data.array.child_type, prev_type->data.array.child_type).id == ConstCastResultIdOk) { convert_to_const_slice = true; prev_inst = cur_inst; @@ -6917,7 +6942,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray && cur_type->data.array.len != prev_type->data.array.len && - types_match_const_cast_only(ira->codegen, prev_type->data.array.child_type, cur_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, prev_type->data.array.child_type, cur_type->data.array.child_type).id == ConstCastResultIdOk) { convert_to_const_slice = true; continue; @@ -6927,7 +6952,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod (prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || cur_type->data.array.len == 0) && types_match_const_cast_only(ira->codegen, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, - cur_type->data.array.child_type)) + cur_type->data.array.child_type).id == ConstCastResultIdOk) { convert_to_const_slice = false; continue; @@ -6937,7 +6962,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod (cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const || prev_type->data.array.len == 0) && types_match_const_cast_only(ira->codegen, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type, - prev_type->data.array.child_type)) + prev_type->data.array.child_type).id == ConstCastResultIdOk) { prev_inst = cur_inst; convert_to_const_slice = false; @@ -8059,7 +8084,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return value; // explicit match or non-const to const - if (types_match_const_cast_only(ira->codegen, wanted_type, actual_type)) { + if (types_match_const_cast_only(ira->codegen, wanted_type, actual_type).id == ConstCastResultIdOk) { return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); } @@ -8105,7 +8130,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); } @@ -8123,7 +8148,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst TypeTableEntry *array_type = actual_type->data.pointer.child_type; if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type).id == ConstCastResultIdOk) { return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); } @@ -8139,7 +8164,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); if (type_is_invalid(cast1->value.type)) @@ -8162,7 +8187,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); if (type_is_invalid(cast1->value.type)) @@ -8224,7 +8249,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { - if (types_match_const_cast_only(ira->codegen, wanted_type->data.maybe.child_type, actual_type)) { + if (types_match_const_cast_only(ira->codegen, wanted_type->data.maybe.child_type, actual_type).id == ConstCastResultIdOk) { return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) @@ -8246,7 +8271,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from child type of error type to error type if (wanted_type->id == TypeTableEntryIdErrorUnion) { - if (types_match_const_cast_only(ira->codegen, wanted_type->data.error_union.payload_type, actual_type)) { + if (types_match_const_cast_only(ira->codegen, wanted_type->data.error_union.payload_type, actual_type).id == ConstCastResultIdOk) { return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) @@ -8268,7 +8293,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == TypeTableEntryIdPointer); if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && - types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) + types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk) { IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); if (type_is_invalid(cast1->value.type)) @@ -8295,7 +8320,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id != TypeTableEntryIdMaybe) { TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; - if (types_match_const_cast_only(ira->codegen, wanted_child_type, actual_type) || + if (types_match_const_cast_only(ira->codegen, wanted_child_type, actual_type).id == ConstCastResultIdOk || actual_type->id == TypeTableEntryIdNullLit || actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) @@ -8445,7 +8470,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from something to const pointer of it if (!type_requires_comptime(actual_type)) { TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true); - if (types_match_const_cast_only(ira->codegen, wanted_type, const_ptr_actual)) { + if (types_match_const_cast_only(ira->codegen, wanted_type, const_ptr_actual).id == ConstCastResultIdOk) { return ir_analyze_cast_ref(ira, source_instr, value, wanted_type); } } @@ -8473,7 +8498,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value); switch (result) { case ImplicitCastMatchResultNo: - ErrorMsg *msg = ir_add_error(ira, value, + ir_add_error(ira, value, buf_sprintf("expected type '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&value->value.type->name))); diff --git a/std/debug/index.zig b/std/debug/index.zig index 6bb578e5bf..4778d63dd2 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -209,8 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); } } else |err| switch (err) { - error.EndOfFile, error.PathNotFound => {}, - else => return err, + error.EndOfFile => {}, } } else |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => { diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 99a8f69c24..26583817e6 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -195,7 +195,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@ const T = @typeOf(value); switch (@typeId(T)) { builtin.TypeId.Int => { - return formatInt(value, 10, false, 0, context, output); + return formatInt(value, 10, false, 0, context, Errors, output); }, builtin.TypeId.Float => { return formatFloat(value, context, output); @@ -290,7 +290,7 @@ pub fn formatFloat(value: var, context: var, comptime Errors: type, output: fn(@ if (float_decimal.exp != 1) { try output(context, "e"); - try formatInt(float_decimal.exp - 1, 10, false, 0, context, output); + try formatInt(float_decimal.exp - 1, 10, false, 0, context, Errors, output); } } @@ -336,12 +336,12 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, comptime E pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, - context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)errors!void) errors!void + context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void { if (@typeOf(value).is_signed) { - return formatIntSigned(value, base, uppercase, width, context, output); + return formatIntSigned(value, base, uppercase, width, context, Errors, output); } else { - return formatIntUnsigned(value, base, uppercase, width, context, output); + return formatIntUnsigned(value, base, uppercase, width, context, Errors, output); } } @@ -354,15 +354,15 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize, try output(context, (&minus_sign)[0..1]); const new_value = uint(-(value + 1)) + 1; const new_width = if (width == 0) 0 else (width - 1); - return formatIntUnsigned(new_value, base, uppercase, new_width, context, output); + return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output); } else if (width == 0) { - return formatIntUnsigned(uint(value), base, uppercase, width, context, output); + return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output); } else { const plus_sign: u8 = '+'; try output(context, (&plus_sign)[0..1]); const new_value = uint(value); const new_width = if (width == 0) 0 else (width - 1); - return formatIntUnsigned(new_value, base, uppercase, new_width, context, output); + return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output); } } @@ -410,7 +410,7 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width: .out_buf = out_buf, .index = 0, }; - formatInt(value, base, uppercase, width, &context, formatIntCallback) catch unreachable; + formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable; return context.index; } const FormatIntBuf = struct { @@ -446,7 +446,14 @@ test "fmt.parseInt" { assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); } -pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) !T { +const ParseUnsignedError = error { + /// The result cannot fit in the type specified + Overflow, + /// The input had a byte that was not a digit + InvalidCharacter, +}; + +pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T { var x: T = 0; for (buf) |c| { @@ -458,16 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) !T { return x; } -fn charToDigit(c: u8, radix: u8) !u8 { +fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { const value = switch (c) { '0' ... '9' => c - '0', 'A' ... 'Z' => c - 'A' + 10, 'a' ... 'z' => c - 'a' + 10, - else => return error.InvalidChar, + else => return error.InvalidCharacter, }; if (value >= radix) - return error.InvalidChar; + return error.InvalidCharacter; return value; } diff --git a/std/math/index.zig b/std/math/index.zig index 9c5e35ef17..f8668cc00d 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -191,17 +191,17 @@ test "math.max" { assert(max(i32(-1), i32(2)) == 2); } -pub fn mul(comptime T: type, a: T, b: T) !T { +pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { var answer: T = undefined; return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer; } -pub fn add(comptime T: type, a: T, b: T) !T { +pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) { var answer: T = undefined; return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer; } -pub fn sub(comptime T: type, a: T, b: T) !T { +pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) { var answer: T = undefined; return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer; } diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 994bf2a8b1..6ffb558174 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -74,7 +74,7 @@ test "string literal to &const []const u8" { assert(mem.eql(u8, *x, "hello")); } -test "implicitly cast from T to %?T" { +test "implicitly cast from T to error!?T" { castToMaybeTypeError(1); comptime castToMaybeTypeError(1); } @@ -83,37 +83,37 @@ const A = struct { }; fn castToMaybeTypeError(z: i32) void { const x = i32(1); - const y: %?i32 = x; + const y: error!?i32 = x; assert(??(try y) == 1); const f = z; - const g: %?i32 = f; + const g: error!?i32 = f; const a = A{ .a = z }; - const b: %?A = a; + const b: error!?A = a; assert((??(b catch unreachable)).a == 1); } -test "implicitly cast from int to %?T" { +test "implicitly cast from int to error!?T" { implicitIntLitToMaybe(); comptime implicitIntLitToMaybe(); } fn implicitIntLitToMaybe() void { const f: ?i32 = 1; - const g: %?i32 = 1; + const g: error!?i32 = 1; } -test "return null from fn() %?&T" { +test "return null from fn() error!?&T" { const a = returnNullFromMaybeTypeErrorRef(); const b = returnNullLitFromMaybeTypeErrorRef(); assert((try a) == null and (try b) == null); } -fn returnNullFromMaybeTypeErrorRef() !?&A { +fn returnNullFromMaybeTypeErrorRef() error!?&A { const a: ?&A = null; return a; } -fn returnNullLitFromMaybeTypeErrorRef() !?&A { +fn returnNullLitFromMaybeTypeErrorRef() error!?&A { return null; } @@ -160,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 { } -test "implicitly cast from [0]T to %[]T" { +test "implicitly cast from [0]T to error![]T" { testCastZeroArrayToErrSliceMut(); comptime testCastZeroArrayToErrSliceMut(); } @@ -169,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void { assert((gimmeErrOrSlice() catch unreachable).len == 0); } -fn gimmeErrOrSlice() ![]u8 { +fn gimmeErrOrSlice() error![]u8 { return []u8{}; } -test "peer type resolution: [0]u8, []const u8, and %[]u8" { +test "peer type resolution: [0]u8, []const u8, and error![]u8" { { var data = "hi"; const slice = data[0..]; @@ -187,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" { assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } } -fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) ![]u8 { +fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 { if (a) { return []u8{}; } @@ -229,7 +229,7 @@ fn foo(args: ...) void { test "peer type resolution: error and [N]T" { - // TODO: implicit %T to %U where T can implicitly cast to U + // TODO: implicit error!T to error!U where T can implicitly cast to U //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); @@ -237,13 +237,13 @@ test "peer type resolution: error and [N]T" { comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); } -//fn testPeerErrorAndArray(x: u8) ![]const u8 { +//fn testPeerErrorAndArray(x: u8) error![]const u8 { // return switch (x) { // 0x00 => "OK", // else => error.BadValue, // }; //} -fn testPeerErrorAndArray2(x: u8) ![]const u8 { +fn testPeerErrorAndArray2(x: u8) error![]const u8 { return switch (x) { 0x00 => "OK", 0x01 => "OKK", diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig index 9fc8104cf8..0c2ae1c383 100644 --- a/test/cases/enum_with_members.zig +++ b/test/cases/enum_with_members.zig @@ -6,7 +6,7 @@ const ET = union(enum) { SINT: i32, UINT: u32, - pub fn print(a: &const ET, buf: []u8) !usize { + pub fn print(a: &const ET, buf: []u8) error!usize { return switch (*a) { ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), diff --git a/test/cases/error.zig b/test/cases/error.zig index 3564ce60aa..f35f2e7ad6 100644 --- a/test/cases/error.zig +++ b/test/cases/error.zig @@ -1,16 +1,16 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; -pub fn foo() !i32 { +pub fn foo() error!i32 { const x = try bar(); return x + 1; } -pub fn bar() !i32 { +pub fn bar() error!i32 { return 13; } -pub fn baz() !i32 { +pub fn baz() error!i32 { const y = foo() catch 1234; return y + 1; } @@ -50,7 +50,7 @@ test "error binary operator" { assert(a == 3); assert(b == 10); } -fn errBinaryOperatorG(x: bool) !isize { +fn errBinaryOperatorG(x: bool) error!isize { return if (x) error.ItBroke else isize(10); } @@ -59,18 +59,18 @@ test "unwrap simple value from error" { const i = unwrapSimpleValueFromErrorDo() catch unreachable; assert(i == 13); } -fn unwrapSimpleValueFromErrorDo() %isize { return 13; } +fn unwrapSimpleValueFromErrorDo() error!isize { return 13; } test "error return in assignment" { doErrReturnInAssignment() catch unreachable; } -fn doErrReturnInAssignment() !void { +fn doErrReturnInAssignment() error!void { var x : i32 = undefined; x = try makeANonErr(); } -fn makeANonErr() !i32 { +fn makeANonErr() error!i32 { return 1; } diff --git a/test/cases/ir_block_deps.zig b/test/cases/ir_block_deps.zig index a762e6e01f..202df19f62 100644 --- a/test/cases/ir_block_deps.zig +++ b/test/cases/ir_block_deps.zig @@ -11,7 +11,7 @@ fn foo(id: u64) !i32 { }; } -fn getErrInt() %i32 { return 0; } +fn getErrInt() error!i32 { return 0; } test "ir block deps" { assert((foo(1) catch unreachable) == 0); diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 314d7d518e..964c5babc1 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -262,7 +262,7 @@ test "generic malloc free" { memFree(u8, a); } const some_mem : [100]u8 = undefined; -fn memAlloc(comptime T: type, n: usize) ![]T { +fn memAlloc(comptime T: type, n: usize) error![]T { return @ptrCast(&T, &some_mem[0])[0..n]; } fn memFree(comptime T: type, memory: []T) void { } @@ -419,7 +419,7 @@ test "cast slice to u8 slice" { test "pointer to void return type" { testPointerToVoidReturnType() catch unreachable; } -fn testPointerToVoidReturnType() !void { +fn testPointerToVoidReturnType() error!void { const a = testPointerToVoidReturnType2(); return *a; } @@ -475,8 +475,8 @@ test "@typeId" { assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral); assert(@typeId(@typeOf(null)) == Tid.NullLiteral); assert(@typeId(?i32) == Tid.Nullable); - assert(@typeId(%i32) == Tid.ErrorUnion); - assert(@typeId(error) == Tid.Error); + assert(@typeId(error!i32) == Tid.ErrorUnion); + assert(@typeId(error) == Tid.ErrorSet); assert(@typeId(AnEnum) == Tid.Enum); assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); assert(@typeId(AUnionEnum) == Tid.Union); diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig index 8e103a3bc7..18a766d9fc 100644 --- a/test/cases/reflection.zig +++ b/test/cases/reflection.zig @@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" { comptime { assert(([10]u8).Child == u8); assert((&u8).Child == u8); - assert((%u8).Child == u8); + assert((error!u8).Payload == u8); assert((?u8).Child == u8); } } diff --git a/test/cases/switch.zig b/test/cases/switch.zig index 156333c571..a0ac646160 100644 --- a/test/cases/switch.zig +++ b/test/cases/switch.zig @@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 { return 10; } -fn return_a_number() !i32 { +fn return_a_number() error!i32 { return 1; } diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig index aa9deea28d..136e8834e6 100644 --- a/test/cases/switch_prong_err_enum.zig +++ b/test/cases/switch_prong_err_enum.zig @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert; var read_count: u64 = 0; -fn readOnce() !u64 { +fn readOnce() error!u64 { read_count += 1; return read_count; } @@ -12,7 +12,7 @@ const FormValue = union(enum) { Other: bool, }; -fn doThing(form_id: u64) !FormValue { +fn doThing(form_id: u64) error!FormValue { return switch (form_id) { 17 => FormValue { .Address = try readOnce() }, else => error.InvalidDebugInfo, diff --git a/test/cases/try.zig b/test/cases/try.zig index 6878a7c98d..4a0425e22e 100644 --- a/test/cases/try.zig +++ b/test/cases/try.zig @@ -17,7 +17,7 @@ fn tryOnErrorUnionImpl() void { assert(x == 11); } -fn returnsTen() !i32 { +fn returnsTen() error!i32 { return 10; } @@ -29,7 +29,7 @@ test "try without vars" { assert(result2 == 1); } -fn failIfTrue(ok: bool) !void { +fn failIfTrue(ok: bool) error!void { if (ok) { return error.ItBroke; } else { diff --git a/test/cases/union.zig b/test/cases/union.zig index ea8a9da188..dc2a7c3414 100644 --- a/test/cases/union.zig +++ b/test/cases/union.zig @@ -13,7 +13,7 @@ const Agg = struct { const v1 = Value { .Int = 1234 }; const v2 = Value { .Array = []u8{3} ** 9 }; -const err = (%Agg)(Agg { +const err = (error!Agg)(Agg { .val1 = v1, .val2 = v2, }); diff --git a/test/cases/while.zig b/test/cases/while.zig index 0b3d2660ed..33d5a5623a 100644 --- a/test/cases/while.zig +++ b/test/cases/while.zig @@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void { test "return with implicit cast from while loop" { returnWithImplicitCastFromWhileLoopTest() catch unreachable; } -fn returnWithImplicitCastFromWhileLoopTest() !void { +fn returnWithImplicitCastFromWhileLoopTest() error!void { while (true) { return; } @@ -116,7 +116,7 @@ test "while with error union condition" { } var numbers_left: i32 = undefined; -fn getNumberOrErr() !i32 { +fn getNumberOrErr() error!i32 { return if (numbers_left == 0) error.OutOfNumbers else x: { @@ -204,7 +204,7 @@ fn testContinueOuter() void { fn returnNull() ?i32 { return null; } fn returnMaybe(x: i32) ?i32 { return x; } -fn returnError() %i32 { return error.YouWantedAnError; } -fn returnSuccess(x: i32) %i32 { return x; } +fn returnError() error!i32 { return error.YouWantedAnError; } +fn returnSuccess(x: i32) error!i32 { return x; } fn returnFalse() bool { return false; } fn returnTrue() bool { return true; }