Commit 39d5f44863

Andrew Kelley <superjoe30@gmail.com>
2018-02-02 20:26:14
*WI* error sets - basic support working
1 parent cfb2c67
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);
src/analyze.hpp
@@ -214,6 +214,8 @@ struct ConstCastErrSetMismatch {
     ZigList<ErrorTableEntry *> 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
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)));
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 => {
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;
 }
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;
 }
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",
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),
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;
 }
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);
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);
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);
     }
 }
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;
 }
 
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,
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 {
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,
 });
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; }
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