| author | |
| committer | |
| log | df5f0517b33b5f7bc2a508cf6a0ee62246f02d21 |
| tree | 64d664b74afd6d100be328b7225b87753bf62fd7 |
| parent | a9f25c7d642ec0ed047ae9be6ad87d102f3f75c8 |
| parent | 9ff872c9829c20cb16d233534248c5cf371a8bd9 |
| signature |
compiler: preserve result type information through address-of operator39 files changed, 1335 insertions(+), 1029 deletions(-)
lib/std/debug.zig+6-1| ... | ... | @@ -514,7 +514,12 @@ pub const StackIterator = struct { |
| 514 | 514 | |
| 515 | 515 | return StackIterator{ |
| 516 | 516 | .first_address = first_address, |
| 517 | .fp = fp orelse @frameAddress(), | |
| 517 | // TODO: this is a workaround for #16876 | |
| 518 | //.fp = fp orelse @frameAddress(), | |
| 519 | .fp = fp orelse blk: { | |
| 520 | const fa = @frameAddress(); | |
| 521 | break :blk fa; | |
| 522 | }, | |
| 518 | 523 | }; |
| 519 | 524 | } |
| 520 | 525 |
src/AstGen.zig+318-305| ... | ... | @@ -265,14 +265,17 @@ const ResultInfo = struct { |
| 265 | 265 | discard, |
| 266 | 266 | /// The expression has an inferred type, and it will be evaluated as an rvalue. |
| 267 | 267 | none, |
| 268 | /// The expression must generate a pointer rather than a value. For example, the left hand side | |
| 269 | /// of an assignment uses this kind of result location. | |
| 270 | ref, | |
| 271 | 268 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 272 | 269 | ty: Zir.Inst.Ref, |
| 273 | 270 | /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, |
| 274 | 271 | /// so no `as` instruction needs to be emitted. |
| 275 | 272 | coerced_ty: Zir.Inst.Ref, |
| 273 | /// The expression must generate a pointer rather than a value. For example, the left hand side | |
| 274 | /// of an assignment uses this kind of result location. | |
| 275 | ref, | |
| 276 | /// The expression must generate a pointer rather than a value, and the pointer will be coerced | |
| 277 | /// by other code to this type, which is guaranteed by earlier instructions to be a pointer type. | |
| 278 | ref_coerced_ty: Zir.Inst.Ref, | |
| 276 | 279 | /// The expression must store its result into this typed pointer. The result instruction |
| 277 | 280 | /// from the expression must be ignored. |
| 278 | 281 | ptr: PtrResultLoc, |
| ... | ... | @@ -303,26 +306,30 @@ const ResultInfo = struct { |
| 303 | 306 | /// Find the result type for a cast builtin given the result location. |
| 304 | 307 | /// If the location does not have a known result type, emits an error on |
| 305 | 308 | /// 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), | |
| 311 | 314 | .ptr => |ptr| { |
| 312 | 315 | 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); | |
| 320 | 317 | }, |
| 321 | } | |
| 318 | }; | |
| 319 | } | |
| 322 | 320 | |
| 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 | } | |
| 326 | 333 | } |
| 327 | 334 | }; |
| 328 | 335 | |
| ... | ... | @@ -933,7 +940,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 933 | 940 | const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs); |
| 934 | 941 | _ = try gz.addUnNode(.validate_deref, lhs, node); |
| 935 | 942 | switch (ri.rl) { |
| 936 | .ref => return lhs, | |
| 943 | .ref, .ref_coerced_ty => return lhs, | |
| 937 | 944 | else => { |
| 938 | 945 | const result = try gz.addUnNode(.load, lhs, node); |
| 939 | 946 | return rvalue(gz, ri, result, node); |
| ... | ... | @@ -941,7 +948,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 941 | 948 | } |
| 942 | 949 | }, |
| 943 | 950 | .address_of => { |
| 944 | const result = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); | |
| 951 | const operand_rl: ResultInfo.Loc = if (try ri.rl.resultType(gz, node)) |res_ty_inst| rl: { | |
| 952 | _ = try gz.addUnTok(.validate_ref_ty, res_ty_inst, tree.firstToken(node)); | |
| 953 | break :rl .{ .ref_coerced_ty = res_ty_inst }; | |
| 954 | } else .ref; | |
| 955 | const result = try expr(gz, scope, .{ .rl = operand_rl }, node_datas[node].lhs); | |
| 945 | 956 | return rvalue(gz, ri, result, node); |
| 946 | 957 | }, |
| 947 | 958 | .optional_type => { |
| ... | ... | @@ -950,7 +961,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 950 | 961 | return rvalue(gz, ri, result, node); |
| 951 | 962 | }, |
| 952 | 963 | .unwrap_optional => switch (ri.rl) { |
| 953 | .ref => { | |
| 964 | .ref, .ref_coerced_ty => { | |
| 954 | 965 | const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); |
| 955 | 966 | |
| 956 | 967 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); |
| ... | ... | @@ -1001,7 +1012,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 1001 | 1012 | else |
| 1002 | 1013 | null; |
| 1003 | 1014 | switch (ri.rl) { |
| 1004 | .ref => return orelseCatchExpr( | |
| 1015 | .ref, .ref_coerced_ty => return orelseCatchExpr( | |
| 1005 | 1016 | gz, |
| 1006 | 1017 | scope, |
| 1007 | 1018 | ri, |
| ... | ... | @@ -1028,7 +1039,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 1028 | 1039 | } |
| 1029 | 1040 | }, |
| 1030 | 1041 | .@"orelse" => switch (ri.rl) { |
| 1031 | .ref => return orelseCatchExpr( | |
| 1042 | .ref, .ref_coerced_ty => return orelseCatchExpr( | |
| 1032 | 1043 | gz, |
| 1033 | 1044 | scope, |
| 1034 | 1045 | ri, |
| ... | ... | @@ -1432,73 +1443,75 @@ fn arrayInitExpr( |
| 1432 | 1443 | break :inst .{ array_type_inst, .none }; |
| 1433 | 1444 | }; |
| 1434 | 1445 | |
| 1446 | if (array_ty != .none) { | |
| 1447 | // Typed inits do not use RLS for language simplicity. | |
| 1448 | switch (ri.rl) { | |
| 1449 | .discard => { | |
| 1450 | if (elem_ty != .none) { | |
| 1451 | const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } }; | |
| 1452 | for (array_init.ast.elements) |elem_init| { | |
| 1453 | _ = try expr(gz, scope, elem_ri, elem_init); | |
| 1454 | } | |
| 1455 | } else { | |
| 1456 | for (array_init.ast.elements, 0..) |elem_init, i| { | |
| 1457 | const this_elem_ty = try gz.add(.{ | |
| 1458 | .tag = .array_init_elem_type, | |
| 1459 | .data = .{ .bin = .{ | |
| 1460 | .lhs = array_ty, | |
| 1461 | .rhs = @enumFromInt(i), | |
| 1462 | } }, | |
| 1463 | }); | |
| 1464 | _ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init); | |
| 1465 | } | |
| 1466 | } | |
| 1467 | return .void_value; | |
| 1468 | }, | |
| 1469 | .ref => return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, true), | |
| 1470 | else => { | |
| 1471 | const array_inst = try arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, false); | |
| 1472 | return rvalue(gz, ri, array_inst, node); | |
| 1473 | }, | |
| 1474 | } | |
| 1475 | } | |
| 1476 | ||
| 1435 | 1477 | switch (ri.rl) { |
| 1478 | .none => return arrayInitExprAnon(gz, scope, node, array_init.ast.elements), | |
| 1436 | 1479 | .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); | |
| 1457 | 1482 | } |
| 1458 | 1483 | return Zir.Inst.Ref.void_value; |
| 1459 | 1484 | }, |
| 1460 | 1485 | .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)); | |
| 1479 | 1488 | }, |
| 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); | |
| 1493 | 1513 | }, |
| 1494 | 1514 | .destructure => |destructure| { |
| 1495 | if (array_ty != .none) { | |
| 1496 | // We have a specific type, so there may be things like default | |
| 1497 | // field values messing with us. Do this as a standard typed | |
| 1498 | // init followed by an rvalue destructure. | |
| 1499 | const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, .array_init); | |
| 1500 | return rvalue(gz, ri, result, node); | |
| 1501 | } | |
| 1502 | 1515 | // Untyped init - destructure directly into result pointers |
| 1503 | 1516 | if (array_init.ast.elements.len != destructure.components.len) { |
| 1504 | 1517 | return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{ |
| ... | ... | @@ -1521,12 +1534,12 @@ fn arrayInitExpr( |
| 1521 | 1534 | } |
| 1522 | 1535 | } |
| 1523 | 1536 | |
| 1524 | fn arrayInitExprRlNone( | |
| 1537 | /// An array initialization expression using an `array_init_anon` instruction. | |
| 1538 | fn arrayInitExprAnon( | |
| 1525 | 1539 | gz: *GenZir, |
| 1526 | 1540 | scope: *Scope, |
| 1527 | 1541 | node: Ast.Node.Index, |
| 1528 | 1542 | elements: []const Ast.Node.Index, |
| 1529 | tag: Zir.Inst.Tag, | |
| 1530 | 1543 | ) InnerError!Zir.Inst.Ref { |
| 1531 | 1544 | const astgen = gz.astgen; |
| 1532 | 1545 | |
| ... | ... | @@ -1540,95 +1553,84 @@ fn arrayInitExprRlNone( |
| 1540 | 1553 | astgen.extra.items[extra_index] = @intFromEnum(elem_ref); |
| 1541 | 1554 | extra_index += 1; |
| 1542 | 1555 | } |
| 1543 | return try gz.addPlNodePayloadIndex(tag, node, payload_index); | |
| 1556 | return try gz.addPlNodePayloadIndex(.array_init_anon, node, payload_index); | |
| 1544 | 1557 | } |
| 1545 | 1558 | |
| 1546 | fn arrayInitExprInner( | |
| 1559 | /// An array initialization expression using an `array_init` or `array_init_ref` instruction. | |
| 1560 | fn arrayInitExprTyped( | |
| 1547 | 1561 | gz: *GenZir, |
| 1548 | 1562 | scope: *Scope, |
| 1549 | 1563 | node: Ast.Node.Index, |
| 1550 | 1564 | 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, | |
| 1554 | 1568 | ) InnerError!Zir.Inst.Ref { |
| 1555 | 1569 | const astgen = gz.astgen; |
| 1556 | 1570 | |
| 1557 | const len = elements.len + @intFromBool(array_ty_inst != .none); | |
| 1571 | const len = elements.len + 1; // +1 for type | |
| 1558 | 1572 | const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ |
| 1559 | 1573 | .operands_len = @intCast(len), |
| 1560 | 1574 | }); |
| 1561 | 1575 | 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; | |
| 1566 | 1578 | |
| 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, | |
| 1573 | 1590 | .data = .{ .bin = .{ |
| 1574 | .lhs = array_ty_inst, | |
| 1591 | .lhs = ty_inst, | |
| 1575 | 1592 | .rhs = @enumFromInt(i), |
| 1576 | 1593 | } }, |
| 1577 | }); | |
| 1578 | break :ri ResultInfo{ .rl = .{ .coerced_ty = ty_expr } }; | |
| 1579 | } else ResultInfo{ .rl = .{ .none = {} } }; | |
| 1594 | }) } }; | |
| 1580 | 1595 | |
| 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 | } | |
| 1584 | 1600 | } |
| 1585 | 1601 | |
| 1602 | const tag: Zir.Inst.Tag = if (is_ref) .array_init_ref else .array_init; | |
| 1586 | 1603 | return try gz.addPlNodePayloadIndex(tag, node, payload_index); |
| 1587 | 1604 | } |
| 1588 | 1605 | |
| 1589 | fn arrayInitExprRlPtr( | |
| 1606 | /// An array initialization expression using element pointers. | |
| 1607 | fn arrayInitExprPtr( | |
| 1590 | 1608 | gz: *GenZir, |
| 1591 | 1609 | scope: *Scope, |
| 1592 | 1610 | node: Ast.Node.Index, |
| 1593 | result_ptr: Zir.Inst.Ref, | |
| 1594 | 1611 | 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 | ||
| 1606 | fn 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 { | |
| 1613 | 1614 | const astgen = gz.astgen; |
| 1614 | 1615 | |
| 1616 | const array_ptr_inst = try gz.addUnNode(.opt_eu_base_ptr_init, ptr_inst, node); | |
| 1617 | ||
| 1615 | 1618 | const payload_index = try addExtra(astgen, Zir.Inst.Block{ |
| 1616 | 1619 | .body_len = @intCast(elements.len), |
| 1617 | 1620 | }); |
| 1618 | 1621 | var extra_index = try reserveExtra(astgen, elements.len); |
| 1619 | 1622 | |
| 1620 | 1623 | 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, | |
| 1623 | 1626 | .index = @intCast(i), |
| 1624 | 1627 | }); |
| 1625 | astgen.extra.items[extra_index] = refToIndex(elem_ptr).?; | |
| 1628 | astgen.extra.items[extra_index] = refToIndex(elem_ptr_inst).?; | |
| 1626 | 1629 | extra_index += 1; |
| 1627 | _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr } } }, elem_init); | |
| 1630 | _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr_inst } } }, elem_init); | |
| 1628 | 1631 | } |
| 1629 | 1632 | |
| 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); | |
| 1632 | 1634 | } |
| 1633 | 1635 | |
| 1634 | 1636 | fn structInitExpr( |
| ... | ... | @@ -1643,7 +1645,26 @@ fn structInitExpr( |
| 1643 | 1645 | |
| 1644 | 1646 | if (struct_init.ast.type_expr == 0) { |
| 1645 | 1647 | if (struct_init.ast.fields.len == 0) { |
| 1646 | return rvalue(gz, ri, .empty_struct, node); | |
| 1648 | // Anonymous init with no fields. | |
| 1649 | switch (ri.rl) { | |
| 1650 | .discard => return .void_value, | |
| 1651 | .ref_coerced_ty => |ptr_ty_inst| return gz.addUnNode(.struct_init_empty_ref_result, ptr_ty_inst, node), | |
| 1652 | .ty, .coerced_ty => |ty_inst| return gz.addUnNode(.struct_init_empty_result, ty_inst, node), | |
| 1653 | .ptr => { | |
| 1654 | // TODO: should we modify this to use RLS for the field stores here? | |
| 1655 | const ty_inst = (try ri.rl.resultType(gz, node)).?; | |
| 1656 | const val = try gz.addUnNode(.struct_init_empty_result, ty_inst, node); | |
| 1657 | return rvalue(gz, ri, val, node); | |
| 1658 | }, | |
| 1659 | .none, .ref, .inferred_ptr => { | |
| 1660 | return rvalue(gz, ri, .empty_struct, node); | |
| 1661 | }, | |
| 1662 | .destructure => |destructure| { | |
| 1663 | return astgen.failNodeNotes(node, "empty initializer cannot be destructured", .{}, &.{ | |
| 1664 | try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}), | |
| 1665 | }); | |
| 1666 | }, | |
| 1667 | } | |
| 1647 | 1668 | } |
| 1648 | 1669 | } else array: { |
| 1649 | 1670 | const node_tags = tree.nodes.items(.tag); |
| ... | ... | @@ -1694,86 +1715,67 @@ fn structInitExpr( |
| 1694 | 1715 | } |
| 1695 | 1716 | } |
| 1696 | 1717 | |
| 1718 | if (struct_init.ast.type_expr != 0) { | |
| 1719 | // Typed inits do not use RLS for language simplicity. | |
| 1720 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | |
| 1721 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | |
| 1722 | switch (ri.rl) { | |
| 1723 | .ref => return structInitExprTyped(gz, scope, node, struct_init, ty_inst, true), | |
| 1724 | else => { | |
| 1725 | const struct_inst = try structInitExprTyped(gz, scope, node, struct_init, ty_inst, false); | |
| 1726 | return rvalue(gz, ri, struct_inst, node); | |
| 1727 | }, | |
| 1728 | } | |
| 1729 | } | |
| 1730 | ||
| 1697 | 1731 | switch (ri.rl) { |
| 1732 | .none => return structInitExprAnon(gz, scope, node, struct_init), | |
| 1698 | 1733 | .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; | |
| 1707 | 1738 | }, |
| 1708 | 1739 | .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)); | |
| 1716 | 1742 | }, |
| 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); | |
| 1725 | 1747 | }, |
| 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); | |
| 1737 | 1751 | }, |
| 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); | |
| 1749 | 1762 | }, |
| 1750 | 1763 | .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 | }); | |
| 1766 | 1769 | }, |
| 1767 | 1770 | } |
| 1768 | 1771 | } |
| 1769 | 1772 | |
| 1770 | fn structInitExprRlNone( | |
| 1773 | /// A struct initialization expression using a `struct_init_anon` instruction. | |
| 1774 | fn structInitExprAnon( | |
| 1771 | 1775 | gz: *GenZir, |
| 1772 | 1776 | scope: *Scope, |
| 1773 | 1777 | node: Ast.Node.Index, |
| 1774 | 1778 | struct_init: Ast.full.StructInit, |
| 1775 | ty_inst: Zir.Inst.Ref, | |
| 1776 | tag: Zir.Inst.Tag, | |
| 1777 | 1779 | ) InnerError!Zir.Inst.Ref { |
| 1778 | 1780 | const astgen = gz.astgen; |
| 1779 | 1781 | const tree = astgen.tree; |
| ... | ... | @@ -1787,104 +1789,83 @@ fn structInitExprRlNone( |
| 1787 | 1789 | for (struct_init.ast.fields) |field_init| { |
| 1788 | 1790 | const name_token = tree.firstToken(field_init) - 2; |
| 1789 | 1791 | const str_index = try astgen.identAsString(name_token); |
| 1790 | const sub_ri: ResultInfo = if (ty_inst != .none) | |
| 1791 | ResultInfo{ .rl = .{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ | |
| 1792 | .container_type = ty_inst, | |
| 1793 | .name_start = str_index, | |
| 1794 | }) } } | |
| 1795 | else | |
| 1796 | .{ .rl = .none }; | |
| 1797 | 1792 | setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ |
| 1798 | 1793 | .field_name = str_index, |
| 1799 | .init = try expr(gz, scope, sub_ri, field_init), | |
| 1794 | .init = try expr(gz, scope, .{ .rl = .none }, field_init), | |
| 1800 | 1795 | }); |
| 1801 | 1796 | extra_index += field_size; |
| 1802 | 1797 | } |
| 1803 | 1798 | |
| 1804 | return try gz.addPlNodePayloadIndex(tag, node, payload_index); | |
| 1805 | } | |
| 1806 | ||
| 1807 | fn 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); | |
| 1823 | 1800 | } |
| 1824 | 1801 | |
| 1825 | fn structInitExprRlPtrInner( | |
| 1802 | /// A struct initialization expression using a `struct_init` or `struct_init_ref` instruction. | |
| 1803 | fn structInitExprTyped( | |
| 1826 | 1804 | gz: *GenZir, |
| 1827 | 1805 | scope: *Scope, |
| 1828 | 1806 | node: Ast.Node.Index, |
| 1829 | 1807 | struct_init: Ast.full.StructInit, |
| 1830 | result_ptr: Zir.Inst.Ref, | |
| 1808 | ty_inst: Zir.Inst.Ref, | |
| 1809 | is_ref: bool, | |
| 1831 | 1810 | ) InnerError!Zir.Inst.Ref { |
| 1832 | 1811 | const astgen = gz.astgen; |
| 1833 | 1812 | const tree = astgen.tree; |
| 1834 | 1813 | |
| 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), | |
| 1837 | 1816 | }); |
| 1838 | var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len); | |
| 1817 | const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len; | |
| 1818 | var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); | |
| 1839 | 1819 | |
| 1840 | 1820 | for (struct_init.ast.fields) |field_init| { |
| 1841 | 1821 | const name_token = tree.firstToken(field_init) - 2; |
| 1842 | 1822 | 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, | |
| 1846 | 1826 | }); |
| 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; | |
| 1850 | 1832 | } |
| 1851 | 1833 | |
| 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); | |
| 1854 | 1836 | } |
| 1855 | 1837 | |
| 1856 | fn structInitExprRlTy( | |
| 1838 | /// A struct initialization expression using field pointers. | |
| 1839 | fn structInitExprPtr( | |
| 1857 | 1840 | gz: *GenZir, |
| 1858 | 1841 | scope: *Scope, |
| 1859 | 1842 | node: Ast.Node.Index, |
| 1860 | 1843 | 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 { | |
| 1864 | 1846 | const astgen = gz.astgen; |
| 1865 | 1847 | const tree = astgen.tree; |
| 1866 | 1848 | |
| 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), | |
| 1869 | 1853 | }); |
| 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); | |
| 1872 | 1855 | |
| 1873 | 1856 | for (struct_init.ast.fields) |field_init| { |
| 1874 | 1857 | const name_token = tree.firstToken(field_init) - 2; |
| 1875 | 1858 | 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, | |
| 1883 | 1862 | }); |
| 1884 | extra_index += field_size; | |
| 1863 | astgen.extra.items[extra_index] = refToIndex(field_ptr).?; | |
| 1864 | extra_index += 1; | |
| 1865 | _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init); | |
| 1885 | 1866 | } |
| 1886 | 1867 | |
| 1887 | return try gz.addPlNodePayloadIndex(tag, node, payload_index); | |
| 1868 | _ = try gz.addPlNodePayloadIndex(.validate_ptr_struct_init, node, payload_index); | |
| 1888 | 1869 | } |
| 1889 | 1870 | |
| 1890 | 1871 | /// This explicitly calls expr in a comptime scope by wrapping it in a `block_comptime` if |
| ... | ... | @@ -2314,7 +2295,7 @@ fn labeledBlockExpr( |
| 2314 | 2295 | const need_rl = astgen.nodes_need_rl.contains(block_node); |
| 2315 | 2296 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 2316 | 2297 | .rl = switch (ri.rl) { |
| 2317 | .ptr => .{ .ty = try ri.rl.resultType(gz, block_node, undefined) }, | |
| 2298 | .ptr => .{ .ty = (try ri.rl.resultType(gz, block_node)).? }, | |
| 2318 | 2299 | .inferred_ptr => .none, |
| 2319 | 2300 | else => ri.rl, |
| 2320 | 2301 | }, |
| ... | ... | @@ -2504,7 +2485,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2504 | 2485 | .array_mul, |
| 2505 | 2486 | .array_type, |
| 2506 | 2487 | .array_type_sentinel, |
| 2507 | .elem_type_index, | |
| 2508 | 2488 | .elem_type, |
| 2509 | 2489 | .indexable_ptr_elem_type, |
| 2510 | 2490 | .vector_elem_type, |
| ... | ... | @@ -2531,7 +2511,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2531 | 2511 | .cmp_gte, |
| 2532 | 2512 | .cmp_gt, |
| 2533 | 2513 | .cmp_neq, |
| 2534 | .coerce_result_ptr, | |
| 2535 | 2514 | .decl_ref, |
| 2536 | 2515 | .decl_val, |
| 2537 | 2516 | .load, |
| ... | ... | @@ -2539,11 +2518,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2539 | 2518 | .elem_ptr, |
| 2540 | 2519 | .elem_val, |
| 2541 | 2520 | .elem_ptr_node, |
| 2542 | .elem_ptr_imm, | |
| 2543 | 2521 | .elem_val_node, |
| 2544 | 2522 | .elem_val_imm, |
| 2545 | 2523 | .field_ptr, |
| 2546 | .field_ptr_init, | |
| 2547 | 2524 | .field_val, |
| 2548 | 2525 | .field_ptr_named, |
| 2549 | 2526 | .field_val_named, |
| ... | ... | @@ -2599,17 +2576,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2599 | 2576 | .import, |
| 2600 | 2577 | .switch_block, |
| 2601 | 2578 | .switch_block_ref, |
| 2602 | .struct_init_empty, | |
| 2603 | .struct_init, | |
| 2604 | .struct_init_ref, | |
| 2605 | .struct_init_anon, | |
| 2606 | .struct_init_anon_ref, | |
| 2607 | .array_init, | |
| 2608 | .array_init_anon, | |
| 2609 | .array_init_ref, | |
| 2610 | .array_init_anon_ref, | |
| 2611 | 2579 | .union_init, |
| 2612 | .field_type, | |
| 2613 | 2580 | .field_type_ref, |
| 2614 | 2581 | .error_set_decl, |
| 2615 | 2582 | .error_set_decl_anon, |
| ... | ... | @@ -2680,14 +2647,27 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2680 | 2647 | .@"await", |
| 2681 | 2648 | .ret_err_value_code, |
| 2682 | 2649 | .closure_get, |
| 2683 | .array_base_ptr, | |
| 2684 | .field_base_ptr, | |
| 2685 | 2650 | .ret_ptr, |
| 2686 | 2651 | .ret_type, |
| 2687 | 2652 | .for_len, |
| 2688 | 2653 | .@"try", |
| 2689 | 2654 | .try_ptr, |
| 2690 | .opt_eu_base_ty, | |
| 2655 | .opt_eu_base_ptr_init, | |
| 2656 | .coerce_ptr_elem_ty, | |
| 2657 | .struct_init_empty, | |
| 2658 | .struct_init_empty_result, | |
| 2659 | .struct_init_empty_ref_result, | |
| 2660 | .struct_init_anon, | |
| 2661 | .struct_init, | |
| 2662 | .struct_init_ref, | |
| 2663 | .struct_init_field_type, | |
| 2664 | .struct_init_field_ptr, | |
| 2665 | .array_init_anon, | |
| 2666 | .array_init, | |
| 2667 | .array_init_ref, | |
| 2668 | .validate_array_init_ref_ty, | |
| 2669 | .array_init_elem_type, | |
| 2670 | .array_init_elem_ptr, | |
| 2691 | 2671 | => break :b false, |
| 2692 | 2672 | |
| 2693 | 2673 | .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { |
| ... | ... | @@ -2738,18 +2718,21 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2738 | 2718 | .store_node, |
| 2739 | 2719 | .store_to_inferred_ptr, |
| 2740 | 2720 | .resolve_inferred_alloc, |
| 2741 | .validate_struct_init, | |
| 2742 | .validate_array_init, | |
| 2743 | 2721 | .set_runtime_safety, |
| 2744 | 2722 | .closure_capture, |
| 2745 | 2723 | .memcpy, |
| 2746 | 2724 | .memset, |
| 2747 | .validate_array_init_ty, | |
| 2748 | .validate_struct_init_ty, | |
| 2749 | 2725 | .validate_deref, |
| 2750 | 2726 | .validate_destructure, |
| 2751 | 2727 | .save_err_ret_index, |
| 2752 | 2728 | .restore_err_ret_index, |
| 2729 | .validate_struct_init_ty, | |
| 2730 | .validate_struct_init_result_ty, | |
| 2731 | .validate_ptr_struct_init, | |
| 2732 | .validate_array_init_ty, | |
| 2733 | .validate_array_init_result_ty, | |
| 2734 | .validate_ptr_array_init, | |
| 2735 | .validate_ref_ty, | |
| 2753 | 2736 | => break :b true, |
| 2754 | 2737 | |
| 2755 | 2738 | .@"defer" => unreachable, |
| ... | ... | @@ -5635,7 +5618,7 @@ fn tryExpr( |
| 5635 | 5618 | const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; |
| 5636 | 5619 | |
| 5637 | 5620 | const operand_ri: ResultInfo = switch (ri.rl) { |
| 5638 | .ref => .{ .rl = .ref, .ctx = .error_handling_expr }, | |
| 5621 | .ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = .error_handling_expr }, | |
| 5639 | 5622 | else => .{ .rl = .none, .ctx = .error_handling_expr }, |
| 5640 | 5623 | }; |
| 5641 | 5624 | // This could be a pointer or value depending on the `ri` parameter. |
| ... | ... | @@ -5648,7 +5631,7 @@ fn tryExpr( |
| 5648 | 5631 | defer else_scope.unstack(); |
| 5649 | 5632 | |
| 5650 | 5633 | const err_tag = switch (ri.rl) { |
| 5651 | .ref => Zir.Inst.Tag.err_union_code_ptr, | |
| 5634 | .ref, .ref_coerced_ty => Zir.Inst.Tag.err_union_code_ptr, | |
| 5652 | 5635 | else => Zir.Inst.Tag.err_union_code, |
| 5653 | 5636 | }; |
| 5654 | 5637 | const err_code = try else_scope.addUnNode(err_tag, operand, node); |
| ... | ... | @@ -5659,7 +5642,7 @@ fn tryExpr( |
| 5659 | 5642 | try else_scope.setTryBody(try_inst, operand); |
| 5660 | 5643 | const result = indexToRef(try_inst); |
| 5661 | 5644 | switch (ri.rl) { |
| 5662 | .ref => return result, | |
| 5645 | .ref, .ref_coerced_ty => return result, | |
| 5663 | 5646 | else => return rvalue(parent_gz, ri, result, node), |
| 5664 | 5647 | } |
| 5665 | 5648 | } |
| ... | ... | @@ -5682,7 +5665,7 @@ fn orelseCatchExpr( |
| 5682 | 5665 | const need_rl = astgen.nodes_need_rl.contains(node); |
| 5683 | 5666 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 5684 | 5667 | .rl = switch (ri.rl) { |
| 5685 | .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) }, | |
| 5668 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? }, | |
| 5686 | 5669 | .inferred_ptr => .none, |
| 5687 | 5670 | else => ri.rl, |
| 5688 | 5671 | }, |
| ... | ... | @@ -5700,7 +5683,7 @@ fn orelseCatchExpr( |
| 5700 | 5683 | defer block_scope.unstack(); |
| 5701 | 5684 | |
| 5702 | 5685 | const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) { |
| 5703 | .ref => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none }, | |
| 5686 | .ref, .ref_coerced_ty => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none }, | |
| 5704 | 5687 | else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none }, |
| 5705 | 5688 | }; |
| 5706 | 5689 | // This could be a pointer or value depending on the `operand_ri` parameter. |
| ... | ... | @@ -5722,7 +5705,7 @@ fn orelseCatchExpr( |
| 5722 | 5705 | // This could be a pointer or value depending on `unwrap_op`. |
| 5723 | 5706 | const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); |
| 5724 | 5707 | const then_result = switch (ri.rl) { |
| 5725 | .ref => unwrapped_payload, | |
| 5708 | .ref, .ref_coerced_ty => unwrapped_payload, | |
| 5726 | 5709 | else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node), |
| 5727 | 5710 | }; |
| 5728 | 5711 | _ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, node); |
| ... | ... | @@ -5793,7 +5776,7 @@ fn fieldAccess( |
| 5793 | 5776 | node: Ast.Node.Index, |
| 5794 | 5777 | ) InnerError!Zir.Inst.Ref { |
| 5795 | 5778 | switch (ri.rl) { |
| 5796 | .ref => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node), | |
| 5779 | .ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node), | |
| 5797 | 5780 | else => { |
| 5798 | 5781 | const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node); |
| 5799 | 5782 | return rvalue(gz, ri, access, node); |
| ... | ... | @@ -5837,7 +5820,7 @@ fn arrayAccess( |
| 5837 | 5820 | const tree = gz.astgen.tree; |
| 5838 | 5821 | const node_datas = tree.nodes.items(.data); |
| 5839 | 5822 | switch (ri.rl) { |
| 5840 | .ref => { | |
| 5823 | .ref, .ref_coerced_ty => { | |
| 5841 | 5824 | const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); |
| 5842 | 5825 | |
| 5843 | 5826 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); |
| ... | ... | @@ -5951,7 +5934,7 @@ fn ifExpr( |
| 5951 | 5934 | const need_rl = astgen.nodes_need_rl.contains(node); |
| 5952 | 5935 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 5953 | 5936 | .rl = switch (ri.rl) { |
| 5954 | .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) }, | |
| 5937 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? }, | |
| 5955 | 5938 | .inferred_ptr => .none, |
| 5956 | 5939 | else => ri.rl, |
| 5957 | 5940 | }, |
| ... | ... | @@ -6181,7 +6164,7 @@ fn whileExpr( |
| 6181 | 6164 | const need_rl = astgen.nodes_need_rl.contains(node); |
| 6182 | 6165 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 6183 | 6166 | .rl = switch (ri.rl) { |
| 6184 | .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) }, | |
| 6167 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? }, | |
| 6185 | 6168 | .inferred_ptr => .none, |
| 6186 | 6169 | else => ri.rl, |
| 6187 | 6170 | }, |
| ... | ... | @@ -6455,7 +6438,7 @@ fn forExpr( |
| 6455 | 6438 | const need_rl = astgen.nodes_need_rl.contains(node); |
| 6456 | 6439 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 6457 | 6440 | .rl = switch (ri.rl) { |
| 6458 | .ptr => .{ .ty = try ri.rl.resultType(parent_gz, node, undefined) }, | |
| 6441 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, node)).? }, | |
| 6459 | 6442 | .inferred_ptr => .none, |
| 6460 | 6443 | else => ri.rl, |
| 6461 | 6444 | }, |
| ... | ... | @@ -6773,7 +6756,7 @@ fn switchExpr( |
| 6773 | 6756 | const need_rl = astgen.nodes_need_rl.contains(switch_node); |
| 6774 | 6757 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 6775 | 6758 | .rl = switch (ri.rl) { |
| 6776 | .ptr => .{ .ty = try ri.rl.resultType(parent_gz, switch_node, undefined) }, | |
| 6759 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, switch_node)).? }, | |
| 6777 | 6760 | .inferred_ptr => .none, |
| 6778 | 6761 | else => ri.rl, |
| 6779 | 6762 | }, |
| ... | ... | @@ -7465,7 +7448,7 @@ fn localVarRef( |
| 7465 | 7448 | gpa, |
| 7466 | 7449 | ); |
| 7467 | 7450 | |
| 7468 | return rvalue(gz, ri, value_inst, ident); | |
| 7451 | return rvalueNoCoercePreRef(gz, ri, value_inst, ident); | |
| 7469 | 7452 | } |
| 7470 | 7453 | s = local_val.parent; |
| 7471 | 7454 | }, |
| ... | ... | @@ -7498,10 +7481,10 @@ fn localVarRef( |
| 7498 | 7481 | ); |
| 7499 | 7482 | |
| 7500 | 7483 | switch (ri.rl) { |
| 7501 | .ref => return ptr_inst, | |
| 7484 | .ref, .ref_coerced_ty => return ptr_inst, | |
| 7502 | 7485 | else => { |
| 7503 | 7486 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); |
| 7504 | return rvalue(gz, ri, loaded, ident); | |
| 7487 | return rvalueNoCoercePreRef(gz, ri, loaded, ident); | |
| 7505 | 7488 | }, |
| 7506 | 7489 | } |
| 7507 | 7490 | } |
| ... | ... | @@ -7535,10 +7518,10 @@ fn localVarRef( |
| 7535 | 7518 | // Decl references happen by name rather than ZIR index so that when unrelated |
| 7536 | 7519 | // decls are modified, ZIR code containing references to them can be unmodified. |
| 7537 | 7520 | switch (ri.rl) { |
| 7538 | .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | |
| 7521 | .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | |
| 7539 | 7522 | else => { |
| 7540 | 7523 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); |
| 7541 | return rvalue(gz, ri, result, ident); | |
| 7524 | return rvalueNoCoercePreRef(gz, ri, result, ident); | |
| 7542 | 7525 | }, |
| 7543 | 7526 | } |
| 7544 | 7527 | } |
| ... | ... | @@ -7924,7 +7907,7 @@ fn bitCast( |
| 7924 | 7907 | node: Ast.Node.Index, |
| 7925 | 7908 | operand_node: Ast.Node.Index, |
| 7926 | 7909 | ) InnerError!Zir.Inst.Ref { |
| 7927 | const dest_type = try ri.rl.resultType(gz, node, "@bitCast"); | |
| 7910 | const dest_type = try ri.rl.resultTypeForCast(gz, node, "@bitCast"); | |
| 7928 | 7911 | const operand = try reachableExpr(gz, scope, .{ .rl = .none }, operand_node, node); |
| 7929 | 7912 | const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ |
| 7930 | 7913 | .lhs = dest_type, |
| ... | ... | @@ -8024,7 +8007,7 @@ fn ptrCast( |
| 8024 | 8007 | // Full cast including result type |
| 8025 | 8008 | |
| 8026 | 8009 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node); |
| 8027 | const result_type = try ri.rl.resultType(gz, root_node, flags.needResultTypeBuiltinName()); | |
| 8010 | const result_type = try ri.rl.resultTypeForCast(gz, root_node, flags.needResultTypeBuiltinName()); | |
| 8028 | 8011 | const operand = try expr(gz, scope, .{ .rl = .none }, node); |
| 8029 | 8012 | try emitDbgStmt(gz, cursor); |
| 8030 | 8013 | const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{ |
| ... | ... | @@ -8208,7 +8191,7 @@ fn builtinCall( |
| 8208 | 8191 | return rvalue(gz, ri, result, node); |
| 8209 | 8192 | }, |
| 8210 | 8193 | .field => { |
| 8211 | if (ri.rl == .ref) { | |
| 8194 | if (ri.rl == .ref or ri.rl == .ref_coerced_ty) { | |
| 8212 | 8195 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ |
| 8213 | 8196 | .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), |
| 8214 | 8197 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]), |
| ... | ... | @@ -8475,7 +8458,7 @@ fn builtinCall( |
| 8475 | 8458 | try emitDbgNode(gz, node); |
| 8476 | 8459 | |
| 8477 | 8460 | const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{ |
| 8478 | .lhs = try ri.rl.resultType(gz, node, "@errSetCast"), | |
| 8461 | .lhs = try ri.rl.resultTypeForCast(gz, node, "@errSetCast"), | |
| 8479 | 8462 | .rhs = try expr(gz, scope, .{ .rl = .none }, params[0]), |
| 8480 | 8463 | .node = gz.nodeIndexToRelative(node), |
| 8481 | 8464 | }); |
| ... | ... | @@ -8548,7 +8531,7 @@ fn builtinCall( |
| 8548 | 8531 | }, |
| 8549 | 8532 | |
| 8550 | 8533 | .splat => { |
| 8551 | const result_type = try ri.rl.resultType(gz, node, "@splat"); | |
| 8534 | const result_type = try ri.rl.resultTypeForCast(gz, node, "@splat"); | |
| 8552 | 8535 | const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node); |
| 8553 | 8536 | const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]); |
| 8554 | 8537 | const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ |
| ... | ... | @@ -8810,7 +8793,7 @@ fn typeCast( |
| 8810 | 8793 | builtin_name: []const u8, |
| 8811 | 8794 | ) InnerError!Zir.Inst.Ref { |
| 8812 | 8795 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); |
| 8813 | const result_type = try ri.rl.resultType(gz, node, builtin_name); | |
| 8796 | const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name); | |
| 8814 | 8797 | const operand = try expr(gz, scope, .{ .rl = .none }, operand_node); |
| 8815 | 8798 | |
| 8816 | 8799 | try emitDbgStmt(gz, cursor); |
| ... | ... | @@ -10069,6 +10052,29 @@ fn rvalue( |
| 10069 | 10052 | ri: ResultInfo, |
| 10070 | 10053 | raw_result: Zir.Inst.Ref, |
| 10071 | 10054 | src_node: Ast.Node.Index, |
| 10055 | ) InnerError!Zir.Inst.Ref { | |
| 10056 | return rvalueInner(gz, ri, raw_result, src_node, true); | |
| 10057 | } | |
| 10058 | ||
| 10059 | /// Like `rvalue`, but refuses to perform coercions before taking references for | |
| 10060 | /// the `ref_coerced_ty` result type. This is used for local variables which do | |
| 10061 | /// not have `alloc`s, because we want variables to have consistent addresses, | |
| 10062 | /// i.e. we want them to act like lvalues. | |
| 10063 | fn 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 | ||
| 10072 | fn rvalueInner( | |
| 10073 | gz: *GenZir, | |
| 10074 | ri: ResultInfo, | |
| 10075 | raw_result: Zir.Inst.Ref, | |
| 10076 | src_node: Ast.Node.Index, | |
| 10077 | allow_coerce_pre_ref: bool, | |
| 10072 | 10078 | ) InnerError!Zir.Inst.Ref { |
| 10073 | 10079 | const result = r: { |
| 10074 | 10080 | if (refToIndex(raw_result)) |result_index| { |
| ... | ... | @@ -10088,7 +10094,14 @@ fn rvalue( |
| 10088 | 10094 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); |
| 10089 | 10095 | return .void_value; |
| 10090 | 10096 | }, |
| 10091 | .ref => { | |
| 10097 | .ref, .ref_coerced_ty => { | |
| 10098 | const coerced_result = if (allow_coerce_pre_ref and ri.rl == .ref_coerced_ty) res: { | |
| 10099 | const ptr_ty = ri.rl.ref_coerced_ty; | |
| 10100 | break :res try gz.addPlNode(.coerce_ptr_elem_ty, src_node, Zir.Inst.Bin{ | |
| 10101 | .lhs = ptr_ty, | |
| 10102 | .rhs = result, | |
| 10103 | }); | |
| 10104 | } else result; | |
| 10092 | 10105 | // We need a pointer but we have a value. |
| 10093 | 10106 | // Unfortunately it's not quite as simple as directly emitting a ref |
| 10094 | 10107 | // instruction here because we need subsequent address-of operator on |
| ... | ... | @@ -10096,14 +10109,14 @@ fn rvalue( |
| 10096 | 10109 | const astgen = gz.astgen; |
| 10097 | 10110 | const tree = astgen.tree; |
| 10098 | 10111 | 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); | |
| 10101 | 10114 | 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); | |
| 10104 | 10117 | const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index); |
| 10105 | 10118 | if (!gop.found_existing) { |
| 10106 | gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token); | |
| 10119 | gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token); | |
| 10107 | 10120 | } |
| 10108 | 10121 | return indexToRef(gop.value_ptr.*); |
| 10109 | 10122 | }, |
src/AstRlAnnotate.zig+26-18| ... | ... | @@ -669,17 +669,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI |
| 669 | 669 | => { |
| 670 | 670 | var buf: [2]Ast.Node.Index = undefined; |
| 671 | 671 | const full = tree.fullArrayInit(&buf, node).?; |
| 672 | const have_type = if (full.ast.type_expr != 0) have_type: { | |
| 672 | ||
| 673 | if (full.ast.type_expr != 0) { | |
| 674 | // Explicitly typed init does not participate in RLS | |
| 673 | 675 | _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); |
| 674 | break :have_type true; | |
| 675 | } else ri.have_type; | |
| 676 | if (have_type) { | |
| 677 | const elem_ri: ResultInfo = .{ | |
| 678 | .have_type = true, | |
| 679 | .have_ptr = ri.have_ptr, | |
| 680 | }; | |
| 681 | 676 | for (full.ast.elements) |elem_init| { |
| 682 | _ = try astrl.expr(elem_init, block, elem_ri); | |
| 677 | _ = try astrl.expr(elem_init, block, ResultInfo.type_only); | |
| 678 | } | |
| 679 | return false; | |
| 680 | } | |
| 681 | ||
| 682 | if (ri.have_type) { | |
| 683 | // Always forward type information | |
| 684 | // If we have a result pointer, we use and forward it | |
| 685 | for (full.ast.elements) |elem_init| { | |
| 686 | _ = try astrl.expr(elem_init, block, ri); | |
| 683 | 687 | } |
| 684 | 688 | return ri.have_ptr; |
| 685 | 689 | } else { |
| ... | ... | @@ -702,17 +706,21 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI |
| 702 | 706 | => { |
| 703 | 707 | var buf: [2]Ast.Node.Index = undefined; |
| 704 | 708 | const full = tree.fullStructInit(&buf, node).?; |
| 705 | const have_type = if (full.ast.type_expr != 0) have_type: { | |
| 709 | ||
| 710 | if (full.ast.type_expr != 0) { | |
| 711 | // Explicitly typed init does not participate in RLS | |
| 706 | 712 | _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); |
| 707 | break :have_type true; | |
| 708 | } else ri.have_type; | |
| 709 | if (have_type) { | |
| 710 | const elem_ri: ResultInfo = .{ | |
| 711 | .have_type = true, | |
| 712 | .have_ptr = ri.have_ptr, | |
| 713 | }; | |
| 714 | 713 | for (full.ast.fields) |field_init| { |
| 715 | _ = try astrl.expr(field_init, block, elem_ri); | |
| 714 | _ = try astrl.expr(field_init, block, ResultInfo.type_only); | |
| 715 | } | |
| 716 | return false; | |
| 717 | } | |
| 718 | ||
| 719 | if (ri.have_type) { | |
| 720 | // Always forward type information | |
| 721 | // If we have a result pointer, we use and forward it | |
| 722 | for (full.ast.fields) |field_init| { | |
| 723 | _ = try astrl.expr(field_init, block, ri); | |
| 716 | 724 | } |
| 717 | 725 | return ri.have_ptr; |
| 718 | 726 | } else { |
src/Autodoc.zig+19-34| ... | ... | @@ -45,6 +45,14 @@ ref_paths_pending_on_types: std.AutoHashMapUnmanaged( |
| 45 | 45 | std.ArrayListUnmanaged(RefPathResumeInfo), |
| 46 | 46 | ) = .{}, |
| 47 | 47 | |
| 48 | /// A set of ZIR instruction refs which have a meaning other than the | |
| 49 | /// instruction they refer to. For instance, during analysis of the arguments to | |
| 50 | /// a `call`, the index of the `call` itself is repurposed to refer to the | |
| 51 | /// parameter type. | |
| 52 | /// TODO: there should be some kind of proper handling for these instructions; | |
| 53 | /// currently we just ignore them! | |
| 54 | repurposed_insts: std.AutoHashMapUnmanaged(Zir.Inst.Index, void) = .{}, | |
| 55 | ||
| 48 | 56 | const RefPathResumeInfo = struct { |
| 49 | 57 | file: *File, |
| 50 | 58 | ref_path: []DocData.Expr, |
| ... | ... | @@ -954,6 +962,11 @@ fn walkInstruction( |
| 954 | 962 | const tags = file.zir.instructions.items(.tag); |
| 955 | 963 | const data = file.zir.instructions.items(.data); |
| 956 | 964 | |
| 965 | if (self.repurposed_insts.contains(@intCast(inst_index))) { | |
| 966 | // TODO: better handling here | |
| 967 | return .{ .expr = .{ .comptimeExpr = 0 } }; | |
| 968 | } | |
| 969 | ||
| 957 | 970 | // We assume that the topmost ast_node entry corresponds to our decl |
| 958 | 971 | const self_ast_node_index = self.ast_nodes.items.len - 1; |
| 959 | 972 | |
| ... | ... | @@ -2378,34 +2391,6 @@ fn walkInstruction( |
| 2378 | 2391 | .expr = .{ .@"&" = expr_index }, |
| 2379 | 2392 | }; |
| 2380 | 2393 | }, |
| 2381 | .array_init_anon_ref => { | |
| 2382 | const pl_node = data[inst_index].pl_node; | |
| 2383 | const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index); | |
| 2384 | const operands = file.zir.refSlice(extra.end, extra.data.operands_len); | |
| 2385 | const array_data = try self.arena.alloc(usize, operands.len); | |
| 2386 | ||
| 2387 | for (operands, 0..) |op, idx| { | |
| 2388 | const wr = try self.walkRef( | |
| 2389 | file, | |
| 2390 | parent_scope, | |
| 2391 | parent_src, | |
| 2392 | op, | |
| 2393 | false, | |
| 2394 | call_ctx, | |
| 2395 | ); | |
| 2396 | const expr_index = self.exprs.items.len; | |
| 2397 | try self.exprs.append(self.arena, wr.expr); | |
| 2398 | array_data[idx] = expr_index; | |
| 2399 | } | |
| 2400 | ||
| 2401 | const expr_index = self.exprs.items.len; | |
| 2402 | try self.exprs.append(self.arena, .{ .array = array_data }); | |
| 2403 | ||
| 2404 | return DocData.WalkResult{ | |
| 2405 | .typeRef = null, | |
| 2406 | .expr = .{ .@"&" = expr_index }, | |
| 2407 | }; | |
| 2408 | }, | |
| 2409 | 2394 | .float => { |
| 2410 | 2395 | const float = data[inst_index].float; |
| 2411 | 2396 | return DocData.WalkResult{ |
| ... | ... | @@ -2696,9 +2681,7 @@ fn walkInstruction( |
| 2696 | 2681 | .expr = .{ .declRef = decl_status }, |
| 2697 | 2682 | }; |
| 2698 | 2683 | }, |
| 2699 | .field_val, .field_ptr, .field_type => { | |
| 2700 | // TODO: field type uses Zir.Inst.FieldType, it just happens to have the | |
| 2701 | // same layout as Zir.Inst.Field :^) | |
| 2684 | .field_val, .field_ptr => { | |
| 2702 | 2685 | const pl_node = data[inst_index].pl_node; |
| 2703 | 2686 | const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index); |
| 2704 | 2687 | |
| ... | ... | @@ -2717,8 +2700,7 @@ fn walkInstruction( |
| 2717 | 2700 | }; |
| 2718 | 2701 | |
| 2719 | 2702 | if (tags[lhs] != .field_val and |
| 2720 | tags[lhs] != .field_ptr and | |
| 2721 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; | |
| 2703 | tags[lhs] != .field_ptr) break :blk lhs_extra.data.lhs; | |
| 2722 | 2704 | |
| 2723 | 2705 | lhs_extra = file.zir.extraData( |
| 2724 | 2706 | Zir.Inst.Field, |
| ... | ... | @@ -2857,7 +2839,7 @@ fn walkInstruction( |
| 2857 | 2839 | |
| 2858 | 2840 | const field_name = blk: { |
| 2859 | 2841 | const field_inst_index = init_extra.data.field_type; |
| 2860 | if (tags[field_inst_index] != .field_type) unreachable; | |
| 2842 | if (tags[field_inst_index] != .struct_init_field_type) unreachable; | |
| 2861 | 2843 | const field_pl_node = data[field_inst_index].pl_node; |
| 2862 | 2844 | const field_extra = file.zir.extraData( |
| 2863 | 2845 | Zir.Inst.FieldType, |
| ... | ... | @@ -3022,6 +3004,9 @@ fn walkInstruction( |
| 3022 | 3004 | var args = try self.arena.alloc(DocData.Expr, args_len); |
| 3023 | 3005 | const body = file.zir.extra[extra.end..]; |
| 3024 | 3006 | |
| 3007 | try self.repurposed_insts.put(self.arena, @intCast(inst_index), {}); | |
| 3008 | defer _ = self.repurposed_insts.remove(@intCast(inst_index)); | |
| 3009 | ||
| 3025 | 3010 | var i: usize = 0; |
| 3026 | 3011 | while (i < args_len) : (i += 1) { |
| 3027 | 3012 | const arg_end = file.zir.extra[extra.end + i]; |
src/InternPool.zig+2-2| ... | ... | @@ -5075,8 +5075,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 5075 | 5075 | try ip.string_bytes.ensureUnusedCapacity(gpa, @as(usize, @intCast(len_including_sentinel + 1))); |
| 5076 | 5076 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len); |
| 5077 | 5077 | switch (aggregate.storage) { |
| 5078 | .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes), | |
| 5079 | .elems => |elems| for (elems) |elem| switch (ip.indexToKey(elem)) { | |
| 5078 | .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes[0..@intCast(len)]), | |
| 5079 | .elems => |elems| for (elems[0..@intCast(len)]) |elem| switch (ip.indexToKey(elem)) { | |
| 5080 | 5080 | .undef => { |
| 5081 | 5081 | ip.string_bytes.shrinkRetainingCapacity(string_bytes_index); |
| 5082 | 5082 | break :bytes; |
src/Sema.zig+478-447| ... | ... | @@ -836,16 +836,11 @@ const LabeledBlock = struct { |
| 836 | 836 | /// the items are contiguous in memory and thus can be passed to |
| 837 | 837 | /// `Module.resolvePeerTypes`. |
| 838 | 838 | const 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) = .{}, | |
| 849 | 844 | }; |
| 850 | 845 | |
| 851 | 846 | const NeededComptimeReason = struct { |
| ... | ... | @@ -1040,17 +1035,14 @@ fn analyzeBodyInner( |
| 1040 | 1035 | .cmp_gte => try sema.zirCmp(block, inst, .gte), |
| 1041 | 1036 | .cmp_gt => try sema.zirCmp(block, inst, .gt), |
| 1042 | 1037 | .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)), |
| 1043 | .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), | |
| 1044 | 1038 | .decl_ref => try sema.zirDeclRef(block, inst), |
| 1045 | 1039 | .decl_val => try sema.zirDeclVal(block, inst), |
| 1046 | 1040 | .load => try sema.zirLoad(block, inst), |
| 1047 | 1041 | .elem_ptr => try sema.zirElemPtr(block, inst), |
| 1048 | 1042 | .elem_ptr_node => try sema.zirElemPtrNode(block, inst), |
| 1049 | .elem_ptr_imm => try sema.zirElemPtrImm(block, inst), | |
| 1050 | 1043 | .elem_val => try sema.zirElemVal(block, inst), |
| 1051 | 1044 | .elem_val_node => try sema.zirElemValNode(block, inst), |
| 1052 | 1045 | .elem_val_imm => try sema.zirElemValImm(block, inst), |
| 1053 | .elem_type_index => try sema.zirElemTypeIndex(block, inst), | |
| 1054 | 1046 | .elem_type => try sema.zirElemType(block, inst), |
| 1055 | 1047 | .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), |
| 1056 | 1048 | .vector_elem_type => try sema.zirVectorElemType(block, inst), |
| ... | ... | @@ -1063,8 +1055,7 @@ fn analyzeBodyInner( |
| 1063 | 1055 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst), |
| 1064 | 1056 | .error_union_type => try sema.zirErrorUnionType(block, inst), |
| 1065 | 1057 | .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), | |
| 1068 | 1059 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 1069 | 1060 | .field_val => try sema.zirFieldVal(block, inst), |
| 1070 | 1061 | .field_val_named => try sema.zirFieldValNamed(block, inst), |
| ... | ... | @@ -1111,16 +1102,19 @@ fn analyzeBodyInner( |
| 1111 | 1102 | .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), |
| 1112 | 1103 | .xor => try sema.zirBitwise(block, inst, .xor), |
| 1113 | 1104 | .struct_init_empty => try sema.zirStructInitEmpty(block, inst), |
| 1105 | .struct_init_empty_result => try sema.zirStructInitEmptyResult(block, inst, false), | |
| 1106 | .struct_init_empty_ref_result => try sema.zirStructInitEmptyResult(block, inst, true), | |
| 1107 | .struct_init_anon => try sema.zirStructInitAnon(block, inst), | |
| 1114 | 1108 | .struct_init => try sema.zirStructInit(block, inst, false), |
| 1115 | 1109 | .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), | |
| 1118 | 1113 | .array_init => try sema.zirArrayInit(block, inst, false), |
| 1119 | 1114 | .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), | |
| 1122 | 1117 | .union_init => try sema.zirUnionInit(block, inst), |
| 1123 | .field_type => try sema.zirFieldType(block, inst), | |
| 1124 | 1118 | .field_type_ref => try sema.zirFieldTypeRef(block, inst), |
| 1125 | 1119 | .int_from_ptr => try sema.zirIntFromPtr(block, inst), |
| 1126 | 1120 | .align_of => try sema.zirAlignOf(block, inst), |
| ... | ... | @@ -1154,10 +1148,10 @@ fn analyzeBodyInner( |
| 1154 | 1148 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), |
| 1155 | 1149 | .@"resume" => try sema.zirResume(block, inst), |
| 1156 | 1150 | .@"await" => try sema.zirAwait(block, inst), |
| 1157 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), | |
| 1158 | .field_base_ptr => try sema.zirFieldBasePtr(block, inst), | |
| 1159 | 1151 | .for_len => try sema.zirForLen(block, inst), |
| 1160 | .opt_eu_base_ty => try sema.zirOptEuBaseTy(block, inst), | |
| 1152 | .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst), | |
| 1153 | .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst), | |
| 1154 | .coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst), | |
| 1161 | 1155 | |
| 1162 | 1156 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 1163 | 1157 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| ... | ... | @@ -1386,23 +1380,33 @@ fn analyzeBodyInner( |
| 1386 | 1380 | i += 1; |
| 1387 | 1381 | continue; |
| 1388 | 1382 | }, |
| 1383 | .validate_struct_init_ty => { | |
| 1384 | try sema.zirValidateStructInitTy(block, inst, false); | |
| 1385 | i += 1; | |
| 1386 | continue; | |
| 1387 | }, | |
| 1388 | .validate_struct_init_result_ty => { | |
| 1389 | try sema.zirValidateStructInitTy(block, inst, true); | |
| 1390 | i += 1; | |
| 1391 | continue; | |
| 1392 | }, | |
| 1389 | 1393 | .validate_array_init_ty => { |
| 1390 | try sema.zirValidateArrayInitTy(block, inst); | |
| 1394 | try sema.zirValidateArrayInitTy(block, inst, false); | |
| 1391 | 1395 | i += 1; |
| 1392 | 1396 | continue; |
| 1393 | 1397 | }, |
| 1394 | .validate_struct_init_ty => { | |
| 1395 | try sema.zirValidateStructInitTy(block, inst); | |
| 1398 | .validate_array_init_result_ty => { | |
| 1399 | try sema.zirValidateArrayInitTy(block, inst, true); | |
| 1396 | 1400 | i += 1; |
| 1397 | 1401 | continue; |
| 1398 | 1402 | }, |
| 1399 | .validate_struct_init => { | |
| 1400 | try sema.zirValidateStructInit(block, inst); | |
| 1403 | .validate_ptr_struct_init => { | |
| 1404 | try sema.zirValidatePtrStructInit(block, inst); | |
| 1401 | 1405 | i += 1; |
| 1402 | 1406 | continue; |
| 1403 | 1407 | }, |
| 1404 | .validate_array_init => { | |
| 1405 | try sema.zirValidateArrayInit(block, inst); | |
| 1408 | .validate_ptr_array_init => { | |
| 1409 | try sema.zirValidatePtrArrayInit(block, inst); | |
| 1406 | 1410 | i += 1; |
| 1407 | 1411 | continue; |
| 1408 | 1412 | }, |
| ... | ... | @@ -1416,6 +1420,11 @@ fn analyzeBodyInner( |
| 1416 | 1420 | i += 1; |
| 1417 | 1421 | continue; |
| 1418 | 1422 | }, |
| 1423 | .validate_ref_ty => { | |
| 1424 | try sema.zirValidateRefTy(block, inst); | |
| 1425 | i += 1; | |
| 1426 | continue; | |
| 1427 | }, | |
| 1419 | 1428 | .@"export" => { |
| 1420 | 1429 | try sema.zirExport(block, inst); |
| 1421 | 1430 | i += 1; |
| ... | ... | @@ -1922,7 +1931,11 @@ fn resolveDestType( |
| 1922 | 1931 | const msg = msg: { |
| 1923 | 1932 | const msg = try sema.errMsg(block, src, "{s} must have a known result type", .{builtin_name}); |
| 1924 | 1933 | errdefer msg.destroy(sema.gpa); |
| 1925 | try sema.errNote(block, src, msg, "result type is unknown due to anytype parameter", .{}); | |
| 1934 | switch (sema.genericPoisonReason(zir_ref)) { | |
| 1935 | .anytype_param => |call_src| try sema.errNote(block, call_src, msg, "result type is unknown due to anytype parameter", .{}), | |
| 1936 | .anyopaque_ptr => |ptr_src| try sema.errNote(block, ptr_src, msg, "result type is unknown due to opaque pointer type", .{}), | |
| 1937 | .unknown => {}, | |
| 1938 | } | |
| 1926 | 1939 | try sema.errNote(block, src, msg, "use @as to provide explicit result type", .{}); |
| 1927 | 1940 | break :msg msg; |
| 1928 | 1941 | }; |
| ... | ... | @@ -1944,6 +1957,65 @@ fn resolveDestType( |
| 1944 | 1957 | return raw_ty; |
| 1945 | 1958 | } |
| 1946 | 1959 | |
| 1960 | const 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. | |
| 1968 | fn 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 | ||
| 1947 | 2019 | fn analyzeAsType( |
| 1948 | 2020 | sema: *Sema, |
| 1949 | 2021 | block: *Block, |
| ... | ... | @@ -2634,217 +2706,6 @@ pub fn resolveInstValue( |
| 2634 | 2706 | }; |
| 2635 | 2707 | } |
| 2636 | 2708 | |
| 2637 | fn 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 | ||
| 2730 | fn 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 | ||
| 2848 | 2709 | pub fn getStructType( |
| 2849 | 2710 | sema: *Sema, |
| 2850 | 2711 | decl: Module.Decl.Index, |
| ... | ... | @@ -4220,8 +4081,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4220 | 4081 | .inferred_alloc => { |
| 4221 | 4082 | const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; |
| 4222 | 4083 | 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); | |
| 4225 | 4091 | |
| 4226 | 4092 | const final_ptr_ty = try sema.ptrType(.{ |
| 4227 | 4093 | .child = final_elem_ty.toIntern(), |
| ... | ... | @@ -4259,55 +4125,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4259 | 4125 | .data = .{ .ty = final_ptr_ty }, |
| 4260 | 4126 | }); |
| 4261 | 4127 | |
| 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 | |
| 4264 | 4129 | // the new result ptr type was available. |
| 4265 | const placeholders = ia2.prongs.items(.placeholder); | |
| 4266 | 4130 | const gpa = sema.gpa; |
| 4267 | 4131 | |
| 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| { | |
| 4291 | 4133 | var replacement_block = block.makeSubBlock(); |
| 4292 | 4134 | defer replacement_block.instructions.deinit(gpa); |
| 4293 | 4135 | |
| 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); | |
| 4298 | 4139 | |
| 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 | |
| 4311 | 4141 | // placeholder instruction with this instruction; no need for an entire block. |
| 4312 | 4142 | if (replacement_block.instructions.items.len == 1) { |
| 4313 | 4143 | const only_inst = replacement_block.instructions.items[0]; |
| ... | ... | @@ -4315,13 +4145,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4315 | 4145 | continue; |
| 4316 | 4146 | } |
| 4317 | 4147 | |
| 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); | |
| 4325 | 4151 | try sema.air_extra.ensureUnusedCapacity( |
| 4326 | 4152 | gpa, |
| 4327 | 4153 | @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len, |
| ... | ... | @@ -4329,7 +4155,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4329 | 4155 | sema.air_instructions.set(placeholder_inst, .{ |
| 4330 | 4156 | .tag = .block, |
| 4331 | 4157 | .data = .{ .ty_pl = .{ |
| 4332 | .ty = ty_inst, | |
| 4158 | .ty = .void_type, | |
| 4333 | 4159 | .payload = sema.addExtraAssumeCapacity(Air.Block{ |
| 4334 | 4160 | .body_len = @intCast(replacement_block.instructions.items.len), |
| 4335 | 4161 | }), |
| ... | ... | @@ -4342,64 +4168,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4342 | 4168 | } |
| 4343 | 4169 | } |
| 4344 | 4170 | |
| 4345 | fn 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 | ||
| 4375 | fn 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 | ||
| 4403 | 4171 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4404 | 4172 | const mod = sema.mod; |
| 4405 | 4173 | const gpa = sema.gpa; |
| ... | ... | @@ -4526,34 +4294,140 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4526 | 4294 | return len; |
| 4527 | 4295 | } |
| 4528 | 4296 | |
| 4529 | fn 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. | |
| 4301 | fn 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 | ||
| 4313 | fn 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 | ||
| 4319 | fn 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 | ||
| 4370 | fn 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 | ||
| 4391 | fn zirValidateArrayInitRefTy( | |
| 4530 | 4392 | sema: *Sema, |
| 4531 | 4393 | block: *Block, |
| 4532 | 4394 | inst: Zir.Inst.Index, |
| 4533 | 4395 | ) CompileError!Air.Inst.Ref { |
| 4534 | 4396 | 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) { | |
| 4541 | 4401 | error.GenericPoison => return .generic_poison_type, |
| 4542 | 4402 | else => |e| return e, |
| 4543 | 4403 | }; |
| 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()); | |
| 4550 | 4414 | } |
| 4415 | // Otherwise, we just want the pointer child type | |
| 4416 | const ret_ty = ptr_ty.childType(mod); | |
| 4417 | if (ret_ty.toIntern() == .anyopaque_type) { | |
| 4418 | // The actual array type is unknown, which we represent with a generic poison. | |
| 4419 | return .generic_poison_type; | |
| 4420 | } | |
| 4421 | const arr_ty = ret_ty.optEuBaseType(mod); | |
| 4422 | try sema.validateArrayInitTy(block, src, src, extra.elem_count, arr_ty); | |
| 4423 | return Air.internedToRef(ret_ty.toIntern()); | |
| 4551 | 4424 | } |
| 4552 | 4425 | |
| 4553 | 4426 | fn zirValidateArrayInitTy( |
| 4554 | 4427 | sema: *Sema, |
| 4555 | 4428 | block: *Block, |
| 4556 | 4429 | inst: Zir.Inst.Index, |
| 4430 | is_result_ty: bool, | |
| 4557 | 4431 | ) CompileError!void { |
| 4558 | 4432 | const mod = sema.mod; |
| 4559 | 4433 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| ... | ... | @@ -4565,22 +4439,34 @@ fn zirValidateArrayInitTy( |
| 4565 | 4439 | error.GenericPoison => return, |
| 4566 | 4440 | else => |e| return e, |
| 4567 | 4441 | }; |
| 4442 | const arr_ty = if (is_result_ty) ty.optEuBaseType(mod) else ty; | |
| 4443 | return sema.validateArrayInitTy(block, src, ty_src, extra.init_count, arr_ty); | |
| 4444 | } | |
| 4568 | 4445 | |
| 4446 | fn validateArrayInitTy( | |
| 4447 | sema: *Sema, | |
| 4448 | block: *Block, | |
| 4449 | src: LazySrcLoc, | |
| 4450 | ty_src: LazySrcLoc, | |
| 4451 | init_count: u32, | |
| 4452 | ty: Type, | |
| 4453 | ) CompileError!void { | |
| 4454 | const mod = sema.mod; | |
| 4569 | 4455 | switch (ty.zigTypeTag(mod)) { |
| 4570 | 4456 | .Array => { |
| 4571 | 4457 | const array_len = ty.arrayLen(mod); |
| 4572 | if (extra.init_count != array_len) { | |
| 4458 | if (init_count != array_len) { | |
| 4573 | 4459 | return sema.fail(block, src, "expected {d} array elements; found {d}", .{ |
| 4574 | array_len, extra.init_count, | |
| 4460 | array_len, init_count, | |
| 4575 | 4461 | }); |
| 4576 | 4462 | } |
| 4577 | 4463 | return; |
| 4578 | 4464 | }, |
| 4579 | 4465 | .Vector => { |
| 4580 | 4466 | const array_len = ty.arrayLen(mod); |
| 4581 | if (extra.init_count != array_len) { | |
| 4467 | if (init_count != array_len) { | |
| 4582 | 4468 | return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ |
| 4583 | array_len, extra.init_count, | |
| 4469 | array_len, init_count, | |
| 4584 | 4470 | }); |
| 4585 | 4471 | } |
| 4586 | 4472 | return; |
| ... | ... | @@ -4588,9 +4474,9 @@ fn zirValidateArrayInitTy( |
| 4588 | 4474 | .Struct => if (ty.isTuple(mod)) { |
| 4589 | 4475 | try sema.resolveTypeFields(ty); |
| 4590 | 4476 | const array_len = ty.arrayLen(mod); |
| 4591 | if (extra.init_count > array_len) { | |
| 4477 | if (init_count > array_len) { | |
| 4592 | 4478 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ |
| 4593 | array_len, extra.init_count, | |
| 4479 | array_len, init_count, | |
| 4594 | 4480 | }); |
| 4595 | 4481 | } |
| 4596 | 4482 | return; |
| ... | ... | @@ -4604,6 +4490,7 @@ fn zirValidateStructInitTy( |
| 4604 | 4490 | sema: *Sema, |
| 4605 | 4491 | block: *Block, |
| 4606 | 4492 | inst: Zir.Inst.Index, |
| 4493 | is_result_ty: bool, | |
| 4607 | 4494 | ) CompileError!void { |
| 4608 | 4495 | const mod = sema.mod; |
| 4609 | 4496 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| ... | ... | @@ -4613,15 +4500,16 @@ fn zirValidateStructInitTy( |
| 4613 | 4500 | error.GenericPoison => return, |
| 4614 | 4501 | else => |e| return e, |
| 4615 | 4502 | }; |
| 4503 | const struct_ty = if (is_result_ty) ty.optEuBaseType(mod) else ty; | |
| 4616 | 4504 | |
| 4617 | switch (ty.zigTypeTag(mod)) { | |
| 4505 | switch (struct_ty.zigTypeTag(mod)) { | |
| 4618 | 4506 | .Struct, .Union => return, |
| 4619 | 4507 | else => {}, |
| 4620 | 4508 | } |
| 4621 | return sema.failWithStructInitNotSupported(block, src, ty); | |
| 4509 | return sema.failWithStructInitNotSupported(block, src, struct_ty); | |
| 4622 | 4510 | } |
| 4623 | 4511 | |
| 4624 | fn zirValidateStructInit( | |
| 4512 | fn zirValidatePtrStructInit( | |
| 4625 | 4513 | sema: *Sema, |
| 4626 | 4514 | block: *Block, |
| 4627 | 4515 | inst: Zir.Inst.Index, |
| ... | ... | @@ -4637,7 +4525,7 @@ fn zirValidateStructInit( |
| 4637 | 4525 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 4638 | 4526 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4639 | 4527 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); |
| 4640 | const agg_ty = sema.typeOf(object_ptr).childType(mod); | |
| 4528 | const agg_ty = sema.typeOf(object_ptr).childType(mod).optEuBaseType(mod); | |
| 4641 | 4529 | switch (agg_ty.zigTypeTag(mod)) { |
| 4642 | 4530 | .Struct => return sema.validateStructInit( |
| 4643 | 4531 | block, |
| ... | ... | @@ -4723,10 +4611,6 @@ fn validateUnionInit( |
| 4723 | 4611 | // based only on the store instructions. |
| 4724 | 4612 | // `first_block_index` needs to point to the `field_ptr` if it exists; |
| 4725 | 4613 | // the `store` otherwise. |
| 4726 | // | |
| 4727 | // It's also possible for there to be no store instruction, in the case | |
| 4728 | // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` | |
| 4729 | // but we have not found a `store`, treat as a runtime-known field. | |
| 4730 | 4614 | var first_block_index = block.instructions.items.len; |
| 4731 | 4615 | var block_index = block.instructions.items.len - 1; |
| 4732 | 4616 | var init_val: ?Value = null; |
| ... | ... | @@ -4963,10 +4847,6 @@ fn validateStructInit( |
| 4963 | 4847 | // based only on the store instructions. |
| 4964 | 4848 | // `first_block_index` needs to point to the `field_ptr` if it exists; |
| 4965 | 4849 | // the `store` otherwise. |
| 4966 | // | |
| 4967 | // It's also possible for there to be no store instruction, in the case | |
| 4968 | // of nested `coerce_result_ptr` instructions. If we see the `field_ptr` | |
| 4969 | // but we have not found a `store`, treat as a runtime-known field. | |
| 4970 | 4850 | |
| 4971 | 4851 | // Possible performance enhancement: save the `block_index` between iterations |
| 4972 | 4852 | // of the for loop. |
| ... | ... | @@ -5115,7 +4995,7 @@ fn validateStructInit( |
| 5115 | 4995 | } |
| 5116 | 4996 | } |
| 5117 | 4997 | |
| 5118 | fn zirValidateArrayInit( | |
| 4998 | fn zirValidatePtrArrayInit( | |
| 5119 | 4999 | sema: *Sema, |
| 5120 | 5000 | block: *Block, |
| 5121 | 5001 | inst: Zir.Inst.Index, |
| ... | ... | @@ -5128,7 +5008,7 @@ fn zirValidateArrayInit( |
| 5128 | 5008 | const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 5129 | 5009 | const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; |
| 5130 | 5010 | const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); |
| 5131 | const array_ty = sema.typeOf(array_ptr).childType(mod); | |
| 5011 | const array_ty = sema.typeOf(array_ptr).childType(mod).optEuBaseType(mod); | |
| 5132 | 5012 | const array_len = array_ty.arrayLen(mod); |
| 5133 | 5013 | |
| 5134 | 5014 | if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -5227,10 +5107,6 @@ fn zirValidateArrayInit( |
| 5227 | 5107 | // `first_block_index` needs to point to the `elem_ptr` if it exists; |
| 5228 | 5108 | // the `store` otherwise. |
| 5229 | 5109 | // |
| 5230 | // It's also possible for there to be no store instruction, in the case | |
| 5231 | // of nested `coerce_result_ptr` instructions. If we see the `elem_ptr` | |
| 5232 | // but we have not found a `store`, treat as a runtime-known element. | |
| 5233 | // | |
| 5234 | 5110 | // This is nearly identical to similar logic in `validateStructInit`. |
| 5235 | 5111 | |
| 5236 | 5112 | // Possible performance enhancement: save the `block_index` between iterations |
| ... | ... | @@ -5540,10 +5416,7 @@ fn storeToInferredAlloc( |
| 5540 | 5416 | try sema.checkComptimeKnownStore(block, dummy_store); |
| 5541 | 5417 | // Add the stored instruction to the set we will use to resolve peer types |
| 5542 | 5418 | // 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).?); | |
| 5547 | 5420 | } |
| 5548 | 5421 | |
| 5549 | 5422 | fn storeToInferredAllocComptime( |
| ... | ... | @@ -8314,10 +8187,10 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 8314 | 8187 | return Air.internedToRef(opt_type.toIntern()); |
| 8315 | 8188 | } |
| 8316 | 8189 | |
| 8317 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 8190 | fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 8318 | 8191 | const mod = sema.mod; |
| 8319 | 8192 | const bin = sema.code.instructions.items(.data)[inst].bin; |
| 8320 | const indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { | |
| 8193 | const maybe_wrapped_indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { | |
| 8321 | 8194 | // Since this is a ZIR instruction that returns a type, encountering |
| 8322 | 8195 | // generic poison should not result in a failed compilation, but the |
| 8323 | 8196 | // generic poison type. This prevents unnecessary failures when |
| ... | ... | @@ -8325,6 +8198,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 8325 | 8198 | error.GenericPoison => return .generic_poison_type, |
| 8326 | 8199 | else => |e| return e, |
| 8327 | 8200 | }; |
| 8201 | const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(mod); | |
| 8328 | 8202 | try sema.resolveTypeFields(indexable_ty); |
| 8329 | 8203 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction |
| 8330 | 8204 | if (indexable_ty.zigTypeTag(mod) == .Struct) { |
| ... | ... | @@ -8339,8 +8213,18 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 8339 | 8213 | fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8340 | 8214 | const mod = sema.mod; |
| 8341 | 8215 | const un_node = sema.code.instructions.items(.data)[inst].un_node; |
| 8342 | const ptr_ty = try sema.resolveType(block, .unneeded, un_node.operand); | |
| 8216 | const maybe_wrapped_ptr_ty = sema.resolveType(block, .unneeded, un_node.operand) catch |err| switch (err) { | |
| 8217 | error.GenericPoison => return .generic_poison_type, | |
| 8218 | else => |e| return e, | |
| 8219 | }; | |
| 8220 | const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(mod); | |
| 8343 | 8221 | assert(ptr_ty.zigTypeTag(mod) == .Pointer); // validated by a previous instruction |
| 8222 | const elem_ty = ptr_ty.childType(mod); | |
| 8223 | if (elem_ty.toIntern() == .anyopaque_type) { | |
| 8224 | // The pointer's actual child type is effectively unknown, so it makes | |
| 8225 | // sense to represent it with a generic poison. | |
| 8226 | return .generic_poison_type; | |
| 8227 | } | |
| 8344 | 8228 | return Air.internedToRef(ptr_ty.childType(mod).toIntern()); |
| 8345 | 8229 | } |
| 8346 | 8230 | |
| ... | ... | @@ -10083,7 +9967,21 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 10083 | 9967 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 10084 | 9968 | } |
| 10085 | 9969 | |
| 10086 | fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: bool) CompileError!Air.Inst.Ref { | |
| 9970 | fn 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 | ||
| 9984 | fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10087 | 9985 | const tracy = trace(@src()); |
| 10088 | 9986 | defer tracy.end(); |
| 10089 | 9987 | |
| ... | ... | @@ -10094,7 +9992,15 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b |
| 10094 | 9992 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 10095 | 9993 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); |
| 10096 | 9994 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 10097 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); | |
| 9995 | const struct_ty = sema.typeOf(object_ptr).childType(mod); | |
| 9996 | switch (struct_ty.zigTypeTag(mod)) { | |
| 9997 | .Struct, .Union => { | |
| 9998 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, true); | |
| 9999 | }, | |
| 10000 | else => { | |
| 10001 | return sema.failWithStructInitNotSupported(block, src, struct_ty); | |
| 10002 | }, | |
| 10003 | } | |
| 10098 | 10004 | } |
| 10099 | 10005 | |
| 10100 | 10006 | fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -10587,15 +10493,23 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10587 | 10493 | return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true); |
| 10588 | 10494 | } |
| 10589 | 10495 | |
| 10590 | fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10496 | fn zirArrayInitElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10591 | 10497 | const tracy = trace(@src()); |
| 10592 | 10498 | defer tracy.end(); |
| 10593 | 10499 | |
| 10500 | const mod = sema.mod; | |
| 10594 | 10501 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 10595 | 10502 | const src = inst_data.src(); |
| 10596 | 10503 | const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; |
| 10597 | 10504 | const array_ptr = try sema.resolveInst(extra.ptr); |
| 10598 | 10505 | const elem_index = try sema.mod.intRef(Type.usize, extra.index); |
| 10506 | const array_ty = sema.typeOf(array_ptr).childType(mod); | |
| 10507 | switch (array_ty.zigTypeTag(mod)) { | |
| 10508 | .Array, .Vector => {}, | |
| 10509 | else => if (!array_ty.isTuple(mod)) { | |
| 10510 | return sema.failWithArrayInitNotSupported(block, src, array_ty); | |
| 10511 | }, | |
| 10512 | } | |
| 10599 | 10513 | return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true); |
| 10600 | 10514 | } |
| 10601 | 10515 | |
| ... | ... | @@ -19213,6 +19127,52 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 19213 | 19127 | } |
| 19214 | 19128 | } |
| 19215 | 19129 | |
| 19130 | fn 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 | ||
| 19216 | 19176 | fn structInitEmpty( |
| 19217 | 19177 | sema: *Sema, |
| 19218 | 19178 | block: *Block, |
| ... | ... | @@ -19230,7 +19190,7 @@ fn structInitEmpty( |
| 19230 | 19190 | defer gpa.free(field_inits); |
| 19231 | 19191 | @memset(field_inits, .none); |
| 19232 | 19192 | |
| 19233 | return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, false); | |
| 19193 | return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, struct_ty, false); | |
| 19234 | 19194 | } |
| 19235 | 19195 | |
| 19236 | 19196 | fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -19321,13 +19281,14 @@ fn zirStructInit( |
| 19321 | 19281 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; |
| 19322 | 19282 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; |
| 19323 | 19283 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; |
| 19324 | const resolved_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) { | |
| 19284 | const result_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) { | |
| 19325 | 19285 | error.GenericPoison => { |
| 19326 | 19286 | // The type wasn't actually known, so treat this as an anon struct init. |
| 19327 | 19287 | return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref); |
| 19328 | 19288 | }, |
| 19329 | 19289 | else => |e| return e, |
| 19330 | 19290 | }; |
| 19291 | const resolved_ty = result_ty.optEuBaseType(mod); | |
| 19331 | 19292 | try sema.resolveTypeLayout(resolved_ty); |
| 19332 | 19293 | |
| 19333 | 19294 | if (resolved_ty.zigTypeTag(mod) == .Struct) { |
| ... | ... | @@ -19372,7 +19333,9 @@ fn zirStructInit( |
| 19372 | 19333 | return sema.failWithOwnedErrorMsg(block, msg); |
| 19373 | 19334 | } |
| 19374 | 19335 | found_fields[field_index] = item.data.field_type; |
| 19375 | field_inits[field_index] = try sema.resolveInst(item.data.init); | |
| 19336 | const uncoerced_init = try sema.resolveInst(item.data.init); | |
| 19337 | const field_ty = resolved_ty.structFieldType(field_index, mod); | |
| 19338 | field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); | |
| 19376 | 19339 | if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| { |
| 19377 | 19340 | const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse { |
| 19378 | 19341 | return sema.failWithNeededComptime(block, field_src, .{ |
| ... | ... | @@ -19386,7 +19349,7 @@ fn zirStructInit( |
| 19386 | 19349 | }; |
| 19387 | 19350 | } |
| 19388 | 19351 | |
| 19389 | return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); | |
| 19352 | return sema.finishStructInit(block, src, src, field_inits, resolved_ty, result_ty, is_ref); | |
| 19390 | 19353 | } else if (resolved_ty.zigTypeTag(mod) == .Union) { |
| 19391 | 19354 | if (extra.data.fields_len != 1) { |
| 19392 | 19355 | return sema.fail(block, src, "union initialization expects exactly one field", .{}); |
| ... | ... | @@ -19401,36 +19364,60 @@ fn zirStructInit( |
| 19401 | 19364 | const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); |
| 19402 | 19365 | const tag_ty = resolved_ty.unionTagTypeHypothetical(mod); |
| 19403 | 19366 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 19367 | const field_ty = mod.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index].toType(); | |
| 19368 | ||
| 19369 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | |
| 19370 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 19371 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); | |
| 19372 | errdefer msg.destroy(sema.gpa); | |
| 19373 | ||
| 19374 | try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{}' declared here", .{ | |
| 19375 | field_name.fmt(ip), | |
| 19376 | }); | |
| 19377 | try sema.addDeclaredHereNote(msg, resolved_ty); | |
| 19378 | break :msg msg; | |
| 19379 | }); | |
| 19380 | } | |
| 19381 | ||
| 19382 | const uncoerced_init_inst = try sema.resolveInst(item.data.init); | |
| 19383 | const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src); | |
| 19404 | 19384 | |
| 19405 | const init_inst = try sema.resolveInst(item.data.init); | |
| 19406 | 19385 | 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 = .{ | |
| 19409 | 19387 | .ty = resolved_ty.toIntern(), |
| 19410 | 19388 | .tag = try tag_val.intern(tag_ty, mod), |
| 19411 | 19389 | .val = try val.intern(field_ty, mod), |
| 19412 | } })).toValue(), is_ref); | |
| 19390 | } })).toValue(); | |
| 19391 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); | |
| 19392 | const final_val = (try sema.resolveMaybeUndefVal(final_val_inst)).?; | |
| 19393 | return sema.addConstantMaybeRef(block, resolved_ty, final_val, is_ref); | |
| 19394 | } | |
| 19395 | ||
| 19396 | if (try sema.typeRequiresComptime(resolved_ty)) { | |
| 19397 | return sema.failWithNeededComptime(block, field_src, .{ | |
| 19398 | .needed_comptime_reason = "initializer of comptime only union must be comptime-known", | |
| 19399 | }); | |
| 19413 | 19400 | } |
| 19414 | 19401 | |
| 19415 | 19402 | if (is_ref) { |
| 19416 | 19403 | const target = mod.getTarget(); |
| 19417 | 19404 | const alloc_ty = try sema.ptrType(.{ |
| 19418 | .child = resolved_ty.toIntern(), | |
| 19405 | .child = result_ty.toIntern(), | |
| 19419 | 19406 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19420 | 19407 | }); |
| 19421 | 19408 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19422 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); | |
| 19409 | const base_ptr = try sema.optEuBasePtrInit(block, alloc, src); | |
| 19410 | const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true); | |
| 19423 | 19411 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 19424 | 19412 | const new_tag = Air.internedToRef(tag_val.toIntern()); |
| 19425 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); | |
| 19413 | _ = try block.addBinOp(.set_union_tag, base_ptr, new_tag); | |
| 19426 | 19414 | return sema.makePtrConst(block, alloc); |
| 19427 | 19415 | } |
| 19428 | 19416 | |
| 19429 | 19417 | try sema.requireRuntimeBlock(block, src, null); |
| 19430 | 19418 | 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); | |
| 19434 | 19421 | } |
| 19435 | 19422 | unreachable; |
| 19436 | 19423 | } |
| ... | ... | @@ -19442,6 +19429,7 @@ fn finishStructInit( |
| 19442 | 19429 | dest_src: LazySrcLoc, |
| 19443 | 19430 | field_inits: []Air.Inst.Ref, |
| 19444 | 19431 | struct_ty: Type, |
| 19432 | result_ty: Type, | |
| 19445 | 19433 | is_ref: bool, |
| 19446 | 19434 | ) CompileError!Air.Inst.Ref { |
| 19447 | 19435 | const mod = sema.mod; |
| ... | ... | @@ -19452,8 +19440,24 @@ fn finishStructInit( |
| 19452 | 19440 | |
| 19453 | 19441 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 19454 | 19442 | .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]; | |
| 19457 | 19461 | |
| 19458 | 19462 | if (default_val == .none) { |
| 19459 | 19463 | if (anon_struct.names.len == 0) { |
| ... | ... | @@ -19480,7 +19484,20 @@ fn finishStructInit( |
| 19480 | 19484 | }, |
| 19481 | 19485 | .struct_type => |struct_type| { |
| 19482 | 19486 | for (0..struct_type.field_types.len) |i| { |
| 19483 | if (field_inits[i] != .none) continue; | |
| 19487 | if (field_inits[i] != .none) { | |
| 19488 | // Coerce the init value to the field type. | |
| 19489 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 19490 | field_inits[i] = sema.coerce(block, field_ty, field_inits[i], init_src) catch |err| switch (err) { | |
| 19491 | error.NeededSourceLocation => { | |
| 19492 | const decl = mod.declPtr(block.src_decl); | |
| 19493 | const field_src = mod.initSrc(init_src.node_offset.x, decl, i); | |
| 19494 | _ = try sema.coerce(block, field_ty, field_inits[i], field_src); | |
| 19495 | unreachable; | |
| 19496 | }, | |
| 19497 | else => |e| return e, | |
| 19498 | }; | |
| 19499 | continue; | |
| 19500 | } | |
| 19484 | 19501 | |
| 19485 | 19502 | const field_init = struct_type.fieldInit(ip, i); |
| 19486 | 19503 | if (field_init == .none) { |
| ... | ... | @@ -19524,29 +19541,39 @@ fn finishStructInit( |
| 19524 | 19541 | |
| 19525 | 19542 | const runtime_index = opt_runtime_index orelse { |
| 19526 | 19543 | 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(); | |
| 19530 | 19546 | } |
| 19531 | 19547 | const struct_val = try mod.intern(.{ .aggregate = .{ |
| 19532 | 19548 | .ty = struct_ty.toIntern(), |
| 19533 | 19549 | .storage = .{ .elems = elems }, |
| 19534 | 19550 | } }); |
| 19535 | return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref); | |
| 19551 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val), init_src); | |
| 19552 | const final_val = (try sema.resolveMaybeUndefVal(final_val_inst)).?; | |
| 19553 | return sema.addConstantMaybeRef(block, result_ty, final_val, is_ref); | |
| 19536 | 19554 | }; |
| 19537 | 19555 | |
| 19556 | if (try sema.typeRequiresComptime(struct_ty)) { | |
| 19557 | const decl = mod.declPtr(block.src_decl); | |
| 19558 | const field_src = mod.initSrc(init_src.node_offset.x, decl, runtime_index); | |
| 19559 | return sema.failWithNeededComptime(block, field_src, .{ | |
| 19560 | .needed_comptime_reason = "initializer of comptime only struct must be comptime-known", | |
| 19561 | }); | |
| 19562 | } | |
| 19563 | ||
| 19538 | 19564 | if (is_ref) { |
| 19539 | 19565 | try sema.resolveStructLayout(struct_ty); |
| 19540 | 19566 | const target = sema.mod.getTarget(); |
| 19541 | 19567 | const alloc_ty = try sema.ptrType(.{ |
| 19542 | .child = struct_ty.toIntern(), | |
| 19568 | .child = result_ty.toIntern(), | |
| 19543 | 19569 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19544 | 19570 | }); |
| 19545 | 19571 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19572 | const base_ptr = try sema.optEuBasePtrInit(block, alloc, init_src); | |
| 19546 | 19573 | for (field_inits, 0..) |field_init, i_usize| { |
| 19547 | 19574 | const i: u32 = @intCast(i_usize); |
| 19548 | 19575 | const field_src = dest_src; |
| 19549 | const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, alloc, i, field_src, struct_ty, true); | |
| 19576 | const field_ptr = try sema.structFieldPtrByIndex(block, dest_src, base_ptr, i, field_src, struct_ty, true); | |
| 19550 | 19577 | try sema.storePtr(block, dest_src, field_ptr, field_init); |
| 19551 | 19578 | } |
| 19552 | 19579 | |
| ... | ... | @@ -19563,19 +19590,19 @@ fn finishStructInit( |
| 19563 | 19590 | else => |e| return e, |
| 19564 | 19591 | }; |
| 19565 | 19592 | try sema.queueFullTypeResolution(struct_ty); |
| 19566 | return block.addAggregateInit(struct_ty, field_inits); | |
| 19593 | const struct_val = try block.addAggregateInit(struct_ty, field_inits); | |
| 19594 | return sema.coerce(block, result_ty, struct_val, init_src); | |
| 19567 | 19595 | } |
| 19568 | 19596 | |
| 19569 | 19597 | fn zirStructInitAnon( |
| 19570 | 19598 | sema: *Sema, |
| 19571 | 19599 | block: *Block, |
| 19572 | 19600 | inst: Zir.Inst.Index, |
| 19573 | is_ref: bool, | |
| 19574 | 19601 | ) CompileError!Air.Inst.Ref { |
| 19575 | 19602 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19576 | 19603 | const src = inst_data.src(); |
| 19577 | 19604 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); |
| 19578 | return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, is_ref); | |
| 19605 | return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, false); | |
| 19579 | 19606 | } |
| 19580 | 19607 | |
| 19581 | 19608 | fn structInitAnon( |
| ... | ... | @@ -19748,13 +19775,14 @@ fn zirArrayInit( |
| 19748 | 19775 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 19749 | 19776 | assert(args.len >= 2); // array_ty + at least one element |
| 19750 | 19777 | |
| 19751 | const array_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) { | |
| 19778 | const result_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) { | |
| 19752 | 19779 | error.GenericPoison => { |
| 19753 | 19780 | // The type wasn't actually known, so treat this as an anon array init. |
| 19754 | 19781 | return sema.arrayInitAnon(block, src, args[1..], is_ref); |
| 19755 | 19782 | }, |
| 19756 | 19783 | else => |e| return e, |
| 19757 | 19784 | }; |
| 19785 | const array_ty = result_ty.optEuBaseType(mod); | |
| 19758 | 19786 | const is_tuple = array_ty.zigTypeTag(mod) == .Struct; |
| 19759 | 19787 | const sentinel_val = array_ty.sentinel(mod); |
| 19760 | 19788 | |
| ... | ... | @@ -19810,10 +19838,12 @@ fn zirArrayInit( |
| 19810 | 19838 | // We checked that all args are comptime above. |
| 19811 | 19839 | val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod); |
| 19812 | 19840 | } |
| 19813 | return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{ | |
| 19841 | const arr_val = try mod.intern(.{ .aggregate = .{ | |
| 19814 | 19842 | .ty = array_ty.toIntern(), |
| 19815 | 19843 | .storage = .{ .elems = elem_vals }, |
| 19816 | } })).toValue(), is_ref); | |
| 19844 | } }); | |
| 19845 | const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val), src); | |
| 19846 | return sema.addConstantMaybeRef(block, result_ty, (try sema.resolveMaybeUndefVal(result_ref)).?, is_ref); | |
| 19817 | 19847 | }; |
| 19818 | 19848 | |
| 19819 | 19849 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| ... | ... | @@ -19830,10 +19860,11 @@ fn zirArrayInit( |
| 19830 | 19860 | if (is_ref) { |
| 19831 | 19861 | const target = mod.getTarget(); |
| 19832 | 19862 | const alloc_ty = try sema.ptrType(.{ |
| 19833 | .child = array_ty.toIntern(), | |
| 19863 | .child = result_ty.toIntern(), | |
| 19834 | 19864 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19835 | 19865 | }); |
| 19836 | 19866 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19867 | const base_ptr = try sema.optEuBasePtrInit(block, alloc, src); | |
| 19837 | 19868 | |
| 19838 | 19869 | if (array_ty.isTuple(mod)) { |
| 19839 | 19870 | for (resolved_args, 0..) |arg, i| { |
| ... | ... | @@ -19844,7 +19875,7 @@ fn zirArrayInit( |
| 19844 | 19875 | const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern()); |
| 19845 | 19876 | |
| 19846 | 19877 | const index = try mod.intRef(Type.usize, i); |
| 19847 | const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); | |
| 19878 | const elem_ptr = try block.addPtrElemPtrTypeRef(base_ptr, index, elem_ptr_ty_ref); | |
| 19848 | 19879 | _ = try block.addBinOp(.store, elem_ptr, arg); |
| 19849 | 19880 | } |
| 19850 | 19881 | return sema.makePtrConst(block, alloc); |
| ... | ... | @@ -19858,26 +19889,26 @@ fn zirArrayInit( |
| 19858 | 19889 | |
| 19859 | 19890 | for (resolved_args, 0..) |arg, i| { |
| 19860 | 19891 | const index = try mod.intRef(Type.usize, i); |
| 19861 | const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref); | |
| 19892 | const elem_ptr = try block.addPtrElemPtrTypeRef(base_ptr, index, elem_ptr_ty_ref); | |
| 19862 | 19893 | _ = try block.addBinOp(.store, elem_ptr, arg); |
| 19863 | 19894 | } |
| 19864 | 19895 | return sema.makePtrConst(block, alloc); |
| 19865 | 19896 | } |
| 19866 | 19897 | |
| 19867 | return block.addAggregateInit(array_ty, resolved_args); | |
| 19898 | const arr_ref = try block.addAggregateInit(array_ty, resolved_args); | |
| 19899 | return sema.coerce(block, result_ty, arr_ref, src); | |
| 19868 | 19900 | } |
| 19869 | 19901 | |
| 19870 | 19902 | fn zirArrayInitAnon( |
| 19871 | 19903 | sema: *Sema, |
| 19872 | 19904 | block: *Block, |
| 19873 | 19905 | inst: Zir.Inst.Index, |
| 19874 | is_ref: bool, | |
| 19875 | 19906 | ) CompileError!Air.Inst.Ref { |
| 19876 | 19907 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19877 | 19908 | const src = inst_data.src(); |
| 19878 | 19909 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 19879 | 19910 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 19880 | return sema.arrayInitAnon(block, src, operands, is_ref); | |
| 19911 | return sema.arrayInitAnon(block, src, operands, false); | |
| 19881 | 19912 | } |
| 19882 | 19913 | |
| 19883 | 19914 | fn arrayInitAnon( |
| ... | ... | @@ -19997,14 +20028,14 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 19997 | 20028 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); |
| 19998 | 20029 | } |
| 19999 | 20030 | |
| 20000 | fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 20031 | fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 20001 | 20032 | const mod = sema.mod; |
| 20002 | 20033 | const ip = &mod.intern_pool; |
| 20003 | 20034 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 20004 | 20035 | const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; |
| 20005 | 20036 | const ty_src = inst_data.src(); |
| 20006 | 20037 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 20007 | const aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) { | |
| 20038 | const wrapped_aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) { | |
| 20008 | 20039 | // Since this is a ZIR instruction that returns a type, encountering |
| 20009 | 20040 | // generic poison should not result in a failed compilation, but the |
| 20010 | 20041 | // generic poison type. This prevents unnecessary failures when |
| ... | ... | @@ -20012,6 +20043,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 20012 | 20043 | error.GenericPoison => return .generic_poison_type, |
| 20013 | 20044 | else => |e| return e, |
| 20014 | 20045 | }; |
| 20046 | const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(mod); | |
| 20015 | 20047 | const zir_field_name = sema.code.nullTerminatedString(extra.name_start); |
| 20016 | 20048 | const field_name = try ip.getOrPutString(sema.gpa, zir_field_name); |
| 20017 | 20049 | return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); |
| ... | ... | @@ -20033,7 +20065,10 @@ fn fieldType( |
| 20033 | 20065 | switch (cur_ty.zigTypeTag(mod)) { |
| 20034 | 20066 | .Struct => switch (ip.indexToKey(cur_ty.toIntern())) { |
| 20035 | 20067 | .anon_struct_type => |anon_struct| { |
| 20036 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); | |
| 20068 | const field_index = if (anon_struct.names.len == 0) | |
| 20069 | try sema.tupleFieldIndex(block, cur_ty, field_name, field_src) | |
| 20070 | else | |
| 20071 | try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); | |
| 20037 | 20072 | return Air.internedToRef(anon_struct.types.get(ip)[field_index]); |
| 20038 | 20073 | }, |
| 20039 | 20074 | .struct_type => |struct_type| { |
| ... | ... | @@ -21620,7 +21655,8 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21620 | 21655 | const operand_coerced = try sema.coerce(block, operand_ty, operand_res, operand_src); |
| 21621 | 21656 | |
| 21622 | 21657 | const ptr_ty = dest_ty.scalarType(mod); |
| 21623 | try sema.checkPtrType(block, src, ptr_ty); | |
| 21658 | try sema.checkPtrType(block, src, ptr_ty, true); | |
| 21659 | ||
| 21624 | 21660 | const elem_ty = ptr_ty.elemType2(mod); |
| 21625 | 21661 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); |
| 21626 | 21662 | |
| ... | ... | @@ -21860,7 +21896,7 @@ fn ptrCastFull( |
| 21860 | 21896 | const mod = sema.mod; |
| 21861 | 21897 | const operand_ty = sema.typeOf(operand); |
| 21862 | 21898 | |
| 21863 | try sema.checkPtrType(block, src, dest_ty); | |
| 21899 | try sema.checkPtrType(block, src, dest_ty, true); | |
| 21864 | 21900 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| 21865 | 21901 | |
| 21866 | 21902 | const src_info = operand_ty.ptrInfo(mod); |
| ... | ... | @@ -22668,10 +22704,11 @@ fn checkPtrType( |
| 22668 | 22704 | block: *Block, |
| 22669 | 22705 | ty_src: LazySrcLoc, |
| 22670 | 22706 | ty: Type, |
| 22707 | allow_slice: bool, | |
| 22671 | 22708 | ) CompileError!void { |
| 22672 | 22709 | const mod = sema.mod; |
| 22673 | 22710 | switch (ty.zigTypeTag(mod)) { |
| 22674 | .Pointer => return, | |
| 22711 | .Pointer => if (allow_slice or !ty.isSlice(mod)) return, | |
| 22675 | 22712 | .Fn => { |
| 22676 | 22713 | const msg = msg: { |
| 22677 | 22714 | const msg = try sema.errMsg( |
| ... | ... | @@ -29577,13 +29614,6 @@ fn storePtr2( |
| 29577 | 29614 | return; |
| 29578 | 29615 | } |
| 29579 | 29616 | |
| 29580 | if (air_tag == .bitcast) { | |
| 29581 | // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr` | |
| 29582 | // to avoid calling `requireRuntimeBlock` for the dummy block. | |
| 29583 | _ = try block.addBinOp(.store, ptr, operand); | |
| 29584 | return; | |
| 29585 | } | |
| 29586 | ||
| 29587 | 29617 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 29588 | 29618 | try sema.queueFullTypeResolution(elem_ty); |
| 29589 | 29619 | |
| ... | ... | @@ -29719,6 +29749,7 @@ fn storePtrVal( |
| 29719 | 29749 | switch (mut_kit.pointee) { |
| 29720 | 29750 | .direct => |val_ptr| { |
| 29721 | 29751 | if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { |
| 29752 | val_ptr.* = (try val_ptr.intern(operand_ty, mod)).toValue(); | |
| 29722 | 29753 | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { |
| 29723 | 29754 | // TODO use failWithInvalidComptimeFieldStore |
| 29724 | 29755 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
src/Zir.zig+181-144| ... | ... | @@ -242,10 +242,9 @@ pub const Inst = struct { |
| 242 | 242 | /// Uses the `pl_node` union field with `Bin` payload. |
| 243 | 243 | /// lhs is length, rhs is element type. |
| 244 | 244 | 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`. | |
| 249 | 248 | /// Uses the `un_node` field. |
| 250 | 249 | elem_type, |
| 251 | 250 | /// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its |
| ... | ... | @@ -353,11 +352,6 @@ pub const Inst = struct { |
| 353 | 352 | /// `!=` |
| 354 | 353 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 355 | 354 | cmp_neq, |
| 356 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- | |
| 357 | /// as type coercion from the new element type to the old element type. | |
| 358 | /// Uses the `pl_node` union field. Payload is `Bin`. | |
| 359 | /// LHS is destination element type, RHS is result pointer. | |
| 360 | coerce_result_ptr, | |
| 361 | 355 | /// Conditional branch. Splits control flow based on a boolean condition value. |
| 362 | 356 | /// Uses the `pl_node` union field. AST node is an if, while, for, etc. |
| 363 | 357 | /// Payload is `CondBr`. |
| ... | ... | @@ -419,13 +413,6 @@ pub const Inst = struct { |
| 419 | 413 | /// Payload is `Bin`. |
| 420 | 414 | /// No OOB safety check is emitted. |
| 421 | 415 | elem_ptr, |
| 422 | /// Same as `elem_ptr_node` except the index is stored immediately rather than | |
| 423 | /// as a reference to another ZIR instruction. | |
| 424 | /// Uses the `pl_node` union field. AST node is an element inside array initialization | |
| 425 | /// syntax. Payload is `ElemPtrImm`. | |
| 426 | /// This instruction has a way to set the result type to be a | |
| 427 | /// single-pointer or a many-pointer. | |
| 428 | elem_ptr_imm, | |
| 429 | 416 | /// Given an array, slice, or pointer, returns the element at the provided index. |
| 430 | 417 | /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. |
| 431 | 418 | elem_val_node, |
| ... | ... | @@ -463,8 +450,6 @@ pub const Inst = struct { |
| 463 | 450 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. |
| 464 | 451 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 465 | 452 | field_ptr, |
| 466 | /// Same as `field_ptr` but used for struct init. | |
| 467 | field_ptr_init, | |
| 468 | 453 | /// Given a struct or object that contains virtual fields, returns the named field. |
| 469 | 454 | /// The field name is stored in string_bytes. Used by a.b syntax. |
| 470 | 455 | /// This instruction also accepts a pointer. |
| ... | ... | @@ -688,84 +673,123 @@ pub const Inst = struct { |
| 688 | 673 | /// A switch expression. Uses the `pl_node` union field. |
| 689 | 674 | /// AST node is the switch, payload is `SwitchBlock`. Operand is a pointer. |
| 690 | 675 | switch_block_ref, |
| 691 | /// Given a | |
| 692 | /// *A returns *A | |
| 693 | /// *E!A returns *A | |
| 694 | /// *?A returns *A | |
| 695 | /// Uses the `un_node` field. | |
| 696 | array_base_ptr, | |
| 697 | /// Given a | |
| 698 | /// *S returns *S | |
| 699 | /// *E!S returns *S | |
| 700 | /// *?S returns *S | |
| 701 | /// Uses the `un_node` field. | |
| 702 | field_base_ptr, | |
| 703 | /// Given a type, strips all optional and error union types wrapping it. | |
| 704 | /// e.g. `E!?u32` becomes `u32`, `[]u8` becomes `[]u8`. | |
| 705 | /// Uses the `un_node` field. | |
| 706 | opt_eu_base_ty, | |
| 707 | /// Checks that the type supports array init syntax. | |
| 708 | /// Returns the underlying indexable type (since the given type may be e.g. an optional). | |
| 709 | /// Uses the `un_node` field. | |
| 710 | validate_array_init_ty, | |
| 711 | /// Checks that the type supports struct init syntax. | |
| 712 | /// Returns the underlying struct type (since the given type may be e.g. an optional). | |
| 713 | /// Uses the `un_node` field. | |
| 714 | validate_struct_init_ty, | |
| 715 | /// Given a set of `field_ptr` instructions, assumes they are all part of a struct | |
| 716 | /// initialization expression, and emits compile errors for duplicate fields | |
| 717 | /// as well as missing fields, if applicable. | |
| 718 | /// This instruction asserts that there is at least one field_ptr instruction, | |
| 719 | /// because it must use one of them to find out the struct type. | |
| 720 | /// Uses the `pl_node` field. Payload is `Block`. | |
| 721 | validate_struct_init, | |
| 722 | /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an | |
| 723 | /// array initialization expression, and emits a compile error if the number of | |
| 724 | /// elements does not match the array type. | |
| 725 | /// This instruction asserts that there is at least one `elem_ptr_imm` instruction, | |
| 726 | /// because it must use one of them to find out the array type. | |
| 727 | /// Uses the `pl_node` field. Payload is `Block`. | |
| 728 | validate_array_init, | |
| 729 | 676 | /// Check that operand type supports the dereference operand (.*). |
| 730 | 677 | /// Uses the `un_node` field. |
| 731 | 678 | validate_deref, |
| 732 | 679 | /// Check that the operand's type is an array or tuple with the given number of elements. |
| 733 | 680 | /// Uses the `pl_node` field. Payload is `ValidateDestructure`. |
| 734 | 681 | validate_destructure, |
| 735 | /// A struct literal with a specified type, with no fields. | |
| 736 | /// Uses the `un_node` field. | |
| 737 | struct_init_empty, | |
| 738 | /// Given a struct or union, and a field name as a string index, | |
| 739 | /// returns the field type. Uses the `pl_node` field. Payload is `FieldType`. | |
| 740 | field_type, | |
| 741 | 682 | /// Given a struct or union, and a field name as a Ref, |
| 742 | 683 | /// returns the field type. Uses the `pl_node` field. Payload is `FieldTypeRef`. |
| 743 | 684 | field_type_ref, |
| 685 | /// Given a pointer, initializes all error unions and optionals in the pointee to payloads, | |
| 686 | /// returning the base payload pointer. For instance, converts *E!?T into a valid *T | |
| 687 | /// (clobbering any existing error or null value). | |
| 688 | /// Uses the `un_node` field. | |
| 689 | opt_eu_base_ptr_init, | |
| 690 | /// Coerce a given value such that when a reference is taken, the resulting pointer will be | |
| 691 | /// coercible to the given type. For instance, given a value of type 'u32' and the pointer | |
| 692 | /// type '*u64', coerces the value to a 'u64'. Asserts that the type is a pointer type. | |
| 693 | /// Uses the `pl_node` field. Payload is `Bin`. | |
| 694 | /// LHS is the pointer type, RHS is the value. | |
| 695 | coerce_ptr_elem_ty, | |
| 696 | /// Given a type, validate that it is a pointer type suitable for return from the address-of | |
| 697 | /// operator. Emit a compile error if not. | |
| 698 | /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. | |
| 699 | validate_ref_ty, | |
| 700 | ||
| 701 | // The following tags all relate to struct initialization expressions. | |
| 702 | ||
| 703 | /// A struct literal with a specified explicit type, with no fields. | |
| 704 | /// Uses the `un_node` field. | |
| 705 | struct_init_empty, | |
| 706 | /// An anonymous struct literal with a known result type, with no fields. | |
| 707 | /// Uses the `un_node` field. | |
| 708 | struct_init_empty_result, | |
| 709 | /// An anonymous struct literal with no fields, returned by reference, with a known result | |
| 710 | /// type for the pointer. Asserts that the type is a pointer. | |
| 711 | /// Uses the `un_node` field. | |
| 712 | struct_init_empty_ref_result, | |
| 713 | /// Struct initialization without a type. Creates a value of an anonymous struct type. | |
| 714 | /// Uses the `pl_node` field. Payload is `StructInitAnon`. | |
| 715 | struct_init_anon, | |
| 744 | 716 | /// Finalizes a typed struct or union initialization, performs validation, and returns the |
| 745 | /// struct or union value. | |
| 717 | /// struct or union value. The given type must be validated prior to this instruction, using | |
| 718 | /// `validate_struct_init_ty` or `validate_struct_init_result_ty`. If the given type is | |
| 719 | /// generic poison, this is downgraded to an anonymous initialization. | |
| 746 | 720 | /// Uses the `pl_node` field. Payload is `StructInit`. |
| 747 | 721 | struct_init, |
| 748 | /// Struct initialization syntax, make the result a pointer. | |
| 722 | /// Struct initialization syntax, make the result a pointer. Equivalent to `struct_init` | |
| 723 | /// followed by `ref` - this ZIR tag exists as an optimization for a common pattern. | |
| 749 | 724 | /// Uses the `pl_node` field. Payload is `StructInit`. |
| 750 | 725 | 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. | |
| 761 | 752 | /// Uses the `pl_node` field. Payload is `MultiOp`. |
| 762 | 753 | 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. | |
| 765 | 761 | 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 | ||
| 769 | 793 | /// Implements the `@unionInit` builtin. |
| 770 | 794 | /// Uses the `pl_node` field. Payload is `UnionInit`. |
| 771 | 795 | union_init, |
| ... | ... | @@ -1038,7 +1062,6 @@ pub const Inst = struct { |
| 1038 | 1062 | .array_type, |
| 1039 | 1063 | .array_type_sentinel, |
| 1040 | 1064 | .vector_type, |
| 1041 | .elem_type_index, | |
| 1042 | 1065 | .elem_type, |
| 1043 | 1066 | .indexable_ptr_elem_type, |
| 1044 | 1067 | .vector_elem_type, |
| ... | ... | @@ -1066,7 +1089,6 @@ pub const Inst = struct { |
| 1066 | 1089 | .cmp_gte, |
| 1067 | 1090 | .cmp_gt, |
| 1068 | 1091 | .cmp_neq, |
| 1069 | .coerce_result_ptr, | |
| 1070 | 1092 | .error_set_decl, |
| 1071 | 1093 | .error_set_decl_anon, |
| 1072 | 1094 | .error_set_decl_func, |
| ... | ... | @@ -1082,7 +1104,6 @@ pub const Inst = struct { |
| 1082 | 1104 | .elem_ptr, |
| 1083 | 1105 | .elem_val, |
| 1084 | 1106 | .elem_ptr_node, |
| 1085 | .elem_ptr_imm, | |
| 1086 | 1107 | .elem_val_node, |
| 1087 | 1108 | .elem_val_imm, |
| 1088 | 1109 | .ensure_result_used, |
| ... | ... | @@ -1091,7 +1112,6 @@ pub const Inst = struct { |
| 1091 | 1112 | .@"export", |
| 1092 | 1113 | .export_value, |
| 1093 | 1114 | .field_ptr, |
| 1094 | .field_ptr_init, | |
| 1095 | 1115 | .field_val, |
| 1096 | 1116 | .field_ptr_named, |
| 1097 | 1117 | .field_val_named, |
| ... | ... | @@ -1154,25 +1174,9 @@ pub const Inst = struct { |
| 1154 | 1174 | .set_eval_branch_quota, |
| 1155 | 1175 | .switch_block, |
| 1156 | 1176 | .switch_block_ref, |
| 1157 | .array_base_ptr, | |
| 1158 | .field_base_ptr, | |
| 1159 | .validate_array_init_ty, | |
| 1160 | .validate_struct_init_ty, | |
| 1161 | .validate_struct_init, | |
| 1162 | .validate_array_init, | |
| 1163 | 1177 | .validate_deref, |
| 1164 | 1178 | .validate_destructure, |
| 1165 | .struct_init_empty, | |
| 1166 | .struct_init, | |
| 1167 | .struct_init_ref, | |
| 1168 | .struct_init_anon, | |
| 1169 | .struct_init_anon_ref, | |
| 1170 | .array_init, | |
| 1171 | .array_init_anon, | |
| 1172 | .array_init_ref, | |
| 1173 | .array_init_anon_ref, | |
| 1174 | 1179 | .union_init, |
| 1175 | .field_type, | |
| 1176 | 1180 | .field_type_ref, |
| 1177 | 1181 | .enum_from_int, |
| 1178 | 1182 | .int_from_enum, |
| ... | ... | @@ -1254,7 +1258,29 @@ pub const Inst = struct { |
| 1254 | 1258 | .save_err_ret_index, |
| 1255 | 1259 | .restore_err_ret_index, |
| 1256 | 1260 | .for_len, |
| 1257 | .opt_eu_base_ty, | |
| 1261 | .opt_eu_base_ptr_init, | |
| 1262 | .coerce_ptr_elem_ty, | |
| 1263 | .struct_init_empty, | |
| 1264 | .struct_init_empty_result, | |
| 1265 | .struct_init_empty_ref_result, | |
| 1266 | .struct_init_anon, | |
| 1267 | .struct_init, | |
| 1268 | .struct_init_ref, | |
| 1269 | .validate_struct_init_ty, | |
| 1270 | .validate_struct_init_result_ty, | |
| 1271 | .validate_ptr_struct_init, | |
| 1272 | .struct_init_field_type, | |
| 1273 | .struct_init_field_ptr, | |
| 1274 | .array_init_anon, | |
| 1275 | .array_init, | |
| 1276 | .array_init_ref, | |
| 1277 | .validate_array_init_ty, | |
| 1278 | .validate_array_init_result_ty, | |
| 1279 | .validate_array_init_ref_ty, | |
| 1280 | .validate_ptr_array_init, | |
| 1281 | .array_init_elem_type, | |
| 1282 | .array_init_elem_ptr, | |
| 1283 | .validate_ref_ty, | |
| 1258 | 1284 | => false, |
| 1259 | 1285 | |
| 1260 | 1286 | .@"break", |
| ... | ... | @@ -1307,10 +1333,6 @@ pub const Inst = struct { |
| 1307 | 1333 | .store_node, |
| 1308 | 1334 | .store_to_inferred_ptr, |
| 1309 | 1335 | .resolve_inferred_alloc, |
| 1310 | .validate_array_init_ty, | |
| 1311 | .validate_struct_init_ty, | |
| 1312 | .validate_struct_init, | |
| 1313 | .validate_array_init, | |
| 1314 | 1336 | .validate_deref, |
| 1315 | 1337 | .validate_destructure, |
| 1316 | 1338 | .@"export", |
| ... | ... | @@ -1323,6 +1345,13 @@ pub const Inst = struct { |
| 1323 | 1345 | .defer_err_code, |
| 1324 | 1346 | .restore_err_ret_index, |
| 1325 | 1347 | .save_err_ret_index, |
| 1348 | .validate_struct_init_ty, | |
| 1349 | .validate_struct_init_result_ty, | |
| 1350 | .validate_ptr_struct_init, | |
| 1351 | .validate_array_init_ty, | |
| 1352 | .validate_array_init_result_ty, | |
| 1353 | .validate_ptr_array_init, | |
| 1354 | .validate_ref_ty, | |
| 1326 | 1355 | => true, |
| 1327 | 1356 | |
| 1328 | 1357 | .param, |
| ... | ... | @@ -1346,7 +1375,6 @@ pub const Inst = struct { |
| 1346 | 1375 | .array_type, |
| 1347 | 1376 | .array_type_sentinel, |
| 1348 | 1377 | .vector_type, |
| 1349 | .elem_type_index, | |
| 1350 | 1378 | .elem_type, |
| 1351 | 1379 | .indexable_ptr_elem_type, |
| 1352 | 1380 | .vector_elem_type, |
| ... | ... | @@ -1374,7 +1402,6 @@ pub const Inst = struct { |
| 1374 | 1402 | .cmp_gte, |
| 1375 | 1403 | .cmp_gt, |
| 1376 | 1404 | .cmp_neq, |
| 1377 | .coerce_result_ptr, | |
| 1378 | 1405 | .error_set_decl, |
| 1379 | 1406 | .error_set_decl_anon, |
| 1380 | 1407 | .error_set_decl_func, |
| ... | ... | @@ -1385,11 +1412,9 @@ pub const Inst = struct { |
| 1385 | 1412 | .elem_ptr, |
| 1386 | 1413 | .elem_val, |
| 1387 | 1414 | .elem_ptr_node, |
| 1388 | .elem_ptr_imm, | |
| 1389 | 1415 | .elem_val_node, |
| 1390 | 1416 | .elem_val_imm, |
| 1391 | 1417 | .field_ptr, |
| 1392 | .field_ptr_init, | |
| 1393 | 1418 | .field_val, |
| 1394 | 1419 | .field_ptr_named, |
| 1395 | 1420 | .field_val_named, |
| ... | ... | @@ -1447,19 +1472,7 @@ pub const Inst = struct { |
| 1447 | 1472 | .typeof_log2_int_type, |
| 1448 | 1473 | .switch_block, |
| 1449 | 1474 | .switch_block_ref, |
| 1450 | .array_base_ptr, | |
| 1451 | .field_base_ptr, | |
| 1452 | .struct_init_empty, | |
| 1453 | .struct_init, | |
| 1454 | .struct_init_ref, | |
| 1455 | .struct_init_anon, | |
| 1456 | .struct_init_anon_ref, | |
| 1457 | .array_init, | |
| 1458 | .array_init_anon, | |
| 1459 | .array_init_ref, | |
| 1460 | .array_init_anon_ref, | |
| 1461 | 1475 | .union_init, |
| 1462 | .field_type, | |
| 1463 | 1476 | .field_type_ref, |
| 1464 | 1477 | .enum_from_int, |
| 1465 | 1478 | .int_from_enum, |
| ... | ... | @@ -1546,7 +1559,22 @@ pub const Inst = struct { |
| 1546 | 1559 | .for_len, |
| 1547 | 1560 | .@"try", |
| 1548 | 1561 | .try_ptr, |
| 1549 | .opt_eu_base_ty, | |
| 1562 | .opt_eu_base_ptr_init, | |
| 1563 | .coerce_ptr_elem_ty, | |
| 1564 | .struct_init_empty, | |
| 1565 | .struct_init_empty_result, | |
| 1566 | .struct_init_empty_ref_result, | |
| 1567 | .struct_init_anon, | |
| 1568 | .struct_init, | |
| 1569 | .struct_init_ref, | |
| 1570 | .struct_init_field_type, | |
| 1571 | .struct_init_field_ptr, | |
| 1572 | .array_init_anon, | |
| 1573 | .array_init, | |
| 1574 | .array_init_ref, | |
| 1575 | .validate_array_init_ref_ty, | |
| 1576 | .array_init_elem_type, | |
| 1577 | .array_init_elem_ptr, | |
| 1550 | 1578 | => false, |
| 1551 | 1579 | |
| 1552 | 1580 | .extended => switch (data.extended.opcode) { |
| ... | ... | @@ -1580,7 +1608,6 @@ pub const Inst = struct { |
| 1580 | 1608 | .array_type = .pl_node, |
| 1581 | 1609 | .array_type_sentinel = .pl_node, |
| 1582 | 1610 | .vector_type = .pl_node, |
| 1583 | .elem_type_index = .bin, | |
| 1584 | 1611 | .elem_type = .un_node, |
| 1585 | 1612 | .indexable_ptr_elem_type = .un_node, |
| 1586 | 1613 | .vector_elem_type = .un_node, |
| ... | ... | @@ -1612,7 +1639,6 @@ pub const Inst = struct { |
| 1612 | 1639 | .cmp_gte = .pl_node, |
| 1613 | 1640 | .cmp_gt = .pl_node, |
| 1614 | 1641 | .cmp_neq = .pl_node, |
| 1615 | .coerce_result_ptr = .pl_node, | |
| 1616 | 1642 | .condbr = .pl_node, |
| 1617 | 1643 | .condbr_inline = .pl_node, |
| 1618 | 1644 | .@"try" = .pl_node, |
| ... | ... | @@ -1631,7 +1657,6 @@ pub const Inst = struct { |
| 1631 | 1657 | .div = .pl_node, |
| 1632 | 1658 | .elem_ptr = .pl_node, |
| 1633 | 1659 | .elem_ptr_node = .pl_node, |
| 1634 | .elem_ptr_imm = .pl_node, | |
| 1635 | 1660 | .elem_val = .pl_node, |
| 1636 | 1661 | .elem_val_node = .pl_node, |
| 1637 | 1662 | .elem_val_imm = .elem_val_imm, |
| ... | ... | @@ -1643,7 +1668,6 @@ pub const Inst = struct { |
| 1643 | 1668 | .@"export" = .pl_node, |
| 1644 | 1669 | .export_value = .pl_node, |
| 1645 | 1670 | .field_ptr = .pl_node, |
| 1646 | .field_ptr_init = .pl_node, | |
| 1647 | 1671 | .field_val = .pl_node, |
| 1648 | 1672 | .field_ptr_named = .pl_node, |
| 1649 | 1673 | .field_val_named = .pl_node, |
| ... | ... | @@ -1701,30 +1725,16 @@ pub const Inst = struct { |
| 1701 | 1725 | .enum_literal = .str_tok, |
| 1702 | 1726 | .switch_block = .pl_node, |
| 1703 | 1727 | .switch_block_ref = .pl_node, |
| 1704 | .array_base_ptr = .un_node, | |
| 1705 | .field_base_ptr = .un_node, | |
| 1706 | .opt_eu_base_ty = .un_node, | |
| 1707 | .validate_array_init_ty = .pl_node, | |
| 1708 | .validate_struct_init_ty = .un_node, | |
| 1709 | .validate_struct_init = .pl_node, | |
| 1710 | .validate_array_init = .pl_node, | |
| 1711 | 1728 | .validate_deref = .un_node, |
| 1712 | 1729 | .validate_destructure = .pl_node, |
| 1713 | .struct_init_empty = .un_node, | |
| 1714 | .field_type = .pl_node, | |
| 1715 | 1730 | .field_type_ref = .pl_node, |
| 1716 | .struct_init = .pl_node, | |
| 1717 | .struct_init_ref = .pl_node, | |
| 1718 | .struct_init_anon = .pl_node, | |
| 1719 | .struct_init_anon_ref = .pl_node, | |
| 1720 | .array_init = .pl_node, | |
| 1721 | .array_init_anon = .pl_node, | |
| 1722 | .array_init_ref = .pl_node, | |
| 1723 | .array_init_anon_ref = .pl_node, | |
| 1724 | 1731 | .union_init = .pl_node, |
| 1725 | 1732 | .type_info = .un_node, |
| 1726 | 1733 | .size_of = .un_node, |
| 1727 | 1734 | .bit_size_of = .un_node, |
| 1735 | .opt_eu_base_ptr_init = .un_node, | |
| 1736 | .coerce_ptr_elem_ty = .pl_node, | |
| 1737 | .validate_ref_ty = .un_tok, | |
| 1728 | 1738 | |
| 1729 | 1739 | .int_from_ptr = .un_node, |
| 1730 | 1740 | .compile_error = .un_node, |
| ... | ... | @@ -1826,6 +1836,27 @@ pub const Inst = struct { |
| 1826 | 1836 | .save_err_ret_index = .save_err_ret_index, |
| 1827 | 1837 | .restore_err_ret_index = .restore_err_ret_index, |
| 1828 | 1838 | |
| 1839 | .struct_init_empty = .un_node, | |
| 1840 | .struct_init_empty_result = .un_node, | |
| 1841 | .struct_init_empty_ref_result = .un_node, | |
| 1842 | .struct_init_anon = .pl_node, | |
| 1843 | .struct_init = .pl_node, | |
| 1844 | .struct_init_ref = .pl_node, | |
| 1845 | .validate_struct_init_ty = .un_node, | |
| 1846 | .validate_struct_init_result_ty = .un_node, | |
| 1847 | .validate_ptr_struct_init = .pl_node, | |
| 1848 | .struct_init_field_type = .pl_node, | |
| 1849 | .struct_init_field_ptr = .pl_node, | |
| 1850 | .array_init_anon = .pl_node, | |
| 1851 | .array_init = .pl_node, | |
| 1852 | .array_init_ref = .pl_node, | |
| 1853 | .validate_array_init_ty = .pl_node, | |
| 1854 | .validate_array_init_result_ty = .pl_node, | |
| 1855 | .validate_array_init_ref_ty = .pl_node, | |
| 1856 | .validate_ptr_array_init = .pl_node, | |
| 1857 | .array_init_elem_type = .bin, | |
| 1858 | .array_init_elem_ptr = .pl_node, | |
| 1859 | ||
| 1829 | 1860 | .extended = .extended, |
| 1830 | 1861 | }); |
| 1831 | 1862 | }; |
| ... | ... | @@ -2771,6 +2802,11 @@ pub const Inst = struct { |
| 2771 | 2802 | }; |
| 2772 | 2803 | }; |
| 2773 | 2804 | |
| 2805 | pub const ArrayInitRefTy = struct { | |
| 2806 | ptr_ty: Ref, | |
| 2807 | elem_count: u32, | |
| 2808 | }; | |
| 2809 | ||
| 2774 | 2810 | pub const Field = struct { |
| 2775 | 2811 | lhs: Ref, |
| 2776 | 2812 | /// Offset into `string_bytes`. |
| ... | ... | @@ -3064,9 +3100,10 @@ pub const Inst = struct { |
| 3064 | 3100 | fields_len: u32, |
| 3065 | 3101 | |
| 3066 | 3102 | pub const Item = struct { |
| 3067 | /// The `field_type` ZIR instruction for this field init. | |
| 3103 | /// The `struct_init_field_type` ZIR instruction for this field init. | |
| 3068 | 3104 | field_type: Index, |
| 3069 | /// The field init expression to be used as the field value. | |
| 3105 | /// The field init expression to be used as the field value. This value will be coerced | |
| 3106 | /// to the field type if not already. | |
| 3070 | 3107 | init: Ref, |
| 3071 | 3108 | }; |
| 3072 | 3109 | }; |
src/print_zir.zig+110-31| ... | ... | @@ -130,6 +130,63 @@ const Writer = struct { |
| 130 | 130 | recurse_decls: bool, |
| 131 | 131 | recurse_blocks: bool, |
| 132 | 132 | |
| 133 | /// Using `std.zig.findLineColumn` whenever we need to resolve a source location makes ZIR | |
| 134 | /// printing O(N^2), which can have drastic effects - taking a ZIR dump from a few seconds to | |
| 135 | /// many minutes. Since we're usually resolving source locations close to one another, | |
| 136 | /// preserving state across source location resolutions speeds things up a lot. | |
| 137 | line_col_cursor: struct { | |
| 138 | line: usize = 0, | |
| 139 | column: usize = 0, | |
| 140 | line_start: usize = 0, | |
| 141 | off: usize = 0, | |
| 142 | ||
| 143 | fn find(cur: *@This(), source: []const u8, want_offset: usize) std.zig.Loc { | |
| 144 | if (want_offset < cur.off) { | |
| 145 | // Go back to the start of this line | |
| 146 | cur.off = cur.line_start; | |
| 147 | cur.column = 0; | |
| 148 | ||
| 149 | while (want_offset < cur.off) { | |
| 150 | // Go back to the newline | |
| 151 | cur.off -= 1; | |
| 152 | ||
| 153 | // Seek to the start of the previous line | |
| 154 | while (cur.off > 0 and source[cur.off - 1] != '\n') { | |
| 155 | cur.off -= 1; | |
| 156 | } | |
| 157 | cur.line_start = cur.off; | |
| 158 | cur.line -= 1; | |
| 159 | } | |
| 160 | } | |
| 161 | ||
| 162 | // The cursor is now positioned before `want_offset`. | |
| 163 | // Seek forward as in `std.zig.findLineColumn`. | |
| 164 | ||
| 165 | while (cur.off < want_offset) : (cur.off += 1) { | |
| 166 | switch (source[cur.off]) { | |
| 167 | '\n' => { | |
| 168 | cur.line += 1; | |
| 169 | cur.column = 0; | |
| 170 | cur.line_start = cur.off + 1; | |
| 171 | }, | |
| 172 | else => { | |
| 173 | cur.column += 1; | |
| 174 | }, | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | while (cur.off < source.len and source[cur.off] != '\n') { | |
| 179 | cur.off += 1; | |
| 180 | } | |
| 181 | ||
| 182 | return .{ | |
| 183 | .line = cur.line, | |
| 184 | .column = cur.column, | |
| 185 | .source_line = source[cur.line_start..cur.off], | |
| 186 | }; | |
| 187 | } | |
| 188 | } = .{}, | |
| 189 | ||
| 133 | 190 | fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index { |
| 134 | 191 | return @as(Ast.Node.Index, @bitCast(offset + @as(i32, @bitCast(self.parent_decl_node)))); |
| 135 | 192 | } |
| ... | ... | @@ -148,8 +205,6 @@ const Writer = struct { |
| 148 | 205 | .store_to_inferred_ptr, |
| 149 | 206 | => try self.writeBin(stream, inst), |
| 150 | 207 | |
| 151 | .elem_type_index => try self.writeElemTypeIndex(stream, inst), | |
| 152 | ||
| 153 | 208 | .alloc, |
| 154 | 209 | .alloc_mut, |
| 155 | 210 | .alloc_comptime_mut, |
| ... | ... | @@ -184,7 +239,6 @@ const Writer = struct { |
| 184 | 239 | .is_non_err_ptr, |
| 185 | 240 | .ret_is_non_err, |
| 186 | 241 | .typeof, |
| 187 | .struct_init_empty, | |
| 188 | 242 | .type_info, |
| 189 | 243 | .size_of, |
| 190 | 244 | .bit_size_of, |
| ... | ... | @@ -224,18 +278,16 @@ const Writer = struct { |
| 224 | 278 | .bit_reverse, |
| 225 | 279 | .@"resume", |
| 226 | 280 | .@"await", |
| 227 | .array_base_ptr, | |
| 228 | .field_base_ptr, | |
| 229 | .validate_struct_init_ty, | |
| 230 | 281 | .make_ptr_const, |
| 231 | 282 | .validate_deref, |
| 232 | 283 | .check_comptime_control_flow, |
| 233 | .opt_eu_base_ty, | |
| 284 | .opt_eu_base_ptr_init, | |
| 234 | 285 | => try self.writeUnNode(stream, inst), |
| 235 | 286 | |
| 236 | 287 | .ref, |
| 237 | 288 | .ret_implicit, |
| 238 | 289 | .closure_capture, |
| 290 | .validate_ref_ty, | |
| 239 | 291 | => try self.writeUnTok(stream, inst), |
| 240 | 292 | |
| 241 | 293 | .bool_br_and, |
| ... | ... | @@ -243,7 +295,6 @@ const Writer = struct { |
| 243 | 295 | => try self.writeBoolBr(stream, inst), |
| 244 | 296 | |
| 245 | 297 | .validate_destructure => try self.writeValidateDestructure(stream, inst), |
| 246 | .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst), | |
| 247 | 298 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 248 | 299 | .ptr_type => try self.writePtrType(stream, inst), |
| 249 | 300 | .int => try self.writeInt(stream, inst), |
| ... | ... | @@ -259,12 +310,6 @@ const Writer = struct { |
| 259 | 310 | .@"break", |
| 260 | 311 | .break_inline, |
| 261 | 312 | => try self.writeBreak(stream, inst), |
| 262 | .array_init, | |
| 263 | .array_init_ref, | |
| 264 | => try self.writeArrayInit(stream, inst), | |
| 265 | .array_init_anon, | |
| 266 | .array_init_anon_ref, | |
| 267 | => try self.writeArrayInitAnon(stream, inst), | |
| 268 | 313 | |
| 269 | 314 | .slice_start => try self.writeSliceStart(stream, inst), |
| 270 | 315 | .slice_end => try self.writeSliceEnd(stream, inst), |
| ... | ... | @@ -273,10 +318,44 @@ const Writer = struct { |
| 273 | 318 | |
| 274 | 319 | .union_init => try self.writeUnionInit(stream, inst), |
| 275 | 320 | |
| 321 | // Struct inits | |
| 322 | ||
| 323 | .struct_init_empty, | |
| 324 | .struct_init_empty_result, | |
| 325 | .struct_init_empty_ref_result, | |
| 326 | => try self.writeUnNode(stream, inst), | |
| 327 | ||
| 328 | .struct_init_anon => try self.writeStructInitAnon(stream, inst), | |
| 329 | ||
| 276 | 330 | .struct_init, |
| 277 | 331 | .struct_init_ref, |
| 278 | 332 | => try self.writeStructInit(stream, inst), |
| 279 | 333 | |
| 334 | .validate_struct_init_ty, | |
| 335 | .validate_struct_init_result_ty, | |
| 336 | => try self.writeUnNode(stream, inst), | |
| 337 | ||
| 338 | .validate_ptr_struct_init => try self.writeBlock(stream, inst), | |
| 339 | .struct_init_field_type => try self.writeStructInitFieldType(stream, inst), | |
| 340 | .struct_init_field_ptr => try self.writePlNodeField(stream, inst), | |
| 341 | ||
| 342 | // Array inits | |
| 343 | ||
| 344 | .array_init_anon => try self.writeArrayInitAnon(stream, inst), | |
| 345 | ||
| 346 | .array_init, | |
| 347 | .array_init_ref, | |
| 348 | => try self.writeArrayInit(stream, inst), | |
| 349 | ||
| 350 | .validate_array_init_ty, | |
| 351 | .validate_array_init_result_ty, | |
| 352 | => try self.writeValidateArrayInitTy(stream, inst), | |
| 353 | ||
| 354 | .validate_array_init_ref_ty => try self.writeValidateArrayInitRefTy(stream, inst), | |
| 355 | .validate_ptr_array_init => try self.writeBlock(stream, inst), | |
| 356 | .array_init_elem_type => try self.writeArrayInitElemType(stream, inst), | |
| 357 | .array_init_elem_ptr => try self.writeArrayInitElemPtr(stream, inst), | |
| 358 | ||
| 280 | 359 | .atomic_load => try self.writeAtomicLoad(stream, inst), |
| 281 | 360 | .atomic_store => try self.writeAtomicStore(stream, inst), |
| 282 | 361 | .atomic_rmw => try self.writeAtomicRmw(stream, inst), |
| ... | ... | @@ -285,11 +364,6 @@ const Writer = struct { |
| 285 | 364 | .field_parent_ptr => try self.writeFieldParentPtr(stream, inst), |
| 286 | 365 | .builtin_call => try self.writeBuiltinCall(stream, inst), |
| 287 | 366 | |
| 288 | .struct_init_anon, | |
| 289 | .struct_init_anon_ref, | |
| 290 | => try self.writeStructInitAnon(stream, inst), | |
| 291 | ||
| 292 | .field_type => try self.writeFieldType(stream, inst), | |
| 293 | 367 | .field_type_ref => try self.writeFieldTypeRef(stream, inst), |
| 294 | 368 | |
| 295 | 369 | .add, |
| ... | ... | @@ -352,16 +426,14 @@ const Writer = struct { |
| 352 | 426 | .elem_val_node, |
| 353 | 427 | .elem_ptr, |
| 354 | 428 | .elem_val, |
| 355 | .coerce_result_ptr, | |
| 356 | 429 | .array_type, |
| 430 | .coerce_ptr_elem_ty, | |
| 357 | 431 | => try self.writePlNodeBin(stream, inst), |
| 358 | 432 | |
| 359 | 433 | .for_len => try self.writePlNodeMultiOp(stream, inst), |
| 360 | 434 | |
| 361 | 435 | .elem_val_imm => try self.writeElemValImm(stream, inst), |
| 362 | 436 | |
| 363 | .elem_ptr_imm => try self.writeElemPtrImm(stream, inst), | |
| 364 | ||
| 365 | 437 | .@"export" => try self.writePlNodeExport(stream, inst), |
| 366 | 438 | .export_value => try self.writePlNodeExportValue(stream, inst), |
| 367 | 439 | |
| ... | ... | @@ -373,8 +445,6 @@ const Writer = struct { |
| 373 | 445 | .block_inline, |
| 374 | 446 | .suspend_block, |
| 375 | 447 | .loop, |
| 376 | .validate_struct_init, | |
| 377 | .validate_array_init, | |
| 378 | 448 | .c_import, |
| 379 | 449 | .typeof_builtin, |
| 380 | 450 | => try self.writeBlock(stream, inst), |
| ... | ... | @@ -395,9 +465,8 @@ const Writer = struct { |
| 395 | 465 | .switch_block_ref, |
| 396 | 466 | => try self.writeSwitchBlock(stream, inst), |
| 397 | 467 | |
| 398 | .field_ptr, | |
| 399 | .field_ptr_init, | |
| 400 | 468 | .field_val, |
| 469 | .field_ptr, | |
| 401 | 470 | => try self.writePlNodeField(stream, inst), |
| 402 | 471 | |
| 403 | 472 | .field_ptr_named, |
| ... | ... | @@ -560,7 +629,7 @@ const Writer = struct { |
| 560 | 629 | try stream.writeByte(')'); |
| 561 | 630 | } |
| 562 | 631 | |
| 563 | fn writeElemTypeIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 632 | fn writeArrayInitElemType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 564 | 633 | const inst_data = self.code.instructions.items(.data)[inst].bin; |
| 565 | 634 | try self.writeInstRef(stream, inst_data.lhs); |
| 566 | 635 | try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)}); |
| ... | ... | @@ -915,7 +984,7 @@ const Writer = struct { |
| 915 | 984 | try stream.print(", {d})", .{inst_data.idx}); |
| 916 | 985 | } |
| 917 | 986 | |
| 918 | fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 987 | fn writeArrayInitElemPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 919 | 988 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 920 | 989 | const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; |
| 921 | 990 | |
| ... | ... | @@ -947,6 +1016,16 @@ const Writer = struct { |
| 947 | 1016 | try self.writeSrc(stream, inst_data.src()); |
| 948 | 1017 | } |
| 949 | 1018 | |
| 1019 | fn writeValidateArrayInitRefTy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 1020 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | |
| 1021 | const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data; | |
| 1022 | ||
| 1023 | try self.writeInstRef(stream, extra.ptr_ty); | |
| 1024 | try stream.writeAll(", "); | |
| 1025 | try stream.print(", {}) ", .{extra.elem_count}); | |
| 1026 | try self.writeSrc(stream, inst_data.src()); | |
| 1027 | } | |
| 1028 | ||
| 950 | 1029 | fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 951 | 1030 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 952 | 1031 | const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); |
| ... | ... | @@ -1077,7 +1156,7 @@ const Writer = struct { |
| 1077 | 1156 | try self.writeSrc(stream, inst_data.src()); |
| 1078 | 1157 | } |
| 1079 | 1158 | |
| 1080 | fn writeFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 1159 | fn writeStructInitFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 1081 | 1160 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1082 | 1161 | const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; |
| 1083 | 1162 | try self.writeInstRef(stream, extra.container_type); |
| ... | ... | @@ -2590,8 +2669,8 @@ const Writer = struct { |
| 2590 | 2669 | .lazy = src, |
| 2591 | 2670 | }; |
| 2592 | 2671 | const src_span = src_loc.span(self.gpa) catch unreachable; |
| 2593 | const start = std.zig.findLineColumn(tree.source, src_span.start); | |
| 2594 | const end = std.zig.findLineColumn(tree.source, src_span.end); | |
| 2672 | const start = self.line_col_cursor.find(tree.source, src_span.start); | |
| 2673 | const end = self.line_col_cursor.find(tree.source, src_span.end); | |
| 2595 | 2674 | try stream.print("{s}:{d}:{d} to :{d}:{d}", .{ |
| 2596 | 2675 | @tagName(src), start.line + 1, start.column + 1, |
| 2597 | 2676 | end.line + 1, end.column + 1, |
src/type.zig+11| ... | ... | @@ -3182,6 +3182,17 @@ pub const Type = struct { |
| 3182 | 3182 | }; |
| 3183 | 3183 | } |
| 3184 | 3184 | |
| 3185 | /// Traverses optional child types and error union payloads until the type | |
| 3186 | /// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`. | |
| 3187 | pub fn optEuBaseType(ty: Type, mod: *Module) Type { | |
| 3188 | var cur = ty; | |
| 3189 | while (true) switch (cur.zigTypeTag(mod)) { | |
| 3190 | .Optional => cur = cur.optionalChild(mod), | |
| 3191 | .ErrorUnion => cur = cur.errorUnionPayload(mod), | |
| 3192 | else => return cur, | |
| 3193 | }; | |
| 3194 | } | |
| 3195 | ||
| 3185 | 3196 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 3186 | 3197 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 3187 | 3198 | pub const @"u16": Type = .{ .ip_index = .u16_type }; |
test/behavior/array.zig+34| ... | ... | @@ -780,3 +780,37 @@ test "runtime side-effects in comptime-known array init" { |
| 780 | 780 | try expectEqual([4]u4{ 1, 2, 4, 8 }, init); |
| 781 | 781 | try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects); |
| 782 | 782 | } |
| 783 | ||
| 784 | test "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 | ||
| 796 | test "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 | ||
| 808 | test "tuple initialized through reference to anonymous array init provides result types" { | |
| 809 | const Tuple = struct { u64, *const u32 }; | |
| 810 | const foo: *const Tuple = &.{ | |
| 811 | @intCast(12345), | |
| 812 | @ptrFromInt(0x1000), | |
| 813 | }; | |
| 814 | try expect(foo[0] == 12345); | |
| 815 | try expect(@intFromPtr(foo[1]) == 0x1000); | |
| 816 | } |
test/behavior/bugs/12776.zig+1| ... | ... | @@ -29,6 +29,7 @@ const CPU = packed struct { |
| 29 | 29 | }; |
| 30 | 30 | |
| 31 | 31 | test { |
| 32 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 32 | 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | 34 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 34 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
test/behavior/bugs/13664.zig+1| ... | ... | @@ -17,6 +17,7 @@ test { |
| 17 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 18 | 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 19 | 19 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 20 | 21 | |
| 21 | 22 | const timestamp: i64 = value(); |
| 22 | 23 | const id = ID{ .fields = Fields{ |
test/behavior/cast.zig+26| ... | ... | @@ -2493,3 +2493,29 @@ test "@as does not corrupt values with incompatible representations" { |
| 2493 | 2493 | }); |
| 2494 | 2494 | try std.testing.expectApproxEqAbs(@as(f32, 1.23), x, 0.001); |
| 2495 | 2495 | } |
| 2496 | ||
| 2497 | test "result information is preserved through many nested structures" { | |
| 2498 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 2499 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 2500 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2501 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 2502 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 2503 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 2504 | ||
| 2505 | const S = struct { | |
| 2506 | fn doTheTest() !void { | |
| 2507 | const E = error{Foo}; | |
| 2508 | const T = *const ?E!struct { x: ?*const E!?u8 }; | |
| 2509 | ||
| 2510 | var val: T = &.{ .x = &@truncate(0x1234) }; | |
| 2511 | ||
| 2512 | const struct_val = val.*.? catch unreachable; | |
| 2513 | const int_val = (struct_val.x.?.* catch unreachable).?; | |
| 2514 | ||
| 2515 | try expect(int_val == 0x34); | |
| 2516 | } | |
| 2517 | }; | |
| 2518 | ||
| 2519 | try S.doTheTest(); | |
| 2520 | try comptime S.doTheTest(); | |
| 2521 | } |
test/behavior/pointers.zig+18| ... | ... | @@ -548,3 +548,21 @@ test "pointer to array has explicit alignment" { |
| 548 | 548 | const casted = S.func(&bases); |
| 549 | 549 | try expect(casted[0].a == 2); |
| 550 | 550 | } |
| 551 | ||
| 552 | test "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 | ||
| 561 | test "result type found through optional pointer" { | |
| 562 | const ptr1: ?*const u32 = &@intCast(123); | |
| 563 | const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) }; | |
| 564 | try expect(ptr1.?.* == 123); | |
| 565 | try expect(ptr2.?.len == 2); | |
| 566 | try expect(ptr2.?[0] == 123); | |
| 567 | try expect(ptr2.?[1] == 0xCD); | |
| 568 | } |
test/behavior/struct.zig+15| ... | ... | @@ -1760,3 +1760,18 @@ test "runtime side-effects in comptime-known struct init" { |
| 1760 | 1760 | try expectEqual(S{ .a = 1, .b = 2, .c = 4, .d = 8 }, init); |
| 1761 | 1761 | try expectEqual(@as(u4, std.math.maxInt(u4)), side_effects); |
| 1762 | 1762 | } |
| 1763 | ||
| 1764 | test "pointer to struct initialized through reference to anonymous initializer provides result types" { | |
| 1765 | const S = struct { a: u8, b: u16, c: *const anyopaque }; | |
| 1766 | var my_u16: u16 = 0xABCD; | |
| 1767 | const s: *const S = &.{ | |
| 1768 | // intentionally out of order | |
| 1769 | .c = @ptrCast("hello"), | |
| 1770 | .b = my_u16, | |
| 1771 | .a = @truncate(my_u16), | |
| 1772 | }; | |
| 1773 | try expect(s.a == 0xCD); | |
| 1774 | try expect(s.b == 0xABCD); | |
| 1775 | const str: *const [5]u8 = @ptrCast(s.c); | |
| 1776 | try std.testing.expectEqualSlices(u8, "hello", str); | |
| 1777 | } |
test/cases/compile_errors/anytype_param_requires_comptime.zig+2-4| ... | ... | @@ -16,7 +16,5 @@ pub export fn entry() void { |
| 16 | 16 | // backend=stage2 |
| 17 | 17 | // target=native |
| 18 | 18 | // |
| 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 { |
| 18 | 18 | // backend=stage2 |
| 19 | 19 | // target=native |
| 20 | 20 | // |
| 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 @@ |
| 1 | export fn foo() void { | |
| 2 | const x: *const anyopaque = &@intCast(123); | |
| 3 | _ = x; | |
| 4 | } | |
| 5 | export fn bar() void { | |
| 6 | const x: *const anyopaque = &.{ | |
| 7 | .x = @intCast(123), | |
| 8 | }; | |
| 9 | _ = x; | |
| 10 | } | |
| 11 | ||
| 12 | // error | |
| 13 | // backend=stage2 | |
| 14 | // target=native | |
| 15 | // | |
| 16 | // :2:34: error: @intCast must have a known result type | |
| 17 | // :2:34: note: result type is unknown due to opaque pointer type | |
| 18 | // :2:34: note: use @as to provide explicit result type | |
| 19 | // :7:14: error: @intCast must have a known result type | |
| 20 | // :6:35: note: result type is unknown due to opaque pointer type | |
| 21 | // :7:14: note: use @as to provide explicit result type |
test/cases/compile_errors/cast_without_result_type_due_to_generic_parameter.zig+12-4| ... | ... | @@ -10,6 +10,11 @@ export fn c() void { |
| 10 | 10 | export fn d() void { |
| 11 | 11 | bar(@floatFromInt(123)); |
| 12 | 12 | } |
| 13 | export fn f() void { | |
| 14 | bar(.{ | |
| 15 | .x = @intCast(123), | |
| 16 | }); | |
| 17 | } | |
| 13 | 18 | |
| 14 | 19 | fn bar(_: anytype) void {} |
| 15 | 20 | |
| ... | ... | @@ -18,14 +23,17 @@ fn bar(_: anytype) void {} |
| 18 | 23 | // target=native |
| 19 | 24 | // |
| 20 | 25 | // :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 | |
| 22 | 27 | // :2:9: note: use @as to provide explicit result type |
| 23 | 28 | // :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 | |
| 25 | 30 | // :5:9: note: use @as to provide explicit result type |
| 26 | 31 | // :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 | |
| 28 | 33 | // :8:9: note: use @as to provide explicit result type |
| 29 | 34 | // :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 | |
| 31 | 36 | // :11:9: note: use @as to provide explicit result type |
| 37 | // :15:14: error: @intCast must have a known result type | |
| 38 | // :14:8: note: result type is unknown due to anytype parameter | |
| 39 | // :15:14: note: use @as to provide explicit result type |
test/cases/compile_errors/for_invalid_ranges.zig+2-1| ... | ... | @@ -31,5 +31,6 @@ export fn e() void { |
| 31 | 31 | // :2:13: error: expected type 'usize', found '*const [5:0]u8' |
| 32 | 32 | // :7:10: error: type 'usize' cannot represent integer value '-1' |
| 33 | 33 | // :12:10: error: expected type 'usize', found '*const [5:0]u8' |
| 34 | // :17:13: error: expected type 'usize', found '*const struct{comptime comptime_int = 97, comptime comptime_int = 98, comptime comptime_int = 99}' | |
| 34 | // :17:13: error: expected type 'usize', found pointer | |
| 35 | // :17:13: note: address-of operator always returns a pointer | |
| 35 | 36 | // :22:20: error: overflow of integer type 'usize' with value '-1' |
test/cases/compile_errors/invalid_store_to_comptime_field.zig+5-4| ... | ... | @@ -71,8 +71,8 @@ pub export fn entry8() void { |
| 71 | 71 | // target=native |
| 72 | 72 | // backend=stage2 |
| 73 | 73 | // |
| 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 | |
| 76 | 76 | // :19:38: error: value stored in comptime field does not match the default value of the field |
| 77 | 77 | // :31:19: error: value stored in comptime field does not match the default value of the field |
| 78 | 78 | // :25:29: note: default value set here |
| ... | ... | @@ -80,5 +80,6 @@ pub export fn entry8() void { |
| 80 | 80 | // :35:29: note: default value set here |
| 81 | 81 | // :45:12: error: value stored in comptime field does not match the default value of the field |
| 82 | 82 | // :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 { |
| 15 | 15 | // backend=llvm |
| 16 | 16 | // target=native |
| 17 | 17 | // |
| 18 | // :4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32' | |
| 18 | // :4:26: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32' |
test/cases/compile_errors/missing_else_clause.zig+3-1| ... | ... | @@ -39,4 +39,6 @@ export fn entry() void { |
| 39 | 39 | // :8:25: note: type 'i32' here |
| 40 | 40 | // :16:16: error: expected type 'tmp.h.T', found 'void' |
| 41 | 41 | // :15:15: note: struct declared here |
| 42 | // :22:9: error: incompatible types: 'void' and 'tmp.k.T' | |
| 42 | // :22:13: error: incompatible types: 'void' and 'tmp.k.T' | |
| 43 | // :22:25: note: type 'void' here | |
| 44 | // :24:13: note: type 'tmp.k.T' here |
test/cases/compile_errors/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig+3-3| ... | ... | @@ -16,9 +16,9 @@ comptime { |
| 16 | 16 | // backend=stage2 |
| 17 | 17 | // target=native |
| 18 | 18 | // |
| 19 | // :2:29: error: expected type '[][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' | |
| 19 | // :2:29: error: expected type '[][]const u8', found '*const [2][]const u8' | |
| 20 | 20 | // :2:29: note: cast discards const qualifier |
| 21 | // :6:31: error: expected type '*[2][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' | |
| 21 | // :6:31: error: expected type '*[2][]const u8', found '*const [2][]const u8' | |
| 22 | 22 | // :6:31: note: cast discards const qualifier |
| 23 | // :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}' | |
| 23 | // :11:19: error: expected type '*tmp.S', found '*const tmp.S' | |
| 24 | 24 | // :11:19: note: cast discards const qualifier |
test/cases/compile_errors/reassign_to_array_parameter.zig+1-1| ... | ... | @@ -9,4 +9,4 @@ export fn entry() void { |
| 9 | 9 | // backend=llvm |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 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 { |
| 12 | 12 | // backend=stage2 |
| 13 | 13 | // target=native |
| 14 | 14 | // |
| 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 { |
| 18 | 18 | // backend=stage2 |
| 19 | 19 | // target=native |
| 20 | 20 | // |
| 21 | // :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32' | |
| 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 { |
| 15 | 15 | // backend=stage2 |
| 16 | 16 | // target=native |
| 17 | 17 | // |
| 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 { |
| 15 | 15 | // backend=stage2 |
| 16 | 16 | // target=native |
| 17 | 17 | // |
| 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 { |
| 18 | 18 | // :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)' |
| 19 | 19 | // :5:12: note: struct declared here |
| 20 | 20 | // :2:12: note: struct declared here |
| 21 | // :7:11: note: function return type declared here |
test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig+2-2| ... | ... | @@ -12,5 +12,5 @@ export fn f() void { |
| 12 | 12 | // backend=stage2 |
| 13 | 13 | // target=native |
| 14 | 14 | // |
| 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 { |
| 12 | 12 | // backend=stage2 |
| 13 | 13 | // target=native |
| 14 | 14 | // |
| 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 { |
| 7 | 7 | // backend=stage2 |
| 8 | 8 | // target=native |
| 9 | 9 | // |
| 10 | // :2:20: error: expected type 'comptime_int', found '*const u8' | |
| 10 | // :2:20: error: expected type 'comptime_int', found pointer | |
| 11 | // :2:20: note: address-of operator always returns a pointer |
test/cases/compile_errors/slice_sentinel_mismatch-1.zig+10-3| ... | ... | @@ -1,11 +1,18 @@ |
| 1 | export fn entry() void { | |
| 1 | export fn entry1() void { | |
| 2 | 2 | const y: [:1]const u8 = &[_:2]u8{ 1, 2 }; |
| 3 | 3 | _ = y; |
| 4 | 4 | } |
| 5 | export fn entry2() void { | |
| 6 | const x: [:2]const u8 = &.{ 1, 2 }; | |
| 7 | const y: [:1]const u8 = x; | |
| 8 | _ = y; | |
| 9 | } | |
| 5 | 10 | |
| 6 | 11 | // error |
| 7 | 12 | // backend=stage2 |
| 8 | 13 | // target=native |
| 9 | 14 | // |
| 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 { |
| 28 | 28 | // target=native |
| 29 | 29 | // |
| 30 | 30 | // :10:20: error: union initializer must initialize one field |
| 31 | // :1:12: note: union declared here | |
| 32 | 31 | // :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field |
| 33 | 32 | // :14:31: note: additional initializer here |
| 34 | 33 | // :1:12: note: union declared here |
test/cases/compile_errors/union_noreturn_field_initialized.zig+1-1| ... | ... | @@ -32,7 +32,7 @@ pub export fn entry3() void { |
| 32 | 32 | // backend=stage2 |
| 33 | 33 | // target=native |
| 34 | 34 | // |
| 35 | // :11:21: error: cannot initialize 'noreturn' field of union | |
| 35 | // :11:14: error: cannot initialize 'noreturn' field of union | |
| 36 | 36 | // :4:9: note: field 'b' declared here |
| 37 | 37 | // :2:15: note: union declared here |
| 38 | 38 | // :19:10: error: cannot initialize 'noreturn' field of union |
test/cases/compile_errors/wrong_types_given_to_export.zig+1-1| ... | ... | @@ -7,5 +7,5 @@ comptime { |
| 7 | 7 | // backend=stage2 |
| 8 | 8 | // target=native |
| 9 | 9 | // |
| 10 | // :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32' | |
| 10 | // :3:41: error: expected type 'builtin.GlobalLinkage', found 'u32' | |
| 11 | 11 | // :?:?: note: enum declared here |
test/compile_errors.zig+2-4| ... | ... | @@ -207,10 +207,8 @@ pub fn addCases(ctx: *Cases) !void { |
| 207 | 207 | ":1:38: note: declared comptime here", |
| 208 | 208 | ":8:36: error: runtime-known argument passed to comptime parameter", |
| 209 | 209 | ":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", | |
| 214 | 212 | }); |
| 215 | 213 | |
| 216 | 214 | case.addSourceFile("import.zig", |
test/tests.zig+5| ... | ... | @@ -1034,6 +1034,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1034 | 1034 | |
| 1035 | 1035 | these_tests.addIncludePath(.{ .path = "test" }); |
| 1036 | 1036 | |
| 1037 | if (test_target.target.getOs().tag == .wasi) { | |
| 1038 | // WASI's default stack size can be too small for some big tests. | |
| 1039 | these_tests.stack_size = 2 * 1024 * 1024; | |
| 1040 | } | |
| 1041 | ||
| 1037 | 1042 | const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{ |
| 1038 | 1043 | options.name, |
| 1039 | 1044 | triple_txt, |