| ... | @@ -566,12 +566,11 @@ fn labeledBlockExpr( | ... | @@ -566,12 +566,11 @@ fn labeledBlockExpr( |
| 566 | .block_inst = block_inst, | 566 | .block_inst = block_inst, |
| 567 | }), | 567 | }), |
| 568 | }; | 568 | }; |
| | 569 | setBlockResultLoc(&block_scope, rl); |
| 569 | defer block_scope.instructions.deinit(mod.gpa); | 570 | defer block_scope.instructions.deinit(mod.gpa); |
| 570 | defer block_scope.labeled_breaks.deinit(mod.gpa); | 571 | defer block_scope.labeled_breaks.deinit(mod.gpa); |
| 571 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); | 572 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); |
| 572 | | 573 | |
| 573 | setBlockResultLoc(&block_scope, rl); | | |
| 574 | | | |
| 575 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); | 574 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); |
| 576 | | 575 | |
| 577 | if (!block_scope.label.?.used) { | 576 | if (!block_scope.label.?.used) { |
| ... | @@ -1337,9 +1336,6 @@ fn orelseCatchExpr( | ... | @@ -1337,9 +1336,6 @@ fn orelseCatchExpr( |
| 1337 | rhs: *ast.Node, | 1336 | rhs: *ast.Node, |
| 1338 | payload_node: ?*ast.Node, | 1337 | payload_node: ?*ast.Node, |
| 1339 | ) InnerError!*zir.Inst { | 1338 | ) InnerError!*zir.Inst { |
| 1340 | if (true) { | | |
| 1341 | @panic("TODO reimplement this"); | | |
| 1342 | } | | |
| 1343 | const tree = scope.tree(); | 1339 | const tree = scope.tree(); |
| 1344 | const src = tree.token_locs[op_token].start; | 1340 | const src = tree.token_locs[op_token].start; |
| 1345 | | 1341 | |
| ... | @@ -1349,22 +1345,12 @@ fn orelseCatchExpr( | ... | @@ -1349,22 +1345,12 @@ fn orelseCatchExpr( |
| 1349 | .arena = scope.arena(), | 1345 | .arena = scope.arena(), |
| 1350 | .instructions = .{}, | 1346 | .instructions = .{}, |
| 1351 | }; | 1347 | }; |
| | 1348 | setBlockResultLoc(&block_scope, rl); |
| 1352 | defer block_scope.instructions.deinit(mod.gpa); | 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 | // This could be a pointer or value depending on the `rl` parameter. | 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 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); | 1354 | const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); |
| 1369 | | 1355 | |
| 1370 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ | 1356 | const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ |
| ... | @@ -1373,6 +1359,10 @@ fn orelseCatchExpr( | ... | @@ -1373,6 +1359,10 @@ fn orelseCatchExpr( |
| 1373 | .else_body = undefined, // populated below | 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 | var then_scope: Scope.GenZIR = .{ | 1366 | var then_scope: Scope.GenZIR = .{ |
| 1377 | .parent = &block_scope.base, | 1367 | .parent = &block_scope.base, |
| 1378 | .decl = block_scope.decl, | 1368 | .decl = block_scope.decl, |
| ... | @@ -1383,8 +1373,7 @@ fn orelseCatchExpr( | ... | @@ -1383,8 +1373,7 @@ fn orelseCatchExpr( |
| 1383 | | 1373 | |
| 1384 | var err_val_scope: Scope.LocalVal = undefined; | 1374 | var err_val_scope: Scope.LocalVal = undefined; |
| 1385 | const then_sub_scope = blk: { | 1375 | const then_sub_scope = blk: { |
| 1386 | const payload = payload_node orelse | 1376 | const payload = payload_node orelse break :blk &then_scope.base; |
| 1387 | break :blk &then_scope.base; | | |
| 1388 | | 1377 | |
| 1389 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); | 1378 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 1390 | if (mem.eql(u8, err_name, "_")) | 1379 | if (mem.eql(u8, err_name, "_")) |
| ... | @@ -1399,10 +1388,8 @@ fn orelseCatchExpr( | ... | @@ -1399,10 +1388,8 @@ fn orelseCatchExpr( |
| 1399 | break :blk &err_val_scope.base; | 1388 | break :blk &err_val_scope.base; |
| 1400 | }; | 1389 | }; |
| 1401 | | 1390 | |
| 1402 | _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ | 1391 | block_scope.break_count += 1; |
| 1403 | .block = block, | 1392 | const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs); |
| 1404 | .operand = try expr(mod, then_sub_scope, branch_rl, rhs), | | |
| 1405 | }, .{}); | | |
| 1406 | | 1393 | |
| 1407 | var else_scope: Scope.GenZIR = .{ | 1394 | var else_scope: Scope.GenZIR = .{ |
| 1408 | .parent = &block_scope.base, | 1395 | .parent = &block_scope.base, |
| ... | @@ -1414,17 +1401,97 @@ fn orelseCatchExpr( | ... | @@ -1414,17 +1401,97 @@ fn orelseCatchExpr( |
| 1414 | | 1401 | |
| 1415 | // This could be a pointer or value depending on `unwrap_op`. | 1402 | // This could be a pointer or value depending on `unwrap_op`. |
| 1416 | const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); | 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. | 1405 | return finishThenElseBlock( |
| 1423 | block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); | 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) }; | 1422 | fn finishThenElseBlock( |
| 1426 | condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; | 1423 | mod: *Module, |
| 1427 | return &block.base; | 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 | /// Return whether the identifier names of two tokens are equal. Resolves @"" | 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,9 +1791,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1724 | .arena = scope.arena(), | 1791 | .arena = scope.arena(), |
| 1725 | .instructions = .{}, | 1792 | .instructions = .{}, |
| 1726 | }; | 1793 | }; |
| 1727 | defer block_scope.instructions.deinit(mod.gpa); | | |
| 1728 | | | |
| 1729 | setBlockResultLoc(&block_scope, rl); | 1794 | setBlockResultLoc(&block_scope, rl); |
| | 1795 | defer block_scope.instructions.deinit(mod.gpa); |
| 1730 | | 1796 | |
| 1731 | const tree = scope.tree(); | 1797 | const tree = scope.tree(); |
| 1732 | const if_src = tree.token_locs[if_node.if_token].start; | 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,64 +1849,21 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1783 | break :blk null; | 1849 | break :blk null; |
| 1784 | }; | 1850 | }; |
| 1785 | | 1851 | |
| 1786 | // We now have enough information to decide whether the result instruction should | 1852 | return finishThenElseBlock( |
| 1787 | // be communicated via result location pointer or break instructions. | 1853 | mod, |
| 1788 | const strat = rlStrategy(rl, &block_scope); | 1854 | scope, |
| 1789 | switch (strat.tag) { | 1855 | rl, |
| 1790 | .break_void => { | 1856 | &block_scope, |
| 1791 | if (!then_result.tag.isNoReturn()) { | 1857 | &then_scope, |
| 1792 | _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ | 1858 | &else_scope, |
| 1793 | .block = block, | 1859 | &condbr.positionals.then_body, |
| 1794 | }); | 1860 | &condbr.positionals.else_body, |
| 1795 | } | 1861 | then_src, |
| 1796 | if (else_result) |inst| { | 1862 | else_src, |
| 1797 | if (!inst.tag.isNoReturn()) { | 1863 | then_result, |
| 1798 | _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ | 1864 | else_result, |
| 1799 | .block = block, | 1865 | block, |
| 1800 | }); | 1866 | ); |
| 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 | } | | |
| 1844 | } | 1867 | } |
| 1845 | | 1868 | |
| 1846 | /// Expects to find exactly 1 .store_to_block_ptr instruction. | 1869 | /// Expects to find exactly 1 .store_to_block_ptr instruction. |