From 5d705fc6e35e75a604d3dbbb377ab01bf2b2b575 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 18 Jun 2018 15:01:42 -0400 Subject: [PATCH] remove error set casting syntax. add `@errSetCast` See #1061 --- doc/langref.html.in | 31 +++++++++++++++----- src/all_types.hpp | 9 ++++++ src/codegen.cpp | 2 ++ src/ir.cpp | 68 +++++++++++++++++++++++++++++++++++++++----- src/ir_print.cpp | 11 +++++++ test/cases/error.zig | 4 +-- 6 files changed, 109 insertions(+), 16 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f1ae2bafaa..48f525fedc 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4919,12 +4919,15 @@ test "main" {

{#see_also|@import#} {#header_close#} - {#header_open|@export#} -
@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8
+ + {#header_open|@errSetCast#} +
@errSetCast(comptime T: DestType, value: var) DestType

- Creates a symbol in the output object file. + Converts an error value from one error set to another error set. Attempting to convert an error + which is not in the destination error set results in {#link|Undefined Behavior#}.

{#header_close#} + {#header_open|@errorName#}
@errorName(err: error) []u8

@@ -4949,6 +4952,14 @@ test "main" { stack trace object. Otherwise returns `null`.

{#header_close#} + + {#header_open|@export#} +
@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8
+

+ Creates a symbol in the output object file. +

+ {#header_close#} + {#header_open|@fence#}
@fence(order: AtomicOrder)

@@ -5817,10 +5828,10 @@ pub fn build(b: &Builder) void { {#header_open|Undefined Behavior#}

Zig has many instances of undefined behavior. If undefined behavior is - detected at compile-time, Zig emits an error. Most undefined behavior that - cannot be detected at compile-time can be detected at runtime. In these cases, - Zig has safety checks. Safety checks can be disabled on a per-block basis - with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#} + detected at compile-time, Zig emits a compile error and refuses to continue. + Most undefined behavior that cannot be detected at compile-time can be detected + at runtime. In these cases, Zig has safety checks. Safety checks can be disabled + on a per-block basis with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#} build mode disables all safety checks in order to facilitate optimizations.

@@ -6101,6 +6112,11 @@ comptime {

TODO

{#header_close#} + + {#header_open|Invalid Error Set Cast#} +

TODO

+ {#header_close#} + {#header_open|Incorrect Pointer Alignment#}

TODO

@@ -6109,6 +6125,7 @@ comptime {

TODO

{#header_close#} + {#header_close#} {#header_open|Memory#}

TODO: explain no default allocator in zig

diff --git a/src/all_types.hpp b/src/all_types.hpp index d94dfa0fcb..732af239e2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1359,6 +1359,7 @@ enum BuiltinFnId { BuiltinFnIdTruncate, BuiltinFnIdIntCast, BuiltinFnIdFloatCast, + BuiltinFnIdErrSetCast, BuiltinFnIdIntToFloat, BuiltinFnIdFloatToInt, BuiltinFnIdBoolToInt, @@ -2121,6 +2122,7 @@ enum IrInstructionId { IrInstructionIdMergeErrRetTraces, IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, + IrInstructionIdErrSetCast, }; struct IrInstruction { @@ -2656,6 +2658,13 @@ struct IrInstructionFloatCast { IrInstruction *target; }; +struct IrInstructionErrSetCast { + IrInstruction base; + + IrInstruction *dest_type; + IrInstruction *target; +}; + struct IrInstructionIntToFloat { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 84335d4e06..585881a9a5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4727,6 +4727,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdIntToFloat: case IrInstructionIdFloatToInt: case IrInstructionIdBoolToInt: + case IrInstructionIdErrSetCast: zig_unreachable(); case IrInstructionIdReturn: @@ -6356,6 +6357,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3); + create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index c75a3ae7c1..e5ba4114cf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatCast *) { return IrInstructionIdFloatCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) { + return IrInstructionIdErrSetCast; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) { return IrInstructionIdIntToFloat; } @@ -1941,6 +1945,17 @@ static IrInstruction *ir_build_float_cast(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) { + IrInstructionErrSetCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) { IrInstructionIntToFloat *instruction = ir_build_instruction(irb, scope, source_node); instruction->dest_type = dest_type; @@ -4054,6 +4069,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdErrSetCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } case BuiltinFnIdIntToFloat: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -10104,13 +10134,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } - // explicit error set cast - if (wanted_type->id == TypeTableEntryIdErrorSet && - actual_type->id == TypeTableEntryIdErrorSet) - { - return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type); - } - // explicit cast from [N]T to []const T if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) { TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; @@ -17593,6 +17616,34 @@ static TypeTableEntry *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstr return dest_type; } +static TypeTableEntry *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) { + TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other); + if (type_is_invalid(dest_type)) + return ira->codegen->builtin_types.entry_invalid; + + if (dest_type->id != TypeTableEntryIdErrorSet) { + ir_add_error(ira, instruction->dest_type, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *target = instruction->target->other; + if (type_is_invalid(target->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + if (target->value.type->id != TypeTableEntryIdErrorSet) { + ir_add_error(ira, instruction->target, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value.type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *result = ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type); + if (type_is_invalid(result->value.type)) + return ira->codegen->builtin_types.entry_invalid; + ir_link_new_instruction(result, &instruction->base); + return dest_type; +} + static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other); if (type_is_invalid(dest_type)) @@ -20193,6 +20244,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_int_cast(ira, (IrInstructionIntCast *)instruction); case IrInstructionIdFloatCast: return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction); + case IrInstructionIdErrSetCast: + return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction); case IrInstructionIdIntToFloat: return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction); case IrInstructionIdFloatToInt: @@ -20544,6 +20597,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: + case IrInstructionIdErrSetCast: case IrInstructionIdIntToFloat: case IrInstructionIdFloatToInt: case IrInstructionIdBoolToInt: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index cb91720180..2667c246a5 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -664,6 +664,14 @@ static void ir_print_float_cast(IrPrint *irp, IrInstructionFloatCast *instructio fprintf(irp->f, ")"); } +static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruction) { + fprintf(irp->f, "@errSetCast("); + ir_print_other_instruction(irp, instruction->dest_type); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) { fprintf(irp->f, "@intToFloat("); ir_print_other_instruction(irp, instruction->dest_type); @@ -1461,6 +1469,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdFloatCast: ir_print_float_cast(irp, (IrInstructionFloatCast *)instruction); break; + case IrInstructionIdErrSetCast: + ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction); + break; case IrInstructionIdIntToFloat: ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction); break; diff --git a/test/cases/error.zig b/test/cases/error.zig index 693631fe2d..95890d8384 100644 --- a/test/cases/error.zig +++ b/test/cases/error.zig @@ -124,8 +124,8 @@ const Set2 = error{ }; fn testExplicitErrorSetCast(set1: Set1) void { - var x = Set2(set1); - var y = Set1(x); + var x = @errSetCast(Set2, set1); + var y = @errSetCast(Set1, x); assert(y == error.A); }