authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-25 01:47:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-31 21:09:22-07:00
loge9e6cc217124cb67c94790e38feaf45abda839ff
treecb78aca0cbe679099874ea97ef673864c257bf2b
parent6c8985fceeeb6314143691570cf0c7a42521e590

astgen: rework orelse/catch


1 files changed, 116 insertions(+), 93 deletions(-)

src/astgen.zig+116-93
...@@ -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);
572573
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());
576575
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;
13451341
...@@ -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);
13531350
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);
13691355
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 below1359 .else_body = undefined, // populated below
1374 }, .{});1360 }, .{});
13751361
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(
13831373
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 orelse1376 const payload = payload_node orelse break :blk &then_scope.base;
1387 break :blk &then_scope.base;
13881377
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 };
14011390
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 }, .{});
14061393
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(
14141401
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 }, .{});
14211404
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}
14241421
1425 condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) };1422fn 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}
14291496
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);
17301796
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 };
17851851
1786 // We now have enough information to decide whether the result instruction should1852 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}
18451868
1846/// Expects to find exactly 1 .store_to_block_ptr instruction.1869/// Expects to find exactly 1 .store_to_block_ptr instruction.