| ... | ... | @@ -566,12 +566,11 @@ fn labeledBlockExpr( |
| 566 | 566 | .block_inst = block_inst, |
| 567 | 567 | }), |
| 568 | 568 | }; |
| 569 | setBlockResultLoc(&block_scope, rl); |
| 569 | 570 | defer block_scope.instructions.deinit(mod.gpa); |
| 570 | 571 | defer block_scope.labeled_breaks.deinit(mod.gpa); |
| 571 | 572 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); |
| 572 | 573 | |
| 573 | | setBlockResultLoc(&block_scope, rl); |
| 574 | | |
| 575 | 574 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); |
| 576 | 575 | |
| 577 | 576 | if (!block_scope.label.?.used) { |
| ... | ... | @@ -1337,9 +1336,6 @@ fn orelseCatchExpr( |
| 1337 | 1336 | rhs: *ast.Node, |
| 1338 | 1337 | payload_node: ?*ast.Node, |
| 1339 | 1338 | ) InnerError!*zir.Inst { |
| 1340 | | if (true) { |
| 1341 | | @panic("TODO reimplement this"); |
| 1342 | | } |
| 1343 | 1339 | const tree = scope.tree(); |
| 1344 | 1340 | const src = tree.token_locs[op_token].start; |
| 1345 | 1341 | |
| ... | ... | @@ -1349,22 +1345,12 @@ fn orelseCatchExpr( |
| 1349 | 1345 | .arena = scope.arena(), |
| 1350 | 1346 | .instructions = .{}, |
| 1351 | 1347 | }; |
| 1348 | setBlockResultLoc(&block_scope, rl); |
| 1352 | 1349 | defer block_scope.instructions.deinit(mod.gpa); |
| 1353 | 1350 | |
| 1354 | | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 1355 | | .instructions = undefined, // populated below |
| 1356 | | }); |
| 1357 | | |
| 1358 | | // Most result location types can be forwarded directly; however |
| 1359 | | // if we need to write to a pointer which has an inferred type, |
| 1360 | | // proper type inference requires peer type resolution on the if's |
| 1361 | | // branches. |
| 1362 | | const branch_rl: ResultLoc = switch (rl) { |
| 1363 | | .discard, .none, .ty, .ptr, .ref => rl, |
| 1364 | | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, |
| 1365 | | }; |
| 1366 | 1351 | // This could be a pointer or value depending on the `rl` parameter. |
| 1367 | | const operand = try expr(mod, &block_scope.base, branch_rl, lhs); |
| 1352 | block_scope.break_count += 1; |
| 1353 | const operand = try expr(mod, &block_scope.base, block_scope.break_result_loc, lhs); |
| 1368 | 1354 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); |
| 1369 | 1355 | |
| 1370 | 1356 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ |
| ... | ... | @@ -1373,6 +1359,10 @@ fn orelseCatchExpr( |
| 1373 | 1359 | .else_body = undefined, // populated below |
| 1374 | 1360 | }, .{}); |
| 1375 | 1361 | |
| 1362 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 1363 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1364 | }); |
| 1365 | |
| 1376 | 1366 | var then_scope: Scope.GenZIR = .{ |
| 1377 | 1367 | .parent = &block_scope.base, |
| 1378 | 1368 | .decl = block_scope.decl, |
| ... | ... | @@ -1383,8 +1373,7 @@ fn orelseCatchExpr( |
| 1383 | 1373 | |
| 1384 | 1374 | var err_val_scope: Scope.LocalVal = undefined; |
| 1385 | 1375 | const then_sub_scope = blk: { |
| 1386 | | const payload = payload_node orelse |
| 1387 | | break :blk &then_scope.base; |
| 1376 | const payload = payload_node orelse break :blk &then_scope.base; |
| 1388 | 1377 | |
| 1389 | 1378 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 1390 | 1379 | if (mem.eql(u8, err_name, "_")) |
| ... | ... | @@ -1399,10 +1388,8 @@ fn orelseCatchExpr( |
| 1399 | 1388 | break :blk &err_val_scope.base; |
| 1400 | 1389 | }; |
| 1401 | 1390 | |
| 1402 | | _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ |
| 1403 | | .block = block, |
| 1404 | | .operand = try expr(mod, then_sub_scope, branch_rl, rhs), |
| 1405 | | }, .{}); |
| 1391 | block_scope.break_count += 1; |
| 1392 | const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs); |
| 1406 | 1393 | |
| 1407 | 1394 | var else_scope: Scope.GenZIR = .{ |
| 1408 | 1395 | .parent = &block_scope.base, |
| ... | ... | @@ -1414,17 +1401,97 @@ fn orelseCatchExpr( |
| 1414 | 1401 | |
| 1415 | 1402 | // This could be a pointer or value depending on `unwrap_op`. |
| 1416 | 1403 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); |
| 1417 | | _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ |
| 1418 | | .block = block, |
| 1419 | | .operand = unwrapped_payload, |
| 1420 | | }, .{}); |
| 1421 | 1404 | |
| 1422 | | // All branches have been generated, add the instructions to the block. |
| 1423 | | block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); |
| 1405 | return finishThenElseBlock( |
| 1406 | mod, |
| 1407 | scope, |
| 1408 | rl, |
| 1409 | &block_scope, |
| 1410 | &then_scope, |
| 1411 | &else_scope, |
| 1412 | &condbr.positionals.then_body, |
| 1413 | &condbr.positionals.else_body, |
| 1414 | src, |
| 1415 | src, |
| 1416 | then_result, |
| 1417 | unwrapped_payload, |
| 1418 | block, |
| 1419 | ); |
| 1420 | } |
| 1424 | 1421 | |
| 1425 | | condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; |
| 1426 | | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; |
| 1427 | | return &block.base; |
| 1422 | fn finishThenElseBlock( |
| 1423 | mod: *Module, |
| 1424 | parent_scope: *Scope, |
| 1425 | rl: ResultLoc, |
| 1426 | block_scope: *Scope.GenZIR, |
| 1427 | then_scope: *Scope.GenZIR, |
| 1428 | else_scope: *Scope.GenZIR, |
| 1429 | then_body: *zir.Body, |
| 1430 | else_body: *zir.Body, |
| 1431 | then_src: usize, |
| 1432 | else_src: usize, |
| 1433 | then_result: *zir.Inst, |
| 1434 | else_result: ?*zir.Inst, |
| 1435 | block: *zir.Inst.Block, |
| 1436 | ) InnerError!*zir.Inst { |
| 1437 | // We now have enough information to decide whether the result instruction should |
| 1438 | // be communicated via result location pointer or break instructions. |
| 1439 | const strat = rlStrategy(rl, block_scope); |
| 1440 | switch (strat.tag) { |
| 1441 | .break_void => { |
| 1442 | if (!then_result.tag.isNoReturn()) { |
| 1443 | _ = try addZirInstTag(mod, &then_scope.base, then_src, .break_void, .{ |
| 1444 | .block = block, |
| 1445 | }); |
| 1446 | } |
| 1447 | if (else_result) |inst| { |
| 1448 | if (!inst.tag.isNoReturn()) { |
| 1449 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ |
| 1450 | .block = block, |
| 1451 | }); |
| 1452 | } |
| 1453 | } else { |
| 1454 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ |
| 1455 | .block = block, |
| 1456 | }); |
| 1457 | } |
| 1458 | assert(!strat.elide_store_to_block_ptr_instructions); |
| 1459 | try copyBodyNoEliding(then_body, then_scope.*); |
| 1460 | try copyBodyNoEliding(else_body, else_scope.*); |
| 1461 | return &block.base; |
| 1462 | }, |
| 1463 | .break_operand => { |
| 1464 | if (!then_result.tag.isNoReturn()) { |
| 1465 | _ = try addZirInstTag(mod, &then_scope.base, then_src, .@"break", .{ |
| 1466 | .block = block, |
| 1467 | .operand = then_result, |
| 1468 | }); |
| 1469 | } |
| 1470 | if (else_result) |inst| { |
| 1471 | if (!inst.tag.isNoReturn()) { |
| 1472 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .@"break", .{ |
| 1473 | .block = block, |
| 1474 | .operand = inst, |
| 1475 | }); |
| 1476 | } |
| 1477 | } else { |
| 1478 | _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ |
| 1479 | .block = block, |
| 1480 | }); |
| 1481 | } |
| 1482 | if (strat.elide_store_to_block_ptr_instructions) { |
| 1483 | try copyBodyWithElidedStoreBlockPtr(then_body, then_scope.*); |
| 1484 | try copyBodyWithElidedStoreBlockPtr(else_body, else_scope.*); |
| 1485 | } else { |
| 1486 | try copyBodyNoEliding(then_body, then_scope.*); |
| 1487 | try copyBodyNoEliding(else_body, else_scope.*); |
| 1488 | } |
| 1489 | switch (rl) { |
| 1490 | .ref => return &block.base, |
| 1491 | else => return rvalue(mod, parent_scope, rl, &block.base), |
| 1492 | } |
| 1493 | }, |
| 1494 | } |
| 1428 | 1495 | } |
| 1429 | 1496 | |
| 1430 | 1497 | /// Return whether the identifier names of two tokens are equal. Resolves @"" |
| ... | ... | @@ -1724,9 +1791,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1724 | 1791 | .arena = scope.arena(), |
| 1725 | 1792 | .instructions = .{}, |
| 1726 | 1793 | }; |
| 1727 | | defer block_scope.instructions.deinit(mod.gpa); |
| 1728 | | |
| 1729 | 1794 | setBlockResultLoc(&block_scope, rl); |
| 1795 | defer block_scope.instructions.deinit(mod.gpa); |
| 1730 | 1796 | |
| 1731 | 1797 | const tree = scope.tree(); |
| 1732 | 1798 | const if_src = tree.token_locs[if_node.if_token].start; |
| ... | ... | @@ -1783,64 +1849,21 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1783 | 1849 | break :blk null; |
| 1784 | 1850 | }; |
| 1785 | 1851 | |
| 1786 | | // We now have enough information to decide whether the result instruction should |
| 1787 | | // be communicated via result location pointer or break instructions. |
| 1788 | | const strat = rlStrategy(rl, &block_scope); |
| 1789 | | switch (strat.tag) { |
| 1790 | | .break_void => { |
| 1791 | | if (!then_result.tag.isNoReturn()) { |
| 1792 | | _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ |
| 1793 | | .block = block, |
| 1794 | | }); |
| 1795 | | } |
| 1796 | | if (else_result) |inst| { |
| 1797 | | if (!inst.tag.isNoReturn()) { |
| 1798 | | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1799 | | .block = block, |
| 1800 | | }); |
| 1801 | | } |
| 1802 | | } else { |
| 1803 | | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1804 | | .block = block, |
| 1805 | | }); |
| 1806 | | } |
| 1807 | | assert(!strat.elide_store_to_block_ptr_instructions); |
| 1808 | | try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); |
| 1809 | | try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); |
| 1810 | | return &block.base; |
| 1811 | | }, |
| 1812 | | .break_operand => { |
| 1813 | | if (!then_result.tag.isNoReturn()) { |
| 1814 | | _ = try addZirInstTag(mod, then_sub_scope, then_src, .@"break", .{ |
| 1815 | | .block = block, |
| 1816 | | .operand = then_result, |
| 1817 | | }); |
| 1818 | | } |
| 1819 | | if (else_result) |inst| { |
| 1820 | | if (!inst.tag.isNoReturn()) { |
| 1821 | | _ = try addZirInstTag(mod, else_sub_scope, else_src, .@"break", .{ |
| 1822 | | .block = block, |
| 1823 | | .operand = inst, |
| 1824 | | }); |
| 1825 | | } |
| 1826 | | } else { |
| 1827 | | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ |
| 1828 | | .block = block, |
| 1829 | | }); |
| 1830 | | } |
| 1831 | | if (strat.elide_store_to_block_ptr_instructions) { |
| 1832 | | try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); |
| 1833 | | try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.else_body, else_scope); |
| 1834 | | } else { |
| 1835 | | try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); |
| 1836 | | try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); |
| 1837 | | } |
| 1838 | | switch (rl) { |
| 1839 | | .ref => return &block.base, |
| 1840 | | else => return rvalue(mod, scope, rl, &block.base), |
| 1841 | | } |
| 1842 | | }, |
| 1843 | | } |
| 1852 | return finishThenElseBlock( |
| 1853 | mod, |
| 1854 | scope, |
| 1855 | rl, |
| 1856 | &block_scope, |
| 1857 | &then_scope, |
| 1858 | &else_scope, |
| 1859 | &condbr.positionals.then_body, |
| 1860 | &condbr.positionals.else_body, |
| 1861 | then_src, |
| 1862 | else_src, |
| 1863 | then_result, |
| 1864 | else_result, |
| 1865 | block, |
| 1866 | ); |
| 1844 | 1867 | } |
| 1845 | 1868 | |
| 1846 | 1869 | /// Expects to find exactly 1 .store_to_block_ptr instruction. |