| 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,6 +80,9 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{}, |
| 80 | root_name: []u8, | 80 | root_name: []u8, |
| 81 | keep_source_files_loaded: bool, | 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 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; | 86 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 84 | 87 | ||
| 85 | const WorkItem = union(enum) { | 88 | const WorkItem = union(enum) { |
| ... | @@ -928,6 +931,11 @@ pub fn deinit(self: *Module) void { | ... | @@ -928,6 +931,11 @@ pub fn deinit(self: *Module) void { |
| 928 | 931 | ||
| 929 | self.symbol_exports.deinit(gpa); | 932 | self.symbol_exports.deinit(gpa); |
| 930 | self.root_scope.destroy(gpa); | 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 | self.* = undefined; | 939 | self.* = undefined; |
| 932 | } | 940 | } |
| 933 | 941 | ||
| ... | @@ -2072,6 +2080,15 @@ fn createNewDecl( | ... | @@ -2072,6 +2080,15 @@ fn createNewDecl( |
| 2072 | return new_decl; | 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 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. | 2092 | /// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites. |
| 2076 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { | 2093 | pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| 2077 | return scope.cast(Scope.Block) orelse | 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,6 +270,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 270 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), | 270 | .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), |
| 271 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), | 271 | .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), |
| 272 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), | 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 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), | 275 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 275 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), | 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,7 +292,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 291 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), | 292 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 292 | .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), | 293 | .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}), |
| 293 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), | 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 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), | 295 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 296 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), | 296 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), |
| 297 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), | 297 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| ... | @@ -459,7 +459,9 @@ fn varDecl( | ... | @@ -459,7 +459,9 @@ fn varDecl( |
| 459 | const tree = scope.tree(); | 459 | const tree = scope.tree(); |
| 460 | const name_src = tree.token_locs[node.name_token].start; | 460 | const name_src = tree.token_locs[node.name_token].start; |
| 461 | const ident_name = try identifierTokenString(mod, scope, node.name_token); | 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 | switch (tree.token_ids[node.mut_token]) { | 465 | switch (tree.token_ids[node.mut_token]) { |
| 464 | .Keyword_const => { | 466 | .Keyword_const => { |
| 465 | // Depending on the type of AST the initialization expression is, we may need an lvalue | 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,11 +584,7 @@ fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerE |
| 582 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 584 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { |
| 583 | const tree = scope.tree(); | 585 | const tree = scope.tree(); |
| 584 | const src = tree.token_locs[node.op_token].start; | 586 | const src = tree.token_locs[node.op_token].start; |
| 585 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | 587 | const operand = try typeExpr(mod, scope, node.rhs); |
| 586 | .ty = Type.initTag(.type), | ||
| 587 | .val = Value.initTag(.type_type), | ||
| 588 | }); | ||
| 589 | const operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | ||
| 590 | return addZIRUnOp(mod, scope, src, .optional_type, operand); | 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,18 +609,13 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir |
| 611 | } | 609 | } |
| 612 | 610 | ||
| 613 | fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { | 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 | const simple = ptr_info.allowzero_token == null and | 612 | const simple = ptr_info.allowzero_token == null and |
| 620 | ptr_info.align_info == null and | 613 | ptr_info.align_info == null and |
| 621 | ptr_info.volatile_token == null and | 614 | ptr_info.volatile_token == null and |
| 622 | ptr_info.sentinel == null; | 615 | ptr_info.sentinel == null; |
| 623 | 616 | ||
| 624 | if (simple) { | 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 | const mutable = ptr_info.const_token == null; | 619 | const mutable = ptr_info.const_token == null; |
| 627 | // TODO stage1 type inference bug | 620 | // TODO stage1 type inference bug |
| 628 | const T = zir.Inst.Tag; | 621 | const T = zir.Inst.Tag; |
| ... | @@ -650,7 +643,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, | ... | @@ -650,7 +643,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 650 | kw_args.sentinel = try expr(mod, scope, .none, some); | 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 | if (kw_args.sentinel) |some| { | 647 | if (kw_args.sentinel) |some| { |
| 655 | kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); | 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,10 +654,6 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 661 | fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { | 654 | fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { |
| 662 | const tree = scope.tree(); | 655 | const tree = scope.tree(); |
| 663 | const src = tree.token_locs[node.op_token].start; | 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 | const usize_type = try addZIRInstConst(mod, scope, src, .{ | 657 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 669 | .ty = Type.initTag(.type), | 658 | .ty = Type.initTag(.type), |
| 670 | .val = Value.initTag(.usize_type), | 659 | .val = Value.initTag(.usize_type), |
| ... | @@ -672,18 +661,14 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst | ... | @@ -672,18 +661,14 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst |
| 672 | 661 | ||
| 673 | // TODO check for [_]T | 662 | // TODO check for [_]T |
| 674 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); | 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 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { | 669 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { |
| 681 | const tree = scope.tree(); | 670 | const tree = scope.tree(); |
| 682 | const src = tree.token_locs[node.op_token].start; | 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 | const usize_type = try addZIRInstConst(mod, scope, src, .{ | 672 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 688 | .ty = Type.initTag(.type), | 673 | .ty = Type.initTag(.type), |
| 689 | .val = Value.initTag(.usize_type), | 674 | .val = Value.initTag(.usize_type), |
| ... | @@ -692,7 +677,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti | ... | @@ -692,7 +677,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti |
| 692 | // TODO check for [_]T | 677 | // TODO check for [_]T |
| 693 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); | 678 | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); |
| 694 | const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); | 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 | const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); | 681 | const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); |
| 697 | 682 | ||
| 698 | return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ | 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,11 +691,7 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner |
| 706 | const tree = scope.tree(); | 691 | const tree = scope.tree(); |
| 707 | const src = tree.token_locs[node.anyframe_token].start; | 692 | const src = tree.token_locs[node.anyframe_token].start; |
| 708 | if (node.result) |some| { | 693 | if (node.result) |some| { |
| 709 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | 694 | const return_type = try typeExpr(mod, scope, some.return_type); |
| 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); | ||
| 714 | return addZIRUnOp(mod, scope, src, .anyframe_type, return_type); | 695 | return addZIRUnOp(mod, scope, src, .anyframe_type, return_type); |
| 715 | } else { | 696 | } else { |
| 716 | return addZIRInstConst(mod, scope, src, .{ | 697 | return addZIRInstConst(mod, scope, src, .{ |
| ... | @@ -723,12 +704,8 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner | ... | @@ -723,12 +704,8 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner |
| 723 | fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { | 704 | fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { |
| 724 | const tree = scope.tree(); | 705 | const tree = scope.tree(); |
| 725 | const src = tree.token_locs[node.op_token].start; | 706 | const src = tree.token_locs[node.op_token].start; |
| 726 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | 707 | const error_set = try typeExpr(mod, scope, node.lhs); |
| 727 | .ty = Type.initTag(.type), | 708 | const payload = try typeExpr(mod, scope, node.rhs); |
| 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); | ||
| 732 | return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload); | 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,6 +728,20 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si |
| 751 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr)); | 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 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. | 745 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. |
| 755 | /// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used. | 746 | /// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used. |
| 756 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { | 747 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { |
| ... | @@ -1517,12 +1508,8 @@ fn simpleCast( | ... | @@ -1517,12 +1508,8 @@ fn simpleCast( |
| 1517 | try ensureBuiltinParamCount(mod, scope, call, 2); | 1508 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 1518 | const tree = scope.tree(); | 1509 | const tree = scope.tree(); |
| 1519 | const src = tree.token_locs[call.builtin_token].start; | 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 | const params = call.params(); | 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 | const rhs = try expr(mod, scope, .none, params[1]); | 1513 | const rhs = try expr(mod, scope, .none, params[1]); |
| 1527 | const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); | 1514 | const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs); |
| 1528 | return rlWrap(mod, scope, rl, result); | 1515 | return rlWrap(mod, scope, rl, result); |
| ... | @@ -1584,12 +1571,8 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa | ... | @@ -1584,12 +1571,8 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa |
| 1584 | try ensureBuiltinParamCount(mod, scope, call, 2); | 1571 | try ensureBuiltinParamCount(mod, scope, call, 2); |
| 1585 | const tree = scope.tree(); | 1572 | const tree = scope.tree(); |
| 1586 | const src = tree.token_locs[call.builtin_token].start; | 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 | const params = call.params(); | 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 | switch (rl) { | 1576 | switch (rl) { |
| 1594 | .none => { | 1577 | .none => { |
| 1595 | const operand = try expr(mod, scope, .none, params[1]); | 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,6 +91,7 @@ pub const Value = extern union { |
| 91 | float_64, | 91 | float_64, |
| 92 | float_128, | 92 | float_128, |
| 93 | enum_literal, | 93 | enum_literal, |
| 94 | error_set, | ||
| 94 | 95 | ||
| 95 | pub const last_no_payload_tag = Tag.bool_false; | 96 | pub const last_no_payload_tag = Tag.bool_false; |
| 96 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; | 97 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| ... | @@ -243,6 +244,9 @@ pub const Value = extern union { | ... | @@ -243,6 +244,9 @@ pub const Value = extern union { |
| 243 | }; | 244 | }; |
| 244 | return Value{ .ptr_otherwise = &new_payload.base }; | 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,6 +350,14 @@ pub const Value = extern union { |
| 346 | .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}), | 350 | .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}), |
| 347 | .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}), | 351 | .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}), |
| 348 | .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}), | 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,6 +449,7 @@ pub const Value = extern union { |
| 437 | .float_64, | 449 | .float_64, |
| 438 | .float_128, | 450 | .float_128, |
| 439 | .enum_literal, | 451 | .enum_literal, |
| 452 | .error_set, | ||
| 440 | => unreachable, | 453 | => unreachable, |
| 441 | }; | 454 | }; |
| 442 | } | 455 | } |
| ... | @@ -503,6 +516,7 @@ pub const Value = extern union { | ... | @@ -503,6 +516,7 @@ pub const Value = extern union { |
| 503 | .unreachable_value, | 516 | .unreachable_value, |
| 504 | .empty_array, | 517 | .empty_array, |
| 505 | .enum_literal, | 518 | .enum_literal, |
| 519 | .error_set, | ||
| 506 | => unreachable, | 520 | => unreachable, |
| 507 | 521 | ||
| 508 | .undef => unreachable, | 522 | .undef => unreachable, |
| ... | @@ -582,6 +596,7 @@ pub const Value = extern union { | ... | @@ -582,6 +596,7 @@ pub const Value = extern union { |
| 582 | .unreachable_value, | 596 | .unreachable_value, |
| 583 | .empty_array, | 597 | .empty_array, |
| 584 | .enum_literal, | 598 | .enum_literal, |
| 599 | .error_set, | ||
| 585 | => unreachable, | 600 | => unreachable, |
| 586 | 601 | ||
| 587 | .undef => unreachable, | 602 | .undef => unreachable, |
| ... | @@ -661,6 +676,7 @@ pub const Value = extern union { | ... | @@ -661,6 +676,7 @@ pub const Value = extern union { |
| 661 | .unreachable_value, | 676 | .unreachable_value, |
| 662 | .empty_array, | 677 | .empty_array, |
| 663 | .enum_literal, | 678 | .enum_literal, |
| 679 | .error_set, | ||
| 664 | => unreachable, | 680 | => unreachable, |
| 665 | 681 | ||
| 666 | .undef => unreachable, | 682 | .undef => unreachable, |
| ... | @@ -767,6 +783,7 @@ pub const Value = extern union { | ... | @@ -767,6 +783,7 @@ pub const Value = extern union { |
| 767 | .unreachable_value, | 783 | .unreachable_value, |
| 768 | .empty_array, | 784 | .empty_array, |
| 769 | .enum_literal, | 785 | .enum_literal, |
| 786 | .error_set, | ||
| 770 | => unreachable, | 787 | => unreachable, |
| 771 | 788 | ||
| 772 | .zero, | 789 | .zero, |
| ... | @@ -850,6 +867,7 @@ pub const Value = extern union { | ... | @@ -850,6 +867,7 @@ pub const Value = extern union { |
| 850 | .unreachable_value, | 867 | .unreachable_value, |
| 851 | .empty_array, | 868 | .empty_array, |
| 852 | .enum_literal, | 869 | .enum_literal, |
| 870 | .error_set, | ||
| 853 | => unreachable, | 871 | => unreachable, |
| 854 | 872 | ||
| 855 | .zero, | 873 | .zero, |
| ... | @@ -1017,6 +1035,7 @@ pub const Value = extern union { | ... | @@ -1017,6 +1035,7 @@ pub const Value = extern union { |
| 1017 | .void_value, | 1035 | .void_value, |
| 1018 | .unreachable_value, | 1036 | .unreachable_value, |
| 1019 | .enum_literal, | 1037 | .enum_literal, |
| 1038 | .error_set, | ||
| 1020 | => unreachable, | 1039 | => unreachable, |
| 1021 | 1040 | ||
| 1022 | .zero => false, | 1041 | .zero => false, |
| ... | @@ -1087,6 +1106,7 @@ pub const Value = extern union { | ... | @@ -1087,6 +1106,7 @@ pub const Value = extern union { |
| 1087 | .unreachable_value, | 1106 | .unreachable_value, |
| 1088 | .empty_array, | 1107 | .empty_array, |
| 1089 | .enum_literal, | 1108 | .enum_literal, |
| 1109 | .error_set, | ||
| 1090 | => unreachable, | 1110 | => unreachable, |
| 1091 | 1111 | ||
| 1092 | .zero, | 1112 | .zero, |
| ... | @@ -1230,6 +1250,7 @@ pub const Value = extern union { | ... | @@ -1230,6 +1250,7 @@ pub const Value = extern union { |
| 1230 | .unreachable_value, | 1250 | .unreachable_value, |
| 1231 | .empty_array, | 1251 | .empty_array, |
| 1232 | .enum_literal, | 1252 | .enum_literal, |
| 1253 | .error_set, | ||
| 1233 | => unreachable, | 1254 | => unreachable, |
| 1234 | 1255 | ||
| 1235 | .ref_val => self.cast(Payload.RefVal).?.val, | 1256 | .ref_val => self.cast(Payload.RefVal).?.val, |
| ... | @@ -1310,6 +1331,7 @@ pub const Value = extern union { | ... | @@ -1310,6 +1331,7 @@ pub const Value = extern union { |
| 1310 | .void_value, | 1331 | .void_value, |
| 1311 | .unreachable_value, | 1332 | .unreachable_value, |
| 1312 | .enum_literal, | 1333 | .enum_literal, |
| 1334 | .error_set, | ||
| 1313 | => unreachable, | 1335 | => unreachable, |
| 1314 | 1336 | ||
| 1315 | .empty_array => unreachable, // out of bounds array index | 1337 | .empty_array => unreachable, // out of bounds array index |
| ... | @@ -1407,6 +1429,7 @@ pub const Value = extern union { | ... | @@ -1407,6 +1429,7 @@ pub const Value = extern union { |
| 1407 | .float_128, | 1429 | .float_128, |
| 1408 | .void_value, | 1430 | .void_value, |
| 1409 | .enum_literal, | 1431 | .enum_literal, |
| 1432 | .error_set, | ||
| 1410 | => false, | 1433 | => false, |
| 1411 | 1434 | ||
| 1412 | .undef => unreachable, | 1435 | .undef => unreachable, |
| ... | @@ -1536,6 +1559,13 @@ pub const Value = extern union { | ... | @@ -1536,6 +1559,13 @@ pub const Value = extern union { |
| 1536 | base: Payload = .{ .tag = .float_128 }, | 1559 | base: Payload = .{ .tag = .float_128 }, |
| 1537 | val: f128, | 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 | /// Big enough to fit any non-BigInt value | 1571 | /// Big enough to fit any non-BigInt value |
src-self-hosted/zir.zig+39| ... | @@ -139,6 +139,8 @@ pub const Inst = struct { | ... | @@ -139,6 +139,8 @@ pub const Inst = struct { |
| 139 | ensure_result_non_error, | 139 | ensure_result_non_error, |
| 140 | /// Create a `E!T` type. | 140 | /// Create a `E!T` type. |
| 141 | error_union_type, | 141 | error_union_type, |
| 142 | /// Create an error set. | ||
| 143 | error_set, | ||
| 142 | /// Export the provided Decl as the provided name in the compilation's output object file. | 144 | /// Export the provided Decl as the provided name in the compilation's output object file. |
| 143 | @"export", | 145 | @"export", |
| 144 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer | 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,6 +361,7 @@ pub const Inst = struct { |
| 359 | .condbr => CondBr, | 361 | .condbr => CondBr, |
| 360 | .ptr_type => PtrType, | 362 | .ptr_type => PtrType, |
| 361 | .enum_literal => EnumLiteral, | 363 | .enum_literal => EnumLiteral, |
| 364 | .error_set => ErrorSet, | ||
| 362 | }; | 365 | }; |
| 363 | } | 366 | } |
| 364 | 367 | ||
| ... | @@ -454,6 +457,7 @@ pub const Inst = struct { | ... | @@ -454,6 +457,7 @@ pub const Inst = struct { |
| 454 | .anyframe_type, | 457 | .anyframe_type, |
| 455 | .error_union_type, | 458 | .error_union_type, |
| 456 | .bitnot, | 459 | .bitnot, |
| 460 | .error_set, | ||
| 457 | => false, | 461 | => false, |
| 458 | 462 | ||
| 459 | .@"break", | 463 | .@"break", |
| ... | @@ -924,6 +928,16 @@ pub const Inst = struct { | ... | @@ -924,6 +928,16 @@ pub const Inst = struct { |
| 924 | }, | 928 | }, |
| 925 | kw_args: struct {}, | 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 | pub const ErrorMsg = struct { | 943 | pub const ErrorMsg = struct { |
| ... | @@ -1158,6 +1172,16 @@ const Writer = struct { | ... | @@ -1158,6 +1172,16 @@ const Writer = struct { |
| 1158 | const name = self.loop_table.get(param).?; | 1172 | const name = self.loop_table.get(param).?; |
| 1159 | return std.zig.renderStringLiteral(name, stream); | 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 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), | 1185 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), |
| 1162 | } | 1186 | } |
| 1163 | } | 1187 | } |
| ... | @@ -1555,6 +1579,21 @@ const Parser = struct { | ... | @@ -1555,6 +1579,21 @@ const Parser = struct { |
| 1555 | const name = try self.parseStringLiteral(); | 1579 | const name = try self.parseStringLiteral(); |
| 1556 | return self.loop_table.get(name).?; | 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 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), | 1597 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), |
| 1559 | } | 1598 | } |
| 1560 | return self.fail("TODO parse parameter {}", .{@typeName(T)}); | 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,6 +126,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 126 | .merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?), | 126 | .merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?), |
| 127 | .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), | 127 | .error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?), |
| 128 | .anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?), | 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,6 +436,7 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr |
| 435 | // The bytes references memory inside the ZIR module, which can get deallocated | 436 | // The bytes references memory inside the ZIR module, which can get deallocated |
| 436 | // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena. | 437 | // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena. |
| 437 | var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa); | 438 | var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa); |
| 439 | errdefer new_decl_arena.deinit(); | ||
| 438 | const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes); | 440 | const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes); |
| 439 | 441 | ||
| 440 | const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); | 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,6 +739,30 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In |
| 737 | return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type)); | 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 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 766 | fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 741 | return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{}); | 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,7 +1403,7 @@ fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) Inne |
| 1377 | 1403 | ||
| 1378 | if (host_size != 0 and bit_offset >= host_size * 8) | 1404 | if (host_size != 0 and bit_offset >= host_size * 8) |
| 1379 | return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); | 1405 | return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); |
| 1380 | 1406 | ||
| 1381 | const sentinel = if (inst.kw_args.sentinel) |some| | 1407 | const sentinel = if (inst.kw_args.sentinel) |some| |
| 1382 | (try resolveInstConst(mod, scope, some)).val | 1408 | (try resolveInstConst(mod, scope, some)).val |
| 1383 | else | 1409 | else |