remove error set casting syntax. add @errSetCast

See #1061
This commit is contained in:
Andrew Kelley 2018-06-18 15:01:42 -04:00
parent 1ca90b5856
commit 5d705fc6e3
6 changed files with 109 additions and 16 deletions

View File

@ -4919,12 +4919,15 @@ test "main" {
</p>
{#see_also|@import#}
{#header_close#}
{#header_open|@export#}
<pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
{#header_open|@errSetCast#}
<pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre>
<p>
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#}.
</p>
{#header_close#}
{#header_open|@errorName#}
<pre><code class="zig">@errorName(err: error) []u8</code></pre>
<p>
@ -4949,6 +4952,14 @@ test "main" {
stack trace object. Otherwise returns `null`.
</p>
{#header_close#}
{#header_open|@export#}
<pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
<p>
Creates a symbol in the output object file.
</p>
{#header_close#}
{#header_open|@fence#}
<pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
<p>
@ -5817,10 +5828,10 @@ pub fn build(b: &Builder) void {
{#header_open|Undefined Behavior#}
<p>
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.
</p>
<p>
@ -6101,6 +6112,11 @@ comptime {
<p>TODO</p>
{#header_close#}
{#header_open|Invalid Error Set Cast#}
<p>TODO</p>
{#header_close#}
{#header_open|Incorrect Pointer Alignment#}
<p>TODO</p>
@ -6109,6 +6125,7 @@ comptime {
<p>TODO</p>
{#header_close#}
{#header_close#}
{#header_open|Memory#}
<p>TODO: explain no default allocator in zig</p>

View File

@ -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;

View File

@ -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) {

View File

@ -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<IrInstructionErrSetCast>(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<IrInstructionIntToFloat>(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:

View File

@ -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;

View File

@ -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);
}