authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-09-18 14:49:18+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-09-23 22:01:08+01:00
log09a57583a4ccce30603ffc8d0e3d7359dc3cb978
treeaab67cf7749a799ae9b236cd4f26bc9f115b82c5
parent01906a3ad8b792627e55551686c25d02fef64e98
signaturelock-open Commit is signed but in an unrecognized format.

compiler: preserve result type information through address-of operator

This commit introduces the new `ref_coerced_ty` result type into AstGen. This represents a expression which we want to treat as an lvalue, and the pointer will be coerced to a given type. This change gives known result types to many expressions, in particular struct and array initializations. This allows certain casts to work which previously required explicitly specifying types via `@as`. It also eliminates our dependence on anonymous struct types for expressions of the form `&.{ ... }` - this paves the way for #16865, and also results in less Sema magic happening for such initializations, also leading to potentially better runtime code. As part of these changes, this commit also implements #17194 by disallowing RLS on explicitly-typed struct and array initializations. Apologies for linking these changes - it seemed rather pointless to try and separate them, since they both make big changes to struct and array initializations in AstGen. The rationale for this change can be found in the proposal - in essence, performing RLS whilst maintaining the semantics of the intermediary type is a very difficult problem to solve. This allowed the problematic `coerce_result_ptr` ZIR instruction to be completely eliminated, which in turn also simplified the logic for inferred allocations in Sema - thanks to this, we almost break even on line count! In doing this, the ZIR instructions surrounding these initializations have been restructured - some have been added and removed, and others renamed for clarity (and their semantics changed slightly). In order to optimize ZIR tag count, the `struct_init_anon_ref` and `array_init_anon_ref` instructions have been removed in favour of using `ref` on a standard anonymous value initialization, since these instructions are now virtually never used. Lastly, it's worth noting that this commit introduces a slightly strange source of generic poison types: in the expression `@as(*anyopaque, &x)`, the sub-expression `x` has a generic poison result type, despite no generic code being involved. This turns out to be a logical choice, because we don't know the result type for `x`, and the generic poison type represents precisely this case, providing the semantics we need. Resolves: #16512 Resolves: #17194

35 files changed, 1251 insertions(+), 1025 deletions(-)

lib/std/debug.zig+6-1
......@@ -514,7 +514,12 @@ pub const StackIterator = struct {
514514
515515 return StackIterator{
516516 .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 },
518523 };
519524 }
520525
src/AstGen.zig+318-305
......@@ -265,14 +265,17 @@ const ResultInfo = struct {
265265 discard,
266266 /// The expression has an inferred type, and it will be evaluated as an rvalue.
267267 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,
271268 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
272269 ty: Zir.Inst.Ref,
273270 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
274271 /// so no `as` instruction needs to be emitted.
275272 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,
276279 /// The expression must store its result into this typed pointer. The result instruction
277280 /// from the expression must be ignored.
278281 ptr: PtrResultLoc,
......@@ -303,26 +306,30 @@ const ResultInfo = struct {
303306 /// Find the result type for a cast builtin given the result location.
304307 /// If the location does not have a known result type, emits an error on
305308 /// the given node.
306 fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
307 const astgen = gz.astgen;
308 switch (rl) {
309 .discard, .none, .ref, .inferred_ptr => {},
310 .ty, .coerced_ty => |ty_ref| return ty_ref,
309 fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
310 return switch (rl) {
311 .discard, .none, .ref, .inferred_ptr, .destructure => null,
312 .ty, .coerced_ty => |ty_ref| ty_ref,
313 .ref_coerced_ty => |ptr_ty| try gz.addUnNode(.elem_type, ptr_ty, node),
311314 .ptr => |ptr| {
312315 const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);
313 return 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 });
316 return try gz.addUnNode(.elem_type, ptr_ty, node);
320317 },
321 }
318 };
319 }
322320
323 return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
324 try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
325 });
321 fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
322 const astgen = gz.astgen;
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 }
326333 }
327334 };
328335
......@@ -933,7 +940,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
933940 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
934941 _ = try gz.addUnNode(.validate_deref, lhs, node);
935942 switch (ri.rl) {
936 .ref => return lhs,
943 .ref, .ref_coerced_ty => return lhs,
937944 else => {
938945 const result = try gz.addUnNode(.load, lhs, node);
939946 return rvalue(gz, ri, result, node);
......@@ -941,7 +948,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
941948 }
942949 },
943950 .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);
945956 return rvalue(gz, ri, result, node);
946957 },
947958 .optional_type => {
......@@ -950,7 +961,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
950961 return rvalue(gz, ri, result, node);
951962 },
952963 .unwrap_optional => switch (ri.rl) {
953 .ref => {
964 .ref, .ref_coerced_ty => {
954965 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
955966
956967 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
......@@ -1001,7 +1012,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
10011012 else
10021013 null;
10031014 switch (ri.rl) {
1004 .ref => return orelseCatchExpr(
1015 .ref, .ref_coerced_ty => return orelseCatchExpr(
10051016 gz,
10061017 scope,
10071018 ri,
......@@ -1028,7 +1039,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
10281039 }
10291040 },
10301041 .@"orelse" => switch (ri.rl) {
1031 .ref => return orelseCatchExpr(
1042 .ref, .ref_coerced_ty => return orelseCatchExpr(
10321043 gz,
10331044 scope,
10341045 ri,
......@@ -1432,73 +1443,75 @@ fn arrayInitExpr(
14321443 break :inst .{ array_type_inst, .none };
14331444 };
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
14351477 switch (ri.rl) {
1478 .none => return arrayInitExprAnon(gz, scope, node, array_init.ast.elements),
14361479 .discard => {
1437 if (elem_ty != .none) {
1438 const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } };
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 }
1480 for (array_init.ast.elements) |elem_init| {
1481 _ = try expr(gz, scope, .{ .rl = .discard }, elem_init);
14571482 }
14581483 return Zir.Inst.Ref.void_value;
14591484 },
14601485 .ref => {
1461 const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init_ref else .array_init_anon_ref;
1462 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, tag);
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);
1486 const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
1487 return gz.addUnTok(.ref, result, tree.firstToken(node));
14791488 },
1480 .ptr => |ptr_res| {
1481 return arrayInitExprRlPtr(gz, scope, node, ptr_res.inst, array_init.ast.elements, array_ty);
1482 },
1483 .inferred_ptr => |ptr_inst| {
1484 if (array_ty == .none) {
1485 // We treat this case differently so that we don't get a crash when
1486 // analyzing array_base_ptr against an alloc_inferred_mut.
1487 // See corresponding logic in structInitExpr.
1488 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1489 return rvalue(gz, ri, result, node);
1490 } else {
1491 return arrayInitExprRlPtr(gz, scope, node, ptr_inst, array_init.ast.elements, array_ty);
1492 }
1489 .ref_coerced_ty => |ptr_ty_inst| {
1490 const dest_arr_ty_inst = try gz.addPlNode(.validate_array_init_ref_ty, node, Zir.Inst.ArrayInitRefTy{
1491 .ptr_ty = ptr_ty_inst,
1492 .elem_count = @intCast(array_init.ast.elements.len),
1493 });
1494 return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, dest_arr_ty_inst, .none, true);
1495 },
1496 .ty, .coerced_ty => |result_ty_inst| {
1497 _ = try gz.addPlNode(.validate_array_init_result_ty, node, Zir.Inst.ArrayInit{
1498 .ty = result_ty_inst,
1499 .init_count = @intCast(array_init.ast.elements.len),
1500 });
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);
14931513 },
14941514 .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 }
15021515 // Untyped init - destructure directly into result pointers
15031516 if (array_init.ast.elements.len != destructure.components.len) {
15041517 return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{
......@@ -1521,12 +1534,12 @@ fn arrayInitExpr(
15211534 }
15221535}
15231536
1524fn arrayInitExprRlNone(
1537/// An array initialization expression using an `array_init_anon` instruction.
1538fn arrayInitExprAnon(
15251539 gz: *GenZir,
15261540 scope: *Scope,
15271541 node: Ast.Node.Index,
15281542 elements: []const Ast.Node.Index,
1529 tag: Zir.Inst.Tag,
15301543) InnerError!Zir.Inst.Ref {
15311544 const astgen = gz.astgen;
15321545
......@@ -1540,95 +1553,84 @@ fn arrayInitExprRlNone(
15401553 astgen.extra.items[extra_index] = @intFromEnum(elem_ref);
15411554 extra_index += 1;
15421555 }
1543 return try gz.addPlNodePayloadIndex(tag, node, payload_index);
1556 return try gz.addPlNodePayloadIndex(.array_init_anon, node, payload_index);
15441557}
15451558
1546fn arrayInitExprInner(
1559/// An array initialization expression using an `array_init` or `array_init_ref` instruction.
1560fn arrayInitExprTyped(
15471561 gz: *GenZir,
15481562 scope: *Scope,
15491563 node: Ast.Node.Index,
15501564 elements: []const Ast.Node.Index,
1551 array_ty_inst: Zir.Inst.Ref,
1552 elem_ty: Zir.Inst.Ref,
1553 tag: Zir.Inst.Tag,
1565 ty_inst: Zir.Inst.Ref,
1566 maybe_elem_ty_inst: Zir.Inst.Ref,
1567 is_ref: bool,
15541568) InnerError!Zir.Inst.Ref {
15551569 const astgen = gz.astgen;
15561570
1557 const len = elements.len + @intFromBool(array_ty_inst != .none);
1571 const len = elements.len + 1; // +1 for type
15581572 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{
15591573 .operands_len = @intCast(len),
15601574 });
15611575 var extra_index = try reserveExtra(astgen, len);
1562 if (array_ty_inst != .none) {
1563 astgen.extra.items[extra_index] = @intFromEnum(array_ty_inst);
1564 extra_index += 1;
1565 }
1576 astgen.extra.items[extra_index] = @intFromEnum(ty_inst);
1577 extra_index += 1;
15661578
1567 for (elements, 0..) |elem_init, i| {
1568 const ri = if (elem_ty != .none)
1569 ResultInfo{ .rl = .{ .coerced_ty = elem_ty } }
1570 else if (array_ty_inst != .none) ri: {
1571 const ty_expr = try gz.add(.{
1572 .tag = .elem_type_index,
1579 if (maybe_elem_ty_inst != .none) {
1580 const elem_ri: ResultInfo = .{ .rl = .{ .coerced_ty = maybe_elem_ty_inst } };
1581 for (elements) |elem_init| {
1582 const elem_inst = try expr(gz, scope, elem_ri, elem_init);
1583 astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
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,
15731590 .data = .{ .bin = .{
1574 .lhs = array_ty_inst,
1591 .lhs = ty_inst,
15751592 .rhs = @enumFromInt(i),
15761593 } },
1577 });
1578 break :ri ResultInfo{ .rl = .{ .coerced_ty = ty_expr } };
1579 } else ResultInfo{ .rl = .{ .none = {} } };
1594 }) } };
15801595
1581 const elem_ref = try expr(gz, scope, ri, elem_init);
1582 astgen.extra.items[extra_index] = @intFromEnum(elem_ref);
1583 extra_index += 1;
1596 const elem_inst = try expr(gz, scope, ri, elem_init);
1597 astgen.extra.items[extra_index] = @intFromEnum(elem_inst);
1598 extra_index += 1;
1599 }
15841600 }
15851601
1602 const tag: Zir.Inst.Tag = if (is_ref) .array_init_ref else .array_init;
15861603 return try gz.addPlNodePayloadIndex(tag, node, payload_index);
15871604}
15881605
1589fn arrayInitExprRlPtr(
1606/// An array initialization expression using element pointers.
1607fn arrayInitExprPtr(
15901608 gz: *GenZir,
15911609 scope: *Scope,
15921610 node: Ast.Node.Index,
1593 result_ptr: Zir.Inst.Ref,
15941611 elements: []const Ast.Node.Index,
1595 array_ty: Zir.Inst.Ref,
1596) InnerError!Zir.Inst.Ref {
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 {
1612 ptr_inst: Zir.Inst.Ref,
1613) InnerError!void {
16131614 const astgen = gz.astgen;
16141615
1616 const array_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
1617
16151618 const payload_index = try addExtra(astgen, Zir.Inst.Block{
16161619 .body_len = @intCast(elements.len),
16171620 });
16181621 var extra_index = try reserveExtra(astgen, elements.len);
16191622
16201623 for (elements, 0..) |elem_init, i| {
1621 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{
1622 .ptr = result_ptr,
1624 const elem_ptr_inst = try gz.addPlNode(.array_init_elem_ptr, elem_init, Zir.Inst.ElemPtrImm{
1625 .ptr = array_ptr_inst,
16231626 .index = @intCast(i),
16241627 });
1625 astgen.extra.items[extra_index] = refToIndex(elem_ptr).?;
1628 astgen.extra.items[extra_index] = refToIndex(elem_ptr_inst).?;
16261629 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);
16281631 }
16291632
1630 _ = try gz.addPlNodePayloadIndex(.validate_array_init, node, payload_index);
1631 return .void_value;
1633 _ = try gz.addPlNodePayloadIndex(.validate_ptr_array_init, node, payload_index);
16321634}
16331635
16341636fn structInitExpr(
......@@ -1643,7 +1645,26 @@ fn structInitExpr(
16431645
16441646 if (struct_init.ast.type_expr == 0) {
16451647 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 }
16471668 }
16481669 } else array: {
16491670 const node_tags = tree.nodes.items(.tag);
......@@ -1694,86 +1715,67 @@ fn structInitExpr(
16941715 }
16951716 }
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
16971731 switch (ri.rl) {
1732 .none => return structInitExprAnon(gz, scope, node, struct_init),
16981733 .discard => {
1699 if (struct_init.ast.type_expr != 0) {
1700 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1701 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
1702 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1703 } else {
1704 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
1705 }
1706 return Zir.Inst.Ref.void_value;
1734 // Even if discarding we must perform an anonymous init to check for duplicate field names.
1735 // TODO: should duplicate field names be caught in AstGen?
1736 _ = try structInitExprAnon(gz, scope, node, struct_init);
1737 return .void_value;
17071738 },
17081739 .ref => {
1709 if (struct_init.ast.type_expr != 0) {
1710 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
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 }
1740 const result = try structInitExprAnon(gz, scope, node, struct_init);
1741 return gz.addUnTok(.ref, result, tree.firstToken(node));
17161742 },
1717 .none => {
1718 if (struct_init.ast.type_expr != 0) {
1719 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1720 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
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 }
1743 .ref_coerced_ty => |ptr_ty_inst| {
1744 const result_ty_inst = try gz.addUnNode(.elem_type, ptr_ty_inst, node);
1745 _ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
1746 return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, true);
17251747 },
1726 .ty, .coerced_ty => |ty_inst| {
1727 if (struct_init.ast.type_expr == 0) {
1728 const struct_ty_inst = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
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);
1748 .ty, .coerced_ty => |result_ty_inst| {
1749 _ = try gz.addUnNode(.validate_struct_init_result_ty, result_ty_inst, node);
1750 return structInitExprTyped(gz, scope, node, struct_init, result_ty_inst, false);
17371751 },
1738 .ptr => |ptr_res| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_res.inst),
1739 .inferred_ptr => |ptr_inst| {
1740 if (struct_init.ast.type_expr == 0) {
1741 // We treat this case differently so that we don't get a crash when
1742 // analyzing field_base_ptr against an alloc_inferred_mut.
1743 // See corresponding logic in arrayInitExpr.
1744 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
1745 return rvalue(gz, ri, result, node);
1746 } else {
1747 return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst);
1748 }
1752 .ptr => |ptr| {
1753 try structInitExprPtr(gz, scope, node, struct_init, ptr.inst);
1754 return .void_value;
1755 },
1756 .inferred_ptr => {
1757 // We can't get field pointers of an untyped inferred alloc, so must perform a
1758 // standard anonymous initialization followed by an rvalue store.
1759 // See corresponding logic in arrayInitExpr.
1760 const struct_inst = try structInitExprAnon(gz, scope, node, struct_init);
1761 return rvalue(gz, ri, struct_inst, node);
17491762 },
17501763 .destructure => |destructure| {
1751 if (struct_init.ast.type_expr == 0) {
1752 // This is an untyped init, so is an actual struct, which does
1753 // not support destructuring.
1754 return astgen.failNodeNotes(node, "struct value cannot be destructured", .{}, &.{
1755 try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
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);
1764 // This is an untyped init, so is an actual struct, which does
1765 // not support destructuring.
1766 return astgen.failNodeNotes(node, "struct value cannot be destructured", .{}, &.{
1767 try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
1768 });
17661769 },
17671770 }
17681771}
17691772
1770fn structInitExprRlNone(
1773/// A struct initialization expression using a `struct_init_anon` instruction.
1774fn structInitExprAnon(
17711775 gz: *GenZir,
17721776 scope: *Scope,
17731777 node: Ast.Node.Index,
17741778 struct_init: Ast.full.StructInit,
1775 ty_inst: Zir.Inst.Ref,
1776 tag: Zir.Inst.Tag,
17771779) InnerError!Zir.Inst.Ref {
17781780 const astgen = gz.astgen;
17791781 const tree = astgen.tree;
......@@ -1787,104 +1789,83 @@ fn structInitExprRlNone(
17871789 for (struct_init.ast.fields) |field_init| {
17881790 const name_token = tree.firstToken(field_init) - 2;
17891791 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 };
17971792 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
17981793 .field_name = str_index,
1799 .init = try expr(gz, scope, sub_ri, field_init),
1794 .init = try expr(gz, scope, .{ .rl = .none }, field_init),
18001795 });
18011796 extra_index += field_size;
18021797 }
18031798
1804 return try gz.addPlNodePayloadIndex(tag, 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);
1799 return gz.addPlNodePayloadIndex(.struct_init_anon, node, payload_index);
18231800}
18241801
1825fn structInitExprRlPtrInner(
1802/// A struct initialization expression using a `struct_init` or `struct_init_ref` instruction.
1803fn structInitExprTyped(
18261804 gz: *GenZir,
18271805 scope: *Scope,
18281806 node: Ast.Node.Index,
18291807 struct_init: Ast.full.StructInit,
1830 result_ptr: Zir.Inst.Ref,
1808 ty_inst: Zir.Inst.Ref,
1809 is_ref: bool,
18311810) InnerError!Zir.Inst.Ref {
18321811 const astgen = gz.astgen;
18331812 const tree = astgen.tree;
18341813
1835 const payload_index = try addExtra(astgen, Zir.Inst.Block{
1836 .body_len = @intCast(struct_init.ast.fields.len),
1814 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
1815 .fields_len = @intCast(struct_init.ast.fields.len),
18371816 });
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
18401820 for (struct_init.ast.fields) |field_init| {
18411821 const name_token = tree.firstToken(field_init) - 2;
18421822 const str_index = try astgen.identAsString(name_token);
1843 const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{
1844 .lhs = result_ptr,
1845 .field_name_start = str_index,
1823 const field_ty_inst = try gz.addPlNode(.struct_init_field_type, field_init, Zir.Inst.FieldType{
1824 .container_type = ty_inst,
1825 .name_start = str_index,
18461826 });
1847 astgen.extra.items[extra_index] = refToIndex(field_ptr).?;
1848 extra_index += 1;
1849 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init);
1827 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{
1828 .field_type = refToIndex(field_ty_inst).?,
1829 .init = try expr(gz, scope, .{ .rl = .{ .coerced_ty = field_ty_inst } }, field_init),
1830 });
1831 extra_index += field_size;
18501832 }
18511833
1852 _ = try gz.addPlNodePayloadIndex(.validate_struct_init, node, payload_index);
1853 return Zir.Inst.Ref.void_value;
1834 const tag: Zir.Inst.Tag = if (is_ref) .struct_init_ref else .struct_init;
1835 return gz.addPlNodePayloadIndex(tag, node, payload_index);
18541836}
18551837
1856fn structInitExprRlTy(
1838/// A struct initialization expression using field pointers.
1839fn structInitExprPtr(
18571840 gz: *GenZir,
18581841 scope: *Scope,
18591842 node: Ast.Node.Index,
18601843 struct_init: Ast.full.StructInit,
1861 ty_inst: Zir.Inst.Ref,
1862 tag: Zir.Inst.Tag,
1863) InnerError!Zir.Inst.Ref {
1844 ptr_inst: Zir.Inst.Ref,
1845) InnerError!void {
18641846 const astgen = gz.astgen;
18651847 const tree = astgen.tree;
18661848
1867 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{
1868 .fields_len = @intCast(struct_init.ast.fields.len),
1849 const struct_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node);
1850
1851 const payload_index = try addExtra(astgen, Zir.Inst.Block{
1852 .body_len = @intCast(struct_init.ast.fields.len),
18691853 });
1870 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len;
1871 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size);
1854 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len);
18721855
18731856 for (struct_init.ast.fields) |field_init| {
18741857 const name_token = tree.firstToken(field_init) - 2;
18751858 const str_index = try astgen.identAsString(name_token);
1876 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
1877 .container_type = ty_inst,
1878 .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),
1859 const field_ptr = try gz.addPlNode(.struct_init_field_ptr, field_init, Zir.Inst.Field{
1860 .lhs = struct_ptr_inst,
1861 .field_name_start = str_index,
18831862 });
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);
18851866 }
18861867
1887 return try gz.addPlNodePayloadIndex(tag, node, payload_index);
1868 _ = try gz.addPlNodePayloadIndex(.validate_ptr_struct_init, node, payload_index);
18881869}
18891870
18901871/// This explicitly calls expr in a comptime scope by wrapping it in a `block_comptime` if
......@@ -2314,7 +2295,7 @@ fn labeledBlockExpr(
23142295 const need_rl = astgen.nodes_need_rl.contains(block_node);
23152296 const block_ri: ResultInfo = if (need_rl) ri else .{
23162297 .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)).? },
23182299 .inferred_ptr => .none,
23192300 else => ri.rl,
23202301 },
......@@ -2504,7 +2485,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25042485 .array_mul,
25052486 .array_type,
25062487 .array_type_sentinel,
2507 .elem_type_index,
25082488 .elem_type,
25092489 .indexable_ptr_elem_type,
25102490 .vector_elem_type,
......@@ -2531,7 +2511,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25312511 .cmp_gte,
25322512 .cmp_gt,
25332513 .cmp_neq,
2534 .coerce_result_ptr,
25352514 .decl_ref,
25362515 .decl_val,
25372516 .load,
......@@ -2539,11 +2518,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25392518 .elem_ptr,
25402519 .elem_val,
25412520 .elem_ptr_node,
2542 .elem_ptr_imm,
25432521 .elem_val_node,
25442522 .elem_val_imm,
25452523 .field_ptr,
2546 .field_ptr_init,
25472524 .field_val,
25482525 .field_ptr_named,
25492526 .field_val_named,
......@@ -2599,17 +2576,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25992576 .import,
26002577 .switch_block,
26012578 .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,
26112579 .union_init,
2612 .field_type,
26132580 .field_type_ref,
26142581 .error_set_decl,
26152582 .error_set_decl_anon,
......@@ -2680,14 +2647,27 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26802647 .@"await",
26812648 .ret_err_value_code,
26822649 .closure_get,
2683 .array_base_ptr,
2684 .field_base_ptr,
26852650 .ret_ptr,
26862651 .ret_type,
26872652 .for_len,
26882653 .@"try",
26892654 .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,
26912671 => break :b false,
26922672
26932673 .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
27382718 .store_node,
27392719 .store_to_inferred_ptr,
27402720 .resolve_inferred_alloc,
2741 .validate_struct_init,
2742 .validate_array_init,
27432721 .set_runtime_safety,
27442722 .closure_capture,
27452723 .memcpy,
27462724 .memset,
2747 .validate_array_init_ty,
2748 .validate_struct_init_ty,
27492725 .validate_deref,
27502726 .validate_destructure,
27512727 .save_err_ret_index,
27522728 .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,
27532736 => break :b true,
27542737
27552738 .@"defer" => unreachable,
......@@ -5635,7 +5618,7 @@ fn tryExpr(
56355618 const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
56365619
56375620 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 },
56395622 else => .{ .rl = .none, .ctx = .error_handling_expr },
56405623 };
56415624 // This could be a pointer or value depending on the `ri` parameter.
......@@ -5648,7 +5631,7 @@ fn tryExpr(
56485631 defer else_scope.unstack();
56495632
56505633 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,
56525635 else => Zir.Inst.Tag.err_union_code,
56535636 };
56545637 const err_code = try else_scope.addUnNode(err_tag, operand, node);
......@@ -5659,7 +5642,7 @@ fn tryExpr(
56595642 try else_scope.setTryBody(try_inst, operand);
56605643 const result = indexToRef(try_inst);
56615644 switch (ri.rl) {
5662 .ref => return result,
5645 .ref, .ref_coerced_ty => return result,
56635646 else => return rvalue(parent_gz, ri, result, node),
56645647 }
56655648}
......@@ -5682,7 +5665,7 @@ fn orelseCatchExpr(
56825665 const need_rl = astgen.nodes_need_rl.contains(node);
56835666 const block_ri: ResultInfo = if (need_rl) ri else .{
56845667 .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)).? },
56865669 .inferred_ptr => .none,
56875670 else => ri.rl,
56885671 },
......@@ -5700,7 +5683,7 @@ fn orelseCatchExpr(
57005683 defer block_scope.unstack();
57015684
57025685 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 },
57045687 else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none },
57055688 };
57065689 // This could be a pointer or value depending on the `operand_ri` parameter.
......@@ -5722,7 +5705,7 @@ fn orelseCatchExpr(
57225705 // This could be a pointer or value depending on `unwrap_op`.
57235706 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
57245707 const then_result = switch (ri.rl) {
5725 .ref => unwrapped_payload,
5708 .ref, .ref_coerced_ty => unwrapped_payload,
57265709 else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node),
57275710 };
57285711 _ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node);
......@@ -5793,7 +5776,7 @@ fn fieldAccess(
57935776 node: Ast.Node.Index,
57945777) InnerError!Zir.Inst.Ref {
57955778 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),
57975780 else => {
57985781 const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node);
57995782 return rvalue(gz, ri, access, node);
......@@ -5837,7 +5820,7 @@ fn arrayAccess(
58375820 const tree = gz.astgen.tree;
58385821 const node_datas = tree.nodes.items(.data);
58395822 switch (ri.rl) {
5840 .ref => {
5823 .ref, .ref_coerced_ty => {
58415824 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
58425825
58435826 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
......@@ -5951,7 +5934,7 @@ fn ifExpr(
59515934 const need_rl = astgen.nodes_need_rl.contains(node);
59525935 const block_ri: ResultInfo = if (need_rl) ri else .{
59535936 .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)).? },
59555938 .inferred_ptr => .none,
59565939 else => ri.rl,
59575940 },
......@@ -6181,7 +6164,7 @@ fn whileExpr(
61816164 const need_rl = astgen.nodes_need_rl.contains(node);
61826165 const block_ri: ResultInfo = if (need_rl) ri else .{
61836166 .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)).? },
61856168 .inferred_ptr => .none,
61866169 else => ri.rl,
61876170 },
......@@ -6455,7 +6438,7 @@ fn forExpr(
64556438 const need_rl = astgen.nodes_need_rl.contains(node);
64566439 const block_ri: ResultInfo = if (need_rl) ri else .{
64576440 .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)).? },
64596442 .inferred_ptr => .none,
64606443 else => ri.rl,
64616444 },
......@@ -6773,7 +6756,7 @@ fn switchExpr(
67736756 const need_rl = astgen.nodes_need_rl.contains(switch_node);
67746757 const block_ri: ResultInfo = if (need_rl) ri else .{
67756758 .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)).? },
67776760 .inferred_ptr => .none,
67786761 else => ri.rl,
67796762 },
......@@ -7465,7 +7448,7 @@ fn localVarRef(
74657448 gpa,
74667449 );
74677450
7468 return rvalue(gz, ri, value_inst, ident);
7451 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
74697452 }
74707453 s = local_val.parent;
74717454 },
......@@ -7498,10 +7481,10 @@ fn localVarRef(
74987481 );
74997482
75007483 switch (ri.rl) {
7501 .ref => return ptr_inst,
7484 .ref, .ref_coerced_ty => return ptr_inst,
75027485 else => {
75037486 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
7504 return rvalue(gz, ri, loaded, ident);
7487 return rvalueNoCoercePreRef(gz, ri, loaded, ident);
75057488 },
75067489 }
75077490 }
......@@ -7535,10 +7518,10 @@ fn localVarRef(
75357518 // Decl references happen by name rather than ZIR index so that when unrelated
75367519 // decls are modified, ZIR code containing references to them can be unmodified.
75377520 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),
75397522 else => {
75407523 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);
75427525 },
75437526 }
75447527}
......@@ -7924,7 +7907,7 @@ fn bitCast(
79247907 node: Ast.Node.Index,
79257908 operand_node: Ast.Node.Index,
79267909) 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");
79287911 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node);
79297912 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
79307913 .lhs = dest_type,
......@@ -8024,7 +8007,7 @@ fn ptrCast(
80248007 // Full cast including result type
80258008
80268009 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());
80288011 const operand = try expr(gz, scope, .{ .rl = .none }, node);
80298012 try emitDbgStmt(gz, cursor);
80308013 const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{
......@@ -8208,7 +8191,7 @@ fn builtinCall(
82088191 return rvalue(gz, ri, result, node);
82098192 },
82108193 .field => {
8211 if (ri.rl == .ref) {
8194 if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
82128195 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
82138196 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
82148197 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]),
......@@ -8475,7 +8458,7 @@ fn builtinCall(
84758458 try emitDbgNode(gz, node);
84768459
84778460 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"),
84798462 .rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
84808463 .node = gz.nodeIndexToRelative(node),
84818464 });
......@@ -8548,7 +8531,7 @@ fn builtinCall(
85488531 },
85498532
85508533 .splat => {
8551 const result_type = try ri.rl.resultType(gz, node, "@splat");
8534 const result_type = try ri.rl.resultTypeForCast(gz, node, "@splat");
85528535 const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
85538536 const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
85548537 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
......@@ -8810,7 +8793,7 @@ fn typeCast(
88108793 builtin_name: []const u8,
88118794) InnerError!Zir.Inst.Ref {
88128795 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);
88148797 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node);
88158798
88168799 try emitDbgStmt(gz, cursor);
......@@ -10069,6 +10052,29 @@ fn rvalue(
1006910052 ri: ResultInfo,
1007010053 raw_result: Zir.Inst.Ref,
1007110054 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,
1007210078) InnerError!Zir.Inst.Ref {
1007310079 const result = r: {
1007410080 if (refToIndex(raw_result)) |result_index| {
......@@ -10088,7 +10094,14 @@ fn rvalue(
1008810094 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
1008910095 return .void_value;
1009010096 },
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;
1009210105 // We need a pointer but we have a value.
1009310106 // Unfortunately it's not quite as simple as directly emitting a ref
1009410107 // instruction here because we need subsequent address-of operator on
......@@ -10096,14 +10109,14 @@ fn rvalue(
1009610109 const astgen = gz.astgen;
1009710110 const tree = astgen.tree;
1009810111 const src_token = tree.firstToken(src_node);
10099 const result_index = refToIndex(result) orelse
10100 return gz.addUnTok(.ref, result, src_token);
10112 const result_index = refToIndex(coerced_result) orelse
10113 return gz.addUnTok(.ref, coerced_result, src_token);
1010110114 const zir_tags = gz.astgen.instructions.items(.tag);
10102 if (zir_tags[result_index].isParam() or astgen.isInferred(result))
10103 return gz.addUnTok(.ref, result, src_token);
10115 if (zir_tags[result_index].isParam() or astgen.isInferred(coerced_result))
10116 return gz.addUnTok(.ref, coerced_result, src_token);
1010410117 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
1010510118 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);
1010710120 }
1010810121 return indexToRef(gop.value_ptr.*);
1010910122 },
src/AstRlAnnotate.zig+26-18
......@@ -669,17 +669,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
669669 => {
670670 var buf: [2]Ast.Node.Index = undefined;
671671 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
673675 _ = 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 };
681676 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);
683687 }
684688 return ri.have_ptr;
685689 } else {
......@@ -702,17 +706,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
702706 => {
703707 var buf: [2]Ast.Node.Index = undefined;
704708 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
706712 _ = 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 };
714713 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);
716724 }
717725 return ri.have_ptr;
718726 } else {
src/Autodoc.zig+3-34
......@@ -2391,34 +2391,6 @@ fn walkInstruction(
23912391 .expr = .{ .@"&" = expr_index },
23922392 };
23932393 },
2394 .array_init_anon_ref => {
2395 const pl_node = data[inst_index].pl_node;
2396 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
2397 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
2398 const array_data = try self.arena.alloc(usize, operands.len);
2399
2400 for (operands, 0..) |op, idx| {
2401 const wr = try self.walkRef(
2402 file,
2403 parent_scope,
2404 parent_src,
2405 op,
2406 false,
2407 call_ctx,
2408 );
2409 const expr_index = self.exprs.items.len;
2410 try self.exprs.append(self.arena, wr.expr);
2411 array_data[idx] = expr_index;
2412 }
2413
2414 const expr_index = self.exprs.items.len;
2415 try self.exprs.append(self.arena, .{ .array = array_data });
2416
2417 return DocData.WalkResult{
2418 .typeRef = null,
2419 .expr = .{ .@"&" = expr_index },
2420 };
2421 },
24222394 .float => {
24232395 const float = data[inst_index].float;
24242396 return DocData.WalkResult{
......@@ -2709,9 +2681,7 @@ fn walkInstruction(
27092681 .expr = .{ .declRef = decl_status },
27102682 };
27112683 },
2712 .field_val, .field_ptr, .field_type => {
2713 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
2714 // same layout as Zir.Inst.Field :^)
2684 .field_val, .field_ptr => {
27152685 const pl_node = data[inst_index].pl_node;
27162686 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
27172687
......@@ -2730,8 +2700,7 @@ fn walkInstruction(
27302700 };
27312701
27322702 if (tags[lhs] != .field_val and
2733 tags[lhs] != .field_ptr and
2734 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
2703 tags[lhs] != .field_ptr) break :blk lhs_extra.data.lhs;
27352704
27362705 lhs_extra = file.zir.extraData(
27372706 Zir.Inst.Field,
......@@ -2870,7 +2839,7 @@ fn walkInstruction(
28702839
28712840 const field_name = blk: {
28722841 const field_inst_index = init_extra.data.field_type;
2873 if (tags[field_inst_index] != .field_type) unreachable;
2842 if (tags[field_inst_index] != .struct_init_field_type) unreachable;
28742843 const field_pl_node = data[field_inst_index].pl_node;
28752844 const field_extra = file.zir.extraData(
28762845 Zir.Inst.FieldType,
src/Sema.zig+478-447
......@@ -836,16 +836,11 @@ const LabeledBlock = struct {
836836/// the items are contiguous in memory and thus can be passed to
837837/// `Module.resolvePeerTypes`.
838838const InferredAlloc = struct {
839 prongs: std.MultiArrayList(struct {
840 /// The dummy instruction used as a peer to resolve the type.
841 /// Although this has a redundant type with placeholder, this is
842 /// needed in addition because it may be a constant value, which
843 /// affects peer type resolution.
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 }) = .{},
839 /// The placeholder `store` instructions used before the result pointer type
840 /// is known. These should be rewritten to perform any required coercions
841 /// when the type is resolved.
842 /// Allocated from `sema.arena`.
843 prongs: std.ArrayListUnmanaged(Air.Inst.Index) = .{},
849844};
850845
851846const NeededComptimeReason = struct {
......@@ -1040,17 +1035,14 @@ fn analyzeBodyInner(
10401035 .cmp_gte => try sema.zirCmp(block, inst, .gte),
10411036 .cmp_gt => try sema.zirCmp(block, inst, .gt),
10421037 .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),
10441038 .decl_ref => try sema.zirDeclRef(block, inst),
10451039 .decl_val => try sema.zirDeclVal(block, inst),
10461040 .load => try sema.zirLoad(block, inst),
10471041 .elem_ptr => try sema.zirElemPtr(block, inst),
10481042 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
1049 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst),
10501043 .elem_val => try sema.zirElemVal(block, inst),
10511044 .elem_val_node => try sema.zirElemValNode(block, inst),
10521045 .elem_val_imm => try sema.zirElemValImm(block, inst),
1053 .elem_type_index => try sema.zirElemTypeIndex(block, inst),
10541046 .elem_type => try sema.zirElemType(block, inst),
10551047 .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst),
10561048 .vector_elem_type => try sema.zirVectorElemType(block, inst),
......@@ -1063,8 +1055,7 @@ fn analyzeBodyInner(
10631055 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst),
10641056 .error_union_type => try sema.zirErrorUnionType(block, inst),
10651057 .error_value => try sema.zirErrorValue(block, inst),
1066 .field_ptr => try sema.zirFieldPtr(block, inst, false),
1067 .field_ptr_init => try sema.zirFieldPtr(block, inst, true),
1058 .field_ptr => try sema.zirFieldPtr(block, inst),
10681059 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
10691060 .field_val => try sema.zirFieldVal(block, inst),
10701061 .field_val_named => try sema.zirFieldValNamed(block, inst),
......@@ -1111,16 +1102,19 @@ fn analyzeBodyInner(
11111102 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
11121103 .xor => try sema.zirBitwise(block, inst, .xor),
11131104 .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),
11141108 .struct_init => try sema.zirStructInit(block, inst, false),
11151109 .struct_init_ref => try sema.zirStructInit(block, inst, true),
1116 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
1117 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
1110 .struct_init_field_type => try sema.zirStructInitFieldType(block, inst),
1111 .struct_init_field_ptr => try sema.zirStructInitFieldPtr(block, inst),
1112 .array_init_anon => try sema.zirArrayInitAnon(block, inst),
11181113 .array_init => try sema.zirArrayInit(block, inst, false),
11191114 .array_init_ref => try sema.zirArrayInit(block, inst, true),
1120 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
1121 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
1115 .array_init_elem_type => try sema.zirArrayInitElemType(block, inst),
1116 .array_init_elem_ptr => try sema.zirArrayInitElemPtr(block, inst),
11221117 .union_init => try sema.zirUnionInit(block, inst),
1123 .field_type => try sema.zirFieldType(block, inst),
11241118 .field_type_ref => try sema.zirFieldTypeRef(block, inst),
11251119 .int_from_ptr => try sema.zirIntFromPtr(block, inst),
11261120 .align_of => try sema.zirAlignOf(block, inst),
......@@ -1154,10 +1148,10 @@ fn analyzeBodyInner(
11541148 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
11551149 .@"resume" => try sema.zirResume(block, inst),
11561150 .@"await" => try sema.zirAwait(block, inst),
1157 .array_base_ptr => try sema.zirArrayBasePtr(block, inst),
1158 .field_base_ptr => try sema.zirFieldBasePtr(block, inst),
11591151 .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
11621156 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
11631157 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
......@@ -1386,23 +1380,33 @@ fn analyzeBodyInner(
13861380 i += 1;
13871381 continue;
13881382 },
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 },
13891393 .validate_array_init_ty => {
1390 try sema.zirValidateArrayInitTy(block, inst);
1394 try sema.zirValidateArrayInitTy(block, inst, false);
13911395 i += 1;
13921396 continue;
13931397 },
1394 .validate_struct_init_ty => {
1395 try sema.zirValidateStructInitTy(block, inst);
1398 .validate_array_init_result_ty => {
1399 try sema.zirValidateArrayInitTy(block, inst, true);
13961400 i += 1;
13971401 continue;
13981402 },
1399 .validate_struct_init => {
1400 try sema.zirValidateStructInit(block, inst);
1403 .validate_ptr_struct_init => {
1404 try sema.zirValidatePtrStructInit(block, inst);
14011405 i += 1;
14021406 continue;
14031407 },
1404 .validate_array_init => {
1405 try sema.zirValidateArrayInit(block, inst);
1408 .validate_ptr_array_init => {
1409 try sema.zirValidatePtrArrayInit(block, inst);
14061410 i += 1;
14071411 continue;
14081412 },
......@@ -1416,6 +1420,11 @@ fn analyzeBodyInner(
14161420 i += 1;
14171421 continue;
14181422 },
1423 .validate_ref_ty => {
1424 try sema.zirValidateRefTy(block, inst);
1425 i += 1;
1426 continue;
1427 },
14191428 .@"export" => {
14201429 try sema.zirExport(block, inst);
14211430 i += 1;
......@@ -1922,7 +1931,11 @@ fn resolveDestType(
19221931 const msg = msg: {
19231932 const msg = try sema.errMsg(block, src, "{s} must have a known result type", .{builtin_name});
19241933 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 }
19261939 try sema.errNote(block, src, msg, "use @as to provide explicit result type", .{});
19271940 break :msg msg;
19281941 };
......@@ -1944,6 +1957,65 @@ fn resolveDestType(
19441957 return raw_ty;
19451958}
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
19472019fn analyzeAsType(
19482020 sema: *Sema,
19492021 block: *Block,
......@@ -2634,217 +2706,6 @@ pub fn resolveInstValue(
26342706 };
26352707}
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
28482709pub fn getStructType(
28492710 sema: *Sema,
28502711 decl: Module.Decl.Index,
......@@ -4220,8 +4081,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42204081 .inferred_alloc => {
42214082 const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
42224083 const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;
4223 const peer_inst_list = ia2.prongs.items(.stored_inst);
4224 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
4084 const peer_vals = try sema.arena.alloc(Air.Inst.Ref, ia2.prongs.items.len);
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
42264092 const final_ptr_ty = try sema.ptrType(.{
42274093 .child = final_elem_ty.toIntern(),
......@@ -4259,55 +4125,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42594125 .data = .{ .ty = final_ptr_ty },
42604126 });
42614127
4262 // Now we need to go back over all the coerce_result_ptr instructions, which
4263 // previously inserted a bitcast as a placeholder, and do the logic as if
4128 // Now we need to go back over all the store instructions, and do the logic as if
42644129 // the new result ptr type was available.
4265 const placeholders = ia2.prongs.items(.placeholder);
42664130 const gpa = sema.gpa;
42674131
4268 var trash_block = block.makeSubBlock();
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
4132 for (ia2.prongs.items) |placeholder_inst| {
42914133 var replacement_block = block.makeSubBlock();
42924134 defer replacement_block.instructions.deinit(gpa);
42934135
4294 const result = switch (sema.air_instructions.items(.tag)[placeholder_inst]) {
4295 .bitcast => result: {
4296 trash_block.instructions.shrinkRetainingCapacity(empty_trash_count);
4297 const sub_ptr = try sema.coerceResultPtr(&replacement_block, src, ptr, dummy_ptr, peer_inst, &trash_block);
4136 assert(sema.air_instructions.items(.tag)[placeholder_inst] == .store);
4137 const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op;
4138 try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .store);
42984139
4299 assert(replacement_block.instructions.items.len > 0);
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
4140 // If only one instruction is produced then we can replace the store
43114141 // placeholder instruction with this instruction; no need for an entire block.
43124142 if (replacement_block.instructions.items.len == 1) {
43134143 const only_inst = replacement_block.instructions.items[0];
......@@ -4315,13 +4145,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
43154145 continue;
43164146 }
43174147
4318 // Here we replace the placeholder bitcast instruction with a block
4319 // that does the coerce_result_ptr logic.
4320 _ = try replacement_block.addBr(placeholder_inst, result);
4321 const ty_inst = if (result == .void_value)
4322 .void_type
4323 else
4324 sema.air_instructions.items(.data)[placeholder_inst].ty_op.ty;
4148 // Here we replace the placeholder store instruction with a block
4149 // that does the actual store logic.
4150 _ = try replacement_block.addBr(placeholder_inst, .void_value);
43254151 try sema.air_extra.ensureUnusedCapacity(
43264152 gpa,
43274153 @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
43294155 sema.air_instructions.set(placeholder_inst, .{
43304156 .tag = .block,
43314157 .data = .{ .ty_pl = .{
4332 .ty = ty_inst,
4158 .ty = .void_type,
43334159 .payload = sema.addExtraAssumeCapacity(Air.Block{
43344160 .body_len = @intCast(replacement_block.instructions.items.len),
43354161 }),
......@@ -4342,64 +4168,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
43424168 }
43434169}
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
44034171fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
44044172 const mod = sema.mod;
44054173 const gpa = sema.gpa;
......@@ -4526,34 +4294,140 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
45264294 return len;
45274295}
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(
45304392 sema: *Sema,
45314393 block: *Block,
45324394 inst: Zir.Inst.Index,
45334395) CompileError!Air.Inst.Ref {
45344396 const mod = sema.mod;
4535 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4536 var ty = sema.resolveType(block, .unneeded, inst_data.operand) catch |err| switch (err) {
4537 // Since this is a ZIR instruction that returns a type, encountering
4538 // generic poison should not result in a failed compilation, but the
4539 // generic poison type. This prevents unnecessary failures when
4540 // constructing types at compile-time.
4397 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
4398 const src = pl_node.src();
4399 const extra = sema.code.extraData(Zir.Inst.ArrayInitRefTy, pl_node.payload_index).data;
4400 const maybe_wrapped_ptr_ty = sema.resolveType(block, .unneeded, extra.ptr_ty) catch |err| switch (err) {
45414401 error.GenericPoison => return .generic_poison_type,
45424402 else => |e| return e,
45434403 };
4544 while (true) {
4545 switch (ty.zigTypeTag(mod)) {
4546 .Optional => ty = ty.optionalChild(mod),
4547 .ErrorUnion => ty = ty.errorUnionPayload(mod),
4548 else => return Air.internedToRef(ty.toIntern()),
4549 }
4404 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(mod);
4405 assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction
4406 if (ptr_ty.isSlice(mod)) {
4407 // Use array of correct length
4408 const arr_ty = try mod.arrayType(.{
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());
45504414 }
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());
45514424}
45524425
45534426fn zirValidateArrayInitTy(
45544427 sema: *Sema,
45554428 block: *Block,
45564429 inst: Zir.Inst.Index,
4430 is_result_ty: bool,
45574431) CompileError!void {
45584432 const mod = sema.mod;
45594433 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
......@@ -4565,22 +4439,34 @@ fn zirValidateArrayInitTy(
45654439 error.GenericPoison => return,
45664440 else => |e| return e,
45674441 };
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;
45694455 switch (ty.zigTypeTag(mod)) {
45704456 .Array => {
45714457 const array_len = ty.arrayLen(mod);
4572 if (extra.init_count != array_len) {
4458 if (init_count != array_len) {
45734459 return sema.fail(block, src, "expected {d} array elements; found {d}", .{
4574 array_len, extra.init_count,
4460 array_len, init_count,
45754461 });
45764462 }
45774463 return;
45784464 },
45794465 .Vector => {
45804466 const array_len = ty.arrayLen(mod);
4581 if (extra.init_count != array_len) {
4467 if (init_count != array_len) {
45824468 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
4583 array_len, extra.init_count,
4469 array_len, init_count,
45844470 });
45854471 }
45864472 return;
......@@ -4588,9 +4474,9 @@ fn zirValidateArrayInitTy(
45884474 .Struct => if (ty.isTuple(mod)) {
45894475 try sema.resolveTypeFields(ty);
45904476 const array_len = ty.arrayLen(mod);
4591 if (extra.init_count > array_len) {
4477 if (init_count > array_len) {
45924478 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
4593 array_len, extra.init_count,
4479 array_len, init_count,
45944480 });
45954481 }
45964482 return;
......@@ -4604,6 +4490,7 @@ fn zirValidateStructInitTy(
46044490 sema: *Sema,
46054491 block: *Block,
46064492 inst: Zir.Inst.Index,
4493 is_result_ty: bool,
46074494) CompileError!void {
46084495 const mod = sema.mod;
46094496 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
......@@ -4613,15 +4500,16 @@ fn zirValidateStructInitTy(
46134500 error.GenericPoison => return,
46144501 else => |e| return e,
46154502 };
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)) {
46184506 .Struct, .Union => return,
46194507 else => {},
46204508 }
4621 return sema.failWithStructInitNotSupported(block, src, ty);
4509 return sema.failWithStructInitNotSupported(block, src, struct_ty);
46224510}
46234511
4624fn zirValidateStructInit(
4512fn zirValidatePtrStructInit(
46254513 sema: *Sema,
46264514 block: *Block,
46274515 inst: Zir.Inst.Index,
......@@ -4637,7 +4525,7 @@ fn zirValidateStructInit(
46374525 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
46384526 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
46394527 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);
46414529 switch (agg_ty.zigTypeTag(mod)) {
46424530 .Struct => return sema.validateStructInit(
46434531 block,
......@@ -4723,10 +4611,6 @@ fn validateUnionInit(
47234611 // based only on the store instructions.
47244612 // `first_block_index` needs to point to the `field_ptr` if it exists;
47254613 // 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.
47304614 var first_block_index = block.instructions.items.len;
47314615 var block_index = block.instructions.items.len - 1;
47324616 var init_val: ?Value = null;
......@@ -4963,10 +4847,6 @@ fn validateStructInit(
49634847 // based only on the store instructions.
49644848 // `first_block_index` needs to point to the `field_ptr` if it exists;
49654849 // 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
49714851 // Possible performance enhancement: save the `block_index` between iterations
49724852 // of the for loop.
......@@ -5115,7 +4995,7 @@ fn validateStructInit(
51154995 }
51164996}
51174997
5118fn zirValidateArrayInit(
4998fn zirValidatePtrArrayInit(
51194999 sema: *Sema,
51205000 block: *Block,
51215001 inst: Zir.Inst.Index,
......@@ -5128,7 +5008,7 @@ fn zirValidateArrayInit(
51285008 const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
51295009 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
51305010 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);
51325012 const array_len = array_ty.arrayLen(mod);
51335013
51345014 if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) {
......@@ -5227,10 +5107,6 @@ fn zirValidateArrayInit(
52275107 // `first_block_index` needs to point to the `elem_ptr` if it exists;
52285108 // the `store` otherwise.
52295109 //
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 //
52345110 // This is nearly identical to similar logic in `validateStructInit`.
52355111
52365112 // Possible performance enhancement: save the `block_index` between iterations
......@@ -5540,10 +5416,7 @@ fn storeToInferredAlloc(
55405416 try sema.checkComptimeKnownStore(block, dummy_store);
55415417 // Add the stored instruction to the set we will use to resolve peer types
55425418 // for the inferred allocation.
5543 try inferred_alloc.prongs.append(sema.arena, .{
5544 .stored_inst = operand,
5545 .placeholder = Air.refToIndex(dummy_store).?,
5546 });
5419 try inferred_alloc.prongs.append(sema.arena, Air.refToIndex(dummy_store).?);
55475420}
55485421
55495422fn storeToInferredAllocComptime(
......@@ -8314,10 +8187,10 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
83148187 return Air.internedToRef(opt_type.toIntern());
83158188}
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 {
83188191 const mod = sema.mod;
83198192 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) {
83218194 // Since this is a ZIR instruction that returns a type, encountering
83228195 // generic poison should not result in a failed compilation, but the
83238196 // generic poison type. This prevents unnecessary failures when
......@@ -8325,6 +8198,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
83258198 error.GenericPoison => return .generic_poison_type,
83268199 else => |e| return e,
83278200 };
8201 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(mod);
83288202 try sema.resolveTypeFields(indexable_ty);
83298203 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
83308204 if (indexable_ty.zigTypeTag(mod) == .Struct) {
......@@ -8339,8 +8213,18 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
83398213fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
83408214 const mod = sema.mod;
83418215 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);
83438221 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 }
83448228 return Air.internedToRef(ptr_ty.childType(mod).toIntern());
83458229}
83468230
......@@ -10083,7 +9967,21 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
100839967 return sema.fieldVal(block, src, object, field_name, field_name_src);
100849968}
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 {
100879985 const tracy = trace(@src());
100889986 defer tracy.end();
100899987
......@@ -10094,7 +9992,15 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
100949992 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
100959993 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
100969994 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 }
1009810004}
1009910005
1010010006fn 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
1058710493 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);
1058810494}
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 {
1059110497 const tracy = trace(@src());
1059210498 defer tracy.end();
1059310499
10500 const mod = sema.mod;
1059410501 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1059510502 const src = inst_data.src();
1059610503 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
1059710504 const array_ptr = try sema.resolveInst(extra.ptr);
1059810505 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 }
1059910513 return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true);
1060010514}
1060110515
......@@ -19213,6 +19127,52 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1921319127 }
1921419128}
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
1921619176fn structInitEmpty(
1921719177 sema: *Sema,
1921819178 block: *Block,
......@@ -19230,7 +19190,7 @@ fn structInitEmpty(
1923019190 defer gpa.free(field_inits);
1923119191 @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);
1923419194}
1923519195
1923619196fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
......@@ -19321,13 +19281,14 @@ fn zirStructInit(
1932119281 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
1932219282 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
1932319283 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) {
1932519285 error.GenericPoison => {
1932619286 // The type wasn't actually known, so treat this as an anon struct init.
1932719287 return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref);
1932819288 },
1932919289 else => |e| return e,
1933019290 };
19291 const resolved_ty = result_ty.optEuBaseType(mod);
1933119292 try sema.resolveTypeLayout(resolved_ty);
1933219293
1933319294 if (resolved_ty.zigTypeTag(mod) == .Struct) {
......@@ -19372,7 +19333,9 @@ fn zirStructInit(
1937219333 return sema.failWithOwnedErrorMsg(block, msg);
1937319334 }
1937419335 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);
1937619339 if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {
1937719340 const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse {
1937819341 return sema.failWithNeededComptime(block, field_src, .{
......@@ -19386,7 +19349,7 @@ fn zirStructInit(
1938619349 };
1938719350 }
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);
1939019353 } else if (resolved_ty.zigTypeTag(mod) == .Union) {
1939119354 if (extra.data.fields_len != 1) {
1939219355 return sema.fail(block, src, "union initialization expects exactly one field", .{});
......@@ -19401,36 +19364,60 @@ fn zirStructInit(
1940119364 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
1940219365 const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
1940319366 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);
1940619385 if (try sema.resolveMaybeUndefVal(init_inst)) |val| {
19407 const field_ty = mod.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index].toType();
19408 return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{
19386 const struct_val = (try mod.intern(.{ .un = .{
1940919387 .ty = resolved_ty.toIntern(),
1941019388 .tag = try tag_val.intern(tag_ty, mod),
1941119389 .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 });
1941319400 }
1941419401
1941519402 if (is_ref) {
1941619403 const target = mod.getTarget();
1941719404 const alloc_ty = try sema.ptrType(.{
19418 .child = resolved_ty.toIntern(),
19405 .child = result_ty.toIntern(),
1941919406 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1942019407 });
1942119408 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);
1942319411 try sema.storePtr(block, src, field_ptr, init_inst);
1942419412 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);
1942619414 return sema.makePtrConst(block, alloc);
1942719415 }
1942819416
1942919417 try sema.requireRuntimeBlock(block, src, null);
1943019418 try sema.queueFullTypeResolution(resolved_ty);
19431 return block.addUnionInit(resolved_ty, field_index, init_inst);
19432 } else if (resolved_ty.isAnonStruct(mod)) {
19433 return sema.fail(block, src, "TODO anon struct init validation", .{});
19419 const union_val = try block.addUnionInit(resolved_ty, field_index, init_inst);
19420 return sema.coerce(block, result_ty, union_val, src);
1943419421 }
1943519422 unreachable;
1943619423}
......@@ -19442,6 +19429,7 @@ fn finishStructInit(
1944219429 dest_src: LazySrcLoc,
1944319430 field_inits: []Air.Inst.Ref,
1944419431 struct_ty: Type,
19432 result_ty: Type,
1944519433 is_ref: bool,
1944619434) CompileError!Air.Inst.Ref {
1944719435 const mod = sema.mod;
......@@ -19452,8 +19440,24 @@ fn finishStructInit(
1945219440
1945319441 switch (ip.indexToKey(struct_ty.toIntern())) {
1945419442 .anon_struct_type => |anon_struct| {
19455 for (anon_struct.values.get(ip), 0..) |default_val, i| {
19456 if (field_inits[i] != .none) continue;
19443 // We can't get the slices, as the coercion may invalidate them.
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
1945819462 if (default_val == .none) {
1945919463 if (anon_struct.names.len == 0) {
......@@ -19480,7 +19484,20 @@ fn finishStructInit(
1948019484 },
1948119485 .struct_type => |struct_type| {
1948219486 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
1948519502 const field_init = struct_type.fieldInit(ip, i);
1948619503 if (field_init == .none) {
......@@ -19524,29 +19541,39 @@ fn finishStructInit(
1952419541
1952519542 const runtime_index = opt_runtime_index orelse {
1952619543 const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
19527 for (elems, field_inits, 0..) |*elem, field_init, field_i| {
19528 elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).?
19529 .intern(struct_ty.structFieldType(field_i, mod), mod);
19544 for (elems, field_inits) |*elem, field_init| {
19545 elem.* = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?.toIntern();
1953019546 }
1953119547 const struct_val = try mod.intern(.{ .aggregate = .{
1953219548 .ty = struct_ty.toIntern(),
1953319549 .storage = .{ .elems = elems },
1953419550 } });
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);
1953619554 };
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
1953819564 if (is_ref) {
1953919565 try sema.resolveStructLayout(struct_ty);
1954019566 const target = sema.mod.getTarget();
1954119567 const alloc_ty = try sema.ptrType(.{
19542 .child = struct_ty.toIntern(),
19568 .child = result_ty.toIntern(),
1954319569 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1954419570 });
1954519571 const alloc = try block.addTy(.alloc, alloc_ty);
19572 const base_ptr = try sema.optEuBasePtrInit(block, alloc, init_src);
1954619573 for (field_inits, 0..) |field_init, i_usize| {
1954719574 const i: u32 = @intCast(i_usize);
1954819575 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);
1955019577 try sema.storePtr(block, dest_src, field_ptr, field_init);
1955119578 }
1955219579
......@@ -19563,19 +19590,19 @@ fn finishStructInit(
1956319590 else => |e| return e,
1956419591 };
1956519592 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);
1956719595}
1956819596
1956919597fn zirStructInitAnon(
1957019598 sema: *Sema,
1957119599 block: *Block,
1957219600 inst: Zir.Inst.Index,
19573 is_ref: bool,
1957419601) CompileError!Air.Inst.Ref {
1957519602 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1957619603 const src = inst_data.src();
1957719604 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);
1957919606}
1958019607
1958119608fn structInitAnon(
......@@ -19748,13 +19775,14 @@ fn zirArrayInit(
1974819775 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
1974919776 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) {
1975219779 error.GenericPoison => {
1975319780 // The type wasn't actually known, so treat this as an anon array init.
1975419781 return sema.arrayInitAnon(block, src, args[1..], is_ref);
1975519782 },
1975619783 else => |e| return e,
1975719784 };
19785 const array_ty = result_ty.optEuBaseType(mod);
1975819786 const is_tuple = array_ty.zigTypeTag(mod) == .Struct;
1975919787 const sentinel_val = array_ty.sentinel(mod);
1976019788
......@@ -19810,10 +19838,12 @@ fn zirArrayInit(
1981019838 // We checked that all args are comptime above.
1981119839 val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod);
1981219840 }
19813 return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{
19841 const arr_val = try mod.intern(.{ .aggregate = .{
1981419842 .ty = array_ty.toIntern(),
1981519843 .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);
1981719847 };
1981819848
1981919849 sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
......@@ -19830,10 +19860,11 @@ fn zirArrayInit(
1983019860 if (is_ref) {
1983119861 const target = mod.getTarget();
1983219862 const alloc_ty = try sema.ptrType(.{
19833 .child = array_ty.toIntern(),
19863 .child = result_ty.toIntern(),
1983419864 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1983519865 });
1983619866 const alloc = try block.addTy(.alloc, alloc_ty);
19867 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
1983719868
1983819869 if (array_ty.isTuple(mod)) {
1983919870 for (resolved_args, 0..) |arg, i| {
......@@ -19844,7 +19875,7 @@ fn zirArrayInit(
1984419875 const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());
1984519876
1984619877 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);
1984819879 _ = try block.addBinOp(.store, elem_ptr, arg);
1984919880 }
1985019881 return sema.makePtrConst(block, alloc);
......@@ -19858,26 +19889,26 @@ fn zirArrayInit(
1985819889
1985919890 for (resolved_args, 0..) |arg, i| {
1986019891 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);
1986219893 _ = try block.addBinOp(.store, elem_ptr, arg);
1986319894 }
1986419895 return sema.makePtrConst(block, alloc);
1986519896 }
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);
1986819900}
1986919901
1987019902fn zirArrayInitAnon(
1987119903 sema: *Sema,
1987219904 block: *Block,
1987319905 inst: Zir.Inst.Index,
19874 is_ref: bool,
1987519906) CompileError!Air.Inst.Ref {
1987619907 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1987719908 const src = inst_data.src();
1987819909 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
1987919910 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);
1988119912}
1988219913
1988319914fn arrayInitAnon(
......@@ -19997,14 +20028,14 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
1999720028 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
1999820029}
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 {
2000120032 const mod = sema.mod;
2000220033 const ip = &mod.intern_pool;
2000320034 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2000420035 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
2000520036 const ty_src = inst_data.src();
2000620037 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) {
2000820039 // Since this is a ZIR instruction that returns a type, encountering
2000920040 // generic poison should not result in a failed compilation, but the
2001020041 // generic poison type. This prevents unnecessary failures when
......@@ -20012,6 +20043,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2001220043 error.GenericPoison => return .generic_poison_type,
2001320044 else => |e| return e,
2001420045 };
20046 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(mod);
2001520047 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
2001620048 const field_name = try ip.getOrPutString(sema.gpa, zir_field_name);
2001720049 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
......@@ -20033,7 +20065,10 @@ fn fieldType(
2003320065 switch (cur_ty.zigTypeTag(mod)) {
2003420066 .Struct => switch (ip.indexToKey(cur_ty.toIntern())) {
2003520067 .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);
2003720072 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
2003820073 },
2003920074 .struct_type => |struct_type| {
......@@ -21620,7 +21655,8 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2162021655 const operand_coerced = try sema.coerce(block, operand_ty, operand_res, operand_src);
2162121656
2162221657 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
2162421660 const elem_ty = ptr_ty.elemType2(mod);
2162521661 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
2162621662
......@@ -21860,7 +21896,7 @@ fn ptrCastFull(
2186021896 const mod = sema.mod;
2186121897 const operand_ty = sema.typeOf(operand);
2186221898
21863 try sema.checkPtrType(block, src, dest_ty);
21899 try sema.checkPtrType(block, src, dest_ty, true);
2186421900 try sema.checkPtrOperand(block, operand_src, operand_ty);
2186521901
2186621902 const src_info = operand_ty.ptrInfo(mod);
......@@ -22668,10 +22704,11 @@ fn checkPtrType(
2266822704 block: *Block,
2266922705 ty_src: LazySrcLoc,
2267022706 ty: Type,
22707 allow_slice: bool,
2267122708) CompileError!void {
2267222709 const mod = sema.mod;
2267322710 switch (ty.zigTypeTag(mod)) {
22674 .Pointer => return,
22711 .Pointer => if (allow_slice or !ty.isSlice(mod)) return,
2267522712 .Fn => {
2267622713 const msg = msg: {
2267722714 const msg = try sema.errMsg(
......@@ -29577,13 +29614,6 @@ fn storePtr2(
2957729614 return;
2957829615 }
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
2958729617 try sema.requireRuntimeBlock(block, src, runtime_src);
2958829618 try sema.queueFullTypeResolution(elem_ty);
2958929619
......@@ -29719,6 +29749,7 @@ fn storePtrVal(
2971929749 switch (mut_kit.pointee) {
2972029750 .direct => |val_ptr| {
2972129751 if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
29752 val_ptr.* = (try val_ptr.intern(operand_ty, mod)).toValue();
2972229753 if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
2972329754 // TODO use failWithInvalidComptimeFieldStore
2972429755 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 {
242242 /// Uses the `pl_node` union field with `Bin` payload.
243243 /// lhs is length, rhs is element type.
244244 vector_type,
245 /// Given an indexable type, returns the type of the element at given index.
246 /// Uses the `bin` union field. lhs is the indexable type, rhs is the index.
247 elem_type_index,
248 /// Given a pointer type, returns its element type.
245 /// Given a pointer type, returns its element type. Reaches through any optional or error
246 /// union types wrapping the pointer. Asserts that the underlying type is a pointer type.
247 /// Returns generic poison if the element type is `anyopaque`.
249248 /// Uses the `un_node` field.
250249 elem_type,
251250 /// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its
......@@ -353,11 +352,6 @@ pub const Inst = struct {
353352 /// `!=`
354353 /// Uses the `pl_node` union field. Payload is `Bin`.
355354 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,
361355 /// Conditional branch. Splits control flow based on a boolean condition value.
362356 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
363357 /// Payload is `CondBr`.
......@@ -419,13 +413,6 @@ pub const Inst = struct {
419413 /// Payload is `Bin`.
420414 /// No OOB safety check is emitted.
421415 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,
429416 /// Given an array, slice, or pointer, returns the element at the provided index.
430417 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
431418 elem_val_node,
......@@ -463,8 +450,6 @@ pub const Inst = struct {
463450 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
464451 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
465452 field_ptr,
466 /// Same as `field_ptr` but used for struct init.
467 field_ptr_init,
468453 /// Given a struct or object that contains virtual fields, returns the named field.
469454 /// The field name is stored in string_bytes. Used by a.b syntax.
470455 /// This instruction also accepts a pointer.
......@@ -688,84 +673,123 @@ pub const Inst = struct {
688673 /// A switch expression. Uses the `pl_node` union field.
689674 /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer.
690675 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,
729676 /// Check that operand type supports the dereference operand (.*).
730677 /// Uses the `un_node` field.
731678 validate_deref,
732679 /// Check that the operand's type is an array or tuple with the given number of elements.
733680 /// Uses the `pl_node` field. Payload is `ValidateDestructure`.
734681 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,
741682 /// Given a struct or union, and a field name as a Ref,
742683 /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`.
743684 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,
744716 /// 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.
746720 /// Uses the `pl_node` field. Payload is `StructInit`.
747721 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.
749724 /// Uses the `pl_node` field. Payload is `StructInit`.
750725 struct_init_ref,
751 /// Struct initialization without a type.
752 /// Uses the `pl_node` field. Payload is `StructInitAnon`.
753 struct_init_anon,
754 /// Anonymous struct initialization syntax, make the result a pointer.
755 /// Uses the `pl_node` field. Payload is `StructInitAnon`.
756 struct_init_anon_ref,
757 /// Array initialization syntax.
758 /// Uses the `pl_node` field. Payload is `MultiOp`.
759 array_init,
760 /// Anonymous array initialization syntax.
726 /// Checks that the type supports struct init syntax. Always returns void.
727 /// Uses the `un_node` field.
728 validate_struct_init_ty,
729 /// Like `validate_struct_init_ty`, but additionally accepts types which structs coerce to.
730 /// Used on the known result type of a struct init expression. Always returns void.
731 /// Uses the `un_node` field.
732 validate_struct_init_result_ty,
733 /// Given a set of `struct_init_field_ptr` instructions, assumes they are all part of a
734 /// struct initialization expression, and emits compile errors for duplicate fields as well
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.
761752 /// Uses the `pl_node` field. Payload is `MultiOp`.
762753 array_init_anon,
763 /// Array initialization syntax, make the result a pointer.
764 /// Uses the `pl_node` field. Payload is `MultiOp`.
754 /// Array initialization syntax with a known type. The given type must be validated prior to
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.
765761 array_init_ref,
766 /// Anonymous array initialization syntax, make the result a pointer.
767 /// Uses the `pl_node` field. Payload is `MultiOp`.
768 array_init_anon_ref,
762 /// Checks that the type supports array init syntax. Always returns void.
763 /// Uses the `pl_node` field. Payload is `ArrayInit`.
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
769793 /// Implements the `@unionInit` builtin.
770794 /// Uses the `pl_node` field. Payload is `UnionInit`.
771795 union_init,
......@@ -1038,7 +1062,6 @@ pub const Inst = struct {
10381062 .array_type,
10391063 .array_type_sentinel,
10401064 .vector_type,
1041 .elem_type_index,
10421065 .elem_type,
10431066 .indexable_ptr_elem_type,
10441067 .vector_elem_type,
......@@ -1066,7 +1089,6 @@ pub const Inst = struct {
10661089 .cmp_gte,
10671090 .cmp_gt,
10681091 .cmp_neq,
1069 .coerce_result_ptr,
10701092 .error_set_decl,
10711093 .error_set_decl_anon,
10721094 .error_set_decl_func,
......@@ -1082,7 +1104,6 @@ pub const Inst = struct {
10821104 .elem_ptr,
10831105 .elem_val,
10841106 .elem_ptr_node,
1085 .elem_ptr_imm,
10861107 .elem_val_node,
10871108 .elem_val_imm,
10881109 .ensure_result_used,
......@@ -1091,7 +1112,6 @@ pub const Inst = struct {
10911112 .@"export",
10921113 .export_value,
10931114 .field_ptr,
1094 .field_ptr_init,
10951115 .field_val,
10961116 .field_ptr_named,
10971117 .field_val_named,
......@@ -1154,25 +1174,9 @@ pub const Inst = struct {
11541174 .set_eval_branch_quota,
11551175 .switch_block,
11561176 .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,
11631177 .validate_deref,
11641178 .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,
11741179 .union_init,
1175 .field_type,
11761180 .field_type_ref,
11771181 .enum_from_int,
11781182 .int_from_enum,
......@@ -1254,7 +1258,29 @@ pub const Inst = struct {
12541258 .save_err_ret_index,
12551259 .restore_err_ret_index,
12561260 .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,
12581284 => false,
12591285
12601286 .@"break",
......@@ -1307,10 +1333,6 @@ pub const Inst = struct {
13071333 .store_node,
13081334 .store_to_inferred_ptr,
13091335 .resolve_inferred_alloc,
1310 .validate_array_init_ty,
1311 .validate_struct_init_ty,
1312 .validate_struct_init,
1313 .validate_array_init,
13141336 .validate_deref,
13151337 .validate_destructure,
13161338 .@"export",
......@@ -1323,6 +1345,13 @@ pub const Inst = struct {
13231345 .defer_err_code,
13241346 .restore_err_ret_index,
13251347 .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,
13261355 => true,
13271356
13281357 .param,
......@@ -1346,7 +1375,6 @@ pub const Inst = struct {
13461375 .array_type,
13471376 .array_type_sentinel,
13481377 .vector_type,
1349 .elem_type_index,
13501378 .elem_type,
13511379 .indexable_ptr_elem_type,
13521380 .vector_elem_type,
......@@ -1374,7 +1402,6 @@ pub const Inst = struct {
13741402 .cmp_gte,
13751403 .cmp_gt,
13761404 .cmp_neq,
1377 .coerce_result_ptr,
13781405 .error_set_decl,
13791406 .error_set_decl_anon,
13801407 .error_set_decl_func,
......@@ -1385,11 +1412,9 @@ pub const Inst = struct {
13851412 .elem_ptr,
13861413 .elem_val,
13871414 .elem_ptr_node,
1388 .elem_ptr_imm,
13891415 .elem_val_node,
13901416 .elem_val_imm,
13911417 .field_ptr,
1392 .field_ptr_init,
13931418 .field_val,
13941419 .field_ptr_named,
13951420 .field_val_named,
......@@ -1447,19 +1472,7 @@ pub const Inst = struct {
14471472 .typeof_log2_int_type,
14481473 .switch_block,
14491474 .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,
14611475 .union_init,
1462 .field_type,
14631476 .field_type_ref,
14641477 .enum_from_int,
14651478 .int_from_enum,
......@@ -1546,7 +1559,22 @@ pub const Inst = struct {
15461559 .for_len,
15471560 .@"try",
15481561 .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,
15501578 => false,
15511579
15521580 .extended => switch (data.extended.opcode) {
......@@ -1580,7 +1608,6 @@ pub const Inst = struct {
15801608 .array_type = .pl_node,
15811609 .array_type_sentinel = .pl_node,
15821610 .vector_type = .pl_node,
1583 .elem_type_index = .bin,
15841611 .elem_type = .un_node,
15851612 .indexable_ptr_elem_type = .un_node,
15861613 .vector_elem_type = .un_node,
......@@ -1612,7 +1639,6 @@ pub const Inst = struct {
16121639 .cmp_gte = .pl_node,
16131640 .cmp_gt = .pl_node,
16141641 .cmp_neq = .pl_node,
1615 .coerce_result_ptr = .pl_node,
16161642 .condbr = .pl_node,
16171643 .condbr_inline = .pl_node,
16181644 .@"try" = .pl_node,
......@@ -1631,7 +1657,6 @@ pub const Inst = struct {
16311657 .div = .pl_node,
16321658 .elem_ptr = .pl_node,
16331659 .elem_ptr_node = .pl_node,
1634 .elem_ptr_imm = .pl_node,
16351660 .elem_val = .pl_node,
16361661 .elem_val_node = .pl_node,
16371662 .elem_val_imm = .elem_val_imm,
......@@ -1643,7 +1668,6 @@ pub const Inst = struct {
16431668 .@"export" = .pl_node,
16441669 .export_value = .pl_node,
16451670 .field_ptr = .pl_node,
1646 .field_ptr_init = .pl_node,
16471671 .field_val = .pl_node,
16481672 .field_ptr_named = .pl_node,
16491673 .field_val_named = .pl_node,
......@@ -1701,30 +1725,16 @@ pub const Inst = struct {
17011725 .enum_literal = .str_tok,
17021726 .switch_block = .pl_node,
17031727 .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,
17111728 .validate_deref = .un_node,
17121729 .validate_destructure = .pl_node,
1713 .struct_init_empty = .un_node,
1714 .field_type = .pl_node,
17151730 .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,
17241731 .union_init = .pl_node,
17251732 .type_info = .un_node,
17261733 .size_of = .un_node,
17271734 .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
17291739 .int_from_ptr = .un_node,
17301740 .compile_error = .un_node,
......@@ -1826,6 +1836,27 @@ pub const Inst = struct {
18261836 .save_err_ret_index = .save_err_ret_index,
18271837 .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
18291860 .extended = .extended,
18301861 });
18311862 };
......@@ -2771,6 +2802,11 @@ pub const Inst = struct {
27712802 };
27722803 };
27732804
2805 pub const ArrayInitRefTy = struct {
2806 ptr_ty: Ref,
2807 elem_count: u32,
2808 };
2809
27742810 pub const Field = struct {
27752811 lhs: Ref,
27762812 /// Offset into `string_bytes`.
......@@ -3064,9 +3100,10 @@ pub const Inst = struct {
30643100 fields_len: u32,
30653101
30663102 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.
30683104 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.
30703107 init: Ref,
30713108 };
30723109 };
src/print_zir.zig+51-29
......@@ -205,8 +205,6 @@ const Writer = struct {
205205 .store_to_inferred_ptr,
206206 => try self.writeBin(stream, inst),
207207
208 .elem_type_index => try self.writeElemTypeIndex(stream, inst),
209
210208 .alloc,
211209 .alloc_mut,
212210 .alloc_comptime_mut,
......@@ -241,7 +239,6 @@ const Writer = struct {
241239 .is_non_err_ptr,
242240 .ret_is_non_err,
243241 .typeof,
244 .struct_init_empty,
245242 .type_info,
246243 .size_of,
247244 .bit_size_of,
......@@ -281,18 +278,16 @@ const Writer = struct {
281278 .bit_reverse,
282279 .@"resume",
283280 .@"await",
284 .array_base_ptr,
285 .field_base_ptr,
286 .validate_struct_init_ty,
287281 .make_ptr_const,
288282 .validate_deref,
289283 .check_comptime_control_flow,
290 .opt_eu_base_ty,
284 .opt_eu_base_ptr_init,
291285 => try self.writeUnNode(stream, inst),
292286
293287 .ref,
294288 .ret_implicit,
295289 .closure_capture,
290 .validate_ref_ty,
296291 => try self.writeUnTok(stream, inst),
297292
298293 .bool_br_and,
......@@ -300,7 +295,6 @@ const Writer = struct {
300295 => try self.writeBoolBr(stream, inst),
301296
302297 .validate_destructure => try self.writeValidateDestructure(stream, inst),
303 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
304298 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
305299 .ptr_type => try self.writePtrType(stream, inst),
306300 .int => try self.writeInt(stream, inst),
......@@ -316,12 +310,6 @@ const Writer = struct {
316310 .@"break",
317311 .break_inline,
318312 => try self.writeBreak(stream, inst),
319 .array_init,
320 .array_init_ref,
321 => try self.writeArrayInit(stream, inst),
322 .array_init_anon,
323 .array_init_anon_ref,
324 => try self.writeArrayInitAnon(stream, inst),
325313
326314 .slice_start => try self.writeSliceStart(stream, inst),
327315 .slice_end => try self.writeSliceEnd(stream, inst),
......@@ -330,10 +318,44 @@ const Writer = struct {
330318
331319 .union_init => try self.writeUnionInit(stream, inst),
332320
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
333330 .struct_init,
334331 .struct_init_ref,
335332 => try self.writeStructInit(stream, inst),
336333
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
337359 .atomic_load => try self.writeAtomicLoad(stream, inst),
338360 .atomic_store => try self.writeAtomicStore(stream, inst),
339361 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
......@@ -342,11 +364,6 @@ const Writer = struct {
342364 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst),
343365 .builtin_call => try self.writeBuiltinCall(stream, inst),
344366
345 .struct_init_anon,
346 .struct_init_anon_ref,
347 => try self.writeStructInitAnon(stream, inst),
348
349 .field_type => try self.writeFieldType(stream, inst),
350367 .field_type_ref => try self.writeFieldTypeRef(stream, inst),
351368
352369 .add,
......@@ -409,16 +426,14 @@ const Writer = struct {
409426 .elem_val_node,
410427 .elem_ptr,
411428 .elem_val,
412 .coerce_result_ptr,
413429 .array_type,
430 .coerce_ptr_elem_ty,
414431 => try self.writePlNodeBin(stream, inst),
415432
416433 .for_len => try self.writePlNodeMultiOp(stream, inst),
417434
418435 .elem_val_imm => try self.writeElemValImm(stream, inst),
419436
420 .elem_ptr_imm => try self.writeElemPtrImm(stream, inst),
421
422437 .@"export" => try self.writePlNodeExport(stream, inst),
423438 .export_value => try self.writePlNodeExportValue(stream, inst),
424439
......@@ -430,8 +445,6 @@ const Writer = struct {
430445 .block_inline,
431446 .suspend_block,
432447 .loop,
433 .validate_struct_init,
434 .validate_array_init,
435448 .c_import,
436449 .typeof_builtin,
437450 => try self.writeBlock(stream, inst),
......@@ -452,9 +465,8 @@ const Writer = struct {
452465 .switch_block_ref,
453466 => try self.writeSwitchBlock(stream, inst),
454467
455 .field_ptr,
456 .field_ptr_init,
457468 .field_val,
469 .field_ptr,
458470 => try self.writePlNodeField(stream, inst),
459471
460472 .field_ptr_named,
......@@ -617,7 +629,7 @@ const Writer = struct {
617629 try stream.writeByte(')');
618630 }
619631
620 fn writeElemTypeIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
632 fn writeArrayInitElemType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
621633 const inst_data = self.code.instructions.items(.data)[inst].bin;
622634 try self.writeInstRef(stream, inst_data.lhs);
623635 try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});
......@@ -972,7 +984,7 @@ const Writer = struct {
972984 try stream.print(", {d})", .{inst_data.idx});
973985 }
974986
975 fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
987 fn writeArrayInitElemPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
976988 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
977989 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
978990
......@@ -1004,6 +1016,16 @@ const Writer = struct {
10041016 try self.writeSrc(stream, inst_data.src());
10051017 }
10061018
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
10071029 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
10081030 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
10091031 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
......@@ -1134,7 +1156,7 @@ const Writer = struct {
11341156 try self.writeSrc(stream, inst_data.src());
11351157 }
11361158
1137 fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1159 fn writeStructInitFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
11381160 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
11391161 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
11401162 try self.writeInstRef(stream, extra.container_type);
src/type.zig+11
......@@ -3182,6 +3182,17 @@ pub const Type = struct {
31823182 };
31833183 }
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
31853196 pub const @"u1": Type = .{ .ip_index = .u1_type };
31863197 pub const @"u8": Type = .{ .ip_index = .u8_type };
31873198 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" {
780780 try expectEqual([4]u4{ 1, 2, 4, 8 }, init);
781781 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
782782}
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/cast.zig+26
......@@ -2493,3 +2493,29 @@ test "@as does not corrupt values with incompatible representations" {
24932493 });
24942494 try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001);
24952495}
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" {
548548 const casted = S.func(&bases);
549549 try expect(casted[0].a == 2);
550550}
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" {
17601760 try expectEqual(S{ .a = 1, .b = 2, .c = 4, .d = 8 }, init);
17611761 try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects);
17621762}
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 {
1616// backend=stage2
1717// target=native
1818//
19// :7:14: error: runtime-known argument passed to parameter of comptime-only type
20// :9:12: note: declared here
21// :4:16: note: struct requires comptime because of this field
22// :4:16: note: types are not available at runtime
19// :7:25: error: unable to resolve comptime value
20// :7:25: note: initializer of comptime only struct must be comptime-known
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 {
1818// backend=stage2
1919// target=native
2020//
21// :11:27: error: expected type 'u8', found '?u8'
22// :11:27: note: cannot convert optional to payload type
23// :11:27: note: consider using '.?', 'orelse', or 'if'
21// :11:20: error: expected type 'u8', found '?u8'
22// :11:20: note: cannot convert optional to payload type
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 {
1010export fn d() void {
1111 bar(@floatFromInt(123));
1212}
13export fn f() void {
14 bar(.{
15 .x = @intCast(123),
16 });
17}
1318
1419fn bar(_: anytype) void {}
1520
......@@ -18,14 +23,17 @@ fn bar(_: anytype) void {}
1823// target=native
1924//
2025// :2:9: error: @ptrFromInt must have a known result type
21// :2:9: note: result type is unknown due to anytype parameter
26// :2:8: note: result type is unknown due to anytype parameter
2227// :2:9: note: use @as to provide explicit result type
2328// :5:9: error: @ptrCast must have a known result type
24// :5:9: note: result type is unknown due to anytype parameter
29// :5:8: note: result type is unknown due to anytype parameter
2530// :5:9: note: use @as to provide explicit result type
2631// :8:9: error: @intCast must have a known result type
27// :8:9: note: result type is unknown due to anytype parameter
32// :8:8: note: result type is unknown due to anytype parameter
2833// :8:9: note: use @as to provide explicit result type
2934// :11:9: error: @floatFromInt must have a known result type
30// :11:9: note: result type is unknown due to anytype parameter
35// :11:8: note: result type is unknown due to anytype parameter
3136// :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 {
3131// :2:13: error: expected type 'usize', found '*const [5:0]u8'
3232// :7:10: error: type 'usize' cannot represent integer value '-1'
3333// :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
3536// :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 {
7171// target=native
7272// backend=stage2
7373//
74// :6:19: 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 field
74// :6:9: error: value stored in comptime field does not match the default value of the field
75// :14:9: error: value stored in comptime field does not match the default value of the field
7676// :19:38: error: value stored in comptime field does not match the default value of the field
7777// :31:19: error: value stored in comptime field does not match the default value of the field
7878// :25:29: note: default value set here
......@@ -80,5 +80,6 @@ pub export fn entry8() void {
8080// :35:29: note: default value set here
8181// :45:12: error: value stored in comptime field does not match the default value of the field
8282// :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 field
84// :59:35: error: value stored in comptime field does not match the default value of the field
83// :66:36: error: value stored in comptime field does not match the default value of the field
84// :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 {
1515// backend=llvm
1616// target=native
1717//
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 {
3939// :8:25: note: type 'i32' here
4040// :16:16: error: expected type 'tmp.h.T', found 'void'
4141// :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 {
1616// backend=stage2
1717// target=native
1818//
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'
2020// :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'
2222// :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'
2424// :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 {
99// backend=llvm
1010// target=native
1111//
12// :2:15: error: cannot assign to constant
12// :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 {
1212// backend=stage2
1313// target=native
1414//
15// :5:10: error: cannot assign to constant
15// :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 {
1818// backend=stage2
1919// target=native
2020//
21// :12:25: 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 type
23// :12:25: note: consider using 'try', 'catch', or 'if'
21// :12:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
22// :12:15: note: cannot convert error union to payload type
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 {
1515// backend=stage2
1616// target=native
1717//
18// :3:36: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type
20// :3:36: note: consider using '.?', 'orelse', or 'if'
18// :3:23: error: expected type 'i32', found '?i32'
19// :3:23: note: cannot convert optional to payload type
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 {
1515// backend=stage2
1616// target=native
1717//
18// :3:36: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type
20// :3:36: note: consider using '.?', 'orelse', or 'if'
18// :3:23: error: expected type 'i32', found '?i32'
19// :3:23: note: cannot convert optional to payload type
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 {
1818// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
1919// :5:12: note: struct declared here
2020// :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 {
1212// backend=stage2
1313// target=native
1414//
15// :7:29: error: unable to resolve comptime value
16// :7:29: note: initializer of comptime only struct must be comptime-known
15// :7:23: error: unable to resolve comptime value
16// :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 {
1212// backend=stage2
1313// target=native
1414//
15// :7:29: error: unable to resolve comptime value
16// :7:29: note: initializer of comptime only union must be comptime-known
15// :7:23: error: unable to resolve comptime value
16// :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 {
77// backend=stage2
88// target=native
99//
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 @@
1export fn entry() void {
1export fn entry1() void {
22 const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
33 _ = y;
44}
5export fn entry2() void {
6 const x: [:2]const u8 = &.{ 1, 2 };
7 const y: [:1]const u8 = x;
8 _ = y;
9}
510
611// error
712// backend=stage2
813// target=native
914//
10// :2:29: error: expected type '[:1]const u8', found '*const [2:2]u8'
11// :2:29: note: pointer sentinel '2' cannot cast into pointer sentinel '1'
15// :2:37: error: expected type '[2:1]u8', found '[2:2]u8'
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 {
2828// target=native
2929//
3030// :10:20: error: union initializer must initialize one field
31// :1:12: note: union declared here
3231// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field
3332// :14:31: note: additional initializer here
3433// :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 {
3232// backend=stage2
3333// target=native
3434//
35// :11:21: error: cannot initialize 'noreturn' field of union
35// :11:14: error: cannot initialize 'noreturn' field of union
3636// :4:9: note: field 'b' declared here
3737// :2:15: note: union declared here
3838// :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 {
77// backend=stage2
88// target=native
99//
10// :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32'
10// :3:41: error: expected type 'builtin.GlobalLinkage', found 'u32'
1111// :?:?: note: enum declared here
test/compile_errors.zig+2-4
......@@ -207,10 +207,8 @@ pub fn addCases(ctx: *Cases) !void {
207207 ":1:38: note: declared comptime here",
208208 ":8:36: error: runtime-known argument passed to comptime parameter",
209209 ":2:41: note: declared comptime here",
210 ":13:29: error: runtime-known argument passed to parameter of comptime-only type",
211 ":3:24: note: declared here",
212 ":12:35: note: struct requires comptime because of this field",
213 ":12:35: note: types are not available at runtime",
210 ":13:32: error: unable to resolve comptime value",
211 ":13:32: note: initializer of comptime only struct must be comptime-known",
214212 });
215213
216214 case.addSourceFile("import.zig",