diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-01-25 01:47:36 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-01-31 21:09:22 -0700 |
| commit | e9e6cc217124cb67c94790e38feaf45abda839ff (patch) | |
| tree | cb78aca0cbe679099874ea97ef673864c257bf2b /src | |
| parent | 6c8985fceeeb6314143691570cf0c7a42521e590 (diff) | |
| download | zig-e9e6cc217124cb67c94790e38feaf45abda839ff.tar.gz zig-e9e6cc217124cb67c94790e38feaf45abda839ff.zip | |
astgen: rework orelse/catch
Diffstat (limited to 'src')
| -rw-r--r-- | src/astgen.zig | 209 |
1 files changed, 116 insertions, 93 deletions
diff --git a/src/astgen.zig b/src/astgen.zig index 994205c3a7..7de94506b7 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -566,12 +566,11 @@ fn labeledBlockExpr( .block_inst = block_inst, }), }; + setBlockResultLoc(&block_scope, rl); defer block_scope.instructions.deinit(mod.gpa); defer block_scope.labeled_breaks.deinit(mod.gpa); defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); - setBlockResultLoc(&block_scope, rl); - try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); if (!block_scope.label.?.used) { @@ -1337,9 +1336,6 @@ fn orelseCatchExpr( rhs: *ast.Node, payload_node: ?*ast.Node, ) InnerError!*zir.Inst { - if (true) { - @panic("TODO reimplement this"); - } const tree = scope.tree(); const src = tree.token_locs[op_token].start; @@ -1349,22 +1345,12 @@ fn orelseCatchExpr( .arena = scope.arena(), .instructions = .{}, }; + setBlockResultLoc(&block_scope, rl); defer block_scope.instructions.deinit(mod.gpa); - const block = try addZIRInstBlock(mod, scope, src, .block, .{ - .instructions = undefined, // populated below - }); - - // Most result location types can be forwarded directly; however - // if we need to write to a pointer which has an inferred type, - // proper type inference requires peer type resolution on the if's - // branches. - const branch_rl: ResultLoc = switch (rl) { - .discard, .none, .ty, .ptr, .ref => rl, - .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block }, - }; // This could be a pointer or value depending on the `rl` parameter. - const operand = try expr(mod, &block_scope.base, branch_rl, lhs); + block_scope.break_count += 1; + const operand = try expr(mod, &block_scope.base, block_scope.break_result_loc, lhs); const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand); const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{ @@ -1373,6 +1359,10 @@ fn orelseCatchExpr( .else_body = undefined, // populated below }, .{}); + const block = try addZIRInstBlock(mod, scope, src, .block, .{ + .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), + }); + var then_scope: Scope.GenZIR = .{ .parent = &block_scope.base, .decl = block_scope.decl, @@ -1383,8 +1373,7 @@ fn orelseCatchExpr( var err_val_scope: Scope.LocalVal = undefined; const then_sub_scope = blk: { - const payload = payload_node orelse - break :blk &then_scope.base; + const payload = payload_node orelse break :blk &then_scope.base; const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); if (mem.eql(u8, err_name, "_")) @@ -1399,10 +1388,8 @@ fn orelseCatchExpr( break :blk &err_val_scope.base; }; - _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{ - .block = block, - .operand = try expr(mod, then_sub_scope, branch_rl, rhs), - }, .{}); + block_scope.break_count += 1; + const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs); var else_scope: Scope.GenZIR = .{ .parent = &block_scope.base, @@ -1414,17 +1401,97 @@ fn orelseCatchExpr( // This could be a pointer or value depending on `unwrap_op`. const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand); - _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{ - .block = block, - .operand = unwrapped_payload, - }, .{}); - // All branches have been generated, add the instructions to the block. - block.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items); + return finishThenElseBlock( + mod, + scope, + rl, + &block_scope, + &then_scope, + &else_scope, + &condbr.positionals.then_body, + &condbr.positionals.else_body, + src, + src, + then_result, + unwrapped_payload, + block, + ); +} - condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) }; - condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) }; - return &block.base; +fn finishThenElseBlock( + mod: *Module, + parent_scope: *Scope, + rl: ResultLoc, + block_scope: *Scope.GenZIR, + then_scope: *Scope.GenZIR, + else_scope: *Scope.GenZIR, + then_body: *zir.Body, + else_body: *zir.Body, + then_src: usize, + else_src: usize, + then_result: *zir.Inst, + else_result: ?*zir.Inst, + block: *zir.Inst.Block, +) InnerError!*zir.Inst { + // We now have enough information to decide whether the result instruction should + // be communicated via result location pointer or break instructions. + const strat = rlStrategy(rl, block_scope); + switch (strat.tag) { + .break_void => { + if (!then_result.tag.isNoReturn()) { + _ = try addZirInstTag(mod, &then_scope.base, then_src, .break_void, .{ + .block = block, + }); + } + if (else_result) |inst| { + if (!inst.tag.isNoReturn()) { + _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ + .block = block, + }); + } + } else { + _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ + .block = block, + }); + } + assert(!strat.elide_store_to_block_ptr_instructions); + try copyBodyNoEliding(then_body, then_scope.*); + try copyBodyNoEliding(else_body, else_scope.*); + return &block.base; + }, + .break_operand => { + if (!then_result.tag.isNoReturn()) { + _ = try addZirInstTag(mod, &then_scope.base, then_src, .@"break", .{ + .block = block, + .operand = then_result, + }); + } + if (else_result) |inst| { + if (!inst.tag.isNoReturn()) { + _ = try addZirInstTag(mod, &else_scope.base, else_src, .@"break", .{ + .block = block, + .operand = inst, + }); + } + } else { + _ = try addZirInstTag(mod, &else_scope.base, else_src, .break_void, .{ + .block = block, + }); + } + if (strat.elide_store_to_block_ptr_instructions) { + try copyBodyWithElidedStoreBlockPtr(then_body, then_scope.*); + try copyBodyWithElidedStoreBlockPtr(else_body, else_scope.*); + } else { + try copyBodyNoEliding(then_body, then_scope.*); + try copyBodyNoEliding(else_body, else_scope.*); + } + switch (rl) { + .ref => return &block.base, + else => return rvalue(mod, parent_scope, rl, &block.base), + } + }, + } } /// 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 .arena = scope.arena(), .instructions = .{}, }; - defer block_scope.instructions.deinit(mod.gpa); - setBlockResultLoc(&block_scope, rl); + defer block_scope.instructions.deinit(mod.gpa); const tree = scope.tree(); 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 break :blk null; }; - // We now have enough information to decide whether the result instruction should - // be communicated via result location pointer or break instructions. - const strat = rlStrategy(rl, &block_scope); - switch (strat.tag) { - .break_void => { - if (!then_result.tag.isNoReturn()) { - _ = try addZirInstTag(mod, then_sub_scope, then_src, .break_void, .{ - .block = block, - }); - } - if (else_result) |inst| { - if (!inst.tag.isNoReturn()) { - _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ - .block = block, - }); - } - } else { - _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ - .block = block, - }); - } - assert(!strat.elide_store_to_block_ptr_instructions); - try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); - try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); - return &block.base; - }, - .break_operand => { - if (!then_result.tag.isNoReturn()) { - _ = try addZirInstTag(mod, then_sub_scope, then_src, .@"break", .{ - .block = block, - .operand = then_result, - }); - } - if (else_result) |inst| { - if (!inst.tag.isNoReturn()) { - _ = try addZirInstTag(mod, else_sub_scope, else_src, .@"break", .{ - .block = block, - .operand = inst, - }); - } - } else { - _ = try addZirInstTag(mod, else_sub_scope, else_src, .break_void, .{ - .block = block, - }); - } - if (strat.elide_store_to_block_ptr_instructions) { - try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.then_body, then_scope); - try copyBodyWithElidedStoreBlockPtr(&condbr.positionals.else_body, else_scope); - } else { - try copyBodyNoEliding(&condbr.positionals.then_body, then_scope); - try copyBodyNoEliding(&condbr.positionals.else_body, else_scope); - } - switch (rl) { - .ref => return &block.base, - else => return rvalue(mod, scope, rl, &block.base), - } - }, - } + return finishThenElseBlock( + mod, + scope, + rl, + &block_scope, + &then_scope, + &else_scope, + &condbr.positionals.then_body, + &condbr.positionals.else_body, + then_src, + else_src, + then_result, + else_result, + block, + ); } /// Expects to find exactly 1 .store_to_block_ptr instruction. |
