authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-02 18:13:32-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-02 18:13:32-05:00
logb8f59e14cdbf90cf724ed9e721c1909293f41b3b
treeef7a9f2b4534f691e6284b16218c354654abb9e5
parent39d5f44863aafa77163b2a7e32f2553a589dbb2c

*WIP* error sets - correctly resolve inferred error sets


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.
1313
1414// TODO this is an explicit cast and should actually coerce the type
1515 erorr set casting
16
17
18test err should be comptime if error set has 0 members
19
20comptime calling fn with inferred error set should give empty error set but still you can use try
21
22comptime err to int of empty err set and of size 1 err set
23
24comptime test for err
25
26
27undefined in infer error
doc/langref.html.in+1-1
......@@ -5682,7 +5682,7 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression |
56825682
56835683CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
56845684
5685MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
5685MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
56865686
56875687PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
56885688
src/all_types.hpp+3-2
......@@ -510,8 +510,7 @@ enum BinOpType {
510510 BinOpTypeAssignBitAnd,
511511 BinOpTypeAssignBitXor,
512512 BinOpTypeAssignBitOr,
513 BinOpTypeAssignBoolAnd,
514 BinOpTypeAssignBoolOr,
513 BinOpTypeAssignMergeErrorSets,
515514 BinOpTypeBoolOr,
516515 BinOpTypeBoolAnd,
517516 BinOpTypeCmpEq,
......@@ -537,6 +536,7 @@ enum BinOpType {
537536 BinOpTypeArrayCat,
538537 BinOpTypeArrayMult,
539538 BinOpTypeErrorUnion,
539 BinOpTypeMergeErrorSets,
540540};
541541
542542struct AstNodeBinOpExpr {
......@@ -2054,6 +2054,7 @@ enum IrBinOp {
20542054 IrBinOpRemMod,
20552055 IrBinOpArrayCat,
20562056 IrBinOpArrayMult,
2057 IrBinOpMergeErrorSets,
20572058};
20582059
20592060struct IrInstructionBinOp {
src/analyze.cpp+38-4
......@@ -530,7 +530,6 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T
530530
531531 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
532532 entry->is_copyable = true;
533 assert(payload_type->type_ref);
534533 assert(payload_type->di_type);
535534 ensure_complete_type(g, payload_type);
536535
......@@ -541,9 +540,16 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T
541540 entry->data.error_union.payload_type = payload_type;
542541
543542 if (!type_has_bits(payload_type)) {
544 entry->type_ref = err_set_type->type_ref;
545 entry->di_type = err_set_type->di_type;
546
543 if (type_has_bits(err_set_type)) {
544 entry->type_ref = err_set_type->type_ref;
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;
547553 } else {
548554 LLVMTypeRef elem_types[] = {
549555 err_set_type->type_ref,
......@@ -3841,6 +3847,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
38413847 }
38423848}
38433849
3850static 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
38443871void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {
38453872 TypeTableEntry *fn_type = fn_table_entry->type_entry;
38463873 assert(!fn_type->data.fn.is_generic);
......@@ -3871,6 +3898,13 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
38713898 return;
38723899 }
38733900
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
38743908 return_err_set_type->data.error_set.infer_fn = nullptr;
38753909 return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
38763910 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) {
4949 case BinOpTypeAssignBitAnd: return "&=";
5050 case BinOpTypeAssignBitXor: return "^=";
5151 case BinOpTypeAssignBitOr: return "|=";
52 case BinOpTypeAssignBoolAnd: return "&&=";
53 case BinOpTypeAssignBoolOr: return "||=";
52 case BinOpTypeAssignMergeErrorSets: return "||=";
5453 case BinOpTypeUnwrapMaybe: return "??";
5554 case BinOpTypeArrayCat: return "++";
5655 case BinOpTypeArrayMult: return "**";
5756 case BinOpTypeErrorUnion: return "!";
57 case BinOpTypeMergeErrorSets: return "||";
5858 }
5959 zig_unreachable();
6060}
src/codegen.cpp+21-1
......@@ -1799,6 +1799,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
17991799 case IrBinOpArrayCat:
18001800 case IrBinOpArrayMult:
18011801 case IrBinOpRemUnspecified:
1802 case IrBinOpMergeErrorSets:
18021803 zig_unreachable();
18031804 case IrBinOpBoolOr:
18041805 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
......@@ -2188,6 +2189,9 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I
21882189 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
21892190 g->err_tag_type, wanted_type, target_val);
21902191 } 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
21912195 if (!type_has_bits(actual_type->data.error_union.payload_type)) {
21922196 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
21932197 g->err_tag_type, wanted_type, target_val);
......@@ -3428,6 +3432,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
34283432 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
34293433 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
34303434
3435 if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {
3436 return err_union_handle;
3437 }
3438
34313439 if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
34323440 LLVMValueRef err_val;
34333441 if (type_has_bits(payload_type)) {
......@@ -3490,9 +3498,11 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
34903498 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
34913499
34923500 TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
3501 TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
3502
34933503 LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
34943504
3495 if (!type_has_bits(payload_type))
3505 if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
34963506 return err_val;
34973507
34983508 assert(instruction->tmp_ptr);
......@@ -3509,6 +3519,11 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
35093519 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
35103520
35113521 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 }
35123527
35133528 LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
35143529
......@@ -4328,9 +4343,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
43284343 case TypeTableEntryIdErrorUnion:
43294344 {
43304345 TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
4346 TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
43314347 if (!type_has_bits(payload_type)) {
4348 assert(type_has_bits(err_set_type));
43324349 uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
43334350 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);
43344354 } else {
43354355 LLVMValueRef err_tag_value;
43364356 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)
28692869 return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
28702870 case BinOpTypeAssignBitOr:
28712871 return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
2872 case BinOpTypeAssignBoolAnd:
2873 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd);
2874 case BinOpTypeAssignBoolOr:
2875 return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
2872 case BinOpTypeAssignMergeErrorSets:
2873 return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
28762874 case BinOpTypeBoolOr:
28772875 return ir_gen_bool_or(irb, scope, node);
28782876 case BinOpTypeBoolAnd:
......@@ -2919,6 +2917,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
29192917 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
29202918 case BinOpTypeArrayMult:
29212919 return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
2920 case BinOpTypeMergeErrorSets:
2921 return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
29222922 case BinOpTypeUnwrapMaybe:
29232923 return ir_gen_maybe_ok_or(irb, scope, node);
29242924 case BinOpTypeErrorUnion:
......@@ -5420,6 +5420,7 @@ static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors,
54205420 }
54215421 }
54225422 assert(index == count);
5423 assert(count != 0);
54235424
54245425 buf_appendf(&err_set_type->name, "}");
54255426
......@@ -5453,21 +5454,21 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
54535454
54545455 uint32_t err_count = node->data.err_set_decl.decls.length;
54555456
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
54615457 Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node);
54625458 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
54635459 buf_init_from_buf(&err_set_type->name, type_name);
54645460 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;
54675461 err_set_type->data.error_set.err_count = err_count;
5468 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
54695462
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 }
54715472
54725473 for (uint32_t i = 0; i < err_count; i += 1) {
54735474 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,
66576658 return ImplicitCastMatchResultNo;
66586659}
66596660
6661static 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
66606682static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
66616683 assert(instruction_count >= 1);
66626684 IrInstruction *prev_inst = instructions[0];
......@@ -6670,6 +6692,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
66706692 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
66716693 err_set_type = prev_inst->value.type;
66726694 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 }
66736698 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
66746699 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
66756700 errors[error_entry->value] = error_entry;
......@@ -6717,6 +6742,10 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
67176742 prev_inst = cur_inst;
67186743 continue;
67196744 }
6745
6746 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
6747 return ira->codegen->builtin_types.entry_invalid;
6748 }
67206749 // if err_set_type is a superset of cur_type, keep err_set_type.
67216750 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type
67226751 bool prev_is_superset = true;
......@@ -6778,6 +6807,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
67786807 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
67796808 errors[error_entry->value] = nullptr;
67806809 }
6810 if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
6811 return ira->codegen->builtin_types.entry_invalid;
6812 }
67816813 for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
67826814 ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
67836815 errors[error_entry->value] = error_entry;
......@@ -6820,6 +6852,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
68206852 if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) {
68216853 continue;
68226854 }
6855 if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
6856 return ira->codegen->builtin_types.entry_invalid;
6857 }
68236858 if (err_set_type == nullptr) {
68246859 err_set_type = cur_type;
68256860 errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
......@@ -7543,6 +7578,8 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
75437578 assert(contained_set->id == TypeTableEntryIdErrorSet);
75447579 assert(container_set->id == TypeTableEntryIdErrorSet);
75457580
7581 zig_panic("TODO explicit error set cast");
7582
75467583 if (container_set->data.error_set.infer_fn == nullptr &&
75477584 container_set != ira->codegen->builtin_types.entry_global_error_set)
75487585 {
......@@ -8058,6 +8095,34 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
80588095 return result;
80598096 }
80608097
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
80618126 BigInt bn;
80628127 bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length);
80638128 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,
90539118 case IrBinOpArrayCat:
90549119 case IrBinOpArrayMult:
90559120 case IrBinOpRemUnspecified:
9121 case IrBinOpMergeErrorSets:
90569122 zig_unreachable();
90579123 case IrBinOpBinOr:
90589124 assert(is_int);
......@@ -9625,6 +9691,45 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
96259691 return get_array_type(ira->codegen, child_type, new_array_len);
96269692}
96279693
9694static 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
96289733static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
96299734 IrBinOp op_id = bin_op_instruction->op_id;
96309735 switch (op_id) {
......@@ -9666,6 +9771,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
96669771 return ir_analyze_array_cat(ira, bin_op_instruction);
96679772 case IrBinOpArrayMult:
96689773 return ir_analyze_array_mult(ira, bin_op_instruction);
9774 case IrBinOpMergeErrorSets:
9775 return ir_analyze_merge_error_sets(ira, bin_op_instruction);
96699776 }
96709777 zig_unreachable();
96719778}
......@@ -11605,6 +11712,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1160511712 }
1160611713 err_set_type = err_entry->set_with_only_this_in_it;
1160711714 } 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 }
1160811718 ErrorTableEntry *err_entry = find_err_table_entry(child_type, field_name);
1160911719 if (err_entry == nullptr) {
1161011720 ir_add_error(ira, &field_ptr_instruction->base,
......@@ -14623,6 +14733,19 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
1462314733 }
1462414734 }
1462514735
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
1462614749 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
1462714750 return ira->codegen->builtin_types.entry_bool;
1462814751 } else if (type_entry->id == TypeTableEntryIdErrorSet) {
......@@ -14861,22 +14984,8 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
1486114984 }
1486214985 }
1486314986 } else if (switch_type->id == TypeTableEntryIdErrorSet) {
14864 FnTableEntry *infer_fn = switch_type->data.error_set.infer_fn;
14865 if (infer_fn != nullptr) {
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 }
14987 if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
14988 return ira->codegen->builtin_types.entry_invalid;
1488014989 }
1488114990
1488214991 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) {
130130 return "++";
131131 case IrBinOpArrayMult:
132132 return "**";
133 case IrBinOpMergeErrorSets:
134 return "||";
133135 }
134136 zig_unreachable();
135137}
src/parser.cpp+2-1
......@@ -1088,12 +1088,13 @@ static BinOpType tok_to_mult_op(Token *token) {
10881088 case TokenIdSlash: return BinOpTypeDiv;
10891089 case TokenIdPercent: return BinOpTypeMod;
10901090 case TokenIdBang: return BinOpTypeErrorUnion;
1091 case TokenIdBarBar: return BinOpTypeMergeErrorSets;
10911092 default: return BinOpTypeInvalid;
10921093 }
10931094}
10941095
10951096/*
1096MultiplyOperator = "!" | "*" | "/" | "%" | "**" | "*%"
1097MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
10971098*/
10981099static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {
10991100 Token *token = &pc->tokens->at(*token_index);
src/tokenizer.cpp+25-4
......@@ -195,7 +195,8 @@ enum TokenizeState {
195195 TokenizeStateSawMinusPercent,
196196 TokenizeStateSawAmpersand,
197197 TokenizeStateSawCaret,
198 TokenizeStateSawPipe,
198 TokenizeStateSawBar,
199 TokenizeStateSawBarBar,
199200 TokenizeStateLineComment,
200201 TokenizeStateLineString,
201202 TokenizeStateLineStringEnd,
......@@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) {
594595 break;
595596 case '|':
596597 begin_token(&t, TokenIdBinOr);
597 t.state = TokenizeStateSawPipe;
598 t.state = TokenizeStateSawBar;
598599 break;
599600 case '=':
600601 begin_token(&t, TokenIdEq);
......@@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) {
888889 continue;
889890 }
890891 break;
891 case TokenizeStateSawPipe:
892 case TokenizeStateSawBar:
892893 switch (c) {
893894 case '=':
894895 set_token_id(&t, t.cur_tok, TokenIdBitOrEq);
895896 end_token(&t);
896897 t.state = TokenizeStateStart;
897898 break;
899 case '|':
900 set_token_id(&t, t.cur_tok, TokenIdBarBar);
901 t.state = TokenizeStateSawBarBar;
902 break;
898903 default:
899904 t.pos -= 1;
900905 end_token(&t);
......@@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) {
902907 continue;
903908 }
904909 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 }
905923 case TokenizeStateSawSlash:
906924 switch (c) {
907925 case '/':
......@@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14281446 case TokenizeStateSawDash:
14291447 case TokenizeStateSawAmpersand:
14301448 case TokenizeStateSawCaret:
1431 case TokenizeStateSawPipe:
1449 case TokenizeStateSawBar:
14321450 case TokenizeStateSawEq:
14331451 case TokenizeStateSawBang:
14341452 case TokenizeStateSawLessThan:
......@@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14431461 case TokenizeStateSawMinusPercent:
14441462 case TokenizeStateLineString:
14451463 case TokenizeStateLineStringEnd:
1464 case TokenizeStateSawBarBar:
14461465 end_token(&t);
14471466 break;
14481467 case TokenizeStateSawDotDot:
......@@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) {
14751494 case TokenIdArrow: return "->";
14761495 case TokenIdAtSign: return "@";
14771496 case TokenIdBang: return "!";
1497 case TokenIdBarBar: return "||";
14781498 case TokenIdBinOr: return "|";
14791499 case TokenIdBinXor: return "^";
14801500 case TokenIdBitAndEq: return "&=";
......@@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) {
15771597 case TokenIdTimesEq: return "*=";
15781598 case TokenIdTimesPercent: return "*%";
15791599 case TokenIdTimesPercentEq: return "*%=";
1600 case TokenIdBarBarEq: return "||=";
15801601 }
15811602 return "(invalid token)";
15821603}
src/tokenizer.hpp+2
......@@ -17,6 +17,8 @@ enum TokenId {
1717 TokenIdArrow,
1818 TokenIdAtSign,
1919 TokenIdBang,
20 TokenIdBarBar,
21 TokenIdBarBarEq,
2022 TokenIdBinOr,
2123 TokenIdBinXor,
2224 TokenIdBitAndEq,
std/debug/index.zig+1
......@@ -210,6 +210,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
210210 }
211211 } else |err| switch (err) {
212212 error.EndOfFile => {},
213 else => return err,
213214 }
214215 } else |err| switch (err) {
215216 error.MissingDebugInfo, error.InvalidDebugInfo => {
std/io.zig+6-2
......@@ -102,12 +102,14 @@ pub const File = struct {
102102 /// The OS-specific file descriptor or file handle.
103103 handle: os.FileHandle,
104104
105 const OpenError = os.WindowsOpenError || os.PosixOpenError;
106
105107 /// `path` may need to be copied in memory to add a null terminating byte. In this case
106108 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
107109 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
108110 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
109111 /// 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 {
111113 if (is_posix) {
112114 const flags = system.O_LARGEFILE|system.O_RDONLY;
113115 const fd = try os.posixOpen(path, flags, 0, allocator);
......@@ -338,7 +340,9 @@ pub const File = struct {
338340 }
339341 }
340342
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 {
342346 if (is_posix) {
343347 try os.posixWrite(self.handle, bytes);
344348 } else if (is_windows) {
std/mem.zig+5-5
......@@ -5,12 +5,12 @@ const math = std.math;
55const builtin = @import("builtin");
66
77pub const Allocator = struct {
8 const Errors = error {OutOfMemory};
8 const Error = error {OutOfMemory};
99
1010 /// Allocate byte_count bytes and return them in a slice, with the
1111 /// slice's pointer aligned at least to alignment bytes.
1212 /// 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,
1414
1515 /// If `new_byte_count > old_mem.len`:
1616 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
......@@ -21,7 +21,7 @@ pub const Allocator = struct {
2121 /// * alignment <= alignment of old_mem.ptr
2222 ///
2323 /// 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,
2525
2626 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
2727 freeFn: fn (self: &Allocator, old_mem: []u8) void,
......@@ -42,7 +42,7 @@ pub const Allocator = struct {
4242 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
4343 n: usize) ![]align(alignment) T
4444 {
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;
4646 const byte_slice = try self.allocFn(self, byte_count, alignment);
4747 // This loop should get optimized out in ReleaseFast mode
4848 for (byte_slice) |*byte| {
......@@ -63,7 +63,7 @@ pub const Allocator = struct {
6363 }
6464
6565 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;
6767 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
6868 // This loop should get optimized out in ReleaseFast mode
6969 for (byte_slice[old_byte_slice.len..]) |*byte| {
std/os/index.zig+60-25
......@@ -38,6 +38,9 @@ pub const windowsLoadDll = windows_util.windowsLoadDll;
3838pub const windowsUnloadDll = windows_util.windowsUnloadDll;
3939pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
4040
41pub const WindowsOpenError = windows_util.OpenError;
42pub const WindowsWriteError = windows_util.WriteError;
43
4144pub const FileHandle = if (is_windows) windows.HANDLE else i32;
4245
4346const debug = std.debug;
......@@ -188,8 +191,21 @@ pub fn posixRead(fd: i32, buf: []u8) !void {
188191 }
189192}
190193
194pub 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
191207/// Calls POSIX write, and keeps trying if it gets interrupted.
192pub fn posixWrite(fd: i32, bytes: []const u8) !void {
208pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
193209 while (true) {
194210 const write_ret = posix.write(fd, bytes.ptr, bytes.len);
195211 const write_err = posix.getErrno(write_ret);
......@@ -197,15 +213,15 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
197213 return switch (write_err) {
198214 posix.EINTR => continue,
199215 posix.EINVAL, posix.EFAULT => unreachable,
200 posix.EAGAIN => error.WouldBlock,
201 posix.EBADF => error.FileClosed,
202 posix.EDESTADDRREQ => error.DestinationAddressRequired,
203 posix.EDQUOT => error.DiskQuota,
204 posix.EFBIG => error.FileTooBig,
205 posix.EIO => error.InputOutput,
206 posix.ENOSPC => error.NoSpaceLeft,
207 posix.EPERM => error.AccessDenied,
208 posix.EPIPE => error.BrokenPipe,
216 posix.EAGAIN => PosixWriteError.WouldBlock,
217 posix.EBADF => PosixWriteError.FileClosed,
218 posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
219 posix.EDQUOT => PosixWriteError.DiskQuota,
220 posix.EFBIG => PosixWriteError.FileTooBig,
221 posix.EIO => PosixWriteError.InputOutput,
222 posix.ENOSPC => PosixWriteError.NoSpaceLeft,
223 posix.EPERM => PosixWriteError.AccessDenied,
224 posix.EPIPE => PosixWriteError.BrokenPipe,
209225 else => unexpectedErrorPosix(write_err),
210226 };
211227 }
......@@ -213,13 +229,32 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
213229 }
214230}
215231
232pub 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
216251/// ::file_path may need to be copied in memory to add a null terminating byte. In this case
217252/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
218253/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
219254/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
220255/// Calls POSIX open, keeps trying if it gets interrupted, and translates
221256/// the return value into zig errors.
222pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) !i32 {
257pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) PosixOpenError!i32 {
223258 var stack_buf: [max_noalloc_path_len]u8 = undefined;
224259 var path0: []u8 = undefined;
225260 var need_free = false;
......@@ -247,20 +282,20 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
247282
248283 posix.EFAULT => unreachable,
249284 posix.EINVAL => unreachable,
250 posix.EACCES => error.AccessDenied,
251 posix.EFBIG, posix.EOVERFLOW => error.FileTooBig,
252 posix.EISDIR => error.IsDir,
253 posix.ELOOP => error.SymLinkLoop,
254 posix.EMFILE => error.ProcessFdQuotaExceeded,
255 posix.ENAMETOOLONG => error.NameTooLong,
256 posix.ENFILE => error.SystemFdQuotaExceeded,
257 posix.ENODEV => error.NoDevice,
258 posix.ENOENT => error.PathNotFound,
259 posix.ENOMEM => error.SystemResources,
260 posix.ENOSPC => error.NoSpaceLeft,
261 posix.ENOTDIR => error.NotDir,
262 posix.EPERM => error.AccessDenied,
263 posix.EEXIST => error.PathAlreadyExists,
285 posix.EACCES => PosixOpenError.AccessDenied,
286 posix.EFBIG, posix.EOVERFLOW => PosixOpenError.FileTooBig,
287 posix.EISDIR => PosixOpenError.IsDir,
288 posix.ELOOP => PosixOpenError.SymLinkLoop,
289 posix.EMFILE => PosixOpenError.ProcessFdQuotaExceeded,
290 posix.ENAMETOOLONG => PosixOpenError.NameTooLong,
291 posix.ENFILE => PosixOpenError.SystemFdQuotaExceeded,
292 posix.ENODEV => PosixOpenError.NoDevice,
293 posix.ENOENT => PosixOpenError.PathNotFound,
294 posix.ENOMEM => PosixOpenError.SystemResources,
295 posix.ENOSPC => PosixOpenError.NoSpaceLeft,
296 posix.ENOTDIR => PosixOpenError.NotDir,
297 posix.EPERM => PosixOpenError.AccessDenied,
298 posix.EEXIST => PosixOpenError.PathAlreadyExists,
264299 else => unexpectedErrorPosix(err),
265300 };
266301 }
std/os/windows/util.zig+32-13
......@@ -26,16 +26,25 @@ pub fn windowsClose(handle: windows.HANDLE) void {
2626 assert(windows.CloseHandle(handle) != 0);
2727}
2828
29pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) !void {
29pub const WriteError = error {
30 SystemResources,
31 OperationAborted,
32 SystemResources,
33 IoPending,
34 BrokenPipe,
35 Unexpected,
36};
37
38pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
3039 if (windows.WriteFile(handle, @ptrCast(&const c_void, bytes.ptr), u32(bytes.len), null, null) == 0) {
3140 const err = windows.GetLastError();
3241 return switch (err) {
33 windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,
34 windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,
35 windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
36 windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,
37 windows.ERROR.IO_PENDING => error.IoPending,
38 windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
42 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
43 windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
44 windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
45 windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
46 windows.ERROR.IO_PENDING => WriteError.IoPending,
47 windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
3948 else => os.unexpectedErrorWindows(err),
4049 };
4150 }
......@@ -66,12 +75,22 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
6675 mem.indexOf(u16, name_wide, []u16{'-','p','t','y'}) != null;
6776}
6877
78pub const OpenError = error {
79 SharingViolation,
80 PathAlreadyExists,
81 FileNotFound,
82 AccessDenied,
83 PipeBusy,
84 Unexpected,
85};
86
6987/// `file_path` may need to be copied in memory to add a null terminating byte. In this case
7088/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
7189/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
7290/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
7391pub 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
7594{
7695 var stack_buf: [os.max_noalloc_path_len]u8 = undefined;
7796 var path0: []u8 = undefined;
......@@ -95,11 +114,11 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
95114 if (result == windows.INVALID_HANDLE_VALUE) {
96115 const err = windows.GetLastError();
97116 return switch (err) {
98 windows.ERROR.SHARING_VIOLATION => error.SharingViolation,
99 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => error.PathAlreadyExists,
100 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
101 windows.ERROR.ACCESS_DENIED => error.AccessDenied,
102 windows.ERROR.PIPE_BUSY => error.PipeBusy,
117 windows.ERROR.SHARING_VIOLATION => OpenError.SharingViolation,
118 windows.ERROR.ALREADY_EXISTS, windows.ERROR.FILE_EXISTS => OpenError.PathAlreadyExists,
119 windows.ERROR.FILE_NOT_FOUND => OpenError.FileNotFound,
120 windows.ERROR.ACCESS_DENIED => OpenError.AccessDenied,
121 windows.ERROR.PIPE_BUSY => OpenError.PipeBusy,
103122 else => os.unexpectedErrorWindows(err),
104123 };
105124 }