authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-24 15:19:48-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-24 15:19:48-07:00
logdf5f0517b33b5f7bc2a508cf6a0ee62246f02d21
tree64d664b74afd6d100be328b7225b87753bf62fd7
parenta9f25c7d642ec0ed047ae9be6ad87d102f3f75c8
parent9ff872c9829c20cb16d233534248c5cf371a8bd9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17205 from mlugg/rls-ref

compiler: preserve result type information through address-of operator

39 files changed, 1335 insertions(+), 1029 deletions(-)

lib/std/debug.zig+6-1
...@@ -514,7 +514,12 @@ pub const StackIterator = struct {...@@ -514,7 +514,12 @@ pub const StackIterator = struct {
514514
515 return StackIterator{515 return StackIterator{
516 .first_address = first_address,516 .first_address = first_address,
517 .fp = fp orelse @frameAddress(),517 // TODO: this is a workaround for #16876
518 //.fp = fp orelse @frameAddress(),
519 .fp = fp orelse blk: {
520 const fa = @frameAddress();
521 break :blk fa;
522 },
518 };523 };
519 }524 }
520525
src/AstGen.zig+318-305
...@@ -265,14 +265,17 @@ const ResultInfo = struct {...@@ -265,14 +265,17 @@ const ResultInfo = struct {
265 discard,265 discard,
266 /// The expression has an inferred type, and it will be evaluated as an rvalue.266 /// The expression has an inferred type, and it will be evaluated as an rvalue.
267 none,267 none,
268 /// The expression must generate a pointer rather than a value. For example, the left hand side
269 /// of an assignment uses this kind of result location.
270 ref,
271 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.268 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
272 ty: Zir.Inst.Ref,269 ty: Zir.Inst.Ref,
273 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,270 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
274 /// so no `as` instruction needs to be emitted.271 /// so no `as` instruction needs to be emitted.
275 coerced_ty: Zir.Inst.Ref,272 coerced_ty: Zir.Inst.Ref,
273 /// The expression must generate a pointer rather than a value. For example, the left hand side
274 /// of an assignment uses this kind of result location.
275 ref,
276 /// The expression must generate a pointer rather than a value, and the pointer will be coerced
277 /// by other code to this type, which is guaranteed by earlier instructions to be a pointer type.
278 ref_coerced_ty: Zir.Inst.Ref,
276 /// The expression must store its result into this typed pointer. The result instruction279 /// The expression must store its result into this typed pointer. The result instruction
277 /// from the expression must be ignored.280 /// from the expression must be ignored.
278 ptr: PtrResultLoc,281 ptr: PtrResultLoc,
...@@ -303,26 +306,30 @@ const ResultInfo = struct {...@@ -303,26 +306,30 @@ const ResultInfo = struct {
303 /// Find the result type for a cast builtin given the result location.306 /// Find the result type for a cast builtin given the result location.
304 /// If the location does not have a known result type, emits an error on307 /// If the location does not have a known result type, emits an error on
305 /// the given node.308 /// the given node.
306 fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {309 fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
307 const astgen = gz.astgen;310 return switch (rl) {
308 switch (rl) {311 .discard, .none, .ref, .inferred_ptr, .destructure => null,
309 .discard, .none, .ref, .inferred_ptr => {},312 .ty, .coerced_ty => |ty_ref| ty_ref,
310 .ty, .coerced_ty => |ty_ref| return ty_ref,313 .ref_coerced_ty => |ptr_ty| try gz.addUnNode(.elem_type, ptr_ty, node),
311 .ptr => |ptr| {314 .ptr => |ptr| {
312 const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);315 const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);
313 return gz.addUnNode(.elem_type, ptr_ty, node);316 return try gz.addUnNode(.elem_type, ptr_ty, node);
314 },
315 .destructure => |destructure| {
316 return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
317 try astgen.errNoteNode(destructure.src_node, "destructure expressions do not provide a single result type", .{}),
318 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
319 });
320 },317 },
321 }318 };
319 }
322320
323 return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{321 fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
324 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),322 const astgen = gz.astgen;
325 });323 if (try rl.resultType(gz, node)) |ty| return ty;
324 switch (rl) {
325 .destructure => |destructure| return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
326 try astgen.errNoteNode(destructure.src_node, "destructure expressions do not provide a single result type", .{}),
327 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
328 }),
329 else => return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
330 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
331 }),
332 }
326 }333 }
327 };334 };
328335
...@@ -933,7 +940,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -933,7 +940,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
933 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);940 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
934 _ = try gz.addUnNode(.validate_deref, lhs, node);941 _ = try gz.addUnNode(.validate_deref, lhs, node);
935 switch (ri.rl) {942 switch (ri.rl) {
936 .ref => return lhs,943 .ref, .ref_coerced_ty => return lhs,
937 else => {944 else => {
938 const result = try gz.addUnNode(.load, lhs, node);945 const result = try gz.addUnNode(.load, lhs, node);
939 return rvalue(gz, ri, result, node);946 return rvalue(gz, ri, result, node);
...@@ -941,7 +948,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -941,7 +948,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
941 }948 }
942 },949 },
943 .address_of => {950 .address_of => {
944 const result = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);951 const operand_rl: ResultInfo.Loc = if (try ri.rl.resultType(gz, node)) |res_ty_inst| rl: {
952 _ = try gz.addUnTok(.validate_ref_ty, res_ty_inst, tree.firstToken(node));
953 break :rl .{ .ref_coerced_ty = res_ty_inst };
954 } else .ref;
955 const result = try expr(gz, scope, .{ .rl = operand_rl }, node_datas[node].lhs);
945 return rvalue(gz, ri, result, node);956 return rvalue(gz, ri, result, node);
946 },957 },
947 .optional_type => {958 .optional_type => {
...@@ -950,7 +961,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -950,7 +961,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
950 return rvalue(gz, ri, result, node);961 return rvalue(gz, ri, result, node);
951 },962 },
952 .unwrap_optional => switch (ri.rl) {963 .unwrap_optional => switch (ri.rl) {
953 .ref => {964 .ref, .ref_coerced_ty => {
954 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);965 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
955966
956 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);967 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
...@@ -1001,7 +1012,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -1001,7 +1012,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
1001 else1012 else
1002 null;1013 null;
1003 switch (ri.rl) {1014 switch (ri.rl) {
1004 .ref => return orelseCatchExpr(1015 .ref, .ref_coerced_ty => return orelseCatchExpr(
1005 gz,1016 gz,
1006 scope,1017 scope,
1007 ri,1018 ri,
...@@ -1028,7 +1039,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -1028,7 +1039,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
1028 }1039 }
1029 },1040 },
1030 .@"orelse" => switch (ri.rl) {1041 .@"orelse" => switch (ri.rl) {
1031 .ref => return orelseCatchExpr(1042 .ref, .ref_coerced_ty => return orelseCatchExpr(
1032 gz,1043 gz,
1033 scope,1044 scope,
1034 ri,1045 ri,
...@@ -1432,73 +1443,75 @@ fn arrayInitExpr(...@@ -1432,73 +1443,75 @@ fn arrayInitExpr(
1432 break :inst .{ array_type_inst, .none };1443 break :inst .{ array_type_inst, .none };
1433 };1444 };
14341445
1446 if (array_ty != .none) {
1447 // Typed inits do not use RLS for language simplicity.
1448 switch (ri.rl) {
1449 .discard => {
1450 if (elem_ty != .none) {
1451 const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } };
1452 for (array_init.ast.elements) |elem_init| {
1453 _ = try expr(gz, scope, elem_ri, elem_init);
1454 }
1455 } else {
1456 for (array_init.ast.elements, 0..) |elem_init, i| {
1457 const this_elem_ty = try gz.add(.{
1458 .tag = .array_init_elem_type,
1459 .data = .{ .bin = .{
1460 .lhs = array_ty,
1461 .rhs = @enumFromInt(i),
1462 } },
1463 });
1464 _ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init);
1465 }
1466 }
1467 return .void_value;
1468 },
1469 .ref => return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, true),
1470 else => {
1471 const array_inst = try arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, false);
1472 return rvalue(gz, ri, array_inst, node);
1473 },
1474 }
1475 }
1476
1435 switch (ri.rl) {1477 switch (ri.rl) {
1478 .none => return arrayInitExprAnon(gz, scope, node, array_init.ast.elements),
1436 .discard => {1479 .discard => {
1437 if (elem_ty != .none) {1480 for (array_init.ast.elements) |elem_init| {
1438 const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } };1481 _ = try expr(gz, scope, .{ .rl = .discard }, elem_init);
1439 for (array_init.ast.elements) |elem_init| {
1440 _ = try expr(gz, scope, elem_ri, elem_init);
1441 }
1442 } else if (array_ty != .none) {
1443 for (array_init.ast.elements, 0..) |elem_init, i| {
1444 const this_elem_ty = try gz.add(.{
1445 .tag = .elem_type_index,
1446 .data = .{ .bin = .{
1447 .lhs = array_ty,
1448 .rhs = @enumFromInt(i),
1449 } },
1450 });
1451 _ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init);
1452 }
1453 } else {
1454 for (array_init.ast.elements) |elem_init| {
1455 _ = try expr(gz, scope, .{ .rl = .discard }, elem_init);
1456 }
1457 }1482 }
1458 return Zir.Inst.Ref.void_value;1483 return Zir.Inst.Ref.void_value;
1459 },1484 },
1460 .ref => {1485 .ref => {
1461 const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init_ref else .array_init_anon_ref;1486 const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
1462 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, tag);1487 return gz.addUnTok(.ref, result, tree.firstToken(node));
1463 },
1464 .none => {
1465 const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init else .array_init_anon;
1466 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, tag);
1467 },
1468 .ty, .coerced_ty => |ty_inst| {
1469 const arr_ty = if (array_ty != .none) array_ty else blk: {
1470 const arr_ty = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
1471 _ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{
1472 .ty = arr_ty,
1473 .init_count = @intCast(array_init.ast.elements.len),
1474 });
1475 break :blk arr_ty;
1476 };
1477 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, arr_ty, elem_ty, .array_init);
1478 return rvalue(gz, ri, result, node);
1479 },1488 },
1480 .ptr => |ptr_res| {1489 .ref_coerced_ty => |ptr_ty_inst| {
1481 return arrayInitExprRlPtr(gz, scope, node, ptr_res.inst, array_init.ast.elements, array_ty);1490 const dest_arr_ty_inst = try gz.addPlNode(.validate_array_init_ref_ty, node, Zir.Inst.ArrayInitRefTy{
1482 },1491 .ptr_ty = ptr_ty_inst,
1483 .inferred_ptr => |ptr_inst| {1492 .elem_count = @intCast(array_init.ast.elements.len),
1484 if (array_ty == .none) {1493 });
1485 // We treat this case differently so that we don't get a crash when1494 return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, dest_arr_ty_inst, .none, true);
1486 // analyzing array_base_ptr against an alloc_inferred_mut.1495 },
1487 // See corresponding logic in structInitExpr.1496 .ty, .coerced_ty => |result_ty_inst| {
1488 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);1497 _ = try gz.addPlNode(.validate_array_init_result_ty, node, Zir.Inst.ArrayInit{
1489 return rvalue(gz, ri, result, node);1498 .ty = result_ty_inst,
1490 } else {1499 .init_count = @intCast(array_init.ast.elements.len),
1491 return arrayInitExprRlPtr(gz, scope, node, ptr_inst, array_init.ast.elements, array_ty);1500 });
1492 }1501 return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, result_ty_inst, .none, false);
1502 },
1503 .ptr => |ptr| {
1504 try arrayInitExprPtr(gz, scope, node, array_init.ast.elements, ptr.inst);
1505 return .void_value;
1506 },
1507 .inferred_ptr => {
1508 // We can't get elem pointers of an untyped inferred alloc, so must perform a
1509 // standard anonymous initialization followed by an rvalue store.
1510 // See corresponding logic in structInitExpr.
1511 const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
1512 return rvalue(gz, ri, result, node);
1493 },1513 },
1494 .destructure => |destructure| {1514 .destructure => |destructure| {
1495 if (array_ty != .none) {
1496 // We have a specific type, so there may be things like default
1497 // field values messing with us. Do this as a standard typed
1498 // init followed by an rvalue destructure.
1499 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, .array_init);
1500 return rvalue(gz, ri, result, node);
1501 }
1502 // Untyped init - destructure directly into result pointers1515 // Untyped init - destructure directly into result pointers
1503 if (array_init.ast.elements.len != destructure.components.len) {1516 if (array_init.ast.elements.len != destructure.components.len) {
1504 return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{1517 return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{
...@@ -1521,12 +1534,12 @@ fn arrayInitExpr(...@@ -1521,12 +1534,12 @@ fn arrayInitExpr(
1521 }1534 }
1522}1535}
15231536
1524fn arrayInitExprRlNone(1537/// An array initialization expression using an `array_init_anon` instruction.
1538fn arrayInitExprAnon(
1525 gz: *GenZir,1539 gz: *GenZir,
1526 scope: *Scope,1540 scope: *Scope,
1527 node: Ast.Node.Index,1541 node: Ast.Node.Index,
1528 elements: []const Ast.Node.Index,1542 elements: []const Ast.Node.Index,
1529 tag: Zir.Inst.Tag,
1530) InnerError!Zir.Inst.Ref {1543) InnerError!Zir.Inst.Ref {
1531 const astgen = gz.astgen;1544 const astgen = gz.astgen;
15321545
...@@ -1540,95 +1553,84 @@ fn arrayInitExprRlNone(...@@ -1540,95 +1553,84 @@ fn arrayInitExprRlNone(
1540 astgen.extra.items[extra_index] = @intFromEnum(elem_ref);1553 astgen.extra.items[extra_index] = @intFromEnum(elem_ref);
1541 extra_index += 1;1554 extra_index += 1;
1542 }1555 }
1543 return try gz.addPlNodePayloadIndex(tag, node, payload_index);1556 return try gz.addPlNodePayloadIndex(.array_init_anon, node, payload_index);
1544}1557}
15451558
1546fn arrayInitExprInner(1559/// An array initialization expression using an `array_init` or `array_init_ref` instruction.
1560fn arrayInitExprTyped(
1547 gz: *GenZir,1561 gz: *GenZir,
1548 scope: *Scope,1562 scope: *Scope,
1549 node: Ast.Node.Index,1563 node: Ast.Node.Index,
1550 elements: []const Ast.Node.Index,1564 elements: []const Ast.Node.Index,
1551 array_ty_inst: Zir.Inst.Ref,1565 ty_inst: Zir.Inst.Ref,
1552 elem_ty: Zir.Inst.Ref,1566 maybe_elem_ty_inst: Zir.Inst.Ref,
1553 tag: Zir.Inst.Tag,1567 is_ref: bool,
1554) InnerError!Zir.Inst.Ref {1568) InnerError!Zir.Inst.Ref {
1555 const astgen = gz.astgen;1569 const astgen = gz.astgen;
15561570
1557 const len = elements.len + @intFromBool(array_ty_inst != .none);1571 const len = elements.len + 1; // +1 for type
1558 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{1572 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
1559 .operands_len = @intCast(len),1573 .operands_len = @intCast(len),
1560 });1574 });
1561 var extra_index = try reserveExtra(astgen, len);1575 var extra_index = try reserveExtra(astgen, len);
1562 if (array_ty_inst != .none) {1576 astgen.extra.items[extra_index] = @intFromEnum(ty_inst);
1563 astgen.extra.items[extra_index] = @intFromEnum(array_ty_inst);1577 extra_index += 1;
1564 extra_index += 1;
1565 }
15661578
1567 for (elements, 0..) |elem_init, i| {1579 if (maybe_elem_ty_inst != .none) {
1568 const ri = if (elem_ty != .none)1580 const elem_ri: ResultInfo = .{ .rl = .{ .coerced_ty = maybe_elem_ty_inst } };
1569 ResultInfo{ .rl = .{ .coerced_ty = elem_ty } }1581 for (elements) |elem_init| {
1570 else if (array_ty_inst != .none) ri: {1582 const elem_inst = try expr(gz, scope, elem_ri, elem_init);
1571 const ty_expr = try gz.add(.{1583 astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
1572 .tag = .elem_type_index,1584 extra_index += 1;
1585 }
1586 } else {
1587 for (elements, 0..) |elem_init, i| {
1588 const ri: ResultInfo = .{ .rl = .{ .coerced_ty = try gz.add(.{
1589 .tag = .array_init_elem_type,
1573 .data = .{ .bin = .{1590 .data = .{ .bin = .{
1574 .lhs = array_ty_inst,1591 .lhs = ty_inst,
1575 .rhs = @enumFromInt(i),1592 .rhs = @enumFromInt(i),
1576 } },1593 } },
1577 });1594 }) } };
1578 break :ri ResultInfo{ .rl = .{ .coerced_ty = ty_expr } };
1579 } else ResultInfo{ .rl = .{ .none = {} } };
15801595
1581 const elem_ref = try expr(gz, scope, ri, elem_init);1596 const elem_inst = try expr(gz, scope, ri, elem_init);
1582 astgen.extra.items[extra_index] = @intFromEnum(elem_ref);1597 astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
1583 extra_index += 1;1598 extra_index += 1;
1599 }
1584 }1600 }
15851601
1602 const tag: Zir.Inst.Tag = if (is_ref) .array_init_ref else .array_init;
1586 return try gz.addPlNodePayloadIndex(tag, node, payload_index);1603 return try gz.addPlNodePayloadIndex(tag, node, payload_index);
1587}1604}
15881605
1589fn arrayInitExprRlPtr(1606/// An array initialization expression using element pointers.
1607fn arrayInitExprPtr(
1590 gz: *GenZir,1608 gz: *GenZir,
1591 scope: *Scope,1609 scope: *Scope,
1592 node: Ast.Node.Index,1610 node: Ast.Node.Index,
1593 result_ptr: Zir.Inst.Ref,
1594 elements: []const Ast.Node.Index,1611 elements: []const Ast.Node.Index,
1595 array_ty: Zir.Inst.Ref,1612 ptr_inst: Zir.Inst.Ref,
1596) InnerError!Zir.Inst.Ref {1613) InnerError!void {
1597 if (array_ty == .none) {
1598 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node);
1599 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements);
1600 }
1601
1602 const casted_ptr = try gz.addPlNode(.coerce_result_ptr, node, Zir.Inst.Bin{ .lhs = array_ty, .rhs = result_ptr });
1603 return arrayInitExprRlPtrInner(gz, scope, node, casted_ptr, elements);
1604}
1605
1606fn arrayInitExprRlPtrInner(
1607 gz: *GenZir,
1608 scope: *Scope,
1609 node: Ast.Node.Index,
1610 result_ptr: Zir.Inst.Ref,
1611 elements: []const Ast.Node.Index,
1612) InnerError!Zir.Inst.Ref {
1613 const astgen = gz.astgen;1614 const astgen = gz.astgen;
16141615
1616 const array_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
1617
1615 const payload_index = try addExtra(astgen, Zir.Inst.Block{1618 const payload_index = try addExtra(astgen, Zir.Inst.Block{
1616 .body_len = @intCast(elements.len),1619 .body_len = @intCast(elements.len),
1617 });1620 });
1618 var extra_index = try reserveExtra(astgen, elements.len);1621 var extra_index = try reserveExtra(astgen, elements.len);
16191622
1620 for (elements, 0..) |elem_init, i| {1623 for (elements, 0..) |elem_init, i| {
1621 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{1624 const elem_ptr_inst = try gz.addPlNode(.array_init_elem_ptr, elem_init, Zir.Inst.ElemPtrImm{
1622 .ptr = result_ptr,1625 .ptr = array_ptr_inst,
1623 .index = @intCast(i),1626 .index = @intCast(i),
1624 });1627 });
1625 astgen.extra.items[extra_index] = refToIndex(elem_ptr).?;1628 astgen.extra.items[extra_index] = refToIndex(elem_ptr_inst).?;
1626 extra_index += 1;1629 extra_index += 1;
1627 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr } } }, elem_init);1630 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr_inst } } }, elem_init);
1628 }1631 }
16291632
1630 _ = try gz.addPlNodePayloadIndex(.validate_array_init, node, payload_index);1633 _ = try gz.addPlNodePayloadIndex(.validate_ptr_array_init, node, payload_index);
1631 return .void_value;
1632}1634}
16331635
1634fn structInitExpr(1636fn structInitExpr(
...@@ -1643,7 +1645,26 @@ fn structInitExpr(...@@ -1643,7 +1645,26 @@ fn structInitExpr(
16431645
1644 if (struct_init.ast.type_expr == 0) {1646 if (struct_init.ast.type_expr == 0) {
1645 if (struct_init.ast.fields.len == 0) {1647 if (struct_init.ast.fields.len == 0) {
1646 return rvalue(gz, ri, .empty_struct, node);1648 // Anonymous init with no fields.
1649 switch (ri.rl) {
1650 .discard => return .void_value,
1651 .ref_coerced_ty => |ptr_ty_inst| return gz.addUnNode(.struct_init_empty_ref_result, ptr_ty_inst, node),
1652 .ty, .coerced_ty => |ty_inst| return gz.addUnNode(.struct_init_empty_result, ty_inst, node),
1653 .ptr => {
1654 // TODO: should we modify this to use RLS for the field stores here?
1655 const ty_inst = (try ri.rl.resultType(gz, node)).?;
1656 const val = try gz.addUnNode(.struct_init_empty_result, ty_inst, node);
1657 return rvalue(gz, ri, val, node);
1658 },
1659 .none, .ref, .inferred_ptr => {
1660 return rvalue(gz, ri, .empty_struct, node);
1661 },
1662 .destructure => |destructure| {
1663 return astgen.failNodeNotes(node, "empty initializer cannot be destructured", .{}, &.{
1664 try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
1665 });
1666 },
1667 }
1647 }1668 }
1648 } else array: {1669 } else array: {
1649 const node_tags = tree.nodes.items(.tag);1670 const node_tags = tree.nodes.items(.tag);
...@@ -1694,86 +1715,67 @@ fn structInitExpr(...@@ -1694,86 +1715,67 @@ fn structInitExpr(
1694 }1715 }
1695 }1716 }
16961717
1718 if (struct_init.ast.type_expr != 0) {
1719 // Typed inits do not use RLS for language simplicity.
1720 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1721 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1722 switch (ri.rl) {
1723 .ref => return structInitExprTyped(gz, scope, node, struct_init, ty_inst, true),
1724 else => {
1725 const struct_inst = try structInitExprTyped(gz, scope, node, struct_init, ty_inst, false);
1726 return rvalue(gz, ri, struct_inst, node);
1727 },
1728 }
1729 }
1730
1697 switch (ri.rl) {1731 switch (ri.rl) {
1732 .none => return structInitExprAnon(gz, scope, node, struct_init),
1698 .discard => {1733 .discard => {
1699 if (struct_init.ast.type_expr != 0) {1734 // Even if discarding we must perform an anonymous init to check for duplicate field names.
1700 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1735 // TODO: should duplicate field names be caught in AstGen?
1701 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);1736 _ = try structInitExprAnon(gz, scope, node, struct_init);
1702 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1737 return .void_value;
1703 } else {
1704 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
1705 }
1706 return Zir.Inst.Ref.void_value;
1707 },1738 },
1708 .ref => {1739 .ref => {
1709 if (struct_init.ast.type_expr != 0) {1740 const result = try structInitExprAnon(gz, scope, node, struct_init);
1710 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1741 return gz.addUnTok(.ref, result, tree.firstToken(node));
1711 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1712 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
1713 } else {
1714 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref);
1715 }
1716 },1742 },
1717 .none => {1743 .ref_coerced_ty => |ptr_ty_inst| {
1718 if (struct_init.ast.type_expr != 0) {1744 const result_ty_inst = try gz.addUnNode(.elem_type, ptr_ty_inst, node);
1719 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1745 _ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
1720 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);1746 return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, true);
1721 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1722 } else {
1723 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
1724 }
1725 },1747 },
1726 .ty, .coerced_ty => |ty_inst| {1748 .ty, .coerced_ty => |result_ty_inst| {
1727 if (struct_init.ast.type_expr == 0) {1749 _ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
1728 const struct_ty_inst = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);1750 return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, false);
1729 _ = try gz.addUnNode(.validate_struct_init_ty, struct_ty_inst, node);
1730 const result = try structInitExprRlTy(gz, scope, node, struct_init, struct_ty_inst, .struct_init);
1731 return rvalue(gz, ri, result, node);
1732 }
1733 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1734 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node);
1735 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
1736 return rvalue(gz, ri, result, node);
1737 },1751 },
1738 .ptr => |ptr_res| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_res.inst),1752 .ptr => |ptr| {
1739 .inferred_ptr => |ptr_inst| {1753 try structInitExprPtr(gz, scope, node, struct_init, ptr.inst);
1740 if (struct_init.ast.type_expr == 0) {1754 return .void_value;
1741 // We treat this case differently so that we don't get a crash when1755 },
1742 // analyzing field_base_ptr against an alloc_inferred_mut.1756 .inferred_ptr => {
1743 // See corresponding logic in arrayInitExpr.1757 // We can't get field pointers of an untyped inferred alloc, so must perform a
1744 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);1758 // standard anonymous initialization followed by an rvalue store.
1745 return rvalue(gz, ri, result, node);1759 // See corresponding logic in arrayInitExpr.
1746 } else {1760 const struct_inst = try structInitExprAnon(gz, scope, node, struct_init);
1747 return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst);1761 return rvalue(gz, ri, struct_inst, node);
1748 }
1749 },1762 },
1750 .destructure => |destructure| {1763 .destructure => |destructure| {
1751 if (struct_init.ast.type_expr == 0) {1764 // This is an untyped init, so is an actual struct, which does
1752 // This is an untyped init, so is an actual struct, which does1765 // not support destructuring.
1753 // not support destructuring.1766 return astgen.failNodeNotes(node, "struct value cannot be destructured", .{}, &.{
1754 return astgen.failNodeNotes(node, "struct value cannot be destructured", .{}, &.{1767 try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
1755 try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),1768 });
1756 });
1757 }
1758 // You can init tuples using struct init syntax and numeric field
1759 // names, but as with array inits, we could be bitten by default
1760 // fields. Therefore, we do a normal typed init then an rvalue
1761 // destructure.
1762 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1763 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1764 const result = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1765 return rvalue(gz, ri, result, node);
1766 },1769 },
1767 }1770 }
1768}1771}
17691772
1770fn structInitExprRlNone(1773/// A struct initialization expression using a `struct_init_anon` instruction.
1774fn structInitExprAnon(
1771 gz: *GenZir,1775 gz: *GenZir,
1772 scope: *Scope,1776 scope: *Scope,
1773 node: Ast.Node.Index,1777 node: Ast.Node.Index,
1774 struct_init: Ast.full.StructInit,1778 struct_init: Ast.full.StructInit,
1775 ty_inst: Zir.Inst.Ref,
1776 tag: Zir.Inst.Tag,
1777) InnerError!Zir.Inst.Ref {1779) InnerError!Zir.Inst.Ref {
1778 const astgen = gz.astgen;1780 const astgen = gz.astgen;
1779 const tree = astgen.tree;1781 const tree = astgen.tree;
...@@ -1787,104 +1789,83 @@ fn structInitExprRlNone(...@@ -1787,104 +1789,83 @@ fn structInitExprRlNone(
1787 for (struct_init.ast.fields) |field_init| {1789 for (struct_init.ast.fields) |field_init| {
1788 const name_token = tree.firstToken(field_init) - 2;1790 const name_token = tree.firstToken(field_init) - 2;
1789 const str_index = try astgen.identAsString(name_token);1791 const str_index = try astgen.identAsString(name_token);
1790 const sub_ri: ResultInfo = if (ty_inst != .none)
1791 ResultInfo{ .rl = .{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
1792 .container_type = ty_inst,
1793 .name_start = str_index,
1794 }) } }
1795 else
1796 .{ .rl = .none };
1797 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{1792 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
1798 .field_name = str_index,1793 .field_name = str_index,
1799 .init = try expr(gz, scope, sub_ri, field_init),1794 .init = try expr(gz, scope, .{ .rl = .none }, field_init),
1800 });1795 });
1801 extra_index += field_size;1796 extra_index += field_size;
1802 }1797 }
18031798
1804 return try gz.addPlNodePayloadIndex(tag, node, payload_index);1799 return gz.addPlNodePayloadIndex(.struct_init_anon, node, payload_index);
1805}
1806
1807fn structInitExprRlPtr(
1808 gz: *GenZir,
1809 scope: *Scope,
1810 node: Ast.Node.Index,
1811 struct_init: Ast.full.StructInit,
1812 result_ptr: Zir.Inst.Ref,
1813) InnerError!Zir.Inst.Ref {
1814 if (struct_init.ast.type_expr == 0) {
1815 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node);
1816 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr);
1817 }
1818 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1819 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1820
1821 const casted_ptr = try gz.addPlNode(.coerce_result_ptr, node, Zir.Inst.Bin{ .lhs = ty_inst, .rhs = result_ptr });
1822 return structInitExprRlPtrInner(gz, scope, node, struct_init, casted_ptr);
1823}1800}
18241801
1825fn structInitExprRlPtrInner(1802/// A struct initialization expression using a `struct_init` or `struct_init_ref` instruction.
1803fn structInitExprTyped(
1826 gz: *GenZir,1804 gz: *GenZir,
1827 scope: *Scope,1805 scope: *Scope,
1828 node: Ast.Node.Index,1806 node: Ast.Node.Index,
1829 struct_init: Ast.full.StructInit,1807 struct_init: Ast.full.StructInit,
1830 result_ptr: Zir.Inst.Ref,1808 ty_inst: Zir.Inst.Ref,
1809 is_ref: bool,
1831) InnerError!Zir.Inst.Ref {1810) InnerError!Zir.Inst.Ref {
1832 const astgen = gz.astgen;1811 const astgen = gz.astgen;
1833 const tree = astgen.tree;1812 const tree = astgen.tree;
18341813
1835 const payload_index = try addExtra(astgen, Zir.Inst.Block{1814 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
1836 .body_len = @intCast(struct_init.ast.fields.len),1815 .fields_len = @intCast(struct_init.ast.fields.len),
1837 });1816 });
1838 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len);1817 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len;
1818 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size);
18391819
1840 for (struct_init.ast.fields) |field_init| {1820 for (struct_init.ast.fields) |field_init| {
1841 const name_token = tree.firstToken(field_init) - 2;1821 const name_token = tree.firstToken(field_init) - 2;
1842 const str_index = try astgen.identAsString(name_token);1822 const str_index = try astgen.identAsString(name_token);
1843 const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{1823 const field_ty_inst = try gz.addPlNode(.struct_init_field_type, field_init, Zir.Inst.FieldType{
1844 .lhs = result_ptr,1824 .container_type = ty_inst,
1845 .field_name_start = str_index,1825 .name_start = str_index,
1846 });1826 });
1847 astgen.extra.items[extra_index] = refToIndex(field_ptr).?;1827 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{
1848 extra_index += 1;1828 .field_type = refToIndex(field_ty_inst).?,
1849 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init);1829 .init = try expr(gz, scope, .{ .rl = .{ .coerced_ty = field_ty_inst } }, field_init),
1830 });
1831 extra_index += field_size;
1850 }1832 }
18511833
1852 _ = try gz.addPlNodePayloadIndex(.validate_struct_init, node, payload_index);1834 const tag: Zir.Inst.Tag = if (is_ref) .struct_init_ref else .struct_init;
1853 return Zir.Inst.Ref.void_value;1835 return gz.addPlNodePayloadIndex(tag, node, payload_index);
1854}1836}
18551837
1856fn structInitExprRlTy(1838/// A struct initialization expression using field pointers.
1839fn structInitExprPtr(
1857 gz: *GenZir,1840 gz: *GenZir,
1858 scope: *Scope,1841 scope: *Scope,
1859 node: Ast.Node.Index,1842 node: Ast.Node.Index,
1860 struct_init: Ast.full.StructInit,1843 struct_init: Ast.full.StructInit,
1861 ty_inst: Zir.Inst.Ref,1844 ptr_inst: Zir.Inst.Ref,
1862 tag: Zir.Inst.Tag,1845) InnerError!void {
1863) InnerError!Zir.Inst.Ref {
1864 const astgen = gz.astgen;1846 const astgen = gz.astgen;
1865 const tree = astgen.tree;1847 const tree = astgen.tree;
18661848
1867 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{1849 const struct_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
1868 .fields_len = @intCast(struct_init.ast.fields.len),1850
1851 const payload_index = try addExtra(astgen, Zir.Inst.Block{
1852 .body_len = @intCast(struct_init.ast.fields.len),
1869 });1853 });
1870 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len;1854 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len);
1871 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size);
18721855
1873 for (struct_init.ast.fields) |field_init| {1856 for (struct_init.ast.fields) |field_init| {
1874 const name_token = tree.firstToken(field_init) - 2;1857 const name_token = tree.firstToken(field_init) - 2;
1875 const str_index = try astgen.identAsString(name_token);1858 const str_index = try astgen.identAsString(name_token);
1876 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{1859 const field_ptr = try gz.addPlNode(.struct_init_field_ptr, field_init, Zir.Inst.Field{
1877 .container_type = ty_inst,1860 .lhs = struct_ptr_inst,
1878 .name_start = str_index,1861 .field_name_start = str_index,
1879 });
1880 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{
1881 .field_type = refToIndex(field_ty_inst).?,
1882 .init = try expr(gz, scope, .{ .rl = .{ .ty = field_ty_inst } }, field_init),
1883 });1862 });
1884 extra_index += field_size;1863 astgen.extra.items[extra_index] = refToIndex(field_ptr).?;
1864 extra_index += 1;
1865 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init);
1885 }1866 }
18861867
1887 return try gz.addPlNodePayloadIndex(tag, node, payload_index);1868 _ = try gz.addPlNodePayloadIndex(.validate_ptr_struct_init, node, payload_index);
1888}1869}
18891870
1890/// This explicitly calls expr in a comptime scope by wrapping it in a `block_comptime` if1871/// This explicitly calls expr in a comptime scope by wrapping it in a `block_comptime` if
...@@ -2314,7 +2295,7 @@ fn labeledBlockExpr(...@@ -2314,7 +2295,7 @@ fn labeledBlockExpr(
2314 const need_rl = astgen.nodes_need_rl.contains(block_node);2295 const need_rl = astgen.nodes_need_rl.contains(block_node);
2315 const block_ri: ResultInfo = if (need_rl) ri else .{2296 const block_ri: ResultInfo = if (need_rl) ri else .{
2316 .rl = switch (ri.rl) {2297 .rl = switch (ri.rl) {
2317 .ptr => .{ .ty = try ri.rl.resultType(gz, block_node, undefined) },2298 .ptr => .{ .ty = (try ri.rl.resultType(gz, block_node)).? },
2318 .inferred_ptr => .none,2299 .inferred_ptr => .none,
2319 else => ri.rl,2300 else => ri.rl,
2320 },2301 },
...@@ -2504,7 +2485,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2504,7 +2485,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2504 .array_mul,2485 .array_mul,
2505 .array_type,2486 .array_type,
2506 .array_type_sentinel,2487 .array_type_sentinel,
2507 .elem_type_index,
2508 .elem_type,2488 .elem_type,
2509 .indexable_ptr_elem_type,2489 .indexable_ptr_elem_type,
2510 .vector_elem_type,2490 .vector_elem_type,
...@@ -2531,7 +2511,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2531,7 +2511,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2531 .cmp_gte,2511 .cmp_gte,
2532 .cmp_gt,2512 .cmp_gt,
2533 .cmp_neq,2513 .cmp_neq,
2534 .coerce_result_ptr,
2535 .decl_ref,2514 .decl_ref,
2536 .decl_val,2515 .decl_val,
2537 .load,2516 .load,
...@@ -2539,11 +2518,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2539,11 +2518,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2539 .elem_ptr,2518 .elem_ptr,
2540 .elem_val,2519 .elem_val,
2541 .elem_ptr_node,2520 .elem_ptr_node,
2542 .elem_ptr_imm,
2543 .elem_val_node,2521 .elem_val_node,
2544 .elem_val_imm,2522 .elem_val_imm,
2545 .field_ptr,2523 .field_ptr,
2546 .field_ptr_init,
2547 .field_val,2524 .field_val,
2548 .field_ptr_named,2525 .field_ptr_named,
2549 .field_val_named,2526 .field_val_named,
...@@ -2599,17 +2576,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2599,17 +2576,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2599 .import,2576 .import,
2600 .switch_block,2577 .switch_block,
2601 .switch_block_ref,2578 .switch_block_ref,
2602 .struct_init_empty,
2603 .struct_init,
2604 .struct_init_ref,
2605 .struct_init_anon,
2606 .struct_init_anon_ref,
2607 .array_init,
2608 .array_init_anon,
2609 .array_init_ref,
2610 .array_init_anon_ref,
2611 .union_init,2579 .union_init,
2612 .field_type,
2613 .field_type_ref,2580 .field_type_ref,
2614 .error_set_decl,2581 .error_set_decl,
2615 .error_set_decl_anon,2582 .error_set_decl_anon,
...@@ -2680,14 +2647,27 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2680,14 +2647,27 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2680 .@"await",2647 .@"await",
2681 .ret_err_value_code,2648 .ret_err_value_code,
2682 .closure_get,2649 .closure_get,
2683 .array_base_ptr,
2684 .field_base_ptr,
2685 .ret_ptr,2650 .ret_ptr,
2686 .ret_type,2651 .ret_type,
2687 .for_len,2652 .for_len,
2688 .@"try",2653 .@"try",
2689 .try_ptr,2654 .try_ptr,
2690 .opt_eu_base_ty,2655 .opt_eu_base_ptr_init,
2656 .coerce_ptr_elem_ty,
2657 .struct_init_empty,
2658 .struct_init_empty_result,
2659 .struct_init_empty_ref_result,
2660 .struct_init_anon,
2661 .struct_init,
2662 .struct_init_ref,
2663 .struct_init_field_type,
2664 .struct_init_field_ptr,
2665 .array_init_anon,
2666 .array_init,
2667 .array_init_ref,
2668 .validate_array_init_ref_ty,
2669 .array_init_elem_type,
2670 .array_init_elem_ptr,
2691 => break :b false,2671 => break :b false,
26922672
2693 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {2673 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
...@@ -2738,18 +2718,21 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2738,18 +2718,21 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2738 .store_node,2718 .store_node,
2739 .store_to_inferred_ptr,2719 .store_to_inferred_ptr,
2740 .resolve_inferred_alloc,2720 .resolve_inferred_alloc,
2741 .validate_struct_init,
2742 .validate_array_init,
2743 .set_runtime_safety,2721 .set_runtime_safety,
2744 .closure_capture,2722 .closure_capture,
2745 .memcpy,2723 .memcpy,
2746 .memset,2724 .memset,
2747 .validate_array_init_ty,
2748 .validate_struct_init_ty,
2749 .validate_deref,2725 .validate_deref,
2750 .validate_destructure,2726 .validate_destructure,
2751 .save_err_ret_index,2727 .save_err_ret_index,
2752 .restore_err_ret_index,2728 .restore_err_ret_index,
2729 .validate_struct_init_ty,
2730 .validate_struct_init_result_ty,
2731 .validate_ptr_struct_init,
2732 .validate_array_init_ty,
2733 .validate_array_init_result_ty,
2734 .validate_ptr_array_init,
2735 .validate_ref_ty,
2753 => break :b true,2736 => break :b true,
27542737
2755 .@"defer" => unreachable,2738 .@"defer" => unreachable,
...@@ -5635,7 +5618,7 @@ fn tryExpr(...@@ -5635,7 +5618,7 @@ fn tryExpr(
5635 const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };5618 const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
56365619
5637 const operand_ri: ResultInfo = switch (ri.rl) {5620 const operand_ri: ResultInfo = switch (ri.rl) {
5638 .ref => .{ .rl = .ref, .ctx = .error_handling_expr },5621 .ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr },
5639 else => .{ .rl = .none, .ctx = .error_handling_expr },5622 else => .{ .rl = .none, .ctx = .error_handling_expr },
5640 };5623 };
5641 // This could be a pointer or value depending on the `ri` parameter.5624 // This could be a pointer or value depending on the `ri` parameter.
...@@ -5648,7 +5631,7 @@ fn tryExpr(...@@ -5648,7 +5631,7 @@ fn tryExpr(
5648 defer else_scope.unstack();5631 defer else_scope.unstack();
56495632
5650 const err_tag = switch (ri.rl) {5633 const err_tag = switch (ri.rl) {
5651 .ref => Zir.Inst.Tag.err_union_code_ptr,5634 .ref, .ref_coerced_ty => Zir.Inst.Tag.err_union_code_ptr,
5652 else => Zir.Inst.Tag.err_union_code,5635 else => Zir.Inst.Tag.err_union_code,
5653 };5636 };
5654 const err_code = try else_scope.addUnNode(err_tag, operand, node);5637 const err_code = try else_scope.addUnNode(err_tag, operand, node);
...@@ -5659,7 +5642,7 @@ fn tryExpr(...@@ -5659,7 +5642,7 @@ fn tryExpr(
5659 try else_scope.setTryBody(try_inst, operand);5642 try else_scope.setTryBody(try_inst, operand);
5660 const result = indexToRef(try_inst);5643 const result = indexToRef(try_inst);
5661 switch (ri.rl) {5644 switch (ri.rl) {
5662 .ref => return result,5645 .ref, .ref_coerced_ty => return result,
5663 else => return rvalue(parent_gz, ri, result, node),5646 else => return rvalue(parent_gz, ri, result, node),
5664 }5647 }
5665}5648}
...@@ -5682,7 +5665,7 @@ fn orelseCatchExpr(...@@ -5682,7 +5665,7 @@ fn orelseCatchExpr(
5682 const need_rl = astgen.nodes_need_rl.contains(node);5665 const need_rl = astgen.nodes_need_rl.contains(node);
5683 const block_ri: ResultInfo = if (need_rl) ri else .{5666 const block_ri: ResultInfo = if (need_rl) ri else .{
5684 .rl = switch (ri.rl) {5667 .rl = switch (ri.rl) {
5685 .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },5668 .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
5686 .inferred_ptr => .none,5669 .inferred_ptr => .none,
5687 else => ri.rl,5670 else => ri.rl,
5688 },5671 },
...@@ -5700,7 +5683,7 @@ fn orelseCatchExpr(...@@ -5700,7 +5683,7 @@ fn orelseCatchExpr(
5700 defer block_scope.unstack();5683 defer block_scope.unstack();
57015684
5702 const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) {5685 const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) {
5703 .ref => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none },5686 .ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none },
5704 else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none },5687 else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none },
5705 };5688 };
5706 // This could be a pointer or value depending on the `operand_ri` parameter.5689 // This could be a pointer or value depending on the `operand_ri` parameter.
...@@ -5722,7 +5705,7 @@ fn orelseCatchExpr(...@@ -5722,7 +5705,7 @@ fn orelseCatchExpr(
5722 // This could be a pointer or value depending on `unwrap_op`.5705 // This could be a pointer or value depending on `unwrap_op`.
5723 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);5706 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
5724 const then_result = switch (ri.rl) {5707 const then_result = switch (ri.rl) {
5725 .ref => unwrapped_payload,5708 .ref, .ref_coerced_ty => unwrapped_payload,
5726 else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node),5709 else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node),
5727 };5710 };
5728 _ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node);5711 _ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node);
...@@ -5793,7 +5776,7 @@ fn fieldAccess(...@@ -5793,7 +5776,7 @@ fn fieldAccess(
5793 node: Ast.Node.Index,5776 node: Ast.Node.Index,
5794) InnerError!Zir.Inst.Ref {5777) InnerError!Zir.Inst.Ref {
5795 switch (ri.rl) {5778 switch (ri.rl) {
5796 .ref => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),5779 .ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),
5797 else => {5780 else => {
5798 const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node);5781 const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node);
5799 return rvalue(gz, ri, access, node);5782 return rvalue(gz, ri, access, node);
...@@ -5837,7 +5820,7 @@ fn arrayAccess(...@@ -5837,7 +5820,7 @@ fn arrayAccess(
5837 const tree = gz.astgen.tree;5820 const tree = gz.astgen.tree;
5838 const node_datas = tree.nodes.items(.data);5821 const node_datas = tree.nodes.items(.data);
5839 switch (ri.rl) {5822 switch (ri.rl) {
5840 .ref => {5823 .ref, .ref_coerced_ty => {
5841 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);5824 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
58425825
5843 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);5826 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
...@@ -5951,7 +5934,7 @@ fn ifExpr(...@@ -5951,7 +5934,7 @@ fn ifExpr(
5951 const need_rl = astgen.nodes_need_rl.contains(node);5934 const need_rl = astgen.nodes_need_rl.contains(node);
5952 const block_ri: ResultInfo = if (need_rl) ri else .{5935 const block_ri: ResultInfo = if (need_rl) ri else .{
5953 .rl = switch (ri.rl) {5936 .rl = switch (ri.rl) {
5954 .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },5937 .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
5955 .inferred_ptr => .none,5938 .inferred_ptr => .none,
5956 else => ri.rl,5939 else => ri.rl,
5957 },5940 },
...@@ -6181,7 +6164,7 @@ fn whileExpr(...@@ -6181,7 +6164,7 @@ fn whileExpr(
6181 const need_rl = astgen.nodes_need_rl.contains(node);6164 const need_rl = astgen.nodes_need_rl.contains(node);
6182 const block_ri: ResultInfo = if (need_rl) ri else .{6165 const block_ri: ResultInfo = if (need_rl) ri else .{
6183 .rl = switch (ri.rl) {6166 .rl = switch (ri.rl) {
6184 .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },6167 .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
6185 .inferred_ptr => .none,6168 .inferred_ptr => .none,
6186 else => ri.rl,6169 else => ri.rl,
6187 },6170 },
...@@ -6455,7 +6438,7 @@ fn forExpr(...@@ -6455,7 +6438,7 @@ fn forExpr(
6455 const need_rl = astgen.nodes_need_rl.contains(node);6438 const need_rl = astgen.nodes_need_rl.contains(node);
6456 const block_ri: ResultInfo = if (need_rl) ri else .{6439 const block_ri: ResultInfo = if (need_rl) ri else .{
6457 .rl = switch (ri.rl) {6440 .rl = switch (ri.rl) {
6458 .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) },6441 .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? },
6459 .inferred_ptr => .none,6442 .inferred_ptr => .none,
6460 else => ri.rl,6443 else => ri.rl,
6461 },6444 },
...@@ -6773,7 +6756,7 @@ fn switchExpr(...@@ -6773,7 +6756,7 @@ fn switchExpr(
6773 const need_rl = astgen.nodes_need_rl.contains(switch_node);6756 const need_rl = astgen.nodes_need_rl.contains(switch_node);
6774 const block_ri: ResultInfo = if (need_rl) ri else .{6757 const block_ri: ResultInfo = if (need_rl) ri else .{
6775 .rl = switch (ri.rl) {6758 .rl = switch (ri.rl) {
6776 .ptr => .{ .ty = try ri.rl.resultType(parent_gz, switch_node, undefined) },6759 .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, switch_node)).? },
6777 .inferred_ptr => .none,6760 .inferred_ptr => .none,
6778 else => ri.rl,6761 else => ri.rl,
6779 },6762 },
...@@ -7465,7 +7448,7 @@ fn localVarRef(...@@ -7465,7 +7448,7 @@ fn localVarRef(
7465 gpa,7448 gpa,
7466 );7449 );
74677450
7468 return rvalue(gz, ri, value_inst, ident);7451 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
7469 }7452 }
7470 s = local_val.parent;7453 s = local_val.parent;
7471 },7454 },
...@@ -7498,10 +7481,10 @@ fn localVarRef(...@@ -7498,10 +7481,10 @@ fn localVarRef(
7498 );7481 );
74997482
7500 switch (ri.rl) {7483 switch (ri.rl) {
7501 .ref => return ptr_inst,7484 .ref, .ref_coerced_ty => return ptr_inst,
7502 else => {7485 else => {
7503 const loaded = try gz.addUnNode(.load, ptr_inst, ident);7486 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
7504 return rvalue(gz, ri, loaded, ident);7487 return rvalueNoCoercePreRef(gz, ri, loaded, ident);
7505 },7488 },
7506 }7489 }
7507 }7490 }
...@@ -7535,10 +7518,10 @@ fn localVarRef(...@@ -7535,10 +7518,10 @@ fn localVarRef(
7535 // Decl references happen by name rather than ZIR index so that when unrelated7518 // Decl references happen by name rather than ZIR index so that when unrelated
7536 // decls are modified, ZIR code containing references to them can be unmodified.7519 // decls are modified, ZIR code containing references to them can be unmodified.
7537 switch (ri.rl) {7520 switch (ri.rl) {
7538 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),7521 .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
7539 else => {7522 else => {
7540 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);7523 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
7541 return rvalue(gz, ri, result, ident);7524 return rvalueNoCoercePreRef(gz, ri, result, ident);
7542 },7525 },
7543 }7526 }
7544}7527}
...@@ -7924,7 +7907,7 @@ fn bitCast(...@@ -7924,7 +7907,7 @@ fn bitCast(
7924 node: Ast.Node.Index,7907 node: Ast.Node.Index,
7925 operand_node: Ast.Node.Index,7908 operand_node: Ast.Node.Index,
7926) InnerError!Zir.Inst.Ref {7909) InnerError!Zir.Inst.Ref {
7927 const dest_type = try ri.rl.resultType(gz, node, "@bitCast");7910 const dest_type = try ri.rl.resultTypeForCast(gz, node, "@bitCast");
7928 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node);7911 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node);
7929 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{7912 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
7930 .lhs = dest_type,7913 .lhs = dest_type,
...@@ -8024,7 +8007,7 @@ fn ptrCast(...@@ -8024,7 +8007,7 @@ fn ptrCast(
8024 // Full cast including result type8007 // Full cast including result type
80258008
8026 const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);8009 const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
8027 const result_type = try ri.rl.resultType(gz, root_node, flags.needResultTypeBuiltinName());8010 const result_type = try ri.rl.resultTypeForCast(gz, root_node, flags.needResultTypeBuiltinName());
8028 const operand = try expr(gz, scope, .{ .rl = .none }, node);8011 const operand = try expr(gz, scope, .{ .rl = .none }, node);
8029 try emitDbgStmt(gz, cursor);8012 try emitDbgStmt(gz, cursor);
8030 const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{8013 const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{
...@@ -8208,7 +8191,7 @@ fn builtinCall(...@@ -8208,7 +8191,7 @@ fn builtinCall(
8208 return rvalue(gz, ri, result, node);8191 return rvalue(gz, ri, result, node);
8209 },8192 },
8210 .field => {8193 .field => {
8211 if (ri.rl == .ref) {8194 if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
8212 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{8195 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
8213 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),8196 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
8214 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]),8197 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]),
...@@ -8475,7 +8458,7 @@ fn builtinCall(...@@ -8475,7 +8458,7 @@ fn builtinCall(
8475 try emitDbgNode(gz, node);8458 try emitDbgNode(gz, node);
84768459
8477 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{8460 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{
8478 .lhs = try ri.rl.resultType(gz, node, "@errSetCast"),8461 .lhs = try ri.rl.resultTypeForCast(gz, node, "@errSetCast"),
8479 .rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),8462 .rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
8480 .node = gz.nodeIndexToRelative(node),8463 .node = gz.nodeIndexToRelative(node),
8481 });8464 });
...@@ -8548,7 +8531,7 @@ fn builtinCall(...@@ -8548,7 +8531,7 @@ fn builtinCall(
8548 },8531 },
85498532
8550 .splat => {8533 .splat => {
8551 const result_type = try ri.rl.resultType(gz, node, "@splat");8534 const result_type = try ri.rl.resultTypeForCast(gz, node, "@splat");
8552 const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);8535 const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
8553 const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);8536 const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
8554 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{8537 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
...@@ -8810,7 +8793,7 @@ fn typeCast(...@@ -8810,7 +8793,7 @@ fn typeCast(
8810 builtin_name: []const u8,8793 builtin_name: []const u8,
8811) InnerError!Zir.Inst.Ref {8794) InnerError!Zir.Inst.Ref {
8812 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);8795 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
8813 const result_type = try ri.rl.resultType(gz, node, builtin_name);8796 const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
8814 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node);8797 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node);
88158798
8816 try emitDbgStmt(gz, cursor);8799 try emitDbgStmt(gz, cursor);
...@@ -10069,6 +10052,29 @@ fn rvalue(...@@ -10069,6 +10052,29 @@ fn rvalue(
10069 ri: ResultInfo,10052 ri: ResultInfo,
10070 raw_result: Zir.Inst.Ref,10053 raw_result: Zir.Inst.Ref,
10071 src_node: Ast.Node.Index,10054 src_node: Ast.Node.Index,
10055) InnerError!Zir.Inst.Ref {
10056 return rvalueInner(gz, ri, raw_result, src_node, true);
10057}
10058
10059/// Like `rvalue`, but refuses to perform coercions before taking references for
10060/// the `ref_coerced_ty` result type. This is used for local variables which do
10061/// not have `alloc`s, because we want variables to have consistent addresses,
10062/// i.e. we want them to act like lvalues.
10063fn rvalueNoCoercePreRef(
10064 gz: *GenZir,
10065 ri: ResultInfo,
10066 raw_result: Zir.Inst.Ref,
10067 src_node: Ast.Node.Index,
10068) InnerError!Zir.Inst.Ref {
10069 return rvalueInner(gz, ri, raw_result, src_node, false);
10070}
10071
10072fn rvalueInner(
10073 gz: *GenZir,
10074 ri: ResultInfo,
10075 raw_result: Zir.Inst.Ref,
10076 src_node: Ast.Node.Index,
10077 allow_coerce_pre_ref: bool,
10072) InnerError!Zir.Inst.Ref {10078) InnerError!Zir.Inst.Ref {
10073 const result = r: {10079 const result = r: {
10074 if (refToIndex(raw_result)) |result_index| {10080 if (refToIndex(raw_result)) |result_index| {
...@@ -10088,7 +10094,14 @@ fn rvalue(...@@ -10088,7 +10094,14 @@ fn rvalue(
10088 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);10094 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
10089 return .void_value;10095 return .void_value;
10090 },10096 },
10091 .ref => {10097 .ref, .ref_coerced_ty => {
10098 const coerced_result = if (allow_coerce_pre_ref and ri.rl == .ref_coerced_ty) res: {
10099 const ptr_ty = ri.rl.ref_coerced_ty;
10100 break :res try gz.addPlNode(.coerce_ptr_elem_ty, src_node, Zir.Inst.Bin{
10101 .lhs = ptr_ty,
10102 .rhs = result,
10103 });
10104 } else result;
10092 // We need a pointer but we have a value.10105 // We need a pointer but we have a value.
10093 // Unfortunately it's not quite as simple as directly emitting a ref10106 // Unfortunately it's not quite as simple as directly emitting a ref
10094 // instruction here because we need subsequent address-of operator on10107 // instruction here because we need subsequent address-of operator on
...@@ -10096,14 +10109,14 @@ fn rvalue(...@@ -10096,14 +10109,14 @@ fn rvalue(
10096 const astgen = gz.astgen;10109 const astgen = gz.astgen;
10097 const tree = astgen.tree;10110 const tree = astgen.tree;
10098 const src_token = tree.firstToken(src_node);10111 const src_token = tree.firstToken(src_node);
10099 const result_index = refToIndex(result) orelse10112 const result_index = refToIndex(coerced_result) orelse
10100 return gz.addUnTok(.ref, result, src_token);10113 return gz.addUnTok(.ref, coerced_result, src_token);
10101 const zir_tags = gz.astgen.instructions.items(.tag);10114 const zir_tags = gz.astgen.instructions.items(.tag);
10102 if (zir_tags[result_index].isParam() or astgen.isInferred(result))10115 if (zir_tags[result_index].isParam() or astgen.isInferred(coerced_result))
10103 return gz.addUnTok(.ref, result, src_token);10116 return gz.addUnTok(.ref, coerced_result, src_token);
10104 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);10117 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
10105 if (!gop.found_existing) {10118 if (!gop.found_existing) {
10106 gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token);10119 gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token);
10107 }10120 }
10108 return indexToRef(gop.value_ptr.*);10121 return indexToRef(gop.value_ptr.*);
10109 },10122 },
src/AstRlAnnotate.zig+26-18
...@@ -669,17 +669,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI...@@ -669,17 +669,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
669 => {669 => {
670 var buf: [2]Ast.Node.Index = undefined;670 var buf: [2]Ast.Node.Index = undefined;
671 const full = tree.fullArrayInit(&buf, node).?;671 const full = tree.fullArrayInit(&buf, node).?;
672 const have_type = if (full.ast.type_expr != 0) have_type: {672
673 if (full.ast.type_expr != 0) {
674 // Explicitly typed init does not participate in RLS
673 _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);675 _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);
674 break :have_type true;
675 } else ri.have_type;
676 if (have_type) {
677 const elem_ri: ResultInfo = .{
678 .have_type = true,
679 .have_ptr = ri.have_ptr,
680 };
681 for (full.ast.elements) |elem_init| {676 for (full.ast.elements) |elem_init| {
682 _ = try astrl.expr(elem_init, block, elem_ri);677 _ = try astrl.expr(elem_init, block, ResultInfo.type_only);
678 }
679 return false;
680 }
681
682 if (ri.have_type) {
683 // Always forward type information
684 // If we have a result pointer, we use and forward it
685 for (full.ast.elements) |elem_init| {
686 _ = try astrl.expr(elem_init, block, ri);
683 }687 }
684 return ri.have_ptr;688 return ri.have_ptr;
685 } else {689 } else {
...@@ -702,17 +706,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI...@@ -702,17 +706,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
702 => {706 => {
703 var buf: [2]Ast.Node.Index = undefined;707 var buf: [2]Ast.Node.Index = undefined;
704 const full = tree.fullStructInit(&buf, node).?;708 const full = tree.fullStructInit(&buf, node).?;
705 const have_type = if (full.ast.type_expr != 0) have_type: {709
710 if (full.ast.type_expr != 0) {
711 // Explicitly typed init does not participate in RLS
706 _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);712 _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none);
707 break :have_type true;
708 } else ri.have_type;
709 if (have_type) {
710 const elem_ri: ResultInfo = .{
711 .have_type = true,
712 .have_ptr = ri.have_ptr,
713 };
714 for (full.ast.fields) |field_init| {713 for (full.ast.fields) |field_init| {
715 _ = try astrl.expr(field_init, block, elem_ri);714 _ = try astrl.expr(field_init, block, ResultInfo.type_only);
715 }
716 return false;
717 }
718
719 if (ri.have_type) {
720 // Always forward type information
721 // If we have a result pointer, we use and forward it
722 for (full.ast.fields) |field_init| {
723 _ = try astrl.expr(field_init, block, ri);
716 }724 }
717 return ri.have_ptr;725 return ri.have_ptr;
718 } else {726 } else {
src/Autodoc.zig+19-34
...@@ -45,6 +45,14 @@ ref_paths_pending_on_types: std.AutoHashMapUnmanaged(...@@ -45,6 +45,14 @@ ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
45 std.ArrayListUnmanaged(RefPathResumeInfo),45 std.ArrayListUnmanaged(RefPathResumeInfo),
46) = .{},46) = .{},
4747
48/// A set of ZIR instruction refs which have a meaning other than the
49/// instruction they refer to. For instance, during analysis of the arguments to
50/// a `call`, the index of the `call` itself is repurposed to refer to the
51/// parameter type.
52/// TODO: there should be some kind of proper handling for these instructions;
53/// currently we just ignore them!
54repurposed_insts: std.AutoHashMapUnmanaged(Zir.Inst.Index, void) = .{},
55
48const RefPathResumeInfo = struct {56const RefPathResumeInfo = struct {
49 file: *File,57 file: *File,
50 ref_path: []DocData.Expr,58 ref_path: []DocData.Expr,
...@@ -954,6 +962,11 @@ fn walkInstruction(...@@ -954,6 +962,11 @@ fn walkInstruction(
954 const tags = file.zir.instructions.items(.tag);962 const tags = file.zir.instructions.items(.tag);
955 const data = file.zir.instructions.items(.data);963 const data = file.zir.instructions.items(.data);
956964
965 if (self.repurposed_insts.contains(@intCast(inst_index))) {
966 // TODO: better handling here
967 return .{ .expr = .{ .comptimeExpr = 0 } };
968 }
969
957 // We assume that the topmost ast_node entry corresponds to our decl970 // We assume that the topmost ast_node entry corresponds to our decl
958 const self_ast_node_index = self.ast_nodes.items.len - 1;971 const self_ast_node_index = self.ast_nodes.items.len - 1;
959972
...@@ -2378,34 +2391,6 @@ fn walkInstruction(...@@ -2378,34 +2391,6 @@ fn walkInstruction(
2378 .expr = .{ .@"&" = expr_index },2391 .expr = .{ .@"&" = expr_index },
2379 };2392 };
2380 },2393 },
2381 .array_init_anon_ref => {
2382 const pl_node = data[inst_index].pl_node;
2383 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
2384 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
2385 const array_data = try self.arena.alloc(usize, operands.len);
2386
2387 for (operands, 0..) |op, idx| {
2388 const wr = try self.walkRef(
2389 file,
2390 parent_scope,
2391 parent_src,
2392 op,
2393 false,
2394 call_ctx,
2395 );
2396 const expr_index = self.exprs.items.len;
2397 try self.exprs.append(self.arena, wr.expr);
2398 array_data[idx] = expr_index;
2399 }
2400
2401 const expr_index = self.exprs.items.len;
2402 try self.exprs.append(self.arena, .{ .array = array_data });
2403
2404 return DocData.WalkResult{
2405 .typeRef = null,
2406 .expr = .{ .@"&" = expr_index },
2407 };
2408 },
2409 .float => {2394 .float => {
2410 const float = data[inst_index].float;2395 const float = data[inst_index].float;
2411 return DocData.WalkResult{2396 return DocData.WalkResult{
...@@ -2696,9 +2681,7 @@ fn walkInstruction(...@@ -2696,9 +2681,7 @@ fn walkInstruction(
2696 .expr = .{ .declRef = decl_status },2681 .expr = .{ .declRef = decl_status },
2697 };2682 };
2698 },2683 },
2699 .field_val, .field_ptr, .field_type => {2684 .field_val, .field_ptr => {
2700 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
2701 // same layout as Zir.Inst.Field :^)
2702 const pl_node = data[inst_index].pl_node;2685 const pl_node = data[inst_index].pl_node;
2703 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);2686 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
27042687
...@@ -2717,8 +2700,7 @@ fn walkInstruction(...@@ -2717,8 +2700,7 @@ fn walkInstruction(
2717 };2700 };
27182701
2719 if (tags[lhs] != .field_val and2702 if (tags[lhs] != .field_val and
2720 tags[lhs] != .field_ptr and2703 tags[lhs] != .field_ptr) break :blk lhs_extra.data.lhs;
2721 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
27222704
2723 lhs_extra = file.zir.extraData(2705 lhs_extra = file.zir.extraData(
2724 Zir.Inst.Field,2706 Zir.Inst.Field,
...@@ -2857,7 +2839,7 @@ fn walkInstruction(...@@ -2857,7 +2839,7 @@ fn walkInstruction(
28572839
2858 const field_name = blk: {2840 const field_name = blk: {
2859 const field_inst_index = init_extra.data.field_type;2841 const field_inst_index = init_extra.data.field_type;
2860 if (tags[field_inst_index] != .field_type) unreachable;2842 if (tags[field_inst_index] != .struct_init_field_type) unreachable;
2861 const field_pl_node = data[field_inst_index].pl_node;2843 const field_pl_node = data[field_inst_index].pl_node;
2862 const field_extra = file.zir.extraData(2844 const field_extra = file.zir.extraData(
2863 Zir.Inst.FieldType,2845 Zir.Inst.FieldType,
...@@ -3022,6 +3004,9 @@ fn walkInstruction(...@@ -3022,6 +3004,9 @@ fn walkInstruction(
3022 var args = try self.arena.alloc(DocData.Expr, args_len);3004 var args = try self.arena.alloc(DocData.Expr, args_len);
3023 const body = file.zir.extra[extra.end..];3005 const body = file.zir.extra[extra.end..];
30243006
3007 try self.repurposed_insts.put(self.arena, @intCast(inst_index), {});
3008 defer _ = self.repurposed_insts.remove(@intCast(inst_index));
3009
3025 var i: usize = 0;3010 var i: usize = 0;
3026 while (i < args_len) : (i += 1) {3011 while (i < args_len) : (i += 1) {
3027 const arg_end = file.zir.extra[extra.end + i];3012 const arg_end = file.zir.extra[extra.end + i];
src/InternPool.zig+2-2
...@@ -5075,8 +5075,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -5075,8 +5075,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
5075 try ip.string_bytes.ensureUnusedCapacity(gpa, @as(usize, @intCast(len_including_sentinel + 1)));5075 try ip.string_bytes.ensureUnusedCapacity(gpa, @as(usize, @intCast(len_including_sentinel + 1)));
5076 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);5076 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
5077 switch (aggregate.storage) {5077 switch (aggregate.storage) {
5078 .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes),5078 .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes[0..@intCast(len)]),
5079 .elems => |elems| for (elems) |elem| switch (ip.indexToKey(elem)) {5079 .elems => |elems| for (elems[0..@intCast(len)]) |elem| switch (ip.indexToKey(elem)) {
5080 .undef => {5080 .undef => {
5081 ip.string_bytes.shrinkRetainingCapacity(string_bytes_index);5081 ip.string_bytes.shrinkRetainingCapacity(string_bytes_index);
5082 break :bytes;5082 break :bytes;
src/Sema.zig+478-447
...@@ -836,16 +836,11 @@ const LabeledBlock = struct {...@@ -836,16 +836,11 @@ const LabeledBlock = struct {
836/// the items are contiguous in memory and thus can be passed to836/// the items are contiguous in memory and thus can be passed to
837/// `Module.resolvePeerTypes`.837/// `Module.resolvePeerTypes`.
838const InferredAlloc = struct {838const InferredAlloc = struct {
839 prongs: std.MultiArrayList(struct {839 /// The placeholder `store` instructions used before the result pointer type
840 /// The dummy instruction used as a peer to resolve the type.840 /// is known. These should be rewritten to perform any required coercions
841 /// Although this has a redundant type with placeholder, this is841 /// when the type is resolved.
842 /// needed in addition because it may be a constant value, which842 /// Allocated from `sema.arena`.
843 /// affects peer type resolution.843 prongs: std.ArrayListUnmanaged(Air.Inst.Index) = .{},
844 stored_inst: Air.Inst.Ref,
845 /// The bitcast instruction used as a placeholder when the
846 /// new result pointer type is not yet known.
847 placeholder: Air.Inst.Index,
848 }) = .{},
849};844};
850845
851const NeededComptimeReason = struct {846const NeededComptimeReason = struct {
...@@ -1040,17 +1035,14 @@ fn analyzeBodyInner(...@@ -1040,17 +1035,14 @@ fn analyzeBodyInner(
1040 .cmp_gte => try sema.zirCmp(block, inst, .gte),1035 .cmp_gte => try sema.zirCmp(block, inst, .gte),
1041 .cmp_gt => try sema.zirCmp(block, inst, .gt),1036 .cmp_gt => try sema.zirCmp(block, inst, .gt),
1042 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),1037 .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),
1043 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
1044 .decl_ref => try sema.zirDeclRef(block, inst),1038 .decl_ref => try sema.zirDeclRef(block, inst),
1045 .decl_val => try sema.zirDeclVal(block, inst),1039 .decl_val => try sema.zirDeclVal(block, inst),
1046 .load => try sema.zirLoad(block, inst),1040 .load => try sema.zirLoad(block, inst),
1047 .elem_ptr => try sema.zirElemPtr(block, inst),1041 .elem_ptr => try sema.zirElemPtr(block, inst),
1048 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),1042 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
1049 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst),
1050 .elem_val => try sema.zirElemVal(block, inst),1043 .elem_val => try sema.zirElemVal(block, inst),
1051 .elem_val_node => try sema.zirElemValNode(block, inst),1044 .elem_val_node => try sema.zirElemValNode(block, inst),
1052 .elem_val_imm => try sema.zirElemValImm(block, inst),1045 .elem_val_imm => try sema.zirElemValImm(block, inst),
1053 .elem_type_index => try sema.zirElemTypeIndex(block, inst),
1054 .elem_type => try sema.zirElemType(block, inst),1046 .elem_type => try sema.zirElemType(block, inst),
1055 .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst),1047 .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst),
1056 .vector_elem_type => try sema.zirVectorElemType(block, inst),1048 .vector_elem_type => try sema.zirVectorElemType(block, inst),
...@@ -1063,8 +1055,7 @@ fn analyzeBodyInner(...@@ -1063,8 +1055,7 @@ fn analyzeBodyInner(
1063 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst),1055 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst),
1064 .error_union_type => try sema.zirErrorUnionType(block, inst),1056 .error_union_type => try sema.zirErrorUnionType(block, inst),
1065 .error_value => try sema.zirErrorValue(block, inst),1057 .error_value => try sema.zirErrorValue(block, inst),
1066 .field_ptr => try sema.zirFieldPtr(block, inst, false),1058 .field_ptr => try sema.zirFieldPtr(block, inst),
1067 .field_ptr_init => try sema.zirFieldPtr(block, inst, true),
1068 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),1059 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
1069 .field_val => try sema.zirFieldVal(block, inst),1060 .field_val => try sema.zirFieldVal(block, inst),
1070 .field_val_named => try sema.zirFieldValNamed(block, inst),1061 .field_val_named => try sema.zirFieldValNamed(block, inst),
...@@ -1111,16 +1102,19 @@ fn analyzeBodyInner(...@@ -1111,16 +1102,19 @@ fn analyzeBodyInner(
1111 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),1102 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
1112 .xor => try sema.zirBitwise(block, inst, .xor),1103 .xor => try sema.zirBitwise(block, inst, .xor),
1113 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),1104 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
1105 .struct_init_empty_result => try sema.zirStructInitEmptyResult(block, inst, false),
1106 .struct_init_empty_ref_result => try sema.zirStructInitEmptyResult(block, inst, true),
1107 .struct_init_anon => try sema.zirStructInitAnon(block, inst),
1114 .struct_init => try sema.zirStructInit(block, inst, false),1108 .struct_init => try sema.zirStructInit(block, inst, false),
1115 .struct_init_ref => try sema.zirStructInit(block, inst, true),1109 .struct_init_ref => try sema.zirStructInit(block, inst, true),
1116 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),1110 .struct_init_field_type => try sema.zirStructInitFieldType(block, inst),
1117 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),1111 .struct_init_field_ptr => try sema.zirStructInitFieldPtr(block, inst),
1112 .array_init_anon => try sema.zirArrayInitAnon(block, inst),
1118 .array_init => try sema.zirArrayInit(block, inst, false),1113 .array_init => try sema.zirArrayInit(block, inst, false),
1119 .array_init_ref => try sema.zirArrayInit(block, inst, true),1114 .array_init_ref => try sema.zirArrayInit(block, inst, true),
1120 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),1115 .array_init_elem_type => try sema.zirArrayInitElemType(block, inst),
1121 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),1116 .array_init_elem_ptr => try sema.zirArrayInitElemPtr(block, inst),
1122 .union_init => try sema.zirUnionInit(block, inst),1117 .union_init => try sema.zirUnionInit(block, inst),
1123 .field_type => try sema.zirFieldType(block, inst),
1124 .field_type_ref => try sema.zirFieldTypeRef(block, inst),1118 .field_type_ref => try sema.zirFieldTypeRef(block, inst),
1125 .int_from_ptr => try sema.zirIntFromPtr(block, inst),1119 .int_from_ptr => try sema.zirIntFromPtr(block, inst),
1126 .align_of => try sema.zirAlignOf(block, inst),1120 .align_of => try sema.zirAlignOf(block, inst),
...@@ -1154,10 +1148,10 @@ fn analyzeBodyInner(...@@ -1154,10 +1148,10 @@ fn analyzeBodyInner(
1154 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),1148 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
1155 .@"resume" => try sema.zirResume(block, inst),1149 .@"resume" => try sema.zirResume(block, inst),
1156 .@"await" => try sema.zirAwait(block, inst),1150 .@"await" => try sema.zirAwait(block, inst),
1157 .array_base_ptr => try sema.zirArrayBasePtr(block, inst),
1158 .field_base_ptr => try sema.zirFieldBasePtr(block, inst),
1159 .for_len => try sema.zirForLen(block, inst),1151 .for_len => try sema.zirForLen(block, inst),
1160 .opt_eu_base_ty => try sema.zirOptEuBaseTy(block, inst),1152 .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst),
1153 .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
1154 .coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst),
11611155
1162 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),1156 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
1163 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),1157 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
...@@ -1386,23 +1380,33 @@ fn analyzeBodyInner(...@@ -1386,23 +1380,33 @@ fn analyzeBodyInner(
1386 i += 1;1380 i += 1;
1387 continue;1381 continue;
1388 },1382 },
1383 .validate_struct_init_ty => {
1384 try sema.zirValidateStructInitTy(block, inst, false);
1385 i += 1;
1386 continue;
1387 },
1388 .validate_struct_init_result_ty => {
1389 try sema.zirValidateStructInitTy(block, inst, true);
1390 i += 1;
1391 continue;
1392 },
1389 .validate_array_init_ty => {1393 .validate_array_init_ty => {
1390 try sema.zirValidateArrayInitTy(block, inst);1394 try sema.zirValidateArrayInitTy(block, inst, false);
1391 i += 1;1395 i += 1;
1392 continue;1396 continue;
1393 },1397 },
1394 .validate_struct_init_ty => {1398 .validate_array_init_result_ty => {
1395 try sema.zirValidateStructInitTy(block, inst);1399 try sema.zirValidateArrayInitTy(block, inst, true);
1396 i += 1;1400 i += 1;
1397 continue;1401 continue;
1398 },1402 },
1399 .validate_struct_init => {1403 .validate_ptr_struct_init => {
1400 try sema.zirValidateStructInit(block, inst);1404 try sema.zirValidatePtrStructInit(block, inst);
1401 i += 1;1405 i += 1;
1402 continue;1406 continue;
1403 },1407 },
1404 .validate_array_init => {1408 .validate_ptr_array_init => {
1405 try sema.zirValidateArrayInit(block, inst);1409 try sema.zirValidatePtrArrayInit(block, inst);
1406 i += 1;1410 i += 1;
1407 continue;1411 continue;
1408 },1412 },
...@@ -1416,6 +1420,11 @@ fn analyzeBodyInner(...@@ -1416,6 +1420,11 @@ fn analyzeBodyInner(
1416 i += 1;1420 i += 1;
1417 continue;1421 continue;
1418 },1422 },
1423 .validate_ref_ty => {
1424 try sema.zirValidateRefTy(block, inst);
1425 i += 1;
1426 continue;
1427 },
1419 .@"export" => {1428 .@"export" => {
1420 try sema.zirExport(block, inst);1429 try sema.zirExport(block, inst);
1421 i += 1;1430 i += 1;
...@@ -1922,7 +1931,11 @@ fn resolveDestType(...@@ -1922,7 +1931,11 @@ fn resolveDestType(
1922 const msg = msg: {1931 const msg = msg: {
1923 const msg = try sema.errMsg(block, src, "{s} must have a known result type", .{builtin_name});1932 const msg = try sema.errMsg(block, src, "{s} must have a known result type", .{builtin_name});
1924 errdefer msg.destroy(sema.gpa);1933 errdefer msg.destroy(sema.gpa);
1925 try sema.errNote(block, src, msg, "result type is unknown due to anytype parameter", .{});1934 switch (sema.genericPoisonReason(zir_ref)) {
1935 .anytype_param => |call_src| try sema.errNote(block, call_src, msg, "result type is unknown due to anytype parameter", .{}),
1936 .anyopaque_ptr => |ptr_src| try sema.errNote(block, ptr_src, msg, "result type is unknown due to opaque pointer type", .{}),
1937 .unknown => {},
1938 }
1926 try sema.errNote(block, src, msg, "use @as to provide explicit result type", .{});1939 try sema.errNote(block, src, msg, "use @as to provide explicit result type", .{});
1927 break :msg msg;1940 break :msg msg;
1928 };1941 };
...@@ -1944,6 +1957,65 @@ fn resolveDestType(...@@ -1944,6 +1957,65 @@ fn resolveDestType(
1944 return raw_ty;1957 return raw_ty;
1945}1958}
19461959
1960const GenericPoisonReason = union(enum) {
1961 anytype_param: LazySrcLoc,
1962 anyopaque_ptr: LazySrcLoc,
1963 unknown,
1964};
1965
1966/// Backtracks through ZIR instructions to determine the reason a generic poison
1967/// type was created. Used for error reporting.
1968fn genericPoisonReason(sema: *Sema, ref: Zir.Inst.Ref) GenericPoisonReason {
1969 var cur = ref;
1970 while (true) {
1971 const inst = Zir.refToIndex(cur) orelse return .unknown;
1972 switch (sema.code.instructions.items(.tag)[inst]) {
1973 .validate_array_init_ref_ty => {
1974 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
1975 const extra = sema.code.extraData(Zir.Inst.ArrayInitRefTy, pl_node.payload_index).data;
1976 cur = extra.ptr_ty;
1977 },
1978 .array_init_elem_type => {
1979 const bin = sema.code.instructions.items(.data)[inst].bin;
1980 cur = bin.lhs;
1981 },
1982 .indexable_ptr_elem_type, .vector_elem_type => {
1983 const un_node = sema.code.instructions.items(.data)[inst].un_node;
1984 cur = un_node.operand;
1985 },
1986 .struct_init_field_type => {
1987 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
1988 const extra = sema.code.extraData(Zir.Inst.FieldType, pl_node.payload_index).data;
1989 cur = extra.container_type;
1990 },
1991 .elem_type => {
1992 // There are two cases here: the pointer type may already have been
1993 // generic poison, or it may have been an anyopaque pointer.
1994 const un_node = sema.code.instructions.items(.data)[inst].un_node;
1995 const operand_ref = sema.resolveInst(un_node.operand) catch |err| switch (err) {
1996 error.GenericPoison => unreachable, // this is a type, not a value
1997 };
1998 const operand_val = Air.refToInterned(operand_ref) orelse return .unknown;
1999 if (operand_val == .generic_poison_type) {
2000 // The pointer was generic poison - keep looking.
2001 cur = un_node.operand;
2002 } else {
2003 // This must be an anyopaque pointer!
2004 return .{ .anyopaque_ptr = un_node.src() };
2005 }
2006 },
2007 .call, .field_call => {
2008 // A function call can never return generic poison, so we must be
2009 // evaluating an `anytype` function parameter.
2010 // TODO: better source location - function decl rather than call
2011 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
2012 return .{ .anytype_param = pl_node.src() };
2013 },
2014 else => return .unknown,
2015 }
2016 }
2017}
2018
1947fn analyzeAsType(2019fn analyzeAsType(
1948 sema: *Sema,2020 sema: *Sema,
1949 block: *Block,2021 block: *Block,
...@@ -2634,217 +2706,6 @@ pub fn resolveInstValue(...@@ -2634,217 +2706,6 @@ pub fn resolveInstValue(
2634 };2706 };
2635}2707}
26362708
2637fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2638 const tracy = trace(@src());
2639 defer tracy.end();
2640
2641 const mod = sema.mod;
2642 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2643 const src = inst_data.src();
2644 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
2645 const pointee_ty = try sema.resolveType(block, src, extra.lhs);
2646 const ptr = try sema.resolveInst(extra.rhs);
2647 const target = mod.getTarget();
2648 const addr_space = target_util.defaultAddressSpace(target, .local);
2649
2650 if (Air.refToIndex(ptr)) |ptr_inst| {
2651 switch (sema.air_instructions.items(.tag)[ptr_inst]) {
2652 .inferred_alloc => {
2653 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
2654 const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
2655 // Add the stored instruction to the set we will use to resolve peer types
2656 // for the inferred allocation.
2657 // This instruction will not make it to codegen; it is only to participate
2658 // in the `stored_inst_list` of the `inferred_alloc`.
2659 var trash_block = block.makeSubBlock();
2660 defer trash_block.instructions.deinit(sema.gpa);
2661 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
2662
2663 const ptr_ty = try sema.ptrType(.{
2664 .child = pointee_ty.toIntern(),
2665 .flags = .{
2666 .alignment = ia1.alignment,
2667 .address_space = addr_space,
2668 },
2669 });
2670 const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
2671
2672 try ia2.prongs.append(sema.arena, .{
2673 .stored_inst = operand,
2674 .placeholder = Air.refToIndex(bitcasted_ptr).?,
2675 });
2676
2677 try sema.checkKnownAllocPtr(ptr, bitcasted_ptr);
2678 return bitcasted_ptr;
2679 },
2680 .inferred_alloc_comptime => {
2681 const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment;
2682 // There will be only one coerce_result_ptr because we are running at comptime.
2683 // The alloc will turn into a Decl.
2684 var anon_decl = try block.startAnonDecl();
2685 defer anon_decl.deinit();
2686 const decl_index = try anon_decl.finish(
2687 pointee_ty,
2688 (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(),
2689 alignment,
2690 );
2691 sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index;
2692 if (alignment != .none) {
2693 try sema.resolveTypeLayout(pointee_ty);
2694 }
2695 const ptr_ty = try sema.ptrType(.{
2696 .child = pointee_ty.toIntern(),
2697 .flags = .{
2698 .alignment = alignment,
2699 .address_space = addr_space,
2700 },
2701 });
2702 try sema.maybeQueueFuncBodyAnalysis(decl_index);
2703 try sema.comptime_mutable_decls.append(decl_index);
2704 return Air.internedToRef((try mod.intern(.{ .ptr = .{
2705 .ty = ptr_ty.toIntern(),
2706 .addr = .{ .mut_decl = .{
2707 .decl = decl_index,
2708 .runtime_index = block.runtime_index,
2709 } },
2710 } })));
2711 },
2712 else => {},
2713 }
2714 }
2715
2716 // Make a dummy store through the pointer to test the coercion.
2717 // We will then use the generated instructions to decide what
2718 // kind of transformations to make on the result pointer.
2719 var trash_block = block.makeSubBlock();
2720 trash_block.is_comptime = false;
2721 defer trash_block.instructions.deinit(sema.gpa);
2722
2723 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
2724 const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value);
2725 const new_ptr = try sema.coerceResultPtr(block, src, ptr, dummy_ptr, dummy_operand, &trash_block);
2726 try sema.checkKnownAllocPtr(ptr, new_ptr);
2727 return new_ptr;
2728}
2729
2730fn coerceResultPtr(
2731 sema: *Sema,
2732 block: *Block,
2733 src: LazySrcLoc,
2734 ptr: Air.Inst.Ref,
2735 dummy_ptr: Air.Inst.Ref,
2736 dummy_operand: Air.Inst.Ref,
2737 trash_block: *Block,
2738) CompileError!Air.Inst.Ref {
2739 const mod = sema.mod;
2740 const target = sema.mod.getTarget();
2741 const addr_space = target_util.defaultAddressSpace(target, .local);
2742 const pointee_ty = sema.typeOf(dummy_operand);
2743 const prev_trash_len = trash_block.instructions.items.len;
2744
2745 try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast);
2746
2747 {
2748 const air_tags = sema.air_instructions.items(.tag);
2749
2750 //std.debug.print("dummy storePtr instructions:\n", .{});
2751 //for (trash_block.instructions.items) |item| {
2752 // std.debug.print(" {s}\n", .{@tagName(air_tags[item])});
2753 //}
2754
2755 // The last one is always `store`.
2756 const trash_inst = trash_block.instructions.items[trash_block.instructions.items.len - 1];
2757 if (air_tags[trash_inst] != .store and air_tags[trash_inst] != .store_safe) {
2758 // no store instruction is generated for zero sized types
2759 assert((try sema.typeHasOnePossibleValue(pointee_ty)) != null);
2760 } else {
2761 trash_block.instructions.items.len -= 1;
2762 assert(trash_inst == sema.air_instructions.len - 1);
2763 sema.air_instructions.len -= 1;
2764 }
2765 }
2766
2767 const ptr_ty = try sema.ptrType(.{
2768 .child = pointee_ty.toIntern(),
2769 .flags = .{ .address_space = addr_space },
2770 });
2771
2772 var new_ptr = ptr;
2773
2774 while (true) {
2775 const air_tags = sema.air_instructions.items(.tag);
2776 const air_datas = sema.air_instructions.items(.data);
2777
2778 if (trash_block.instructions.items.len == prev_trash_len) {
2779 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2780 return Air.internedToRef(ptr_val.toIntern());
2781 }
2782 if (pointee_ty.eql(Type.null, sema.mod)) {
2783 const null_inst = Air.internedToRef(Value.null.toIntern());
2784 _ = try block.addBinOp(.store, new_ptr, null_inst);
2785 return .void_value;
2786 }
2787 return sema.bitCast(block, ptr_ty, new_ptr, src, null);
2788 }
2789
2790 const trash_inst = trash_block.instructions.pop();
2791
2792 switch (air_tags[trash_inst]) {
2793 // Array coerced to Vector where element size is not equal but coercible.
2794 .aggregate_init => {
2795 const ty_pl = air_datas[trash_inst].ty_pl;
2796 const ptr_operand_ty = try sema.ptrType(.{
2797 .child = (try sema.analyzeAsType(block, src, ty_pl.ty)).toIntern(),
2798 .flags = .{ .address_space = addr_space },
2799 });
2800
2801 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2802 return Air.internedToRef(ptr_val.toIntern());
2803 } else {
2804 return sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
2805 }
2806 },
2807 .bitcast => {
2808 const ty_op = air_datas[trash_inst].ty_op;
2809 const operand_ty = sema.typeOf(ty_op.operand);
2810 const ptr_operand_ty = try sema.ptrType(.{
2811 .child = operand_ty.toIntern(),
2812 .flags = .{ .address_space = addr_space },
2813 });
2814 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2815 new_ptr = Air.internedToRef((try mod.getCoerced(ptr_val, ptr_operand_ty)).toIntern());
2816 } else {
2817 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
2818 }
2819 },
2820 .wrap_optional => {
2821 new_ptr = try sema.analyzeOptionalPayloadPtr(block, src, new_ptr, false, true);
2822 },
2823 .wrap_errunion_err => {
2824 return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{});
2825 },
2826 .wrap_errunion_payload => {
2827 new_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, new_ptr, false, true);
2828 },
2829 .array_to_slice => {
2830 return sema.fail(block, src, "TODO coerce_result_ptr array_to_slice", .{});
2831 },
2832 .get_union_tag => {
2833 return sema.fail(block, src, "TODO coerce_result_ptr get_union_tag", .{});
2834 },
2835 else => {
2836 if (std.debug.runtime_safety) {
2837 std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{
2838 air_tags[trash_inst],
2839 });
2840 } else {
2841 unreachable;
2842 }
2843 },
2844 }
2845 }
2846}
2847
2848pub fn getStructType(2709pub fn getStructType(
2849 sema: *Sema,2710 sema: *Sema,
2850 decl: Module.Decl.Index,2711 decl: Module.Decl.Index,
...@@ -4220,8 +4081,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4220,8 +4081,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4220 .inferred_alloc => {4081 .inferred_alloc => {
4221 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;4082 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
4222 const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;4083 const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;
4223 const peer_inst_list = ia2.prongs.items(.stored_inst);4084 const peer_vals = try sema.arena.alloc(Air.Inst.Ref, ia2.prongs.items.len);
4224 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);4085 for (peer_vals, ia2.prongs.items) |*peer_val, store_inst| {
4086 assert(sema.air_instructions.items(.tag)[store_inst] == .store);
4087 const bin_op = sema.air_instructions.items(.data)[store_inst].bin_op;
4088 peer_val.* = bin_op.rhs;
4089 }
4090 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none);
42254091
4226 const final_ptr_ty = try sema.ptrType(.{4092 const final_ptr_ty = try sema.ptrType(.{
4227 .child = final_elem_ty.toIntern(),4093 .child = final_elem_ty.toIntern(),
...@@ -4259,55 +4125,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4259,55 +4125,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4259 .data = .{ .ty = final_ptr_ty },4125 .data = .{ .ty = final_ptr_ty },
4260 });4126 });
42614127
4262 // Now we need to go back over all the coerce_result_ptr instructions, which4128 // Now we need to go back over all the store instructions, and do the logic as if
4263 // previously inserted a bitcast as a placeholder, and do the logic as if
4264 // the new result ptr type was available.4129 // the new result ptr type was available.
4265 const placeholders = ia2.prongs.items(.placeholder);
4266 const gpa = sema.gpa;4130 const gpa = sema.gpa;
42674131
4268 var trash_block = block.makeSubBlock();4132 for (ia2.prongs.items) |placeholder_inst| {
4269 trash_block.is_comptime = false;
4270 defer trash_block.instructions.deinit(gpa);
4271
4272 const mut_final_ptr_ty = try sema.ptrType(.{
4273 .child = final_elem_ty.toIntern(),
4274 .flags = .{
4275 .alignment = ia1.alignment,
4276 .address_space = target_util.defaultAddressSpace(target, .local),
4277 },
4278 });
4279 const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty);
4280 const empty_trash_count = trash_block.instructions.items.len;
4281
4282 for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| {
4283 const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst));
4284
4285 if (mut_final_ptr_ty.eql(sub_ptr_ty, mod)) {
4286 // New result location type is the same as the old one; nothing
4287 // to do here.
4288 continue;
4289 }
4290
4291 var replacement_block = block.makeSubBlock();4133 var replacement_block = block.makeSubBlock();
4292 defer replacement_block.instructions.deinit(gpa);4134 defer replacement_block.instructions.deinit(gpa);
42934135
4294 const result = switch (sema.air_instructions.items(.tag)[placeholder_inst]) {4136 assert(sema.air_instructions.items(.tag)[placeholder_inst] == .store);
4295 .bitcast => result: {4137 const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op;
4296 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);4138 try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .store);
4297 const sub_ptr = try sema.coerceResultPtr(&replacement_block, src, ptr, dummy_ptr, peer_inst, &trash_block);
42984139
4299 assert(replacement_block.instructions.items.len > 0);4140 // If only one instruction is produced then we can replace the store
4300 break :result sub_ptr;
4301 },
4302 .store, .store_safe => result: {
4303 const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op;
4304 try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .bitcast);
4305 break :result .void_value;
4306 },
4307 else => unreachable,
4308 };
4309
4310 // If only one instruction is produced then we can replace the bitcast
4311 // placeholder instruction with this instruction; no need for an entire block.4141 // placeholder instruction with this instruction; no need for an entire block.
4312 if (replacement_block.instructions.items.len == 1) {4142 if (replacement_block.instructions.items.len == 1) {
4313 const only_inst = replacement_block.instructions.items[0];4143 const only_inst = replacement_block.instructions.items[0];
...@@ -4315,13 +4145,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4315,13 +4145,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4315 continue;4145 continue;
4316 }4146 }
43174147
4318 // Here we replace the placeholder bitcast instruction with a block4148 // Here we replace the placeholder store instruction with a block
4319 // that does the coerce_result_ptr logic.4149 // that does the actual store logic.
4320 _ = try replacement_block.addBr(placeholder_inst, result);4150 _ = try replacement_block.addBr(placeholder_inst, .void_value);
4321 const ty_inst = if (result == .void_value)
4322 .void_type
4323 else
4324 sema.air_instructions.items(.data)[placeholder_inst].ty_op.ty;
4325 try sema.air_extra.ensureUnusedCapacity(4151 try sema.air_extra.ensureUnusedCapacity(
4326 gpa,4152 gpa,
4327 @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len,4153 @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len,
...@@ -4329,7 +4155,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4329,7 +4155,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4329 sema.air_instructions.set(placeholder_inst, .{4155 sema.air_instructions.set(placeholder_inst, .{
4330 .tag = .block,4156 .tag = .block,
4331 .data = .{ .ty_pl = .{4157 .data = .{ .ty_pl = .{
4332 .ty = ty_inst,4158 .ty = .void_type,
4333 .payload = sema.addExtraAssumeCapacity(Air.Block{4159 .payload = sema.addExtraAssumeCapacity(Air.Block{
4334 .body_len = @intCast(replacement_block.instructions.items.len),4160 .body_len = @intCast(replacement_block.instructions.items.len),
4335 }),4161 }),
...@@ -4342,64 +4168,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4342,64 +4168,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4342 }4168 }
4343}4169}
43444170
4345fn zirArrayBasePtr(
4346 sema: *Sema,
4347 block: *Block,
4348 inst: Zir.Inst.Index,
4349) CompileError!Air.Inst.Ref {
4350 const mod = sema.mod;
4351 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4352 const src = inst_data.src();
4353
4354 const start_ptr = try sema.resolveInst(inst_data.operand);
4355 var base_ptr = start_ptr;
4356 while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
4357 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
4358 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
4359 else => break,
4360 };
4361
4362 const elem_ty = sema.typeOf(base_ptr).childType(mod);
4363 switch (elem_ty.zigTypeTag(mod)) {
4364 .Array, .Vector => return base_ptr,
4365 .Struct => if (elem_ty.isTuple(mod)) {
4366 // TODO validate element count
4367 try sema.checkKnownAllocPtr(start_ptr, base_ptr);
4368 return base_ptr;
4369 },
4370 else => {},
4371 }
4372 return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
4373}
4374
4375fn zirFieldBasePtr(
4376 sema: *Sema,
4377 block: *Block,
4378 inst: Zir.Inst.Index,
4379) CompileError!Air.Inst.Ref {
4380 const mod = sema.mod;
4381 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4382 const src = inst_data.src();
4383
4384 const start_ptr = try sema.resolveInst(inst_data.operand);
4385 var base_ptr = start_ptr;
4386 while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
4387 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
4388 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
4389 else => break,
4390 };
4391
4392 const elem_ty = sema.typeOf(base_ptr).childType(mod);
4393 switch (elem_ty.zigTypeTag(mod)) {
4394 .Struct, .Union => {
4395 try sema.checkKnownAllocPtr(start_ptr, base_ptr);
4396 return base_ptr;
4397 },
4398 else => {},
4399 }
4400 return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
4401}
4402
4403fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4171fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4404 const mod = sema.mod;4172 const mod = sema.mod;
4405 const gpa = sema.gpa;4173 const gpa = sema.gpa;
...@@ -4526,34 +4294,140 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -4526,34 +4294,140 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
4526 return len;4294 return len;
4527}4295}
45284296
4529fn zirOptEuBaseTy(4297/// Given any single pointer, retrieve a pointer to the payload of any optional
4298/// or error union pointed to, initializing these pointers along the way.
4299/// Given a `*E!?T`, returns a (valid) `*T`.
4300/// May invalidate already-stored payload data.
4301fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref {
4302 const mod = sema.mod;
4303 var base_ptr = ptr;
4304 while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
4305 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
4306 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
4307 else => break,
4308 };
4309 try sema.checkKnownAllocPtr(ptr, base_ptr);
4310 return base_ptr;
4311}
4312
4313fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4314 const un_node = sema.code.instructions.items(.data)[inst].un_node;
4315 const ptr = try sema.resolveInst(un_node.operand);
4316 return sema.optEuBasePtrInit(block, ptr, un_node.src());
4317}
4318
4319fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4320 const mod = sema.mod;
4321 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
4322 const src = pl_node.src();
4323 const extra = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
4324 const uncoerced_val = try sema.resolveInst(extra.rhs);
4325 const maybe_wrapped_ptr_ty = sema.resolveType(block, .unneeded, extra.lhs) catch |err| switch (err) {
4326 error.GenericPoison => return uncoerced_val,
4327 else => |e| return e,
4328 };
4329 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(mod);
4330 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
4331 const elem_ty = ptr_ty.childType(mod);
4332 switch (ptr_ty.ptrSize(mod)) {
4333 .One => {
4334 const uncoerced_ty = sema.typeOf(uncoerced_val);
4335 if (elem_ty.zigTypeTag(mod) == .Array and elem_ty.childType(mod).toIntern() == uncoerced_ty.toIntern()) {
4336 // We're trying to initialize a *[1]T with a reference to a T - don't perform any coercion.
4337 return uncoerced_val;
4338 }
4339 // If the destination type is anyopaque, don't coerce - the pointer will coerce instead.
4340 if (elem_ty.toIntern() == .anyopaque_type) {
4341 return uncoerced_val;
4342 } else {
4343 return sema.coerce(block, elem_ty, uncoerced_val, src);
4344 }
4345 },
4346 .Slice, .Many => {
4347 // Our goal is to coerce `uncoerced_val` to an array of `elem_ty`.
4348 const val_ty = sema.typeOf(uncoerced_val);
4349 switch (val_ty.zigTypeTag(mod)) {
4350 .Array, .Vector => {},
4351 else => if (!val_ty.isTuple(mod)) {
4352 return sema.fail(block, src, "expected array of '{}', found '{}'", .{ elem_ty.fmt(mod), val_ty.fmt(mod) });
4353 },
4354 }
4355 const want_ty = try mod.arrayType(.{
4356 .len = val_ty.arrayLen(mod),
4357 .child = elem_ty.toIntern(),
4358 .sentinel = if (ptr_ty.sentinel(mod)) |s| s.toIntern() else .none,
4359 });
4360 return sema.coerce(block, want_ty, uncoerced_val, src);
4361 },
4362 .C => {
4363 // There's nothing meaningful to do here, because we don't know if this is meant to be a
4364 // single-pointer or a many-pointer.
4365 return uncoerced_val;
4366 },
4367 }
4368}
4369
4370fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
4371 const mod = sema.mod;
4372 const un_tok = sema.code.instructions.items(.data)[inst].un_tok;
4373 const src = un_tok.src();
4374 const ty_operand = sema.resolveType(block, src, un_tok.operand) catch |err| switch (err) {
4375 error.GenericPoison => {
4376 // We don't actually have a type, so this will be treated as an untyped address-of operator.
4377 return;
4378 },
4379 else => |e| return e,
4380 };
4381 if (ty_operand.optEuBaseType(mod).zigTypeTag(mod) != .Pointer) {
4382 return sema.failWithOwnedErrorMsg(block, msg: {
4383 const msg = try sema.errMsg(block, src, "expected type '{}', found pointer", .{ty_operand.fmt(mod)});
4384 errdefer msg.destroy(sema.gpa);
4385 try sema.errNote(block, src, msg, "address-of operator always returns a pointer", .{});
4386 break :msg msg;
4387 });
4388 }
4389}
4390
4391fn zirValidateArrayInitRefTy(
4530 sema: *Sema,4392 sema: *Sema,
4531 block: *Block,4393 block: *Block,
4532 inst: Zir.Inst.Index,4394 inst: Zir.Inst.Index,
4533) CompileError!Air.Inst.Ref {4395) CompileError!Air.Inst.Ref {
4534 const mod = sema.mod;4396 const mod = sema.mod;
4535 const inst_data = sema.code.instructions.items(.data)[inst].un_node;4397 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
4536 var ty = sema.resolveType(block, .unneeded, inst_data.operand) catch |err| switch (err) {4398 const src = pl_node.src();
4537 // Since this is a ZIR instruction that returns a type, encountering4399 const extra = sema.code.extraData(Zir.Inst.ArrayInitRefTy, pl_node.payload_index).data;
4538 // generic poison should not result in a failed compilation, but the4400 const maybe_wrapped_ptr_ty = sema.resolveType(block, .unneeded, extra.ptr_ty) catch |err| switch (err) {
4539 // generic poison type. This prevents unnecessary failures when
4540 // constructing types at compile-time.
4541 error.GenericPoison => return .generic_poison_type,4401 error.GenericPoison => return .generic_poison_type,
4542 else => |e| return e,4402 else => |e| return e,
4543 };4403 };
4544 while (true) {4404 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(mod);
4545 switch (ty.zigTypeTag(mod)) {4405 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
4546 .Optional => ty = ty.optionalChild(mod),4406 if (ptr_ty.isSlice(mod)) {
4547 .ErrorUnion => ty = ty.errorUnionPayload(mod),4407 // Use array of correct length
4548 else => return Air.internedToRef(ty.toIntern()),4408 const arr_ty = try mod.arrayType(.{
4549 }4409 .len = extra.elem_count,
4410 .child = ptr_ty.childType(mod).toIntern(),
4411 .sentinel = if (ptr_ty.sentinel(mod)) |s| s.toIntern() else .none,
4412 });
4413 return Air.internedToRef(arr_ty.toIntern());
4550 }4414 }
4415 // Otherwise, we just want the pointer child type
4416 const ret_ty = ptr_ty.childType(mod);
4417 if (ret_ty.toIntern() == .anyopaque_type) {
4418 // The actual array type is unknown, which we represent with a generic poison.
4419 return .generic_poison_type;
4420 }
4421 const arr_ty = ret_ty.optEuBaseType(mod);
4422 try sema.validateArrayInitTy(block, src, src, extra.elem_count, arr_ty);
4423 return Air.internedToRef(ret_ty.toIntern());
4551}4424}
45524425
4553fn zirValidateArrayInitTy(4426fn zirValidateArrayInitTy(
4554 sema: *Sema,4427 sema: *Sema,
4555 block: *Block,4428 block: *Block,
4556 inst: Zir.Inst.Index,4429 inst: Zir.Inst.Index,
4430 is_result_ty: bool,
4557) CompileError!void {4431) CompileError!void {
4558 const mod = sema.mod;4432 const mod = sema.mod;
4559 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;4433 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
...@@ -4565,22 +4439,34 @@ fn zirValidateArrayInitTy(...@@ -4565,22 +4439,34 @@ fn zirValidateArrayInitTy(
4565 error.GenericPoison => return,4439 error.GenericPoison => return,
4566 else => |e| return e,4440 else => |e| return e,
4567 };4441 };
4442 const arr_ty = if (is_result_ty) ty.optEuBaseType(mod) else ty;
4443 return sema.validateArrayInitTy(block, src, ty_src, extra.init_count, arr_ty);
4444}
45684445
4446fn validateArrayInitTy(
4447 sema: *Sema,
4448 block: *Block,
4449 src: LazySrcLoc,
4450 ty_src: LazySrcLoc,
4451 init_count: u32,
4452 ty: Type,
4453) CompileError!void {
4454 const mod = sema.mod;
4569 switch (ty.zigTypeTag(mod)) {4455 switch (ty.zigTypeTag(mod)) {
4570 .Array => {4456 .Array => {
4571 const array_len = ty.arrayLen(mod);4457 const array_len = ty.arrayLen(mod);
4572 if (extra.init_count != array_len) {4458 if (init_count != array_len) {
4573 return sema.fail(block, src, "expected {d} array elements; found {d}", .{4459 return sema.fail(block, src, "expected {d} array elements; found {d}", .{
4574 array_len, extra.init_count,4460 array_len, init_count,
4575 });4461 });
4576 }4462 }
4577 return;4463 return;
4578 },4464 },
4579 .Vector => {4465 .Vector => {
4580 const array_len = ty.arrayLen(mod);4466 const array_len = ty.arrayLen(mod);
4581 if (extra.init_count != array_len) {4467 if (init_count != array_len) {
4582 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{4468 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
4583 array_len, extra.init_count,4469 array_len, init_count,
4584 });4470 });
4585 }4471 }
4586 return;4472 return;
...@@ -4588,9 +4474,9 @@ fn zirValidateArrayInitTy(...@@ -4588,9 +4474,9 @@ fn zirValidateArrayInitTy(
4588 .Struct => if (ty.isTuple(mod)) {4474 .Struct => if (ty.isTuple(mod)) {
4589 try sema.resolveTypeFields(ty);4475 try sema.resolveTypeFields(ty);
4590 const array_len = ty.arrayLen(mod);4476 const array_len = ty.arrayLen(mod);
4591 if (extra.init_count > array_len) {4477 if (init_count > array_len) {
4592 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{4478 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
4593 array_len, extra.init_count,4479 array_len, init_count,
4594 });4480 });
4595 }4481 }
4596 return;4482 return;
...@@ -4604,6 +4490,7 @@ fn zirValidateStructInitTy(...@@ -4604,6 +4490,7 @@ fn zirValidateStructInitTy(
4604 sema: *Sema,4490 sema: *Sema,
4605 block: *Block,4491 block: *Block,
4606 inst: Zir.Inst.Index,4492 inst: Zir.Inst.Index,
4493 is_result_ty: bool,
4607) CompileError!void {4494) CompileError!void {
4608 const mod = sema.mod;4495 const mod = sema.mod;
4609 const inst_data = sema.code.instructions.items(.data)[inst].un_node;4496 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
...@@ -4613,15 +4500,16 @@ fn zirValidateStructInitTy(...@@ -4613,15 +4500,16 @@ fn zirValidateStructInitTy(
4613 error.GenericPoison => return,4500 error.GenericPoison => return,
4614 else => |e| return e,4501 else => |e| return e,
4615 };4502 };
4503 const struct_ty = if (is_result_ty) ty.optEuBaseType(mod) else ty;
46164504
4617 switch (ty.zigTypeTag(mod)) {4505 switch (struct_ty.zigTypeTag(mod)) {
4618 .Struct, .Union => return,4506 .Struct, .Union => return,
4619 else => {},4507 else => {},
4620 }4508 }
4621 return sema.failWithStructInitNotSupported(block, src, ty);4509 return sema.failWithStructInitNotSupported(block, src, struct_ty);
4622}4510}
46234511
4624fn zirValidateStructInit(4512fn zirValidatePtrStructInit(
4625 sema: *Sema,4513 sema: *Sema,
4626 block: *Block,4514 block: *Block,
4627 inst: Zir.Inst.Index,4515 inst: Zir.Inst.Index,
...@@ -4637,7 +4525,7 @@ fn zirValidateStructInit(...@@ -4637,7 +4525,7 @@ fn zirValidateStructInit(
4637 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;4525 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
4638 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;4526 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
4639 const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);4527 const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
4640 const agg_ty = sema.typeOf(object_ptr).childType(mod);4528 const agg_ty = sema.typeOf(object_ptr).childType(mod).optEuBaseType(mod);
4641 switch (agg_ty.zigTypeTag(mod)) {4529 switch (agg_ty.zigTypeTag(mod)) {
4642 .Struct => return sema.validateStructInit(4530 .Struct => return sema.validateStructInit(
4643 block,4531 block,
...@@ -4723,10 +4611,6 @@ fn validateUnionInit(...@@ -4723,10 +4611,6 @@ fn validateUnionInit(
4723 // based only on the store instructions.4611 // based only on the store instructions.
4724 // `first_block_index` needs to point to the `field_ptr` if it exists;4612 // `first_block_index` needs to point to the `field_ptr` if it exists;
4725 // the `store` otherwise.4613 // the `store` otherwise.
4726 //
4727 // It's also possible for there to be no store instruction, in the case
4728 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
4729 // but we have not found a `store`, treat as a runtime-known field.
4730 var first_block_index = block.instructions.items.len;4614 var first_block_index = block.instructions.items.len;
4731 var block_index = block.instructions.items.len - 1;4615 var block_index = block.instructions.items.len - 1;
4732 var init_val: ?Value = null;4616 var init_val: ?Value = null;
...@@ -4963,10 +4847,6 @@ fn validateStructInit(...@@ -4963,10 +4847,6 @@ fn validateStructInit(
4963 // based only on the store instructions.4847 // based only on the store instructions.
4964 // `first_block_index` needs to point to the `field_ptr` if it exists;4848 // `first_block_index` needs to point to the `field_ptr` if it exists;
4965 // the `store` otherwise.4849 // the `store` otherwise.
4966 //
4967 // It's also possible for there to be no store instruction, in the case
4968 // of nested `coerce_result_ptr` instructions. If we see the `field_ptr`
4969 // but we have not found a `store`, treat as a runtime-known field.
49704850
4971 // Possible performance enhancement: save the `block_index` between iterations4851 // Possible performance enhancement: save the `block_index` between iterations
4972 // of the for loop.4852 // of the for loop.
...@@ -5115,7 +4995,7 @@ fn validateStructInit(...@@ -5115,7 +4995,7 @@ fn validateStructInit(
5115 }4995 }
5116}4996}
51174997
5118fn zirValidateArrayInit(4998fn zirValidatePtrArrayInit(
5119 sema: *Sema,4999 sema: *Sema,
5120 block: *Block,5000 block: *Block,
5121 inst: Zir.Inst.Index,5001 inst: Zir.Inst.Index,
...@@ -5128,7 +5008,7 @@ fn zirValidateArrayInit(...@@ -5128,7 +5008,7 @@ fn zirValidateArrayInit(
5128 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;5008 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
5129 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;5009 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
5130 const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);5010 const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);
5131 const array_ty = sema.typeOf(array_ptr).childType(mod);5011 const array_ty = sema.typeOf(array_ptr).childType(mod).optEuBaseType(mod);
5132 const array_len = array_ty.arrayLen(mod);5012 const array_len = array_ty.arrayLen(mod);
51335013
5134 if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) {5014 if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) {
...@@ -5227,10 +5107,6 @@ fn zirValidateArrayInit(...@@ -5227,10 +5107,6 @@ fn zirValidateArrayInit(
5227 // `first_block_index` needs to point to the `elem_ptr` if it exists;5107 // `first_block_index` needs to point to the `elem_ptr` if it exists;
5228 // the `store` otherwise.5108 // the `store` otherwise.
5229 //5109 //
5230 // It's also possible for there to be no store instruction, in the case
5231 // of nested `coerce_result_ptr` instructions. If we see the `elem_ptr`
5232 // but we have not found a `store`, treat as a runtime-known element.
5233 //
5234 // This is nearly identical to similar logic in `validateStructInit`.5110 // This is nearly identical to similar logic in `validateStructInit`.
52355111
5236 // Possible performance enhancement: save the `block_index` between iterations5112 // Possible performance enhancement: save the `block_index` between iterations
...@@ -5540,10 +5416,7 @@ fn storeToInferredAlloc(...@@ -5540,10 +5416,7 @@ fn storeToInferredAlloc(
5540 try sema.checkComptimeKnownStore(block, dummy_store);5416 try sema.checkComptimeKnownStore(block, dummy_store);
5541 // Add the stored instruction to the set we will use to resolve peer types5417 // Add the stored instruction to the set we will use to resolve peer types
5542 // for the inferred allocation.5418 // for the inferred allocation.
5543 try inferred_alloc.prongs.append(sema.arena, .{5419 try inferred_alloc.prongs.append(sema.arena, Air.refToIndex(dummy_store).?);
5544 .stored_inst = operand,
5545 .placeholder = Air.refToIndex(dummy_store).?,
5546 });
5547}5420}
55485421
5549fn storeToInferredAllocComptime(5422fn storeToInferredAllocComptime(
...@@ -8314,10 +8187,10 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -8314,10 +8187,10 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
8314 return Air.internedToRef(opt_type.toIntern());8187 return Air.internedToRef(opt_type.toIntern());
8315}8188}
83168189
8317fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8190fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
8318 const mod = sema.mod;8191 const mod = sema.mod;
8319 const bin = sema.code.instructions.items(.data)[inst].bin;8192 const bin = sema.code.instructions.items(.data)[inst].bin;
8320 const indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) {8193 const maybe_wrapped_indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) {
8321 // Since this is a ZIR instruction that returns a type, encountering8194 // Since this is a ZIR instruction that returns a type, encountering
8322 // generic poison should not result in a failed compilation, but the8195 // generic poison should not result in a failed compilation, but the
8323 // generic poison type. This prevents unnecessary failures when8196 // generic poison type. This prevents unnecessary failures when
...@@ -8325,6 +8198,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -8325,6 +8198,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
8325 error.GenericPoison => return .generic_poison_type,8198 error.GenericPoison => return .generic_poison_type,
8326 else => |e| return e,8199 else => |e| return e,
8327 };8200 };
8201 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(mod);
8328 try sema.resolveTypeFields(indexable_ty);8202 try sema.resolveTypeFields(indexable_ty);
8329 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction8203 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
8330 if (indexable_ty.zigTypeTag(mod) == .Struct) {8204 if (indexable_ty.zigTypeTag(mod) == .Struct) {
...@@ -8339,8 +8213,18 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -8339,8 +8213,18 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
8339fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8213fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
8340 const mod = sema.mod;8214 const mod = sema.mod;
8341 const un_node = sema.code.instructions.items(.data)[inst].un_node;8215 const un_node = sema.code.instructions.items(.data)[inst].un_node;
8342 const ptr_ty = try sema.resolveType(block, .unneeded, un_node.operand);8216 const maybe_wrapped_ptr_ty = sema.resolveType(block, .unneeded, un_node.operand) catch |err| switch (err) {
8217 error.GenericPoison => return .generic_poison_type,
8218 else => |e| return e,
8219 };
8220 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(mod);
8343 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction8221 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
8222 const elem_ty = ptr_ty.childType(mod);
8223 if (elem_ty.toIntern() == .anyopaque_type) {
8224 // The pointer's actual child type is effectively unknown, so it makes
8225 // sense to represent it with a generic poison.
8226 return .generic_poison_type;
8227 }
8344 return Air.internedToRef(ptr_ty.childType(mod).toIntern());8228 return Air.internedToRef(ptr_ty.childType(mod).toIntern());
8345}8229}
83468230
...@@ -10083,7 +9967,21 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -10083,7 +9967,21 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
10083 return sema.fieldVal(block, src, object, field_name, field_name_src);9967 return sema.fieldVal(block, src, object, field_name, field_name_src);
10084}9968}
100859969
10086fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref {9970fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9971 const tracy = trace(@src());
9972 defer tracy.end();
9973
9974 const mod = sema.mod;
9975 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9976 const src = inst_data.src();
9977 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
9978 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
9979 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
9980 const object_ptr = try sema.resolveInst(extra.lhs);
9981 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
9982}
9983
9984fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10087 const tracy = trace(@src());9985 const tracy = trace(@src());
10088 defer tracy.end();9986 defer tracy.end();
100899987
...@@ -10094,7 +9992,15 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b...@@ -10094,7 +9992,15 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
10094 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;9992 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
10095 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));9993 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
10096 const object_ptr = try sema.resolveInst(extra.lhs);9994 const object_ptr = try sema.resolveInst(extra.lhs);
10097 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);9995 const struct_ty = sema.typeOf(object_ptr).childType(mod);
9996 switch (struct_ty.zigTypeTag(mod)) {
9997 .Struct, .Union => {
9998 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, true);
9999 },
10000 else => {
10001 return sema.failWithStructInitNotSupported(block, src, struct_ty);
10002 },
10003 }
10098}10004}
1009910005
10100fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10006fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -10587,15 +10493,23 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10587,15 +10493,23 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10587 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);10493 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);
10588}10494}
1058910495
10590fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10496fn zirArrayInitElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10591 const tracy = trace(@src());10497 const tracy = trace(@src());
10592 defer tracy.end();10498 defer tracy.end();
1059310499
10500 const mod = sema.mod;
10594 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;10501 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
10595 const src = inst_data.src();10502 const src = inst_data.src();
10596 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;10503 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
10597 const array_ptr = try sema.resolveInst(extra.ptr);10504 const array_ptr = try sema.resolveInst(extra.ptr);
10598 const elem_index = try sema.mod.intRef(Type.usize, extra.index);10505 const elem_index = try sema.mod.intRef(Type.usize, extra.index);
10506 const array_ty = sema.typeOf(array_ptr).childType(mod);
10507 switch (array_ty.zigTypeTag(mod)) {
10508 .Array, .Vector => {},
10509 else => if (!array_ty.isTuple(mod)) {
10510 return sema.failWithArrayInitNotSupported(block, src, array_ty);
10511 },
10512 }
10599 return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true);10513 return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true);
10600}10514}
1060110515
...@@ -19213,6 +19127,52 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -19213,6 +19127,52 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
19213 }19127 }
19214}19128}
1921519129
19130fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_byref: bool) CompileError!Air.Inst.Ref {
19131 const tracy = trace(@src());
19132 defer tracy.end();
19133
19134 const mod = sema.mod;
19135 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
19136 const src = inst_data.src();
19137 const ty_operand = sema.resolveType(block, src, inst_data.operand) catch |err| switch (err) {
19138 // Generic poison means this is an untyped anonymous empty struct init
19139 error.GenericPoison => return .empty_struct,
19140 else => |e| return e,
19141 };
19142 const init_ty = if (is_byref) ty: {
19143 const ptr_ty = ty_operand.optEuBaseType(mod);
19144 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
19145 if (!ptr_ty.isSlice(mod)) {
19146 break :ty ptr_ty.childType(mod);
19147 }
19148 // To make `&.{}` a `[:s]T`, the init should be a `[0:s]T`.
19149 break :ty try mod.arrayType(.{
19150 .len = 0,
19151 .sentinel = if (ptr_ty.sentinel(mod)) |s| s.toIntern() else .none,
19152 .child = ptr_ty.childType(mod).toIntern(),
19153 });
19154 } else ty_operand;
19155 const obj_ty = init_ty.optEuBaseType(mod);
19156
19157 const empty_ref = switch (obj_ty.zigTypeTag(mod)) {
19158 .Struct => try sema.structInitEmpty(block, obj_ty, src, src),
19159 .Array, .Vector => try sema.arrayInitEmpty(block, src, obj_ty),
19160 .Union => return sema.fail(block, src, "union initializer must initialize one field", .{}),
19161 else => return sema.failWithArrayInitNotSupported(block, src, obj_ty),
19162 };
19163 const init_ref = try sema.coerce(block, init_ty, empty_ref, src);
19164
19165 if (is_byref) {
19166 const init_val = (try sema.resolveMaybeUndefVal(init_ref)).?;
19167 var anon_decl = try block.startAnonDecl();
19168 defer anon_decl.deinit();
19169 const decl = try anon_decl.finish(init_ty, init_val, .none);
19170 return sema.analyzeDeclRef(decl);
19171 } else {
19172 return init_ref;
19173 }
19174}
19175
19216fn structInitEmpty(19176fn structInitEmpty(
19217 sema: *Sema,19177 sema: *Sema,
19218 block: *Block,19178 block: *Block,
...@@ -19230,7 +19190,7 @@ fn structInitEmpty(...@@ -19230,7 +19190,7 @@ fn structInitEmpty(
19230 defer gpa.free(field_inits);19190 defer gpa.free(field_inits);
19231 @memset(field_inits, .none);19191 @memset(field_inits, .none);
1923219192
19233 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false);19193 return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, struct_ty, false);
19234}19194}
1923519195
19236fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {19196fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
...@@ -19321,13 +19281,14 @@ fn zirStructInit(...@@ -19321,13 +19281,14 @@ fn zirStructInit(
19321 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;19281 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
19322 const first_field_type_data = zir_datas[first_item.field_type].pl_node;19282 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
19323 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;19283 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
19324 const resolved_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) {19284 const result_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) {
19325 error.GenericPoison => {19285 error.GenericPoison => {
19326 // The type wasn't actually known, so treat this as an anon struct init.19286 // The type wasn't actually known, so treat this as an anon struct init.
19327 return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref);19287 return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref);
19328 },19288 },
19329 else => |e| return e,19289 else => |e| return e,
19330 };19290 };
19291 const resolved_ty = result_ty.optEuBaseType(mod);
19331 try sema.resolveTypeLayout(resolved_ty);19292 try sema.resolveTypeLayout(resolved_ty);
1933219293
19333 if (resolved_ty.zigTypeTag(mod) == .Struct) {19294 if (resolved_ty.zigTypeTag(mod) == .Struct) {
...@@ -19372,7 +19333,9 @@ fn zirStructInit(...@@ -19372,7 +19333,9 @@ fn zirStructInit(
19372 return sema.failWithOwnedErrorMsg(block, msg);19333 return sema.failWithOwnedErrorMsg(block, msg);
19373 }19334 }
19374 found_fields[field_index] = item.data.field_type;19335 found_fields[field_index] = item.data.field_type;
19375 field_inits[field_index] = try sema.resolveInst(item.data.init);19336 const uncoerced_init = try sema.resolveInst(item.data.init);
19337 const field_ty = resolved_ty.structFieldType(field_index, mod);
19338 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
19376 if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {19339 if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {
19377 const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse {19340 const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse {
19378 return sema.failWithNeededComptime(block, field_src, .{19341 return sema.failWithNeededComptime(block, field_src, .{
...@@ -19386,7 +19349,7 @@ fn zirStructInit(...@@ -19386,7 +19349,7 @@ fn zirStructInit(
19386 };19349 };
19387 }19350 }
1938819351
19389 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);19352 return sema.finishStructInit(block, src, src, field_inits, resolved_ty, result_ty, is_ref);
19390 } else if (resolved_ty.zigTypeTag(mod) == .Union) {19353 } else if (resolved_ty.zigTypeTag(mod) == .Union) {
19391 if (extra.data.fields_len != 1) {19354 if (extra.data.fields_len != 1) {
19392 return sema.fail(block, src, "union initialization expects exactly one field", .{});19355 return sema.fail(block, src, "union initialization expects exactly one field", .{});
...@@ -19401,36 +19364,60 @@ fn zirStructInit(...@@ -19401,36 +19364,60 @@ fn zirStructInit(
19401 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);19364 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
19402 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);19365 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
19403 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);19366 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
19367 const field_ty = mod.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index].toType();
19368
19369 if (field_ty.zigTypeTag(mod) == .NoReturn) {
19370 return sema.failWithOwnedErrorMsg(block, msg: {
19371 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
19372 errdefer msg.destroy(sema.gpa);
19373
19374 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{}' declared here", .{
19375 field_name.fmt(ip),
19376 });
19377 try sema.addDeclaredHereNote(msg, resolved_ty);
19378 break :msg msg;
19379 });
19380 }
19381
19382 const uncoerced_init_inst = try sema.resolveInst(item.data.init);
19383 const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src);
1940419384
19405 const init_inst = try sema.resolveInst(item.data.init);
19406 if (try sema.resolveMaybeUndefVal(init_inst)) |val| {19385 if (try sema.resolveMaybeUndefVal(init_inst)) |val| {
19407 const field_ty = mod.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index].toType();19386 const struct_val = (try mod.intern(.{ .un = .{
19408 return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{
19409 .ty = resolved_ty.toIntern(),19387 .ty = resolved_ty.toIntern(),
19410 .tag = try tag_val.intern(tag_ty, mod),19388 .tag = try tag_val.intern(tag_ty, mod),
19411 .val = try val.intern(field_ty, mod),19389 .val = try val.intern(field_ty, mod),
19412 } })).toValue(), is_ref);19390 } })).toValue();
19391 const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src);
19392 const final_val = (try sema.resolveMaybeUndefVal(final_val_inst)).?;
19393 return sema.addConstantMaybeRef(block, resolved_ty, final_val, is_ref);
19394 }
19395
19396 if (try sema.typeRequiresComptime(resolved_ty)) {
19397 return sema.failWithNeededComptime(block, field_src, .{
19398 .needed_comptime_reason = "initializer of comptime only union must be comptime-known",
19399 });
19413 }19400 }
1941419401
19415 if (is_ref) {19402 if (is_ref) {
19416 const target = mod.getTarget();19403 const target = mod.getTarget();
19417 const alloc_ty = try sema.ptrType(.{19404 const alloc_ty = try sema.ptrType(.{
19418 .child = resolved_ty.toIntern(),19405 .child = result_ty.toIntern(),
19419 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19406 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19420 });19407 });
19421 const alloc = try block.addTy(.alloc, alloc_ty);19408 const alloc = try block.addTy(.alloc, alloc_ty);
19422 const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);19409 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
19410 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);
19423 try sema.storePtr(block, src, field_ptr, init_inst);19411 try sema.storePtr(block, src, field_ptr, init_inst);
19424 const new_tag = Air.internedToRef(tag_val.toIntern());19412 const new_tag = Air.internedToRef(tag_val.toIntern());
19425 _ = try block.addBinOp(.set_union_tag, alloc, new_tag);19413 _ = try block.addBinOp(.set_union_tag, base_ptr, new_tag);
19426 return sema.makePtrConst(block, alloc);19414 return sema.makePtrConst(block, alloc);
19427 }19415 }
1942819416
19429 try sema.requireRuntimeBlock(block, src, null);19417 try sema.requireRuntimeBlock(block, src, null);
19430 try sema.queueFullTypeResolution(resolved_ty);19418 try sema.queueFullTypeResolution(resolved_ty);
19431 return block.addUnionInit(resolved_ty, field_index, init_inst);19419 const union_val = try block.addUnionInit(resolved_ty, field_index, init_inst);
19432 } else if (resolved_ty.isAnonStruct(mod)) {19420 return sema.coerce(block, result_ty, union_val, src);
19433 return sema.fail(block, src, "TODO anon struct init validation", .{});
19434 }19421 }
19435 unreachable;19422 unreachable;
19436}19423}
...@@ -19442,6 +19429,7 @@ fn finishStructInit(...@@ -19442,6 +19429,7 @@ fn finishStructInit(
19442 dest_src: LazySrcLoc,19429 dest_src: LazySrcLoc,
19443 field_inits: []Air.Inst.Ref,19430 field_inits: []Air.Inst.Ref,
19444 struct_ty: Type,19431 struct_ty: Type,
19432 result_ty: Type,
19445 is_ref: bool,19433 is_ref: bool,
19446) CompileError!Air.Inst.Ref {19434) CompileError!Air.Inst.Ref {
19447 const mod = sema.mod;19435 const mod = sema.mod;
...@@ -19452,8 +19440,24 @@ fn finishStructInit(...@@ -19452,8 +19440,24 @@ fn finishStructInit(
1945219440
19453 switch (ip.indexToKey(struct_ty.toIntern())) {19441 switch (ip.indexToKey(struct_ty.toIntern())) {
19454 .anon_struct_type => |anon_struct| {19442 .anon_struct_type => |anon_struct| {
19455 for (anon_struct.values.get(ip), 0..) |default_val, i| {19443 // We can't get the slices, as the coercion may invalidate them.
19456 if (field_inits[i] != .none) continue;19444 for (0..anon_struct.types.len) |i| {
19445 if (field_inits[i] != .none) {
19446 // Coerce the init value to the field type.
19447 const field_ty = anon_struct.types.get(ip)[i].toType();
19448 field_inits[i] = sema.coerce(block, field_ty, field_inits[i], .unneeded) catch |err| switch (err) {
19449 error.NeededSourceLocation => {
19450 const decl = mod.declPtr(block.src_decl);
19451 const field_src = mod.initSrc(init_src.node_offset.x, decl, i);
19452 _ = try sema.coerce(block, field_ty, field_inits[i], field_src);
19453 unreachable;
19454 },
19455 else => |e| return e,
19456 };
19457 continue;
19458 }
19459
19460 const default_val = anon_struct.values.get(ip)[i];
1945719461
19458 if (default_val == .none) {19462 if (default_val == .none) {
19459 if (anon_struct.names.len == 0) {19463 if (anon_struct.names.len == 0) {
...@@ -19480,7 +19484,20 @@ fn finishStructInit(...@@ -19480,7 +19484,20 @@ fn finishStructInit(
19480 },19484 },
19481 .struct_type => |struct_type| {19485 .struct_type => |struct_type| {
19482 for (0..struct_type.field_types.len) |i| {19486 for (0..struct_type.field_types.len) |i| {
19483 if (field_inits[i] != .none) continue;19487 if (field_inits[i] != .none) {
19488 // Coerce the init value to the field type.
19489 const field_ty = struct_type.field_types.get(ip)[i].toType();
19490 field_inits[i] = sema.coerce(block, field_ty, field_inits[i], init_src) catch |err| switch (err) {
19491 error.NeededSourceLocation => {
19492 const decl = mod.declPtr(block.src_decl);
19493 const field_src = mod.initSrc(init_src.node_offset.x, decl, i);
19494 _ = try sema.coerce(block, field_ty, field_inits[i], field_src);
19495 unreachable;
19496 },
19497 else => |e| return e,
19498 };
19499 continue;
19500 }
1948419501
19485 const field_init = struct_type.fieldInit(ip, i);19502 const field_init = struct_type.fieldInit(ip, i);
19486 if (field_init == .none) {19503 if (field_init == .none) {
...@@ -19524,29 +19541,39 @@ fn finishStructInit(...@@ -19524,29 +19541,39 @@ fn finishStructInit(
1952419541
19525 const runtime_index = opt_runtime_index orelse {19542 const runtime_index = opt_runtime_index orelse {
19526 const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);19543 const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
19527 for (elems, field_inits, 0..) |*elem, field_init, field_i| {19544 for (elems, field_inits) |*elem, field_init| {
19528 elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).?19545 elem.* = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?.toIntern();
19529 .intern(struct_ty.structFieldType(field_i, mod), mod);
19530 }19546 }
19531 const struct_val = try mod.intern(.{ .aggregate = .{19547 const struct_val = try mod.intern(.{ .aggregate = .{
19532 .ty = struct_ty.toIntern(),19548 .ty = struct_ty.toIntern(),
19533 .storage = .{ .elems = elems },19549 .storage = .{ .elems = elems },
19534 } });19550 } });
19535 return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref);19551 const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val), init_src);
19552 const final_val = (try sema.resolveMaybeUndefVal(final_val_inst)).?;
19553 return sema.addConstantMaybeRef(block, result_ty, final_val, is_ref);
19536 };19554 };
1953719555
19556 if (try sema.typeRequiresComptime(struct_ty)) {
19557 const decl = mod.declPtr(block.src_decl);
19558 const field_src = mod.initSrc(init_src.node_offset.x, decl, runtime_index);
19559 return sema.failWithNeededComptime(block, field_src, .{
19560 .needed_comptime_reason = "initializer of comptime only struct must be comptime-known",
19561 });
19562 }
19563
19538 if (is_ref) {19564 if (is_ref) {
19539 try sema.resolveStructLayout(struct_ty);19565 try sema.resolveStructLayout(struct_ty);
19540 const target = sema.mod.getTarget();19566 const target = sema.mod.getTarget();
19541 const alloc_ty = try sema.ptrType(.{19567 const alloc_ty = try sema.ptrType(.{
19542 .child = struct_ty.toIntern(),19568 .child = result_ty.toIntern(),
19543 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19569 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19544 });19570 });
19545 const alloc = try block.addTy(.alloc, alloc_ty);19571 const alloc = try block.addTy(.alloc, alloc_ty);
19572 const base_ptr = try sema.optEuBasePtrInit(block, alloc, init_src);
19546 for (field_inits, 0..) |field_init, i_usize| {19573 for (field_inits, 0..) |field_init, i_usize| {
19547 const i: u32 = @intCast(i_usize);19574 const i: u32 = @intCast(i_usize);
19548 const field_src = dest_src;19575 const field_src = dest_src;
19549 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true);19576 const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, base_ptr, i, field_src, struct_ty, true);
19550 try sema.storePtr(block, dest_src, field_ptr, field_init);19577 try sema.storePtr(block, dest_src, field_ptr, field_init);
19551 }19578 }
1955219579
...@@ -19563,19 +19590,19 @@ fn finishStructInit(...@@ -19563,19 +19590,19 @@ fn finishStructInit(
19563 else => |e| return e,19590 else => |e| return e,
19564 };19591 };
19565 try sema.queueFullTypeResolution(struct_ty);19592 try sema.queueFullTypeResolution(struct_ty);
19566 return block.addAggregateInit(struct_ty, field_inits);19593 const struct_val = try block.addAggregateInit(struct_ty, field_inits);
19594 return sema.coerce(block, result_ty, struct_val, init_src);
19567}19595}
1956819596
19569fn zirStructInitAnon(19597fn zirStructInitAnon(
19570 sema: *Sema,19598 sema: *Sema,
19571 block: *Block,19599 block: *Block,
19572 inst: Zir.Inst.Index,19600 inst: Zir.Inst.Index,
19573 is_ref: bool,
19574) CompileError!Air.Inst.Ref {19601) CompileError!Air.Inst.Ref {
19575 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;19602 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
19576 const src = inst_data.src();19603 const src = inst_data.src();
19577 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);19604 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
19578 return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, is_ref);19605 return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, false);
19579}19606}
1958019607
19581fn structInitAnon(19608fn structInitAnon(
...@@ -19748,13 +19775,14 @@ fn zirArrayInit(...@@ -19748,13 +19775,14 @@ fn zirArrayInit(
19748 const args = sema.code.refSlice(extra.end, extra.data.operands_len);19775 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
19749 assert(args.len >= 2); // array_ty + at least one element19776 assert(args.len >= 2); // array_ty + at least one element
1975019777
19751 const array_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) {19778 const result_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) {
19752 error.GenericPoison => {19779 error.GenericPoison => {
19753 // The type wasn't actually known, so treat this as an anon array init.19780 // The type wasn't actually known, so treat this as an anon array init.
19754 return sema.arrayInitAnon(block, src, args[1..], is_ref);19781 return sema.arrayInitAnon(block, src, args[1..], is_ref);
19755 },19782 },
19756 else => |e| return e,19783 else => |e| return e,
19757 };19784 };
19785 const array_ty = result_ty.optEuBaseType(mod);
19758 const is_tuple = array_ty.zigTypeTag(mod) == .Struct;19786 const is_tuple = array_ty.zigTypeTag(mod) == .Struct;
19759 const sentinel_val = array_ty.sentinel(mod);19787 const sentinel_val = array_ty.sentinel(mod);
1976019788
...@@ -19810,10 +19838,12 @@ fn zirArrayInit(...@@ -19810,10 +19838,12 @@ fn zirArrayInit(
19810 // We checked that all args are comptime above.19838 // We checked that all args are comptime above.
19811 val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod);19839 val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod);
19812 }19840 }
19813 return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{19841 const arr_val = try mod.intern(.{ .aggregate = .{
19814 .ty = array_ty.toIntern(),19842 .ty = array_ty.toIntern(),
19815 .storage = .{ .elems = elem_vals },19843 .storage = .{ .elems = elem_vals },
19816 } })).toValue(), is_ref);19844 } });
19845 const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val), src);
19846 return sema.addConstantMaybeRef(block, result_ty, (try sema.resolveMaybeUndefVal(result_ref)).?, is_ref);
19817 };19847 };
1981819848
19819 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {19849 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
...@@ -19830,10 +19860,11 @@ fn zirArrayInit(...@@ -19830,10 +19860,11 @@ fn zirArrayInit(
19830 if (is_ref) {19860 if (is_ref) {
19831 const target = mod.getTarget();19861 const target = mod.getTarget();
19832 const alloc_ty = try sema.ptrType(.{19862 const alloc_ty = try sema.ptrType(.{
19833 .child = array_ty.toIntern(),19863 .child = result_ty.toIntern(),
19834 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19864 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19835 });19865 });
19836 const alloc = try block.addTy(.alloc, alloc_ty);19866 const alloc = try block.addTy(.alloc, alloc_ty);
19867 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
1983719868
19838 if (array_ty.isTuple(mod)) {19869 if (array_ty.isTuple(mod)) {
19839 for (resolved_args, 0..) |arg, i| {19870 for (resolved_args, 0..) |arg, i| {
...@@ -19844,7 +19875,7 @@ fn zirArrayInit(...@@ -19844,7 +19875,7 @@ fn zirArrayInit(
19844 const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());19875 const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());
1984519876
19846 const index = try mod.intRef(Type.usize, i);19877 const index = try mod.intRef(Type.usize, i);
19847 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);19878 const elem_ptr = try block.addPtrElemPtrTypeRef(base_ptr, index, elem_ptr_ty_ref);
19848 _ = try block.addBinOp(.store, elem_ptr, arg);19879 _ = try block.addBinOp(.store, elem_ptr, arg);
19849 }19880 }
19850 return sema.makePtrConst(block, alloc);19881 return sema.makePtrConst(block, alloc);
...@@ -19858,26 +19889,26 @@ fn zirArrayInit(...@@ -19858,26 +19889,26 @@ fn zirArrayInit(
1985819889
19859 for (resolved_args, 0..) |arg, i| {19890 for (resolved_args, 0..) |arg, i| {
19860 const index = try mod.intRef(Type.usize, i);19891 const index = try mod.intRef(Type.usize, i);
19861 const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);19892 const elem_ptr = try block.addPtrElemPtrTypeRef(base_ptr, index, elem_ptr_ty_ref);
19862 _ = try block.addBinOp(.store, elem_ptr, arg);19893 _ = try block.addBinOp(.store, elem_ptr, arg);
19863 }19894 }
19864 return sema.makePtrConst(block, alloc);19895 return sema.makePtrConst(block, alloc);
19865 }19896 }
1986619897
19867 return block.addAggregateInit(array_ty, resolved_args);19898 const arr_ref = try block.addAggregateInit(array_ty, resolved_args);
19899 return sema.coerce(block, result_ty, arr_ref, src);
19868}19900}
1986919901
19870fn zirArrayInitAnon(19902fn zirArrayInitAnon(
19871 sema: *Sema,19903 sema: *Sema,
19872 block: *Block,19904 block: *Block,
19873 inst: Zir.Inst.Index,19905 inst: Zir.Inst.Index,
19874 is_ref: bool,
19875) CompileError!Air.Inst.Ref {19906) CompileError!Air.Inst.Ref {
19876 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;19907 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
19877 const src = inst_data.src();19908 const src = inst_data.src();
19878 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);19909 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
19879 const operands = sema.code.refSlice(extra.end, extra.data.operands_len);19910 const operands = sema.code.refSlice(extra.end, extra.data.operands_len);
19880 return sema.arrayInitAnon(block, src, operands, is_ref);19911 return sema.arrayInitAnon(block, src, operands, false);
19881}19912}
1988219913
19883fn arrayInitAnon(19914fn arrayInitAnon(
...@@ -19997,14 +20028,14 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -19997,14 +20028,14 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
19997 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);20028 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
19998}20029}
1999920030
20000fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {20031fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
20001 const mod = sema.mod;20032 const mod = sema.mod;
20002 const ip = &mod.intern_pool;20033 const ip = &mod.intern_pool;
20003 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;20034 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
20004 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;20035 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
20005 const ty_src = inst_data.src();20036 const ty_src = inst_data.src();
20006 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };20037 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
20007 const aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) {20038 const wrapped_aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) {
20008 // Since this is a ZIR instruction that returns a type, encountering20039 // Since this is a ZIR instruction that returns a type, encountering
20009 // generic poison should not result in a failed compilation, but the20040 // generic poison should not result in a failed compilation, but the
20010 // generic poison type. This prevents unnecessary failures when20041 // generic poison type. This prevents unnecessary failures when
...@@ -20012,6 +20043,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -20012,6 +20043,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
20012 error.GenericPoison => return .generic_poison_type,20043 error.GenericPoison => return .generic_poison_type,
20013 else => |e| return e,20044 else => |e| return e,
20014 };20045 };
20046 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(mod);
20015 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);20047 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
20016 const field_name = try ip.getOrPutString(sema.gpa, zir_field_name);20048 const field_name = try ip.getOrPutString(sema.gpa, zir_field_name);
20017 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);20049 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
...@@ -20033,7 +20065,10 @@ fn fieldType(...@@ -20033,7 +20065,10 @@ fn fieldType(
20033 switch (cur_ty.zigTypeTag(mod)) {20065 switch (cur_ty.zigTypeTag(mod)) {
20034 .Struct => switch (ip.indexToKey(cur_ty.toIntern())) {20066 .Struct => switch (ip.indexToKey(cur_ty.toIntern())) {
20035 .anon_struct_type => |anon_struct| {20067 .anon_struct_type => |anon_struct| {
20036 const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);20068 const field_index = if (anon_struct.names.len == 0)
20069 try sema.tupleFieldIndex(block, cur_ty, field_name, field_src)
20070 else
20071 try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
20037 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);20072 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
20038 },20073 },
20039 .struct_type => |struct_type| {20074 .struct_type => |struct_type| {
...@@ -21620,7 +21655,8 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -21620,7 +21655,8 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21620 const operand_coerced = try sema.coerce(block, operand_ty, operand_res, operand_src);21655 const operand_coerced = try sema.coerce(block, operand_ty, operand_res, operand_src);
2162121656
21622 const ptr_ty = dest_ty.scalarType(mod);21657 const ptr_ty = dest_ty.scalarType(mod);
21623 try sema.checkPtrType(block, src, ptr_ty);21658 try sema.checkPtrType(block, src, ptr_ty, true);
21659
21624 const elem_ty = ptr_ty.elemType2(mod);21660 const elem_ty = ptr_ty.elemType2(mod);
21625 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);21661 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
2162621662
...@@ -21860,7 +21896,7 @@ fn ptrCastFull(...@@ -21860,7 +21896,7 @@ fn ptrCastFull(
21860 const mod = sema.mod;21896 const mod = sema.mod;
21861 const operand_ty = sema.typeOf(operand);21897 const operand_ty = sema.typeOf(operand);
2186221898
21863 try sema.checkPtrType(block, src, dest_ty);21899 try sema.checkPtrType(block, src, dest_ty, true);
21864 try sema.checkPtrOperand(block, operand_src, operand_ty);21900 try sema.checkPtrOperand(block, operand_src, operand_ty);
2186521901
21866 const src_info = operand_ty.ptrInfo(mod);21902 const src_info = operand_ty.ptrInfo(mod);
...@@ -22668,10 +22704,11 @@ fn checkPtrType(...@@ -22668,10 +22704,11 @@ fn checkPtrType(
22668 block: *Block,22704 block: *Block,
22669 ty_src: LazySrcLoc,22705 ty_src: LazySrcLoc,
22670 ty: Type,22706 ty: Type,
22707 allow_slice: bool,
22671) CompileError!void {22708) CompileError!void {
22672 const mod = sema.mod;22709 const mod = sema.mod;
22673 switch (ty.zigTypeTag(mod)) {22710 switch (ty.zigTypeTag(mod)) {
22674 .Pointer => return,22711 .Pointer => if (allow_slice or !ty.isSlice(mod)) return,
22675 .Fn => {22712 .Fn => {
22676 const msg = msg: {22713 const msg = msg: {
22677 const msg = try sema.errMsg(22714 const msg = try sema.errMsg(
...@@ -29577,13 +29614,6 @@ fn storePtr2(...@@ -29577,13 +29614,6 @@ fn storePtr2(
29577 return;29614 return;
29578 }29615 }
2957929616
29580 if (air_tag == .bitcast) {
29581 // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr`
29582 // to avoid calling `requireRuntimeBlock` for the dummy block.
29583 _ = try block.addBinOp(.store, ptr, operand);
29584 return;
29585 }
29586
29587 try sema.requireRuntimeBlock(block, src, runtime_src);29617 try sema.requireRuntimeBlock(block, src, runtime_src);
29588 try sema.queueFullTypeResolution(elem_ty);29618 try sema.queueFullTypeResolution(elem_ty);
2958929619
...@@ -29719,6 +29749,7 @@ fn storePtrVal(...@@ -29719,6 +29749,7 @@ fn storePtrVal(
29719 switch (mut_kit.pointee) {29749 switch (mut_kit.pointee) {
29720 .direct => |val_ptr| {29750 .direct => |val_ptr| {
29721 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {29751 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
29752 val_ptr.* = (try val_ptr.intern(operand_ty, mod)).toValue();
29722 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {29753 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
29723 // TODO use failWithInvalidComptimeFieldStore29754 // TODO use failWithInvalidComptimeFieldStore
29724 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});29755 return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
src/Zir.zig+181-144
...@@ -242,10 +242,9 @@ pub const Inst = struct {...@@ -242,10 +242,9 @@ pub const Inst = struct {
242 /// Uses the `pl_node` union field with `Bin` payload.242 /// Uses the `pl_node` union field with `Bin` payload.
243 /// lhs is length, rhs is element type.243 /// lhs is length, rhs is element type.
244 vector_type,244 vector_type,
245 /// Given an indexable type, returns the type of the element at given index.245 /// Given a pointer type, returns its element type. Reaches through any optional or error
246 /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.246 /// union types wrapping the pointer. Asserts that the underlying type is a pointer type.
247 elem_type_index,247 /// Returns generic poison if the element type is `anyopaque`.
248 /// Given a pointer type, returns its element type.
249 /// Uses the `un_node` field.248 /// Uses the `un_node` field.
250 elem_type,249 elem_type,
251 /// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its250 /// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its
...@@ -353,11 +352,6 @@ pub const Inst = struct {...@@ -353,11 +352,6 @@ pub const Inst = struct {
353 /// `!=`352 /// `!=`
354 /// Uses the `pl_node` union field. Payload is `Bin`.353 /// Uses the `pl_node` union field. Payload is `Bin`.
355 cmp_neq,354 cmp_neq,
356 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
357 /// as type coercion from the new element type to the old element type.
358 /// Uses the `pl_node` union field. Payload is `Bin`.
359 /// LHS is destination element type, RHS is result pointer.
360 coerce_result_ptr,
361 /// Conditional branch. Splits control flow based on a boolean condition value.355 /// Conditional branch. Splits control flow based on a boolean condition value.
362 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.356 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
363 /// Payload is `CondBr`.357 /// Payload is `CondBr`.
...@@ -419,13 +413,6 @@ pub const Inst = struct {...@@ -419,13 +413,6 @@ pub const Inst = struct {
419 /// Payload is `Bin`.413 /// Payload is `Bin`.
420 /// No OOB safety check is emitted.414 /// No OOB safety check is emitted.
421 elem_ptr,415 elem_ptr,
422 /// Same as `elem_ptr_node` except the index is stored immediately rather than
423 /// as a reference to another ZIR instruction.
424 /// Uses the `pl_node` union field. AST node is an element inside array initialization
425 /// syntax. Payload is `ElemPtrImm`.
426 /// This instruction has a way to set the result type to be a
427 /// single-pointer or a many-pointer.
428 elem_ptr_imm,
429 /// Given an array, slice, or pointer, returns the element at the provided index.416 /// Given an array, slice, or pointer, returns the element at the provided index.
430 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.417 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
431 elem_val_node,418 elem_val_node,
...@@ -463,8 +450,6 @@ pub const Inst = struct {...@@ -463,8 +450,6 @@ pub const Inst = struct {
463 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.450 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
464 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.451 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
465 field_ptr,452 field_ptr,
466 /// Same as `field_ptr` but used for struct init.
467 field_ptr_init,
468 /// Given a struct or object that contains virtual fields, returns the named field.453 /// Given a struct or object that contains virtual fields, returns the named field.
469 /// The field name is stored in string_bytes. Used by a.b syntax.454 /// The field name is stored in string_bytes. Used by a.b syntax.
470 /// This instruction also accepts a pointer.455 /// This instruction also accepts a pointer.
...@@ -688,84 +673,123 @@ pub const Inst = struct {...@@ -688,84 +673,123 @@ pub const Inst = struct {
688 /// A switch expression. Uses the `pl_node` union field.673 /// A switch expression. Uses the `pl_node` union field.
689 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.674 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
690 switch_block_ref,675 switch_block_ref,
691 /// Given a
692 /// *A returns *A
693 /// *E!A returns *A
694 /// *?A returns *A
695 /// Uses the `un_node` field.
696 array_base_ptr,
697 /// Given a
698 /// *S returns *S
699 /// *E!S returns *S
700 /// *?S returns *S
701 /// Uses the `un_node` field.
702 field_base_ptr,
703 /// Given a type, strips all optional and error union types wrapping it.
704 /// e.g. `E!?u32` becomes `u32`, `[]u8` becomes `[]u8`.
705 /// Uses the `un_node` field.
706 opt_eu_base_ty,
707 /// Checks that the type supports array init syntax.
708 /// Returns the underlying indexable type (since the given type may be e.g. an optional).
709 /// Uses the `un_node` field.
710 validate_array_init_ty,
711 /// Checks that the type supports struct init syntax.
712 /// Returns the underlying struct type (since the given type may be e.g. an optional).
713 /// Uses the `un_node` field.
714 validate_struct_init_ty,
715 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
716 /// initialization expression, and emits compile errors for duplicate fields
717 /// as well as missing fields, if applicable.
718 /// This instruction asserts that there is at least one field_ptr instruction,
719 /// because it must use one of them to find out the struct type.
720 /// Uses the `pl_node` field. Payload is `Block`.
721 validate_struct_init,
722 /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an
723 /// array initialization expression, and emits a compile error if the number of
724 /// elements does not match the array type.
725 /// This instruction asserts that there is at least one `elem_ptr_imm` instruction,
726 /// because it must use one of them to find out the array type.
727 /// Uses the `pl_node` field. Payload is `Block`.
728 validate_array_init,
729 /// Check that operand type supports the dereference operand (.*).676 /// Check that operand type supports the dereference operand (.*).
730 /// Uses the `un_node` field.677 /// Uses the `un_node` field.
731 validate_deref,678 validate_deref,
732 /// Check that the operand's type is an array or tuple with the given number of elements.679 /// Check that the operand's type is an array or tuple with the given number of elements.
733 /// Uses the `pl_node` field. Payload is `ValidateDestructure`.680 /// Uses the `pl_node` field. Payload is `ValidateDestructure`.
734 validate_destructure,681 validate_destructure,
735 /// A struct literal with a specified type, with no fields.
736 /// Uses the `un_node` field.
737 struct_init_empty,
738 /// Given a struct or union, and a field name as a string index,
739 /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`.
740 field_type,
741 /// Given a struct or union, and a field name as a Ref,682 /// Given a struct or union, and a field name as a Ref,
742 /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.683 /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
743 field_type_ref,684 field_type_ref,
685 /// Given a pointer, initializes all error unions and optionals in the pointee to payloads,
686 /// returning the base payload pointer. For instance, converts *E!?T into a valid *T
687 /// (clobbering any existing error or null value).
688 /// Uses the `un_node` field.
689 opt_eu_base_ptr_init,
690 /// Coerce a given value such that when a reference is taken, the resulting pointer will be
691 /// coercible to the given type. For instance, given a value of type 'u32' and the pointer
692 /// type '*u64', coerces the value to a 'u64'. Asserts that the type is a pointer type.
693 /// Uses the `pl_node` field. Payload is `Bin`.
694 /// LHS is the pointer type, RHS is the value.
695 coerce_ptr_elem_ty,
696 /// Given a type, validate that it is a pointer type suitable for return from the address-of
697 /// operator. Emit a compile error if not.
698 /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type.
699 validate_ref_ty,
700
701 // The following tags all relate to struct initialization expressions.
702
703 /// A struct literal with a specified explicit type, with no fields.
704 /// Uses the `un_node` field.
705 struct_init_empty,
706 /// An anonymous struct literal with a known result type, with no fields.
707 /// Uses the `un_node` field.
708 struct_init_empty_result,
709 /// An anonymous struct literal with no fields, returned by reference, with a known result
710 /// type for the pointer. Asserts that the type is a pointer.
711 /// Uses the `un_node` field.
712 struct_init_empty_ref_result,
713 /// Struct initialization without a type. Creates a value of an anonymous struct type.
714 /// Uses the `pl_node` field. Payload is `StructInitAnon`.
715 struct_init_anon,
744 /// Finalizes a typed struct or union initialization, performs validation, and returns the716 /// Finalizes a typed struct or union initialization, performs validation, and returns the
745 /// struct or union value.717 /// struct or union value. The given type must be validated prior to this instruction, using
718 /// `validate_struct_init_ty` or `validate_struct_init_result_ty`. If the given type is
719 /// generic poison, this is downgraded to an anonymous initialization.
746 /// Uses the `pl_node` field. Payload is `StructInit`.720 /// Uses the `pl_node` field. Payload is `StructInit`.
747 struct_init,721 struct_init,
748 /// Struct initialization syntax, make the result a pointer.722 /// Struct initialization syntax, make the result a pointer. Equivalent to `struct_init`
723 /// followed by `ref` - this ZIR tag exists as an optimization for a common pattern.
749 /// Uses the `pl_node` field. Payload is `StructInit`.724 /// Uses the `pl_node` field. Payload is `StructInit`.
750 struct_init_ref,725 struct_init_ref,
751 /// Struct initialization without a type.726 /// Checks that the type supports struct init syntax. Always returns void.
752 /// Uses the `pl_node` field. Payload is `StructInitAnon`.727 /// Uses the `un_node` field.
753 struct_init_anon,728 validate_struct_init_ty,
754 /// Anonymous struct initialization syntax, make the result a pointer.729 /// Like `validate_struct_init_ty`, but additionally accepts types which structs coerce to.
755 /// Uses the `pl_node` field. Payload is `StructInitAnon`.730 /// Used on the known result type of a struct init expression. Always returns void.
756 struct_init_anon_ref,731 /// Uses the `un_node` field.
757 /// Array initialization syntax.732 validate_struct_init_result_ty,
758 /// Uses the `pl_node` field. Payload is `MultiOp`.733 /// Given a set of `struct_init_field_ptr` instructions, assumes they are all part of a
759 array_init,734 /// struct initialization expression, and emits compile errors for duplicate fields as well
760 /// Anonymous array initialization syntax.735 /// as missing fields, if applicable.
736 /// This instruction asserts that there is at least one struct_init_field_ptr instruction,
737 /// because it must use one of them to find out the struct type.
738 /// Uses the `pl_node` field. Payload is `Block`.
739 validate_ptr_struct_init,
740 /// Given a type being used for a struct initialization expression, returns the type of the
741 /// field with the given name.
742 /// Uses the `pl_node` field. Payload is `FieldType`.
743 struct_init_field_type,
744 /// Given a pointer being used as the result pointer of a struct initialization expression,
745 /// return a pointer to the field of the given name.
746 /// Uses the `pl_node` field. The AST node is the field initializer. Payload is Field.
747 struct_init_field_ptr,
748
749 // The following tags all relate to array initialization expressions.
750
751 /// Array initialization without a type. Creates a value of a tuple type.
761 /// Uses the `pl_node` field. Payload is `MultiOp`.752 /// Uses the `pl_node` field. Payload is `MultiOp`.
762 array_init_anon,753 array_init_anon,
763 /// Array initialization syntax, make the result a pointer.754 /// Array initialization syntax with a known type. The given type must be validated prior to
764 /// Uses the `pl_node` field. Payload is `MultiOp`.755 /// this instruction, using some `validate_array_init_*_ty` instruction.
756 /// Uses the `pl_node` field. Payload is `MultiOp`, where the first operand is the type.
757 array_init,
758 /// Array initialization syntax, make the result a pointer. Equivalent to `array_init`
759 /// followed by `ref`- this ZIR tag exists as an optimization for a common pattern.
760 /// Uses the `pl_node` field. Payload is `MultiOp`, where the first operand is the type.
765 array_init_ref,761 array_init_ref,
766 /// Anonymous array initialization syntax, make the result a pointer.762 /// Checks that the type supports array init syntax. Always returns void.
767 /// Uses the `pl_node` field. Payload is `MultiOp`.763 /// Uses the `pl_node` field. Payload is `ArrayInit`.
768 array_init_anon_ref,764 validate_array_init_ty,
765 /// Like `validate_array_init_ty`, but additionally accepts types which arrays coerce to.
766 /// Used on the known result type of an array init expression. Always returns void.
767 /// Uses the `pl_node` field. Payload is `ArrayInit`.
768 validate_array_init_result_ty,
769 /// Given a pointer or slice type and an element count, return the expected type of an array
770 /// initializer such that a pointer to the initializer has the given pointer type, checking
771 /// that this type supports array init syntax and emitting a compile error if not. Preserves
772 /// error union and optional wrappers on the array type, if any.
773 /// Asserts that the given type is a pointer or slice type.
774 /// Uses the `pl_node` field. Payload is `ArrayInitRefTy`.
775 validate_array_init_ref_ty,
776 /// Given a set of `array_init_elem_ptr` instructions, assumes they are all part of an array
777 /// initialization expression, and emits a compile error if the number of elements does not
778 /// match the array type.
779 /// This instruction asserts that there is at least one `array_init_elem_ptr` instruction,
780 /// because it must use one of them to find out the array type.
781 /// Uses the `pl_node` field. Payload is `Block`.
782 validate_ptr_array_init,
783 /// Given a type being used for an array initialization expression, returns the type of the
784 /// element at the given index.
785 /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.
786 array_init_elem_type,
787 /// Given a pointer being used as the result pointer of an array initialization expression,
788 /// return a pointer to the element at the given index.
789 /// Uses the `pl_node` union field. AST node is an element inside array initialization
790 /// syntax. Payload is `ElemPtrImm`.
791 array_init_elem_ptr,
792
769 /// Implements the `@unionInit` builtin.793 /// Implements the `@unionInit` builtin.
770 /// Uses the `pl_node` field. Payload is `UnionInit`.794 /// Uses the `pl_node` field. Payload is `UnionInit`.
771 union_init,795 union_init,
...@@ -1038,7 +1062,6 @@ pub const Inst = struct {...@@ -1038,7 +1062,6 @@ pub const Inst = struct {
1038 .array_type,1062 .array_type,
1039 .array_type_sentinel,1063 .array_type_sentinel,
1040 .vector_type,1064 .vector_type,
1041 .elem_type_index,
1042 .elem_type,1065 .elem_type,
1043 .indexable_ptr_elem_type,1066 .indexable_ptr_elem_type,
1044 .vector_elem_type,1067 .vector_elem_type,
...@@ -1066,7 +1089,6 @@ pub const Inst = struct {...@@ -1066,7 +1089,6 @@ pub const Inst = struct {
1066 .cmp_gte,1089 .cmp_gte,
1067 .cmp_gt,1090 .cmp_gt,
1068 .cmp_neq,1091 .cmp_neq,
1069 .coerce_result_ptr,
1070 .error_set_decl,1092 .error_set_decl,
1071 .error_set_decl_anon,1093 .error_set_decl_anon,
1072 .error_set_decl_func,1094 .error_set_decl_func,
...@@ -1082,7 +1104,6 @@ pub const Inst = struct {...@@ -1082,7 +1104,6 @@ pub const Inst = struct {
1082 .elem_ptr,1104 .elem_ptr,
1083 .elem_val,1105 .elem_val,
1084 .elem_ptr_node,1106 .elem_ptr_node,
1085 .elem_ptr_imm,
1086 .elem_val_node,1107 .elem_val_node,
1087 .elem_val_imm,1108 .elem_val_imm,
1088 .ensure_result_used,1109 .ensure_result_used,
...@@ -1091,7 +1112,6 @@ pub const Inst = struct {...@@ -1091,7 +1112,6 @@ pub const Inst = struct {
1091 .@"export",1112 .@"export",
1092 .export_value,1113 .export_value,
1093 .field_ptr,1114 .field_ptr,
1094 .field_ptr_init,
1095 .field_val,1115 .field_val,
1096 .field_ptr_named,1116 .field_ptr_named,
1097 .field_val_named,1117 .field_val_named,
...@@ -1154,25 +1174,9 @@ pub const Inst = struct {...@@ -1154,25 +1174,9 @@ pub const Inst = struct {
1154 .set_eval_branch_quota,1174 .set_eval_branch_quota,
1155 .switch_block,1175 .switch_block,
1156 .switch_block_ref,1176 .switch_block_ref,
1157 .array_base_ptr,
1158 .field_base_ptr,
1159 .validate_array_init_ty,
1160 .validate_struct_init_ty,
1161 .validate_struct_init,
1162 .validate_array_init,
1163 .validate_deref,1177 .validate_deref,
1164 .validate_destructure,1178 .validate_destructure,
1165 .struct_init_empty,
1166 .struct_init,
1167 .struct_init_ref,
1168 .struct_init_anon,
1169 .struct_init_anon_ref,
1170 .array_init,
1171 .array_init_anon,
1172 .array_init_ref,
1173 .array_init_anon_ref,
1174 .union_init,1179 .union_init,
1175 .field_type,
1176 .field_type_ref,1180 .field_type_ref,
1177 .enum_from_int,1181 .enum_from_int,
1178 .int_from_enum,1182 .int_from_enum,
...@@ -1254,7 +1258,29 @@ pub const Inst = struct {...@@ -1254,7 +1258,29 @@ pub const Inst = struct {
1254 .save_err_ret_index,1258 .save_err_ret_index,
1255 .restore_err_ret_index,1259 .restore_err_ret_index,
1256 .for_len,1260 .for_len,
1257 .opt_eu_base_ty,1261 .opt_eu_base_ptr_init,
1262 .coerce_ptr_elem_ty,
1263 .struct_init_empty,
1264 .struct_init_empty_result,
1265 .struct_init_empty_ref_result,
1266 .struct_init_anon,
1267 .struct_init,
1268 .struct_init_ref,
1269 .validate_struct_init_ty,
1270 .validate_struct_init_result_ty,
1271 .validate_ptr_struct_init,
1272 .struct_init_field_type,
1273 .struct_init_field_ptr,
1274 .array_init_anon,
1275 .array_init,
1276 .array_init_ref,
1277 .validate_array_init_ty,
1278 .validate_array_init_result_ty,
1279 .validate_array_init_ref_ty,
1280 .validate_ptr_array_init,
1281 .array_init_elem_type,
1282 .array_init_elem_ptr,
1283 .validate_ref_ty,
1258 => false,1284 => false,
12591285
1260 .@"break",1286 .@"break",
...@@ -1307,10 +1333,6 @@ pub const Inst = struct {...@@ -1307,10 +1333,6 @@ pub const Inst = struct {
1307 .store_node,1333 .store_node,
1308 .store_to_inferred_ptr,1334 .store_to_inferred_ptr,
1309 .resolve_inferred_alloc,1335 .resolve_inferred_alloc,
1310 .validate_array_init_ty,
1311 .validate_struct_init_ty,
1312 .validate_struct_init,
1313 .validate_array_init,
1314 .validate_deref,1336 .validate_deref,
1315 .validate_destructure,1337 .validate_destructure,
1316 .@"export",1338 .@"export",
...@@ -1323,6 +1345,13 @@ pub const Inst = struct {...@@ -1323,6 +1345,13 @@ pub const Inst = struct {
1323 .defer_err_code,1345 .defer_err_code,
1324 .restore_err_ret_index,1346 .restore_err_ret_index,
1325 .save_err_ret_index,1347 .save_err_ret_index,
1348 .validate_struct_init_ty,
1349 .validate_struct_init_result_ty,
1350 .validate_ptr_struct_init,
1351 .validate_array_init_ty,
1352 .validate_array_init_result_ty,
1353 .validate_ptr_array_init,
1354 .validate_ref_ty,
1326 => true,1355 => true,
13271356
1328 .param,1357 .param,
...@@ -1346,7 +1375,6 @@ pub const Inst = struct {...@@ -1346,7 +1375,6 @@ pub const Inst = struct {
1346 .array_type,1375 .array_type,
1347 .array_type_sentinel,1376 .array_type_sentinel,
1348 .vector_type,1377 .vector_type,
1349 .elem_type_index,
1350 .elem_type,1378 .elem_type,
1351 .indexable_ptr_elem_type,1379 .indexable_ptr_elem_type,
1352 .vector_elem_type,1380 .vector_elem_type,
...@@ -1374,7 +1402,6 @@ pub const Inst = struct {...@@ -1374,7 +1402,6 @@ pub const Inst = struct {
1374 .cmp_gte,1402 .cmp_gte,
1375 .cmp_gt,1403 .cmp_gt,
1376 .cmp_neq,1404 .cmp_neq,
1377 .coerce_result_ptr,
1378 .error_set_decl,1405 .error_set_decl,
1379 .error_set_decl_anon,1406 .error_set_decl_anon,
1380 .error_set_decl_func,1407 .error_set_decl_func,
...@@ -1385,11 +1412,9 @@ pub const Inst = struct {...@@ -1385,11 +1412,9 @@ pub const Inst = struct {
1385 .elem_ptr,1412 .elem_ptr,
1386 .elem_val,1413 .elem_val,
1387 .elem_ptr_node,1414 .elem_ptr_node,
1388 .elem_ptr_imm,
1389 .elem_val_node,1415 .elem_val_node,
1390 .elem_val_imm,1416 .elem_val_imm,
1391 .field_ptr,1417 .field_ptr,
1392 .field_ptr_init,
1393 .field_val,1418 .field_val,
1394 .field_ptr_named,1419 .field_ptr_named,
1395 .field_val_named,1420 .field_val_named,
...@@ -1447,19 +1472,7 @@ pub const Inst = struct {...@@ -1447,19 +1472,7 @@ pub const Inst = struct {
1447 .typeof_log2_int_type,1472 .typeof_log2_int_type,
1448 .switch_block,1473 .switch_block,
1449 .switch_block_ref,1474 .switch_block_ref,
1450 .array_base_ptr,
1451 .field_base_ptr,
1452 .struct_init_empty,
1453 .struct_init,
1454 .struct_init_ref,
1455 .struct_init_anon,
1456 .struct_init_anon_ref,
1457 .array_init,
1458 .array_init_anon,
1459 .array_init_ref,
1460 .array_init_anon_ref,
1461 .union_init,1475 .union_init,
1462 .field_type,
1463 .field_type_ref,1476 .field_type_ref,
1464 .enum_from_int,1477 .enum_from_int,
1465 .int_from_enum,1478 .int_from_enum,
...@@ -1546,7 +1559,22 @@ pub const Inst = struct {...@@ -1546,7 +1559,22 @@ pub const Inst = struct {
1546 .for_len,1559 .for_len,
1547 .@"try",1560 .@"try",
1548 .try_ptr,1561 .try_ptr,
1549 .opt_eu_base_ty,1562 .opt_eu_base_ptr_init,
1563 .coerce_ptr_elem_ty,
1564 .struct_init_empty,
1565 .struct_init_empty_result,
1566 .struct_init_empty_ref_result,
1567 .struct_init_anon,
1568 .struct_init,
1569 .struct_init_ref,
1570 .struct_init_field_type,
1571 .struct_init_field_ptr,
1572 .array_init_anon,
1573 .array_init,
1574 .array_init_ref,
1575 .validate_array_init_ref_ty,
1576 .array_init_elem_type,
1577 .array_init_elem_ptr,
1550 => false,1578 => false,
15511579
1552 .extended => switch (data.extended.opcode) {1580 .extended => switch (data.extended.opcode) {
...@@ -1580,7 +1608,6 @@ pub const Inst = struct {...@@ -1580,7 +1608,6 @@ pub const Inst = struct {
1580 .array_type = .pl_node,1608 .array_type = .pl_node,
1581 .array_type_sentinel = .pl_node,1609 .array_type_sentinel = .pl_node,
1582 .vector_type = .pl_node,1610 .vector_type = .pl_node,
1583 .elem_type_index = .bin,
1584 .elem_type = .un_node,1611 .elem_type = .un_node,
1585 .indexable_ptr_elem_type = .un_node,1612 .indexable_ptr_elem_type = .un_node,
1586 .vector_elem_type = .un_node,1613 .vector_elem_type = .un_node,
...@@ -1612,7 +1639,6 @@ pub const Inst = struct {...@@ -1612,7 +1639,6 @@ pub const Inst = struct {
1612 .cmp_gte = .pl_node,1639 .cmp_gte = .pl_node,
1613 .cmp_gt = .pl_node,1640 .cmp_gt = .pl_node,
1614 .cmp_neq = .pl_node,1641 .cmp_neq = .pl_node,
1615 .coerce_result_ptr = .pl_node,
1616 .condbr = .pl_node,1642 .condbr = .pl_node,
1617 .condbr_inline = .pl_node,1643 .condbr_inline = .pl_node,
1618 .@"try" = .pl_node,1644 .@"try" = .pl_node,
...@@ -1631,7 +1657,6 @@ pub const Inst = struct {...@@ -1631,7 +1657,6 @@ pub const Inst = struct {
1631 .div = .pl_node,1657 .div = .pl_node,
1632 .elem_ptr = .pl_node,1658 .elem_ptr = .pl_node,
1633 .elem_ptr_node = .pl_node,1659 .elem_ptr_node = .pl_node,
1634 .elem_ptr_imm = .pl_node,
1635 .elem_val = .pl_node,1660 .elem_val = .pl_node,
1636 .elem_val_node = .pl_node,1661 .elem_val_node = .pl_node,
1637 .elem_val_imm = .elem_val_imm,1662 .elem_val_imm = .elem_val_imm,
...@@ -1643,7 +1668,6 @@ pub const Inst = struct {...@@ -1643,7 +1668,6 @@ pub const Inst = struct {
1643 .@"export" = .pl_node,1668 .@"export" = .pl_node,
1644 .export_value = .pl_node,1669 .export_value = .pl_node,
1645 .field_ptr = .pl_node,1670 .field_ptr = .pl_node,
1646 .field_ptr_init = .pl_node,
1647 .field_val = .pl_node,1671 .field_val = .pl_node,
1648 .field_ptr_named = .pl_node,1672 .field_ptr_named = .pl_node,
1649 .field_val_named = .pl_node,1673 .field_val_named = .pl_node,
...@@ -1701,30 +1725,16 @@ pub const Inst = struct {...@@ -1701,30 +1725,16 @@ pub const Inst = struct {
1701 .enum_literal = .str_tok,1725 .enum_literal = .str_tok,
1702 .switch_block = .pl_node,1726 .switch_block = .pl_node,
1703 .switch_block_ref = .pl_node,1727 .switch_block_ref = .pl_node,
1704 .array_base_ptr = .un_node,
1705 .field_base_ptr = .un_node,
1706 .opt_eu_base_ty = .un_node,
1707 .validate_array_init_ty = .pl_node,
1708 .validate_struct_init_ty = .un_node,
1709 .validate_struct_init = .pl_node,
1710 .validate_array_init = .pl_node,
1711 .validate_deref = .un_node,1728 .validate_deref = .un_node,
1712 .validate_destructure = .pl_node,1729 .validate_destructure = .pl_node,
1713 .struct_init_empty = .un_node,
1714 .field_type = .pl_node,
1715 .field_type_ref = .pl_node,1730 .field_type_ref = .pl_node,
1716 .struct_init = .pl_node,
1717 .struct_init_ref = .pl_node,
1718 .struct_init_anon = .pl_node,
1719 .struct_init_anon_ref = .pl_node,
1720 .array_init = .pl_node,
1721 .array_init_anon = .pl_node,
1722 .array_init_ref = .pl_node,
1723 .array_init_anon_ref = .pl_node,
1724 .union_init = .pl_node,1731 .union_init = .pl_node,
1725 .type_info = .un_node,1732 .type_info = .un_node,
1726 .size_of = .un_node,1733 .size_of = .un_node,
1727 .bit_size_of = .un_node,1734 .bit_size_of = .un_node,
1735 .opt_eu_base_ptr_init = .un_node,
1736 .coerce_ptr_elem_ty = .pl_node,
1737 .validate_ref_ty = .un_tok,
17281738
1729 .int_from_ptr = .un_node,1739 .int_from_ptr = .un_node,
1730 .compile_error = .un_node,1740 .compile_error = .un_node,
...@@ -1826,6 +1836,27 @@ pub const Inst = struct {...@@ -1826,6 +1836,27 @@ pub const Inst = struct {
1826 .save_err_ret_index = .save_err_ret_index,1836 .save_err_ret_index = .save_err_ret_index,
1827 .restore_err_ret_index = .restore_err_ret_index,1837 .restore_err_ret_index = .restore_err_ret_index,
18281838
1839 .struct_init_empty = .un_node,
1840 .struct_init_empty_result = .un_node,
1841 .struct_init_empty_ref_result = .un_node,
1842 .struct_init_anon = .pl_node,
1843 .struct_init = .pl_node,
1844 .struct_init_ref = .pl_node,
1845 .validate_struct_init_ty = .un_node,
1846 .validate_struct_init_result_ty = .un_node,
1847 .validate_ptr_struct_init = .pl_node,
1848 .struct_init_field_type = .pl_node,
1849 .struct_init_field_ptr = .pl_node,
1850 .array_init_anon = .pl_node,
1851 .array_init = .pl_node,
1852 .array_init_ref = .pl_node,
1853 .validate_array_init_ty = .pl_node,
1854 .validate_array_init_result_ty = .pl_node,
1855 .validate_array_init_ref_ty = .pl_node,
1856 .validate_ptr_array_init = .pl_node,
1857 .array_init_elem_type = .bin,
1858 .array_init_elem_ptr = .pl_node,
1859
1829 .extended = .extended,1860 .extended = .extended,
1830 });1861 });
1831 };1862 };
...@@ -2771,6 +2802,11 @@ pub const Inst = struct {...@@ -2771,6 +2802,11 @@ pub const Inst = struct {
2771 };2802 };
2772 };2803 };
27732804
2805 pub const ArrayInitRefTy = struct {
2806 ptr_ty: Ref,
2807 elem_count: u32,
2808 };
2809
2774 pub const Field = struct {2810 pub const Field = struct {
2775 lhs: Ref,2811 lhs: Ref,
2776 /// Offset into `string_bytes`.2812 /// Offset into `string_bytes`.
...@@ -3064,9 +3100,10 @@ pub const Inst = struct {...@@ -3064,9 +3100,10 @@ pub const Inst = struct {
3064 fields_len: u32,3100 fields_len: u32,
30653101
3066 pub const Item = struct {3102 pub const Item = struct {
3067 /// The `field_type` ZIR instruction for this field init.3103 /// The `struct_init_field_type` ZIR instruction for this field init.
3068 field_type: Index,3104 field_type: Index,
3069 /// The field init expression to be used as the field value.3105 /// The field init expression to be used as the field value. This value will be coerced
3106 /// to the field type if not already.
3070 init: Ref,3107 init: Ref,
3071 };3108 };
3072 };3109 };
src/print_zir.zig+110-31
...@@ -130,6 +130,63 @@ const Writer = struct {...@@ -130,6 +130,63 @@ const Writer = struct {
130 recurse_decls: bool,130 recurse_decls: bool,
131 recurse_blocks: bool,131 recurse_blocks: bool,
132132
133 /// Using `std.zig.findLineColumn` whenever we need to resolve a source location makes ZIR
134 /// printing O(N^2), which can have drastic effects - taking a ZIR dump from a few seconds to
135 /// many minutes. Since we're usually resolving source locations close to one another,
136 /// preserving state across source location resolutions speeds things up a lot.
137 line_col_cursor: struct {
138 line: usize = 0,
139 column: usize = 0,
140 line_start: usize = 0,
141 off: usize = 0,
142
143 fn find(cur: *@This(), source: []const u8, want_offset: usize) std.zig.Loc {
144 if (want_offset < cur.off) {
145 // Go back to the start of this line
146 cur.off = cur.line_start;
147 cur.column = 0;
148
149 while (want_offset < cur.off) {
150 // Go back to the newline
151 cur.off -= 1;
152
153 // Seek to the start of the previous line
154 while (cur.off > 0 and source[cur.off - 1] != '\n') {
155 cur.off -= 1;
156 }
157 cur.line_start = cur.off;
158 cur.line -= 1;
159 }
160 }
161
162 // The cursor is now positioned before `want_offset`.
163 // Seek forward as in `std.zig.findLineColumn`.
164
165 while (cur.off < want_offset) : (cur.off += 1) {
166 switch (source[cur.off]) {
167 '\n' => {
168 cur.line += 1;
169 cur.column = 0;
170 cur.line_start = cur.off + 1;
171 },
172 else => {
173 cur.column += 1;
174 },
175 }
176 }
177
178 while (cur.off < source.len and source[cur.off] != '\n') {
179 cur.off += 1;
180 }
181
182 return .{
183 .line = cur.line,
184 .column = cur.column,
185 .source_line = source[cur.line_start..cur.off],
186 };
187 }
188 } = .{},
189
133 fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index {190 fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index {
134 return @as(Ast.Node.Index, @bitCast(offset + @as(i32, @bitCast(self.parent_decl_node))));191 return @as(Ast.Node.Index, @bitCast(offset + @as(i32, @bitCast(self.parent_decl_node))));
135 }192 }
...@@ -148,8 +205,6 @@ const Writer = struct {...@@ -148,8 +205,6 @@ const Writer = struct {
148 .store_to_inferred_ptr,205 .store_to_inferred_ptr,
149 => try self.writeBin(stream, inst),206 => try self.writeBin(stream, inst),
150207
151 .elem_type_index => try self.writeElemTypeIndex(stream, inst),
152
153 .alloc,208 .alloc,
154 .alloc_mut,209 .alloc_mut,
155 .alloc_comptime_mut,210 .alloc_comptime_mut,
...@@ -184,7 +239,6 @@ const Writer = struct {...@@ -184,7 +239,6 @@ const Writer = struct {
184 .is_non_err_ptr,239 .is_non_err_ptr,
185 .ret_is_non_err,240 .ret_is_non_err,
186 .typeof,241 .typeof,
187 .struct_init_empty,
188 .type_info,242 .type_info,
189 .size_of,243 .size_of,
190 .bit_size_of,244 .bit_size_of,
...@@ -224,18 +278,16 @@ const Writer = struct {...@@ -224,18 +278,16 @@ const Writer = struct {
224 .bit_reverse,278 .bit_reverse,
225 .@"resume",279 .@"resume",
226 .@"await",280 .@"await",
227 .array_base_ptr,
228 .field_base_ptr,
229 .validate_struct_init_ty,
230 .make_ptr_const,281 .make_ptr_const,
231 .validate_deref,282 .validate_deref,
232 .check_comptime_control_flow,283 .check_comptime_control_flow,
233 .opt_eu_base_ty,284 .opt_eu_base_ptr_init,
234 => try self.writeUnNode(stream, inst),285 => try self.writeUnNode(stream, inst),
235286
236 .ref,287 .ref,
237 .ret_implicit,288 .ret_implicit,
238 .closure_capture,289 .closure_capture,
290 .validate_ref_ty,
239 => try self.writeUnTok(stream, inst),291 => try self.writeUnTok(stream, inst),
240292
241 .bool_br_and,293 .bool_br_and,
...@@ -243,7 +295,6 @@ const Writer = struct {...@@ -243,7 +295,6 @@ const Writer = struct {
243 => try self.writeBoolBr(stream, inst),295 => try self.writeBoolBr(stream, inst),
244296
245 .validate_destructure => try self.writeValidateDestructure(stream, inst),297 .validate_destructure => try self.writeValidateDestructure(stream, inst),
246 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
247 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),298 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
248 .ptr_type => try self.writePtrType(stream, inst),299 .ptr_type => try self.writePtrType(stream, inst),
249 .int => try self.writeInt(stream, inst),300 .int => try self.writeInt(stream, inst),
...@@ -259,12 +310,6 @@ const Writer = struct {...@@ -259,12 +310,6 @@ const Writer = struct {
259 .@"break",310 .@"break",
260 .break_inline,311 .break_inline,
261 => try self.writeBreak(stream, inst),312 => try self.writeBreak(stream, inst),
262 .array_init,
263 .array_init_ref,
264 => try self.writeArrayInit(stream, inst),
265 .array_init_anon,
266 .array_init_anon_ref,
267 => try self.writeArrayInitAnon(stream, inst),
268313
269 .slice_start => try self.writeSliceStart(stream, inst),314 .slice_start => try self.writeSliceStart(stream, inst),
270 .slice_end => try self.writeSliceEnd(stream, inst),315 .slice_end => try self.writeSliceEnd(stream, inst),
...@@ -273,10 +318,44 @@ const Writer = struct {...@@ -273,10 +318,44 @@ const Writer = struct {
273318
274 .union_init => try self.writeUnionInit(stream, inst),319 .union_init => try self.writeUnionInit(stream, inst),
275320
321 // Struct inits
322
323 .struct_init_empty,
324 .struct_init_empty_result,
325 .struct_init_empty_ref_result,
326 => try self.writeUnNode(stream, inst),
327
328 .struct_init_anon => try self.writeStructInitAnon(stream, inst),
329
276 .struct_init,330 .struct_init,
277 .struct_init_ref,331 .struct_init_ref,
278 => try self.writeStructInit(stream, inst),332 => try self.writeStructInit(stream, inst),
279333
334 .validate_struct_init_ty,
335 .validate_struct_init_result_ty,
336 => try self.writeUnNode(stream, inst),
337
338 .validate_ptr_struct_init => try self.writeBlock(stream, inst),
339 .struct_init_field_type => try self.writeStructInitFieldType(stream, inst),
340 .struct_init_field_ptr => try self.writePlNodeField(stream, inst),
341
342 // Array inits
343
344 .array_init_anon => try self.writeArrayInitAnon(stream, inst),
345
346 .array_init,
347 .array_init_ref,
348 => try self.writeArrayInit(stream, inst),
349
350 .validate_array_init_ty,
351 .validate_array_init_result_ty,
352 => try self.writeValidateArrayInitTy(stream, inst),
353
354 .validate_array_init_ref_ty => try self.writeValidateArrayInitRefTy(stream, inst),
355 .validate_ptr_array_init => try self.writeBlock(stream, inst),
356 .array_init_elem_type => try self.writeArrayInitElemType(stream, inst),
357 .array_init_elem_ptr => try self.writeArrayInitElemPtr(stream, inst),
358
280 .atomic_load => try self.writeAtomicLoad(stream, inst),359 .atomic_load => try self.writeAtomicLoad(stream, inst),
281 .atomic_store => try self.writeAtomicStore(stream, inst),360 .atomic_store => try self.writeAtomicStore(stream, inst),
282 .atomic_rmw => try self.writeAtomicRmw(stream, inst),361 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
...@@ -285,11 +364,6 @@ const Writer = struct {...@@ -285,11 +364,6 @@ const Writer = struct {
285 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst),364 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst),
286 .builtin_call => try self.writeBuiltinCall(stream, inst),365 .builtin_call => try self.writeBuiltinCall(stream, inst),
287366
288 .struct_init_anon,
289 .struct_init_anon_ref,
290 => try self.writeStructInitAnon(stream, inst),
291
292 .field_type => try self.writeFieldType(stream, inst),
293 .field_type_ref => try self.writeFieldTypeRef(stream, inst),367 .field_type_ref => try self.writeFieldTypeRef(stream, inst),
294368
295 .add,369 .add,
...@@ -352,16 +426,14 @@ const Writer = struct {...@@ -352,16 +426,14 @@ const Writer = struct {
352 .elem_val_node,426 .elem_val_node,
353 .elem_ptr,427 .elem_ptr,
354 .elem_val,428 .elem_val,
355 .coerce_result_ptr,
356 .array_type,429 .array_type,
430 .coerce_ptr_elem_ty,
357 => try self.writePlNodeBin(stream, inst),431 => try self.writePlNodeBin(stream, inst),
358432
359 .for_len => try self.writePlNodeMultiOp(stream, inst),433 .for_len => try self.writePlNodeMultiOp(stream, inst),
360434
361 .elem_val_imm => try self.writeElemValImm(stream, inst),435 .elem_val_imm => try self.writeElemValImm(stream, inst),
362436
363 .elem_ptr_imm => try self.writeElemPtrImm(stream, inst),
364
365 .@"export" => try self.writePlNodeExport(stream, inst),437 .@"export" => try self.writePlNodeExport(stream, inst),
366 .export_value => try self.writePlNodeExportValue(stream, inst),438 .export_value => try self.writePlNodeExportValue(stream, inst),
367439
...@@ -373,8 +445,6 @@ const Writer = struct {...@@ -373,8 +445,6 @@ const Writer = struct {
373 .block_inline,445 .block_inline,
374 .suspend_block,446 .suspend_block,
375 .loop,447 .loop,
376 .validate_struct_init,
377 .validate_array_init,
378 .c_import,448 .c_import,
379 .typeof_builtin,449 .typeof_builtin,
380 => try self.writeBlock(stream, inst),450 => try self.writeBlock(stream, inst),
...@@ -395,9 +465,8 @@ const Writer = struct {...@@ -395,9 +465,8 @@ const Writer = struct {
395 .switch_block_ref,465 .switch_block_ref,
396 => try self.writeSwitchBlock(stream, inst),466 => try self.writeSwitchBlock(stream, inst),
397467
398 .field_ptr,
399 .field_ptr_init,
400 .field_val,468 .field_val,
469 .field_ptr,
401 => try self.writePlNodeField(stream, inst),470 => try self.writePlNodeField(stream, inst),
402471
403 .field_ptr_named,472 .field_ptr_named,
...@@ -560,7 +629,7 @@ const Writer = struct {...@@ -560,7 +629,7 @@ const Writer = struct {
560 try stream.writeByte(')');629 try stream.writeByte(')');
561 }630 }
562631
563 fn writeElemTypeIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {632 fn writeArrayInitElemType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
564 const inst_data = self.code.instructions.items(.data)[inst].bin;633 const inst_data = self.code.instructions.items(.data)[inst].bin;
565 try self.writeInstRef(stream, inst_data.lhs);634 try self.writeInstRef(stream, inst_data.lhs);
566 try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});635 try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});
...@@ -915,7 +984,7 @@ const Writer = struct {...@@ -915,7 +984,7 @@ const Writer = struct {
915 try stream.print(", {d})", .{inst_data.idx});984 try stream.print(", {d})", .{inst_data.idx});
916 }985 }
917986
918 fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {987 fn writeArrayInitElemPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
919 const inst_data = self.code.instructions.items(.data)[inst].pl_node;988 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
920 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;989 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
921990
...@@ -947,6 +1016,16 @@ const Writer = struct {...@@ -947,6 +1016,16 @@ const Writer = struct {
947 try self.writeSrc(stream, inst_data.src());1016 try self.writeSrc(stream, inst_data.src());
948 }1017 }
9491018
1019 fn writeValidateArrayInitRefTy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1020 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1021 const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data;
1022
1023 try self.writeInstRef(stream, extra.ptr_ty);
1024 try stream.writeAll(", ");
1025 try stream.print(", {}) ", .{extra.elem_count});
1026 try self.writeSrc(stream, inst_data.src());
1027 }
1028
950 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {1029 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
951 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1030 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
952 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);1031 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
...@@ -1077,7 +1156,7 @@ const Writer = struct {...@@ -1077,7 +1156,7 @@ const Writer = struct {
1077 try self.writeSrc(stream, inst_data.src());1156 try self.writeSrc(stream, inst_data.src());
1078 }1157 }
10791158
1080 fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {1159 fn writeStructInitFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1081 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1160 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1082 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;1161 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
1083 try self.writeInstRef(stream, extra.container_type);1162 try self.writeInstRef(stream, extra.container_type);
...@@ -2590,8 +2669,8 @@ const Writer = struct {...@@ -2590,8 +2669,8 @@ const Writer = struct {
2590 .lazy = src,2669 .lazy = src,
2591 };2670 };
2592 const src_span = src_loc.span(self.gpa) catch unreachable;2671 const src_span = src_loc.span(self.gpa) catch unreachable;
2593 const start = std.zig.findLineColumn(tree.source, src_span.start);2672 const start = self.line_col_cursor.find(tree.source, src_span.start);
2594 const end = std.zig.findLineColumn(tree.source, src_span.end);2673 const end = self.line_col_cursor.find(tree.source, src_span.end);
2595 try stream.print("{s}:{d}:{d} to :{d}:{d}", .{2674 try stream.print("{s}:{d}:{d} to :{d}:{d}", .{
2596 @tagName(src), start.line + 1, start.column + 1,2675 @tagName(src), start.line + 1, start.column + 1,
2597 end.line + 1, end.column + 1,2676 end.line + 1, end.column + 1,
src/type.zig+11
...@@ -3182,6 +3182,17 @@ pub const Type = struct {...@@ -3182,6 +3182,17 @@ pub const Type = struct {
3182 };3182 };
3183 }3183 }
31843184
3185 /// Traverses optional child types and error union payloads until the type
3186 /// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
3187 pub fn optEuBaseType(ty: Type, mod: *Module) Type {
3188 var cur = ty;
3189 while (true) switch (cur.zigTypeTag(mod)) {
3190 .Optional => cur = cur.optionalChild(mod),
3191 .ErrorUnion => cur = cur.errorUnionPayload(mod),
3192 else => return cur,
3193 };
3194 }
3195
3185 pub const @"u1": Type = .{ .ip_index = .u1_type };3196 pub const @"u1": Type = .{ .ip_index = .u1_type };
3186 pub const @"u8": Type = .{ .ip_index = .u8_type };3197 pub const @"u8": Type = .{ .ip_index = .u8_type };
3187 pub const @"u16": Type = .{ .ip_index = .u16_type };3198 pub const @"u16": Type = .{ .ip_index = .u16_type };
test/behavior/array.zig+34
...@@ -780,3 +780,37 @@ test "runtime side-effects in comptime-known array init" {...@@ -780,3 +780,37 @@ test "runtime side-effects in comptime-known array init" {
780 try expectEqual([4]u4{ 1, 2, 4, 8 }, init);780 try expectEqual([4]u4{ 1, 2, 4, 8 }, init);
781 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);781 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
782}782}
783
784test "slice initialized through reference to anonymous array init provides result types" {
785 var my_u32: u32 = 123;
786 var my_u64: u64 = 456;
787 const foo: []const u16 = &.{
788 @intCast(my_u32),
789 @intCast(my_u64),
790 @truncate(my_u32),
791 @truncate(my_u64),
792 };
793 try std.testing.expectEqualSlices(u16, &.{ 123, 456, 123, 456 }, foo);
794}
795
796test "pointer to array initialized through reference to anonymous array init provides result types" {
797 var my_u32: u32 = 123;
798 var my_u64: u64 = 456;
799 const foo: *const [4]u16 = &.{
800 @intCast(my_u32),
801 @intCast(my_u64),
802 @truncate(my_u32),
803 @truncate(my_u64),
804 };
805 try std.testing.expectEqualSlices(u16, &.{ 123, 456, 123, 456 }, foo);
806}
807
808test "tuple initialized through reference to anonymous array init provides result types" {
809 const Tuple = struct { u64, *const u32 };
810 const foo: *const Tuple = &.{
811 @intCast(12345),
812 @ptrFromInt(0x1000),
813 };
814 try expect(foo[0] == 12345);
815 try expect(@intFromPtr(foo[1]) == 0x1000);
816}
test/behavior/bugs/12776.zig+1
...@@ -29,6 +29,7 @@ const CPU = packed struct {...@@ -29,6 +29,7 @@ const CPU = packed struct {
29};29};
3030
31test {31test {
32 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
test/behavior/bugs/13664.zig+1
...@@ -17,6 +17,7 @@ test {...@@ -17,6 +17,7 @@ test {
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2021
21 const timestamp: i64 = value();22 const timestamp: i64 = value();
22 const id = ID{ .fields = Fields{23 const id = ID{ .fields = Fields{
test/behavior/cast.zig+26
...@@ -2493,3 +2493,29 @@ test "@as does not corrupt values with incompatible representations" {...@@ -2493,3 +2493,29 @@ test "@as does not corrupt values with incompatible representations" {
2493 });2493 });
2494 try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001);2494 try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001);
2495}2495}
2496
2497test "result information is preserved through many nested structures" {
2498 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2500 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2501 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2502 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2503 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2504
2505 const S = struct {
2506 fn doTheTest() !void {
2507 const E = error{Foo};
2508 const T = *const ?E!struct { x: ?*const E!?u8 };
2509
2510 var val: T = &.{ .x = &@truncate(0x1234) };
2511
2512 const struct_val = val.*.? catch unreachable;
2513 const int_val = (struct_val.x.?.* catch unreachable).?;
2514
2515 try expect(int_val == 0x34);
2516 }
2517 };
2518
2519 try S.doTheTest();
2520 try comptime S.doTheTest();
2521}
test/behavior/pointers.zig+18
...@@ -548,3 +548,21 @@ test "pointer to array has explicit alignment" {...@@ -548,3 +548,21 @@ test "pointer to array has explicit alignment" {
548 const casted = S.func(&bases);548 const casted = S.func(&bases);
549 try expect(casted[0].a == 2);549 try expect(casted[0].a == 2);
550}550}
551
552test "result type preserved through multiple references" {
553 const S = struct { x: u32 };
554 var my_u64: u64 = 12345;
555 const foo: *const *const *const S = &&&.{
556 .x = @intCast(my_u64),
557 };
558 try expect(foo.*.*.*.x == 12345);
559}
560
561test "result type found through optional pointer" {
562 const ptr1: ?*const u32 = &@intCast(123);
563 const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) };
564 try expect(ptr1.?.* == 123);
565 try expect(ptr2.?.len == 2);
566 try expect(ptr2.?[0] == 123);
567 try expect(ptr2.?[1] == 0xCD);
568}
test/behavior/struct.zig+15
...@@ -1760,3 +1760,18 @@ test "runtime side-effects in comptime-known struct init" {...@@ -1760,3 +1760,18 @@ test "runtime side-effects in comptime-known struct init" {
1760 try expectEqual(S{ .a = 1, .b = 2, .c = 4, .d = 8 }, init);1760 try expectEqual(S{ .a = 1, .b = 2, .c = 4, .d = 8 }, init);
1761 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);1761 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
1762}1762}
1763
1764test "pointer to struct initialized through reference to anonymous initializer provides result types" {
1765 const S = struct { a: u8, b: u16, c: *const anyopaque };
1766 var my_u16: u16 = 0xABCD;
1767 const s: *const S = &.{
1768 // intentionally out of order
1769 .c = @ptrCast("hello"),
1770 .b = my_u16,
1771 .a = @truncate(my_u16),
1772 };
1773 try expect(s.a == 0xCD);
1774 try expect(s.b == 0xABCD);
1775 const str: *const [5]u8 = @ptrCast(s.c);
1776 try std.testing.expectEqualSlices(u8, "hello", str);
1777}
test/cases/compile_errors/anytype_param_requires_comptime.zig+2-4
...@@ -16,7 +16,5 @@ pub export fn entry() void {...@@ -16,7 +16,5 @@ pub export fn entry() void {
16// backend=stage216// backend=stage2
17// target=native17// target=native
18//18//
19// :7:14: error: runtime-known argument passed to parameter of comptime-only type19// :7:25: error: unable to resolve comptime value
20// :9:12: note: declared here20// :7:25: note: initializer of comptime only struct must be comptime-known
21// :4:16: note: struct requires comptime because of this field
22// :4:16: note: types are not available at runtime
test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig+3-3
...@@ -18,6 +18,6 @@ export fn entry() void {...@@ -18,6 +18,6 @@ export fn entry() void {
18// backend=stage218// backend=stage2
19// target=native19// target=native
20//20//
21// :11:27: error: expected type 'u8', found '?u8'21// :11:20: error: expected type 'u8', found '?u8'
22// :11:27: note: cannot convert optional to payload type22// :11:20: note: cannot convert optional to payload type
23// :11:27: note: consider using '.?', 'orelse', or 'if'23// :11:20: note: consider using '.?', 'orelse', or 'if'
test/cases/compile_errors/cast_without_result_type_due_to_anyopaque_pointer.zig created+21
...@@ -0,0 +1,21 @@
1export fn foo() void {
2 const x: *const anyopaque = &@intCast(123);
3 _ = x;
4}
5export fn bar() void {
6 const x: *const anyopaque = &.{
7 .x = @intCast(123),
8 };
9 _ = x;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :2:34: error: @intCast must have a known result type
17// :2:34: note: result type is unknown due to opaque pointer type
18// :2:34: note: use @as to provide explicit result type
19// :7:14: error: @intCast must have a known result type
20// :6:35: note: result type is unknown due to opaque pointer type
21// :7:14: note: use @as to provide explicit result type
test/cases/compile_errors/cast_without_result_type_due_to_generic_parameter.zig+12-4
...@@ -10,6 +10,11 @@ export fn c() void {...@@ -10,6 +10,11 @@ export fn c() void {
10export fn d() void {10export fn d() void {
11 bar(@floatFromInt(123));11 bar(@floatFromInt(123));
12}12}
13export fn f() void {
14 bar(.{
15 .x = @intCast(123),
16 });
17}
1318
14fn bar(_: anytype) void {}19fn bar(_: anytype) void {}
1520
...@@ -18,14 +23,17 @@ fn bar(_: anytype) void {}...@@ -18,14 +23,17 @@ fn bar(_: anytype) void {}
18// target=native23// target=native
19//24//
20// :2:9: error: @ptrFromInt must have a known result type25// :2:9: error: @ptrFromInt must have a known result type
21// :2:9: note: result type is unknown due to anytype parameter26// :2:8: note: result type is unknown due to anytype parameter
22// :2:9: note: use @as to provide explicit result type27// :2:9: note: use @as to provide explicit result type
23// :5:9: error: @ptrCast must have a known result type28// :5:9: error: @ptrCast must have a known result type
24// :5:9: note: result type is unknown due to anytype parameter29// :5:8: note: result type is unknown due to anytype parameter
25// :5:9: note: use @as to provide explicit result type30// :5:9: note: use @as to provide explicit result type
26// :8:9: error: @intCast must have a known result type31// :8:9: error: @intCast must have a known result type
27// :8:9: note: result type is unknown due to anytype parameter32// :8:8: note: result type is unknown due to anytype parameter
28// :8:9: note: use @as to provide explicit result type33// :8:9: note: use @as to provide explicit result type
29// :11:9: error: @floatFromInt must have a known result type34// :11:9: error: @floatFromInt must have a known result type
30// :11:9: note: result type is unknown due to anytype parameter35// :11:8: note: result type is unknown due to anytype parameter
31// :11:9: note: use @as to provide explicit result type36// :11:9: note: use @as to provide explicit result type
37// :15:14: error: @intCast must have a known result type
38// :14:8: note: result type is unknown due to anytype parameter
39// :15:14: note: use @as to provide explicit result type
test/cases/compile_errors/for_invalid_ranges.zig+2-1
...@@ -31,5 +31,6 @@ export fn e() void {...@@ -31,5 +31,6 @@ export fn e() void {
31// :2:13: error: expected type 'usize', found '*const [5:0]u8'31// :2:13: error: expected type 'usize', found '*const [5:0]u8'
32// :7:10: error: type 'usize' cannot represent integer value '-1'32// :7:10: error: type 'usize' cannot represent integer value '-1'
33// :12:10: error: expected type 'usize', found '*const [5:0]u8'33// :12:10: error: expected type 'usize', found '*const [5:0]u8'
34// :17:13: error: expected type 'usize', found '*const struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}'34// :17:13: error: expected type 'usize', found pointer
35// :17:13: note: address-of operator always returns a pointer
35// :22:20: error: overflow of integer type 'usize' with value '-1'36// :22:20: error: overflow of integer type 'usize' with value '-1'
test/cases/compile_errors/invalid_store_to_comptime_field.zig+5-4
...@@ -71,8 +71,8 @@ pub export fn entry8() void {...@@ -71,8 +71,8 @@ pub export fn entry8() void {
71// target=native71// target=native
72// backend=stage272// backend=stage2
73//73//
74// :6:19: error: value stored in comptime field does not match the default value of the field74// :6:9: error: value stored in comptime field does not match the default value of the field
75// :14:19: error: value stored in comptime field does not match the default value of the field75// :14:9: error: value stored in comptime field does not match the default value of the field
76// :19:38: error: value stored in comptime field does not match the default value of the field76// :19:38: error: value stored in comptime field does not match the default value of the field
77// :31:19: error: value stored in comptime field does not match the default value of the field77// :31:19: error: value stored in comptime field does not match the default value of the field
78// :25:29: note: default value set here78// :25:29: note: default value set here
...@@ -80,5 +80,6 @@ pub export fn entry8() void {...@@ -80,5 +80,6 @@ pub export fn entry8() void {
80// :35:29: note: default value set here80// :35:29: note: default value set here
81// :45:12: error: value stored in comptime field does not match the default value of the field81// :45:12: error: value stored in comptime field does not match the default value of the field
82// :53:25: error: value stored in comptime field does not match the default value of the field82// :53:25: error: value stored in comptime field does not match the default value of the field
83// :66:43: error: value stored in comptime field does not match the default value of the field83// :66:36: error: value stored in comptime field does not match the default value of the field
84// :59:35: error: value stored in comptime field does not match the default value of the field84// :59:30: error: value stored in comptime field does not match the default value of the field
85// :57:29: note: default value set here
test/cases/compile_errors/missing_const_in_slice_with_nested_array_type.zig+1-1
...@@ -15,4 +15,4 @@ export fn entry() void {...@@ -15,4 +15,4 @@ export fn entry() void {
15// backend=llvm15// backend=llvm
16// target=native16// target=native
17//17//
18// :4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'18// :4:26: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
test/cases/compile_errors/missing_else_clause.zig+3-1
...@@ -39,4 +39,6 @@ export fn entry() void {...@@ -39,4 +39,6 @@ export fn entry() void {
39// :8:25: note: type 'i32' here39// :8:25: note: type 'i32' here
40// :16:16: error: expected type 'tmp.h.T', found 'void'40// :16:16: error: expected type 'tmp.h.T', found 'void'
41// :15:15: note: struct declared here41// :15:15: note: struct declared here
42// :22:9: error: incompatible types: 'void' and 'tmp.k.T'42// :22:13: error: incompatible types: 'void' and 'tmp.k.T'
43// :22:25: note: type 'void' here
44// :24:13: note: type 'tmp.k.T' here
test/cases/compile_errors/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig+3-3
...@@ -16,9 +16,9 @@ comptime {...@@ -16,9 +16,9 @@ comptime {
16// backend=stage216// backend=stage2
17// target=native17// target=native
18//18//
19// :2:29: error: expected type '[][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'19// :2:29: error: expected type '[][]const u8', found '*const [2][]const u8'
20// :2:29: note: cast discards const qualifier20// :2:29: note: cast discards const qualifier
21// :6:31: error: expected type '*[2][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}'21// :6:31: error: expected type '*[2][]const u8', found '*const [2][]const u8'
22// :6:31: note: cast discards const qualifier22// :6:31: note: cast discards const qualifier
23// :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}'23// :11:19: error: expected type '*tmp.S', found '*const tmp.S'
24// :11:19: note: cast discards const qualifier24// :11:19: note: cast discards const qualifier
test/cases/compile_errors/reassign_to_array_parameter.zig+1-1
...@@ -9,4 +9,4 @@ export fn entry() void {...@@ -9,4 +9,4 @@ export fn entry() void {
9// backend=llvm9// backend=llvm
10// target=native10// target=native
11//11//
12// :2:15: error: cannot assign to constant12// :2:5: error: cannot assign to constant
test/cases/compile_errors/reassign_to_struct_parameter.zig+1-1
...@@ -12,4 +12,4 @@ export fn entry() void {...@@ -12,4 +12,4 @@ export fn entry() void {
12// backend=stage212// backend=stage2
13// target=native13// target=native
14//14//
15// :5:10: error: cannot assign to constant15// :5:5: error: cannot assign to constant
test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig+3-3
...@@ -18,6 +18,6 @@ export fn entry() void {...@@ -18,6 +18,6 @@ export fn entry() void {
18// backend=stage218// backend=stage2
19// target=native19// target=native
20//20//
21// :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'21// :12:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
22// :12:25: note: cannot convert error union to payload type22// :12:15: note: cannot convert error union to payload type
23// :12:25: note: consider using 'try', 'catch', or 'if'23// :12:15: note: consider using 'try', 'catch', or 'if'
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig+3-3
...@@ -15,6 +15,6 @@ pub const Container = struct {...@@ -15,6 +15,6 @@ pub const Container = struct {
15// backend=stage215// backend=stage2
16// target=native16// target=native
17//17//
18// :3:36: error: expected type 'i32', found '?i32'18// :3:23: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type19// :3:23: note: cannot convert optional to payload type
20// :3:36: note: consider using '.?', 'orelse', or 'if'20// :3:23: note: consider using '.?', 'orelse', or 'if'
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig+3-3
...@@ -15,6 +15,6 @@ pub const Container = struct {...@@ -15,6 +15,6 @@ pub const Container = struct {
15// backend=stage215// backend=stage2
16// target=native16// target=native
17//17//
18// :3:36: error: expected type 'i32', found '?i32'18// :3:23: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type19// :3:23: note: cannot convert optional to payload type
20// :3:36: note: consider using '.?', 'orelse', or 'if'20// :3:23: note: consider using '.?', 'orelse', or 'if'
test/cases/compile_errors/return_incompatible_generic_struct.zig+1
...@@ -18,3 +18,4 @@ export fn entry() void {...@@ -18,3 +18,4 @@ export fn entry() void {
18// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'18// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
19// :5:12: note: struct declared here19// :5:12: note: struct declared here
20// :2:12: note: struct declared here20// :2:12: note: struct declared here
21// :7:11: note: function return type declared here
test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig+2-2
...@@ -12,5 +12,5 @@ export fn f() void {...@@ -12,5 +12,5 @@ export fn f() void {
12// backend=stage212// backend=stage2
13// target=native13// target=native
14//14//
15// :7:29: error: unable to resolve comptime value15// :7:23: error: unable to resolve comptime value
16// :7:29: note: initializer of comptime only struct must be comptime-known16// :7:23: note: initializer of comptime only struct must be comptime-known
test/cases/compile_errors/runtime_assignment_to_comptime_union_type.zig+2-2
...@@ -12,5 +12,5 @@ export fn f() void {...@@ -12,5 +12,5 @@ export fn f() void {
12// backend=stage212// backend=stage2
13// target=native13// target=native
14//14//
15// :7:29: error: unable to resolve comptime value15// :7:23: error: unable to resolve comptime value
16// :7:29: note: initializer of comptime only union must be comptime-known16// :7:23: note: initializer of comptime only union must be comptime-known
test/cases/compile_errors/shift_amount_has_to_be_an_integer_type.zig+2-1
...@@ -7,4 +7,5 @@ export fn entry() void {...@@ -7,4 +7,5 @@ export fn entry() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:20: error: expected type 'comptime_int', found '*const u8'10// :2:20: error: expected type 'comptime_int', found pointer
11// :2:20: note: address-of operator always returns a pointer
test/cases/compile_errors/slice_sentinel_mismatch-1.zig+10-3
...@@ -1,11 +1,18 @@...@@ -1,11 +1,18 @@
1export fn entry() void {1export fn entry1() void {
2 const y: [:1]const u8 = &[_:2]u8{ 1, 2 };2 const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
3 _ = y;3 _ = y;
4}4}
5export fn entry2() void {
6 const x: [:2]const u8 = &.{ 1, 2 };
7 const y: [:1]const u8 = x;
8 _ = y;
9}
510
6// error11// error
7// backend=stage212// backend=stage2
8// target=native13// target=native
9//14//
10// :2:29: error: expected type '[:1]const u8', found '*const [2:2]u8'15// :2:37: error: expected type '[2:1]u8', found '[2:2]u8'
11// :2:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'16// :2:37: note: array sentinel '2' cannot cast into array sentinel '1'
17// :7:29: error: expected type '[:1]const u8', found '[:2]const u8'
18// :7:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
test/cases/compile_errors/union_init_with_none_or_multiple_fields.zig-1
...@@ -28,7 +28,6 @@ export fn u2m() void {...@@ -28,7 +28,6 @@ export fn u2m() void {
28// target=native28// target=native
29//29//
30// :10:20: error: union initializer must initialize one field30// :10:20: error: union initializer must initialize one field
31// :1:12: note: union declared here
32// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field31// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field
33// :14:31: note: additional initializer here32// :14:31: note: additional initializer here
34// :1:12: note: union declared here33// :1:12: note: union declared here
test/cases/compile_errors/union_noreturn_field_initialized.zig+1-1
...@@ -32,7 +32,7 @@ pub export fn entry3() void {...@@ -32,7 +32,7 @@ pub export fn entry3() void {
32// backend=stage232// backend=stage2
33// target=native33// target=native
34//34//
35// :11:21: error: cannot initialize 'noreturn' field of union35// :11:14: error: cannot initialize 'noreturn' field of union
36// :4:9: note: field 'b' declared here36// :4:9: note: field 'b' declared here
37// :2:15: note: union declared here37// :2:15: note: union declared here
38// :19:10: error: cannot initialize 'noreturn' field of union38// :19:10: error: cannot initialize 'noreturn' field of union
test/cases/compile_errors/wrong_types_given_to_export.zig+1-1
...@@ -7,5 +7,5 @@ comptime {...@@ -7,5 +7,5 @@ comptime {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32'10// :3:41: error: expected type 'builtin.GlobalLinkage', found 'u32'
11// :?:?: note: enum declared here11// :?:?: note: enum declared here
test/compile_errors.zig+2-4
...@@ -207,10 +207,8 @@ pub fn addCases(ctx: *Cases) !void {...@@ -207,10 +207,8 @@ pub fn addCases(ctx: *Cases) !void {
207 ":1:38: note: declared comptime here",207 ":1:38: note: declared comptime here",
208 ":8:36: error: runtime-known argument passed to comptime parameter",208 ":8:36: error: runtime-known argument passed to comptime parameter",
209 ":2:41: note: declared comptime here",209 ":2:41: note: declared comptime here",
210 ":13:29: error: runtime-known argument passed to parameter of comptime-only type",210 ":13:32: error: unable to resolve comptime value",
211 ":3:24: note: declared here",211 ":13:32: note: initializer of comptime only struct must be comptime-known",
212 ":12:35: note: struct requires comptime because of this field",
213 ":12:35: note: types are not available at runtime",
214 });212 });
215213
216 case.addSourceFile("import.zig",214 case.addSourceFile("import.zig",
test/tests.zig+5
...@@ -1034,6 +1034,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -1034,6 +1034,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
10341034
1035 these_tests.addIncludePath(.{ .path = "test" });1035 these_tests.addIncludePath(.{ .path = "test" });
10361036
1037 if (test_target.target.getOs().tag == .wasi) {
1038 // WASI's default stack size can be too small for some big tests.
1039 these_tests.stack_size = 2 * 1024 * 1024;
1040 }
1041
1037 const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{1042 const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{
1038 options.name,1043 options.name,
1039 triple_txt,1044 triple_txt,