Skip to content

stage2: astgen for try #7606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion src/astgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
.For => return forExpr(mod, scope, rl, node.castTag(.For).?),
.ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
.Slice => return rlWrap(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)),
.Try => return tryExpr(mod, scope, rl, node.castTag(.Try).?),
.Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
.Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
.OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
Expand All @@ -287,7 +288,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
.Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
.Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
.Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
.ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
.ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
.StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
Expand Down Expand Up @@ -1055,6 +1055,86 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
});
}

fn tryExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.op_token].start;

const operand_ptr = try expr(mod, scope, .ref, node.rhs);
// TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer
const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr);
const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union);

var block_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.arena = scope.arena(),
.instructions = .{},
};
defer block_scope.instructions.deinit(mod.gpa);

const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
.condition = cond,
.then_body = undefined, // populated below
.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),
});

// 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 },
};

var then_scope: Scope.GenZIR = .{
.parent = scope,
.decl = block_scope.decl,
.arena = block_scope.arena,
.instructions = .{},
};
defer then_scope.instructions.deinit(mod.gpa);

var err_val_scope: Scope.LocalVal = undefined;

const unwrapped_err_ptr = try addZIRUnOp(mod, &then_scope.base, src, .unwrap_err_code, operand_ptr);
const unwrapped_err = try addZIRUnOp(mod, &then_scope.base, src, .deref, unwrapped_err_ptr);

_ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{
.block = block,
.operand = try addZIRUnOp(mod, &then_scope.base, src, .@"return", try addZIRBinOp(
mod,
&then_scope.base,
src,
.as,
try addZIRNoOp(mod, &then_scope.base, src, .ret_type),
unwrapped_err,
)),
}, .{});

var else_scope: Scope.GenZIR = .{
.parent = scope,
.decl = block_scope.decl,
.arena = block_scope.arena,
.instructions = .{},
};
defer else_scope.instructions.deinit(mod.gpa);

const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, .unwrap_err_unsafe, operand_ptr);
_ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{
.block = block,
.operand = unwrapped_payload,
}, .{});

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 rlWrapPtr(mod, scope, rl, &block.base);
}

fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {
return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .iserr, .unwrap_err_unsafe, node.rhs, node.payload);
}
Expand Down
28 changes: 14 additions & 14 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2006,6 +2006,20 @@ const AfterUpdateHook = union(enum) {
fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8, hook: AfterUpdateHook) !void {
try comp.update();

if (zir_out_path) |zop| {
const module = comp.bin_file.options.module orelse
fatal("-femit-zir with no zig source code", .{});
var new_zir_module = try zir.emit(gpa, module);
defer new_zir_module.deinit(gpa);

const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
defer baf.destroy();

try new_zir_module.writeToStream(gpa, baf.writer());

try baf.finish();
}

var errors = try comp.getAllErrorsAlloc();
defer errors.deinit(comp.gpa);

Expand All @@ -2024,20 +2038,6 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,
.{},
),
}

if (zir_out_path) |zop| {
const module = comp.bin_file.options.module orelse
fatal("-femit-zir with no zig source code", .{});
var new_zir_module = try zir.emit(gpa, module);
defer new_zir_module.deinit(gpa);

const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
defer baf.destroy();

try new_zir_module.writeToStream(gpa, baf.writer());

try baf.finish();
}
}

fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
Expand Down