| author | |
| committer | |
| log | 5502160bd23f14b91ac2bd3726a93bdd0b40cc53 |
| tree | 81ced0f54f4c02eb7fd3bdd5d3d1248014f356a6 |
| parent | ae0a219d1f5495acc4d82421fa24d84186c2a40d |
| parent | 0c315e7f7613b085a203e9c94d222e846b5b9e46 |
| signature |
implement anonymous struct literals and anonymous list literals18 files changed, 783 insertions(+), 243 deletions(-)
doc/langref.html.in+112-1| ... | ... | @@ -1734,6 +1734,43 @@ test "array initialization with function calls" { |
| 1734 | 1734 | {#code_end#} |
| 1735 | 1735 | {#see_also|for|Slices#} |
| 1736 | 1736 | |
| 1737 | {#header_open|Anonymous List Literals#} | |
| 1738 | <p>Similar to {#link|Enum Literals#} and {#link|Anonymous Struct Literals#} | |
| 1739 | the type can be omitted from array literals:</p> | |
| 1740 | {#code_begin|test|anon_list#} | |
| 1741 | const std = @import("std"); | |
| 1742 | const assert = std.debug.assert; | |
| 1743 | ||
| 1744 | test "anonymous list literal syntax" { | |
| 1745 | var array: [4]u8 = .{11, 22, 33, 44}; | |
| 1746 | assert(array[0] == 11); | |
| 1747 | assert(array[1] == 22); | |
| 1748 | assert(array[2] == 33); | |
| 1749 | assert(array[3] == 44); | |
| 1750 | } | |
| 1751 | {#code_end#} | |
| 1752 | <p> | |
| 1753 | If there is no type in the result location then an anonymous list literal actually | |
| 1754 | turns into a {#link|struct#} with numbered field names: | |
| 1755 | </p> | |
| 1756 | {#code_begin|test|infer_list_literal#} | |
| 1757 | const std = @import("std"); | |
| 1758 | const assert = std.debug.assert; | |
| 1759 | ||
| 1760 | test "fully anonymous list literal" { | |
| 1761 | dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"}); | |
| 1762 | } | |
| 1763 | ||
| 1764 | fn dump(args: var) void { | |
| 1765 | assert(args.@"0" == 1234); | |
| 1766 | assert(args.@"1" == 12.34); | |
| 1767 | assert(args.@"2"); | |
| 1768 | assert(args.@"3"[0] == 'h'); | |
| 1769 | assert(args.@"3"[1] == 'i'); | |
| 1770 | } | |
| 1771 | {#code_end#} | |
| 1772 | {#header_close#} | |
| 1773 | ||
| 1737 | 1774 | {#header_open|Multidimensional Arrays#} |
| 1738 | 1775 | <p> |
| 1739 | 1776 | Mutlidimensional arrays can be created by nesting arrays: |
| ... | ... | @@ -2526,7 +2563,8 @@ test "overaligned pointer to packed struct" { |
| 2526 | 2563 | Don't worry, there will be a good solution for this use case in zig. |
| 2527 | 2564 | </p> |
| 2528 | 2565 | {#header_close#} |
| 2529 | {#header_open|struct Naming#} | |
| 2566 | ||
| 2567 | {#header_open|Struct Naming#} | |
| 2530 | 2568 | <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p> |
| 2531 | 2569 | <ul> |
| 2532 | 2570 | <li>If the struct is in the initialization expression of a variable, it gets named after |
| ... | ... | @@ -2552,6 +2590,53 @@ fn List(comptime T: type) type { |
| 2552 | 2590 | } |
| 2553 | 2591 | {#code_end#} |
| 2554 | 2592 | {#header_close#} |
| 2593 | ||
| 2594 | {#header_open|Anonymous Struct Literals#} | |
| 2595 | <p> | |
| 2596 | Zig allows omitting the struct type of a literal. When the result is {#link|coerced|Type Coercion#}, | |
| 2597 | the struct literal will directly instantiate the result location, with no copy: | |
| 2598 | </p> | |
| 2599 | {#code_begin|test|struct_result#} | |
| 2600 | const std = @import("std"); | |
| 2601 | const assert = std.debug.assert; | |
| 2602 | ||
| 2603 | const Point = struct {x: i32, y: i32}; | |
| 2604 | ||
| 2605 | test "anonymous struct literal" { | |
| 2606 | var pt: Point = .{ | |
| 2607 | .x = 13, | |
| 2608 | .y = 67, | |
| 2609 | }; | |
| 2610 | assert(pt.x == 13); | |
| 2611 | assert(pt.y == 67); | |
| 2612 | } | |
| 2613 | {#code_end#} | |
| 2614 | <p> | |
| 2615 | The struct type can be inferred. Here the result location does not include a type, and | |
| 2616 | so Zig infers the type: | |
| 2617 | </p> | |
| 2618 | {#code_begin|test|struct_anon#} | |
| 2619 | const std = @import("std"); | |
| 2620 | const assert = std.debug.assert; | |
| 2621 | ||
| 2622 | test "fully anonymous struct" { | |
| 2623 | dump(.{ | |
| 2624 | .int = @as(u32, 1234), | |
| 2625 | .float = @as(f64, 12.34), | |
| 2626 | .b = true, | |
| 2627 | .s = "hi", | |
| 2628 | }); | |
| 2629 | } | |
| 2630 | ||
| 2631 | fn dump(args: var) void { | |
| 2632 | assert(args.int == 1234); | |
| 2633 | assert(args.float == 12.34); | |
| 2634 | assert(args.b); | |
| 2635 | assert(args.s[0] == 'h'); | |
| 2636 | assert(args.s[1] == 'i'); | |
| 2637 | } | |
| 2638 | {#code_end#} | |
| 2639 | {#header_close#} | |
| 2555 | 2640 | {#see_also|comptime|@fieldParentPtr#} |
| 2556 | 2641 | {#header_close#} |
| 2557 | 2642 | {#header_open|enum#} |
| ... | ... | @@ -2906,6 +2991,32 @@ test "@tagName" { |
| 2906 | 2991 | <p>A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible |
| 2907 | 2992 | to be in a {#link|packed struct#}. |
| 2908 | 2993 | {#header_close#} |
| 2994 | ||
| 2995 | {#header_open|Anonymous Union Literals#} | |
| 2996 | <p>{#link|Anonymous Struct Literals#} syntax can be used to initialize unions without specifying | |
| 2997 | the type:</p> | |
| 2998 | {#code_begin|test|anon_union#} | |
| 2999 | const std = @import("std"); | |
| 3000 | const assert = std.debug.assert; | |
| 3001 | ||
| 3002 | const Number = union { | |
| 3003 | int: i32, | |
| 3004 | float: f64, | |
| 3005 | }; | |
| 3006 | ||
| 3007 | test "anonymous union literal syntax" { | |
| 3008 | var i: Number = .{.int = 42}; | |
| 3009 | var f = makeNumber(); | |
| 3010 | assert(i.int == 42); | |
| 3011 | assert(f.float == 12.34); | |
| 3012 | } | |
| 3013 | ||
| 3014 | fn makeNumber() Number { | |
| 3015 | return .{.float = 12.34}; | |
| 3016 | } | |
| 3017 | {#code_end#} | |
| 3018 | {#header_close#} | |
| 3019 | ||
| 2909 | 3020 | {#header_close#} |
| 2910 | 3021 | |
| 2911 | 3022 | {#header_open|blocks#} |
lib/std/builtin.zig+2-31| ... | ... | @@ -90,40 +90,11 @@ pub const Mode = enum { |
| 90 | 90 | ReleaseSmall, |
| 91 | 91 | }; |
| 92 | 92 | |
| 93 | /// This data structure is used by the Zig language code generation and | |
| 94 | /// therefore must be kept in sync with the compiler implementation. | |
| 95 | pub const TypeId = enum { | |
| 96 | Type, | |
| 97 | Void, | |
| 98 | Bool, | |
| 99 | NoReturn, | |
| 100 | Int, | |
| 101 | Float, | |
| 102 | Pointer, | |
| 103 | Array, | |
| 104 | Struct, | |
| 105 | ComptimeFloat, | |
| 106 | ComptimeInt, | |
| 107 | Undefined, | |
| 108 | Null, | |
| 109 | Optional, | |
| 110 | ErrorUnion, | |
| 111 | ErrorSet, | |
| 112 | Enum, | |
| 113 | Union, | |
| 114 | Fn, | |
| 115 | BoundFn, | |
| 116 | ArgTuple, | |
| 117 | Opaque, | |
| 118 | Frame, | |
| 119 | AnyFrame, | |
| 120 | Vector, | |
| 121 | EnumLiteral, | |
| 122 | }; | |
| 93 | pub const TypeId = @TagType(TypeInfo); | |
| 123 | 94 | |
| 124 | 95 | /// This data structure is used by the Zig language code generation and |
| 125 | 96 | /// therefore must be kept in sync with the compiler implementation. |
| 126 | pub const TypeInfo = union(TypeId) { | |
| 97 | pub const TypeInfo = union(enum) { | |
| 127 | 98 | Type: void, |
| 128 | 99 | Void: void, |
| 129 | 100 | Bool: void, |
lib/std/zig/ast.zig+17-4| ... | ... | @@ -1648,10 +1648,15 @@ pub const Node = struct { |
| 1648 | 1648 | |
| 1649 | 1649 | pub const SuffixOp = struct { |
| 1650 | 1650 | base: Node, |
| 1651 | lhs: *Node, | |
| 1651 | lhs: Lhs, | |
| 1652 | 1652 | op: Op, |
| 1653 | 1653 | rtoken: TokenIndex, |
| 1654 | 1654 | |
| 1655 | pub const Lhs = union(enum) { | |
| 1656 | node: *Node, | |
| 1657 | dot: TokenIndex, | |
| 1658 | }; | |
| 1659 | ||
| 1655 | 1660 | pub const Op = union(enum) { |
| 1656 | 1661 | Call: Call, |
| 1657 | 1662 | ArrayAccess: *Node, |
| ... | ... | @@ -1679,8 +1684,13 @@ pub const Node = struct { |
| 1679 | 1684 | pub fn iterate(self: *SuffixOp, index: usize) ?*Node { |
| 1680 | 1685 | var i = index; |
| 1681 | 1686 | |
| 1682 | if (i < 1) return self.lhs; | |
| 1683 | i -= 1; | |
| 1687 | switch (self.lhs) { | |
| 1688 | .node => |node| { | |
| 1689 | if (i == 0) return node; | |
| 1690 | i -= 1; | |
| 1691 | }, | |
| 1692 | .dot => {}, | |
| 1693 | } | |
| 1684 | 1694 | |
| 1685 | 1695 | switch (self.op) { |
| 1686 | 1696 | .Call => |*call_info| { |
| ... | ... | @@ -1721,7 +1731,10 @@ pub const Node = struct { |
| 1721 | 1731 | .Call => |*call_info| if (call_info.async_token) |async_token| return async_token, |
| 1722 | 1732 | else => {}, |
| 1723 | 1733 | } |
| 1724 | return self.lhs.firstToken(); | |
| 1734 | switch (self.lhs) { | |
| 1735 | .node => |node| return node.firstToken(), | |
| 1736 | .dot => |dot| return dot, | |
| 1737 | } | |
| 1725 | 1738 | } |
| 1726 | 1739 | |
| 1727 | 1740 | pub fn lastToken(self: *const SuffixOp) TokenIndex { |
lib/std/zig/parse.zig+32-20| ... | ... | @@ -1026,16 +1026,16 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1026 | 1026 | /// CurlySuffixExpr <- TypeExpr InitList? |
| 1027 | 1027 | fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1028 | 1028 | const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null; |
| 1029 | const init_list = (try parseInitList(arena, it, tree)) orelse return type_expr; | |
| 1030 | init_list.cast(Node.SuffixOp).?.lhs = type_expr; | |
| 1031 | return init_list; | |
| 1029 | const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr; | |
| 1030 | suffix_op.lhs.node = type_expr; | |
| 1031 | return &suffix_op.base; | |
| 1032 | 1032 | } |
| 1033 | 1033 | |
| 1034 | 1034 | /// InitList |
| 1035 | 1035 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE |
| 1036 | 1036 | /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE |
| 1037 | 1037 | /// / LBRACE RBRACE |
| 1038 | fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 1038 | fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp { | |
| 1039 | 1039 | const lbrace = eatToken(it, .LBrace) orelse return null; |
| 1040 | 1040 | var init_list = Node.SuffixOp.Op.InitList.init(arena); |
| 1041 | 1041 | |
| ... | ... | @@ -1064,11 +1064,11 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1064 | 1064 | const node = try arena.create(Node.SuffixOp); |
| 1065 | 1065 | node.* = Node.SuffixOp{ |
| 1066 | 1066 | .base = Node{ .id = .SuffixOp }, |
| 1067 | .lhs = undefined, // set by caller | |
| 1067 | .lhs = .{.node = undefined}, // set by caller | |
| 1068 | 1068 | .op = op, |
| 1069 | 1069 | .rtoken = try expectToken(it, tree, .RBrace), |
| 1070 | 1070 | }; |
| 1071 | return &node.base; | |
| 1071 | return node; | |
| 1072 | 1072 | } |
| 1073 | 1073 | |
| 1074 | 1074 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr |
| ... | ... | @@ -1117,7 +1117,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1117 | 1117 | |
| 1118 | 1118 | while (try parseSuffixOp(arena, it, tree)) |node| { |
| 1119 | 1119 | switch (node.id) { |
| 1120 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, | |
| 1120 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, | |
| 1121 | 1121 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, |
| 1122 | 1122 | else => unreachable, |
| 1123 | 1123 | } |
| ... | ... | @@ -1133,7 +1133,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1133 | 1133 | const node = try arena.create(Node.SuffixOp); |
| 1134 | 1134 | node.* = Node.SuffixOp{ |
| 1135 | 1135 | .base = Node{ .id = .SuffixOp }, |
| 1136 | .lhs = res, | |
| 1136 | .lhs = .{.node = res}, | |
| 1137 | 1137 | .op = Node.SuffixOp.Op{ |
| 1138 | 1138 | .Call = Node.SuffixOp.Op.Call{ |
| 1139 | 1139 | .params = params.list, |
| ... | ... | @@ -1150,7 +1150,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1150 | 1150 | while (true) { |
| 1151 | 1151 | if (try parseSuffixOp(arena, it, tree)) |node| { |
| 1152 | 1152 | switch (node.id) { |
| 1153 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, | |
| 1153 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, | |
| 1154 | 1154 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, |
| 1155 | 1155 | else => unreachable, |
| 1156 | 1156 | } |
| ... | ... | @@ -1161,7 +1161,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1161 | 1161 | const call = try arena.create(Node.SuffixOp); |
| 1162 | 1162 | call.* = Node.SuffixOp{ |
| 1163 | 1163 | .base = Node{ .id = .SuffixOp }, |
| 1164 | .lhs = res, | |
| 1164 | .lhs = .{.node = res}, | |
| 1165 | 1165 | .op = Node.SuffixOp.Op{ |
| 1166 | 1166 | .Call = Node.SuffixOp.Op.Call{ |
| 1167 | 1167 | .params = params.list, |
| ... | ... | @@ -1215,7 +1215,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1215 | 1215 | return &node.base; |
| 1216 | 1216 | } |
| 1217 | 1217 | if (try parseContainerDecl(arena, it, tree)) |node| return node; |
| 1218 | if (try parseEnumLiteral(arena, it, tree)) |node| return node; | |
| 1218 | if (try parseAnonLiteral(arena, it, tree)) |node| return node; | |
| 1219 | 1219 | if (try parseErrorSetDecl(arena, it, tree)) |node| return node; |
| 1220 | 1220 | if (try parseFloatLiteral(arena, it, tree)) |node| return node; |
| 1221 | 1221 | if (try parseFnProto(arena, it, tree)) |node| return node; |
| ... | ... | @@ -1494,16 +1494,28 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1494 | 1494 | } |
| 1495 | 1495 | |
| 1496 | 1496 | /// DOT IDENTIFIER |
| 1497 | fn parseEnumLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 1497 | fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 1498 | 1498 | const dot = eatToken(it, .Period) orelse return null; |
| 1499 | const name = try expectToken(it, tree, .Identifier); | |
| 1500 | const node = try arena.create(Node.EnumLiteral); | |
| 1501 | node.* = Node.EnumLiteral{ | |
| 1502 | .base = Node{ .id = .EnumLiteral }, | |
| 1503 | .dot = dot, | |
| 1504 | .name = name, | |
| 1505 | }; | |
| 1506 | return &node.base; | |
| 1499 | ||
| 1500 | // anon enum literal | |
| 1501 | if (eatToken(it, .Identifier)) |name| { | |
| 1502 | const node = try arena.create(Node.EnumLiteral); | |
| 1503 | node.* = Node.EnumLiteral{ | |
| 1504 | .base = Node{ .id = .EnumLiteral }, | |
| 1505 | .dot = dot, | |
| 1506 | .name = name, | |
| 1507 | }; | |
| 1508 | return &node.base; | |
| 1509 | } | |
| 1510 | ||
| 1511 | // anon container literal | |
| 1512 | if (try parseInitList(arena, it, tree)) |node| { | |
| 1513 | node.lhs = .{.dot = dot}; | |
| 1514 | return &node.base; | |
| 1515 | } | |
| 1516 | ||
| 1517 | putBackToken(it, dot); | |
| 1518 | return null; | |
| 1507 | 1519 | } |
| 1508 | 1520 | |
| 1509 | 1521 | /// AsmOutput <- COLON AsmOutputList AsmInput? |
lib/std/zig/parser_test.zig+17| ... | ... | @@ -1,3 +1,20 @@ |
| 1 | test "zig fmt: anon struct literal syntax" { | |
| 2 | try testCanonical( | |
| 3 | \\const x = .{ | |
| 4 | \\ .a = b, | |
| 5 | \\ .c = d, | |
| 6 | \\}; | |
| 7 | \\ | |
| 8 | ); | |
| 9 | } | |
| 10 | ||
| 11 | test "zig fmt: anon list literal syntax" { | |
| 12 | try testCanonical( | |
| 13 | \\const x = .{ a, b, c }; | |
| 14 | \\ | |
| 15 | ); | |
| 16 | } | |
| 17 | ||
| 1 | 18 | test "zig fmt: async function" { |
| 2 | 19 | try testCanonical( |
| 3 | 20 | \\pub const Server = struct { |
lib/std/zig/render.zig+42-15| ... | ... | @@ -538,9 +538,9 @@ fn renderExpression( |
| 538 | 538 | try renderToken(tree, stream, async_token, indent, start_col, Space.Space); |
| 539 | 539 | } |
| 540 | 540 | |
| 541 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 541 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | |
| 542 | 542 | |
| 543 | const lparen = tree.nextToken(suffix_op.lhs.lastToken()); | |
| 543 | const lparen = tree.nextToken(suffix_op.lhs.node.lastToken()); | |
| 544 | 544 | |
| 545 | 545 | if (call_info.params.len == 0) { |
| 546 | 546 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); |
| ... | ... | @@ -598,7 +598,7 @@ fn renderExpression( |
| 598 | 598 | const lbracket = tree.prevToken(index_expr.firstToken()); |
| 599 | 599 | const rbracket = tree.nextToken(index_expr.lastToken()); |
| 600 | 600 | |
| 601 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 601 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | |
| 602 | 602 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 603 | 603 | |
| 604 | 604 | const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; |
| ... | ... | @@ -616,18 +616,18 @@ fn renderExpression( |
| 616 | 616 | }, |
| 617 | 617 | |
| 618 | 618 | ast.Node.SuffixOp.Op.Deref => { |
| 619 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 619 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | |
| 620 | 620 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* |
| 621 | 621 | }, |
| 622 | 622 | |
| 623 | 623 | ast.Node.SuffixOp.Op.UnwrapOptional => { |
| 624 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 624 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | |
| 625 | 625 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . |
| 626 | 626 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? |
| 627 | 627 | }, |
| 628 | 628 | |
| 629 | 629 | @TagType(ast.Node.SuffixOp.Op).Slice => |range| { |
| 630 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 630 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | |
| 631 | 631 | |
| 632 | 632 | const lbracket = tree.prevToken(range.start.firstToken()); |
| 633 | 633 | const dotdot = tree.nextToken(range.start.lastToken()); |
| ... | ... | @@ -647,10 +647,16 @@ fn renderExpression( |
| 647 | 647 | }, |
| 648 | 648 | |
| 649 | 649 | ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| { |
| 650 | const lbrace = tree.nextToken(suffix_op.lhs.lastToken()); | |
| 650 | const lbrace = switch (suffix_op.lhs) { | |
| 651 | .dot => |dot| tree.nextToken(dot), | |
| 652 | .node => |node| tree.nextToken(node.lastToken()), | |
| 653 | }; | |
| 651 | 654 | |
| 652 | 655 | if (field_inits.len == 0) { |
| 653 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 656 | switch (suffix_op.lhs) { | |
| 657 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 658 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 659 | } | |
| 654 | 660 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); |
| 655 | 661 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 656 | 662 | } |
| ... | ... | @@ -691,7 +697,10 @@ fn renderExpression( |
| 691 | 697 | break :blk; |
| 692 | 698 | } |
| 693 | 699 | |
| 694 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 700 | switch (suffix_op.lhs) { | |
| 701 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 702 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 703 | } | |
| 695 | 704 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| 696 | 705 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); |
| 697 | 706 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| ... | ... | @@ -699,7 +708,10 @@ fn renderExpression( |
| 699 | 708 | |
| 700 | 709 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { |
| 701 | 710 | // render all on one line, no trailing comma |
| 702 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 711 | switch (suffix_op.lhs) { | |
| 712 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 713 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 714 | } | |
| 703 | 715 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| 704 | 716 | |
| 705 | 717 | var it = field_inits.iterator(0); |
| ... | ... | @@ -719,7 +731,10 @@ fn renderExpression( |
| 719 | 731 | |
| 720 | 732 | const new_indent = indent + indent_delta; |
| 721 | 733 | |
| 722 | try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.lhs, Space.None); | |
| 734 | switch (suffix_op.lhs) { | |
| 735 | .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), | |
| 736 | .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), | |
| 737 | } | |
| 723 | 738 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); |
| 724 | 739 | |
| 725 | 740 | var it = field_inits.iterator(0); |
| ... | ... | @@ -743,23 +758,35 @@ fn renderExpression( |
| 743 | 758 | }, |
| 744 | 759 | |
| 745 | 760 | ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| { |
| 746 | const lbrace = tree.nextToken(suffix_op.lhs.lastToken()); | |
| 761 | const lbrace = switch (suffix_op.lhs) { | |
| 762 | .dot => |dot| tree.nextToken(dot), | |
| 763 | .node => |node| tree.nextToken(node.lastToken()), | |
| 764 | }; | |
| 747 | 765 | |
| 748 | 766 | if (exprs.len == 0) { |
| 749 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 767 | switch (suffix_op.lhs) { | |
| 768 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 769 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 770 | } | |
| 750 | 771 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| 751 | 772 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 752 | 773 | } |
| 753 | 774 | if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) { |
| 754 | 775 | const expr = exprs.at(0).*; |
| 755 | 776 | |
| 756 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 777 | switch (suffix_op.lhs) { | |
| 778 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 779 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 780 | } | |
| 757 | 781 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| 758 | 782 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); |
| 759 | 783 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 760 | 784 | } |
| 761 | 785 | |
| 762 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | |
| 786 | switch (suffix_op.lhs) { | |
| 787 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | |
| 788 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | |
| 789 | } | |
| 763 | 790 | |
| 764 | 791 | // scan to find row size |
| 765 | 792 | const maybe_row_size: ?usize = blk: { |
src/all_types.hpp+17-3| ... | ... | @@ -1187,10 +1187,22 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 1187 | 1187 | static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX; |
| 1188 | 1188 | static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1; |
| 1189 | 1189 | |
| 1190 | struct InferredStructField { | |
| 1191 | ZigType *inferred_struct_type; | |
| 1192 | Buf *field_name; | |
| 1193 | }; | |
| 1194 | ||
| 1190 | 1195 | struct ZigTypePointer { |
| 1191 | 1196 | ZigType *child_type; |
| 1192 | 1197 | ZigType *slice_parent; |
| 1193 | 1198 | |
| 1199 | // Anonymous struct literal syntax uses this when the result location has | |
| 1200 | // no type in it. This field is null if this pointer does not refer to | |
| 1201 | // a field of a currently-being-inferred struct type. | |
| 1202 | // When this is non-null, the pointer is pointing to the base of the inferred | |
| 1203 | // struct. | |
| 1204 | InferredStructField *inferred_struct_field; | |
| 1205 | ||
| 1194 | 1206 | PtrLen ptr_len; |
| 1195 | 1207 | uint32_t explicit_alignment; // 0 means use ABI alignment |
| 1196 | 1208 | |
| ... | ... | @@ -1237,6 +1249,7 @@ struct TypeStructField { |
| 1237 | 1249 | enum ResolveStatus { |
| 1238 | 1250 | ResolveStatusUnstarted, |
| 1239 | 1251 | ResolveStatusInvalid, |
| 1252 | ResolveStatusBeingInferred, | |
| 1240 | 1253 | ResolveStatusZeroBitsKnown, |
| 1241 | 1254 | ResolveStatusAlignmentKnown, |
| 1242 | 1255 | ResolveStatusSizeKnown, |
| ... | ... | @@ -1285,6 +1298,7 @@ struct ZigTypeStruct { |
| 1285 | 1298 | bool requires_comptime; |
| 1286 | 1299 | bool resolve_loop_flag_zero_bits; |
| 1287 | 1300 | bool resolve_loop_flag_other; |
| 1301 | bool is_inferred; | |
| 1288 | 1302 | }; |
| 1289 | 1303 | |
| 1290 | 1304 | struct ZigTypeOptional { |
| ... | ... | @@ -1741,6 +1755,7 @@ struct TypeId { |
| 1741 | 1755 | union { |
| 1742 | 1756 | struct { |
| 1743 | 1757 | ZigType *child_type; |
| 1758 | InferredStructField *inferred_struct_field; | |
| 1744 | 1759 | PtrLen ptr_len; |
| 1745 | 1760 | uint32_t alignment; |
| 1746 | 1761 | |
| ... | ... | @@ -2812,7 +2827,7 @@ struct IrInstructionElemPtr { |
| 2812 | 2827 | |
| 2813 | 2828 | IrInstruction *array_ptr; |
| 2814 | 2829 | IrInstruction *elem_index; |
| 2815 | IrInstruction *init_array_type; | |
| 2830 | AstNode *init_array_type_source_node; | |
| 2816 | 2831 | PtrLen ptr_len; |
| 2817 | 2832 | bool safety_check_on; |
| 2818 | 2833 | }; |
| ... | ... | @@ -2909,11 +2924,11 @@ struct IrInstructionResizeSlice { |
| 2909 | 2924 | struct IrInstructionContainerInitList { |
| 2910 | 2925 | IrInstruction base; |
| 2911 | 2926 | |
| 2912 | IrInstruction *container_type; | |
| 2913 | 2927 | IrInstruction *elem_type; |
| 2914 | 2928 | size_t item_count; |
| 2915 | 2929 | IrInstruction **elem_result_loc_list; |
| 2916 | 2930 | IrInstruction *result_loc; |
| 2931 | AstNode *init_array_type_source_node; | |
| 2917 | 2932 | }; |
| 2918 | 2933 | |
| 2919 | 2934 | struct IrInstructionContainerInitFieldsField { |
| ... | ... | @@ -2926,7 +2941,6 @@ struct IrInstructionContainerInitFieldsField { |
| 2926 | 2941 | struct IrInstructionContainerInitFields { |
| 2927 | 2942 | IrInstruction base; |
| 2928 | 2943 | |
| 2929 | IrInstruction *container_type; | |
| 2930 | 2944 | size_t field_count; |
| 2931 | 2945 | IrInstructionContainerInitFieldsField *fields; |
| 2932 | 2946 | IrInstruction *result_loc; |
src/analyze.cpp+91-40| ... | ... | @@ -140,7 +140,6 @@ void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope |
| 140 | 140 | static ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, |
| 141 | 141 | ZigType *import, Buf *bare_name) |
| 142 | 142 | { |
| 143 | assert(node == nullptr || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr); | |
| 144 | 143 | ScopeDecls *scope = allocate<ScopeDecls>(1); |
| 145 | 144 | init_scope(g, &scope->base, ScopeIdDecls, node, parent); |
| 146 | 145 | scope->decl_table.init(4); |
| ... | ... | @@ -346,6 +345,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 346 | 345 | switch (status) { |
| 347 | 346 | case ResolveStatusInvalid: |
| 348 | 347 | zig_unreachable(); |
| 348 | case ResolveStatusBeingInferred: | |
| 349 | zig_unreachable(); | |
| 349 | 350 | case ResolveStatusUnstarted: |
| 350 | 351 | case ResolveStatusZeroBitsKnown: |
| 351 | 352 | return true; |
| ... | ... | @@ -362,6 +363,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 362 | 363 | switch (status) { |
| 363 | 364 | case ResolveStatusInvalid: |
| 364 | 365 | zig_unreachable(); |
| 366 | case ResolveStatusBeingInferred: | |
| 367 | zig_unreachable(); | |
| 365 | 368 | case ResolveStatusUnstarted: |
| 366 | 369 | return true; |
| 367 | 370 | case ResolveStatusZeroBitsKnown: |
| ... | ... | @@ -483,7 +486,7 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { |
| 483 | 486 | ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, |
| 484 | 487 | bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, |
| 485 | 488 | uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, |
| 486 | uint32_t vector_index) | |
| 489 | uint32_t vector_index, InferredStructField *inferred_struct_field) | |
| 487 | 490 | { |
| 488 | 491 | assert(ptr_len != PtrLenC || allow_zero); |
| 489 | 492 | assert(!type_is_invalid(child_type)); |
| ... | ... | @@ -506,7 +509,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con |
| 506 | 509 | TypeId type_id = {}; |
| 507 | 510 | ZigType **parent_pointer = nullptr; |
| 508 | 511 | if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || |
| 509 | allow_zero || vector_index != VECTOR_INDEX_NONE) | |
| 512 | allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr) | |
| 510 | 513 | { |
| 511 | 514 | type_id.id = ZigTypeIdPointer; |
| 512 | 515 | type_id.data.pointer.child_type = child_type; |
| ... | ... | @@ -518,6 +521,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con |
| 518 | 521 | type_id.data.pointer.ptr_len = ptr_len; |
| 519 | 522 | type_id.data.pointer.allow_zero = allow_zero; |
| 520 | 523 | type_id.data.pointer.vector_index = vector_index; |
| 524 | type_id.data.pointer.inferred_struct_field = inferred_struct_field; | |
| 521 | 525 | |
| 522 | 526 | auto existing_entry = g->type_table.maybe_get(type_id); |
| 523 | 527 | if (existing_entry) |
| ... | ... | @@ -545,8 +549,15 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con |
| 545 | 549 | } |
| 546 | 550 | buf_resize(&entry->name, 0); |
| 547 | 551 | if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) { |
| 548 | buf_appendf(&entry->name, "%s%s%s%s%s", | |
| 549 | star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); | |
| 552 | if (inferred_struct_field == nullptr) { | |
| 553 | buf_appendf(&entry->name, "%s%s%s%s%s", | |
| 554 | star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); | |
| 555 | } else { | |
| 556 | buf_appendf(&entry->name, "(%s%s%s%s field '%s' of %s)", | |
| 557 | star_str, const_str, volatile_str, allow_zero_str, | |
| 558 | buf_ptr(inferred_struct_field->field_name), | |
| 559 | buf_ptr(&inferred_struct_field->inferred_struct_type->name)); | |
| 560 | } | |
| 550 | 561 | } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) { |
| 551 | 562 | buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, |
| 552 | 563 | const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); |
| ... | ... | @@ -603,6 +614,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con |
| 603 | 614 | entry->data.pointer.host_int_bytes = host_int_bytes; |
| 604 | 615 | entry->data.pointer.allow_zero = allow_zero; |
| 605 | 616 | entry->data.pointer.vector_index = vector_index; |
| 617 | entry->data.pointer.inferred_struct_field = inferred_struct_field; | |
| 606 | 618 | |
| 607 | 619 | if (parent_pointer) { |
| 608 | 620 | *parent_pointer = entry; |
| ... | ... | @@ -617,12 +629,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 617 | 629 | uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) |
| 618 | 630 | { |
| 619 | 631 | return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, |
| 620 | byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE); | |
| 632 | byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr); | |
| 621 | 633 | } |
| 622 | 634 | |
| 623 | 635 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { |
| 624 | 636 | return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, |
| 625 | VECTOR_INDEX_NONE); | |
| 637 | VECTOR_INDEX_NONE, nullptr); | |
| 626 | 638 | } |
| 627 | 639 | |
| 628 | 640 | ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| ... | ... | @@ -2079,7 +2091,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 2079 | 2091 | } |
| 2080 | 2092 | |
| 2081 | 2093 | assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); |
| 2082 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2094 | assert(decl_node->type == NodeTypeContainerDecl || decl_node->type == NodeTypeContainerInitExpr); | |
| 2083 | 2095 | |
| 2084 | 2096 | size_t field_count = struct_type->data.structure.src_field_count; |
| 2085 | 2097 | |
| ... | ... | @@ -2667,7 +2679,6 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2667 | 2679 | return ErrorNone; |
| 2668 | 2680 | |
| 2669 | 2681 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 2670 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2671 | 2682 | |
| 2672 | 2683 | if (struct_type->data.structure.resolve_loop_flag_zero_bits) { |
| 2673 | 2684 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| ... | ... | @@ -2678,29 +2689,46 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2678 | 2689 | } |
| 2679 | 2690 | return ErrorSemanticAnalyzeFail; |
| 2680 | 2691 | } |
| 2681 | ||
| 2682 | 2692 | struct_type->data.structure.resolve_loop_flag_zero_bits = true; |
| 2683 | 2693 | |
| 2684 | assert(!struct_type->data.structure.fields); | |
| 2685 | size_t field_count = decl_node->data.container_decl.fields.length; | |
| 2686 | struct_type->data.structure.src_field_count = (uint32_t)field_count; | |
| 2687 | struct_type->data.structure.fields = allocate<TypeStructField>(field_count); | |
| 2694 | size_t field_count; | |
| 2695 | if (decl_node->type == NodeTypeContainerDecl) { | |
| 2696 | field_count = decl_node->data.container_decl.fields.length; | |
| 2697 | struct_type->data.structure.src_field_count = (uint32_t)field_count; | |
| 2698 | ||
| 2699 | src_assert(struct_type->data.structure.fields == nullptr, decl_node); | |
| 2700 | struct_type->data.structure.fields = allocate<TypeStructField>(field_count); | |
| 2701 | } else if (decl_node->type == NodeTypeContainerInitExpr) { | |
| 2702 | src_assert(struct_type->data.structure.is_inferred, decl_node); | |
| 2703 | src_assert(struct_type->data.structure.fields != nullptr, decl_node); | |
| 2704 | ||
| 2705 | field_count = struct_type->data.structure.src_field_count; | |
| 2706 | } else zig_unreachable(); | |
| 2707 | ||
| 2688 | 2708 | struct_type->data.structure.fields_by_name.init(field_count); |
| 2689 | 2709 | |
| 2690 | 2710 | Scope *scope = &struct_type->data.structure.decls_scope->base; |
| 2691 | 2711 | |
| 2692 | 2712 | size_t gen_field_index = 0; |
| 2693 | 2713 | for (size_t i = 0; i < field_count; i += 1) { |
| 2694 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 2695 | 2714 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| 2696 | type_struct_field->name = field_node->data.struct_field.name; | |
| 2697 | type_struct_field->decl_node = field_node; | |
| 2698 | 2715 | |
| 2699 | if (field_node->data.struct_field.type == nullptr) { | |
| 2700 | add_node_error(g, field_node, buf_sprintf("struct field missing type")); | |
| 2701 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2702 | return ErrorSemanticAnalyzeFail; | |
| 2703 | } | |
| 2716 | AstNode *field_node; | |
| 2717 | if (decl_node->type == NodeTypeContainerDecl) { | |
| 2718 | field_node = decl_node->data.container_decl.fields.at(i); | |
| 2719 | type_struct_field->name = field_node->data.struct_field.name; | |
| 2720 | type_struct_field->decl_node = field_node; | |
| 2721 | ||
| 2722 | if (field_node->data.struct_field.type == nullptr) { | |
| 2723 | add_node_error(g, field_node, buf_sprintf("struct field missing type")); | |
| 2724 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2725 | return ErrorSemanticAnalyzeFail; | |
| 2726 | } | |
| 2727 | } else if (decl_node->type == NodeTypeContainerInitExpr) { | |
| 2728 | field_node = type_struct_field->decl_node; | |
| 2729 | ||
| 2730 | src_assert(type_struct_field->type_entry != nullptr, field_node); | |
| 2731 | } else zig_unreachable(); | |
| 2704 | 2732 | |
| 2705 | 2733 | auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field); |
| 2706 | 2734 | if (field_entry != nullptr) { |
| ... | ... | @@ -2711,16 +2739,21 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2711 | 2739 | return ErrorSemanticAnalyzeFail; |
| 2712 | 2740 | } |
| 2713 | 2741 | |
| 2714 | ConstExprValue *field_type_val = analyze_const_value(g, scope, | |
| 2715 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | |
| 2716 | if (type_is_invalid(field_type_val->type)) { | |
| 2717 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2718 | return ErrorSemanticAnalyzeFail; | |
| 2719 | } | |
| 2720 | assert(field_type_val->special != ConstValSpecialRuntime); | |
| 2721 | type_struct_field->type_val = field_type_val; | |
| 2722 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) | |
| 2723 | return ErrorSemanticAnalyzeFail; | |
| 2742 | ConstExprValue *field_type_val; | |
| 2743 | if (decl_node->type == NodeTypeContainerDecl) { | |
| 2744 | field_type_val = analyze_const_value(g, scope, | |
| 2745 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | |
| 2746 | if (type_is_invalid(field_type_val->type)) { | |
| 2747 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2748 | return ErrorSemanticAnalyzeFail; | |
| 2749 | } | |
| 2750 | assert(field_type_val->special != ConstValSpecialRuntime); | |
| 2751 | type_struct_field->type_val = field_type_val; | |
| 2752 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) | |
| 2753 | return ErrorSemanticAnalyzeFail; | |
| 2754 | } else if (decl_node->type == NodeTypeContainerInitExpr) { | |
| 2755 | field_type_val = type_struct_field->type_val; | |
| 2756 | } else zig_unreachable(); | |
| 2724 | 2757 | |
| 2725 | 2758 | bool field_is_opaque_type; |
| 2726 | 2759 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { |
| ... | ... | @@ -2804,7 +2837,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2804 | 2837 | } |
| 2805 | 2838 | |
| 2806 | 2839 | struct_type->data.structure.resolve_loop_flag_other = true; |
| 2807 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2840 | assert(decl_node->type == NodeTypeContainerDecl || decl_node->type == NodeTypeContainerInitExpr); | |
| 2808 | 2841 | |
| 2809 | 2842 | size_t field_count = struct_type->data.structure.src_field_count; |
| 2810 | 2843 | bool packed = struct_type->data.structure.layout == ContainerLayoutPacked; |
| ... | ... | @@ -2814,7 +2847,8 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2814 | 2847 | if (field->gen_index == SIZE_MAX) |
| 2815 | 2848 | continue; |
| 2816 | 2849 | |
| 2817 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; | |
| 2850 | AstNode *align_expr = (field->decl_node->type == NodeTypeStructField) ? | |
| 2851 | field->decl_node->data.struct_field.align_expr : nullptr; | |
| 2818 | 2852 | if (align_expr != nullptr) { |
| 2819 | 2853 | if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, |
| 2820 | 2854 | &field->align)) |
| ... | ... | @@ -5413,6 +5447,12 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 5413 | 5447 | if (type_entry->one_possible_value != OnePossibleValueInvalid) |
| 5414 | 5448 | return type_entry->one_possible_value; |
| 5415 | 5449 | |
| 5450 | if (type_entry->id == ZigTypeIdStruct && | |
| 5451 | type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) | |
| 5452 | { | |
| 5453 | return OnePossibleValueNo; | |
| 5454 | } | |
| 5455 | ||
| 5416 | 5456 | Error err; |
| 5417 | 5457 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) |
| 5418 | 5458 | return OnePossibleValueInvalid; |
| ... | ... | @@ -6132,6 +6172,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 6132 | 6172 | continue; |
| 6133 | 6173 | if (instruction->ref_count == 0) |
| 6134 | 6174 | continue; |
| 6175 | if ((err = type_resolve(g, instruction->value.type, ResolveStatusZeroBitsKnown))) | |
| 6176 | return ErrorSemanticAnalyzeFail; | |
| 6135 | 6177 | if (!type_has_bits(instruction->value.type)) |
| 6136 | 6178 | continue; |
| 6137 | 6179 | if (scope_needs_spill(instruction->scope)) { |
| ... | ... | @@ -6271,6 +6313,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 6271 | 6313 | switch (status) { |
| 6272 | 6314 | case ResolveStatusUnstarted: |
| 6273 | 6315 | return ErrorNone; |
| 6316 | case ResolveStatusBeingInferred: | |
| 6317 | zig_unreachable(); | |
| 6274 | 6318 | case ResolveStatusInvalid: |
| 6275 | 6319 | zig_unreachable(); |
| 6276 | 6320 | case ResolveStatusZeroBitsKnown: |
| ... | ... | @@ -6995,7 +7039,16 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 6995 | 7039 | a.data.pointer.alignment == b.data.pointer.alignment && |
| 6996 | 7040 | a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && |
| 6997 | 7041 | a.data.pointer.vector_index == b.data.pointer.vector_index && |
| 6998 | a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; | |
| 7042 | a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes && | |
| 7043 | ( | |
| 7044 | a.data.pointer.inferred_struct_field == b.data.pointer.inferred_struct_field || | |
| 7045 | (a.data.pointer.inferred_struct_field != nullptr && | |
| 7046 | b.data.pointer.inferred_struct_field != nullptr && | |
| 7047 | a.data.pointer.inferred_struct_field->inferred_struct_type == | |
| 7048 | b.data.pointer.inferred_struct_field->inferred_struct_type && | |
| 7049 | buf_eql_buf(a.data.pointer.inferred_struct_field->field_name, | |
| 7050 | b.data.pointer.inferred_struct_field->field_name)) | |
| 7051 | ); | |
| 6999 | 7052 | case ZigTypeIdArray: |
| 7000 | 7053 | return a.data.array.child_type == b.data.array.child_type && |
| 7001 | 7054 | a.data.array.size == b.data.array.size; |
| ... | ... | @@ -7808,7 +7861,6 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 7808 | 7861 | ZigLLVMDIScope *di_scope; |
| 7809 | 7862 | unsigned line; |
| 7810 | 7863 | if (decl_node != nullptr) { |
| 7811 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 7812 | 7864 | Scope *scope = &struct_type->data.structure.decls_scope->base; |
| 7813 | 7865 | ZigType *import = get_scope_import(scope); |
| 7814 | 7866 | di_file = import->data.structure.root_struct->di_file; |
| ... | ... | @@ -8011,7 +8063,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 8011 | 8063 | } |
| 8012 | 8064 | unsigned line; |
| 8013 | 8065 | if (decl_node != nullptr) { |
| 8014 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 8066 | AstNode *field_node = field->decl_node; | |
| 8015 | 8067 | line = field_node->line + 1; |
| 8016 | 8068 | } else { |
| 8017 | 8069 | line = 0; |
| ... | ... | @@ -8307,12 +8359,12 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus |
| 8307 | 8359 | if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { |
| 8308 | 8360 | peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, |
| 8309 | 8361 | PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, |
| 8310 | VECTOR_INDEX_NONE); | |
| 8362 | VECTOR_INDEX_NONE, nullptr); | |
| 8311 | 8363 | } else { |
| 8312 | 8364 | uint32_t host_vec_len = type->data.pointer.host_int_bytes; |
| 8313 | 8365 | ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); |
| 8314 | 8366 | peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, |
| 8315 | PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE); | |
| 8367 | PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr); | |
| 8316 | 8368 | } |
| 8317 | 8369 | type->llvm_type = get_llvm_type(g, peer_type); |
| 8318 | 8370 | type->llvm_di_type = get_llvm_di_type(g, peer_type); |
| ... | ... | @@ -9038,4 +9090,3 @@ Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, |
| 9038 | 9090 | *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); |
| 9039 | 9091 | return ErrorNone; |
| 9040 | 9092 | } |
| 9041 |
src/analyze.hpp+1-1| ... | ... | @@ -24,7 +24,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, |
| 24 | 24 | ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, |
| 25 | 25 | bool is_const, bool is_volatile, PtrLen ptr_len, |
| 26 | 26 | uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, |
| 27 | bool allow_zero, uint32_t vector_index); | |
| 27 | bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field); | |
| 28 | 28 | uint64_t type_size(CodeGen *g, ZigType *type_entry); |
| 29 | 29 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); |
| 30 | 30 | ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
src/ast_render.cpp+3-1| ... | ... | @@ -821,7 +821,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 821 | 821 | break; |
| 822 | 822 | } |
| 823 | 823 | case NodeTypeContainerInitExpr: |
| 824 | render_node_ungrouped(ar, node->data.container_init_expr.type); | |
| 824 | if (node->data.container_init_expr.type != nullptr) { | |
| 825 | render_node_ungrouped(ar, node->data.container_init_expr.type); | |
| 826 | } | |
| 825 | 827 | if (node->data.container_init_expr.kind == ContainerInitKindStruct) { |
| 826 | 828 | fprintf(ar->f, "{\n"); |
| 827 | 829 | ar->indent += ar->indent_size; |
src/ir.cpp+313-109| ... | ... | @@ -202,6 +202,10 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char |
| 202 | 202 | Scope *scope, AstNode *source_node, Buf *out_bare_name); |
| 203 | 203 | static ResultLocCast *ir_build_cast_result_loc(IrBuilder *irb, IrInstruction *dest_type, |
| 204 | 204 | ResultLoc *parent_result_loc); |
| 205 | static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, | |
| 206 | TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing); | |
| 207 | static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, | |
| 208 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); | |
| 205 | 209 | |
| 206 | 210 | static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { |
| 207 | 211 | assert(get_src_ptr_type(const_val->type) != nullptr); |
| ... | ... | @@ -1350,18 +1354,17 @@ static IrInstruction *ir_build_return_ptr(IrAnalyze *ira, IrInstruction *source_ |
| 1350 | 1354 | |
| 1351 | 1355 | static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1352 | 1356 | IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len, |
| 1353 | IrInstruction *init_array_type) | |
| 1357 | AstNode *init_array_type_source_node) | |
| 1354 | 1358 | { |
| 1355 | 1359 | IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, scope, source_node); |
| 1356 | 1360 | instruction->array_ptr = array_ptr; |
| 1357 | 1361 | instruction->elem_index = elem_index; |
| 1358 | 1362 | instruction->safety_check_on = safety_check_on; |
| 1359 | 1363 | instruction->ptr_len = ptr_len; |
| 1360 | instruction->init_array_type = init_array_type; | |
| 1364 | instruction->init_array_type_source_node = init_array_type_source_node; | |
| 1361 | 1365 | |
| 1362 | 1366 | ir_ref_instruction(array_ptr, irb->current_basic_block); |
| 1363 | 1367 | ir_ref_instruction(elem_index, irb->current_basic_block); |
| 1364 | if (init_array_type != nullptr) ir_ref_instruction(init_array_type, irb->current_basic_block); | |
| 1365 | 1368 | |
| 1366 | 1369 | return &instruction->base; |
| 1367 | 1370 | } |
| ... | ... | @@ -1575,17 +1578,16 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour |
| 1575 | 1578 | } |
| 1576 | 1579 | |
| 1577 | 1580 | static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1578 | IrInstruction *container_type, size_t item_count, IrInstruction **elem_result_loc_list, | |
| 1579 | IrInstruction *result_loc) | |
| 1581 | size_t item_count, IrInstruction **elem_result_loc_list, IrInstruction *result_loc, | |
| 1582 | AstNode *init_array_type_source_node) | |
| 1580 | 1583 | { |
| 1581 | 1584 | IrInstructionContainerInitList *container_init_list_instruction = |
| 1582 | 1585 | ir_build_instruction<IrInstructionContainerInitList>(irb, scope, source_node); |
| 1583 | container_init_list_instruction->container_type = container_type; | |
| 1584 | 1586 | container_init_list_instruction->item_count = item_count; |
| 1585 | 1587 | container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; |
| 1586 | 1588 | container_init_list_instruction->result_loc = result_loc; |
| 1589 | container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; | |
| 1587 | 1590 | |
| 1588 | ir_ref_instruction(container_type, irb->current_basic_block); | |
| 1589 | 1591 | for (size_t i = 0; i < item_count; i += 1) { |
| 1590 | 1592 | ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block); |
| 1591 | 1593 | } |
| ... | ... | @@ -1595,17 +1597,14 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, |
| 1595 | 1597 | } |
| 1596 | 1598 | |
| 1597 | 1599 | static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1598 | IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields, | |
| 1599 | IrInstruction *result_loc) | |
| 1600 | size_t field_count, IrInstructionContainerInitFieldsField *fields, IrInstruction *result_loc) | |
| 1600 | 1601 | { |
| 1601 | 1602 | IrInstructionContainerInitFields *container_init_fields_instruction = |
| 1602 | 1603 | ir_build_instruction<IrInstructionContainerInitFields>(irb, scope, source_node); |
| 1603 | container_init_fields_instruction->container_type = container_type; | |
| 1604 | 1604 | container_init_fields_instruction->field_count = field_count; |
| 1605 | 1605 | container_init_fields_instruction->fields = fields; |
| 1606 | 1606 | container_init_fields_instruction->result_loc = result_loc; |
| 1607 | 1607 | |
| 1608 | ir_ref_instruction(container_type, irb->current_basic_block); | |
| 1609 | 1608 | for (size_t i = 0; i < field_count; i += 1) { |
| 1610 | 1609 | ir_ref_instruction(fields[i].result_loc, irb->current_basic_block); |
| 1611 | 1610 | } |
| ... | ... | @@ -3084,7 +3083,7 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN |
| 3084 | 3083 | instruction->result_loc = result_loc; |
| 3085 | 3084 | instruction->ty = ty; |
| 3086 | 3085 | |
| 3087 | ir_ref_instruction(ty, irb->current_basic_block); | |
| 3086 | if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block); | |
| 3088 | 3087 | |
| 3089 | 3088 | return &instruction->base; |
| 3090 | 3089 | } |
| ... | ... | @@ -6127,28 +6126,46 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A |
| 6127 | 6126 | AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; |
| 6128 | 6127 | ContainerInitKind kind = container_init_expr->kind; |
| 6129 | 6128 | |
| 6130 | IrInstruction *container_type = nullptr; | |
| 6131 | IrInstruction *elem_type = nullptr; | |
| 6132 | if (container_init_expr->type->type == NodeTypeInferredArrayType) { | |
| 6133 | elem_type = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.child_type, scope); | |
| 6134 | if (elem_type == irb->codegen->invalid_instruction) | |
| 6135 | return elem_type; | |
| 6136 | } else { | |
| 6137 | container_type = ir_gen_node(irb, container_init_expr->type, scope); | |
| 6138 | if (container_type == irb->codegen->invalid_instruction) | |
| 6139 | return container_type; | |
| 6140 | } | |
| 6141 | ||
| 6142 | switch (kind) { | |
| 6143 | case ContainerInitKindStruct: { | |
| 6144 | if (elem_type != nullptr) { | |
| 6129 | ResultLocCast *result_loc_cast = nullptr; | |
| 6130 | ResultLoc *child_result_loc; | |
| 6131 | AstNode *init_array_type_source_node; | |
| 6132 | if (container_init_expr->type != nullptr) { | |
| 6133 | IrInstruction *container_type; | |
| 6134 | if (container_init_expr->type->type == NodeTypeInferredArrayType) { | |
| 6135 | if (kind == ContainerInitKindStruct) { | |
| 6145 | 6136 | add_node_error(irb->codegen, container_init_expr->type, |
| 6146 | 6137 | buf_sprintf("initializing array with struct syntax")); |
| 6147 | 6138 | return irb->codegen->invalid_instruction; |
| 6148 | 6139 | } |
| 6140 | IrInstruction *elem_type = ir_gen_node(irb, | |
| 6141 | container_init_expr->type->data.inferred_array_type.child_type, scope); | |
| 6142 | if (elem_type == irb->codegen->invalid_instruction) | |
| 6143 | return elem_type; | |
| 6144 | size_t item_count = container_init_expr->entries.length; | |
| 6145 | IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); | |
| 6146 | container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); | |
| 6147 | } else { | |
| 6148 | container_type = ir_gen_node(irb, container_init_expr->type, scope); | |
| 6149 | if (container_type == irb->codegen->invalid_instruction) | |
| 6150 | return container_type; | |
| 6151 | } | |
| 6149 | 6152 | |
| 6150 | IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, | |
| 6151 | container_type); | |
| 6153 | result_loc_cast = ir_build_cast_result_loc(irb, container_type, parent_result_loc); | |
| 6154 | child_result_loc = &result_loc_cast->base; | |
| 6155 | init_array_type_source_node = container_type->source_node; | |
| 6156 | } else { | |
| 6157 | child_result_loc = parent_result_loc; | |
| 6158 | if (parent_result_loc->source_instruction != nullptr) { | |
| 6159 | init_array_type_source_node = parent_result_loc->source_instruction->source_node; | |
| 6160 | } else { | |
| 6161 | init_array_type_source_node = node; | |
| 6162 | } | |
| 6163 | } | |
| 6164 | ||
| 6165 | switch (kind) { | |
| 6166 | case ContainerInitKindStruct: { | |
| 6167 | IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, | |
| 6168 | nullptr); | |
| 6152 | 6169 | |
| 6153 | 6170 | size_t field_count = container_init_expr->entries.length; |
| 6154 | 6171 | IrInstructionContainerInitFieldsField *fields = allocate<IrInstructionContainerInitFieldsField>(field_count); |
| ... | ... | @@ -6176,29 +6193,27 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A |
| 6176 | 6193 | fields[i].source_node = entry_node; |
| 6177 | 6194 | fields[i].result_loc = field_ptr; |
| 6178 | 6195 | } |
| 6179 | IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, | |
| 6180 | field_count, fields, container_ptr); | |
| 6196 | IrInstruction *result = ir_build_container_init_fields(irb, scope, node, field_count, | |
| 6197 | fields, container_ptr); | |
| 6181 | 6198 | |
| 6182 | return ir_lval_wrap(irb, scope, init_fields, lval, parent_result_loc); | |
| 6199 | if (result_loc_cast != nullptr) { | |
| 6200 | result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); | |
| 6201 | } | |
| 6202 | return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); | |
| 6183 | 6203 | } |
| 6184 | 6204 | case ContainerInitKindArray: { |
| 6185 | 6205 | size_t item_count = container_init_expr->entries.length; |
| 6186 | 6206 | |
| 6187 | if (container_type == nullptr) { | |
| 6188 | IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); | |
| 6189 | container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); | |
| 6190 | } | |
| 6191 | ||
| 6192 | IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, | |
| 6193 | container_type); | |
| 6207 | IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, | |
| 6208 | nullptr); | |
| 6194 | 6209 | |
| 6195 | 6210 | IrInstruction **result_locs = allocate<IrInstruction *>(item_count); |
| 6196 | 6211 | for (size_t i = 0; i < item_count; i += 1) { |
| 6197 | 6212 | AstNode *expr_node = container_init_expr->entries.at(i); |
| 6198 | 6213 | |
| 6199 | 6214 | IrInstruction *elem_index = ir_build_const_usize(irb, scope, expr_node, i); |
| 6200 | IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, elem_index, | |
| 6201 | false, PtrLenSingle, container_type); | |
| 6215 | IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, | |
| 6216 | elem_index, false, PtrLenSingle, init_array_type_source_node); | |
| 6202 | 6217 | ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1); |
| 6203 | 6218 | result_loc_inst->base.id = ResultLocIdInstruction; |
| 6204 | 6219 | result_loc_inst->base.source_instruction = elem_ptr; |
| ... | ... | @@ -6213,9 +6228,12 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A |
| 6213 | 6228 | |
| 6214 | 6229 | result_locs[i] = elem_ptr; |
| 6215 | 6230 | } |
| 6216 | IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, | |
| 6217 | item_count, result_locs, container_ptr); | |
| 6218 | return ir_lval_wrap(irb, scope, init_list, lval, parent_result_loc); | |
| 6231 | IrInstruction *result = ir_build_container_init_list(irb, scope, node, item_count, | |
| 6232 | result_locs, container_ptr, init_array_type_source_node); | |
| 6233 | if (result_loc_cast != nullptr) { | |
| 6234 | result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); | |
| 6235 | } | |
| 6236 | return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); | |
| 6219 | 6237 | } |
| 6220 | 6238 | } |
| 6221 | 6239 | zig_unreachable(); |
| ... | ... | @@ -7935,14 +7953,14 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o |
| 7935 | 7953 | static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, |
| 7936 | 7954 | Scope *scope, AstNode *source_node, Buf *out_bare_name) |
| 7937 | 7955 | { |
| 7938 | if (exec->name) { | |
| 7956 | if (exec != nullptr && exec->name) { | |
| 7939 | 7957 | ZigType *import = get_scope_import(scope); |
| 7940 | 7958 | Buf *namespace_name = buf_alloc(); |
| 7941 | 7959 | append_namespace_qualification(codegen, namespace_name, import); |
| 7942 | 7960 | buf_append_buf(namespace_name, exec->name); |
| 7943 | 7961 | buf_init_from_buf(out_bare_name, exec->name); |
| 7944 | 7962 | return namespace_name; |
| 7945 | } else if (exec->name_fn != nullptr) { | |
| 7963 | } else if (exec != nullptr && exec->name_fn != nullptr) { | |
| 7946 | 7964 | Buf *name = buf_alloc(); |
| 7947 | 7965 | buf_append_buf(name, &exec->name_fn->symbol_name); |
| 7948 | 7966 | buf_appendf(name, "("); |
| ... | ... | @@ -15541,11 +15559,7 @@ static bool ir_result_has_type(ResultLoc *result_loc) { |
| 15541 | 15559 | static IrInstruction *ir_resolve_no_result_loc(IrAnalyze *ira, IrInstruction *suspend_source_instr, |
| 15542 | 15560 | ResultLoc *result_loc, ZigType *value_type, bool force_runtime, bool non_null_comptime) |
| 15543 | 15561 | { |
| 15544 | Error err; | |
| 15545 | ||
| 15546 | 15562 | IrInstructionAllocaGen *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr, 0, ""); |
| 15547 | if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown))) | |
| 15548 | return ira->codegen->invalid_instruction; | |
| 15549 | 15563 | alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false, |
| 15550 | 15564 | PtrLenSingle, 0, 0, 0, false); |
| 15551 | 15565 | set_up_result_loc_for_inferred_comptime(&alloca_gen->base); |
| ... | ... | @@ -15750,6 +15764,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe |
| 15750 | 15764 | return casted_value; |
| 15751 | 15765 | } |
| 15752 | 15766 | |
| 15767 | bool old_parent_result_loc_written = result_cast->parent->written; | |
| 15753 | 15768 | IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_cast->parent, |
| 15754 | 15769 | dest_type, casted_value, force_runtime, non_null_comptime, true); |
| 15755 | 15770 | if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || |
| ... | ... | @@ -15775,6 +15790,22 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe |
| 15775 | 15790 | parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, |
| 15776 | 15791 | parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); |
| 15777 | 15792 | |
| 15793 | { | |
| 15794 | // we also need to check that this cast is OK. | |
| 15795 | ConstCastOnly const_cast_result = types_match_const_cast_only(ira, | |
| 15796 | parent_result_loc->value.type, ptr_type, | |
| 15797 | result_cast->base.source_instruction->source_node, false); | |
| 15798 | if (const_cast_result.id == ConstCastResultIdInvalid) | |
| 15799 | return ira->codegen->invalid_instruction; | |
| 15800 | if (const_cast_result.id != ConstCastResultIdOk) { | |
| 15801 | // We will not be able to provide a result location for this value. Create | |
| 15802 | // a new result location. | |
| 15803 | result_cast->parent->written = old_parent_result_loc_written; | |
| 15804 | return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type, | |
| 15805 | force_runtime, non_null_comptime); | |
| 15806 | } | |
| 15807 | } | |
| 15808 | ||
| 15778 | 15809 | result_loc->written = true; |
| 15779 | 15810 | result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, |
| 15780 | 15811 | ptr_type, result_cast->base.source_instruction, false); |
| ... | ... | @@ -15902,10 +15933,37 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s |
| 15902 | 15933 | return result_loc; |
| 15903 | 15934 | } |
| 15904 | 15935 | |
| 15905 | static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { | |
| 15906 | ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); | |
| 15907 | if (type_is_invalid(implicit_elem_type)) | |
| 15908 | return ira->codegen->invalid_instruction; | |
| 15936 | static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, | |
| 15937 | IrInstructionResolveResult *instruction) | |
| 15938 | { | |
| 15939 | ZigType *implicit_elem_type; | |
| 15940 | if (instruction->ty == nullptr) { | |
| 15941 | if (instruction->result_loc->id == ResultLocIdCast) { | |
| 15942 | implicit_elem_type = ir_resolve_type(ira, | |
| 15943 | instruction->result_loc->source_instruction->child); | |
| 15944 | if (type_is_invalid(implicit_elem_type)) | |
| 15945 | return ira->codegen->invalid_instruction; | |
| 15946 | } else if (instruction->result_loc->id == ResultLocIdReturn) { | |
| 15947 | implicit_elem_type = ira->explicit_return_type; | |
| 15948 | if (type_is_invalid(implicit_elem_type)) | |
| 15949 | return ira->codegen->invalid_instruction; | |
| 15950 | } else { | |
| 15951 | Buf *bare_name = buf_alloc(); | |
| 15952 | Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), | |
| 15953 | instruction->base.scope, instruction->base.source_node, bare_name); | |
| 15954 | ||
| 15955 | ZigType *inferred_struct_type = get_partial_container_type(ira->codegen, | |
| 15956 | instruction->base.scope, ContainerKindStruct, instruction->base.source_node, | |
| 15957 | buf_ptr(name), bare_name, ContainerLayoutAuto); | |
| 15958 | inferred_struct_type->data.structure.is_inferred = true; | |
| 15959 | inferred_struct_type->data.structure.resolve_status = ResolveStatusBeingInferred; | |
| 15960 | implicit_elem_type = inferred_struct_type; | |
| 15961 | } | |
| 15962 | } else { | |
| 15963 | implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); | |
| 15964 | if (type_is_invalid(implicit_elem_type)) | |
| 15965 | return ira->codegen->invalid_instruction; | |
| 15966 | } | |
| 15909 | 15967 | IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, |
| 15910 | 15968 | implicit_elem_type, nullptr, false, true, true); |
| 15911 | 15969 | if (result_loc != nullptr) |
| ... | ... | @@ -16267,13 +16325,78 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 16267 | 16325 | return ir_const_void(ira, source_instr); |
| 16268 | 16326 | } |
| 16269 | 16327 | |
| 16270 | ZigType *child_type = ptr->value.type->data.pointer.child_type; | |
| 16328 | InferredStructField *isf = ptr->value.type->data.pointer.inferred_struct_field; | |
| 16329 | if (allow_write_through_const && isf != nullptr) { | |
| 16330 | // Now it's time to add the field to the struct type. | |
| 16331 | uint32_t old_field_count = isf->inferred_struct_type->data.structure.src_field_count; | |
| 16332 | uint32_t new_field_count = old_field_count + 1; | |
| 16333 | isf->inferred_struct_type->data.structure.src_field_count = new_field_count; | |
| 16334 | if (new_field_count > 16) { | |
| 16335 | // This thing with 16 is a hack to allow this functionality to work without | |
| 16336 | // modifying the ConstExprValue layout of structs. That reworking needs to be | |
| 16337 | // done, but this hack lets us do it separately, in the future. | |
| 16338 | zig_panic("TODO need to rework the layout of ZigTypeStruct. This realloc would have caused invalid pointer references"); | |
| 16339 | } | |
| 16340 | if (isf->inferred_struct_type->data.structure.fields == nullptr) { | |
| 16341 | isf->inferred_struct_type->data.structure.fields = allocate<TypeStructField>(16); | |
| 16342 | } | |
| 16343 | ||
| 16344 | // This reference can't live long, don't keep it around outside this block. | |
| 16345 | TypeStructField *field = &isf->inferred_struct_type->data.structure.fields[old_field_count]; | |
| 16346 | field->name = isf->field_name; | |
| 16347 | field->type_entry = uncasted_value->value.type; | |
| 16348 | field->type_val = create_const_type(ira->codegen, field->type_entry); | |
| 16349 | field->src_index = old_field_count; | |
| 16350 | field->decl_node = uncasted_value->source_node; | |
| 16351 | ||
| 16352 | ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false); | |
| 16353 | IrInstruction *casted_ptr; | |
| 16354 | if (instr_is_comptime(ptr)) { | |
| 16355 | casted_ptr = ir_const(ira, source_instr, struct_ptr_type); | |
| 16356 | copy_const_val(&casted_ptr->value, &ptr->value, false); | |
| 16357 | casted_ptr->value.type = struct_ptr_type; | |
| 16358 | } else { | |
| 16359 | casted_ptr = ir_build_cast(&ira->new_irb, source_instr->scope, | |
| 16360 | source_instr->source_node, struct_ptr_type, ptr, CastOpNoop); | |
| 16361 | casted_ptr->value.type = struct_ptr_type; | |
| 16362 | } | |
| 16363 | if (instr_is_comptime(casted_ptr)) { | |
| 16364 | ConstExprValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); | |
| 16365 | if (!ptr_val) | |
| 16366 | return ira->codegen->invalid_instruction; | |
| 16367 | if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { | |
| 16368 | ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, | |
| 16369 | source_instr->source_node); | |
| 16370 | struct_val->special = ConstValSpecialStatic; | |
| 16371 | if (new_field_count > 16) { | |
| 16372 | // This thing with 16 is a hack to allow this functionality to work without | |
| 16373 | // modifying the ConstExprValue layout of structs. That reworking needs to be | |
| 16374 | // done, but this hack lets us do it separately, in the future. | |
| 16375 | zig_panic("TODO need to rework the layout of ConstExprValue for structs. This realloc would have caused invalid pointer references"); | |
| 16376 | } | |
| 16377 | if (struct_val->data.x_struct.fields == nullptr) { | |
| 16378 | struct_val->data.x_struct.fields = create_const_vals(16); | |
| 16379 | } | |
| 16380 | ||
| 16381 | ConstExprValue *field_val = &struct_val->data.x_struct.fields[old_field_count]; | |
| 16382 | field_val->special = ConstValSpecialUndef; | |
| 16383 | field_val->type = field->type_entry; | |
| 16384 | field_val->parent.id = ConstParentIdStruct; | |
| 16385 | field_val->parent.data.p_struct.struct_val = struct_val; | |
| 16386 | field_val->parent.data.p_struct.field_index = old_field_count; | |
| 16387 | } | |
| 16388 | } | |
| 16389 | ||
| 16390 | ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, casted_ptr, | |
| 16391 | isf->inferred_struct_type, true); | |
| 16392 | } | |
| 16271 | 16393 | |
| 16272 | 16394 | if (ptr->value.type->data.pointer.is_const && !allow_write_through_const) { |
| 16273 | 16395 | ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); |
| 16274 | 16396 | return ira->codegen->invalid_instruction; |
| 16275 | 16397 | } |
| 16276 | 16398 | |
| 16399 | ZigType *child_type = ptr->value.type->data.pointer.child_type; | |
| 16277 | 16400 | IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type); |
| 16278 | 16401 | if (value == ira->codegen->invalid_instruction) |
| 16279 | 16402 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -17769,6 +17892,19 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17769 | 17892 | } else if (array_type->id == ZigTypeIdVector) { |
| 17770 | 17893 | // This depends on whether the element index is comptime, so it is computed later. |
| 17771 | 17894 | return_type = nullptr; |
| 17895 | } else if (elem_ptr_instruction->init_array_type_source_node != nullptr && | |
| 17896 | array_type->id == ZigTypeIdStruct && | |
| 17897 | array_type->data.structure.resolve_status == ResolveStatusBeingInferred) | |
| 17898 | { | |
| 17899 | ZigType *usize = ira->codegen->builtin_types.entry_usize; | |
| 17900 | IrInstruction *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); | |
| 17901 | if (casted_elem_index == ira->codegen->invalid_instruction) | |
| 17902 | return ira->codegen->invalid_instruction; | |
| 17903 | ir_assert(instr_is_comptime(casted_elem_index), &elem_ptr_instruction->base); | |
| 17904 | Buf *field_name = buf_alloc(); | |
| 17905 | bigint_append_buf(field_name, &casted_elem_index->value.data.x_bigint, 10); | |
| 17906 | return ir_analyze_inferred_field_ptr(ira, field_name, &elem_ptr_instruction->base, | |
| 17907 | array_ptr, array_type); | |
| 17772 | 17908 | } else { |
| 17773 | 17909 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 17774 | 17910 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | ... | @@ -17799,7 +17935,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17799 | 17935 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, |
| 17800 | 17936 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 17801 | 17937 | elem_ptr_instruction->ptr_len, |
| 17802 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index); | |
| 17938 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, | |
| 17939 | nullptr); | |
| 17803 | 17940 | } else if (return_type->data.pointer.explicit_alignment != 0) { |
| 17804 | 17941 | // figure out the largest alignment possible |
| 17805 | 17942 | |
| ... | ... | @@ -17837,7 +17974,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17837 | 17974 | if (array_ptr_val == nullptr) |
| 17838 | 17975 | return ira->codegen->invalid_instruction; |
| 17839 | 17976 | |
| 17840 | if (array_ptr_val->special == ConstValSpecialUndef && elem_ptr_instruction->init_array_type != nullptr) { | |
| 17977 | if (array_ptr_val->special == ConstValSpecialUndef && | |
| 17978 | elem_ptr_instruction->init_array_type_source_node != nullptr) | |
| 17979 | { | |
| 17841 | 17980 | if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { |
| 17842 | 17981 | array_ptr_val->data.x_array.special = ConstArraySpecialNone; |
| 17843 | 17982 | array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len); |
| ... | ... | @@ -17851,11 +17990,13 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17851 | 17990 | elem_val->parent.data.p_array.elem_index = i; |
| 17852 | 17991 | } |
| 17853 | 17992 | } else if (is_slice(array_type)) { |
| 17854 | ZigType *actual_array_type = ir_resolve_type(ira, elem_ptr_instruction->init_array_type->child); | |
| 17993 | ir_assert(array_ptr->value.type->id == ZigTypeIdPointer, &elem_ptr_instruction->base); | |
| 17994 | ZigType *actual_array_type = array_ptr->value.type->data.pointer.child_type; | |
| 17995 | ||
| 17855 | 17996 | if (type_is_invalid(actual_array_type)) |
| 17856 | 17997 | return ira->codegen->invalid_instruction; |
| 17857 | 17998 | if (actual_array_type->id != ZigTypeIdArray) { |
| 17858 | ir_add_error(ira, elem_ptr_instruction->init_array_type, | |
| 17999 | ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, | |
| 17859 | 18000 | buf_sprintf("expected array type or [_], found slice")); |
| 17860 | 18001 | return ira->codegen->invalid_instruction; |
| 17861 | 18002 | } |
| ... | ... | @@ -17879,7 +18020,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17879 | 18020 | false); |
| 17880 | 18021 | array_ptr_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = ConstPtrMutInfer; |
| 17881 | 18022 | } else { |
| 17882 | ir_add_error(ira, elem_ptr_instruction->init_array_type, | |
| 18023 | ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, | |
| 17883 | 18024 | buf_sprintf("expected array type or [_], found '%s'", |
| 17884 | 18025 | buf_ptr(&array_type->name))); |
| 17885 | 18026 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -18012,7 +18153,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 18012 | 18153 | if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { |
| 18013 | 18154 | result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, |
| 18014 | 18155 | elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, |
| 18015 | false, elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); | |
| 18156 | false, elem_ptr_instruction->ptr_len, nullptr); | |
| 18016 | 18157 | result->value.type = return_type; |
| 18017 | 18158 | result->value.special = ConstValSpecialStatic; |
| 18018 | 18159 | } else { |
| ... | ... | @@ -18036,7 +18177,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 18036 | 18177 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, |
| 18037 | 18178 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 18038 | 18179 | elem_ptr_instruction->ptr_len, |
| 18039 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME); | |
| 18180 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME, | |
| 18181 | nullptr); | |
| 18040 | 18182 | } else { |
| 18041 | 18183 | // runtime known element index |
| 18042 | 18184 | switch (type_requires_comptime(ira->codegen, return_type)) { |
| ... | ... | @@ -18073,7 +18215,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 18073 | 18215 | |
| 18074 | 18216 | IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, |
| 18075 | 18217 | elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on, |
| 18076 | elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); | |
| 18218 | elem_ptr_instruction->ptr_len, nullptr); | |
| 18077 | 18219 | result->value.type = return_type; |
| 18078 | 18220 | return result; |
| 18079 | 18221 | } |
| ... | ... | @@ -18152,31 +18294,34 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction |
| 18152 | 18294 | case OnePossibleValueNo: |
| 18153 | 18295 | break; |
| 18154 | 18296 | } |
| 18155 | ResolveStatus needed_resolve_status = | |
| 18156 | (struct_type->data.structure.layout == ContainerLayoutAuto) ? | |
| 18157 | ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; | |
| 18158 | if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) | |
| 18159 | return ira->codegen->invalid_instruction; | |
| 18160 | assert(struct_ptr->value.type->id == ZigTypeIdPointer); | |
| 18161 | uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; | |
| 18162 | uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; | |
| 18163 | uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? | |
| 18164 | get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; | |
| 18165 | 18297 | bool is_const = struct_ptr->value.type->data.pointer.is_const; |
| 18166 | 18298 | bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; |
| 18167 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, | |
| 18168 | is_const, is_volatile, PtrLenSingle, field->align, | |
| 18169 | (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), | |
| 18170 | (uint32_t)host_int_bytes_for_result_type, false); | |
| 18299 | ZigType *ptr_type; | |
| 18300 | if (struct_type->data.structure.is_inferred) { | |
| 18301 | ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, | |
| 18302 | is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); | |
| 18303 | } else { | |
| 18304 | ResolveStatus needed_resolve_status = | |
| 18305 | (struct_type->data.structure.layout == ContainerLayoutAuto) ? | |
| 18306 | ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; | |
| 18307 | if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) | |
| 18308 | return ira->codegen->invalid_instruction; | |
| 18309 | assert(struct_ptr->value.type->id == ZigTypeIdPointer); | |
| 18310 | uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; | |
| 18311 | uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; | |
| 18312 | uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? | |
| 18313 | get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; | |
| 18314 | ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, | |
| 18315 | is_const, is_volatile, PtrLenSingle, field->align, | |
| 18316 | (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), | |
| 18317 | (uint32_t)host_int_bytes_for_result_type, false); | |
| 18318 | } | |
| 18171 | 18319 | if (instr_is_comptime(struct_ptr)) { |
| 18172 | 18320 | ConstExprValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); |
| 18173 | 18321 | if (!ptr_val) |
| 18174 | 18322 | return ira->codegen->invalid_instruction; |
| 18175 | 18323 | |
| 18176 | 18324 | if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { |
| 18177 | if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusSizeKnown))) | |
| 18178 | return ira->codegen->invalid_instruction; | |
| 18179 | ||
| 18180 | 18325 | ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); |
| 18181 | 18326 | if (struct_val == nullptr) |
| 18182 | 18327 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -18188,7 +18333,8 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction |
| 18188 | 18333 | for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { |
| 18189 | 18334 | ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; |
| 18190 | 18335 | field_val->special = ConstValSpecialUndef; |
| 18191 | field_val->type = struct_type->data.structure.fields[i].type_entry; | |
| 18336 | field_val->type = resolve_struct_field_type(ira->codegen, | |
| 18337 | &struct_type->data.structure.fields[i]); | |
| 18192 | 18338 | field_val->parent.id = ConstParentIdStruct; |
| 18193 | 18339 | field_val->parent.data.p_struct.struct_val = struct_val; |
| 18194 | 18340 | field_val->parent.data.p_struct.field_index = i; |
| ... | ... | @@ -18217,12 +18363,53 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction |
| 18217 | 18363 | return result; |
| 18218 | 18364 | } |
| 18219 | 18365 | |
| 18366 | static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, | |
| 18367 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type) | |
| 18368 | { | |
| 18369 | // The type of the field is not available until a store using this pointer happens. | |
| 18370 | // So, here we create a special pointer type which has the inferred struct type and | |
| 18371 | // field name encoded in the type. Later, when there is a store via this pointer, | |
| 18372 | // the field type will then be available, and the field will be added to the inferred | |
| 18373 | // struct. | |
| 18374 | ||
| 18375 | ZigType *container_ptr_type = container_ptr->value.type; | |
| 18376 | ir_assert(container_ptr_type->id == ZigTypeIdPointer, source_instr); | |
| 18377 | ||
| 18378 | InferredStructField *inferred_struct_field = allocate<InferredStructField>(1, "InferredStructField"); | |
| 18379 | inferred_struct_field->inferred_struct_type = container_type; | |
| 18380 | inferred_struct_field->field_name = field_name; | |
| 18381 | ||
| 18382 | ZigType *elem_type = ira->codegen->builtin_types.entry_c_void; | |
| 18383 | ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, | |
| 18384 | container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, | |
| 18385 | PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field); | |
| 18386 | ||
| 18387 | if (instr_is_comptime(container_ptr)) { | |
| 18388 | IrInstruction *result = ir_const(ira, source_instr, field_ptr_type); | |
| 18389 | copy_const_val(&result->value, &container_ptr->value, false); | |
| 18390 | result->value.type = field_ptr_type; | |
| 18391 | return result; | |
| 18392 | } | |
| 18393 | ||
| 18394 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, | |
| 18395 | source_instr->source_node, field_ptr_type, container_ptr, CastOpNoop); | |
| 18396 | result->value.type = field_ptr_type; | |
| 18397 | return result; | |
| 18398 | } | |
| 18399 | ||
| 18220 | 18400 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, |
| 18221 | 18401 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) |
| 18222 | 18402 | { |
| 18223 | 18403 | Error err; |
| 18224 | 18404 | |
| 18225 | 18405 | ZigType *bare_type = container_ref_type(container_type); |
| 18406 | ||
| 18407 | if (initializing && bare_type->id == ZigTypeIdStruct && | |
| 18408 | bare_type->data.structure.resolve_status == ResolveStatusBeingInferred) | |
| 18409 | { | |
| 18410 | return ir_analyze_inferred_field_ptr(ira, field_name, source_instr, container_ptr, bare_type); | |
| 18411 | } | |
| 18412 | ||
| 18226 | 18413 | if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) |
| 18227 | 18414 | return ira->codegen->invalid_instruction; |
| 18228 | 18415 | |
| ... | ... | @@ -19997,6 +20184,11 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 19997 | 20184 | return ira->codegen->invalid_instruction; |
| 19998 | 20185 | } |
| 19999 | 20186 | |
| 20187 | if (container_type->data.structure.resolve_status == ResolveStatusBeingInferred) { | |
| 20188 | // We're now done inferring the type. | |
| 20189 | container_type->data.structure.resolve_status = ResolveStatusUnstarted; | |
| 20190 | } | |
| 20191 | ||
| 20000 | 20192 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) |
| 20001 | 20193 | return ira->codegen->invalid_instruction; |
| 20002 | 20194 | |
| ... | ... | @@ -20066,8 +20258,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 20066 | 20258 | TypeStructField *field = &container_type->data.structure.fields[i]; |
| 20067 | 20259 | if (field->init_val == nullptr) { |
| 20068 | 20260 | // it's not memoized. time to go analyze it |
| 20069 | assert(field->decl_node->type == NodeTypeStructField); | |
| 20070 | AstNode *init_node = field->decl_node->data.struct_field.value; | |
| 20261 | AstNode *init_node; | |
| 20262 | if (field->decl_node->type == NodeTypeStructField) { | |
| 20263 | init_node = field->decl_node->data.struct_field.value; | |
| 20264 | } else { | |
| 20265 | init_node = nullptr; | |
| 20266 | } | |
| 20071 | 20267 | if (init_node == nullptr) { |
| 20072 | 20268 | ir_add_error_node(ira, instruction->source_node, |
| 20073 | 20269 | buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); |
| ... | ... | @@ -20124,14 +20320,18 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 20124 | 20320 | static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 20125 | 20321 | IrInstructionContainerInitList *instruction) |
| 20126 | 20322 | { |
| 20127 | ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); | |
| 20128 | if (type_is_invalid(container_type)) | |
| 20129 | return ira->codegen->invalid_instruction; | |
| 20323 | ir_assert(instruction->result_loc != nullptr, &instruction->base); | |
| 20324 | IrInstruction *result_loc = instruction->result_loc->child; | |
| 20325 | if (type_is_invalid(result_loc->value.type)) | |
| 20326 | return result_loc; | |
| 20327 | ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); | |
| 20328 | ||
| 20329 | ZigType *container_type = result_loc->value.type->data.pointer.child_type; | |
| 20130 | 20330 | |
| 20131 | 20331 | size_t elem_count = instruction->item_count; |
| 20132 | 20332 | |
| 20133 | 20333 | if (is_slice(container_type)) { |
| 20134 | ir_add_error(ira, instruction->container_type, | |
| 20334 | ir_add_error_node(ira, instruction->init_array_type_source_node, | |
| 20135 | 20335 | buf_sprintf("expected array type or [_], found slice")); |
| 20136 | 20336 | return ira->codegen->invalid_instruction; |
| 20137 | 20337 | } |
| ... | ... | @@ -20153,29 +20353,28 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 20153 | 20353 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc); |
| 20154 | 20354 | } |
| 20155 | 20355 | |
| 20156 | if (container_type->id != ZigTypeIdArray) { | |
| 20356 | if (container_type->id == ZigTypeIdArray) { | |
| 20357 | ZigType *child_type = container_type->data.array.child_type; | |
| 20358 | if (container_type->data.array.len != elem_count) { | |
| 20359 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 20360 | ||
| 20361 | ir_add_error(ira, &instruction->base, | |
| 20362 | buf_sprintf("expected %s literal, found %s literal", | |
| 20363 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); | |
| 20364 | return ira->codegen->invalid_instruction; | |
| 20365 | } | |
| 20366 | } else if (container_type->id == ZigTypeIdStruct && | |
| 20367 | container_type->data.structure.resolve_status == ResolveStatusBeingInferred) | |
| 20368 | { | |
| 20369 | // We're now done inferring the type. | |
| 20370 | container_type->data.structure.resolve_status = ResolveStatusUnstarted; | |
| 20371 | } else { | |
| 20157 | 20372 | ir_add_error_node(ira, instruction->base.source_node, |
| 20158 | 20373 | buf_sprintf("type '%s' does not support array initialization", |
| 20159 | 20374 | buf_ptr(&container_type->name))); |
| 20160 | 20375 | return ira->codegen->invalid_instruction; |
| 20161 | 20376 | } |
| 20162 | 20377 | |
| 20163 | ir_assert(instruction->result_loc != nullptr, &instruction->base); | |
| 20164 | IrInstruction *result_loc = instruction->result_loc->child; | |
| 20165 | if (type_is_invalid(result_loc->value.type)) | |
| 20166 | return result_loc; | |
| 20167 | ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); | |
| 20168 | ||
| 20169 | ZigType *child_type = container_type->data.array.child_type; | |
| 20170 | if (container_type->data.array.len != elem_count) { | |
| 20171 | ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); | |
| 20172 | ||
| 20173 | ir_add_error(ira, &instruction->base, | |
| 20174 | buf_sprintf("expected %s literal, found %s literal", | |
| 20175 | buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); | |
| 20176 | return ira->codegen->invalid_instruction; | |
| 20177 | } | |
| 20178 | ||
| 20179 | 20378 | switch (type_has_one_possible_value(ira->codegen, container_type)) { |
| 20180 | 20379 | case OnePossibleValueInvalid: |
| 20181 | 20380 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -20262,16 +20461,14 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 20262 | 20461 | static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, |
| 20263 | 20462 | IrInstructionContainerInitFields *instruction) |
| 20264 | 20463 | { |
| 20265 | IrInstruction *container_type_value = instruction->container_type->child; | |
| 20266 | ZigType *container_type = ir_resolve_type(ira, container_type_value); | |
| 20267 | if (type_is_invalid(container_type)) | |
| 20268 | return ira->codegen->invalid_instruction; | |
| 20269 | ||
| 20270 | 20464 | ir_assert(instruction->result_loc != nullptr, &instruction->base); |
| 20271 | 20465 | IrInstruction *result_loc = instruction->result_loc->child; |
| 20272 | 20466 | if (type_is_invalid(result_loc->value.type)) |
| 20273 | 20467 | return result_loc; |
| 20274 | 20468 | |
| 20469 | ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); | |
| 20470 | ZigType *container_type = result_loc->value.type->data.pointer.child_type; | |
| 20471 | ||
| 20275 | 20472 | return ir_analyze_container_init_fields(ira, &instruction->base, container_type, |
| 20276 | 20473 | instruction->field_count, instruction->fields, result_loc); |
| 20277 | 20474 | } |
| ... | ... | @@ -24607,6 +24804,10 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 24607 | 24804 | ZigType *src_type = ptr->value.type; |
| 24608 | 24805 | assert(!type_is_invalid(src_type)); |
| 24609 | 24806 | |
| 24807 | if (src_type == dest_type) { | |
| 24808 | return ptr; | |
| 24809 | } | |
| 24810 | ||
| 24610 | 24811 | // We have a check for zero bits later so we use get_src_ptr_type to |
| 24611 | 24812 | // validate src_type and dest_type. |
| 24612 | 24813 | |
| ... | ... | @@ -24656,6 +24857,9 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 24656 | 24857 | IrInstruction *result; |
| 24657 | 24858 | if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) { |
| 24658 | 24859 | result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); |
| 24860 | ||
| 24861 | if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) | |
| 24862 | return ira->codegen->invalid_instruction; | |
| 24659 | 24863 | } else { |
| 24660 | 24864 | result = ir_const(ira, source_instr, dest_type); |
| 24661 | 24865 | } |
src/ir_print.cpp+4-4| ... | ... | @@ -731,7 +731,6 @@ static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) { |
| 731 | 731 | } |
| 732 | 732 | |
| 733 | 733 | static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerInitList *instruction) { |
| 734 | ir_print_other_instruction(irp, instruction->container_type); | |
| 735 | 734 | fprintf(irp->f, "{"); |
| 736 | 735 | if (instruction->item_count > 50) { |
| 737 | 736 | fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count); |
| ... | ... | @@ -743,11 +742,11 @@ static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerIni |
| 743 | 742 | ir_print_other_instruction(irp, result_loc); |
| 744 | 743 | } |
| 745 | 744 | } |
| 746 | fprintf(irp->f, "}"); | |
| 745 | fprintf(irp->f, "}result="); | |
| 746 | ir_print_other_instruction(irp, instruction->result_loc); | |
| 747 | 747 | } |
| 748 | 748 | |
| 749 | 749 | static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerInitFields *instruction) { |
| 750 | ir_print_other_instruction(irp, instruction->container_type); | |
| 751 | 750 | fprintf(irp->f, "{"); |
| 752 | 751 | for (size_t i = 0; i < instruction->field_count; i += 1) { |
| 753 | 752 | IrInstructionContainerInitFieldsField *field = &instruction->fields[i]; |
| ... | ... | @@ -755,7 +754,8 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI |
| 755 | 754 | fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name)); |
| 756 | 755 | ir_print_other_instruction(irp, field->result_loc); |
| 757 | 756 | } |
| 758 | fprintf(irp->f, "} // container init"); | |
| 757 | fprintf(irp->f, "}result="); | |
| 758 | ir_print_other_instruction(irp, instruction->result_loc); | |
| 759 | 759 | } |
| 760 | 760 | |
| 761 | 761 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { |
src/parser.cpp+16-10| ... | ... | @@ -81,7 +81,7 @@ static AstNode *ast_parse_for_type_expr(ParseContext *pc); |
| 81 | 81 | static AstNode *ast_parse_while_type_expr(ParseContext *pc); |
| 82 | 82 | static AstNode *ast_parse_switch_expr(ParseContext *pc); |
| 83 | 83 | static AstNode *ast_parse_asm_expr(ParseContext *pc); |
| 84 | static AstNode *ast_parse_enum_lit(ParseContext *pc); | |
| 84 | static AstNode *ast_parse_anon_lit(ParseContext *pc); | |
| 85 | 85 | static AstNode *ast_parse_asm_output(ParseContext *pc); |
| 86 | 86 | static AsmOutput *ast_parse_asm_output_item(ParseContext *pc); |
| 87 | 87 | static AstNode *ast_parse_asm_input(ParseContext *pc); |
| ... | ... | @@ -1600,9 +1600,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1600 | 1600 | if (container_decl != nullptr) |
| 1601 | 1601 | return container_decl; |
| 1602 | 1602 | |
| 1603 | AstNode *enum_lit = ast_parse_enum_lit(pc); | |
| 1604 | if (enum_lit != nullptr) | |
| 1605 | return enum_lit; | |
| 1603 | AstNode *anon_lit = ast_parse_anon_lit(pc); | |
| 1604 | if (anon_lit != nullptr) | |
| 1605 | return anon_lit; | |
| 1606 | 1606 | |
| 1607 | 1607 | AstNode *error_set_decl = ast_parse_error_set_decl(pc); |
| 1608 | 1608 | if (error_set_decl != nullptr) |
| ... | ... | @@ -1876,16 +1876,22 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) { |
| 1876 | 1876 | return res; |
| 1877 | 1877 | } |
| 1878 | 1878 | |
| 1879 | static AstNode *ast_parse_enum_lit(ParseContext *pc) { | |
| 1879 | static AstNode *ast_parse_anon_lit(ParseContext *pc) { | |
| 1880 | 1880 | Token *period = eat_token_if(pc, TokenIdDot); |
| 1881 | 1881 | if (period == nullptr) |
| 1882 | 1882 | return nullptr; |
| 1883 | 1883 | |
| 1884 | Token *identifier = expect_token(pc, TokenIdSymbol); | |
| 1885 | AstNode *res = ast_create_node(pc, NodeTypeEnumLiteral, period); | |
| 1886 | res->data.enum_literal.period = period; | |
| 1887 | res->data.enum_literal.identifier = identifier; | |
| 1888 | return res; | |
| 1884 | // anon enum literal | |
| 1885 | Token *identifier = eat_token_if(pc, TokenIdSymbol); | |
| 1886 | if (identifier != nullptr) { | |
| 1887 | AstNode *res = ast_create_node(pc, NodeTypeEnumLiteral, period); | |
| 1888 | res->data.enum_literal.period = period; | |
| 1889 | res->data.enum_literal.identifier = identifier; | |
| 1890 | return res; | |
| 1891 | } | |
| 1892 | ||
| 1893 | // anon container literal | |
| 1894 | return ast_parse_init_list(pc); | |
| 1889 | 1895 | } |
| 1890 | 1896 | |
| 1891 | 1897 | // AsmOutput <- COLON AsmOutputList AsmInput? |
test/compile_errors.zig+19-2| ... | ... | @@ -2,6 +2,23 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "missing const in slice with nested array type", | |
| 7 | \\const Geo3DTex2D = struct { vertices: [][2]f32 }; | |
| 8 | \\pub fn getGeo3DTex2D() Geo3DTex2D { | |
| 9 | \\ return Geo3DTex2D{ | |
| 10 | \\ .vertices = [_][2]f32{ | |
| 11 | \\ [_]f32{ -0.5, -0.5}, | |
| 12 | \\ }, | |
| 13 | \\ }; | |
| 14 | \\} | |
| 15 | \\export fn entry() void { | |
| 16 | \\ var geo_data = getGeo3DTex2D(); | |
| 17 | \\} | |
| 18 | , | |
| 19 | "tmp.zig:4:30: error: expected type '[][2]f32', found '[1][2]f32'", | |
| 20 | ); | |
| 21 | ||
| 5 | 22 | cases.add( |
| 6 | 23 | "slicing of global undefined pointer", |
| 7 | 24 | \\var buf: *[1]u8 = undefined; |
| ... | ... | @@ -216,9 +233,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 216 | 233 | \\ const obj = AstObject{ .lhsExpr = lhsExpr }; |
| 217 | 234 | \\} |
| 218 | 235 | , |
| 219 | "tmp.zig:4:19: error: union 'AstObject' depends on itself", | |
| 220 | "tmp.zig:2:5: note: while checking this field", | |
| 236 | "tmp.zig:1:17: error: struct 'LhsExpr' depends on itself", | |
| 221 | 237 | "tmp.zig:5:5: note: while checking this field", |
| 238 | "tmp.zig:2:5: note: while checking this field", | |
| 222 | 239 | ); |
| 223 | 240 | |
| 224 | 241 | cases.add( |
test/stage1/behavior/array.zig+14| ... | ... | @@ -298,3 +298,17 @@ test "implicit cast zero sized array ptr to slice" { |
| 298 | 298 | const c: []const u8 = &b; |
| 299 | 299 | expect(c.len == 0); |
| 300 | 300 | } |
| 301 | ||
| 302 | test "anonymous list literal syntax" { | |
| 303 | const S = struct { | |
| 304 | fn doTheTest() void { | |
| 305 | var array: [4]u8 = .{1, 2, 3, 4}; | |
| 306 | expect(array[0] == 1); | |
| 307 | expect(array[1] == 2); | |
| 308 | expect(array[2] == 3); | |
| 309 | expect(array[3] == 4); | |
| 310 | } | |
| 311 | }; | |
| 312 | S.doTheTest(); | |
| 313 | comptime S.doTheTest(); | |
| 314 | } |
test/stage1/behavior/async_fn.zig+2-2| ... | ... | @@ -1214,7 +1214,7 @@ test "spill target expr in a for loop" { |
| 1214 | 1214 | } |
| 1215 | 1215 | |
| 1216 | 1216 | const Foo = struct { |
| 1217 | slice: []i32, | |
| 1217 | slice: []const i32, | |
| 1218 | 1218 | }; |
| 1219 | 1219 | |
| 1220 | 1220 | fn atest(foo: *Foo) i32 { |
| ... | ... | @@ -1245,7 +1245,7 @@ test "spill target expr in a for loop, with a var decl in the loop body" { |
| 1245 | 1245 | } |
| 1246 | 1246 | |
| 1247 | 1247 | const Foo = struct { |
| 1248 | slice: []i32, | |
| 1248 | slice: []const i32, | |
| 1249 | 1249 | }; |
| 1250 | 1250 | |
| 1251 | 1251 | fn atest(foo: *Foo) i32 { |
test/stage1/behavior/struct.zig+59| ... | ... | @@ -709,3 +709,62 @@ test "packed struct field passed to generic function" { |
| 709 | 709 | var loaded = S.genericReadPackedField(&p.b); |
| 710 | 710 | expect(loaded == 29); |
| 711 | 711 | } |
| 712 | ||
| 713 | test "anonymous struct literal syntax" { | |
| 714 | const S = struct { | |
| 715 | const Point = struct { | |
| 716 | x: i32, | |
| 717 | y: i32, | |
| 718 | }; | |
| 719 | ||
| 720 | fn doTheTest() void { | |
| 721 | var p: Point = .{ | |
| 722 | .x = 1, | |
| 723 | .y = 2, | |
| 724 | }; | |
| 725 | expect(p.x == 1); | |
| 726 | expect(p.y == 2); | |
| 727 | } | |
| 728 | }; | |
| 729 | S.doTheTest(); | |
| 730 | comptime S.doTheTest(); | |
| 731 | } | |
| 732 | ||
| 733 | test "fully anonymous struct" { | |
| 734 | const S = struct { | |
| 735 | fn doTheTest() void { | |
| 736 | dump(.{ | |
| 737 | .int = @as(u32, 1234), | |
| 738 | .float = @as(f64, 12.34), | |
| 739 | .b = true, | |
| 740 | .s = "hi", | |
| 741 | }); | |
| 742 | } | |
| 743 | fn dump(args: var) void { | |
| 744 | expect(args.int == 1234); | |
| 745 | expect(args.float == 12.34); | |
| 746 | expect(args.b); | |
| 747 | expect(args.s[0] == 'h'); | |
| 748 | expect(args.s[1] == 'i'); | |
| 749 | } | |
| 750 | }; | |
| 751 | S.doTheTest(); | |
| 752 | comptime S.doTheTest(); | |
| 753 | } | |
| 754 | ||
| 755 | test "fully anonymous list literal" { | |
| 756 | const S = struct { | |
| 757 | fn doTheTest() void { | |
| 758 | dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"}); | |
| 759 | } | |
| 760 | fn dump(args: var) void { | |
| 761 | expect(args.@"0" == 1234); | |
| 762 | expect(args.@"1" == 12.34); | |
| 763 | expect(args.@"2"); | |
| 764 | expect(args.@"3"[0] == 'h'); | |
| 765 | expect(args.@"3"[1] == 'i'); | |
| 766 | } | |
| 767 | }; | |
| 768 | S.doTheTest(); | |
| 769 | comptime S.doTheTest(); | |
| 770 | } |
test/stage1/behavior/union.zig+22| ... | ... | @@ -549,3 +549,25 @@ test "initialize global array of union" { |
| 549 | 549 | expect(glbl_array[0].U0 == 1); |
| 550 | 550 | expect(glbl_array[1].U1 == 2); |
| 551 | 551 | } |
| 552 | ||
| 553 | test "anonymous union literal syntax" { | |
| 554 | const S = struct { | |
| 555 | const Number = union { | |
| 556 | int: i32, | |
| 557 | float: f64, | |
| 558 | }; | |
| 559 | ||
| 560 | fn doTheTest() void { | |
| 561 | var i: Number = .{.int = 42}; | |
| 562 | var f = makeNumber(); | |
| 563 | expect(i.int == 42); | |
| 564 | expect(f.float == 12.34); | |
| 565 | } | |
| 566 | ||
| 567 | fn makeNumber() Number { | |
| 568 | return .{.float = 12.34}; | |
| 569 | } | |
| 570 | }; | |
| 571 | S.doTheTest(); | |
| 572 | comptime S.doTheTest(); | |
| 573 | } |