| author | |
| committer | |
| log | b8f59e14cdbf90cf724ed9e721c1909293f41b3b |
| tree | ef7a9f2b4534f691e6284b16218c354654abb9e5 |
| parent | 39d5f44863aafa77163b2a7e32f2553a589dbb2c |
16 files changed, 350 insertions(+), 89 deletions(-)
TODO+12| ... | @@ -13,3 +13,15 @@ then you can return void, or any error, and the error set is inferred. | ... | @@ -13,3 +13,15 @@ then you can return void, or any error, and the error set is inferred. |
| 13 | 13 | ||
| 14 | // TODO this is an explicit cast and should actually coerce the type | 14 | // TODO this is an explicit cast and should actually coerce the type |
| 15 | erorr set casting | 15 | erorr set casting |
| 16 | |||
| 17 | |||
| 18 | test err should be comptime if error set has 0 members | ||
| 19 | |||
| 20 | comptime calling fn with inferred error set should give empty error set but still you can use try | ||
| 21 | |||
| 22 | comptime err to int of empty err set and of size 1 err set | ||
| 23 | |||
| 24 | comptime test for err | ||
| 25 | |||
| 26 | |||
| 27 | undefined in infer error |
doc/langref.html.in+1-1| ... | @@ -5682,7 +5682,7 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | | ... | @@ -5682,7 +5682,7 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | |
| 5682 | 5682 | ||
| 5683 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) | 5683 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) |
| 5684 | 5684 | ||
| 5685 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | 5685 | MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" |
| 5686 | 5686 | ||
| 5687 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression | 5687 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression |
| 5688 | 5688 |
src/all_types.hpp+3-2| ... | @@ -510,8 +510,7 @@ enum BinOpType { | ... | @@ -510,8 +510,7 @@ enum BinOpType { |
| 510 | BinOpTypeAssignBitAnd, | 510 | BinOpTypeAssignBitAnd, |
| 511 | BinOpTypeAssignBitXor, | 511 | BinOpTypeAssignBitXor, |
| 512 | BinOpTypeAssignBitOr, | 512 | BinOpTypeAssignBitOr, |
| 513 | BinOpTypeAssignBoolAnd, | 513 | BinOpTypeAssignMergeErrorSets, |
| 514 | BinOpTypeAssignBoolOr, | ||
| 515 | BinOpTypeBoolOr, | 514 | BinOpTypeBoolOr, |
| 516 | BinOpTypeBoolAnd, | 515 | BinOpTypeBoolAnd, |
| 517 | BinOpTypeCmpEq, | 516 | BinOpTypeCmpEq, |
| ... | @@ -537,6 +536,7 @@ enum BinOpType { | ... | @@ -537,6 +536,7 @@ enum BinOpType { |
| 537 | BinOpTypeArrayCat, | 536 | BinOpTypeArrayCat, |
| 538 | BinOpTypeArrayMult, | 537 | BinOpTypeArrayMult, |
| 539 | BinOpTypeErrorUnion, | 538 | BinOpTypeErrorUnion, |
| 539 | BinOpTypeMergeErrorSets, | ||
| 540 | }; | 540 | }; |
| 541 | 541 | ||
| 542 | struct AstNodeBinOpExpr { | 542 | struct AstNodeBinOpExpr { |
| ... | @@ -2054,6 +2054,7 @@ enum IrBinOp { | ... | @@ -2054,6 +2054,7 @@ enum IrBinOp { |
| 2054 | IrBinOpRemMod, | 2054 | IrBinOpRemMod, |
| 2055 | IrBinOpArrayCat, | 2055 | IrBinOpArrayCat, |
| 2056 | IrBinOpArrayMult, | 2056 | IrBinOpArrayMult, |
| 2057 | IrBinOpMergeErrorSets, | ||
| 2057 | }; | 2058 | }; |
| 2058 | 2059 | ||
| 2059 | struct IrInstructionBinOp { | 2060 | struct IrInstructionBinOp { |
src/analyze.cpp+38-4| ... | @@ -530,7 +530,6 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T | ... | @@ -530,7 +530,6 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T |
| 530 | 530 | ||
| 531 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); | 531 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); |
| 532 | entry->is_copyable = true; | 532 | entry->is_copyable = true; |
| 533 | assert(payload_type->type_ref); | ||
| 534 | assert(payload_type->di_type); | 533 | assert(payload_type->di_type); |
| 535 | ensure_complete_type(g, payload_type); | 534 | ensure_complete_type(g, payload_type); |
| 536 | 535 | ||
| ... | @@ -541,9 +540,16 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T | ... | @@ -541,9 +540,16 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T |
| 541 | entry->data.error_union.payload_type = payload_type; | 540 | entry->data.error_union.payload_type = payload_type; |
| 542 | 541 | ||
| 543 | if (!type_has_bits(payload_type)) { | 542 | if (!type_has_bits(payload_type)) { |
| 544 | entry->type_ref = err_set_type->type_ref; | 543 | if (type_has_bits(err_set_type)) { |
| 545 | entry->di_type = err_set_type->di_type; | 544 | entry->type_ref = err_set_type->type_ref; |
| 546 | 545 | entry->di_type = err_set_type->di_type; | |
| 546 | } else { | ||
| 547 | entry->zero_bits = true; | ||
| 548 | entry->di_type = g->builtin_types.entry_void->di_type; | ||
| 549 | } | ||
| 550 | } else if (!type_has_bits(err_set_type)) { | ||
| 551 | entry->type_ref = payload_type->type_ref; | ||
| 552 | entry->di_type = payload_type->di_type; | ||
| 547 | } else { | 553 | } else { |
| 548 | LLVMTypeRef elem_types[] = { | 554 | LLVMTypeRef elem_types[] = { |
| 549 | err_set_type->type_ref, | 555 | err_set_type->type_ref, |
| ... | @@ -3841,6 +3847,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari | ... | @@ -3841,6 +3847,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari |
| 3841 | } | 3847 | } |
| 3842 | } | 3848 | } |
| 3843 | 3849 | ||
| 3850 | static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) { | ||
| 3851 | FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn; | ||
| 3852 | if (infer_fn != nullptr) { | ||
| 3853 | if (infer_fn->anal_state == FnAnalStateInvalid) { | ||
| 3854 | return false; | ||
| 3855 | } else if (infer_fn->anal_state == FnAnalStateReady) { | ||
| 3856 | analyze_fn_body(g, infer_fn); | ||
| 3857 | if (err_set_type->data.error_set.infer_fn != nullptr) { | ||
| 3858 | assert(g->errors.length != 0); | ||
| 3859 | return false; | ||
| 3860 | } | ||
| 3861 | } else { | ||
| 3862 | add_node_error(g, source_node, | ||
| 3863 | buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet", | ||
| 3864 | buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name))); | ||
| 3865 | return false; | ||
| 3866 | } | ||
| 3867 | } | ||
| 3868 | return true; | ||
| 3869 | } | ||
| 3870 | |||
| 3844 | void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) { | 3871 | void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) { |
| 3845 | TypeTableEntry *fn_type = fn_table_entry->type_entry; | 3872 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 3846 | assert(!fn_type->data.fn.is_generic); | 3873 | assert(!fn_type->data.fn.is_generic); |
| ... | @@ -3871,6 +3898,13 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ | ... | @@ -3871,6 +3898,13 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3871 | return; | 3898 | return; |
| 3872 | } | 3899 | } |
| 3873 | 3900 | ||
| 3901 | if (inferred_err_set_type->data.error_set.infer_fn != nullptr) { | ||
| 3902 | if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) { | ||
| 3903 | fn_table_entry->anal_state = FnAnalStateInvalid; | ||
| 3904 | return; | ||
| 3905 | } | ||
| 3906 | } | ||
| 3907 | |||
| 3874 | return_err_set_type->data.error_set.infer_fn = nullptr; | 3908 | return_err_set_type->data.error_set.infer_fn = nullptr; |
| 3875 | return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; | 3909 | return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; |
| 3876 | return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count); | 3910 | return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count); |
src/ast_render.cpp+2-2| ... | @@ -49,12 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) { | ... | @@ -49,12 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) { |
| 49 | case BinOpTypeAssignBitAnd: return "&="; | 49 | case BinOpTypeAssignBitAnd: return "&="; |
| 50 | case BinOpTypeAssignBitXor: return "^="; | 50 | case BinOpTypeAssignBitXor: return "^="; |
| 51 | case BinOpTypeAssignBitOr: return "|="; | 51 | case BinOpTypeAssignBitOr: return "|="; |
| 52 | case BinOpTypeAssignBoolAnd: return "&&="; | 52 | case BinOpTypeAssignMergeErrorSets: return "||="; |
| 53 | case BinOpTypeAssignBoolOr: return "||="; | ||
| 54 | case BinOpTypeUnwrapMaybe: return "??"; | 53 | case BinOpTypeUnwrapMaybe: return "??"; |
| 55 | case BinOpTypeArrayCat: return "++"; | 54 | case BinOpTypeArrayCat: return "++"; |
| 56 | case BinOpTypeArrayMult: return "**"; | 55 | case BinOpTypeArrayMult: return "**"; |
| 57 | case BinOpTypeErrorUnion: return "!"; | 56 | case BinOpTypeErrorUnion: return "!"; |
| 57 | case BinOpTypeMergeErrorSets: return "||"; | ||
| 58 | } | 58 | } |
| 59 | zig_unreachable(); | 59 | zig_unreachable(); |
| 60 | } | 60 | } |
src/codegen.cpp+21-1| ... | @@ -1799,6 +1799,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1799,6 +1799,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1799 | case IrBinOpArrayCat: | 1799 | case IrBinOpArrayCat: |
| 1800 | case IrBinOpArrayMult: | 1800 | case IrBinOpArrayMult: |
| 1801 | case IrBinOpRemUnspecified: | 1801 | case IrBinOpRemUnspecified: |
| 1802 | case IrBinOpMergeErrorSets: | ||
| 1802 | zig_unreachable(); | 1803 | zig_unreachable(); |
| 1803 | case IrBinOpBoolOr: | 1804 | case IrBinOpBoolOr: |
| 1804 | return LLVMBuildOr(g->builder, op1_value, op2_value, ""); | 1805 | return LLVMBuildOr(g->builder, op1_value, op2_value, ""); |
| ... | @@ -2188,6 +2189,9 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I | ... | @@ -2188,6 +2189,9 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I |
| 2188 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), | 2189 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2189 | g->err_tag_type, wanted_type, target_val); | 2190 | g->err_tag_type, wanted_type, target_val); |
| 2190 | } else if (actual_type->id == TypeTableEntryIdErrorUnion) { | 2191 | } else if (actual_type->id == TypeTableEntryIdErrorUnion) { |
| 2192 | // this should have been a compile time constant | ||
| 2193 | assert(type_has_bits(actual_type->data.error_union.err_set_type)); | ||
| 2194 | |||
| 2191 | if (!type_has_bits(actual_type->data.error_union.payload_type)) { | 2195 | if (!type_has_bits(actual_type->data.error_union.payload_type)) { |
| 2192 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), | 2196 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2193 | g->err_tag_type, wanted_type, target_val); | 2197 | g->err_tag_type, wanted_type, target_val); |
| ... | @@ -3428,6 +3432,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -3428,6 +3432,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3428 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); | 3432 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); |
| 3429 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); | 3433 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3430 | 3434 | ||
| 3435 | if (!type_has_bits(err_union_type->data.error_union.err_set_type)) { | ||
| 3436 | return err_union_handle; | ||
| 3437 | } | ||
| 3438 | |||
| 3431 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { | 3439 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { |
| 3432 | LLVMValueRef err_val; | 3440 | LLVMValueRef err_val; |
| 3433 | if (type_has_bits(payload_type)) { | 3441 | if (type_has_bits(payload_type)) { |
| ... | @@ -3490,9 +3498,11 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable | ... | @@ -3490,9 +3498,11 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable |
| 3490 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 3498 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3491 | 3499 | ||
| 3492 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; | 3500 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; |
| 3501 | TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type; | ||
| 3502 | |||
| 3493 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); | 3503 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); |
| 3494 | 3504 | ||
| 3495 | if (!type_has_bits(payload_type)) | 3505 | if (!type_has_bits(payload_type) || !type_has_bits(err_set_type)) |
| 3496 | return err_val; | 3506 | return err_val; |
| 3497 | 3507 | ||
| 3498 | assert(instruction->tmp_ptr); | 3508 | assert(instruction->tmp_ptr); |
| ... | @@ -3509,6 +3519,11 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa | ... | @@ -3509,6 +3519,11 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 3509 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | 3519 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3510 | 3520 | ||
| 3511 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; | 3521 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; |
| 3522 | TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type; | ||
| 3523 | |||
| 3524 | if (!type_has_bits(err_set_type)) { | ||
| 3525 | return ir_llvm_value(g, instruction->value); | ||
| 3526 | } | ||
| 3512 | 3527 | ||
| 3513 | LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); | 3528 | LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); |
| 3514 | 3529 | ||
| ... | @@ -4328,9 +4343,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -4328,9 +4343,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4328 | case TypeTableEntryIdErrorUnion: | 4343 | case TypeTableEntryIdErrorUnion: |
| 4329 | { | 4344 | { |
| 4330 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; | 4345 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; |
| 4346 | TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type; | ||
| 4331 | if (!type_has_bits(payload_type)) { | 4347 | if (!type_has_bits(payload_type)) { |
| 4348 | assert(type_has_bits(err_set_type)); | ||
| 4332 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; | 4349 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; |
| 4333 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); | 4350 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 4351 | } else if (!type_has_bits(err_set_type)) { | ||
| 4352 | assert(type_has_bits(payload_type)); | ||
| 4353 | return gen_const_val(g, const_val->data.x_err_union.payload); | ||
| 4334 | } else { | 4354 | } else { |
| 4335 | LLVMValueRef err_tag_value; | 4355 | LLVMValueRef err_tag_value; |
| 4336 | LLVMValueRef err_payload_value; | 4356 | LLVMValueRef err_payload_value; |
src/ir.cpp+138-29| ... | @@ -2869,10 +2869,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2869,10 +2869,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2869 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); | 2869 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); |
| 2870 | case BinOpTypeAssignBitOr: | 2870 | case BinOpTypeAssignBitOr: |
| 2871 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); | 2871 | return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); |
| 2872 | case BinOpTypeAssignBoolAnd: | 2872 | case BinOpTypeAssignMergeErrorSets: |
| 2873 | return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd); | 2873 | return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets); |
| 2874 | case BinOpTypeAssignBoolOr: | ||
| 2875 | return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr); | ||
| 2876 | case BinOpTypeBoolOr: | 2874 | case BinOpTypeBoolOr: |
| 2877 | return ir_gen_bool_or(irb, scope, node); | 2875 | return ir_gen_bool_or(irb, scope, node); |
| 2878 | case BinOpTypeBoolAnd: | 2876 | case BinOpTypeBoolAnd: |
| ... | @@ -2919,6 +2917,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -2919,6 +2917,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2919 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); | 2917 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); |
| 2920 | case BinOpTypeArrayMult: | 2918 | case BinOpTypeArrayMult: |
| 2921 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); | 2919 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); |
| 2920 | case BinOpTypeMergeErrorSets: | ||
| 2921 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); | ||
| 2922 | case BinOpTypeUnwrapMaybe: | 2922 | case BinOpTypeUnwrapMaybe: |
| 2923 | return ir_gen_maybe_ok_or(irb, scope, node); | 2923 | return ir_gen_maybe_ok_or(irb, scope, node); |
| 2924 | case BinOpTypeErrorUnion: | 2924 | case BinOpTypeErrorUnion: |
| ... | @@ -5420,6 +5420,7 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, | ... | @@ -5420,6 +5420,7 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, |
| 5420 | } | 5420 | } |
| 5421 | } | 5421 | } |
| 5422 | assert(index == count); | 5422 | assert(index == count); |
| 5423 | assert(count != 0); | ||
| 5423 | 5424 | ||
| 5424 | buf_appendf(&err_set_type->name, "}"); | 5425 | buf_appendf(&err_set_type->name, "}"); |
| 5425 | 5426 | ||
| ... | @@ -5453,21 +5454,21 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A | ... | @@ -5453,21 +5454,21 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A |
| 5453 | 5454 | ||
| 5454 | uint32_t err_count = node->data.err_set_decl.decls.length; | 5455 | uint32_t err_count = node->data.err_set_decl.decls.length; |
| 5455 | 5456 | ||
| 5456 | if (err_count == 0) { | ||
| 5457 | add_node_error(irb->codegen, node, buf_sprintf("empty error set")); | ||
| 5458 | return irb->codegen->invalid_instruction; | ||
| 5459 | } | ||
| 5460 | |||
| 5461 | Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node); | 5457 | Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node); |
| 5462 | TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet); | 5458 | TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet); |
| 5463 | buf_init_from_buf(&err_set_type->name, type_name); | 5459 | buf_init_from_buf(&err_set_type->name, type_name); |
| 5464 | err_set_type->is_copyable = true; | 5460 | err_set_type->is_copyable = true; |
| 5465 | err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref; | ||
| 5466 | err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type; | ||
| 5467 | err_set_type->data.error_set.err_count = err_count; | 5461 | err_set_type->data.error_set.err_count = err_count; |
| 5468 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); | ||
| 5469 | 5462 | ||
| 5470 | irb->codegen->error_di_types.append(&err_set_type->di_type); | 5463 | if (err_count == 0) { |
| 5464 | err_set_type->zero_bits = true; | ||
| 5465 | err_set_type->di_type = irb->codegen->builtin_types.entry_void->di_type; | ||
| 5466 | } else { | ||
| 5467 | err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref; | ||
| 5468 | err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type; | ||
| 5469 | irb->codegen->error_di_types.append(&err_set_type->di_type); | ||
| 5470 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); | ||
| 5471 | } | ||
| 5471 | 5472 | ||
| 5472 | for (uint32_t i = 0; i < err_count; i += 1) { | 5473 | for (uint32_t i = 0; i < err_count; i += 1) { |
| 5473 | AstNode *symbol_node = node->data.err_set_decl.decls.at(i); | 5474 | AstNode *symbol_node = node->data.err_set_decl.decls.at(i); |
| ... | @@ -6657,6 +6658,27 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -6657,6 +6658,27 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6657 | return ImplicitCastMatchResultNo; | 6658 | return ImplicitCastMatchResultNo; |
| 6658 | } | 6659 | } |
| 6659 | 6660 | ||
| 6661 | static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) { | ||
| 6662 | FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn; | ||
| 6663 | if (infer_fn != nullptr) { | ||
| 6664 | if (infer_fn->anal_state == FnAnalStateInvalid) { | ||
| 6665 | return false; | ||
| 6666 | } else if (infer_fn->anal_state == FnAnalStateReady) { | ||
| 6667 | analyze_fn_body(ira->codegen, infer_fn); | ||
| 6668 | if (err_set_type->data.error_set.infer_fn != nullptr) { | ||
| 6669 | assert(ira->codegen->errors.length != 0); | ||
| 6670 | return false; | ||
| 6671 | } | ||
| 6672 | } else { | ||
| 6673 | ir_add_error_node(ira, source_node, | ||
| 6674 | buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet", | ||
| 6675 | buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name))); | ||
| 6676 | return false; | ||
| 6677 | } | ||
| 6678 | } | ||
| 6679 | return true; | ||
| 6680 | } | ||
| 6681 | |||
| 6660 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { | 6682 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { |
| 6661 | assert(instruction_count >= 1); | 6683 | assert(instruction_count >= 1); |
| 6662 | IrInstruction *prev_inst = instructions[0]; | 6684 | IrInstruction *prev_inst = instructions[0]; |
| ... | @@ -6670,6 +6692,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6670,6 +6692,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6670 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) { | 6692 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) { |
| 6671 | err_set_type = prev_inst->value.type; | 6693 | err_set_type = prev_inst->value.type; |
| 6672 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | 6694 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); |
| 6695 | if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) { | ||
| 6696 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6697 | } | ||
| 6673 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | 6698 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { |
| 6674 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | 6699 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; |
| 6675 | errors[error_entry->value] = error_entry; | 6700 | errors[error_entry->value] = error_entry; |
| ... | @@ -6717,6 +6742,10 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6717,6 +6742,10 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6717 | prev_inst = cur_inst; | 6742 | prev_inst = cur_inst; |
| 6718 | continue; | 6743 | continue; |
| 6719 | } | 6744 | } |
| 6745 | |||
| 6746 | if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) { | ||
| 6747 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6748 | } | ||
| 6720 | // if err_set_type is a superset of cur_type, keep err_set_type. | 6749 | // if err_set_type is a superset of cur_type, keep err_set_type. |
| 6721 | // if cur_type is a superset of err_set_type, switch err_set_type to cur_type | 6750 | // if cur_type is a superset of err_set_type, switch err_set_type to cur_type |
| 6722 | bool prev_is_superset = true; | 6751 | bool prev_is_superset = true; |
| ... | @@ -6778,6 +6807,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6778,6 +6807,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6778 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | 6807 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; |
| 6779 | errors[error_entry->value] = nullptr; | 6808 | errors[error_entry->value] = nullptr; |
| 6780 | } | 6809 | } |
| 6810 | if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) { | ||
| 6811 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6812 | } | ||
| 6781 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { | 6813 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { |
| 6782 | ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; | 6814 | ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; |
| 6783 | errors[error_entry->value] = error_entry; | 6815 | errors[error_entry->value] = error_entry; |
| ... | @@ -6820,6 +6852,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -6820,6 +6852,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6820 | if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) { | 6852 | if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) { |
| 6821 | continue; | 6853 | continue; |
| 6822 | } | 6854 | } |
| 6855 | if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) { | ||
| 6856 | return ira->codegen->builtin_types.entry_invalid; | ||
| 6857 | } | ||
| 6823 | if (err_set_type == nullptr) { | 6858 | if (err_set_type == nullptr) { |
| 6824 | err_set_type = cur_type; | 6859 | err_set_type = cur_type; |
| 6825 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | 6860 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); |
| ... | @@ -7543,6 +7578,8 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou | ... | @@ -7543,6 +7578,8 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou |
| 7543 | assert(contained_set->id == TypeTableEntryIdErrorSet); | 7578 | assert(contained_set->id == TypeTableEntryIdErrorSet); |
| 7544 | assert(container_set->id == TypeTableEntryIdErrorSet); | 7579 | assert(container_set->id == TypeTableEntryIdErrorSet); |
| 7545 | 7580 | ||
| 7581 | zig_panic("TODO explicit error set cast"); | ||
| 7582 | |||
| 7546 | if (container_set->data.error_set.infer_fn == nullptr && | 7583 | if (container_set->data.error_set.infer_fn == nullptr && |
| 7547 | container_set != ira->codegen->builtin_types.entry_global_error_set) | 7584 | container_set != ira->codegen->builtin_types.entry_global_error_set) |
| 7548 | { | 7585 | { |
| ... | @@ -8058,6 +8095,34 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -8058,6 +8095,34 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 8058 | return result; | 8095 | return result; |
| 8059 | } | 8096 | } |
| 8060 | 8097 | ||
| 8098 | TypeTableEntry *err_set_type; | ||
| 8099 | if (err_type->id == TypeTableEntryIdErrorUnion) { | ||
| 8100 | err_set_type = err_type->data.error_union.err_set_type; | ||
| 8101 | } else if (err_type->id == TypeTableEntryIdErrorSet) { | ||
| 8102 | err_set_type = err_type; | ||
| 8103 | } else { | ||
| 8104 | zig_unreachable(); | ||
| 8105 | } | ||
| 8106 | if (err_set_type != ira->codegen->builtin_types.entry_global_error_set) { | ||
| 8107 | if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) { | ||
| 8108 | return ira->codegen->invalid_instruction; | ||
| 8109 | } | ||
| 8110 | if (err_set_type->data.error_set.err_count == 0) { | ||
| 8111 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8112 | source_instr->source_node, wanted_type); | ||
| 8113 | result->value.type = wanted_type; | ||
| 8114 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | ||
| 8115 | return result; | ||
| 8116 | } else if (err_set_type->data.error_set.err_count == 1) { | ||
| 8117 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8118 | source_instr->source_node, wanted_type); | ||
| 8119 | result->value.type = wanted_type; | ||
| 8120 | ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; | ||
| 8121 | bigint_init_unsigned(&result->value.data.x_bigint, err->value); | ||
| 8122 | return result; | ||
| 8123 | } | ||
| 8124 | } | ||
| 8125 | |||
| 8061 | BigInt bn; | 8126 | BigInt bn; |
| 8062 | bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); | 8127 | bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); |
| 8063 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { | 8128 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { |
| ... | @@ -9053,6 +9118,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, | ... | @@ -9053,6 +9118,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val, |
| 9053 | case IrBinOpArrayCat: | 9118 | case IrBinOpArrayCat: |
| 9054 | case IrBinOpArrayMult: | 9119 | case IrBinOpArrayMult: |
| 9055 | case IrBinOpRemUnspecified: | 9120 | case IrBinOpRemUnspecified: |
| 9121 | case IrBinOpMergeErrorSets: | ||
| 9056 | zig_unreachable(); | 9122 | zig_unreachable(); |
| 9057 | case IrBinOpBinOr: | 9123 | case IrBinOpBinOr: |
| 9058 | assert(is_int); | 9124 | assert(is_int); |
| ... | @@ -9625,6 +9691,45 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -9625,6 +9691,45 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp |
| 9625 | return get_array_type(ira->codegen, child_type, new_array_len); | 9691 | return get_array_type(ira->codegen, child_type, new_array_len); |
| 9626 | } | 9692 | } |
| 9627 | 9693 | ||
| 9694 | static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { | ||
| 9695 | TypeTableEntry *op1_type = ir_resolve_type(ira, instruction->op1->other); | ||
| 9696 | if (type_is_invalid(op1_type)) | ||
| 9697 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9698 | |||
| 9699 | TypeTableEntry *op2_type = ir_resolve_type(ira, instruction->op2->other); | ||
| 9700 | if (type_is_invalid(op2_type)) | ||
| 9701 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9702 | |||
| 9703 | if (op1_type == ira->codegen->builtin_types.entry_global_error_set || | ||
| 9704 | op2_type == ira->codegen->builtin_types.entry_global_error_set) | ||
| 9705 | { | ||
| 9706 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 9707 | out_val->data.x_type = ira->codegen->builtin_types.entry_global_error_set; | ||
| 9708 | return ira->codegen->builtin_types.entry_type; | ||
| 9709 | } | ||
| 9710 | |||
| 9711 | if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) { | ||
| 9712 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9713 | } | ||
| 9714 | |||
| 9715 | if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) { | ||
| 9716 | return ira->codegen->builtin_types.entry_invalid; | ||
| 9717 | } | ||
| 9718 | |||
| 9719 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | ||
| 9720 | for (uint32_t i = 0; i < op1_type->data.error_set.err_count; i += 1) { | ||
| 9721 | ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; | ||
| 9722 | errors[error_entry->value] = error_entry; | ||
| 9723 | } | ||
| 9724 | TypeTableEntry *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type); | ||
| 9725 | free(errors); | ||
| 9726 | |||
| 9727 | |||
| 9728 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 9729 | out_val->data.x_type = result_type; | ||
| 9730 | return ira->codegen->builtin_types.entry_type; | ||
| 9731 | } | ||
| 9732 | |||
| 9628 | static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 9733 | static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 9629 | IrBinOp op_id = bin_op_instruction->op_id; | 9734 | IrBinOp op_id = bin_op_instruction->op_id; |
| 9630 | switch (op_id) { | 9735 | switch (op_id) { |
| ... | @@ -9666,6 +9771,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi | ... | @@ -9666,6 +9771,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi |
| 9666 | return ir_analyze_array_cat(ira, bin_op_instruction); | 9771 | return ir_analyze_array_cat(ira, bin_op_instruction); |
| 9667 | case IrBinOpArrayMult: | 9772 | case IrBinOpArrayMult: |
| 9668 | return ir_analyze_array_mult(ira, bin_op_instruction); | 9773 | return ir_analyze_array_mult(ira, bin_op_instruction); |
| 9774 | case IrBinOpMergeErrorSets: | ||
| 9775 | return ir_analyze_merge_error_sets(ira, bin_op_instruction); | ||
| 9669 | } | 9776 | } |
| 9670 | zig_unreachable(); | 9777 | zig_unreachable(); |
| 9671 | } | 9778 | } |
| ... | @@ -11605,6 +11712,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -11605,6 +11712,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11605 | } | 11712 | } |
| 11606 | err_set_type = err_entry->set_with_only_this_in_it; | 11713 | err_set_type = err_entry->set_with_only_this_in_it; |
| 11607 | } else { | 11714 | } else { |
| 11715 | if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) { | ||
| 11716 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11717 | } | ||
| 11608 | ErrorTableEntry *err_entry = find_err_table_entry(child_type, field_name); | 11718 | ErrorTableEntry *err_entry = find_err_table_entry(child_type, field_name); |
| 11609 | if (err_entry == nullptr) { | 11719 | if (err_entry == nullptr) { |
| 11610 | ir_add_error(ira, &field_ptr_instruction->base, | 11720 | ir_add_error(ira, &field_ptr_instruction->base, |
| ... | @@ -14623,6 +14733,19 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc | ... | @@ -14623,6 +14733,19 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc |
| 14623 | } | 14733 | } |
| 14624 | } | 14734 | } |
| 14625 | 14735 | ||
| 14736 | TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type; | ||
| 14737 | if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) { | ||
| 14738 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14739 | } | ||
| 14740 | if (err_set_type != ira->codegen->builtin_types.entry_global_error_set && | ||
| 14741 | err_set_type->data.error_set.err_count == 0) | ||
| 14742 | { | ||
| 14743 | assert(err_set_type->data.error_set.infer_fn == nullptr); | ||
| 14744 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | ||
| 14745 | out_val->data.x_bool = false; | ||
| 14746 | return ira->codegen->builtin_types.entry_bool; | ||
| 14747 | } | ||
| 14748 | |||
| 14626 | ir_build_test_err_from(&ira->new_irb, &instruction->base, value); | 14749 | ir_build_test_err_from(&ira->new_irb, &instruction->base, value); |
| 14627 | return ira->codegen->builtin_types.entry_bool; | 14750 | return ira->codegen->builtin_types.entry_bool; |
| 14628 | } else if (type_entry->id == TypeTableEntryIdErrorSet) { | 14751 | } else if (type_entry->id == TypeTableEntryIdErrorSet) { |
| ... | @@ -14861,22 +14984,8 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira | ... | @@ -14861,22 +14984,8 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 14861 | } | 14984 | } |
| 14862 | } | 14985 | } |
| 14863 | } else if (switch_type->id == TypeTableEntryIdErrorSet) { | 14986 | } else if (switch_type->id == TypeTableEntryIdErrorSet) { |
| 14864 | FnTableEntry *infer_fn = switch_type->data.error_set.infer_fn; | 14987 | if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) { |
| 14865 | if (infer_fn != nullptr) { | 14988 | return ira->codegen->builtin_types.entry_invalid; |
| 14866 | if (infer_fn->anal_state == FnAnalStateInvalid) { | ||
| 14867 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14868 | } else if (infer_fn->anal_state == FnAnalStateReady) { | ||
| 14869 | analyze_fn_body(ira->codegen, infer_fn); | ||
| 14870 | if (switch_type->data.error_set.infer_fn != nullptr) { | ||
| 14871 | assert(ira->codegen->errors.length != 0); | ||
| 14872 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14873 | } | ||
| 14874 | } else { | ||
| 14875 | ir_add_error(ira, &instruction->base, | ||
| 14876 | buf_sprintf("cannot switch on inferred error set '%s': function '%s' not fully analyzed yet", | ||
| 14877 | buf_ptr(&switch_type->name), buf_ptr(&switch_type->data.error_set.infer_fn->symbol_name))); | ||
| 14878 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14879 | } | ||
| 14880 | } | 14989 | } |
| 14881 | 14990 | ||
| 14882 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); | 14991 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); |
src/ir_print.cpp+2| ... | @@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { | ... | @@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { |
| 130 | return "++"; | 130 | return "++"; |
| 131 | case IrBinOpArrayMult: | 131 | case IrBinOpArrayMult: |
| 132 | return "**"; | 132 | return "**"; |
| 133 | case IrBinOpMergeErrorSets: | ||
| 134 | return "||"; | ||
| 133 | } | 135 | } |
| 134 | zig_unreachable(); | 136 | zig_unreachable(); |
| 135 | } | 137 | } |
src/parser.cpp+2-1| ... | @@ -1088,12 +1088,13 @@ static BinOpType tok_to_mult_op(Token *token) { | ... | @@ -1088,12 +1088,13 @@ static BinOpType tok_to_mult_op(Token *token) { |
| 1088 | case TokenIdSlash: return BinOpTypeDiv; | 1088 | case TokenIdSlash: return BinOpTypeDiv; |
| 1089 | case TokenIdPercent: return BinOpTypeMod; | 1089 | case TokenIdPercent: return BinOpTypeMod; |
| 1090 | case TokenIdBang: return BinOpTypeErrorUnion; | 1090 | case TokenIdBang: return BinOpTypeErrorUnion; |
| 1091 | case TokenIdBarBar: return BinOpTypeMergeErrorSets; | ||
| 1091 | default: return BinOpTypeInvalid; | 1092 | default: return BinOpTypeInvalid; |
| 1092 | } | 1093 | } |
| 1093 | } | 1094 | } |
| 1094 | 1095 | ||
| 1095 | /* | 1096 | /* |
| 1096 | MultiplyOperator = "!" | "*" | "/" | "%" | "**" | "*%" | 1097 | MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" |
| 1097 | */ | 1098 | */ |
| 1098 | static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) { | 1099 | static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1099 | Token *token = &pc->tokens->at(*token_index); | 1100 | Token *token = &pc->tokens->at(*token_index); |
src/tokenizer.cpp+25-4| ... | @@ -195,7 +195,8 @@ enum TokenizeState { | ... | @@ -195,7 +195,8 @@ enum TokenizeState { |
| 195 | TokenizeStateSawMinusPercent, | 195 | TokenizeStateSawMinusPercent, |
| 196 | TokenizeStateSawAmpersand, | 196 | TokenizeStateSawAmpersand, |
| 197 | TokenizeStateSawCaret, | 197 | TokenizeStateSawCaret, |
| 198 | TokenizeStateSawPipe, | 198 | TokenizeStateSawBar, |
| 199 | TokenizeStateSawBarBar, | ||
| 199 | TokenizeStateLineComment, | 200 | TokenizeStateLineComment, |
| 200 | TokenizeStateLineString, | 201 | TokenizeStateLineString, |
| 201 | TokenizeStateLineStringEnd, | 202 | TokenizeStateLineStringEnd, |
| ... | @@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 594 | break; | 595 | break; |
| 595 | case '|': | 596 | case '|': |
| 596 | begin_token(&t, TokenIdBinOr); | 597 | begin_token(&t, TokenIdBinOr); |
| 597 | t.state = TokenizeStateSawPipe; | 598 | t.state = TokenizeStateSawBar; |
| 598 | break; | 599 | break; |
| 599 | case '=': | 600 | case '=': |
| 600 | begin_token(&t, TokenIdEq); | 601 | begin_token(&t, TokenIdEq); |
| ... | @@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 888 | continue; | 889 | continue; |
| 889 | } | 890 | } |
| 890 | break; | 891 | break; |
| 891 | case TokenizeStateSawPipe: | 892 | case TokenizeStateSawBar: |
| 892 | switch (c) { | 893 | switch (c) { |
| 893 | case '=': | 894 | case '=': |
| 894 | set_token_id(&t, t.cur_tok, TokenIdBitOrEq); | 895 | set_token_id(&t, t.cur_tok, TokenIdBitOrEq); |
| 895 | end_token(&t); | 896 | end_token(&t); |
| 896 | t.state = TokenizeStateStart; | 897 | t.state = TokenizeStateStart; |
| 897 | break; | 898 | break; |
| 899 | case '|': | ||
| 900 | set_token_id(&t, t.cur_tok, TokenIdBarBar); | ||
| 901 | t.state = TokenizeStateSawBarBar; | ||
| 902 | break; | ||
| 898 | default: | 903 | default: |
| 899 | t.pos -= 1; | 904 | t.pos -= 1; |
| 900 | end_token(&t); | 905 | end_token(&t); |
| ... | @@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 902 | continue; | 907 | continue; |
| 903 | } | 908 | } |
| 904 | break; | 909 | break; |
| 910 | case TokenizeStateSawBarBar: | ||
| 911 | switch (c) { | ||
| 912 | case '=': | ||
| 913 | set_token_id(&t, t.cur_tok, TokenIdBarBarEq); | ||
| 914 | end_token(&t); | ||
| 915 | t.state = TokenizeStateStart; | ||
| 916 | break; | ||
| 917 | default: | ||
| 918 | t.pos -= 1; | ||
| 919 | end_token(&t); | ||
| 920 | t.state = TokenizeStateStart; | ||
| 921 | continue; | ||
| 922 | } | ||
| 905 | case TokenizeStateSawSlash: | 923 | case TokenizeStateSawSlash: |
| 906 | switch (c) { | 924 | switch (c) { |
| 907 | case '/': | 925 | case '/': |
| ... | @@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1428 | case TokenizeStateSawDash: | 1446 | case TokenizeStateSawDash: |
| 1429 | case TokenizeStateSawAmpersand: | 1447 | case TokenizeStateSawAmpersand: |
| 1430 | case TokenizeStateSawCaret: | 1448 | case TokenizeStateSawCaret: |
| 1431 | case TokenizeStateSawPipe: | 1449 | case TokenizeStateSawBar: |
| 1432 | case TokenizeStateSawEq: | 1450 | case TokenizeStateSawEq: |
| 1433 | case TokenizeStateSawBang: | 1451 | case TokenizeStateSawBang: |
| 1434 | case TokenizeStateSawLessThan: | 1452 | case TokenizeStateSawLessThan: |
| ... | @@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1443 | case TokenizeStateSawMinusPercent: | 1461 | case TokenizeStateSawMinusPercent: |
| 1444 | case TokenizeStateLineString: | 1462 | case TokenizeStateLineString: |
| 1445 | case TokenizeStateLineStringEnd: | 1463 | case TokenizeStateLineStringEnd: |
| 1464 | case TokenizeStateSawBarBar: | ||
| 1446 | end_token(&t); | 1465 | end_token(&t); |
| 1447 | break; | 1466 | break; |
| 1448 | case TokenizeStateSawDotDot: | 1467 | case TokenizeStateSawDotDot: |
| ... | @@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) { | ... | @@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) { |
| 1475 | case TokenIdArrow: return "->"; | 1494 | case TokenIdArrow: return "->"; |
| 1476 | case TokenIdAtSign: return "@"; | 1495 | case TokenIdAtSign: return "@"; |
| 1477 | case TokenIdBang: return "!"; | 1496 | case TokenIdBang: return "!"; |
| 1497 | case TokenIdBarBar: return "||"; | ||
| 1478 | case TokenIdBinOr: return "|"; | 1498 | case TokenIdBinOr: return "|"; |
| 1479 | case TokenIdBinXor: return "^"; | 1499 | case TokenIdBinXor: return "^"; |
| 1480 | case TokenIdBitAndEq: return "&="; | 1500 | case TokenIdBitAndEq: return "&="; |
| ... | @@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) { | ... | @@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) { |
| 1577 | case TokenIdTimesEq: return "*="; | 1597 | case TokenIdTimesEq: return "*="; |
| 1578 | case TokenIdTimesPercent: return "*%"; | 1598 | case TokenIdTimesPercent: return "*%"; |
| 1579 | case TokenIdTimesPercentEq: return "*%="; | 1599 | case TokenIdTimesPercentEq: return "*%="; |
| 1600 | case TokenIdBarBarEq: return "||="; | ||
| 1580 | } | 1601 | } |
| 1581 | return "(invalid token)"; | 1602 | return "(invalid token)"; |
| 1582 | } | 1603 | } |
src/tokenizer.hpp+2| ... | @@ -17,6 +17,8 @@ enum TokenId { | ... | @@ -17,6 +17,8 @@ enum TokenId { |
| 17 | TokenIdArrow, | 17 | TokenIdArrow, |
| 18 | TokenIdAtSign, | 18 | TokenIdAtSign, |
| 19 | TokenIdBang, | 19 | TokenIdBang, |
| 20 | TokenIdBarBar, | ||
| 21 | TokenIdBarBarEq, | ||
| 20 | TokenIdBinOr, | 22 | TokenIdBinOr, |
| 21 | TokenIdBinXor, | 23 | TokenIdBinXor, |
| 22 | TokenIdBitAndEq, | 24 | TokenIdBitAndEq, |
std/debug/index.zig+1| ... | @@ -210,6 +210,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a | ... | @@ -210,6 +210,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a |
| 210 | } | 210 | } |
| 211 | } else |err| switch (err) { | 211 | } else |err| switch (err) { |
| 212 | error.EndOfFile => {}, | 212 | error.EndOfFile => {}, |
| 213 | else => return err, | ||
| 213 | } | 214 | } |
| 214 | } else |err| switch (err) { | 215 | } else |err| switch (err) { |
| 215 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 216 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
std/io.zig+6-2| ... | @@ -102,12 +102,14 @@ pub const File = struct { | ... | @@ -102,12 +102,14 @@ pub const File = struct { |
| 102 | /// The OS-specific file descriptor or file handle. | 102 | /// The OS-specific file descriptor or file handle. |
| 103 | handle: os.FileHandle, | 103 | handle: os.FileHandle, |
| 104 | 104 | ||
| 105 | const OpenError = os.WindowsOpenError || os.PosixOpenError; | ||
| 106 | |||
| 105 | /// `path` may need to be copied in memory to add a null terminating byte. In this case | 107 | /// `path` may need to be copied in memory to add a null terminating byte. In this case |
| 106 | /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed | 108 | /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed |
| 107 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. | 109 | /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned. |
| 108 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 110 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 109 | /// Call close to clean up. | 111 | /// Call close to clean up. |
| 110 | pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) !File { | 112 | pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) OpenError!File { |
| 111 | if (is_posix) { | 113 | if (is_posix) { |
| 112 | const flags = system.O_LARGEFILE|system.O_RDONLY; | 114 | const flags = system.O_LARGEFILE|system.O_RDONLY; |
| 113 | const fd = try os.posixOpen(path, flags, 0, allocator); | 115 | const fd = try os.posixOpen(path, flags, 0, allocator); |
| ... | @@ -338,7 +340,9 @@ pub const File = struct { | ... | @@ -338,7 +340,9 @@ pub const File = struct { |
| 338 | } | 340 | } |
| 339 | } | 341 | } |
| 340 | 342 | ||
| 341 | fn write(self: &File, bytes: []const u8) !void { | 343 | const WriteError = os.WindowsWriteError || os.PosixWriteError; |
| 344 | |||
| 345 | fn write(self: &File, bytes: []const u8) WriteError!void { | ||
| 342 | if (is_posix) { | 346 | if (is_posix) { |
| 343 | try os.posixWrite(self.handle, bytes); | 347 | try os.posixWrite(self.handle, bytes); |
| 344 | } else if (is_windows) { | 348 | } else if (is_windows) { |
std/mem.zig+5-5| ... | @@ -5,12 +5,12 @@ const math = std.math; | ... | @@ -5,12 +5,12 @@ const math = std.math; |
| 5 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 6 | 6 | ||
| 7 | pub const Allocator = struct { | 7 | pub const Allocator = struct { |
| 8 | const Errors = error {OutOfMemory}; | 8 | const Error = error {OutOfMemory}; |
| 9 | 9 | ||
| 10 | /// Allocate byte_count bytes and return them in a slice, with the | 10 | /// Allocate byte_count bytes and return them in a slice, with the |
| 11 | /// slice's pointer aligned at least to alignment bytes. | 11 | /// slice's pointer aligned at least to alignment bytes. |
| 12 | /// The returned newly allocated memory is undefined. | 12 | /// The returned newly allocated memory is undefined. |
| 13 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Errors![]u8, | 13 | allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) Error![]u8, |
| 14 | 14 | ||
| 15 | /// If `new_byte_count > old_mem.len`: | 15 | /// If `new_byte_count > old_mem.len`: |
| 16 | /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn. | 16 | /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn. |
| ... | @@ -21,7 +21,7 @@ pub const Allocator = struct { | ... | @@ -21,7 +21,7 @@ pub const Allocator = struct { |
| 21 | /// * alignment <= alignment of old_mem.ptr | 21 | /// * alignment <= alignment of old_mem.ptr |
| 22 | /// | 22 | /// |
| 23 | /// The returned newly allocated memory is undefined. | 23 | /// The returned newly allocated memory is undefined. |
| 24 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Errors![]u8, | 24 | reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) Error![]u8, |
| 25 | 25 | ||
| 26 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` | 26 | /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn` |
| 27 | freeFn: fn (self: &Allocator, old_mem: []u8) void, | 27 | freeFn: fn (self: &Allocator, old_mem: []u8) void, |
| ... | @@ -42,7 +42,7 @@ pub const Allocator = struct { | ... | @@ -42,7 +42,7 @@ pub const Allocator = struct { |
| 42 | fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, | 42 | fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29, |
| 43 | n: usize) ![]align(alignment) T | 43 | n: usize) ![]align(alignment) T |
| 44 | { | 44 | { |
| 45 | const byte_count = try math.mul(usize, @sizeOf(T), n); | 45 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 46 | const byte_slice = try self.allocFn(self, byte_count, alignment); | 46 | const byte_slice = try self.allocFn(self, byte_count, alignment); |
| 47 | // This loop should get optimized out in ReleaseFast mode | 47 | // This loop should get optimized out in ReleaseFast mode |
| 48 | for (byte_slice) |*byte| { | 48 | for (byte_slice) |*byte| { |
| ... | @@ -63,7 +63,7 @@ pub const Allocator = struct { | ... | @@ -63,7 +63,7 @@ pub const Allocator = struct { |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | const old_byte_slice = ([]u8)(old_mem); | 65 | const old_byte_slice = ([]u8)(old_mem); |
| 66 | const byte_count = try math.mul(usize, @sizeOf(T), n); | 66 | const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory; |
| 67 | const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment); | 67 | const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment); |
| 68 | // This loop should get optimized out in ReleaseFast mode | 68 | // This loop should get optimized out in ReleaseFast mode |
| 69 | for (byte_slice[old_byte_slice.len..]) |*byte| { | 69 | for (byte_slice[old_byte_slice.len..]) |*byte| { |
std/os/index.zig+60-25| ... | @@ -38,6 +38,9 @@ pub const windowsLoadDll = windows_util.windowsLoadDll; | ... | @@ -38,6 +38,9 @@ pub const windowsLoadDll = windows_util.windowsLoadDll; |
| 38 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; | 38 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; |
| 39 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | 39 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 40 | 40 | ||
| 41 | pub const WindowsOpenError = windows_util.OpenError; | ||
| 42 | pub const WindowsWriteError = windows_util.WriteError; | ||
| 43 | |||
| 41 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | 44 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; |
| 42 | 45 | ||
| 43 | const debug = std.debug; | 46 | const debug = std.debug; |
| ... | @@ -188,8 +191,21 @@ pub fn posixRead(fd: i32, buf: []u8) !void { | ... | @@ -188,8 +191,21 @@ pub fn posixRead(fd: i32, buf: []u8) !void { |
| 188 | } | 191 | } |
| 189 | } | 192 | } |
| 190 | 193 | ||
| 194 | pub const PosixWriteError = error { | ||
| 195 | WouldBlock, | ||
| 196 | FileClosed, | ||
| 197 | DestinationAddressRequired, | ||
| 198 | DiskQuota, | ||
| 199 | FileTooBig, | ||
| 200 | InputOutput, | ||
| 201 | NoSpaceLeft, | ||
| 202 | AccessDenied, | ||
| 203 | BrokenPipe, | ||
| 204 | Unexpected, | ||
| 205 | }; | ||
| 206 | |||
| 191 | /// Calls POSIX write, and keeps trying if it gets interrupted. | 207 | /// Calls POSIX write, and keeps trying if it gets interrupted. |
| 192 | pub fn posixWrite(fd: i32, bytes: []const u8) !void { | 208 | pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void { |
| 193 | while (true) { | 209 | while (true) { |
| 194 | const write_ret = posix.write(fd, bytes.ptr, bytes.len); | 210 | const write_ret = posix.write(fd, bytes.ptr, bytes.len); |
| 195 | const write_err = posix.getErrno(write_ret); | 211 | const write_err = posix.getErrno(write_ret); |
| ... | @@ -197,15 +213,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { | ... | @@ -197,15 +213,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 197 | return switch (write_err) { | 213 | return switch (write_err) { |
| 198 | posix.EINTR => continue, | 214 | posix.EINTR => continue, |
| 199 | posix.EINVAL, posix.EFAULT => unreachable, | 215 | posix.EINVAL, posix.EFAULT => unreachable, |
| 200 | posix.EAGAIN => error.WouldBlock, | 216 | posix.EAGAIN => PosixWriteError.WouldBlock, |
| 201 | posix.EBADF => error.FileClosed, | 217 | posix.EBADF => PosixWriteError.FileClosed, |
| 202 | posix.EDESTADDRREQ => error.DestinationAddressRequired, | 218 | posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired, |
| 203 | posix.EDQUOT => error.DiskQuota, | 219 | posix.EDQUOT => PosixWriteError.DiskQuota, |
| 204 | posix.EFBIG => error.FileTooBig, | 220 | posix.EFBIG => PosixWriteError.FileTooBig, |
| 205 | posix.EIO => error.InputOutput, | 221 | posix.EIO => PosixWriteError.InputOutput, |
| 206 | posix.ENOSPC => error.NoSpaceLeft, | 222 | posix.ENOSPC => PosixWriteError.NoSpaceLeft, |
| 207 | posix.EPERM => error.AccessDenied, | 223 | posix.EPERM => PosixWriteError.AccessDenied, |
| 208 | posix.EPIPE => error.BrokenPipe, | 224 | posix.EPIPE => PosixWriteError.BrokenPipe, |
| 209 | else => unexpectedErrorPosix(write_err), | 225 | else => unexpectedErrorPosix(write_err), |
| 210 | }; | 226 | }; |
| 211 | } | 227 | } |
| ... | @@ -213,13 +229,32 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { | ... | @@ -213,13 +229,32 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 213 | } | 229 | } |
| 214 | } | 230 | } |
| 215 | 231 | ||
| 232 | pub const PosixOpenError = error { | ||
| 233 | OutOfMemory, | ||
| 234 | AccessDenied, | ||
| 235 | FileTooBig, | ||
| 236 | IsDir, | ||
| 237 | SymLinkLoop, | ||
| 238 | ProcessFdQuotaExceeded, | ||
| 239 | NameTooLong, | ||
| 240 | SystemFdQuotaExceeded, | ||
| 241 | NoDevice, | ||
| 242 | PathNotFound, | ||
| 243 | SystemResources, | ||
| 244 | NoSpaceLeft, | ||
| 245 | NotDir, | ||
| 246 | AccessDenied, | ||
| 247 | PathAlreadyExists, | ||
| 248 | Unexpected, | ||
| 249 | }; | ||
| 250 | |||
| 216 | /// ::file_path may need to be copied in memory to add a null terminating byte. In this case | 251 | /// ::file_path may need to be copied in memory to add a null terminating byte. In this case |
| 217 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed | 252 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed |
| 218 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. | 253 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. |
| 219 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 254 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 220 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates | 255 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates |
| 221 | /// the return value into zig errors. | 256 | /// the return value into zig errors. |
| 222 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) !i32 { | 257 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) PosixOpenError!i32 { |
| 223 | var stack_buf: [max_noalloc_path_len]u8 = undefined; | 258 | var stack_buf: [max_noalloc_path_len]u8 = undefined; |
| 224 | var path0: []u8 = undefined; | 259 | var path0: []u8 = undefined; |
| 225 | var need_free = false; | 260 | var need_free = false; |
| ... | @@ -247,20 +282,20 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al | ... | @@ -247,20 +282,20 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 247 | 282 | ||
| 248 | posix.EFAULT => unreachable, | 283 | posix.EFAULT => unreachable, |
| 249 | posix.EINVAL => unreachable, | 284 | posix.EINVAL => unreachable, |
| 250 | posix.EACCES => error.AccessDenied, | 285 | posix.EACCES => PosixOpenError.AccessDenied, |
| 251 | posix.EFBIG, posix.EOVERFLOW => error.FileTooBig, | 286 | posix.EFBIG, posix.EOVERFLOW => PosixOpenError.FileTooBig, |
| 252 | posix.EISDIR => error.IsDir, | 287 | posix.EISDIR => PosixOpenError.IsDir, |
| 253 | posix.ELOOP => error.SymLinkLoop, | 288 | posix.ELOOP => PosixOpenError.SymLinkLoop, |
| 254 | posix.EMFILE => error.ProcessFdQuotaExceeded, | 289 | posix.EMFILE => PosixOpenError.ProcessFdQuotaExceeded, |
| 255 | posix.ENAMETOOLONG => error.NameTooLong, | 290 | posix.ENAMETOOLONG => PosixOpenError.NameTooLong, |
| 256 | posix.ENFILE => error.SystemFdQuotaExceeded, | 291 | posix.ENFILE => PosixOpenError.SystemFdQuotaExceeded, |
| 257 | posix.ENODEV => error.NoDevice, | 292 | posix.ENODEV => PosixOpenError.NoDevice, |
| 258 | posix.ENOENT => error.PathNotFound, | 293 | posix.ENOENT => PosixOpenError.PathNotFound, |
| 259 | posix.ENOMEM => error.SystemResources, | 294 | posix.ENOMEM => PosixOpenError.SystemResources, |
| 260 | posix.ENOSPC => error.NoSpaceLeft, | 295 | posix.ENOSPC => PosixOpenError.NoSpaceLeft, |
| 261 | posix.ENOTDIR => error.NotDir, | 296 | posix.ENOTDIR => PosixOpenError.NotDir, |
| 262 | posix.EPERM => error.AccessDenied, | 297 | posix.EPERM => PosixOpenError.AccessDenied, |
| 263 | posix.EEXIST => error.PathAlreadyExists, | 298 | posix.EEXIST => PosixOpenError.PathAlreadyExists, |
| 264 | else => unexpectedErrorPosix(err), | 299 | else => unexpectedErrorPosix(err), |
| 265 | }; | 300 | }; |
| 266 | } | 301 | } |
std/os/windows/util.zig+32-13| ... | @@ -26,16 +26,25 @@ pub fn windowsClose(handle: windows.HANDLE) void { | ... | @@ -26,16 +26,25 @@ pub fn windowsClose(handle: windows.HANDLE) void { |
| 26 | assert(windows.CloseHandle(handle) != 0); | 26 | assert(windows.CloseHandle(handle) != 0); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) !void { | 29 | pub const WriteError = error { |
| 30 | SystemResources, | ||
| 31 | OperationAborted, | ||
| 32 | SystemResources, | ||
| 33 | IoPending, | ||
| 34 | BrokenPipe, | ||
| 35 | Unexpected, | ||
| 36 | }; | ||
| 37 | |||
| 38 | pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void { | ||
| 30 | if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { | 39 | if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) { |
| 31 | const err = windows.GetLastError(); | 40 | const err = windows.GetLastError(); |
| 32 | return switch (err) { | 41 | return switch (err) { |
| 33 | windows.ERROR.INVALID_USER_BUFFER => error.SystemResources, | 42 | windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources, |
| 34 | windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources, | 43 | windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources, |
| 35 | windows.ERROR.OPERATION_ABORTED => error.OperationAborted, | 44 | windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted, |
| 36 | windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources, | 45 | windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources, |
| 37 | windows.ERROR.IO_PENDING => error.IoPending, | 46 | windows.ERROR.IO_PENDING => WriteError.IoPending, |
| 38 | windows.ERROR.BROKEN_PIPE => error.BrokenPipe, | 47 | windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe, |
| 39 | else => os.unexpectedErrorWindows(err), | 48 | else => os.unexpectedErrorWindows(err), |
| 40 | }; | 49 | }; |
| 41 | } | 50 | } |
| ... | @@ -66,12 +75,22 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool { | ... | @@ -66,12 +75,22 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool { |
| 66 | mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null; | 75 | mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null; |
| 67 | } | 76 | } |
| 68 | 77 | ||
| 78 | pub const OpenError = error { | ||
| 79 | SharingViolation, | ||
| 80 | PathAlreadyExists, | ||
| 81 | FileNotFound, | ||
| 82 | AccessDenied, | ||
| 83 | PipeBusy, | ||
| 84 | Unexpected, | ||
| 85 | }; | ||
| 86 | |||
| 69 | /// `file_path` may need to be copied in memory to add a null terminating byte. In this case | 87 | /// `file_path` may need to be copied in memory to add a null terminating byte. In this case |
| 70 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed | 88 | /// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed |
| 71 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. | 89 | /// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned. |
| 72 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. | 90 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 73 | pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD, | 91 | pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD, |
| 74 | creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator) %windows.HANDLE | 92 | creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator) |
| 93 | OpenError!windows.HANDLE | ||
| 75 | { | 94 | { |
| 76 | var stack_buf: [os.max_noalloc_path_len]u8 = undefined; | 95 | var stack_buf: [os.max_noalloc_path_len]u8 = undefined; |
| 77 | var path0: []u8 = undefined; | 96 | var path0: []u8 = undefined; |
| ... | @@ -95,11 +114,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m | ... | @@ -95,11 +114,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m |
| 95 | if (result == windows.INVALID_HANDLE_VALUE) { | 114 | if (result == windows.INVALID_HANDLE_VALUE) { |
| 96 | const err = windows.GetLastError(); | 115 | const err = windows.GetLastError(); |
| 97 | return switch (err) { | 116 | return switch (err) { |
| 98 | windows.ERROR.SHARING_VIOLATION => error.SharingViolation, | 117 | windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation, |
| 99 | windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists, | 118 | windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists, |
| 100 | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, | 119 | windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound, |
| 101 | windows.ERROR.ACCESS_DENIED => error.AccessDenied, | 120 | windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied, |
| 102 | windows.ERROR.PIPE_BUSY => error.PipeBusy, | 121 | windows.ERROR.PIPE_BUSY => OpenError.PipeBusy, |
| 103 | else => os.unexpectedErrorWindows(err), | 122 | else => os.unexpectedErrorWindows(err), |
| 104 | }; | 123 | }; |
| 105 | } | 124 | } |