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....@@ -13,3 +13,15 @@ then you can return void, or any error, and the error set is inferred.
1313
14// TODO this is an explicit cast and should actually coerce the type14// TODO this is an explicit cast and should actually coerce the type
15 erorr set casting15 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 |...@@ -5682,7 +5682,7 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression |
56825682
5683CurlySuffixExpression = TypeExpr option(ContainerInitExpression)5683CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
56845684
5685MultiplyOperator = "*" | "/" | "%" | "**" | "*%"5685MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
56865686
5687PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression5687PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
56885688
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};
541541
542struct AstNodeBinOpExpr {542struct 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};
20582059
2059struct IrInstructionBinOp {2060struct 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
530530
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);
536535
...@@ -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;
542541
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;
546545 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}
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
3844void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {3871void 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 }
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
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);
34303434
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);
34913499
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);
34943504
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;
34973507
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);
35103520
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 }
35123527
3513 LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);3528 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) {...@@ -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);
54235424
5424 buf_appendf(&err_set_type->name, "}");5425 buf_appendf(&err_set_type->name, "}");
54255426
...@@ -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
54535454
5454 uint32_t err_count = node->data.err_set_decl.decls.length;5455 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
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);
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
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}
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
6660static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {6682static 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_type6750 // 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);
75457580
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 }
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
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}
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
9628static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {9733static 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 }
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
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 }
1488114990
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}
10941095
1095/*1096/*
1096MultiplyOperator = "!" | "*" | "/" | "%" | "**" | "*%"1097MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
1097*/1098*/
1098static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {1099static 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,
104104
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 case107 /// `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 fixed108 /// 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 }
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 {
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;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7pub const Allocator = struct {7pub const Allocator = struct {
8 const Errors = error {OutOfMemory};8 const Error = error {OutOfMemory};
99
10 /// Allocate byte_count bytes and return them in a slice, with the10 /// 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,
1414
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.ptr21 /// * 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,
2525
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) T43 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 mode47 // 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 }
6464
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 mode68 // 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;
38pub const windowsUnloadDll = windows_util.windowsUnloadDll; 38pub const windowsUnloadDll = windows_util.windowsUnloadDll;
39pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;39pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
4040
41pub const WindowsOpenError = windows_util.OpenError;
42pub const WindowsWriteError = windows_util.WriteError;
43
41pub const FileHandle = if (is_windows) windows.HANDLE else i32;44pub const FileHandle = if (is_windows) windows.HANDLE else i32;
4245
43const debug = std.debug;46const 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}
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
191/// Calls POSIX write, and keeps trying if it gets interrupted.207/// 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 {
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}
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
216/// ::file_path may need to be copied in memory to add a null terminating byte. In this case251/// ::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 fixed252/// 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 translates255/// 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.
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 {
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
247282
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}
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 {
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}
6877
78pub 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 case87/// `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 fixed88/// 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.
73pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,91pub 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.HANDLE92 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 }