| author | |
| committer | |
| log | 5161d70620342749b1995fdaabb39220654cc941 |
| tree | ba940c1a85386f1866cd75aab67809b4c0c95755 |
| parent | 40ca39d3d5a556e3b5d7298e3a5182f4351bdd17 |
14 files changed, 949 insertions(+), 499 deletions(-)
doc/langref.html.in+8-8| ... | ... | @@ -1281,7 +1281,7 @@ const ptr = &x; |
| 1281 | 1281 | <pre><code>x() x[] x.y |
| 1282 | 1282 | !x -x -%x ~x *x &amp;x ?x %x ??x |
| 1283 | 1283 | x{} |
| 1284 | * / % ** *% | |
| 1284 | ! * / % ** *% | |
| 1285 | 1285 | + - ++ +% -% |
| 1286 | 1286 | &lt;&lt; &gt;&gt; |
| 1287 | 1287 | &amp; |
| ... | ... | @@ -5566,14 +5566,12 @@ fn readU32Be() u32 {} |
| 5566 | 5566 | {#header_open|Grammar#} |
| 5567 | 5567 | <pre><code class="nohighlight">Root = many(TopLevelItem) EOF |
| 5568 | 5568 | |
| 5569 | TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl | |
| 5569 | TopLevelItem = CompTimeExpression(Block) | TopLevelDecl | TestDecl | |
| 5570 | 5570 | |
| 5571 | 5571 | TestDecl = "test" String Block |
| 5572 | 5572 | |
| 5573 | 5573 | TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) |
| 5574 | 5574 | |
| 5575 | ErrorValueDecl = "error" Symbol ";" | |
| 5576 | ||
| 5577 | 5575 | GlobalVarDecl = option("export") VariableDeclaration ";" |
| 5578 | 5576 | |
| 5579 | 5577 | LocalVarDecl = option("comptime") VariableDeclaration |
| ... | ... | @@ -5588,7 +5586,7 @@ UseDecl = "use" Expression ";" |
| 5588 | 5586 | |
| 5589 | 5587 | ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" |
| 5590 | 5588 | |
| 5591 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr | |
| 5589 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr | |
| 5592 | 5590 | |
| 5593 | 5591 | FnDef = option("inline" | "export") FnProto Block |
| 5594 | 5592 | |
| ... | ... | @@ -5682,7 +5680,7 @@ MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | |
| 5682 | 5680 | |
| 5683 | 5681 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) |
| 5684 | 5682 | |
| 5685 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | |
| 5683 | MultiplyOperator = "!" | "*" | "/" | "%" | "**" | "*%" | |
| 5686 | 5684 | |
| 5687 | 5685 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression |
| 5688 | 5686 | |
| ... | ... | @@ -5702,9 +5700,9 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") |
| 5702 | 5700 | |
| 5703 | 5701 | StructLiteralField = "." Symbol "=" Expression |
| 5704 | 5702 | |
| 5705 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "??" | "-%" | "try" | |
| 5703 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | |
| 5706 | 5704 | |
| 5707 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) | |
| 5705 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | |
| 5708 | 5706 | |
| 5709 | 5707 | ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr |
| 5710 | 5708 | |
| ... | ... | @@ -5712,6 +5710,8 @@ GroupedExpression = "(" Expression ")" |
| 5712 | 5710 | |
| 5713 | 5711 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 5714 | 5712 | |
| 5713 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" | |
| 5714 | ||
| 5715 | 5715 | ContainerDecl = option("extern" | "packed") |
| 5716 | 5716 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) |
| 5717 | 5717 | "{" many(ContainerMember) "}"</code></pre> |
src/all_types.hpp+41-19| ... | ... | @@ -236,7 +236,7 @@ struct ConstExprValue { |
| 236 | 236 | TypeTableEntry *x_type; |
| 237 | 237 | ConstExprValue *x_maybe; |
| 238 | 238 | ConstErrValue x_err_union; |
| 239 | ErrorTableEntry *x_pure_err; | |
| 239 | ErrorTableEntry *x_err_set; | |
| 240 | 240 | BigInt x_enum_tag; |
| 241 | 241 | ConstStructValue x_struct; |
| 242 | 242 | ConstUnionValue x_union; |
| ... | ... | @@ -353,7 +353,6 @@ enum NodeType { |
| 353 | 353 | NodeTypeReturnExpr, |
| 354 | 354 | NodeTypeDefer, |
| 355 | 355 | NodeTypeVariableDeclaration, |
| 356 | NodeTypeErrorValueDecl, | |
| 357 | 356 | NodeTypeTestDecl, |
| 358 | 357 | NodeTypeBinOpExpr, |
| 359 | 358 | NodeTypeUnwrapErrorExpr, |
| ... | ... | @@ -393,6 +392,7 @@ enum NodeType { |
| 393 | 392 | NodeTypeVarLiteral, |
| 394 | 393 | NodeTypeIfErrorExpr, |
| 395 | 394 | NodeTypeTestExpr, |
| 395 | NodeTypeErrorSetDecl, | |
| 396 | 396 | }; |
| 397 | 397 | |
| 398 | 398 | struct AstNodeRoot { |
| ... | ... | @@ -424,6 +424,8 @@ struct AstNodeFnProto { |
| 424 | 424 | AstNode *align_expr; |
| 425 | 425 | // populated if the "section(S)" is present |
| 426 | 426 | AstNode *section_expr; |
| 427 | ||
| 428 | bool auto_err_set; | |
| 427 | 429 | }; |
| 428 | 430 | |
| 429 | 431 | struct AstNodeFnDef { |
| ... | ... | @@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration { |
| 486 | 488 | AstNode *section_expr; |
| 487 | 489 | }; |
| 488 | 490 | |
| 489 | struct AstNodeErrorValueDecl { | |
| 490 | Buf *name; | |
| 491 | ||
| 492 | ErrorTableEntry *err; | |
| 493 | }; | |
| 494 | ||
| 495 | 491 | struct AstNodeTestDecl { |
| 496 | 492 | Buf *name; |
| 497 | 493 | |
| ... | ... | @@ -540,6 +536,7 @@ enum BinOpType { |
| 540 | 536 | BinOpTypeUnwrapMaybe, |
| 541 | 537 | BinOpTypeArrayCat, |
| 542 | 538 | BinOpTypeArrayMult, |
| 539 | BinOpTypeErrorUnion, | |
| 543 | 540 | }; |
| 544 | 541 | |
| 545 | 542 | struct AstNodeBinOpExpr { |
| ... | ... | @@ -595,7 +592,6 @@ enum PrefixOp { |
| 595 | 592 | PrefixOpNegationWrap, |
| 596 | 593 | PrefixOpDereference, |
| 597 | 594 | PrefixOpMaybe, |
| 598 | PrefixOpError, | |
| 599 | 595 | PrefixOpUnwrapMaybe, |
| 600 | 596 | }; |
| 601 | 597 | |
| ... | ... | @@ -762,6 +758,10 @@ struct AstNodeContainerDecl { |
| 762 | 758 | bool auto_enum; // union(enum) |
| 763 | 759 | }; |
| 764 | 760 | |
| 761 | struct AstNodeErrorSetDecl { | |
| 762 | ZigList<AstNode *> decls; | |
| 763 | }; | |
| 764 | ||
| 765 | 765 | struct AstNodeStructField { |
| 766 | 766 | VisibMod visib_mod; |
| 767 | 767 | Buf *name; |
| ... | ... | @@ -858,7 +858,6 @@ struct AstNode { |
| 858 | 858 | AstNodeReturnExpr return_expr; |
| 859 | 859 | AstNodeDefer defer; |
| 860 | 860 | AstNodeVariableDeclaration variable_declaration; |
| 861 | AstNodeErrorValueDecl error_value_decl; | |
| 862 | 861 | AstNodeTestDecl test_decl; |
| 863 | 862 | AstNodeBinOpExpr bin_op_expr; |
| 864 | 863 | AstNodeCatchExpr unwrap_err_expr; |
| ... | ... | @@ -899,6 +898,7 @@ struct AstNode { |
| 899 | 898 | AstNodeArrayType array_type; |
| 900 | 899 | AstNodeErrorType error_type; |
| 901 | 900 | AstNodeVarLiteral var_literal; |
| 901 | AstNodeErrorSetDecl err_set_decl; | |
| 902 | 902 | } data; |
| 903 | 903 | }; |
| 904 | 904 | |
| ... | ... | @@ -993,8 +993,15 @@ struct TypeTableEntryMaybe { |
| 993 | 993 | TypeTableEntry *child_type; |
| 994 | 994 | }; |
| 995 | 995 | |
| 996 | struct TypeTableEntryError { | |
| 997 | TypeTableEntry *child_type; | |
| 996 | struct TypeTableEntryErrorUnion { | |
| 997 | TypeTableEntry *err_set_type; | |
| 998 | TypeTableEntry *payload_type; | |
| 999 | }; | |
| 1000 | ||
| 1001 | struct TypeTableEntryErrorSet { | |
| 1002 | uint32_t err_count; | |
| 1003 | ErrorTableEntry **errors; | |
| 1004 | FnTableEntry *infer_fn; | |
| 998 | 1005 | }; |
| 999 | 1006 | |
| 1000 | 1007 | struct TypeTableEntryEnum { |
| ... | ... | @@ -1097,7 +1104,7 @@ enum TypeTableEntryId { |
| 1097 | 1104 | TypeTableEntryIdNullLit, |
| 1098 | 1105 | TypeTableEntryIdMaybe, |
| 1099 | 1106 | TypeTableEntryIdErrorUnion, |
| 1100 | TypeTableEntryIdPureError, | |
| 1107 | TypeTableEntryIdErrorSet, | |
| 1101 | 1108 | TypeTableEntryIdEnum, |
| 1102 | 1109 | TypeTableEntryIdUnion, |
| 1103 | 1110 | TypeTableEntryIdFn, |
| ... | ... | @@ -1126,7 +1133,8 @@ struct TypeTableEntry { |
| 1126 | 1133 | TypeTableEntryArray array; |
| 1127 | 1134 | TypeTableEntryStruct structure; |
| 1128 | 1135 | TypeTableEntryMaybe maybe; |
| 1129 | TypeTableEntryError error; | |
| 1136 | TypeTableEntryErrorUnion error_union; | |
| 1137 | TypeTableEntryErrorSet error_set; | |
| 1130 | 1138 | TypeTableEntryEnum enumeration; |
| 1131 | 1139 | TypeTableEntryUnion unionation; |
| 1132 | 1140 | TypeTableEntryFn fn; |
| ... | ... | @@ -1136,7 +1144,6 @@ struct TypeTableEntry { |
| 1136 | 1144 | // use these fields to make sure we don't duplicate type table entries for the same type |
| 1137 | 1145 | TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const] |
| 1138 | 1146 | TypeTableEntry *maybe_parent; |
| 1139 | TypeTableEntry *error_parent; | |
| 1140 | 1147 | // If we generate a constant name value for this type, we memoize it here. |
| 1141 | 1148 | // The type of this is array |
| 1142 | 1149 | ConstExprValue *cached_const_name_val; |
| ... | ... | @@ -1340,6 +1347,10 @@ struct TypeId { |
| 1340 | 1347 | bool is_signed; |
| 1341 | 1348 | uint32_t bit_count; |
| 1342 | 1349 | } integer; |
| 1350 | struct { | |
| 1351 | TypeTableEntry *err_set_type; | |
| 1352 | TypeTableEntry *payload_type; | |
| 1353 | } error_union; | |
| 1343 | 1354 | } data; |
| 1344 | 1355 | }; |
| 1345 | 1356 | |
| ... | ... | @@ -1481,7 +1492,7 @@ struct CodeGen { |
| 1481 | 1492 | TypeTableEntry *entry_undef; |
| 1482 | 1493 | TypeTableEntry *entry_null; |
| 1483 | 1494 | TypeTableEntry *entry_var; |
| 1484 | TypeTableEntry *entry_pure_error; | |
| 1495 | TypeTableEntry *entry_global_error_set; | |
| 1485 | 1496 | TypeTableEntry *entry_arg_tuple; |
| 1486 | 1497 | } builtin_types; |
| 1487 | 1498 | |
| ... | ... | @@ -1570,7 +1581,6 @@ struct CodeGen { |
| 1570 | 1581 | LLVMValueRef return_address_fn_val; |
| 1571 | 1582 | LLVMValueRef frame_address_fn_val; |
| 1572 | 1583 | bool error_during_imports; |
| 1573 | TypeTableEntry *err_tag_type; | |
| 1574 | 1584 | |
| 1575 | 1585 | const char **clang_argv; |
| 1576 | 1586 | size_t clang_argv_len; |
| ... | ... | @@ -1584,7 +1594,9 @@ struct CodeGen { |
| 1584 | 1594 | |
| 1585 | 1595 | bool each_lib_rpath; |
| 1586 | 1596 | |
| 1587 | ZigList<AstNode *> error_decls; | |
| 1597 | TypeTableEntry *err_tag_type; | |
| 1598 | ZigList<ZigLLVMDIEnumerator *> err_enumerators; | |
| 1599 | ZigList<ErrorTableEntry *> errors_by_index; | |
| 1588 | 1600 | bool generate_error_name_table; |
| 1589 | 1601 | LLVMValueRef err_name_table; |
| 1590 | 1602 | size_t largest_err_name_len; |
| ... | ... | @@ -1617,6 +1629,8 @@ struct CodeGen { |
| 1617 | 1629 | TypeTableEntry *align_amt_type; |
| 1618 | 1630 | TypeTableEntry *stack_trace_type; |
| 1619 | 1631 | TypeTableEntry *ptr_to_stack_trace_type; |
| 1632 | ||
| 1633 | ZigList<ZigLLVMDIType **> error_di_types; | |
| 1620 | 1634 | }; |
| 1621 | 1635 | |
| 1622 | 1636 | enum VarLinkage { |
| ... | ... | @@ -1653,6 +1667,7 @@ struct ErrorTableEntry { |
| 1653 | 1667 | Buf name; |
| 1654 | 1668 | uint32_t value; |
| 1655 | 1669 | AstNode *decl_node; |
| 1670 | TypeTableEntry *set_with_only_this_in_it; | |
| 1656 | 1671 | // If we generate a constant error name value for this error, we memoize it here. |
| 1657 | 1672 | // The type of this is array |
| 1658 | 1673 | ConstExprValue *cached_error_name_val; |
| ... | ... | @@ -1920,6 +1935,7 @@ enum IrInstructionId { |
| 1920 | 1935 | IrInstructionIdArgType, |
| 1921 | 1936 | IrInstructionIdExport, |
| 1922 | 1937 | IrInstructionIdErrorReturnTrace, |
| 1938 | IrInstructionIdErrorUnion, | |
| 1923 | 1939 | }; |
| 1924 | 1940 | |
| 1925 | 1941 | struct IrInstruction { |
| ... | ... | @@ -1996,7 +2012,6 @@ enum IrUnOp { |
| 1996 | 2012 | IrUnOpNegation, |
| 1997 | 2013 | IrUnOpNegationWrap, |
| 1998 | 2014 | IrUnOpDereference, |
| 1999 | IrUnOpError, | |
| 2000 | 2015 | IrUnOpMaybe, |
| 2001 | 2016 | }; |
| 2002 | 2017 | |
| ... | ... | @@ -2750,6 +2765,13 @@ struct IrInstructionErrorReturnTrace { |
| 2750 | 2765 | IrInstruction base; |
| 2751 | 2766 | }; |
| 2752 | 2767 | |
| 2768 | struct IrInstructionErrorUnion { | |
| 2769 | IrInstruction base; | |
| 2770 | ||
| 2771 | IrInstruction *err_set; | |
| 2772 | IrInstruction *payload; | |
| 2773 | }; | |
| 2774 | ||
| 2753 | 2775 | static const size_t slice_ptr_index = 0; |
| 2754 | 2776 | static const size_t slice_len_index = 1; |
| 2755 | 2777 |
src/analyze.cpp+124-88| ... | ... | @@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 224 | 224 | case TypeTableEntryIdNullLit: |
| 225 | 225 | case TypeTableEntryIdMaybe: |
| 226 | 226 | case TypeTableEntryIdErrorUnion: |
| 227 | case TypeTableEntryIdPureError: | |
| 227 | case TypeTableEntryIdErrorSet: | |
| 228 | 228 | case TypeTableEntryIdFn: |
| 229 | 229 | case TypeTableEntryIdNamespace: |
| 230 | 230 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { |
| 260 | 260 | case TypeTableEntryIdNullLit: |
| 261 | 261 | case TypeTableEntryIdMaybe: |
| 262 | 262 | case TypeTableEntryIdErrorUnion: |
| 263 | case TypeTableEntryIdPureError: | |
| 263 | case TypeTableEntryIdErrorSet: | |
| 264 | 264 | case TypeTableEntryIdFn: |
| 265 | 265 | case TypeTableEntryIdNamespace: |
| 266 | 266 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -514,29 +514,39 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 514 | 514 | } |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | |
| 518 | if (child_type->error_parent) | |
| 519 | return child_type->error_parent; | |
| 517 | TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type) { | |
| 518 | assert(err_set_type->id == TypeTableEntryIdErrorSet); | |
| 519 | ||
| 520 | TypeId type_id = {}; | |
| 521 | type_id.id = TypeTableEntryIdErrorUnion; | |
| 522 | type_id.data.error_union.err_set_type = err_set_type; | |
| 523 | type_id.data.error_union.payload_type = payload_type; | |
| 524 | ||
| 525 | auto existing_entry = g->type_table.maybe_get(type_id); | |
| 526 | if (existing_entry) { | |
| 527 | return existing_entry->value; | |
| 528 | } | |
| 520 | 529 | |
| 521 | 530 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); |
| 522 | 531 | entry->is_copyable = true; |
| 523 | assert(child_type->type_ref); | |
| 524 | assert(child_type->di_type); | |
| 525 | ensure_complete_type(g, child_type); | |
| 532 | assert(payload_type->type_ref); | |
| 533 | assert(payload_type->di_type); | |
| 534 | ensure_complete_type(g, payload_type); | |
| 526 | 535 | |
| 527 | 536 | buf_resize(&entry->name, 0); |
| 528 | buf_appendf(&entry->name, "%%%s", buf_ptr(&child_type->name)); | |
| 537 | buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); | |
| 529 | 538 | |
| 530 | entry->data.error.child_type = child_type; | |
| 539 | entry->data.error_union.err_set_type = err_set_type; | |
| 540 | entry->data.error_union.payload_type = payload_type; | |
| 531 | 541 | |
| 532 | if (!type_has_bits(child_type)) { | |
| 533 | entry->type_ref = g->err_tag_type->type_ref; | |
| 534 | entry->di_type = g->err_tag_type->di_type; | |
| 542 | if (!type_has_bits(payload_type)) { | |
| 543 | entry->type_ref = err_set_type->type_ref; | |
| 544 | entry->di_type = err_set_type->di_type; | |
| 535 | 545 | |
| 536 | 546 | } else { |
| 537 | 547 | LLVMTypeRef elem_types[] = { |
| 538 | g->err_tag_type->type_ref, | |
| 539 | child_type->type_ref, | |
| 548 | err_set_type->type_ref, | |
| 549 | payload_type->type_ref, | |
| 540 | 550 | }; |
| 541 | 551 | entry->type_ref = LLVMStructType(elem_types, 2, false); |
| 542 | 552 | |
| ... | ... | @@ -547,12 +557,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 547 | 557 | ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name), |
| 548 | 558 | compile_unit_scope, di_file, line); |
| 549 | 559 | |
| 550 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | |
| 551 | uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | |
| 560 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_type->type_ref); | |
| 561 | uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref); | |
| 552 | 562 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index); |
| 553 | 563 | |
| 554 | uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref); | |
| 555 | uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref); | |
| 564 | uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_type->type_ref); | |
| 565 | uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref); | |
| 556 | 566 | uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, |
| 557 | 567 | err_union_payload_index); |
| 558 | 568 | |
| ... | ... | @@ -565,13 +575,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 565 | 575 | tag_debug_size_in_bits, |
| 566 | 576 | tag_debug_align_in_bits, |
| 567 | 577 | tag_offset_in_bits, |
| 568 | 0, child_type->di_type), | |
| 578 | 0, err_set_type->di_type), | |
| 569 | 579 | ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type), |
| 570 | 580 | "value", di_file, line, |
| 571 | 581 | value_debug_size_in_bits, |
| 572 | 582 | value_debug_align_in_bits, |
| 573 | 583 | value_offset_in_bits, |
| 574 | 0, child_type->di_type), | |
| 584 | 0, payload_type->di_type), | |
| 575 | 585 | }; |
| 576 | 586 | |
| 577 | 587 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, |
| ... | ... | @@ -587,7 +597,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 587 | 597 | entry->di_type = replacement_di_type; |
| 588 | 598 | } |
| 589 | 599 | |
| 590 | child_type->error_parent = entry; | |
| 600 | g->type_table.put(type_id, entry); | |
| 591 | 601 | return entry; |
| 592 | 602 | } |
| 593 | 603 | |
| ... | ... | @@ -937,7 +947,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 937 | 947 | handle_is_ptr(fn_type_id->return_type); |
| 938 | 948 | bool prefix_arg_error_return_trace = g->have_err_ret_tracing && |
| 939 | 949 | (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion || |
| 940 | fn_type_id->return_type->id == TypeTableEntryIdPureError); | |
| 950 | fn_type_id->return_type->id == TypeTableEntryIdErrorSet); | |
| 941 | 951 | // +1 for maybe making the first argument the return value |
| 942 | 952 | // +1 for maybe last argument the error return trace |
| 943 | 953 | LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count); |
| ... | ... | @@ -1177,7 +1187,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { |
| 1177 | 1187 | case TypeTableEntryIdUndefLit: |
| 1178 | 1188 | case TypeTableEntryIdNullLit: |
| 1179 | 1189 | case TypeTableEntryIdErrorUnion: |
| 1180 | case TypeTableEntryIdPureError: | |
| 1190 | case TypeTableEntryIdErrorSet: | |
| 1181 | 1191 | case TypeTableEntryIdNamespace: |
| 1182 | 1192 | case TypeTableEntryIdBlock: |
| 1183 | 1193 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -1218,7 +1228,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { |
| 1218 | 1228 | case TypeTableEntryIdUndefLit: |
| 1219 | 1229 | case TypeTableEntryIdNullLit: |
| 1220 | 1230 | case TypeTableEntryIdErrorUnion: |
| 1221 | case TypeTableEntryIdPureError: | |
| 1231 | case TypeTableEntryIdErrorSet: | |
| 1222 | 1232 | case TypeTableEntryIdNamespace: |
| 1223 | 1233 | case TypeTableEntryIdBlock: |
| 1224 | 1234 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -1263,7 +1273,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { |
| 1263 | 1273 | zig_unreachable(); |
| 1264 | 1274 | } |
| 1265 | 1275 | |
| 1266 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { | |
| 1276 | static TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) { | |
| 1277 | TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet); | |
| 1278 | buf_resize(&err_set_type->name, 0); | |
| 1279 | buf_appendf(&err_set_type->name, "%s.errors", buf_ptr(&fn_entry->symbol_name)); | |
| 1280 | err_set_type->is_copyable = true; | |
| 1281 | err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref; | |
| 1282 | err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type; | |
| 1283 | err_set_type->data.error_set.err_count = 0; | |
| 1284 | err_set_type->data.error_set.errors = nullptr; | |
| 1285 | err_set_type->data.error_set.infer_fn = fn_entry; | |
| 1286 | ||
| 1287 | g->error_di_types.append(&err_set_type->di_type); | |
| 1288 | ||
| 1289 | return err_set_type; | |
| 1290 | } | |
| 1291 | ||
| 1292 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) { | |
| 1267 | 1293 | assert(proto_node->type == NodeTypeFnProto); |
| 1268 | 1294 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1269 | 1295 | |
| ... | ... | @@ -1359,7 +1385,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1359 | 1385 | case TypeTableEntryIdStruct: |
| 1360 | 1386 | case TypeTableEntryIdMaybe: |
| 1361 | 1387 | case TypeTableEntryIdErrorUnion: |
| 1362 | case TypeTableEntryIdPureError: | |
| 1388 | case TypeTableEntryIdErrorSet: | |
| 1363 | 1389 | case TypeTableEntryIdEnum: |
| 1364 | 1390 | case TypeTableEntryIdUnion: |
| 1365 | 1391 | case TypeTableEntryIdFn: |
| ... | ... | @@ -1382,8 +1408,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1382 | 1408 | } |
| 1383 | 1409 | } |
| 1384 | 1410 | |
| 1385 | fn_type_id.return_type = (fn_proto->return_type == nullptr) ? | |
| 1386 | g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type); | |
| 1411 | TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); | |
| 1412 | if (fn_proto->auto_err_set) { | |
| 1413 | TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(g, fn_entry); | |
| 1414 | fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type); | |
| 1415 | } else { | |
| 1416 | fn_type_id.return_type = specified_return_type; | |
| 1417 | } | |
| 1387 | 1418 | |
| 1388 | 1419 | if (type_is_invalid(fn_type_id.return_type)) { |
| 1389 | 1420 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -1434,7 +1465,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1434 | 1465 | case TypeTableEntryIdStruct: |
| 1435 | 1466 | case TypeTableEntryIdMaybe: |
| 1436 | 1467 | case TypeTableEntryIdErrorUnion: |
| 1437 | case TypeTableEntryIdPureError: | |
| 1468 | case TypeTableEntryIdErrorSet: | |
| 1438 | 1469 | case TypeTableEntryIdEnum: |
| 1439 | 1470 | case TypeTableEntryIdUnion: |
| 1440 | 1471 | case TypeTableEntryIdFn: |
| ... | ... | @@ -2756,7 +2787,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { |
| 2756 | 2787 | return g->test_fn_type; |
| 2757 | 2788 | |
| 2758 | 2789 | FnTypeId fn_type_id = {0}; |
| 2759 | fn_type_id.return_type = get_error_type(g, g->builtin_types.entry_void); | |
| 2790 | fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set, | |
| 2791 | g->builtin_types.entry_void); | |
| 2760 | 2792 | g->test_fn_type = get_fn_type(g, &fn_type_id); |
| 2761 | 2793 | return g->test_fn_type; |
| 2762 | 2794 | } |
| ... | ... | @@ -2824,7 +2856,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2824 | 2856 | |
| 2825 | 2857 | Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; |
| 2826 | 2858 | |
| 2827 | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); | |
| 2859 | fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry); | |
| 2828 | 2860 | |
| 2829 | 2861 | if (fn_proto->section_expr != nullptr) { |
| 2830 | 2862 | if (fn_table_entry->body_node == nullptr) { |
| ... | ... | @@ -2949,29 +2981,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope |
| 2949 | 2981 | g->resolve_queue.append(&tld_fn->base); |
| 2950 | 2982 | } |
| 2951 | 2983 | |
| 2952 | static void preview_error_value_decl(CodeGen *g, AstNode *node) { | |
| 2953 | assert(node->type == NodeTypeErrorValueDecl); | |
| 2954 | ||
| 2955 | ErrorTableEntry *err = allocate<ErrorTableEntry>(1); | |
| 2956 | ||
| 2957 | err->decl_node = node; | |
| 2958 | buf_init_from_buf(&err->name, node->data.error_value_decl.name); | |
| 2959 | ||
| 2960 | auto existing_entry = g->error_table.maybe_get(&err->name); | |
| 2961 | if (existing_entry) { | |
| 2962 | // duplicate error definitions allowed and they get the same value | |
| 2963 | err->value = existing_entry->value->value; | |
| 2964 | } else { | |
| 2965 | size_t error_value_count = g->error_decls.length; | |
| 2966 | assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count)); | |
| 2967 | err->value = (uint32_t)error_value_count; | |
| 2968 | g->error_decls.append(node); | |
| 2969 | g->error_table.put(&err->name, err); | |
| 2970 | } | |
| 2971 | ||
| 2972 | node->data.error_value_decl.err = err; | |
| 2973 | } | |
| 2974 | ||
| 2975 | 2984 | static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { |
| 2976 | 2985 | assert(node->type == NodeTypeCompTime); |
| 2977 | 2986 | |
| ... | ... | @@ -3045,10 +3054,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3045 | 3054 | import->use_decls.append(node); |
| 3046 | 3055 | break; |
| 3047 | 3056 | } |
| 3048 | case NodeTypeErrorValueDecl: | |
| 3049 | // error value declarations do not depend on other top level decls | |
| 3050 | preview_error_value_decl(g, node); | |
| 3051 | break; | |
| 3052 | 3057 | case NodeTypeTestDecl: |
| 3053 | 3058 | preview_test_decl(g, node, decls_scope); |
| 3054 | 3059 | break; |
| ... | ... | @@ -3097,6 +3102,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3097 | 3102 | case NodeTypeVarLiteral: |
| 3098 | 3103 | case NodeTypeIfErrorExpr: |
| 3099 | 3104 | case NodeTypeTestExpr: |
| 3105 | case NodeTypeErrorSetDecl: | |
| 3100 | 3106 | zig_unreachable(); |
| 3101 | 3107 | } |
| 3102 | 3108 | } |
| ... | ... | @@ -3147,7 +3153,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 3147 | 3153 | case TypeTableEntryIdStruct: |
| 3148 | 3154 | case TypeTableEntryIdMaybe: |
| 3149 | 3155 | case TypeTableEntryIdErrorUnion: |
| 3150 | case TypeTableEntryIdPureError: | |
| 3156 | case TypeTableEntryIdErrorSet: | |
| 3151 | 3157 | case TypeTableEntryIdEnum: |
| 3152 | 3158 | case TypeTableEntryIdUnion: |
| 3153 | 3159 | case TypeTableEntryIdFn: |
| ... | ... | @@ -3403,13 +3409,16 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry * |
| 3403 | 3409 | actual_type->data.maybe.child_type); |
| 3404 | 3410 | } |
| 3405 | 3411 | |
| 3406 | // error | |
| 3412 | // error union | |
| 3407 | 3413 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 3408 | 3414 | actual_type->id == TypeTableEntryIdErrorUnion) |
| 3409 | 3415 | { |
| 3410 | 3416 | return types_match_const_cast_only( |
| 3411 | expected_type->data.error.child_type, | |
| 3412 | actual_type->data.error.child_type); | |
| 3417 | expected_type->data.error_union.payload_type, | |
| 3418 | actual_type->data.error_union.payload_type) && | |
| 3419 | types_match_const_cast_only( | |
| 3420 | expected_type->data.error_union.err_set_type, | |
| 3421 | actual_type->data.error_union.err_set_type); | |
| 3413 | 3422 | } |
| 3414 | 3423 | |
| 3415 | 3424 | // fn |
| ... | ... | @@ -3625,7 +3634,7 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 3625 | 3634 | case TypeTableEntryIdNullLit: |
| 3626 | 3635 | case TypeTableEntryIdMaybe: |
| 3627 | 3636 | case TypeTableEntryIdErrorUnion: |
| 3628 | case TypeTableEntryIdPureError: | |
| 3637 | case TypeTableEntryIdErrorSet: | |
| 3629 | 3638 | case TypeTableEntryIdFn: |
| 3630 | 3639 | case TypeTableEntryIdNamespace: |
| 3631 | 3640 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -3673,7 +3682,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 3673 | 3682 | case TypeTableEntryIdNullLit: |
| 3674 | 3683 | case TypeTableEntryIdMaybe: |
| 3675 | 3684 | case TypeTableEntryIdErrorUnion: |
| 3676 | case TypeTableEntryIdPureError: | |
| 3685 | case TypeTableEntryIdErrorSet: | |
| 3677 | 3686 | case TypeTableEntryIdFn: |
| 3678 | 3687 | case TypeTableEntryIdNamespace: |
| 3679 | 3688 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -3774,14 +3783,36 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3774 | 3783 | &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3775 | 3784 | fn_table_entry->implicit_return_type = block_return_type; |
| 3776 | 3785 | |
| 3777 | if (block_return_type->id == TypeTableEntryIdInvalid || | |
| 3778 | fn_table_entry->analyzed_executable.invalid) | |
| 3779 | { | |
| 3786 | if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) { | |
| 3780 | 3787 | assert(g->errors.length > 0); |
| 3781 | 3788 | fn_table_entry->anal_state = FnAnalStateInvalid; |
| 3782 | 3789 | return; |
| 3783 | 3790 | } |
| 3784 | 3791 | |
| 3792 | if (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3793 | TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; | |
| 3794 | if (return_err_set_type->data.error_set.infer_fn != nullptr) { | |
| 3795 | TypeTableEntry *inferred_err_set_type; | |
| 3796 | if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) { | |
| 3797 | inferred_err_set_type = fn_table_entry->implicit_return_type; | |
| 3798 | } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) { | |
| 3799 | inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type; | |
| 3800 | } else { | |
| 3801 | add_node_error(g, return_type_node, | |
| 3802 | buf_sprintf("function with inferred error set must return at least one possible error")); | |
| 3803 | fn_table_entry->anal_state = FnAnalStateInvalid; | |
| 3804 | return; | |
| 3805 | } | |
| 3806 | ||
| 3807 | return_err_set_type->data.error_set.infer_fn = nullptr; | |
| 3808 | return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; | |
| 3809 | return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count); | |
| 3810 | for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) { | |
| 3811 | return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i]; | |
| 3812 | } | |
| 3813 | } | |
| 3814 | } | |
| 3815 | ||
| 3785 | 3816 | if (g->verbose_ir) { |
| 3786 | 3817 | fprintf(stderr, "{ // (analyzed)\n"); |
| 3787 | 3818 | ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4); |
| ... | ... | @@ -3791,7 +3822,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ |
| 3791 | 3822 | fn_table_entry->anal_state = FnAnalStateComplete; |
| 3792 | 3823 | } |
| 3793 | 3824 | |
| 3794 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | |
| 3825 | void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | |
| 3795 | 3826 | assert(fn_table_entry->anal_state != FnAnalStateProbing); |
| 3796 | 3827 | if (fn_table_entry->anal_state != FnAnalStateReady) |
| 3797 | 3828 | return; |
| ... | ... | @@ -4022,7 +4053,8 @@ void semantic_analyze(CodeGen *g) { |
| 4022 | 4053 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { |
| 4023 | 4054 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); |
| 4024 | 4055 | bool pointer_only = false; |
| 4025 | resolve_top_level_decl(g, tld, pointer_only, nullptr); | |
| 4056 | AstNode *source_node = nullptr; | |
| 4057 | resolve_top_level_decl(g, tld, pointer_only, source_node); | |
| 4026 | 4058 | } |
| 4027 | 4059 | |
| 4028 | 4060 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| ... | ... | @@ -4114,7 +4146,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 4114 | 4146 | case TypeTableEntryIdInt: |
| 4115 | 4147 | case TypeTableEntryIdFloat: |
| 4116 | 4148 | case TypeTableEntryIdPointer: |
| 4117 | case TypeTableEntryIdPureError: | |
| 4149 | case TypeTableEntryIdErrorSet: | |
| 4118 | 4150 | case TypeTableEntryIdFn: |
| 4119 | 4151 | case TypeTableEntryIdEnum: |
| 4120 | 4152 | return false; |
| ... | ... | @@ -4122,7 +4154,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 4122 | 4154 | case TypeTableEntryIdStruct: |
| 4123 | 4155 | return type_has_bits(type_entry); |
| 4124 | 4156 | case TypeTableEntryIdErrorUnion: |
| 4125 | return type_has_bits(type_entry->data.error.child_type); | |
| 4157 | return type_has_bits(type_entry->data.error_union.payload_type); | |
| 4126 | 4158 | case TypeTableEntryIdMaybe: |
| 4127 | 4159 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 4128 | 4160 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && |
| ... | ... | @@ -4386,9 +4418,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 4386 | 4418 | case TypeTableEntryIdErrorUnion: |
| 4387 | 4419 | // TODO better hashing algorithm |
| 4388 | 4420 | return 3415065496; |
| 4389 | case TypeTableEntryIdPureError: | |
| 4390 | // TODO better hashing algorithm | |
| 4391 | return 2630160122; | |
| 4421 | case TypeTableEntryIdErrorSet: | |
| 4422 | assert(const_val->data.x_err_set != nullptr); | |
| 4423 | return const_val->data.x_err_set->value ^ 2630160122; | |
| 4392 | 4424 | case TypeTableEntryIdFn: |
| 4393 | 4425 | return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry); |
| 4394 | 4426 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -4515,7 +4547,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 4515 | 4547 | case TypeTableEntryIdMaybe: |
| 4516 | 4548 | case TypeTableEntryIdErrorUnion: |
| 4517 | 4549 | case TypeTableEntryIdEnum: |
| 4518 | case TypeTableEntryIdPureError: | |
| 4550 | case TypeTableEntryIdErrorSet: | |
| 4519 | 4551 | case TypeTableEntryIdFn: |
| 4520 | 4552 | case TypeTableEntryIdBool: |
| 4521 | 4553 | case TypeTableEntryIdInt: |
| ... | ... | @@ -4894,8 +4926,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 4894 | 4926 | return a->data.x_type == b->data.x_type; |
| 4895 | 4927 | case TypeTableEntryIdVoid: |
| 4896 | 4928 | return true; |
| 4897 | case TypeTableEntryIdPureError: | |
| 4898 | return a->data.x_pure_err == b->data.x_pure_err; | |
| 4929 | case TypeTableEntryIdErrorSet: | |
| 4930 | return a->data.x_err_set->value == b->data.x_err_set->value; | |
| 4899 | 4931 | case TypeTableEntryIdFn: |
| 4900 | 4932 | return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry; |
| 4901 | 4933 | case TypeTableEntryIdBool: |
| ... | ... | @@ -5256,9 +5288,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5256 | 5288 | buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name)); |
| 5257 | 5289 | return; |
| 5258 | 5290 | } |
| 5259 | case TypeTableEntryIdPureError: | |
| 5291 | case TypeTableEntryIdErrorSet: | |
| 5260 | 5292 | { |
| 5261 | buf_appendf(buf, "(pure error constant)"); | |
| 5293 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); | |
| 5262 | 5294 | return; |
| 5263 | 5295 | } |
| 5264 | 5296 | case TypeTableEntryIdArgTuple: |
| ... | ... | @@ -5319,8 +5351,7 @@ uint32_t type_id_hash(TypeId x) { |
| 5319 | 5351 | case TypeTableEntryIdUndefLit: |
| 5320 | 5352 | case TypeTableEntryIdNullLit: |
| 5321 | 5353 | case TypeTableEntryIdMaybe: |
| 5322 | case TypeTableEntryIdErrorUnion: | |
| 5323 | case TypeTableEntryIdPureError: | |
| 5354 | case TypeTableEntryIdErrorSet: | |
| 5324 | 5355 | case TypeTableEntryIdEnum: |
| 5325 | 5356 | case TypeTableEntryIdUnion: |
| 5326 | 5357 | case TypeTableEntryIdFn: |
| ... | ... | @@ -5329,6 +5360,8 @@ uint32_t type_id_hash(TypeId x) { |
| 5329 | 5360 | case TypeTableEntryIdBoundFn: |
| 5330 | 5361 | case TypeTableEntryIdArgTuple: |
| 5331 | 5362 | zig_unreachable(); |
| 5363 | case TypeTableEntryIdErrorUnion: | |
| 5364 | return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type); | |
| 5332 | 5365 | case TypeTableEntryIdPointer: |
| 5333 | 5366 | return hash_ptr(x.data.pointer.child_type) + |
| 5334 | 5367 | (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + |
| ... | ... | @@ -5363,8 +5396,7 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 5363 | 5396 | case TypeTableEntryIdUndefLit: |
| 5364 | 5397 | case TypeTableEntryIdNullLit: |
| 5365 | 5398 | case TypeTableEntryIdMaybe: |
| 5366 | case TypeTableEntryIdErrorUnion: | |
| 5367 | case TypeTableEntryIdPureError: | |
| 5399 | case TypeTableEntryIdErrorSet: | |
| 5368 | 5400 | case TypeTableEntryIdEnum: |
| 5369 | 5401 | case TypeTableEntryIdUnion: |
| 5370 | 5402 | case TypeTableEntryIdFn: |
| ... | ... | @@ -5374,6 +5406,10 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 5374 | 5406 | case TypeTableEntryIdArgTuple: |
| 5375 | 5407 | case TypeTableEntryIdOpaque: |
| 5376 | 5408 | zig_unreachable(); |
| 5409 | case TypeTableEntryIdErrorUnion: | |
| 5410 | return a.data.error_union.err_set_type == b.data.error_union.err_set_type && | |
| 5411 | a.data.error_union.payload_type == b.data.error_union.payload_type; | |
| 5412 | ||
| 5377 | 5413 | case TypeTableEntryIdPointer: |
| 5378 | 5414 | return a.data.pointer.child_type == b.data.pointer.child_type && |
| 5379 | 5415 | a.data.pointer.is_const == b.data.pointer.is_const && |
| ... | ... | @@ -5478,7 +5514,7 @@ static const TypeTableEntryId all_type_ids[] = { |
| 5478 | 5514 | TypeTableEntryIdNullLit, |
| 5479 | 5515 | TypeTableEntryIdMaybe, |
| 5480 | 5516 | TypeTableEntryIdErrorUnion, |
| 5481 | TypeTableEntryIdPureError, | |
| 5517 | TypeTableEntryIdErrorSet, | |
| 5482 | 5518 | TypeTableEntryIdEnum, |
| 5483 | 5519 | TypeTableEntryIdUnion, |
| 5484 | 5520 | TypeTableEntryIdFn, |
| ... | ... | @@ -5533,7 +5569,7 @@ size_t type_id_index(TypeTableEntryId id) { |
| 5533 | 5569 | return 13; |
| 5534 | 5570 | case TypeTableEntryIdErrorUnion: |
| 5535 | 5571 | return 14; |
| 5536 | case TypeTableEntryIdPureError: | |
| 5572 | case TypeTableEntryIdErrorSet: | |
| 5537 | 5573 | return 15; |
| 5538 | 5574 | case TypeTableEntryIdEnum: |
| 5539 | 5575 | return 16; |
| ... | ... | @@ -5590,8 +5626,8 @@ const char *type_id_name(TypeTableEntryId id) { |
| 5590 | 5626 | return "Nullable"; |
| 5591 | 5627 | case TypeTableEntryIdErrorUnion: |
| 5592 | 5628 | return "ErrorUnion"; |
| 5593 | case TypeTableEntryIdPureError: | |
| 5594 | return "Error"; | |
| 5629 | case TypeTableEntryIdErrorSet: | |
| 5630 | return "ErrorSet"; | |
| 5595 | 5631 | case TypeTableEntryIdEnum: |
| 5596 | 5632 | return "Enum"; |
| 5597 | 5633 | case TypeTableEntryIdUnion: |
src/analyze.hpp+2-2| ... | ... | @@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type); |
| 30 | 30 | TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, |
| 31 | 31 | AstNode *decl_node, const char *name, ContainerLayout layout); |
| 32 | 32 | TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); |
| 33 | TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); | |
| 33 | TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type); | |
| 34 | 34 | TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); |
| 35 | 35 | TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name); |
| 36 | 36 | TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[], |
| ... | ... | @@ -46,7 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry); |
| 46 | 46 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); |
| 47 | 47 | |
| 48 | 48 | |
| 49 | // TODO move these over, these used to be static | |
| 50 | 49 | bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type); |
| 51 | 50 | VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); |
| 52 | 51 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| ... | ... | @@ -188,6 +187,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G |
| 188 | 187 | |
| 189 | 188 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); |
| 190 | 189 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g); |
| 190 | void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | |
| 191 | 191 | |
| 192 | 192 | |
| 193 | 193 | #endif |
src/ast_render.cpp+24-5| ... | ... | @@ -54,6 +54,7 @@ static const char *bin_op_str(BinOpType bin_op) { |
| 54 | 54 | case BinOpTypeUnwrapMaybe: return "??"; |
| 55 | 55 | case BinOpTypeArrayCat: return "++"; |
| 56 | 56 | case BinOpTypeArrayMult: return "**"; |
| 57 | case BinOpTypeErrorUnion: return "!"; | |
| 57 | 58 | } |
| 58 | 59 | zig_unreachable(); |
| 59 | 60 | } |
| ... | ... | @@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 67 | 68 | case PrefixOpBinNot: return "~"; |
| 68 | 69 | case PrefixOpDereference: return "*"; |
| 69 | 70 | case PrefixOpMaybe: return "?"; |
| 70 | case PrefixOpError: return "%"; | |
| 71 | 71 | case PrefixOpUnwrapMaybe: return "??"; |
| 72 | 72 | } |
| 73 | 73 | zig_unreachable(); |
| ... | ... | @@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) { |
| 174 | 174 | return "Defer"; |
| 175 | 175 | case NodeTypeVariableDeclaration: |
| 176 | 176 | return "VariableDeclaration"; |
| 177 | case NodeTypeErrorValueDecl: | |
| 178 | return "ErrorValueDecl"; | |
| 179 | 177 | case NodeTypeTestDecl: |
| 180 | 178 | return "TestDecl"; |
| 181 | 179 | case NodeTypeIntLiteral: |
| ... | ... | @@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) { |
| 244 | 242 | return "IfErrorExpr"; |
| 245 | 243 | case NodeTypeTestExpr: |
| 246 | 244 | return "TestExpr"; |
| 245 | case NodeTypeErrorSetDecl: | |
| 246 | return "ErrorSetDecl"; | |
| 247 | 247 | } |
| 248 | 248 | zig_unreachable(); |
| 249 | 249 | } |
| ... | ... | @@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 396 | 396 | |
| 397 | 397 | if (child->type == NodeTypeUse || |
| 398 | 398 | child->type == NodeTypeVariableDeclaration || |
| 399 | child->type == NodeTypeErrorValueDecl || | |
| 400 | 399 | child->type == NodeTypeFnProto) |
| 401 | 400 | { |
| 402 | 401 | fprintf(ar->f, ";"); |
| ... | ... | @@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 452 | 451 | AstNode *return_type_node = node->data.fn_proto.return_type; |
| 453 | 452 | assert(return_type_node != nullptr); |
| 454 | 453 | fprintf(ar->f, " "); |
| 454 | if (node->data.fn_proto.auto_err_set) { | |
| 455 | fprintf(ar->f, "!"); | |
| 456 | } | |
| 455 | 457 | render_node_grouped(ar, return_type_node); |
| 456 | 458 | break; |
| 457 | 459 | } |
| ... | ... | @@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1017 | 1019 | render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); |
| 1018 | 1020 | break; |
| 1019 | 1021 | } |
| 1022 | case NodeTypeErrorSetDecl: | |
| 1023 | { | |
| 1024 | fprintf(ar->f, "error {\n"); | |
| 1025 | ar->indent += ar->indent_size; | |
| 1026 | ||
| 1027 | for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) { | |
| 1028 | AstNode *field_node = node->data.err_set_decl.decls.at(i); | |
| 1029 | assert(field_node->type == NodeTypeSymbol); | |
| 1030 | print_indent(ar); | |
| 1031 | print_symbol(ar, field_node->data.symbol_expr.symbol); | |
| 1032 | fprintf(ar->f, ",\n"); | |
| 1033 | } | |
| 1034 | ||
| 1035 | ar->indent -= ar->indent_size; | |
| 1036 | print_indent(ar); | |
| 1037 | fprintf(ar->f, "}"); | |
| 1038 | break; | |
| 1039 | } | |
| 1020 | 1040 | case NodeTypeFnDecl: |
| 1021 | 1041 | case NodeTypeParamDecl: |
| 1022 | case NodeTypeErrorValueDecl: | |
| 1023 | 1042 | case NodeTypeTestDecl: |
| 1024 | 1043 | case NodeTypeStructField: |
| 1025 | 1044 | case NodeTypeUse: |
src/codegen.cpp+76-51| ... | ... | @@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 92 | 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 93 | 93 | buf_resize(&g->global_asm, 0); |
| 94 | 94 | |
| 95 | // reserve index 0 to indicate no error | |
| 96 | g->error_decls.append(nullptr); | |
| 97 | ||
| 98 | 95 | if (root_src_path) { |
| 99 | 96 | Buf *src_basename = buf_alloc(); |
| 100 | 97 | Buf *src_dir = buf_alloc(); |
| ... | ... | @@ -410,7 +407,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e |
| 410 | 407 | } |
| 411 | 408 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 412 | 409 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; |
| 413 | if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) { | |
| 410 | if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) { | |
| 414 | 411 | return UINT32_MAX; |
| 415 | 412 | } |
| 416 | 413 | bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type); |
| ... | ... | @@ -1442,7 +1439,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 1442 | 1439 | is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError; |
| 1443 | 1440 | // TODO: emit a branch to check if the return value is an error |
| 1444 | 1441 | } |
| 1445 | } else if (return_type->id == TypeTableEntryIdPureError) { | |
| 1442 | } else if (return_type->id == TypeTableEntryIdErrorSet) { | |
| 1446 | 1443 | is_err_return = true; |
| 1447 | 1444 | } |
| 1448 | 1445 | if (is_err_return) { |
| ... | ... | @@ -1823,7 +1820,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1823 | 1820 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 1824 | 1821 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); |
| 1825 | 1822 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 1826 | } else if (type_entry->id == TypeTableEntryIdPureError || | |
| 1823 | } else if (type_entry->id == TypeTableEntryIdErrorSet || | |
| 1827 | 1824 | type_entry->id == TypeTableEntryIdPointer || |
| 1828 | 1825 | type_entry->id == TypeTableEntryIdBool) |
| 1829 | 1826 | { |
| ... | ... | @@ -2139,7 +2136,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, |
| 2139 | 2136 | |
| 2140 | 2137 | static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) { |
| 2141 | 2138 | TypeTableEntry *wanted_type = instruction->base.value.type; |
| 2142 | assert(wanted_type->id == TypeTableEntryIdPureError); | |
| 2139 | assert(wanted_type->id == TypeTableEntryIdErrorSet); | |
| 2143 | 2140 | |
| 2144 | 2141 | TypeTableEntry *actual_type = instruction->target->value.type; |
| 2145 | 2142 | assert(actual_type->id == TypeTableEntryIdInt); |
| ... | ... | @@ -2156,11 +2153,11 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I |
| 2156 | 2153 | eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true); |
| 2157 | 2154 | |
| 2158 | 2155 | if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && |
| 2159 | bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length) | |
| 2156 | bigint_as_unsigned(&biggest_possible_err_val) < g->errors_by_index.length) | |
| 2160 | 2157 | { |
| 2161 | 2158 | ok_bit = neq_zero_bit; |
| 2162 | 2159 | } else { |
| 2163 | LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false); | |
| 2160 | LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->errors_by_index.length, false); | |
| 2164 | 2161 | LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, ""); |
| 2165 | 2162 | ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, ""); |
| 2166 | 2163 | } |
| ... | ... | @@ -2187,15 +2184,15 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I |
| 2187 | 2184 | TypeTableEntry *actual_type = instruction->target->value.type; |
| 2188 | 2185 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); |
| 2189 | 2186 | |
| 2190 | if (actual_type->id == TypeTableEntryIdPureError) { | |
| 2187 | if (actual_type->id == TypeTableEntryIdErrorSet) { | |
| 2191 | 2188 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2192 | 2189 | g->err_tag_type, wanted_type, target_val); |
| 2193 | 2190 | } else if (actual_type->id == TypeTableEntryIdErrorUnion) { |
| 2194 | if (!type_has_bits(actual_type->data.error.child_type)) { | |
| 2191 | if (!type_has_bits(actual_type->data.error_union.payload_type)) { | |
| 2195 | 2192 | return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), |
| 2196 | 2193 | g->err_tag_type, wanted_type, target_val); |
| 2197 | 2194 | } else { |
| 2198 | zig_panic("TODO"); | |
| 2195 | zig_panic("TODO err to int when error union payload type not void"); | |
| 2199 | 2196 | } |
| 2200 | 2197 | } else { |
| 2201 | 2198 | zig_unreachable(); |
| ... | ... | @@ -2235,7 +2232,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst |
| 2235 | 2232 | |
| 2236 | 2233 | switch (op_id) { |
| 2237 | 2234 | case IrUnOpInvalid: |
| 2238 | case IrUnOpError: | |
| 2239 | 2235 | case IrUnOpMaybe: |
| 2240 | 2236 | case IrUnOpDereference: |
| 2241 | 2237 | zig_unreachable(); |
| ... | ... | @@ -2489,7 +2485,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2489 | 2485 | TypeTableEntry *src_return_type = fn_type_id->return_type; |
| 2490 | 2486 | bool ret_has_bits = type_has_bits(src_return_type); |
| 2491 | 2487 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); |
| 2492 | bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError); | |
| 2488 | bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet); | |
| 2493 | 2489 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0); |
| 2494 | 2490 | bool is_var_args = fn_type_id->is_var_args; |
| 2495 | 2491 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); |
| ... | ... | @@ -2907,7 +2903,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru |
| 2907 | 2903 | static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) { |
| 2908 | 2904 | assert(g->generate_error_name_table); |
| 2909 | 2905 | |
| 2910 | if (g->error_decls.length == 1) { | |
| 2906 | if (g->errors_by_index.length == 1) { | |
| 2911 | 2907 | LLVMBuildUnreachable(g->builder); |
| 2912 | 2908 | return nullptr; |
| 2913 | 2909 | } |
| ... | ... | @@ -2915,7 +2911,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI |
| 2915 | 2911 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); |
| 2916 | 2912 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 2917 | 2913 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); |
| 2918 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false); | |
| 2914 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false); | |
| 2919 | 2915 | add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); |
| 2920 | 2916 | } |
| 2921 | 2917 | |
| ... | ... | @@ -3393,11 +3389,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, |
| 3393 | 3389 | |
| 3394 | 3390 | static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { |
| 3395 | 3391 | TypeTableEntry *err_union_type = instruction->value->value.type; |
| 3396 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | |
| 3392 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; | |
| 3397 | 3393 | LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value); |
| 3398 | 3394 | |
| 3399 | 3395 | LLVMValueRef err_val; |
| 3400 | if (type_has_bits(child_type)) { | |
| 3396 | if (type_has_bits(payload_type)) { | |
| 3401 | 3397 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3402 | 3398 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3403 | 3399 | } else { |
| ... | ... | @@ -3412,11 +3408,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 3412 | 3408 | TypeTableEntry *ptr_type = instruction->value->value.type; |
| 3413 | 3409 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 3414 | 3410 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; |
| 3415 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | |
| 3411 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; | |
| 3416 | 3412 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); |
| 3417 | 3413 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3418 | 3414 | |
| 3419 | if (type_has_bits(child_type)) { | |
| 3415 | if (type_has_bits(payload_type)) { | |
| 3420 | 3416 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3421 | 3417 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3422 | 3418 | } else { |
| ... | ... | @@ -3428,13 +3424,13 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3428 | 3424 | TypeTableEntry *ptr_type = instruction->value->value.type; |
| 3429 | 3425 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 3430 | 3426 | TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type; |
| 3431 | TypeTableEntry *child_type = err_union_type->data.error.child_type; | |
| 3427 | TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type; | |
| 3432 | 3428 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); |
| 3433 | 3429 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3434 | 3430 | |
| 3435 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) { | |
| 3431 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { | |
| 3436 | 3432 | LLVMValueRef err_val; |
| 3437 | if (type_has_bits(child_type)) { | |
| 3433 | if (type_has_bits(payload_type)) { | |
| 3438 | 3434 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3439 | 3435 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3440 | 3436 | } else { |
| ... | ... | @@ -3452,7 +3448,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3452 | 3448 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3453 | 3449 | } |
| 3454 | 3450 | |
| 3455 | if (type_has_bits(child_type)) { | |
| 3451 | if (type_has_bits(payload_type)) { | |
| 3456 | 3452 | return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); |
| 3457 | 3453 | } else { |
| 3458 | 3454 | return nullptr; |
| ... | ... | @@ -3493,10 +3489,10 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable |
| 3493 | 3489 | |
| 3494 | 3490 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3495 | 3491 | |
| 3496 | TypeTableEntry *child_type = wanted_type->data.error.child_type; | |
| 3492 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; | |
| 3497 | 3493 | LLVMValueRef err_val = ir_llvm_value(g, instruction->value); |
| 3498 | 3494 | |
| 3499 | if (!type_has_bits(child_type)) | |
| 3495 | if (!type_has_bits(payload_type)) | |
| 3500 | 3496 | return err_val; |
| 3501 | 3497 | |
| 3502 | 3498 | assert(instruction->tmp_ptr); |
| ... | ... | @@ -3512,11 +3508,11 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 3512 | 3508 | |
| 3513 | 3509 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 3514 | 3510 | |
| 3515 | TypeTableEntry *child_type = wanted_type->data.error.child_type; | |
| 3511 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; | |
| 3516 | 3512 | |
| 3517 | 3513 | LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref); |
| 3518 | 3514 | |
| 3519 | if (!type_has_bits(child_type)) | |
| 3515 | if (!type_has_bits(payload_type)) | |
| 3520 | 3516 | return ok_err_val; |
| 3521 | 3517 | |
| 3522 | 3518 | assert(instruction->tmp_ptr); |
| ... | ... | @@ -3527,7 +3523,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 3527 | 3523 | gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); |
| 3528 | 3524 | |
| 3529 | 3525 | LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); |
| 3530 | gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val); | |
| 3526 | gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); | |
| 3531 | 3527 | |
| 3532 | 3528 | return instruction->tmp_ptr; |
| 3533 | 3529 | } |
| ... | ... | @@ -3700,6 +3696,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3700 | 3696 | case IrInstructionIdArgType: |
| 3701 | 3697 | case IrInstructionIdTagType: |
| 3702 | 3698 | case IrInstructionIdExport: |
| 3699 | case IrInstructionIdErrorUnion: | |
| 3703 | 3700 | zig_unreachable(); |
| 3704 | 3701 | case IrInstructionIdReturn: |
| 3705 | 3702 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -3933,7 +3930,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3933 | 3930 | case TypeTableEntryIdUndefLit: |
| 3934 | 3931 | case TypeTableEntryIdNullLit: |
| 3935 | 3932 | case TypeTableEntryIdErrorUnion: |
| 3936 | case TypeTableEntryIdPureError: | |
| 3933 | case TypeTableEntryIdErrorSet: | |
| 3937 | 3934 | case TypeTableEntryIdNamespace: |
| 3938 | 3935 | case TypeTableEntryIdBlock: |
| 3939 | 3936 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -4026,10 +4023,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4026 | 4023 | switch (type_entry->id) { |
| 4027 | 4024 | case TypeTableEntryIdInt: |
| 4028 | 4025 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); |
| 4029 | case TypeTableEntryIdPureError: | |
| 4030 | assert(const_val->data.x_pure_err); | |
| 4031 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, | |
| 4032 | const_val->data.x_pure_err->value, false); | |
| 4026 | case TypeTableEntryIdErrorSet: | |
| 4027 | assert(const_val->data.x_err_set != nullptr); | |
| 4028 | return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, | |
| 4029 | const_val->data.x_err_set->value, false); | |
| 4033 | 4030 | case TypeTableEntryIdFloat: |
| 4034 | 4031 | switch (type_entry->data.floating.bit_count) { |
| 4035 | 4032 | case 32: |
| ... | ... | @@ -4330,8 +4327,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4330 | 4327 | } |
| 4331 | 4328 | case TypeTableEntryIdErrorUnion: |
| 4332 | 4329 | { |
| 4333 | TypeTableEntry *child_type = type_entry->data.error.child_type; | |
| 4334 | if (!type_has_bits(child_type)) { | |
| 4330 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; | |
| 4331 | if (!type_has_bits(payload_type)) { | |
| 4335 | 4332 | uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; |
| 4336 | 4333 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 4337 | 4334 | } else { |
| ... | ... | @@ -4340,7 +4337,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4340 | 4337 | bool make_unnamed_struct; |
| 4341 | 4338 | if (const_val->data.x_err_union.err) { |
| 4342 | 4339 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); |
| 4343 | err_payload_value = LLVMConstNull(child_type->type_ref); | |
| 4340 | err_payload_value = LLVMConstNull(payload_type->type_ref); | |
| 4344 | 4341 | make_unnamed_struct = false; |
| 4345 | 4342 | } else { |
| 4346 | 4343 | err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); |
| ... | ... | @@ -4410,21 +4407,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const |
| 4410 | 4407 | } |
| 4411 | 4408 | |
| 4412 | 4409 | static void generate_error_name_table(CodeGen *g) { |
| 4413 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { | |
| 4410 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) { | |
| 4414 | 4411 | return; |
| 4415 | 4412 | } |
| 4416 | 4413 | |
| 4417 | assert(g->error_decls.length > 0); | |
| 4414 | assert(g->errors_by_index.length > 0); | |
| 4418 | 4415 | |
| 4419 | 4416 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| 4420 | 4417 | TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type); |
| 4421 | 4418 | |
| 4422 | LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length); | |
| 4419 | LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length); | |
| 4423 | 4420 | values[0] = LLVMGetUndef(str_type->type_ref); |
| 4424 | for (size_t i = 1; i < g->error_decls.length; i += 1) { | |
| 4425 | AstNode *error_decl_node = g->error_decls.at(i); | |
| 4426 | assert(error_decl_node->type == NodeTypeErrorValueDecl); | |
| 4427 | Buf *name = error_decl_node->data.error_value_decl.name; | |
| 4421 | for (size_t i = 1; i < g->errors_by_index.length; i += 1) { | |
| 4422 | ErrorTableEntry *err_entry = g->errors_by_index.at(i); | |
| 4423 | Buf *name = &err_entry->name; | |
| 4428 | 4424 | |
| 4429 | 4425 | g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); |
| 4430 | 4426 | |
| ... | ... | @@ -4443,7 +4439,7 @@ static void generate_error_name_table(CodeGen *g) { |
| 4443 | 4439 | values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); |
| 4444 | 4440 | } |
| 4445 | 4441 | |
| 4446 | LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length); | |
| 4442 | LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->errors_by_index.length); | |
| 4447 | 4443 | |
| 4448 | 4444 | g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), |
| 4449 | 4445 | buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false))); |
| ... | ... | @@ -4573,6 +4569,28 @@ static void validate_inline_fns(CodeGen *g) { |
| 4573 | 4569 | static void do_code_gen(CodeGen *g) { |
| 4574 | 4570 | assert(!g->errors.length); |
| 4575 | 4571 | |
| 4572 | { | |
| 4573 | // create debug type for error sets | |
| 4574 | assert(g->err_enumerators.length == g->errors_by_index.length); | |
| 4575 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref); | |
| 4576 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref); | |
| 4577 | ZigLLVMDIFile *err_set_di_file = nullptr; | |
| 4578 | ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 4579 | ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name), | |
| 4580 | err_set_di_file, 0, | |
| 4581 | tag_debug_size_in_bits, | |
| 4582 | tag_debug_align_in_bits, | |
| 4583 | g->err_enumerators.items, g->err_enumerators.length, | |
| 4584 | g->err_tag_type->di_type, ""); | |
| 4585 | ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type); | |
| 4586 | g->builtin_types.entry_global_error_set->di_type = err_set_di_type; | |
| 4587 | ||
| 4588 | for (size_t i = 0; i < g->error_di_types.length; i += 1) { | |
| 4589 | ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i); | |
| 4590 | *di_type_ptr = err_set_di_type; | |
| 4591 | } | |
| 4592 | } | |
| 4593 | ||
| 4576 | 4594 | codegen_add_time_event(g, "Code Generation"); |
| 4577 | 4595 | |
| 4578 | 4596 | generate_error_name_table(g); |
| ... | ... | @@ -5176,16 +5194,23 @@ static void define_builtin_types(CodeGen *g) { |
| 5176 | 5194 | } |
| 5177 | 5195 | |
| 5178 | 5196 | { |
| 5179 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); | |
| 5197 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet); | |
| 5180 | 5198 | buf_init_from_str(&entry->name, "error"); |
| 5181 | 5199 | |
| 5182 | 5200 | // TODO allow overriding this type and keep track of max value and emit an |
| 5183 | 5201 | // error if there are too many errors declared |
| 5184 | 5202 | g->err_tag_type = g->builtin_types.entry_u16; |
| 5185 | 5203 | |
| 5186 | g->builtin_types.entry_pure_error = entry; | |
| 5204 | g->builtin_types.entry_global_error_set = entry; | |
| 5187 | 5205 | entry->type_ref = g->err_tag_type->type_ref; |
| 5188 | entry->di_type = g->err_tag_type->di_type; | |
| 5206 | ||
| 5207 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | |
| 5208 | ZigLLVMTag_DW_enumeration_type(), "error", | |
| 5209 | ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0); | |
| 5210 | ||
| 5211 | // reserve index 0 to indicate no error | |
| 5212 | g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0)); | |
| 5213 | g->errors_by_index.append(nullptr); | |
| 5189 | 5214 | |
| 5190 | 5215 | g->primitive_type_table.put(&entry->name, entry); |
| 5191 | 5216 | } |
| ... | ... | @@ -5815,7 +5840,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry |
| 5815 | 5840 | case TypeTableEntryIdBoundFn: |
| 5816 | 5841 | case TypeTableEntryIdArgTuple: |
| 5817 | 5842 | case TypeTableEntryIdErrorUnion: |
| 5818 | case TypeTableEntryIdPureError: | |
| 5843 | case TypeTableEntryIdErrorSet: | |
| 5819 | 5844 | zig_unreachable(); |
| 5820 | 5845 | case TypeTableEntryIdVoid: |
| 5821 | 5846 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -5988,7 +6013,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf |
| 5988 | 6013 | return; |
| 5989 | 6014 | } |
| 5990 | 6015 | case TypeTableEntryIdErrorUnion: |
| 5991 | case TypeTableEntryIdPureError: | |
| 6016 | case TypeTableEntryIdErrorSet: | |
| 5992 | 6017 | case TypeTableEntryIdFn: |
| 5993 | 6018 | zig_panic("TODO implement get_c_type for more types"); |
| 5994 | 6019 | case TypeTableEntryIdInvalid: |
| ... | ... | @@ -6155,7 +6180,7 @@ static void gen_h_file(CodeGen *g) { |
| 6155 | 6180 | case TypeTableEntryIdUndefLit: |
| 6156 | 6181 | case TypeTableEntryIdNullLit: |
| 6157 | 6182 | case TypeTableEntryIdErrorUnion: |
| 6158 | case TypeTableEntryIdPureError: | |
| 6183 | case TypeTableEntryIdErrorSet: | |
| 6159 | 6184 | case TypeTableEntryIdNamespace: |
| 6160 | 6185 | case TypeTableEntryIdBlock: |
| 6161 | 6186 | case TypeTableEntryIdBoundFn: |
src/ir.cpp+533-163| ... | ... | @@ -580,6 +580,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace |
| 580 | 580 | return IrInstructionIdErrorReturnTrace; |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) { | |
| 584 | return IrInstructionIdErrorUnion; | |
| 585 | } | |
| 586 | ||
| 583 | 587 | template<typename T> |
| 584 | 588 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 585 | 589 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2326,6 +2330,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, |
| 2326 | 2330 | return &instruction->base; |
| 2327 | 2331 | } |
| 2328 | 2332 | |
| 2333 | static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2334 | IrInstruction *err_set, IrInstruction *payload) | |
| 2335 | { | |
| 2336 | IrInstructionErrorUnion *instruction = ir_build_instruction<IrInstructionErrorUnion>(irb, scope, source_node); | |
| 2337 | instruction->err_set = err_set; | |
| 2338 | instruction->payload = payload; | |
| 2339 | ||
| 2340 | ir_ref_instruction(err_set, irb->current_basic_block); | |
| 2341 | ir_ref_instruction(payload, irb->current_basic_block); | |
| 2342 | ||
| 2343 | return &instruction->base; | |
| 2344 | } | |
| 2345 | ||
| 2329 | 2346 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2330 | 2347 | results[ReturnKindUnconditional] = 0; |
| 2331 | 2348 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2800,6 +2817,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As |
| 2800 | 2817 | return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); |
| 2801 | 2818 | } |
| 2802 | 2819 | |
| 2820 | static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | |
| 2821 | assert(node->type == NodeTypeBinOpExpr); | |
| 2822 | ||
| 2823 | AstNode *op1_node = node->data.bin_op_expr.op1; | |
| 2824 | AstNode *op2_node = node->data.bin_op_expr.op2; | |
| 2825 | ||
| 2826 | IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope); | |
| 2827 | if (err_set == irb->codegen->invalid_instruction) | |
| 2828 | return irb->codegen->invalid_instruction; | |
| 2829 | ||
| 2830 | IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope); | |
| 2831 | if (payload == irb->codegen->invalid_instruction) | |
| 2832 | return irb->codegen->invalid_instruction; | |
| 2833 | ||
| 2834 | return ir_build_error_union(irb, parent_scope, node, err_set, payload); | |
| 2835 | } | |
| 2836 | ||
| 2803 | 2837 | static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 2804 | 2838 | assert(node->type == NodeTypeBinOpExpr); |
| 2805 | 2839 | |
| ... | ... | @@ -2887,6 +2921,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) |
| 2887 | 2921 | return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); |
| 2888 | 2922 | case BinOpTypeUnwrapMaybe: |
| 2889 | 2923 | return ir_gen_maybe_ok_or(irb, scope, node); |
| 2924 | case BinOpTypeErrorUnion: | |
| 2925 | return ir_gen_error_union(irb, scope, node); | |
| 2890 | 2926 | } |
| 2891 | 2927 | zig_unreachable(); |
| 2892 | 2928 | } |
| ... | ... | @@ -3990,8 +4026,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod |
| 3990 | 4026 | return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval); |
| 3991 | 4027 | case PrefixOpMaybe: |
| 3992 | 4028 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval); |
| 3993 | case PrefixOpError: | |
| 3994 | return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval); | |
| 3995 | 4029 | case PrefixOpUnwrapMaybe: |
| 3996 | 4030 | return ir_gen_maybe_assert_ok(irb, scope, node, lval); |
| 3997 | 4031 | } |
| ... | ... | @@ -5165,7 +5199,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast |
| 5165 | 5199 | |
| 5166 | 5200 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5167 | 5201 | assert(node->type == NodeTypeErrorType); |
| 5168 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_pure_error); | |
| 5202 | return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set); | |
| 5169 | 5203 | } |
| 5170 | 5204 | |
| 5171 | 5205 | static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| ... | ... | @@ -5249,8 +5283,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 5249 | 5283 | Scope *err_scope; |
| 5250 | 5284 | if (var_node) { |
| 5251 | 5285 | assert(var_node->type == NodeTypeSymbol); |
| 5252 | IrInstruction *var_type = ir_build_const_type(irb, parent_scope, node, | |
| 5253 | irb->codegen->builtin_types.entry_pure_error); | |
| 5254 | 5286 | Buf *var_name = var_node->data.symbol_expr.symbol; |
| 5255 | 5287 | bool is_const = true; |
| 5256 | 5288 | bool is_shadowable = false; |
| ... | ... | @@ -5258,7 +5290,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN |
| 5258 | 5290 | is_const, is_const, is_shadowable, is_comptime); |
| 5259 | 5291 | err_scope = var->child_scope; |
| 5260 | 5292 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); |
| 5261 | ir_build_var_decl(irb, err_scope, var_node, var, var_type, nullptr, err_val); | |
| 5293 | ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val); | |
| 5262 | 5294 | } else { |
| 5263 | 5295 | err_scope = parent_scope; |
| 5264 | 5296 | } |
| ... | ... | @@ -5348,6 +5380,70 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, |
| 5348 | 5380 | return ir_build_const_type(irb, parent_scope, node, container_type); |
| 5349 | 5381 | } |
| 5350 | 5382 | |
| 5383 | static TypeTableEntry *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node, | |
| 5384 | ErrorTableEntry *err_entry) | |
| 5385 | { | |
| 5386 | TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet); | |
| 5387 | buf_resize(&err_set_type->name, 0); | |
| 5388 | buf_appendf(&err_set_type->name, "@typeOf(error.%s)", buf_ptr(&err_entry->name)); | |
| 5389 | err_set_type->is_copyable = true; | |
| 5390 | err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref; | |
| 5391 | err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type; | |
| 5392 | err_set_type->data.error_set.err_count = 1; | |
| 5393 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1); | |
| 5394 | ||
| 5395 | g->error_di_types.append(&err_set_type->di_type); | |
| 5396 | ||
| 5397 | err_set_type->data.error_set.errors[0] = err_entry; | |
| 5398 | ||
| 5399 | return err_set_type; | |
| 5400 | } | |
| 5401 | ||
| 5402 | static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | |
| 5403 | assert(node->type == NodeTypeErrorSetDecl); | |
| 5404 | ||
| 5405 | uint32_t err_count = node->data.err_set_decl.decls.length; | |
| 5406 | ||
| 5407 | if (err_count == 0) { | |
| 5408 | add_node_error(irb->codegen, node, buf_sprintf("empty error set")); | |
| 5409 | return irb->codegen->invalid_instruction; | |
| 5410 | } | |
| 5411 | ||
| 5412 | Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node); | |
| 5413 | TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet); | |
| 5414 | buf_init_from_buf(&err_set_type->name, type_name); | |
| 5415 | err_set_type->is_copyable = true; | |
| 5416 | err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref; | |
| 5417 | err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type; | |
| 5418 | err_set_type->data.error_set.err_count = err_count; | |
| 5419 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); | |
| 5420 | ||
| 5421 | irb->codegen->error_di_types.append(&err_set_type->di_type); | |
| 5422 | ||
| 5423 | for (uint32_t i = 0; i < err_count; i += 1) { | |
| 5424 | AstNode *symbol_node = node->data.err_set_decl.decls.at(i); | |
| 5425 | assert(symbol_node->type == NodeTypeSymbol); | |
| 5426 | Buf *err_name = symbol_node->data.symbol_expr.symbol; | |
| 5427 | ErrorTableEntry *err = allocate<ErrorTableEntry>(1); | |
| 5428 | err->decl_node = symbol_node; | |
| 5429 | buf_init_from_buf(&err->name, err_name); | |
| 5430 | ||
| 5431 | auto existing_entry = irb->codegen->error_table.put_unique(err_name, err); | |
| 5432 | if (existing_entry) { | |
| 5433 | err->value = existing_entry->value->value; | |
| 5434 | } else { | |
| 5435 | size_t error_value_count = irb->codegen->errors_by_index.length; | |
| 5436 | assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count)); | |
| 5437 | err->value = error_value_count; | |
| 5438 | irb->codegen->errors_by_index.append(err); | |
| 5439 | irb->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(irb->codegen->dbuilder, | |
| 5440 | buf_ptr(err_name), error_value_count)); | |
| 5441 | } | |
| 5442 | err_set_type->data.error_set.errors[i] = err; | |
| 5443 | } | |
| 5444 | return ir_build_const_type(irb, parent_scope, node, err_set_type); | |
| 5445 | } | |
| 5446 | ||
| 5351 | 5447 | static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 5352 | 5448 | assert(node->type == NodeTypeFnProto); |
| 5353 | 5449 | |
| ... | ... | @@ -5401,7 +5497,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5401 | 5497 | case NodeTypeStructField: |
| 5402 | 5498 | case NodeTypeFnDef: |
| 5403 | 5499 | case NodeTypeFnDecl: |
| 5404 | case NodeTypeErrorValueDecl: | |
| 5405 | 5500 | case NodeTypeTestDecl: |
| 5406 | 5501 | zig_unreachable(); |
| 5407 | 5502 | case NodeTypeBlock: |
| ... | ... | @@ -5482,6 +5577,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 5482 | 5577 | return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); |
| 5483 | 5578 | case NodeTypeFnProto: |
| 5484 | 5579 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); |
| 5580 | case NodeTypeErrorSetDecl: | |
| 5581 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); | |
| 5485 | 5582 | } |
| 5486 | 5583 | zig_unreachable(); |
| 5487 | 5584 | } |
| ... | ... | @@ -6301,25 +6398,32 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 6301 | 6398 | return ImplicitCastMatchResultYes; |
| 6302 | 6399 | } |
| 6303 | 6400 | |
| 6304 | // implicit T to %T | |
| 6401 | // implicit T to U!T | |
| 6305 | 6402 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6306 | ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value)) | |
| 6403 | ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value)) | |
| 6307 | 6404 | { |
| 6308 | 6405 | return ImplicitCastMatchResultYes; |
| 6309 | 6406 | } |
| 6310 | 6407 | |
| 6311 | // implicit conversion from pure error to error union type | |
| 6408 | // implicit conversion from error set to error union type | |
| 6312 | 6409 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6313 | actual_type->id == TypeTableEntryIdPureError) | |
| 6410 | actual_type->id == TypeTableEntryIdErrorSet) | |
| 6411 | { | |
| 6412 | return ImplicitCastMatchResultYes; | |
| 6413 | } | |
| 6414 | ||
| 6415 | // implicit conversion from error set to another error set | |
| 6416 | if (expected_type->id == TypeTableEntryIdErrorSet && | |
| 6417 | actual_type->id == TypeTableEntryIdErrorSet) | |
| 6314 | 6418 | { |
| 6315 | 6419 | return ImplicitCastMatchResultYes; |
| 6316 | 6420 | } |
| 6317 | 6421 | |
| 6318 | // implicit conversion from T to %?T | |
| 6422 | // implicit conversion from T to U!?T | |
| 6319 | 6423 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| 6320 | expected_type->data.error.child_type->id == TypeTableEntryIdMaybe && | |
| 6424 | expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && | |
| 6321 | 6425 | ir_types_match_with_implicit_cast(ira, |
| 6322 | expected_type->data.error.child_type->data.maybe.child_type, | |
| 6426 | expected_type->data.error_union.payload_type->data.maybe.child_type, | |
| 6323 | 6427 | actual_type, value)) |
| 6324 | 6428 | { |
| 6325 | 6429 | return ImplicitCastMatchResultYes; |
| ... | ... | @@ -6503,7 +6607,19 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6503 | 6607 | if (type_is_invalid(prev_inst->value.type)) { |
| 6504 | 6608 | return ira->codegen->builtin_types.entry_invalid; |
| 6505 | 6609 | } |
| 6506 | bool any_are_pure_error = (prev_inst->value.type->id == TypeTableEntryIdPureError); | |
| 6610 | ErrorTableEntry **errors = nullptr; | |
| 6611 | TypeTableEntry *err_set_type = nullptr; | |
| 6612 | if (prev_inst->value.type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 6613 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | |
| 6614 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) { | |
| 6615 | err_set_type = prev_inst->value.type; | |
| 6616 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | |
| 6617 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6618 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | |
| 6619 | errors[error_entry->value] = error_entry; | |
| 6620 | } | |
| 6621 | } | |
| 6622 | ||
| 6507 | 6623 | bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit); |
| 6508 | 6624 | bool convert_to_const_slice = false; |
| 6509 | 6625 | for (size_t i = 1; i < instruction_count; i += 1) { |
| ... | ... | @@ -6524,27 +6640,133 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6524 | 6640 | continue; |
| 6525 | 6641 | } |
| 6526 | 6642 | |
| 6527 | if (prev_type->id == TypeTableEntryIdPureError) { | |
| 6643 | if (prev_type->id == TypeTableEntryIdNullLit) { | |
| 6528 | 6644 | prev_inst = cur_inst; |
| 6529 | 6645 | continue; |
| 6530 | 6646 | } |
| 6531 | 6647 | |
| 6532 | if (prev_type->id == TypeTableEntryIdNullLit) { | |
| 6533 | prev_inst = cur_inst; | |
| 6648 | if (cur_type->id == TypeTableEntryIdNullLit) { | |
| 6649 | any_are_null = true; | |
| 6534 | 6650 | continue; |
| 6535 | 6651 | } |
| 6536 | 6652 | |
| 6537 | if (cur_type->id == TypeTableEntryIdPureError) { | |
| 6538 | if (prev_type->id == TypeTableEntryIdArray) { | |
| 6539 | convert_to_const_slice = true; | |
| 6653 | if (prev_type->id == TypeTableEntryIdErrorSet) { | |
| 6654 | assert(err_set_type != nullptr); | |
| 6655 | if (cur_type->id == TypeTableEntryIdErrorSet) { | |
| 6656 | if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 6657 | continue; | |
| 6658 | } | |
| 6659 | if (cur_type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 6660 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | |
| 6661 | prev_inst = cur_inst; | |
| 6662 | continue; | |
| 6663 | } | |
| 6664 | // if err_set_type is a superset of cur_type, keep err_set_type. | |
| 6665 | // if cur_type is a superset of err_set_type, switch err_set_type to cur_type | |
| 6666 | // otherwise emit a compile error | |
| 6667 | bool prev_is_superset = true; | |
| 6668 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | |
| 6669 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | |
| 6670 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | |
| 6671 | if (error_entry == nullptr) { | |
| 6672 | prev_is_superset = false; | |
| 6673 | break; | |
| 6674 | } | |
| 6675 | } | |
| 6676 | if (prev_is_superset) { | |
| 6677 | continue; | |
| 6678 | } | |
| 6679 | ||
| 6680 | // unset everything in errors | |
| 6681 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6682 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | |
| 6683 | errors[error_entry->value] = nullptr; | |
| 6684 | } | |
| 6685 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | |
| 6686 | ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i]; | |
| 6687 | errors[error_entry->value] = error_entry; | |
| 6688 | } | |
| 6689 | bool cur_is_superset = true; | |
| 6690 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6691 | ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; | |
| 6692 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | |
| 6693 | if (error_entry == nullptr) { | |
| 6694 | cur_is_superset = false; | |
| 6695 | break; | |
| 6696 | } | |
| 6697 | } | |
| 6698 | if (cur_is_superset) { | |
| 6699 | err_set_type = cur_inst->value.type; | |
| 6700 | prev_inst = cur_inst; | |
| 6701 | continue; | |
| 6702 | } | |
| 6703 | } else if (cur_type->id == TypeTableEntryIdErrorUnion) { | |
| 6704 | // err_set_type must be a subset of cur_type's error set | |
| 6705 | // unset everything in errors | |
| 6706 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6707 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | |
| 6708 | errors[error_entry->value] = nullptr; | |
| 6709 | } | |
| 6710 | TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type; | |
| 6711 | for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { | |
| 6712 | ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; | |
| 6713 | errors[error_entry->value] = error_entry; | |
| 6714 | } | |
| 6715 | bool cur_is_superset = true; | |
| 6716 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6717 | ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; | |
| 6718 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | |
| 6719 | if (error_entry == nullptr) { | |
| 6720 | cur_is_superset = false; | |
| 6721 | break; | |
| 6722 | } | |
| 6723 | } | |
| 6724 | if (cur_is_superset) { | |
| 6725 | err_set_type = cur_err_set_type; | |
| 6726 | prev_inst = cur_inst; | |
| 6727 | continue; | |
| 6728 | } | |
| 6729 | } else { | |
| 6730 | prev_inst = cur_inst; | |
| 6731 | continue; | |
| 6540 | 6732 | } |
| 6541 | any_are_pure_error = true; | |
| 6542 | continue; | |
| 6543 | 6733 | } |
| 6544 | 6734 | |
| 6545 | if (cur_type->id == TypeTableEntryIdNullLit) { | |
| 6546 | any_are_null = true; | |
| 6547 | continue; | |
| 6735 | if (cur_type->id == TypeTableEntryIdErrorSet) { | |
| 6736 | if (prev_type->id == TypeTableEntryIdArray) { | |
| 6737 | convert_to_const_slice = true; | |
| 6738 | } | |
| 6739 | if (cur_type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 6740 | err_set_type = ira->codegen->builtin_types.entry_global_error_set; | |
| 6741 | continue; | |
| 6742 | } | |
| 6743 | if (err_set_type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 6744 | continue; | |
| 6745 | } | |
| 6746 | if (err_set_type == nullptr) { | |
| 6747 | err_set_type = cur_type; | |
| 6748 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | |
| 6749 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 6750 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | |
| 6751 | errors[error_entry->value] = error_entry; | |
| 6752 | } | |
| 6753 | continue; | |
| 6754 | } | |
| 6755 | if (prev_type->id == TypeTableEntryIdErrorUnion) { | |
| 6756 | // the cur type error set must be a subset | |
| 6757 | bool prev_is_superset = true; | |
| 6758 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | |
| 6759 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | |
| 6760 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | |
| 6761 | if (error_entry == nullptr) { | |
| 6762 | prev_is_superset = false; | |
| 6763 | break; | |
| 6764 | } | |
| 6765 | } | |
| 6766 | if (prev_is_superset) { | |
| 6767 | continue; | |
| 6768 | } | |
| 6769 | } | |
| 6548 | 6770 | } |
| 6549 | 6771 | |
| 6550 | 6772 | if (types_match_const_cast_only(prev_type, cur_type)) { |
| ... | ... | @@ -6574,20 +6796,20 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6574 | 6796 | } |
| 6575 | 6797 | |
| 6576 | 6798 | if (prev_type->id == TypeTableEntryIdErrorUnion && |
| 6577 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) | |
| 6799 | types_match_const_cast_only(prev_type->data.error_union.payload_type, cur_type)) | |
| 6578 | 6800 | { |
| 6579 | 6801 | continue; |
| 6580 | 6802 | } |
| 6581 | 6803 | |
| 6582 | 6804 | if (cur_type->id == TypeTableEntryIdErrorUnion && |
| 6583 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) | |
| 6805 | types_match_const_cast_only(cur_type->data.error_union.payload_type, prev_type)) | |
| 6584 | 6806 | { |
| 6585 | 6807 | prev_inst = cur_inst; |
| 6586 | 6808 | continue; |
| 6587 | 6809 | } |
| 6588 | 6810 | |
| 6589 | 6811 | if (prev_type->id == TypeTableEntryIdMaybe && |
| 6590 | types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type)) | |
| 6812 | types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type)) | |
| 6591 | 6813 | { |
| 6592 | 6814 | continue; |
| 6593 | 6815 | } |
| ... | ... | @@ -6700,16 +6922,19 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6700 | 6922 | |
| 6701 | 6923 | return ira->codegen->builtin_types.entry_invalid; |
| 6702 | 6924 | } |
| 6925 | ||
| 6926 | free(errors); | |
| 6927 | ||
| 6703 | 6928 | if (convert_to_const_slice) { |
| 6704 | 6929 | assert(prev_inst->value.type->id == TypeTableEntryIdArray); |
| 6705 | 6930 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true); |
| 6706 | 6931 | TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type); |
| 6707 | if (any_are_pure_error) { | |
| 6708 | return get_error_type(ira->codegen, slice_type); | |
| 6932 | if (err_set_type != nullptr) { | |
| 6933 | return get_error_union_type(ira->codegen, err_set_type, slice_type); | |
| 6709 | 6934 | } else { |
| 6710 | 6935 | return slice_type; |
| 6711 | 6936 | } |
| 6712 | } else if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) { | |
| 6937 | } else if (err_set_type != nullptr && prev_inst->value.type->id != TypeTableEntryIdErrorSet) { | |
| 6713 | 6938 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || |
| 6714 | 6939 | prev_inst->value.type->id == TypeTableEntryIdNumLitFloat) |
| 6715 | 6940 | { |
| ... | ... | @@ -6723,7 +6948,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 6723 | 6948 | } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) { |
| 6724 | 6949 | return prev_inst->value.type; |
| 6725 | 6950 | } else { |
| 6726 | return get_error_type(ira->codegen, prev_inst->value.type); | |
| 6951 | return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type); | |
| 6727 | 6952 | } |
| 6728 | 6953 | } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) { |
| 6729 | 6954 | if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt || |
| ... | ... | @@ -7199,7 +7424,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 7199 | 7424 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); |
| 7200 | 7425 | |
| 7201 | 7426 | if (instr_is_comptime(value)) { |
| 7202 | TypeTableEntry *payload_type = wanted_type->data.error.child_type; | |
| 7427 | TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type; | |
| 7203 | 7428 | IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type); |
| 7204 | 7429 | if (type_is_invalid(casted_payload->value.type)) |
| 7205 | 7430 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -7224,8 +7449,43 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction |
| 7224 | 7449 | return result; |
| 7225 | 7450 | } |
| 7226 | 7451 | |
| 7227 | static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { | |
| 7228 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | |
| 7452 | static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, | |
| 7453 | TypeTableEntry *wanted_type) | |
| 7454 | { | |
| 7455 | TypeTableEntry *contained_set = value->value.type; | |
| 7456 | TypeTableEntry *container_set = wanted_type; | |
| 7457 | ||
| 7458 | assert(contained_set->id == TypeTableEntryIdErrorSet); | |
| 7459 | assert(container_set->id == TypeTableEntryIdErrorSet); | |
| 7460 | ||
| 7461 | if (container_set->data.error_set.infer_fn == nullptr && | |
| 7462 | container_set != ira->codegen->builtin_types.entry_global_error_set) | |
| 7463 | { | |
| 7464 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | |
| 7465 | for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { | |
| 7466 | ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; | |
| 7467 | errors[error_entry->value] = error_entry; | |
| 7468 | } | |
| 7469 | ErrorMsg *err_msg = nullptr; | |
| 7470 | for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) { | |
| 7471 | ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i]; | |
| 7472 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | |
| 7473 | if (error_entry == nullptr) { | |
| 7474 | if (err_msg == nullptr) { | |
| 7475 | err_msg = ir_add_error(ira, source_instr, | |
| 7476 | buf_sprintf("invalid cast of error set '%s' to error set '%s'", | |
| 7477 | buf_ptr(&contained_set->name), buf_ptr(&container_set->name))); | |
| 7478 | } | |
| 7479 | add_error_note(ira->codegen, err_msg, contained_error_entry->decl_node, | |
| 7480 | buf_sprintf("'%s.%s' not present in '%s'", buf_ptr(&contained_set->name), | |
| 7481 | buf_ptr(&contained_error_entry->name), buf_ptr(&container_set->name))); | |
| 7482 | } | |
| 7483 | } | |
| 7484 | free(errors); | |
| 7485 | if (err_msg != nullptr) { | |
| 7486 | return ira->codegen->invalid_instruction; | |
| 7487 | } | |
| 7488 | } | |
| 7229 | 7489 | |
| 7230 | 7490 | if (instr_is_comptime(value)) { |
| 7231 | 7491 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); |
| ... | ... | @@ -7236,7 +7496,30 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so |
| 7236 | 7496 | source_instr->scope, source_instr->source_node); |
| 7237 | 7497 | const_instruction->base.value.type = wanted_type; |
| 7238 | 7498 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 7239 | const_instruction->base.value.data.x_err_union.err = val->data.x_pure_err; | |
| 7499 | const_instruction->base.value.data.x_err_set = val->data.x_err_set; | |
| 7500 | return &const_instruction->base; | |
| 7501 | } | |
| 7502 | ||
| 7503 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpNoop); | |
| 7504 | result->value.type = wanted_type; | |
| 7505 | return result; | |
| 7506 | } | |
| 7507 | ||
| 7508 | static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { | |
| 7509 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | |
| 7510 | ||
| 7511 | IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); | |
| 7512 | ||
| 7513 | if (instr_is_comptime(casted_value)) { | |
| 7514 | ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 7515 | if (!val) | |
| 7516 | return ira->codegen->invalid_instruction; | |
| 7517 | ||
| 7518 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | |
| 7519 | source_instr->scope, source_instr->source_node); | |
| 7520 | const_instruction->base.value.type = wanted_type; | |
| 7521 | const_instruction->base.value.special = ConstValSpecialStatic; | |
| 7522 | const_instruction->base.value.data.x_err_union.err = val->data.x_err_set; | |
| 7240 | 7523 | const_instruction->base.value.data.x_err_union.payload = nullptr; |
| 7241 | 7524 | return &const_instruction->base; |
| 7242 | 7525 | } |
| ... | ... | @@ -7616,9 +7899,12 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction |
| 7616 | 7899 | return result; |
| 7617 | 7900 | } |
| 7618 | 7901 | |
| 7619 | static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) { | |
| 7902 | static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, | |
| 7903 | TypeTableEntry *wanted_type) | |
| 7904 | { | |
| 7620 | 7905 | assert(target->value.type->id == TypeTableEntryIdInt); |
| 7621 | 7906 | assert(!target->value.type->data.integral.is_signed); |
| 7907 | assert(wanted_type->id == TypeTableEntryIdErrorSet); | |
| 7622 | 7908 | |
| 7623 | 7909 | if (instr_is_comptime(target)) { |
| 7624 | 7910 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| ... | ... | @@ -7626,10 +7912,10 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 7626 | 7912 | return ira->codegen->invalid_instruction; |
| 7627 | 7913 | |
| 7628 | 7914 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 7629 | source_instr->source_node, ira->codegen->builtin_types.entry_pure_error); | |
| 7915 | source_instr->source_node, wanted_type); | |
| 7630 | 7916 | |
| 7631 | 7917 | BigInt err_count; |
| 7632 | bigint_init_unsigned(&err_count, ira->codegen->error_decls.length); | |
| 7918 | bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length); | |
| 7633 | 7919 | if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { |
| 7634 | 7920 | Buf *val_buf = buf_alloc(); |
| 7635 | 7921 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); |
| ... | ... | @@ -7639,13 +7925,12 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 7639 | 7925 | } |
| 7640 | 7926 | |
| 7641 | 7927 | size_t index = bigint_as_unsigned(&val->data.x_bigint); |
| 7642 | AstNode *error_decl_node = ira->codegen->error_decls.at(index); | |
| 7643 | result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err; | |
| 7928 | result->value.data.x_err_set = ira->codegen->errors_by_index.at(index); | |
| 7644 | 7929 | return result; |
| 7645 | 7930 | } |
| 7646 | 7931 | |
| 7647 | 7932 | IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target); |
| 7648 | result->value.type = ira->codegen->builtin_types.entry_pure_error; | |
| 7933 | result->value.type = wanted_type; | |
| 7649 | 7934 | return result; |
| 7650 | 7935 | } |
| 7651 | 7936 | |
| ... | ... | @@ -7667,8 +7952,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7667 | 7952 | ErrorTableEntry *err; |
| 7668 | 7953 | if (err_type->id == TypeTableEntryIdErrorUnion) { |
| 7669 | 7954 | err = val->data.x_err_union.err; |
| 7670 | } else if (err_type->id == TypeTableEntryIdPureError) { | |
| 7671 | err = val->data.x_pure_err; | |
| 7955 | } else if (err_type->id == TypeTableEntryIdErrorSet) { | |
| 7956 | err = val->data.x_err_set; | |
| 7672 | 7957 | } else { |
| 7673 | 7958 | zig_unreachable(); |
| 7674 | 7959 | } |
| ... | ... | @@ -7689,7 +7974,7 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc |
| 7689 | 7974 | } |
| 7690 | 7975 | |
| 7691 | 7976 | BigInt bn; |
| 7692 | bigint_init_unsigned(&bn, ira->codegen->error_decls.length); | |
| 7977 | bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); | |
| 7693 | 7978 | if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { |
| 7694 | 7979 | ir_add_error_node(ira, source_instr->source_node, |
| 7695 | 7980 | buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); |
| ... | ... | @@ -7734,6 +8019,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7734 | 8019 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); |
| 7735 | 8020 | } |
| 7736 | 8021 | |
| 8022 | // explicit error set cast | |
| 8023 | if (wanted_type->id == TypeTableEntryIdErrorSet && | |
| 8024 | actual_type->id == TypeTableEntryIdErrorSet) | |
| 8025 | { | |
| 8026 | return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type); | |
| 8027 | } | |
| 8028 | ||
| 7737 | 8029 | // explicit cast from int to float |
| 7738 | 8030 | if (wanted_type->id == TypeTableEntryIdFloat && |
| 7739 | 8031 | actual_type->id == TypeTableEntryIdInt) |
| ... | ... | @@ -7894,12 +8186,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7894 | 8186 | |
| 7895 | 8187 | // explicit cast from child type of error type to error type |
| 7896 | 8188 | if (wanted_type->id == TypeTableEntryIdErrorUnion) { |
| 7897 | if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) { | |
| 8189 | if (types_match_const_cast_only(wanted_type->data.error_union.payload_type, actual_type)) { | |
| 7898 | 8190 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); |
| 7899 | 8191 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || |
| 7900 | 8192 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| 7901 | 8193 | { |
| 7902 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) { | |
| 8194 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { | |
| 7903 | 8195 | return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); |
| 7904 | 8196 | } else { |
| 7905 | 8197 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -7909,16 +8201,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7909 | 8201 | |
| 7910 | 8202 | // explicit cast from [N]T to %[]const T |
| 7911 | 8203 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7912 | is_slice(wanted_type->data.error.child_type) && | |
| 8204 | is_slice(wanted_type->data.error_union.payload_type) && | |
| 7913 | 8205 | actual_type->id == TypeTableEntryIdArray) |
| 7914 | 8206 | { |
| 7915 | 8207 | TypeTableEntry *ptr_type = |
| 7916 | wanted_type->data.error.child_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 8208 | wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 7917 | 8209 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 7918 | 8210 | if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) && |
| 7919 | 8211 | types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type)) |
| 7920 | 8212 | { |
| 7921 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); | |
| 8213 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); | |
| 7922 | 8214 | if (type_is_invalid(cast1->value.type)) |
| 7923 | 8215 | return ira->codegen->invalid_instruction; |
| 7924 | 8216 | |
| ... | ... | @@ -7930,25 +8222,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 7930 | 8222 | } |
| 7931 | 8223 | } |
| 7932 | 8224 | |
| 7933 | // explicit cast from pure error to error union type | |
| 8225 | // explicit cast from error set to error union type | |
| 7934 | 8226 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7935 | actual_type->id == TypeTableEntryIdPureError) | |
| 8227 | actual_type->id == TypeTableEntryIdErrorSet) | |
| 7936 | 8228 | { |
| 7937 | 8229 | return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); |
| 7938 | 8230 | } |
| 7939 | 8231 | |
| 7940 | 8232 | // explicit cast from T to %?T |
| 7941 | 8233 | if (wanted_type->id == TypeTableEntryIdErrorUnion && |
| 7942 | wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe && | |
| 8234 | wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && | |
| 7943 | 8235 | actual_type->id != TypeTableEntryIdMaybe) |
| 7944 | 8236 | { |
| 7945 | TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type; | |
| 8237 | TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; | |
| 7946 | 8238 | if (types_match_const_cast_only(wanted_child_type, actual_type) || |
| 7947 | 8239 | actual_type->id == TypeTableEntryIdNullLit || |
| 7948 | 8240 | actual_type->id == TypeTableEntryIdNumLitInt || |
| 7949 | 8241 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| 7950 | 8242 | { |
| 7951 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); | |
| 8243 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); | |
| 7952 | 8244 | if (type_is_invalid(cast1->value.type)) |
| 7953 | 8245 | return ira->codegen->invalid_instruction; |
| 7954 | 8246 | |
| ... | ... | @@ -8017,21 +8309,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8017 | 8309 | return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); |
| 8018 | 8310 | } |
| 8019 | 8311 | |
| 8020 | // explicit cast from %void to integer type which can fit it | |
| 8312 | // explicit cast from T!void to integer type which can fit it | |
| 8021 | 8313 | bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion && |
| 8022 | !type_has_bits(actual_type->data.error.child_type); | |
| 8023 | bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError; | |
| 8024 | if ((actual_type_is_void_err || actual_type_is_pure_err) && | |
| 8025 | wanted_type->id == TypeTableEntryIdInt) | |
| 8026 | { | |
| 8314 | !type_has_bits(actual_type->data.error_union.payload_type); | |
| 8315 | bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet; | |
| 8316 | if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) { | |
| 8027 | 8317 | return ir_analyze_err_to_int(ira, source_instr, value, wanted_type); |
| 8028 | 8318 | } |
| 8029 | 8319 | |
| 8030 | // explicit cast from integer to pure error | |
| 8031 | if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt && | |
| 8320 | // explicit cast from integer to error set | |
| 8321 | if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt && | |
| 8032 | 8322 | !actual_type->data.integral.is_signed) |
| 8033 | 8323 | { |
| 8034 | return ir_analyze_int_to_err(ira, source_instr, value); | |
| 8324 | return ir_analyze_int_to_err(ira, source_instr, value, wanted_type); | |
| 8035 | 8325 | } |
| 8036 | 8326 | |
| 8037 | 8327 | // explicit cast from integer to enum type with no payload |
| ... | ... | @@ -8524,7 +8814,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 8524 | 8814 | case TypeTableEntryIdMetaType: |
| 8525 | 8815 | case TypeTableEntryIdVoid: |
| 8526 | 8816 | case TypeTableEntryIdPointer: |
| 8527 | case TypeTableEntryIdPureError: | |
| 8817 | case TypeTableEntryIdErrorSet: | |
| 8528 | 8818 | case TypeTableEntryIdFn: |
| 8529 | 8819 | case TypeTableEntryIdOpaque: |
| 8530 | 8820 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -9312,7 +9602,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { |
| 9312 | 9602 | case TypeTableEntryIdInt: |
| 9313 | 9603 | case TypeTableEntryIdFloat: |
| 9314 | 9604 | case TypeTableEntryIdVoid: |
| 9315 | case TypeTableEntryIdPureError: | |
| 9605 | case TypeTableEntryIdErrorSet: | |
| 9316 | 9606 | case TypeTableEntryIdFn: |
| 9317 | 9607 | return VarClassRequiredAny; |
| 9318 | 9608 | case TypeTableEntryIdNumLitFloat: |
| ... | ... | @@ -9338,7 +9628,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { |
| 9338 | 9628 | case TypeTableEntryIdMaybe: |
| 9339 | 9629 | return get_var_class_required(type_entry->data.maybe.child_type); |
| 9340 | 9630 | case TypeTableEntryIdErrorUnion: |
| 9341 | return get_var_class_required(type_entry->data.error.child_type); | |
| 9631 | return get_var_class_required(type_entry->data.error_union.payload_type); | |
| 9342 | 9632 | |
| 9343 | 9633 | case TypeTableEntryIdStruct: |
| 9344 | 9634 | case TypeTableEntryIdEnum: |
| ... | ... | @@ -9573,7 +9863,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 9573 | 9863 | case TypeTableEntryIdNullLit: |
| 9574 | 9864 | case TypeTableEntryIdMaybe: |
| 9575 | 9865 | case TypeTableEntryIdErrorUnion: |
| 9576 | case TypeTableEntryIdPureError: | |
| 9866 | case TypeTableEntryIdErrorSet: | |
| 9577 | 9867 | case TypeTableEntryIdNamespace: |
| 9578 | 9868 | case TypeTableEntryIdBlock: |
| 9579 | 9869 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -9596,7 +9886,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi |
| 9596 | 9886 | case TypeTableEntryIdNullLit: |
| 9597 | 9887 | case TypeTableEntryIdMaybe: |
| 9598 | 9888 | case TypeTableEntryIdErrorUnion: |
| 9599 | case TypeTableEntryIdPureError: | |
| 9889 | case TypeTableEntryIdErrorSet: | |
| 9600 | 9890 | zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); |
| 9601 | 9891 | case TypeTableEntryIdNamespace: |
| 9602 | 9892 | case TypeTableEntryIdBlock: |
| ... | ... | @@ -9630,6 +9920,24 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 9630 | 9920 | return nullable_type; |
| 9631 | 9921 | } |
| 9632 | 9922 | |
| 9923 | static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira, | |
| 9924 | IrInstructionErrorUnion *instruction) | |
| 9925 | { | |
| 9926 | TypeTableEntry *err_set_type = ir_resolve_type(ira, instruction->err_set->other); | |
| 9927 | if (type_is_invalid(err_set_type)) | |
| 9928 | return ira->codegen->builtin_types.entry_invalid; | |
| 9929 | ||
| 9930 | TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload->other); | |
| 9931 | if (type_is_invalid(payload_type)) | |
| 9932 | return ira->codegen->builtin_types.entry_invalid; | |
| 9933 | ||
| 9934 | TypeTableEntry *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | |
| 9935 | ||
| 9936 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 9937 | out_val->data.x_type = result_type; | |
| 9938 | return ira->codegen->builtin_types.entry_type; | |
| 9939 | } | |
| 9940 | ||
| 9633 | 9941 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 9634 | 9942 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| 9635 | 9943 | { |
| ... | ... | @@ -10114,7 +10422,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10114 | 10422 | TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; |
| 10115 | 10423 | ir_add_alloca(ira, new_call_instruction, return_type); |
| 10116 | 10424 | |
| 10117 | if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10425 | if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10118 | 10426 | parent_fn_entry->calls_errorable_function = true; |
| 10119 | 10427 | } |
| 10120 | 10428 | |
| ... | ... | @@ -10124,7 +10432,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10124 | 10432 | FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 10125 | 10433 | assert(fn_type_id->return_type != nullptr); |
| 10126 | 10434 | assert(parent_fn_entry != nullptr); |
| 10127 | if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10435 | if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) { | |
| 10128 | 10436 | parent_fn_entry->calls_errorable_function = true; |
| 10129 | 10437 | } |
| 10130 | 10438 | |
| ... | ... | @@ -10243,58 +10551,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 10243 | 10551 | } |
| 10244 | 10552 | } |
| 10245 | 10553 | |
| 10246 | static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { | |
| 10247 | assert(un_op_instruction->op_id == IrUnOpError); | |
| 10248 | IrInstruction *value = un_op_instruction->value->other; | |
| 10249 | ||
| 10250 | TypeTableEntry *meta_type = ir_resolve_type(ira, value); | |
| 10251 | if (type_is_invalid(meta_type)) | |
| 10252 | return ira->codegen->builtin_types.entry_invalid; | |
| 10253 | ||
| 10254 | ||
| 10255 | switch (meta_type->id) { | |
| 10256 | case TypeTableEntryIdInvalid: // handled above | |
| 10257 | zig_unreachable(); | |
| 10258 | ||
| 10259 | case TypeTableEntryIdVoid: | |
| 10260 | case TypeTableEntryIdBool: | |
| 10261 | case TypeTableEntryIdInt: | |
| 10262 | case TypeTableEntryIdFloat: | |
| 10263 | case TypeTableEntryIdPointer: | |
| 10264 | case TypeTableEntryIdArray: | |
| 10265 | case TypeTableEntryIdStruct: | |
| 10266 | case TypeTableEntryIdMaybe: | |
| 10267 | case TypeTableEntryIdErrorUnion: | |
| 10268 | case TypeTableEntryIdPureError: | |
| 10269 | case TypeTableEntryIdEnum: | |
| 10270 | case TypeTableEntryIdUnion: | |
| 10271 | case TypeTableEntryIdFn: | |
| 10272 | case TypeTableEntryIdBoundFn: | |
| 10273 | { | |
| 10274 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); | |
| 10275 | TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type); | |
| 10276 | out_val->data.x_type = result_type; | |
| 10277 | return ira->codegen->builtin_types.entry_type; | |
| 10278 | } | |
| 10279 | case TypeTableEntryIdMetaType: | |
| 10280 | case TypeTableEntryIdNumLitFloat: | |
| 10281 | case TypeTableEntryIdNumLitInt: | |
| 10282 | case TypeTableEntryIdUndefLit: | |
| 10283 | case TypeTableEntryIdNullLit: | |
| 10284 | case TypeTableEntryIdNamespace: | |
| 10285 | case TypeTableEntryIdBlock: | |
| 10286 | case TypeTableEntryIdUnreachable: | |
| 10287 | case TypeTableEntryIdVar: | |
| 10288 | case TypeTableEntryIdArgTuple: | |
| 10289 | case TypeTableEntryIdOpaque: | |
| 10290 | ir_add_error_node(ira, un_op_instruction->base.source_node, | |
| 10291 | buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name))); | |
| 10292 | return ira->codegen->builtin_types.entry_invalid; | |
| 10293 | } | |
| 10294 | zig_unreachable(); | |
| 10295 | } | |
| 10296 | ||
| 10297 | ||
| 10298 | 10554 | static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 10299 | 10555 | IrInstruction *value = un_op_instruction->value->other; |
| 10300 | 10556 | |
| ... | ... | @@ -10350,7 +10606,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op |
| 10350 | 10606 | case TypeTableEntryIdNullLit: |
| 10351 | 10607 | case TypeTableEntryIdMaybe: |
| 10352 | 10608 | case TypeTableEntryIdErrorUnion: |
| 10353 | case TypeTableEntryIdPureError: | |
| 10609 | case TypeTableEntryIdErrorSet: | |
| 10354 | 10610 | case TypeTableEntryIdEnum: |
| 10355 | 10611 | case TypeTableEntryIdUnion: |
| 10356 | 10612 | case TypeTableEntryIdFn: |
| ... | ... | @@ -10460,8 +10716,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio |
| 10460 | 10716 | return ir_analyze_dereference(ira, un_op_instruction); |
| 10461 | 10717 | case IrUnOpMaybe: |
| 10462 | 10718 | return ir_analyze_maybe(ira, un_op_instruction); |
| 10463 | case IrUnOpError: | |
| 10464 | return ir_analyze_unary_prefix_op_err(ira, un_op_instruction); | |
| 10465 | 10719 | } |
| 10466 | 10720 | zig_unreachable(); |
| 10467 | 10721 | } |
| ... | ... | @@ -11083,6 +11337,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 11083 | 11337 | zig_unreachable(); |
| 11084 | 11338 | } |
| 11085 | 11339 | |
| 11340 | static ErrorTableEntry *find_err_table_entry(TypeTableEntry *err_set_type, Buf *field_name) { | |
| 11341 | assert(err_set_type->id == TypeTableEntryIdErrorSet); | |
| 11342 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | |
| 11343 | ErrorTableEntry *err_table_entry = err_set_type->data.error_set.errors[i]; | |
| 11344 | if (buf_eql_buf(&err_table_entry->name, field_name)) { | |
| 11345 | return err_table_entry; | |
| 11346 | } | |
| 11347 | } | |
| 11348 | return nullptr; | |
| 11349 | } | |
| 11350 | ||
| 11086 | 11351 | static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { |
| 11087 | 11352 | IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; |
| 11088 | 11353 | if (type_is_invalid(container_ptr->value.type)) |
| ... | ... | @@ -11224,23 +11489,49 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11224 | 11489 | buf_sprintf("container '%s' has no member called '%s'", |
| 11225 | 11490 | buf_ptr(&child_type->name), buf_ptr(field_name))); |
| 11226 | 11491 | return ira->codegen->builtin_types.entry_invalid; |
| 11227 | } else if (child_type->id == TypeTableEntryIdPureError) { | |
| 11228 | auto err_table_entry = ira->codegen->error_table.maybe_get(field_name); | |
| 11229 | if (err_table_entry) { | |
| 11230 | ConstExprValue *const_val = create_const_vals(1); | |
| 11231 | const_val->special = ConstValSpecialStatic; | |
| 11232 | const_val->type = child_type; | |
| 11233 | const_val->data.x_pure_err = err_table_entry->value; | |
| 11234 | ||
| 11235 | bool ptr_is_const = true; | |
| 11236 | bool ptr_is_volatile = false; | |
| 11237 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, | |
| 11238 | child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11492 | } else if (child_type->id == TypeTableEntryIdErrorSet) { | |
| 11493 | ErrorTableEntry *err_entry; | |
| 11494 | TypeTableEntry *err_set_type; | |
| 11495 | if (child_type == ira->codegen->builtin_types.entry_global_error_set) { | |
| 11496 | auto existing_entry = ira->codegen->error_table.maybe_get(field_name); | |
| 11497 | if (existing_entry) { | |
| 11498 | err_entry = existing_entry->value; | |
| 11499 | } else { | |
| 11500 | err_entry = allocate<ErrorTableEntry>(1); | |
| 11501 | err_entry->decl_node = field_ptr_instruction->base.source_node; | |
| 11502 | buf_init_from_buf(&err_entry->name, field_name); | |
| 11503 | size_t error_value_count = ira->codegen->errors_by_index.length; | |
| 11504 | assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); | |
| 11505 | err_entry->value = error_value_count; | |
| 11506 | ira->codegen->errors_by_index.append(err_entry); | |
| 11507 | ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder, | |
| 11508 | buf_ptr(field_name), error_value_count)); | |
| 11509 | ira->codegen->error_table.put(field_name, err_entry); | |
| 11510 | } | |
| 11511 | if (err_entry->set_with_only_this_in_it == nullptr) { | |
| 11512 | err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen, | |
| 11513 | field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, | |
| 11514 | err_entry); | |
| 11515 | } | |
| 11516 | err_set_type = err_entry->set_with_only_this_in_it; | |
| 11517 | } else { | |
| 11518 | ErrorTableEntry *err_entry = find_err_table_entry(child_type, field_name); | |
| 11519 | if (err_entry == nullptr) { | |
| 11520 | ir_add_error(ira, &field_ptr_instruction->base, | |
| 11521 | buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name))); | |
| 11522 | return ira->codegen->builtin_types.entry_invalid; | |
| 11523 | } | |
| 11524 | err_set_type = child_type; | |
| 11239 | 11525 | } |
| 11526 | ConstExprValue *const_val = create_const_vals(1); | |
| 11527 | const_val->special = ConstValSpecialStatic; | |
| 11528 | const_val->type = err_set_type; | |
| 11529 | const_val->data.x_err_set = err_entry; | |
| 11240 | 11530 | |
| 11241 | ir_add_error(ira, &field_ptr_instruction->base, | |
| 11242 | buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name))); | |
| 11243 | return ira->codegen->builtin_types.entry_invalid; | |
| 11531 | bool ptr_is_const = true; | |
| 11532 | bool ptr_is_volatile = false; | |
| 11533 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, | |
| 11534 | err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11244 | 11535 | } else if (child_type->id == TypeTableEntryIdInt) { |
| 11245 | 11536 | if (buf_eql_str(field_name, "bit_count")) { |
| 11246 | 11537 | bool ptr_is_const = true; |
| ... | ... | @@ -11323,11 +11614,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11323 | 11614 | return ira->codegen->builtin_types.entry_invalid; |
| 11324 | 11615 | } |
| 11325 | 11616 | } else if (child_type->id == TypeTableEntryIdErrorUnion) { |
| 11326 | if (buf_eql_str(field_name, "Child")) { | |
| 11617 | if (buf_eql_str(field_name, "Payload")) { | |
| 11618 | bool ptr_is_const = true; | |
| 11619 | bool ptr_is_volatile = false; | |
| 11620 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11621 | create_const_type(ira->codegen, child_type->data.error_union.payload_type), | |
| 11622 | ira->codegen->builtin_types.entry_type, | |
| 11623 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11624 | } else if (buf_eql_str(field_name, "ErrorSet")) { | |
| 11327 | 11625 | bool ptr_is_const = true; |
| 11328 | 11626 | bool ptr_is_volatile = false; |
| 11329 | 11627 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, |
| 11330 | create_const_type(ira->codegen, child_type->data.error.child_type), | |
| 11628 | create_const_type(ira->codegen, child_type->data.error_union.err_set_type), | |
| 11331 | 11629 | ira->codegen->builtin_types.entry_type, |
| 11332 | 11630 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); |
| 11333 | 11631 | } else { |
| ... | ... | @@ -11514,7 +11812,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 11514 | 11812 | case TypeTableEntryIdStruct: |
| 11515 | 11813 | case TypeTableEntryIdMaybe: |
| 11516 | 11814 | case TypeTableEntryIdErrorUnion: |
| 11517 | case TypeTableEntryIdPureError: | |
| 11815 | case TypeTableEntryIdErrorSet: | |
| 11518 | 11816 | case TypeTableEntryIdEnum: |
| 11519 | 11817 | case TypeTableEntryIdUnion: |
| 11520 | 11818 | case TypeTableEntryIdFn: |
| ... | ... | @@ -11781,7 +12079,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 11781 | 12079 | case TypeTableEntryIdNumLitInt: |
| 11782 | 12080 | case TypeTableEntryIdMaybe: |
| 11783 | 12081 | case TypeTableEntryIdErrorUnion: |
| 11784 | case TypeTableEntryIdPureError: | |
| 12082 | case TypeTableEntryIdErrorSet: | |
| 11785 | 12083 | case TypeTableEntryIdEnum: |
| 11786 | 12084 | case TypeTableEntryIdUnion: |
| 11787 | 12085 | case TypeTableEntryIdFn: |
| ... | ... | @@ -11889,7 +12187,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 11889 | 12187 | case TypeTableEntryIdNumLitInt: |
| 11890 | 12188 | case TypeTableEntryIdMaybe: |
| 11891 | 12189 | case TypeTableEntryIdErrorUnion: |
| 11892 | case TypeTableEntryIdPureError: | |
| 12190 | case TypeTableEntryIdErrorSet: | |
| 11893 | 12191 | case TypeTableEntryIdEnum: |
| 11894 | 12192 | case TypeTableEntryIdUnion: |
| 11895 | 12193 | case TypeTableEntryIdFn: |
| ... | ... | @@ -11942,7 +12240,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 11942 | 12240 | case TypeTableEntryIdStruct: |
| 11943 | 12241 | case TypeTableEntryIdMaybe: |
| 11944 | 12242 | case TypeTableEntryIdErrorUnion: |
| 11945 | case TypeTableEntryIdPureError: | |
| 12243 | case TypeTableEntryIdErrorSet: | |
| 11946 | 12244 | case TypeTableEntryIdEnum: |
| 11947 | 12245 | case TypeTableEntryIdUnion: |
| 11948 | 12246 | case TypeTableEntryIdFn: |
| ... | ... | @@ -12277,7 +12575,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12277 | 12575 | case TypeTableEntryIdPointer: |
| 12278 | 12576 | case TypeTableEntryIdFn: |
| 12279 | 12577 | case TypeTableEntryIdNamespace: |
| 12280 | case TypeTableEntryIdPureError: | |
| 12578 | case TypeTableEntryIdErrorSet: | |
| 12281 | 12579 | if (pointee_val) { |
| 12282 | 12580 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); |
| 12283 | 12581 | copy_const_val(out_val, pointee_val, true); |
| ... | ... | @@ -12347,8 +12645,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12347 | 12645 | return target_type; |
| 12348 | 12646 | } |
| 12349 | 12647 | case TypeTableEntryIdErrorUnion: |
| 12350 | // see https://github.com/andrewrk/zig/issues/632 | |
| 12351 | zig_panic("TODO switch on error union"); | |
| 12352 | 12648 | case TypeTableEntryIdUnreachable: |
| 12353 | 12649 | case TypeTableEntryIdArray: |
| 12354 | 12650 | case TypeTableEntryIdStruct: |
| ... | ... | @@ -12873,7 +13169,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 12873 | 13169 | case TypeTableEntryIdNullLit: |
| 12874 | 13170 | case TypeTableEntryIdMaybe: |
| 12875 | 13171 | case TypeTableEntryIdErrorUnion: |
| 12876 | case TypeTableEntryIdPureError: | |
| 13172 | case TypeTableEntryIdErrorSet: | |
| 12877 | 13173 | case TypeTableEntryIdUnion: |
| 12878 | 13174 | case TypeTableEntryIdFn: |
| 12879 | 13175 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -12961,7 +13257,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc |
| 12961 | 13257 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); |
| 12962 | 13258 | TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 12963 | 13259 | if (casted_value->value.special == ConstValSpecialStatic) { |
| 12964 | ErrorTableEntry *err = casted_value->value.data.x_pure_err; | |
| 13260 | ErrorTableEntry *err = casted_value->value.data.x_err_set; | |
| 12965 | 13261 | if (!err->cached_error_name_val) { |
| 12966 | 13262 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); |
| 12967 | 13263 | err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true); |
| ... | ... | @@ -14106,7 +14402,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc |
| 14106 | 14402 | case TypeTableEntryIdStruct: |
| 14107 | 14403 | case TypeTableEntryIdMaybe: |
| 14108 | 14404 | case TypeTableEntryIdErrorUnion: |
| 14109 | case TypeTableEntryIdPureError: | |
| 14405 | case TypeTableEntryIdErrorSet: | |
| 14110 | 14406 | case TypeTableEntryIdEnum: |
| 14111 | 14407 | case TypeTableEntryIdUnion: |
| 14112 | 14408 | case TypeTableEntryIdFn: |
| ... | ... | @@ -14239,7 +14535,7 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc |
| 14239 | 14535 | |
| 14240 | 14536 | ir_build_test_err_from(&ira->new_irb, &instruction->base, value); |
| 14241 | 14537 | return ira->codegen->builtin_types.entry_bool; |
| 14242 | } else if (type_entry->id == TypeTableEntryIdPureError) { | |
| 14538 | } else if (type_entry->id == TypeTableEntryIdErrorSet) { | |
| 14243 | 14539 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14244 | 14540 | out_val->data.x_bool = true; |
| 14245 | 14541 | return ira->codegen->builtin_types.entry_bool; |
| ... | ... | @@ -14275,13 +14571,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, |
| 14275 | 14571 | assert(err); |
| 14276 | 14572 | |
| 14277 | 14573 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14278 | out_val->data.x_pure_err = err; | |
| 14279 | return ira->codegen->builtin_types.entry_pure_error; | |
| 14574 | out_val->data.x_err_set = err; | |
| 14575 | return type_entry->data.error_union.err_set_type; | |
| 14280 | 14576 | } |
| 14281 | 14577 | } |
| 14282 | 14578 | |
| 14283 | 14579 | ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value); |
| 14284 | return ira->codegen->builtin_types.entry_pure_error; | |
| 14580 | return type_entry->data.error_union.err_set_type; | |
| 14285 | 14581 | } else { |
| 14286 | 14582 | ir_add_error(ira, value, |
| 14287 | 14583 | buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); |
| ... | ... | @@ -14305,10 +14601,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| 14305 | 14601 | if (type_is_invalid(type_entry)) { |
| 14306 | 14602 | return ira->codegen->builtin_types.entry_invalid; |
| 14307 | 14603 | } else if (type_entry->id == TypeTableEntryIdErrorUnion) { |
| 14308 | TypeTableEntry *child_type = type_entry->data.error.child_type; | |
| 14309 | TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type, | |
| 14604 | TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; | |
| 14605 | TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, | |
| 14310 | 14606 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 14311 | get_abi_alignment(ira->codegen, child_type), 0, 0); | |
| 14607 | get_abi_alignment(ira->codegen, payload_type), 0, 0); | |
| 14312 | 14608 | if (instr_is_comptime(value)) { |
| 14313 | 14609 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); |
| 14314 | 14610 | if (!ptr_val) |
| ... | ... | @@ -14343,6 +14639,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc |
| 14343 | 14639 | AstNode *proto_node = instruction->base.source_node; |
| 14344 | 14640 | assert(proto_node->type == NodeTypeFnProto); |
| 14345 | 14641 | |
| 14642 | if (proto_node->data.fn_proto.auto_err_set) { | |
| 14643 | ir_add_error(ira, &instruction->base, | |
| 14644 | buf_sprintf("inferring error set of return type valid only for function definitions")); | |
| 14645 | return ira->codegen->builtin_types.entry_invalid; | |
| 14646 | } | |
| 14647 | ||
| 14346 | 14648 | FnTypeId fn_type_id = {0}; |
| 14347 | 14649 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); |
| 14348 | 14650 | |
| ... | ... | @@ -14468,6 +14770,71 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 14468 | 14770 | } |
| 14469 | 14771 | } |
| 14470 | 14772 | } |
| 14773 | } else if (switch_type->id == TypeTableEntryIdErrorSet) { | |
| 14774 | FnTableEntry *infer_fn = switch_type->data.error_set.infer_fn; | |
| 14775 | if (infer_fn != nullptr) { | |
| 14776 | if (infer_fn->anal_state == FnAnalStateInvalid) { | |
| 14777 | return ira->codegen->builtin_types.entry_invalid; | |
| 14778 | } else if (infer_fn->anal_state == FnAnalStateReady) { | |
| 14779 | analyze_fn_body(ira->codegen, infer_fn); | |
| 14780 | if (switch_type->data.error_set.infer_fn != nullptr) { | |
| 14781 | assert(ira->codegen->errors.length != 0); | |
| 14782 | return ira->codegen->builtin_types.entry_invalid; | |
| 14783 | } | |
| 14784 | } else { | |
| 14785 | ir_add_error(ira, &instruction->base, | |
| 14786 | buf_sprintf("cannot switch on inferred error set '%s': function '%s' not fully analyzed yet", | |
| 14787 | buf_ptr(&switch_type->name), buf_ptr(&switch_type->data.error_set.infer_fn->symbol_name))); | |
| 14788 | return ira->codegen->builtin_types.entry_invalid; | |
| 14789 | } | |
| 14790 | } | |
| 14791 | ||
| 14792 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); | |
| 14793 | ||
| 14794 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | |
| 14795 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; | |
| 14796 | ||
| 14797 | IrInstruction *start_value = range->start->other; | |
| 14798 | if (type_is_invalid(start_value->value.type)) | |
| 14799 | return ira->codegen->builtin_types.entry_invalid; | |
| 14800 | ||
| 14801 | IrInstruction *end_value = range->end->other; | |
| 14802 | if (type_is_invalid(end_value->value.type)) | |
| 14803 | return ira->codegen->builtin_types.entry_invalid; | |
| 14804 | ||
| 14805 | assert(start_value->value.type->id == TypeTableEntryIdErrorSet); | |
| 14806 | uint32_t start_index = start_value->value.data.x_err_set->value; | |
| 14807 | ||
| 14808 | assert(end_value->value.type->id == TypeTableEntryIdErrorSet); | |
| 14809 | uint32_t end_index = end_value->value.data.x_err_set->value; | |
| 14810 | ||
| 14811 | if (start_index != end_index) { | |
| 14812 | ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors")); | |
| 14813 | return ira->codegen->builtin_types.entry_invalid; | |
| 14814 | } | |
| 14815 | ||
| 14816 | AstNode *prev_node = field_prev_uses[start_index]; | |
| 14817 | if (prev_node != nullptr) { | |
| 14818 | Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name; | |
| 14819 | ErrorMsg *msg = ir_add_error(ira, start_value, | |
| 14820 | buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name))); | |
| 14821 | add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here")); | |
| 14822 | } | |
| 14823 | field_prev_uses[start_index] = start_value->source_node; | |
| 14824 | } | |
| 14825 | if (!instruction->have_else_prong) { | |
| 14826 | for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { | |
| 14827 | ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; | |
| 14828 | ||
| 14829 | AstNode *prev_node = field_prev_uses[err_entry->value]; | |
| 14830 | if (prev_node == nullptr) { | |
| 14831 | ir_add_error(ira, &instruction->base, | |
| 14832 | buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); | |
| 14833 | } | |
| 14834 | } | |
| 14835 | } | |
| 14836 | ||
| 14837 | free(field_prev_uses); | |
| 14471 | 14838 | } else if (switch_type->id == TypeTableEntryIdInt) { |
| 14472 | 14839 | RangeSet rs = {0}; |
| 14473 | 14840 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| ... | ... | @@ -14760,7 +15127,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 14760 | 15127 | zig_panic("TODO buf_write_value_bytes maybe type"); |
| 14761 | 15128 | case TypeTableEntryIdErrorUnion: |
| 14762 | 15129 | zig_panic("TODO buf_write_value_bytes error union"); |
| 14763 | case TypeTableEntryIdPureError: | |
| 15130 | case TypeTableEntryIdErrorSet: | |
| 14764 | 15131 | zig_panic("TODO buf_write_value_bytes pure error type"); |
| 14765 | 15132 | case TypeTableEntryIdEnum: |
| 14766 | 15133 | zig_panic("TODO buf_write_value_bytes enum type"); |
| ... | ... | @@ -14818,7 +15185,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 14818 | 15185 | zig_panic("TODO buf_read_value_bytes maybe type"); |
| 14819 | 15186 | case TypeTableEntryIdErrorUnion: |
| 14820 | 15187 | zig_panic("TODO buf_read_value_bytes error union"); |
| 14821 | case TypeTableEntryIdPureError: | |
| 15188 | case TypeTableEntryIdErrorSet: | |
| 14822 | 15189 | zig_panic("TODO buf_read_value_bytes pure error type"); |
| 14823 | 15190 | case TypeTableEntryIdEnum: |
| 14824 | 15191 | zig_panic("TODO buf_read_value_bytes enum type"); |
| ... | ... | @@ -15429,6 +15796,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15429 | 15796 | return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); |
| 15430 | 15797 | case IrInstructionIdErrorReturnTrace: |
| 15431 | 15798 | return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); |
| 15799 | case IrInstructionIdErrorUnion: | |
| 15800 | return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction); | |
| 15432 | 15801 | } |
| 15433 | 15802 | zig_unreachable(); |
| 15434 | 15803 | } |
| ... | ... | @@ -15614,6 +15983,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15614 | 15983 | case IrInstructionIdArgType: |
| 15615 | 15984 | case IrInstructionIdTagType: |
| 15616 | 15985 | case IrInstructionIdErrorReturnTrace: |
| 15986 | case IrInstructionIdErrorUnion: | |
| 15617 | 15987 | return false; |
| 15618 | 15988 | case IrInstructionIdAsm: |
| 15619 | 15989 | { |
src/ir_print.cpp+8-2| ... | ... | @@ -148,8 +148,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { |
| 148 | 148 | return "*"; |
| 149 | 149 | case IrUnOpMaybe: |
| 150 | 150 | return "?"; |
| 151 | case IrUnOpError: | |
| 152 | return "%"; | |
| 153 | 151 | } |
| 154 | 152 | zig_unreachable(); |
| 155 | 153 | } |
| ... | ... | @@ -1004,6 +1002,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr |
| 1004 | 1002 | fprintf(irp->f, "@errorReturnTrace()"); |
| 1005 | 1003 | } |
| 1006 | 1004 | |
| 1005 | static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) { | |
| 1006 | ir_print_other_instruction(irp, instruction->err_set); | |
| 1007 | fprintf(irp->f, "!"); | |
| 1008 | ir_print_other_instruction(irp, instruction->payload); | |
| 1009 | } | |
| 1007 | 1010 | |
| 1008 | 1011 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1009 | 1012 | ir_print_prefix(irp, instruction); |
| ... | ... | @@ -1322,6 +1325,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1322 | 1325 | case IrInstructionIdErrorReturnTrace: |
| 1323 | 1326 | ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction); |
| 1324 | 1327 | break; |
| 1328 | case IrInstructionIdErrorUnion: | |
| 1329 | ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction); | |
| 1330 | break; | |
| 1325 | 1331 | } |
| 1326 | 1332 | fprintf(irp->f, "\n"); |
| 1327 | 1333 | } |
src/parser.cpp+50-37| ... | ... | @@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo |
| 221 | 221 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); |
| 222 | 222 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory); |
| 223 | 223 | static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index); |
| 224 | static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index); | |
| 224 | 225 | |
| 225 | 226 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| 226 | 227 | if (token->id == token_id) { |
| ... | ... | @@ -651,8 +652,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b |
| 651 | 652 | } |
| 652 | 653 | |
| 653 | 654 | /* |
| 654 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol)) | |
| 655 | PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | |
| 655 | 656 | KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" |
| 657 | ErrorSetDecl = "error" "{" list(Symbol, ",") "}" | |
| 656 | 658 | */ |
| 657 | 659 | static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 658 | 660 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -716,9 +718,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo |
| 716 | 718 | *token_index += 1; |
| 717 | 719 | return node; |
| 718 | 720 | } else if (token->id == TokenIdKeywordError) { |
| 719 | AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); | |
| 720 | *token_index += 1; | |
| 721 | return node; | |
| 721 | Token *next_token = &pc->tokens->at(*token_index + 1); | |
| 722 | if (next_token->id == TokenIdLBrace) { | |
| 723 | AstNode *node = ast_create_node(pc, NodeTypeErrorSetDecl, token); | |
| 724 | *token_index += 2; | |
| 725 | for (;;) { | |
| 726 | Token *item_tok = &pc->tokens->at(*token_index); | |
| 727 | if (item_tok->id == TokenIdRBrace) { | |
| 728 | *token_index += 1; | |
| 729 | return node; | |
| 730 | } else if (item_tok->id == TokenIdSymbol) { | |
| 731 | AstNode *symbol_node = ast_parse_symbol(pc, token_index); | |
| 732 | node->data.err_set_decl.decls.append(symbol_node); | |
| 733 | Token *opt_comma_tok = &pc->tokens->at(*token_index); | |
| 734 | if (opt_comma_tok->id == TokenIdComma) { | |
| 735 | *token_index += 1; | |
| 736 | } | |
| 737 | } else { | |
| 738 | ast_invalid_token_error(pc, item_tok); | |
| 739 | } | |
| 740 | } | |
| 741 | } else { | |
| 742 | AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); | |
| 743 | *token_index += 1; | |
| 744 | return node; | |
| 745 | } | |
| 722 | 746 | } else if (token->id == TokenIdAtSign) { |
| 723 | 747 | *token_index += 1; |
| 724 | 748 | Token *name_tok = &pc->tokens->at(*token_index); |
| ... | ... | @@ -950,7 +974,6 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 950 | 974 | case TokenIdTilde: return PrefixOpBinNot; |
| 951 | 975 | case TokenIdStar: return PrefixOpDereference; |
| 952 | 976 | case TokenIdMaybe: return PrefixOpMaybe; |
| 953 | case TokenIdPercent: return PrefixOpError; | |
| 954 | 977 | case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe; |
| 955 | 978 | case TokenIdStarStar: return PrefixOpDereference; |
| 956 | 979 | default: return PrefixOpInvalid; |
| ... | ... | @@ -998,7 +1021,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) { |
| 998 | 1021 | |
| 999 | 1022 | /* |
| 1000 | 1023 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression |
| 1001 | PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | "try" | |
| 1024 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | |
| 1002 | 1025 | */ |
| 1003 | 1026 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1004 | 1027 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1043,12 +1066,13 @@ static BinOpType tok_to_mult_op(Token *token) { |
| 1043 | 1066 | case TokenIdStarStar: return BinOpTypeArrayMult; |
| 1044 | 1067 | case TokenIdSlash: return BinOpTypeDiv; |
| 1045 | 1068 | case TokenIdPercent: return BinOpTypeMod; |
| 1069 | case TokenIdBang: return BinOpTypeErrorUnion; | |
| 1046 | 1070 | default: return BinOpTypeInvalid; |
| 1047 | 1071 | } |
| 1048 | 1072 | } |
| 1049 | 1073 | |
| 1050 | 1074 | /* |
| 1051 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | |
| 1075 | MultiplyOperator = "!" | "*" | "/" | "%" | "**" | "*%" | |
| 1052 | 1076 | */ |
| 1053 | 1077 | static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 1054 | 1078 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2240,7 +2264,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand |
| 2240 | 2264 | } |
| 2241 | 2265 | |
| 2242 | 2266 | /* |
| 2243 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr | |
| 2267 | FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr | |
| 2244 | 2268 | */ |
| 2245 | 2269 | static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { |
| 2246 | 2270 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2315,6 +2339,21 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m |
| 2315 | 2339 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2316 | 2340 | next_token = &pc->tokens->at(*token_index); |
| 2317 | 2341 | } |
| 2342 | if (next_token->id == TokenIdKeywordError) { | |
| 2343 | Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1); | |
| 2344 | if (maybe_lbrace_tok->id == TokenIdLBrace) { | |
| 2345 | *token_index += 1; | |
| 2346 | node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token); | |
| 2347 | return node; | |
| 2348 | } | |
| 2349 | ||
| 2350 | return node; | |
| 2351 | } | |
| 2352 | if (next_token->id == TokenIdBang) { | |
| 2353 | *token_index += 1; | |
| 2354 | node->data.fn_proto.auto_err_set = true; | |
| 2355 | next_token = &pc->tokens->at(*token_index); | |
| 2356 | } | |
| 2318 | 2357 | node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true); |
| 2319 | 2358 | |
| 2320 | 2359 | return node; |
| ... | ... | @@ -2559,26 +2598,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2559 | 2598 | return node; |
| 2560 | 2599 | } |
| 2561 | 2600 | |
| 2562 | /* | |
| 2563 | ErrorValueDecl : "error" "Symbol" ";" | |
| 2564 | */ | |
| 2565 | static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index) { | |
| 2566 | Token *first_token = &pc->tokens->at(*token_index); | |
| 2567 | ||
| 2568 | if (first_token->id != TokenIdKeywordError) { | |
| 2569 | return nullptr; | |
| 2570 | } | |
| 2571 | *token_index += 1; | |
| 2572 | ||
| 2573 | Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 2574 | ast_eat_token(pc, token_index, TokenIdSemicolon); | |
| 2575 | ||
| 2576 | AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token); | |
| 2577 | node->data.error_value_decl.name = token_buf(name_tok); | |
| 2578 | ||
| 2579 | return node; | |
| 2580 | } | |
| 2581 | ||
| 2582 | 2601 | /* |
| 2583 | 2602 | TestDecl = "test" String Block |
| 2584 | 2603 | */ |
| ... | ... | @@ -2611,12 +2630,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig |
| 2611 | 2630 | continue; |
| 2612 | 2631 | } |
| 2613 | 2632 | |
| 2614 | AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index); | |
| 2615 | if (error_value_node) { | |
| 2616 | top_level_decls->append(error_value_node); | |
| 2617 | continue; | |
| 2618 | } | |
| 2619 | ||
| 2620 | 2633 | AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index); |
| 2621 | 2634 | if (test_decl_node) { |
| 2622 | 2635 | top_level_decls->append(test_decl_node); |
| ... | ... | @@ -2744,9 +2757,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2744 | 2757 | visit_field(&node->data.variable_declaration.align_expr, visit, context); |
| 2745 | 2758 | visit_field(&node->data.variable_declaration.section_expr, visit, context); |
| 2746 | 2759 | break; |
| 2747 | case NodeTypeErrorValueDecl: | |
| 2748 | // none | |
| 2749 | break; | |
| 2750 | 2760 | case NodeTypeTestDecl: |
| 2751 | 2761 | visit_field(&node->data.test_decl.body, visit, context); |
| 2752 | 2762 | break; |
| ... | ... | @@ -2899,5 +2909,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2899 | 2909 | visit_field(&node->data.addr_of_expr.align_expr, visit, context); |
| 2900 | 2910 | visit_field(&node->data.addr_of_expr.op_expr, visit, context); |
| 2901 | 2911 | break; |
| 2912 | case NodeTypeErrorSetDecl: | |
| 2913 | visit_node_list(&node->data.err_set_decl.decls, visit, context); | |
| 2914 | break; | |
| 2902 | 2915 | } |
| 2903 | 2916 | } |
src/zig_llvm.cpp+4| ... | ... | @@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 437 | 437 | return dwarf::DW_TAG_structure_type; |
| 438 | 438 | } |
| 439 | 439 | |
| 440 | unsigned ZigLLVMTag_DW_enumeration_type(void) { | |
| 441 | return dwarf::DW_TAG_enumeration_type; | |
| 442 | } | |
| 443 | ||
| 440 | 444 | unsigned ZigLLVMTag_DW_union_type(void) { |
| 441 | 445 | return dwarf::DW_TAG_union_type; |
| 442 | 446 | } |
src/zig_llvm.h+1| ... | ... | @@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 133 | 133 | ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 134 | 134 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void); |
| 135 | 135 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void); |
| 136 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void); | |
| 136 | 137 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); |
| 137 | 138 | |
| 138 | 139 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
std/debug/index.zig+34-46| ... | ... | @@ -10,15 +10,6 @@ const builtin = @import("builtin"); |
| 10 | 10 | |
| 11 | 11 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; |
| 12 | 12 | |
| 13 | error MissingDebugInfo; | |
| 14 | error InvalidDebugInfo; | |
| 15 | error UnsupportedDebugInfo; | |
| 16 | error UnknownObjectFormat; | |
| 17 | error TodoSupportCoffDebugInfo; | |
| 18 | error TodoSupportMachoDebugInfo; | |
| 19 | error TodoSupportCOFFDebugInfo; | |
| 20 | ||
| 21 | ||
| 22 | 13 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| 23 | 14 | /// Does not append a newline. |
| 24 | 15 | /// TODO atomic/multithread support |
| ... | ... | @@ -29,7 +20,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void { |
| 29 | 20 | const stderr = getStderrStream() catch return; |
| 30 | 21 | stderr.print(fmt, args) catch return; |
| 31 | 22 | } |
| 32 | fn getStderrStream() %&io.OutStream { | |
| 23 | fn getStderrStream() !&io.OutStream { | |
| 33 | 24 | if (stderr_stream) |st| { |
| 34 | 25 | return st; |
| 35 | 26 | } else { |
| ... | ... | @@ -42,7 +33,7 @@ fn getStderrStream() %&io.OutStream { |
| 42 | 33 | } |
| 43 | 34 | |
| 44 | 35 | var self_debug_info: ?&ElfStackTrace = null; |
| 45 | pub fn getSelfDebugInfo() %&ElfStackTrace { | |
| 36 | pub fn getSelfDebugInfo() !&ElfStackTrace { | |
| 46 | 37 | if (self_debug_info) |info| { |
| 47 | 38 | return info; |
| 48 | 39 | } else { |
| ... | ... | @@ -149,11 +140,8 @@ const WHITE = "\x1b[37;1m"; |
| 149 | 140 | const DIM = "\x1b[2m"; |
| 150 | 141 | const RESET = "\x1b[0m"; |
| 151 | 142 | |
| 152 | error PathNotFound; | |
| 153 | error InvalidDebugInfo; | |
| 154 | ||
| 155 | 143 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, |
| 156 | debug_info: &ElfStackTrace, tty_color: bool) %void | |
| 144 | debug_info: &ElfStackTrace, tty_color: bool) !void | |
| 157 | 145 | { |
| 158 | 146 | var frame_index: usize = undefined; |
| 159 | 147 | var frames_left: usize = undefined; |
| ... | ... | @@ -175,7 +163,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O |
| 175 | 163 | } |
| 176 | 164 | |
| 177 | 165 | pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, |
| 178 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) %void | |
| 166 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void | |
| 179 | 167 | { |
| 180 | 168 | var ignored_count: usize = 0; |
| 181 | 169 | |
| ... | ... | @@ -191,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat |
| 191 | 179 | } |
| 192 | 180 | } |
| 193 | 181 | |
| 194 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) %void { | |
| 182 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) !void { | |
| 195 | 183 | if (builtin.os == builtin.Os.windows) { |
| 196 | 184 | return error.UnsupportedDebugInfo; |
| 197 | 185 | } |
| ... | ... | @@ -232,7 +220,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a |
| 232 | 220 | } |
| 233 | 221 | } |
| 234 | 222 | |
| 235 | pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace { | |
| 223 | pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace { | |
| 236 | 224 | switch (builtin.object_format) { |
| 237 | 225 | builtin.ObjectFormat.elf => { |
| 238 | 226 | const st = try allocator.create(ElfStackTrace); |
| ... | ... | @@ -276,7 +264,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) %&ElfStackTrace { |
| 276 | 264 | } |
| 277 | 265 | } |
| 278 | 266 | |
| 279 | fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) %void { | |
| 267 | fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) !void { | |
| 280 | 268 | var f = try io.File.openRead(line_info.file_name, allocator); |
| 281 | 269 | defer f.close(); |
| 282 | 270 | // TODO fstat and make sure that the file has the correct size |
| ... | ... | @@ -324,7 +312,7 @@ pub const ElfStackTrace = struct { |
| 324 | 312 | return self.abbrev_table_list.allocator; |
| 325 | 313 | } |
| 326 | 314 | |
| 327 | pub fn readString(self: &ElfStackTrace) %[]u8 { | |
| 315 | pub fn readString(self: &ElfStackTrace) ![]u8 { | |
| 328 | 316 | var in_file_stream = io.FileInStream.init(&self.self_exe_file); |
| 329 | 317 | const in_stream = &in_file_stream.stream; |
| 330 | 318 | return readStringRaw(self.allocator(), in_stream); |
| ... | ... | @@ -387,7 +375,7 @@ const Constant = struct { |
| 387 | 375 | payload: []u8, |
| 388 | 376 | signed: bool, |
| 389 | 377 | |
| 390 | fn asUnsignedLe(self: &const Constant) %u64 { | |
| 378 | fn asUnsignedLe(self: &const Constant) !u64 { | |
| 391 | 379 | if (self.payload.len > @sizeOf(u64)) |
| 392 | 380 | return error.InvalidDebugInfo; |
| 393 | 381 | if (self.signed) |
| ... | ... | @@ -414,7 +402,7 @@ const Die = struct { |
| 414 | 402 | return null; |
| 415 | 403 | } |
| 416 | 404 | |
| 417 | fn getAttrAddr(self: &const Die, id: u64) %u64 { | |
| 405 | fn getAttrAddr(self: &const Die, id: u64) !u64 { | |
| 418 | 406 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 419 | 407 | return switch (*form_value) { |
| 420 | 408 | FormValue.Address => |value| value, |
| ... | ... | @@ -422,7 +410,7 @@ const Die = struct { |
| 422 | 410 | }; |
| 423 | 411 | } |
| 424 | 412 | |
| 425 | fn getAttrSecOffset(self: &const Die, id: u64) %u64 { | |
| 413 | fn getAttrSecOffset(self: &const Die, id: u64) !u64 { | |
| 426 | 414 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 427 | 415 | return switch (*form_value) { |
| 428 | 416 | FormValue.Const => |value| value.asUnsignedLe(), |
| ... | ... | @@ -431,7 +419,7 @@ const Die = struct { |
| 431 | 419 | }; |
| 432 | 420 | } |
| 433 | 421 | |
| 434 | fn getAttrUnsignedLe(self: &const Die, id: u64) %u64 { | |
| 422 | fn getAttrUnsignedLe(self: &const Die, id: u64) !u64 { | |
| 435 | 423 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 436 | 424 | return switch (*form_value) { |
| 437 | 425 | FormValue.Const => |value| value.asUnsignedLe(), |
| ... | ... | @@ -439,7 +427,7 @@ const Die = struct { |
| 439 | 427 | }; |
| 440 | 428 | } |
| 441 | 429 | |
| 442 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) %[]u8 { | |
| 430 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) ![]u8 { | |
| 443 | 431 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 444 | 432 | return switch (*form_value) { |
| 445 | 433 | FormValue.String => |value| value, |
| ... | ... | @@ -512,7 +500,7 @@ const LineNumberProgram = struct { |
| 512 | 500 | }; |
| 513 | 501 | } |
| 514 | 502 | |
| 515 | pub fn checkLineMatch(self: &LineNumberProgram) %?LineInfo { | |
| 503 | pub fn checkLineMatch(self: &LineNumberProgram) !?LineInfo { | |
| 516 | 504 | if (self.target_address >= self.prev_address and self.target_address < self.address) { |
| 517 | 505 | const file_entry = if (self.prev_file == 0) { |
| 518 | 506 | return error.MissingDebugInfo; |
| ... | ... | @@ -544,7 +532,7 @@ const LineNumberProgram = struct { |
| 544 | 532 | } |
| 545 | 533 | }; |
| 546 | 534 | |
| 547 | fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 { | |
| 535 | fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) ![]u8 { | |
| 548 | 536 | var buf = ArrayList(u8).init(allocator); |
| 549 | 537 | while (true) { |
| 550 | 538 | const byte = try in_stream.readByte(); |
| ... | ... | @@ -555,58 +543,58 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) %[]u8 { |
| 555 | 543 | return buf.toSlice(); |
| 556 | 544 | } |
| 557 | 545 | |
| 558 | fn getString(st: &ElfStackTrace, offset: u64) %[]u8 { | |
| 546 | fn getString(st: &ElfStackTrace, offset: u64) ![]u8 { | |
| 559 | 547 | const pos = st.debug_str.offset + offset; |
| 560 | 548 | try st.self_exe_file.seekTo(pos); |
| 561 | 549 | return st.readString(); |
| 562 | 550 | } |
| 563 | 551 | |
| 564 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %[]u8 { | |
| 552 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) ![]u8 { | |
| 565 | 553 | const buf = try global_allocator.alloc(u8, size); |
| 566 | 554 | errdefer global_allocator.free(buf); |
| 567 | 555 | if ((try in_stream.read(buf)) < size) return error.EndOfFile; |
| 568 | 556 | return buf; |
| 569 | 557 | } |
| 570 | 558 | |
| 571 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | |
| 559 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | |
| 572 | 560 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 573 | 561 | return FormValue { .Block = buf }; |
| 574 | 562 | } |
| 575 | 563 | |
| 576 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | |
| 564 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | |
| 577 | 565 | const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); |
| 578 | 566 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 579 | 567 | } |
| 580 | 568 | |
| 581 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) %FormValue { | |
| 569 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) !FormValue { | |
| 582 | 570 | return FormValue { .Const = Constant { |
| 583 | 571 | .signed = signed, |
| 584 | 572 | .payload = try readAllocBytes(allocator, in_stream, size), |
| 585 | 573 | }}; |
| 586 | 574 | } |
| 587 | 575 | |
| 588 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) %u64 { | |
| 576 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) !u64 { | |
| 589 | 577 | return if (is_64) try in_stream.readIntLe(u64) |
| 590 | 578 | else u64(try in_stream.readIntLe(u32)) ; |
| 591 | 579 | } |
| 592 | 580 | |
| 593 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) %u64 { | |
| 581 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) !u64 { | |
| 594 | 582 | return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) |
| 595 | 583 | else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) |
| 596 | 584 | else unreachable; |
| 597 | 585 | } |
| 598 | 586 | |
| 599 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) %FormValue { | |
| 587 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | |
| 600 | 588 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 601 | 589 | return FormValue { .Ref = buf }; |
| 602 | 590 | } |
| 603 | 591 | |
| 604 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) %FormValue { | |
| 592 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) !FormValue { | |
| 605 | 593 | const block_len = try in_stream.readIntLe(T); |
| 606 | 594 | return parseFormValueRefLen(allocator, in_stream, block_len); |
| 607 | 595 | } |
| 608 | 596 | |
| 609 | fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) %FormValue { | |
| 597 | fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) !FormValue { | |
| 610 | 598 | return switch (form_id) { |
| 611 | 599 | DW.FORM_addr => FormValue { .Address = try parseFormValueTargetAddrSize(in_stream) }, |
| 612 | 600 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), |
| ... | ... | @@ -656,7 +644,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 656 | 644 | }; |
| 657 | 645 | } |
| 658 | 646 | |
| 659 | fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable { | |
| 647 | fn parseAbbrevTable(st: &ElfStackTrace) !AbbrevTable { | |
| 660 | 648 | const in_file = &st.self_exe_file; |
| 661 | 649 | var in_file_stream = io.FileInStream.init(in_file); |
| 662 | 650 | const in_stream = &in_file_stream.stream; |
| ... | ... | @@ -688,7 +676,7 @@ fn parseAbbrevTable(st: &ElfStackTrace) %AbbrevTable { |
| 688 | 676 | |
| 689 | 677 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 690 | 678 | /// seeks in the stream and parses it. |
| 691 | fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) %&const AbbrevTable { | |
| 679 | fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) !&const AbbrevTable { | |
| 692 | 680 | for (st.abbrev_table_list.toSlice()) |*header| { |
| 693 | 681 | if (header.offset == abbrev_offset) { |
| 694 | 682 | return &header.table; |
| ... | ... | @@ -710,7 +698,7 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) ?&con |
| 710 | 698 | return null; |
| 711 | 699 | } |
| 712 | 700 | |
| 713 | fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) %Die { | |
| 701 | fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) !Die { | |
| 714 | 702 | const in_file = &st.self_exe_file; |
| 715 | 703 | var in_file_stream = io.FileInStream.init(in_file); |
| 716 | 704 | const in_stream = &in_file_stream.stream; |
| ... | ... | @@ -732,7 +720,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) % |
| 732 | 720 | return result; |
| 733 | 721 | } |
| 734 | 722 | |
| 735 | fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) %LineInfo { | |
| 723 | fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) !LineInfo { | |
| 736 | 724 | const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir); |
| 737 | 725 | |
| 738 | 726 | const in_file = &st.self_exe_file; |
| ... | ... | @@ -910,7 +898,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 910 | 898 | return error.MissingDebugInfo; |
| 911 | 899 | } |
| 912 | 900 | |
| 913 | fn scanAllCompileUnits(st: &ElfStackTrace) %void { | |
| 901 | fn scanAllCompileUnits(st: &ElfStackTrace) !void { | |
| 914 | 902 | const debug_info_end = st.debug_info.offset + st.debug_info.size; |
| 915 | 903 | var this_unit_offset = st.debug_info.offset; |
| 916 | 904 | var cu_index: usize = 0; |
| ... | ... | @@ -986,7 +974,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) %void { |
| 986 | 974 | } |
| 987 | 975 | } |
| 988 | 976 | |
| 989 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit { | |
| 977 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit { | |
| 990 | 978 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); |
| 991 | 979 | const in_stream = &in_file_stream.stream; |
| 992 | 980 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| ... | ... | @@ -1022,7 +1010,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) %&const CompileUnit |
| 1022 | 1010 | return error.MissingDebugInfo; |
| 1023 | 1011 | } |
| 1024 | 1012 | |
| 1025 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 { | |
| 1013 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) !u64 { | |
| 1026 | 1014 | const first_32_bits = try in_stream.readIntLe(u32); |
| 1027 | 1015 | *is_64 = (first_32_bits == 0xffffffff); |
| 1028 | 1016 | if (*is_64) { |
| ... | ... | @@ -1033,7 +1021,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) %u64 { |
| 1033 | 1021 | } |
| 1034 | 1022 | } |
| 1035 | 1023 | |
| 1036 | fn readULeb128(in_stream: &io.InStream) %u64 { | |
| 1024 | fn readULeb128(in_stream: &io.InStream) !u64 { | |
| 1037 | 1025 | var result: u64 = 0; |
| 1038 | 1026 | var shift: usize = 0; |
| 1039 | 1027 | |
| ... | ... | @@ -1054,7 +1042,7 @@ fn readULeb128(in_stream: &io.InStream) %u64 { |
| 1054 | 1042 | } |
| 1055 | 1043 | } |
| 1056 | 1044 | |
| 1057 | fn readILeb128(in_stream: &io.InStream) %i64 { | |
| 1045 | fn readILeb128(in_stream: &io.InStream) !i64 { | |
| 1058 | 1046 | var result: i64 = 0; |
| 1059 | 1047 | var shift: usize = 0; |
| 1060 | 1048 |
std/os/index.zig+43-77| ... | ... | @@ -57,25 +57,10 @@ const ArrayList = std.ArrayList; |
| 57 | 57 | const Buffer = std.Buffer; |
| 58 | 58 | const math = std.math; |
| 59 | 59 | |
| 60 | error SystemResources; | |
| 61 | error AccessDenied; | |
| 62 | error InvalidExe; | |
| 63 | error FileSystem; | |
| 64 | error IsDir; | |
| 65 | error FileNotFound; | |
| 66 | error FileBusy; | |
| 67 | error PathAlreadyExists; | |
| 68 | error SymLinkLoop; | |
| 69 | error ReadOnlyFileSystem; | |
| 70 | error LinkQuotaExceeded; | |
| 71 | error RenameAcrossMountPoints; | |
| 72 | error DirNotEmpty; | |
| 73 | error WouldBlock; | |
| 74 | ||
| 75 | 60 | /// Fills `buf` with random bytes. If linking against libc, this calls the |
| 76 | 61 | /// appropriate OS-specific library call. Otherwise it uses the zig standard |
| 77 | 62 | /// library implementation. |
| 78 | pub fn getRandomBytes(buf: []u8) %void { | |
| 63 | pub fn getRandomBytes(buf: []u8) !void { | |
| 79 | 64 | switch (builtin.os) { |
| 80 | 65 | Os.linux => while (true) { |
| 81 | 66 | // TODO check libc version and potentially call c.getrandom. |
| ... | ... | @@ -182,7 +167,7 @@ pub fn close(handle: FileHandle) void { |
| 182 | 167 | } |
| 183 | 168 | |
| 184 | 169 | /// Calls POSIX read, and keeps trying if it gets interrupted. |
| 185 | pub fn posixRead(fd: i32, buf: []u8) %void { | |
| 170 | pub fn posixRead(fd: i32, buf: []u8) !void { | |
| 186 | 171 | var index: usize = 0; |
| 187 | 172 | while (index < buf.len) { |
| 188 | 173 | const amt_written = posix.read(fd, &buf[index], buf.len - index); |
| ... | ... | @@ -203,17 +188,8 @@ pub fn posixRead(fd: i32, buf: []u8) %void { |
| 203 | 188 | } |
| 204 | 189 | } |
| 205 | 190 | |
| 206 | error WouldBlock; | |
| 207 | error FileClosed; | |
| 208 | error DestinationAddressRequired; | |
| 209 | error DiskQuota; | |
| 210 | error FileTooBig; | |
| 211 | error InputOutput; | |
| 212 | error NoSpaceLeft; | |
| 213 | error BrokenPipe; | |
| 214 | ||
| 215 | 191 | /// Calls POSIX write, and keeps trying if it gets interrupted. |
| 216 | pub fn posixWrite(fd: i32, bytes: []const u8) %void { | |
| 192 | pub fn posixWrite(fd: i32, bytes: []const u8) !void { | |
| 217 | 193 | while (true) { |
| 218 | 194 | const write_ret = posix.write(fd, bytes.ptr, bytes.len); |
| 219 | 195 | const write_err = posix.getErrno(write_ret); |
| ... | ... | @@ -243,7 +219,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void { |
| 243 | 219 | /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory. |
| 244 | 220 | /// Calls POSIX open, keeps trying if it gets interrupted, and translates |
| 245 | 221 | /// the return value into zig errors. |
| 246 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) %i32 { | |
| 222 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) !i32 { | |
| 247 | 223 | var stack_buf: [max_noalloc_path_len]u8 = undefined; |
| 248 | 224 | var path0: []u8 = undefined; |
| 249 | 225 | var need_free = false; |
| ... | ... | @@ -292,7 +268,7 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al |
| 292 | 268 | } |
| 293 | 269 | } |
| 294 | 270 | |
| 295 | pub fn posixDup2(old_fd: i32, new_fd: i32) %void { | |
| 271 | pub fn posixDup2(old_fd: i32, new_fd: i32) !void { | |
| 296 | 272 | while (true) { |
| 297 | 273 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); |
| 298 | 274 | if (err > 0) { |
| ... | ... | @@ -307,7 +283,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) %void { |
| 307 | 283 | } |
| 308 | 284 | } |
| 309 | 285 | |
| 310 | pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) %[]?&u8 { | |
| 286 | pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) ![]?&u8 { | |
| 311 | 287 | const envp_count = env_map.count(); |
| 312 | 288 | const envp_buf = try allocator.alloc(?&u8, envp_count + 1); |
| 313 | 289 | mem.set(?&u8, envp_buf, null); |
| ... | ... | @@ -344,7 +320,7 @@ pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) void { |
| 344 | 320 | /// `argv[0]` is the executable path. |
| 345 | 321 | /// This function also uses the PATH environment variable to get the full path to the executable. |
| 346 | 322 | pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, |
| 347 | allocator: &Allocator) %void | |
| 323 | allocator: &Allocator) !void | |
| 348 | 324 | { |
| 349 | 325 | const argv_buf = try allocator.alloc(?&u8, argv.len + 1); |
| 350 | 326 | mem.set(?&u8, argv_buf, null); |
| ... | ... | @@ -419,7 +395,7 @@ fn posixExecveErrnoToErr(err: usize) error { |
| 419 | 395 | pub var posix_environ_raw: []&u8 = undefined; |
| 420 | 396 | |
| 421 | 397 | /// Caller must free result when done. |
| 422 | pub fn getEnvMap(allocator: &Allocator) %BufMap { | |
| 398 | pub fn getEnvMap(allocator: &Allocator) !BufMap { | |
| 423 | 399 | var result = BufMap.init(allocator); |
| 424 | 400 | errdefer result.deinit(); |
| 425 | 401 | |
| ... | ... | @@ -480,10 +456,8 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 480 | 456 | return null; |
| 481 | 457 | } |
| 482 | 458 | |
| 483 | error EnvironmentVariableNotFound; | |
| 484 | ||
| 485 | 459 | /// Caller must free returned memory. |
| 486 | pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 { | |
| 460 | pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) ![]u8 { | |
| 487 | 461 | if (is_windows) { |
| 488 | 462 | const key_with_null = try cstr.addNullByte(allocator, key); |
| 489 | 463 | defer allocator.free(key_with_null); |
| ... | ... | @@ -517,7 +491,7 @@ pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) %[]u8 { |
| 517 | 491 | } |
| 518 | 492 | |
| 519 | 493 | /// Caller must free the returned memory. |
| 520 | pub fn getCwd(allocator: &Allocator) %[]u8 { | |
| 494 | pub fn getCwd(allocator: &Allocator) ![]u8 { | |
| 521 | 495 | switch (builtin.os) { |
| 522 | 496 | Os.windows => { |
| 523 | 497 | var buf = try allocator.alloc(u8, 256); |
| ... | ... | @@ -564,7 +538,7 @@ test "os.getCwd" { |
| 564 | 538 | _ = getCwd(debug.global_allocator); |
| 565 | 539 | } |
| 566 | 540 | |
| 567 | pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | |
| 541 | pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void { | |
| 568 | 542 | if (is_windows) { |
| 569 | 543 | return symLinkWindows(allocator, existing_path, new_path); |
| 570 | 544 | } else { |
| ... | ... | @@ -572,7 +546,7 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con |
| 572 | 546 | } |
| 573 | 547 | } |
| 574 | 548 | |
| 575 | pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | |
| 549 | pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void { | |
| 576 | 550 | const existing_with_null = try cstr.addNullByte(allocator, existing_path); |
| 577 | 551 | defer allocator.free(existing_with_null); |
| 578 | 552 | const new_with_null = try cstr.addNullByte(allocator, new_path); |
| ... | ... | @@ -586,7 +560,7 @@ pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path |
| 586 | 560 | } |
| 587 | 561 | } |
| 588 | 562 | |
| 589 | pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | |
| 563 | pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void { | |
| 590 | 564 | const full_buf = try allocator.alloc(u8, existing_path.len + new_path.len + 2); |
| 591 | 565 | defer allocator.free(full_buf); |
| 592 | 566 | |
| ... | ... | @@ -623,7 +597,7 @@ const b64_fs_encoder = base64.Base64Encoder.init( |
| 623 | 597 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", |
| 624 | 598 | base64.standard_pad_char); |
| 625 | 599 | |
| 626 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) %void { | |
| 600 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) !void { | |
| 627 | 601 | if (symLink(allocator, existing_path, new_path)) { |
| 628 | 602 | return; |
| 629 | 603 | } else |err| { |
| ... | ... | @@ -652,7 +626,7 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: |
| 652 | 626 | |
| 653 | 627 | } |
| 654 | 628 | |
| 655 | pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void { | |
| 629 | pub fn deleteFile(allocator: &Allocator, file_path: []const u8) !void { | |
| 656 | 630 | if (builtin.os == Os.windows) { |
| 657 | 631 | return deleteFileWindows(allocator, file_path); |
| 658 | 632 | } else { |
| ... | ... | @@ -660,10 +634,7 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) %void { |
| 660 | 634 | } |
| 661 | 635 | } |
| 662 | 636 | |
| 663 | error FileNotFound; | |
| 664 | error AccessDenied; | |
| 665 | ||
| 666 | pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void { | |
| 637 | pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) !void { | |
| 667 | 638 | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 668 | 639 | defer allocator.free(buf); |
| 669 | 640 | |
| ... | ... | @@ -681,7 +652,7 @@ pub fn deleteFileWindows(allocator: &Allocator, file_path: []const u8) %void { |
| 681 | 652 | } |
| 682 | 653 | } |
| 683 | 654 | |
| 684 | pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void { | |
| 655 | pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) !void { | |
| 685 | 656 | const buf = try allocator.alloc(u8, file_path.len + 1); |
| 686 | 657 | defer allocator.free(buf); |
| 687 | 658 | |
| ... | ... | @@ -708,13 +679,13 @@ pub fn deleteFilePosix(allocator: &Allocator, file_path: []const u8) %void { |
| 708 | 679 | } |
| 709 | 680 | |
| 710 | 681 | /// Calls ::copyFileMode with 0o666 for the mode. |
| 711 | pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) %void { | |
| 682 | pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) !void { | |
| 712 | 683 | return copyFileMode(allocator, source_path, dest_path, 0o666); |
| 713 | 684 | } |
| 714 | 685 | |
| 715 | 686 | // TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open |
| 716 | 687 | /// Guaranteed to be atomic. |
| 717 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) %void { | |
| 688 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) !void { | |
| 718 | 689 | var rand_buf: [12]u8 = undefined; |
| 719 | 690 | const tmp_path = try allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len)); |
| 720 | 691 | defer allocator.free(tmp_path); |
| ... | ... | @@ -738,7 +709,7 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [ |
| 738 | 709 | } |
| 739 | 710 | } |
| 740 | 711 | |
| 741 | pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) %void { | |
| 712 | pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) !void { | |
| 742 | 713 | const full_buf = try allocator.alloc(u8, old_path.len + new_path.len + 2); |
| 743 | 714 | defer allocator.free(full_buf); |
| 744 | 715 | |
| ... | ... | @@ -783,7 +754,7 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 783 | 754 | } |
| 784 | 755 | } |
| 785 | 756 | |
| 786 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void { | |
| 757 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) !void { | |
| 787 | 758 | if (is_windows) { |
| 788 | 759 | return makeDirWindows(allocator, dir_path); |
| 789 | 760 | } else { |
| ... | ... | @@ -791,7 +762,7 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 791 | 762 | } |
| 792 | 763 | } |
| 793 | 764 | |
| 794 | pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void { | |
| 765 | pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) !void { | |
| 795 | 766 | const path_buf = try cstr.addNullByte(allocator, dir_path); |
| 796 | 767 | defer allocator.free(path_buf); |
| 797 | 768 | |
| ... | ... | @@ -805,7 +776,7 @@ pub fn makeDirWindows(allocator: &Allocator, dir_path: []const u8) %void { |
| 805 | 776 | } |
| 806 | 777 | } |
| 807 | 778 | |
| 808 | pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void { | |
| 779 | pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) !void { | |
| 809 | 780 | const path_buf = try cstr.addNullByte(allocator, dir_path); |
| 810 | 781 | defer allocator.free(path_buf); |
| 811 | 782 | |
| ... | ... | @@ -831,7 +802,7 @@ pub fn makeDirPosix(allocator: &Allocator, dir_path: []const u8) %void { |
| 831 | 802 | |
| 832 | 803 | /// Calls makeDir recursively to make an entire path. Returns success if the path |
| 833 | 804 | /// already exists and is a directory. |
| 834 | pub fn makePath(allocator: &Allocator, full_path: []const u8) %void { | |
| 805 | pub fn makePath(allocator: &Allocator, full_path: []const u8) !void { | |
| 835 | 806 | const resolved_path = try path.resolve(allocator, full_path); |
| 836 | 807 | defer allocator.free(resolved_path); |
| 837 | 808 | |
| ... | ... | @@ -869,7 +840,7 @@ pub fn makePath(allocator: &Allocator, full_path: []const u8) %void { |
| 869 | 840 | |
| 870 | 841 | /// Returns ::error.DirNotEmpty if the directory is not empty. |
| 871 | 842 | /// To delete a directory recursively, see ::deleteTree |
| 872 | pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void { | |
| 843 | pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) !void { | |
| 873 | 844 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); |
| 874 | 845 | defer allocator.free(path_buf); |
| 875 | 846 | |
| ... | ... | @@ -898,7 +869,7 @@ pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 898 | 869 | /// removes it. If it cannot be removed because it is a non-empty directory, |
| 899 | 870 | /// this function recursively removes its entries and then tries again. |
| 900 | 871 | // TODO non-recursive implementation |
| 901 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) %void { | |
| 872 | pub fn deleteTree(allocator: &Allocator, full_path: []const u8) !void { | |
| 902 | 873 | start_over: while (true) { |
| 903 | 874 | // First, try deleting the item as a file. This way we don't follow sym links. |
| 904 | 875 | if (deleteFile(allocator, full_path)) { |
| ... | ... | @@ -967,7 +938,7 @@ pub const Dir = struct { |
| 967 | 938 | }; |
| 968 | 939 | }; |
| 969 | 940 | |
| 970 | pub fn open(allocator: &Allocator, dir_path: []const u8) %Dir { | |
| 941 | pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir { | |
| 971 | 942 | const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator); |
| 972 | 943 | return Dir { |
| 973 | 944 | .allocator = allocator, |
| ... | ... | @@ -985,7 +956,7 @@ pub const Dir = struct { |
| 985 | 956 | |
| 986 | 957 | /// Memory such as file names referenced in this returned entry becomes invalid |
| 987 | 958 | /// with subsequent calls to next, as well as when this ::Dir is deinitialized. |
| 988 | pub fn next(self: &Dir) %?Entry { | |
| 959 | pub fn next(self: &Dir) !?Entry { | |
| 989 | 960 | start_over: while (true) { |
| 990 | 961 | if (self.index >= self.end_index) { |
| 991 | 962 | if (self.buf.len == 0) { |
| ... | ... | @@ -1042,7 +1013,7 @@ pub const Dir = struct { |
| 1042 | 1013 | } |
| 1043 | 1014 | }; |
| 1044 | 1015 | |
| 1045 | pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void { | |
| 1016 | pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) !void { | |
| 1046 | 1017 | const path_buf = try allocator.alloc(u8, dir_path.len + 1); |
| 1047 | 1018 | defer allocator.free(path_buf); |
| 1048 | 1019 | |
| ... | ... | @@ -1066,7 +1037,7 @@ pub fn changeCurDir(allocator: &Allocator, dir_path: []const u8) %void { |
| 1066 | 1037 | } |
| 1067 | 1038 | |
| 1068 | 1039 | /// Read value of a symbolic link. |
| 1069 | pub fn readLink(allocator: &Allocator, pathname: []const u8) %[]u8 { | |
| 1040 | pub fn readLink(allocator: &Allocator, pathname: []const u8) ![]u8 { | |
| 1070 | 1041 | const path_buf = try allocator.alloc(u8, pathname.len + 1); |
| 1071 | 1042 | defer allocator.free(path_buf); |
| 1072 | 1043 | |
| ... | ... | @@ -1143,11 +1114,7 @@ test "os.sleep" { |
| 1143 | 1114 | sleep(0, 1); |
| 1144 | 1115 | } |
| 1145 | 1116 | |
| 1146 | error ResourceLimitReached; | |
| 1147 | error InvalidUserId; | |
| 1148 | error PermissionDenied; | |
| 1149 | ||
| 1150 | pub fn posix_setuid(uid: u32) %void { | |
| 1117 | pub fn posix_setuid(uid: u32) !void { | |
| 1151 | 1118 | const err = posix.getErrno(posix.setuid(uid)); |
| 1152 | 1119 | if (err == 0) return; |
| 1153 | 1120 | return switch (err) { |
| ... | ... | @@ -1158,7 +1125,7 @@ pub fn posix_setuid(uid: u32) %void { |
| 1158 | 1125 | }; |
| 1159 | 1126 | } |
| 1160 | 1127 | |
| 1161 | pub fn posix_setreuid(ruid: u32, euid: u32) %void { | |
| 1128 | pub fn posix_setreuid(ruid: u32, euid: u32) !void { | |
| 1162 | 1129 | const err = posix.getErrno(posix.setreuid(ruid, euid)); |
| 1163 | 1130 | if (err == 0) return; |
| 1164 | 1131 | return switch (err) { |
| ... | ... | @@ -1169,7 +1136,7 @@ pub fn posix_setreuid(ruid: u32, euid: u32) %void { |
| 1169 | 1136 | }; |
| 1170 | 1137 | } |
| 1171 | 1138 | |
| 1172 | pub fn posix_setgid(gid: u32) %void { | |
| 1139 | pub fn posix_setgid(gid: u32) !void { | |
| 1173 | 1140 | const err = posix.getErrno(posix.setgid(gid)); |
| 1174 | 1141 | if (err == 0) return; |
| 1175 | 1142 | return switch (err) { |
| ... | ... | @@ -1180,7 +1147,7 @@ pub fn posix_setgid(gid: u32) %void { |
| 1180 | 1147 | }; |
| 1181 | 1148 | } |
| 1182 | 1149 | |
| 1183 | pub fn posix_setregid(rgid: u32, egid: u32) %void { | |
| 1150 | pub fn posix_setregid(rgid: u32, egid: u32) !void { | |
| 1184 | 1151 | const err = posix.getErrno(posix.setregid(rgid, egid)); |
| 1185 | 1152 | if (err == 0) return; |
| 1186 | 1153 | return switch (err) { |
| ... | ... | @@ -1191,8 +1158,7 @@ pub fn posix_setregid(rgid: u32, egid: u32) %void { |
| 1191 | 1158 | }; |
| 1192 | 1159 | } |
| 1193 | 1160 | |
| 1194 | error NoStdHandles; | |
| 1195 | pub fn windowsGetStdHandle(handle_id: windows.DWORD) %windows.HANDLE { | |
| 1161 | pub fn windowsGetStdHandle(handle_id: windows.DWORD) !windows.HANDLE { | |
| 1196 | 1162 | if (windows.GetStdHandle(handle_id)) |handle| { |
| 1197 | 1163 | if (handle == windows.INVALID_HANDLE_VALUE) { |
| 1198 | 1164 | const err = windows.GetLastError(); |
| ... | ... | @@ -1261,7 +1227,7 @@ pub const ArgIteratorWindows = struct { |
| 1261 | 1227 | } |
| 1262 | 1228 | |
| 1263 | 1229 | /// You must free the returned memory when done. |
| 1264 | pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?%[]u8 { | |
| 1230 | pub fn next(self: &ArgIteratorWindows, allocator: &Allocator) ?internalNext.errors![]u8 { | |
| 1265 | 1231 | // march forward over whitespace |
| 1266 | 1232 | while (true) : (self.index += 1) { |
| 1267 | 1233 | const byte = self.cmd_line[self.index]; |
| ... | ... | @@ -1314,7 +1280,7 @@ pub const ArgIteratorWindows = struct { |
| 1314 | 1280 | } |
| 1315 | 1281 | } |
| 1316 | 1282 | |
| 1317 | fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) %[]u8 { | |
| 1283 | fn internalNext(self: &ArgIteratorWindows, allocator: &Allocator) ![]u8 { | |
| 1318 | 1284 | var buf = try Buffer.initSize(allocator, 0); |
| 1319 | 1285 | defer buf.deinit(); |
| 1320 | 1286 | |
| ... | ... | @@ -1358,7 +1324,7 @@ pub const ArgIteratorWindows = struct { |
| 1358 | 1324 | } |
| 1359 | 1325 | } |
| 1360 | 1326 | |
| 1361 | fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) %void { | |
| 1327 | fn emitBackslashes(self: &ArgIteratorWindows, buf: &Buffer, emit_count: usize) !void { | |
| 1362 | 1328 | var i: usize = 0; |
| 1363 | 1329 | while (i < emit_count) : (i += 1) { |
| 1364 | 1330 | try buf.appendByte('\\'); |
| ... | ... | @@ -1397,7 +1363,7 @@ pub const ArgIterator = struct { |
| 1397 | 1363 | } |
| 1398 | 1364 | |
| 1399 | 1365 | /// You must free the returned memory when done. |
| 1400 | pub fn next(self: &ArgIterator, allocator: &Allocator) ?%[]u8 { | |
| 1366 | pub fn next(self: &ArgIterator, allocator: &Allocator) ?![]u8 { | |
| 1401 | 1367 | if (builtin.os == Os.windows) { |
| 1402 | 1368 | return self.inner.next(allocator); |
| 1403 | 1369 | } else { |
| ... | ... | @@ -1422,7 +1388,7 @@ pub fn args() ArgIterator { |
| 1422 | 1388 | } |
| 1423 | 1389 | |
| 1424 | 1390 | /// Caller must call freeArgs on result. |
| 1425 | pub fn argsAlloc(allocator: &mem.Allocator) %[]const []u8 { | |
| 1391 | pub fn argsAlloc(allocator: &mem.Allocator) ![]const []u8 { | |
| 1426 | 1392 | // TODO refactor to only make 1 allocation. |
| 1427 | 1393 | var it = args(); |
| 1428 | 1394 | var contents = try Buffer.initSize(allocator, 0); |
| ... | ... | @@ -1529,7 +1495,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) error { |
| 1529 | 1495 | return error.Unexpected; |
| 1530 | 1496 | } |
| 1531 | 1497 | |
| 1532 | pub fn openSelfExe() %io.File { | |
| 1498 | pub fn openSelfExe() !io.File { | |
| 1533 | 1499 | switch (builtin.os) { |
| 1534 | 1500 | Os.linux => { |
| 1535 | 1501 | return io.File.openRead("/proc/self/exe", null); |
| ... | ... | @@ -1547,7 +1513,7 @@ pub fn openSelfExe() %io.File { |
| 1547 | 1513 | /// This function may return an error if the current executable |
| 1548 | 1514 | /// was deleted after spawning. |
| 1549 | 1515 | /// Caller owns returned memory. |
| 1550 | pub fn selfExePath(allocator: &mem.Allocator) %[]u8 { | |
| 1516 | pub fn selfExePath(allocator: &mem.Allocator) ![]u8 { | |
| 1551 | 1517 | switch (builtin.os) { |
| 1552 | 1518 | Os.linux => { |
| 1553 | 1519 | // If the currently executing binary has been deleted, |
| ... | ... | @@ -1590,7 +1556,7 @@ pub fn selfExePath(allocator: &mem.Allocator) %[]u8 { |
| 1590 | 1556 | |
| 1591 | 1557 | /// Get the directory path that contains the current executable. |
| 1592 | 1558 | /// Caller owns returned memory. |
| 1593 | pub fn selfExeDirPath(allocator: &mem.Allocator) %[]u8 { | |
| 1559 | pub fn selfExeDirPath(allocator: &mem.Allocator) ![]u8 { | |
| 1594 | 1560 | switch (builtin.os) { |
| 1595 | 1561 | Os.linux => { |
| 1596 | 1562 | // If the currently executing binary has been deleted, |
std/special/test_runner.zig+1-1| ... | ... | @@ -4,7 +4,7 @@ const builtin = @import("builtin"); |
| 4 | 4 | const test_fn_list = builtin.__zig_test_fn_slice; |
| 5 | 5 | const warn = std.debug.warn; |
| 6 | 6 | |
| 7 | pub fn main() %void { | |
| 7 | pub fn main() !void { | |
| 8 | 8 | for (test_fn_list) |test_fn, i| { |
| 9 | 9 | warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name); |
| 10 | 10 |