| author | |
| committer | |
| log | e9b15ac9a099fd17e6b68d0f04ec42a2dbfda0ca |
| tree | e87ce5b3ddb43d4add33b720412b1a354d718d95 |
| parent | 16d7db59ed9b0b1be6790bdb80777fbe5f80c7ed |
5 files changed, 142 insertions(+), 47 deletions(-)
src-self-hosted/Module.zig+17| ... | ... | @@ -80,6 +80,9 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{}, |
| 80 | 80 | root_name: []u8, |
| 81 | 81 | keep_source_files_loaded: bool, |
| 82 | 82 | |
| 83 | /// Error tags and their values, tag names are duped with mod.gpa. | |
| 84 | global_error_set: std.StringHashMapUnmanaged(u16) = .{}, | |
| 85 | ||
| 83 | 86 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 84 | 87 | |
| 85 | 88 | const WorkItem = union(enum) { |
| ... | ... | @@ -928,6 +931,11 @@ pub fn deinit(self: *Module) void { |
| 928 | 931 | |
| 929 | 932 | self.symbol_exports.deinit(gpa); |
| 930 | 933 | self.root_scope.destroy(gpa); |
| 934 | ||
| 935 | for (self.global_error_set.items()) |entry| { | |
| 936 | gpa.free(entry.key); | |
| 937 | } | |
| 938 | self.global_error_set.deinit(gpa); | |
| 931 | 939 | self.* = undefined; |
| 932 | 940 | } |
| 933 | 941 | |
| ... | ... | @@ -2072,6 +2080,15 @@ fn createNewDecl( |
| 2072 | 2080 | return new_decl; |
| 2073 | 2081 | } |
| 2074 | 2082 | |
| 2083 | /// Get error value for error tag `name`. | |
| 2084 | pub fn getErrorValue(self: *Module, name: []const u8) !u16 { | |
| 2085 | const new_val = @intCast(u16, self.global_error_set.items().len); | |
| 2086 | if (self.global_error_set.get(name)) |some| return some; | |
| 2087 | ||
| 2088 | try self.global_error_set.put(self.gpa, try self.gpa.dupe(u8, name), new_val); | |
| 2089 | return new_val; | |
| 2090 | } | |
| 2091 | ||
| 2075 | 2092 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. |
| 2076 | 2093 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| 2077 | 2094 | return scope.cast(Scope.Block) orelse |
src-self-hosted/astgen.zig+29-46| ... | ... | @@ -270,6 +270,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 270 | 270 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), |
| 271 | 271 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), |
| 272 | 272 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), |
| 273 | .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), | |
| 273 | 274 | |
| 274 | 275 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 275 | 276 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), |
| ... | ... | @@ -291,7 +292,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 291 | 292 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 292 | 293 | .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), |
| 293 | 294 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 294 | .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}), | |
| 295 | 295 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 296 | 296 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), |
| 297 | 297 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| ... | ... | @@ -459,7 +459,9 @@ fn varDecl( |
| 459 | 459 | const tree = scope.tree(); |
| 460 | 460 | const name_src = tree.token_locs[node.name_token].start; |
| 461 | 461 | const ident_name = try identifierTokenString(mod, scope, node.name_token); |
| 462 | const init_node = node.getTrailer("init_node").?; | |
| 462 | const init_node = node.getTrailer("init_node") orelse | |
| 463 | return mod.fail(scope, name_src, "variables must be initialized", .{}); | |
| 464 | ||
| 463 | 465 | switch (tree.token_ids[node.mut_token]) { |
| 464 | 466 | .Keyword_const => { |
| 465 | 467 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| ... | ... | @@ -582,11 +584,7 @@ fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerE |
| 582 | 584 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { |
| 583 | 585 | const tree = scope.tree(); |
| 584 | 586 | const src = tree.token_locs[node.op_token].start; |
| 585 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 586 | .ty = Type.initTag(.type), | |
| 587 | .val = Value.initTag(.type_type), | |
| 588 | }); | |
| 589 | const operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 587 | const operand = try typeExpr(mod, scope, node.rhs); | |
| 590 | 588 | return addZIRUnOp(mod, scope, src, .optional_type, operand); |
| 591 | 589 | } |
| 592 | 590 | |
| ... | ... | @@ -611,18 +609,13 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir |
| 611 | 609 | } |
| 612 | 610 | |
| 613 | 611 | fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { |
| 614 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 615 | .ty = Type.initTag(.type), | |
| 616 | .val = Value.initTag(.type_type), | |
| 617 | }); | |
| 618 | ||
| 619 | 612 | const simple = ptr_info.allowzero_token == null and |
| 620 | 613 | ptr_info.align_info == null and |
| 621 | 614 | ptr_info.volatile_token == null and |
| 622 | 615 | ptr_info.sentinel == null; |
| 623 | 616 | |
| 624 | 617 | if (simple) { |
| 625 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); | |
| 618 | const child_type = try typeExpr(mod, scope, rhs); | |
| 626 | 619 | const mutable = ptr_info.const_token == null; |
| 627 | 620 | // TODO stage1 type inference bug |
| 628 | 621 | const T = zir.Inst.Tag; |
| ... | ... | @@ -650,7 +643,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 650 | 643 | kw_args.sentinel = try expr(mod, scope, .none, some); |
| 651 | 644 | } |
| 652 | 645 | |
| 653 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); | |
| 646 | const child_type = try typeExpr(mod, scope, rhs); | |
| 654 | 647 | if (kw_args.sentinel) |some| { |
| 655 | 648 | kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); |
| 656 | 649 | } |
| ... | ... | @@ -661,10 +654,6 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 661 | 654 | fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { |
| 662 | 655 | const tree = scope.tree(); |
| 663 | 656 | const src = tree.token_locs[node.op_token].start; |
| 664 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 665 | .ty = Type.initTag(.type), | |
| 666 | .val = Value.initTag(.type_type), | |
| 667 | }); | |
| 668 | 657 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 669 | 658 | .ty = Type.initTag(.type), |
| 670 | 659 | .val = Value.initTag(.usize_type), |
| ... | ... | @@ -672,18 +661,14 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst |
| 672 | 661 | |
| 673 | 662 | // TODO check for [_]T |
| 674 | 663 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); |
| 675 | const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 664 | const elem_type = try typeExpr(mod, scope, node.rhs); | |
| 676 | 665 | |
| 677 | return addZIRBinOp(mod, scope, src, .array_type, len, child_type); | |
| 666 | return addZIRBinOp(mod, scope, src, .array_type, len, elem_type); | |
| 678 | 667 | } |
| 679 | 668 | |
| 680 | 669 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { |
| 681 | 670 | const tree = scope.tree(); |
| 682 | 671 | const src = tree.token_locs[node.op_token].start; |
| 683 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 684 | .ty = Type.initTag(.type), | |
| 685 | .val = Value.initTag(.type_type), | |
| 686 | }); | |
| 687 | 672 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 688 | 673 | .ty = Type.initTag(.type), |
| 689 | 674 | .val = Value.initTag(.usize_type), |
| ... | ... | @@ -692,7 +677,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti |
| 692 | 677 | // TODO check for [_]T |
| 693 | 678 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); |
| 694 | 679 | const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); |
| 695 | const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 680 | const elem_type = try typeExpr(mod, scope, node.rhs); | |
| 696 | 681 | const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); |
| 697 | 682 | |
| 698 | 683 | return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ |
| ... | ... | @@ -706,11 +691,7 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner |
| 706 | 691 | const tree = scope.tree(); |
| 707 | 692 | const src = tree.token_locs[node.anyframe_token].start; |
| 708 | 693 | if (node.result) |some| { |
| 709 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 710 | .ty = Type.initTag(.type), | |
| 711 | .val = Value.initTag(.type_type), | |
| 712 | }); | |
| 713 | const return_type = try expr(mod, scope, .{ .ty = meta_type}, some.return_type); | |
| 694 | const return_type = try typeExpr(mod, scope, some.return_type); | |
| 714 | 695 | return addZIRUnOp(mod, scope, src, .anyframe_type, return_type); |
| 715 | 696 | } else { |
| 716 | 697 | return addZIRInstConst(mod, scope, src, .{ |
| ... | ... | @@ -723,12 +704,8 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner |
| 723 | 704 | fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { |
| 724 | 705 | const tree = scope.tree(); |
| 725 | 706 | const src = tree.token_locs[node.op_token].start; |
| 726 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | |
| 727 | .ty = Type.initTag(.type), | |
| 728 | .val = Value.initTag(.type_type), | |
| 729 | }); | |
| 730 | const error_set = try expr(mod, scope, .{ .ty = meta_type }, node.lhs); | |
| 731 | const payload = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | |
| 707 | const error_set = try typeExpr(mod, scope, node.lhs); | |
| 708 | const payload = try typeExpr(mod, scope, node.rhs); | |
| 732 | 709 | return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload); |
| 733 | 710 | } |
| 734 | 711 | |
| ... | ... | @@ -751,6 +728,20 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si |
| 751 | 728 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr)); |
| 752 | 729 | } |
| 753 | 730 | |
| 731 | fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { | |
| 732 | const tree = scope.tree(); | |
| 733 | const src = tree.token_locs[node.error_token].start; | |
| 734 | const decls = node.decls(); | |
| 735 | const fields = try scope.arena().alloc([]const u8, decls.len); | |
| 736 | ||
| 737 | for (decls) |decl, i| { | |
| 738 | const tag = decl.castTag(.ErrorTag).?; | |
| 739 | fields[i] = try identifierTokenString(mod, scope, tag.name_token); | |
| 740 | } | |
| 741 | ||
| 742 | return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); | |
| 743 | } | |
| 744 | ||
| 754 | 745 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. |
| 755 | 746 | /// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used. |
| 756 | 747 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { |
| ... | ... | @@ -1517,12 +1508,8 @@ fn simpleCast( |
| 1517 | 1508 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 1518 | 1509 | const tree = scope.tree(); |
| 1519 | 1510 | const src = tree.token_locs[call.builtin_token].start; |
| 1520 | const type_type = try addZIRInstConst(mod, scope, src, .{ | |
| 1521 | .ty = Type.initTag(.type), | |
| 1522 | .val = Value.initTag(.type_type), | |
| 1523 | }); | |
| 1524 | 1511 | const params = call.params(); |
| 1525 | const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]); | |
| 1512 | const dest_type = try typeExpr(mod, scope, params[0]); | |
| 1526 | 1513 | const rhs = try expr(mod, scope, .none, params[1]); |
| 1527 | 1514 | const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); |
| 1528 | 1515 | return rlWrap(mod, scope, rl, result); |
| ... | ... | @@ -1584,12 +1571,8 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa |
| 1584 | 1571 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 1585 | 1572 | const tree = scope.tree(); |
| 1586 | 1573 | const src = tree.token_locs[call.builtin_token].start; |
| 1587 | const type_type = try addZIRInstConst(mod, scope, src, .{ | |
| 1588 | .ty = Type.initTag(.type), | |
| 1589 | .val = Value.initTag(.type_type), | |
| 1590 | }); | |
| 1591 | 1574 | const params = call.params(); |
| 1592 | const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]); | |
| 1575 | const dest_type = try typeExpr(mod, scope, params[0]); | |
| 1593 | 1576 | switch (rl) { |
| 1594 | 1577 | .none => { |
| 1595 | 1578 | const operand = try expr(mod, scope, .none, params[1]); |
src-self-hosted/value.zig+30| ... | ... | @@ -91,6 +91,7 @@ pub const Value = extern union { |
| 91 | 91 | float_64, |
| 92 | 92 | float_128, |
| 93 | 93 | enum_literal, |
| 94 | error_set, | |
| 94 | 95 | |
| 95 | 96 | pub const last_no_payload_tag = Tag.bool_false; |
| 96 | 97 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| ... | ... | @@ -243,6 +244,9 @@ pub const Value = extern union { |
| 243 | 244 | }; |
| 244 | 245 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 245 | 246 | }, |
| 247 | ||
| 248 | // memory is managed by the declaration | |
| 249 | .error_set => return self, | |
| 246 | 250 | } |
| 247 | 251 | } |
| 248 | 252 | |
| ... | ... | @@ -346,6 +350,14 @@ pub const Value = extern union { |
| 346 | 350 | .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}), |
| 347 | 351 | .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}), |
| 348 | 352 | .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}), |
| 353 | .error_set => { | |
| 354 | const error_set = val.cast(Payload.ErrorSet).?; | |
| 355 | try out_stream.writeAll("error{"); | |
| 356 | for (error_set.fields.items()) |entry| { | |
| 357 | try out_stream.print("{},", .{entry.value}); | |
| 358 | } | |
| 359 | return out_stream.writeAll("}"); | |
| 360 | }, | |
| 349 | 361 | }; |
| 350 | 362 | } |
| 351 | 363 | |
| ... | ... | @@ -437,6 +449,7 @@ pub const Value = extern union { |
| 437 | 449 | .float_64, |
| 438 | 450 | .float_128, |
| 439 | 451 | .enum_literal, |
| 452 | .error_set, | |
| 440 | 453 | => unreachable, |
| 441 | 454 | }; |
| 442 | 455 | } |
| ... | ... | @@ -503,6 +516,7 @@ pub const Value = extern union { |
| 503 | 516 | .unreachable_value, |
| 504 | 517 | .empty_array, |
| 505 | 518 | .enum_literal, |
| 519 | .error_set, | |
| 506 | 520 | => unreachable, |
| 507 | 521 | |
| 508 | 522 | .undef => unreachable, |
| ... | ... | @@ -582,6 +596,7 @@ pub const Value = extern union { |
| 582 | 596 | .unreachable_value, |
| 583 | 597 | .empty_array, |
| 584 | 598 | .enum_literal, |
| 599 | .error_set, | |
| 585 | 600 | => unreachable, |
| 586 | 601 | |
| 587 | 602 | .undef => unreachable, |
| ... | ... | @@ -661,6 +676,7 @@ pub const Value = extern union { |
| 661 | 676 | .unreachable_value, |
| 662 | 677 | .empty_array, |
| 663 | 678 | .enum_literal, |
| 679 | .error_set, | |
| 664 | 680 | => unreachable, |
| 665 | 681 | |
| 666 | 682 | .undef => unreachable, |
| ... | ... | @@ -767,6 +783,7 @@ pub const Value = extern union { |
| 767 | 783 | .unreachable_value, |
| 768 | 784 | .empty_array, |
| 769 | 785 | .enum_literal, |
| 786 | .error_set, | |
| 770 | 787 | => unreachable, |
| 771 | 788 | |
| 772 | 789 | .zero, |
| ... | ... | @@ -850,6 +867,7 @@ pub const Value = extern union { |
| 850 | 867 | .unreachable_value, |
| 851 | 868 | .empty_array, |
| 852 | 869 | .enum_literal, |
| 870 | .error_set, | |
| 853 | 871 | => unreachable, |
| 854 | 872 | |
| 855 | 873 | .zero, |
| ... | ... | @@ -1017,6 +1035,7 @@ pub const Value = extern union { |
| 1017 | 1035 | .void_value, |
| 1018 | 1036 | .unreachable_value, |
| 1019 | 1037 | .enum_literal, |
| 1038 | .error_set, | |
| 1020 | 1039 | => unreachable, |
| 1021 | 1040 | |
| 1022 | 1041 | .zero => false, |
| ... | ... | @@ -1087,6 +1106,7 @@ pub const Value = extern union { |
| 1087 | 1106 | .unreachable_value, |
| 1088 | 1107 | .empty_array, |
| 1089 | 1108 | .enum_literal, |
| 1109 | .error_set, | |
| 1090 | 1110 | => unreachable, |
| 1091 | 1111 | |
| 1092 | 1112 | .zero, |
| ... | ... | @@ -1230,6 +1250,7 @@ pub const Value = extern union { |
| 1230 | 1250 | .unreachable_value, |
| 1231 | 1251 | .empty_array, |
| 1232 | 1252 | .enum_literal, |
| 1253 | .error_set, | |
| 1233 | 1254 | => unreachable, |
| 1234 | 1255 | |
| 1235 | 1256 | .ref_val => self.cast(Payload.RefVal).?.val, |
| ... | ... | @@ -1310,6 +1331,7 @@ pub const Value = extern union { |
| 1310 | 1331 | .void_value, |
| 1311 | 1332 | .unreachable_value, |
| 1312 | 1333 | .enum_literal, |
| 1334 | .error_set, | |
| 1313 | 1335 | => unreachable, |
| 1314 | 1336 | |
| 1315 | 1337 | .empty_array => unreachable, // out of bounds array index |
| ... | ... | @@ -1407,6 +1429,7 @@ pub const Value = extern union { |
| 1407 | 1429 | .float_128, |
| 1408 | 1430 | .void_value, |
| 1409 | 1431 | .enum_literal, |
| 1432 | .error_set, | |
| 1410 | 1433 | => false, |
| 1411 | 1434 | |
| 1412 | 1435 | .undef => unreachable, |
| ... | ... | @@ -1536,6 +1559,13 @@ pub const Value = extern union { |
| 1536 | 1559 | base: Payload = .{ .tag = .float_128 }, |
| 1537 | 1560 | val: f128, |
| 1538 | 1561 | }; |
| 1562 | ||
| 1563 | pub const ErrorSet = struct { | |
| 1564 | base: Payload = .{ .tag = .error_set }, | |
| 1565 | ||
| 1566 | // TODO revisit this when we have the concept of the error tag type | |
| 1567 | fields: std.StringHashMapUnmanaged(u16), | |
| 1568 | }; | |
| 1539 | 1569 | }; |
| 1540 | 1570 | |
| 1541 | 1571 | /// Big enough to fit any non-BigInt value |
src-self-hosted/zir.zig+39| ... | ... | @@ -139,6 +139,8 @@ pub const Inst = struct { |
| 139 | 139 | ensure_result_non_error, |
| 140 | 140 | /// Create a `E!T` type. |
| 141 | 141 | error_union_type, |
| 142 | /// Create an error set. | |
| 143 | error_set, | |
| 142 | 144 | /// Export the provided Decl as the provided name in the compilation's output object file. |
| 143 | 145 | @"export", |
| 144 | 146 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer |
| ... | ... | @@ -359,6 +361,7 @@ pub const Inst = struct { |
| 359 | 361 | .condbr => CondBr, |
| 360 | 362 | .ptr_type => PtrType, |
| 361 | 363 | .enum_literal => EnumLiteral, |
| 364 | .error_set => ErrorSet, | |
| 362 | 365 | }; |
| 363 | 366 | } |
| 364 | 367 | |
| ... | ... | @@ -454,6 +457,7 @@ pub const Inst = struct { |
| 454 | 457 | .anyframe_type, |
| 455 | 458 | .error_union_type, |
| 456 | 459 | .bitnot, |
| 460 | .error_set, | |
| 457 | 461 | => false, |
| 458 | 462 | |
| 459 | 463 | .@"break", |
| ... | ... | @@ -924,6 +928,16 @@ pub const Inst = struct { |
| 924 | 928 | }, |
| 925 | 929 | kw_args: struct {}, |
| 926 | 930 | }; |
| 931 | ||
| 932 | pub const ErrorSet = struct { | |
| 933 | pub const base_tag = Tag.error_set; | |
| 934 | base: Inst, | |
| 935 | ||
| 936 | positionals: struct { | |
| 937 | fields: [][]const u8, | |
| 938 | }, | |
| 939 | kw_args: struct {}, | |
| 940 | }; | |
| 927 | 941 | }; |
| 928 | 942 | |
| 929 | 943 | pub const ErrorMsg = struct { |
| ... | ... | @@ -1158,6 +1172,16 @@ const Writer = struct { |
| 1158 | 1172 | const name = self.loop_table.get(param).?; |
| 1159 | 1173 | return std.zig.renderStringLiteral(name, stream); |
| 1160 | 1174 | }, |
| 1175 | [][]const u8 => { | |
| 1176 | try stream.writeByte('['); | |
| 1177 | for (param) |str, i| { | |
| 1178 | if (i != 0) { | |
| 1179 | try stream.writeAll(", "); | |
| 1180 | } | |
| 1181 | try std.zig.renderStringLiteral(str, stream); | |
| 1182 | } | |
| 1183 | try stream.writeByte(']'); | |
| 1184 | }, | |
| 1161 | 1185 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), |
| 1162 | 1186 | } |
| 1163 | 1187 | } |
| ... | ... | @@ -1555,6 +1579,21 @@ const Parser = struct { |
| 1555 | 1579 | const name = try self.parseStringLiteral(); |
| 1556 | 1580 | return self.loop_table.get(name).?; |
| 1557 | 1581 | }, |
| 1582 | [][]const u8 => { | |
| 1583 | try requireEatBytes(self, "["); | |
| 1584 | skipSpace(self); | |
| 1585 | if (eatByte(self, ']')) return &[0][]const u8{}; | |
| 1586 | ||
| 1587 | var strings = std.ArrayList([]const u8).init(&self.arena.allocator); | |
| 1588 | while (true) { | |
| 1589 | skipSpace(self); | |
| 1590 | try strings.append(try self.parseStringLiteral()); | |
| 1591 | skipSpace(self); | |
| 1592 | if (!eatByte(self, ',')) break; | |
| 1593 | } | |
| 1594 | try requireEatBytes(self, "]"); | |
| 1595 | return strings.toOwnedSlice(); | |
| 1596 | }, | |
| 1558 | 1597 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), |
| 1559 | 1598 | } |
| 1560 | 1599 | return self.fail("TODO parse parameter {}", .{@typeName(T)}); |
src-self-hosted/zir_sema.zig+27-1| ... | ... | @@ -126,6 +126,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 126 | 126 | .merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?), |
| 127 | 127 | .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), |
| 128 | 128 | .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?), |
| 129 | .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?), | |
| 129 | 130 | } |
| 130 | 131 | } |
| 131 | 132 | |
| ... | ... | @@ -435,6 +436,7 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr |
| 435 | 436 | // The bytes references memory inside the ZIR module, which can get deallocated |
| 436 | 437 | // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena. |
| 437 | 438 | var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 439 | errdefer new_decl_arena.deinit(); | |
| 438 | 440 | const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes); |
| 439 | 441 | |
| 440 | 442 | const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); |
| ... | ... | @@ -737,6 +739,30 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In |
| 737 | 739 | return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type)); |
| 738 | 740 | } |
| 739 | 741 | |
| 742 | fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst { | |
| 743 | // The bytes references memory inside the ZIR module, which can get deallocated | |
| 744 | // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena. | |
| 745 | var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa); | |
| 746 | errdefer new_decl_arena.deinit(); | |
| 747 | ||
| 748 | const payload = try scope.arena().create(Value.Payload.ErrorSet); | |
| 749 | payload.* = .{ .fields = .{} }; | |
| 750 | try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len); | |
| 751 | ||
| 752 | for (inst.positionals.fields) |field_name| { | |
| 753 | const value = try mod.getErrorValue(field_name); | |
| 754 | if (payload.fields.fetchPutAssumeCapacity(field_name, value)) |prev| { | |
| 755 | return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name}); | |
| 756 | } | |
| 757 | } | |
| 758 | // TODO create name in format "error:line:column" | |
| 759 | const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{ | |
| 760 | .ty = Type.initTag(.type), | |
| 761 | .val = Value.initPayload(&payload.base), | |
| 762 | }); | |
| 763 | return mod.analyzeDeclRef(scope, inst.base.src, new_decl); | |
| 764 | } | |
| 765 | ||
| 740 | 766 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 741 | 767 | return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{}); |
| 742 | 768 | } |
| ... | ... | @@ -1377,7 +1403,7 @@ fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) Inne |
| 1377 | 1403 | |
| 1378 | 1404 | if (host_size != 0 and bit_offset >= host_size * 8) |
| 1379 | 1405 | return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); |
| 1380 | ||
| 1406 | ||
| 1381 | 1407 | const sentinel = if (inst.kw_args.sentinel) |some| |
| 1382 | 1408 | (try resolveInstConst(mod, scope, some)).val |
| 1383 | 1409 | else |