fix: broken conditionals
This commit is contained in:
parent
b231e66b49
commit
97a43f63eb
33 changed files with 358 additions and 313 deletions
378
src/AstGen.zig
378
src/AstGen.zig
|
|
@ -195,7 +195,6 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
|||
astgen.extra.items.len += reserved_extra_count;
|
||||
|
||||
const fatal = if (tree.errors.len == 0) fatal: {
|
||||
// TODO: Make sure this is never null.
|
||||
file(&block, &file_scope, tree.root) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.SemanticError => break :fatal true,
|
||||
|
|
@ -599,18 +598,15 @@ fn setCondBrPayload(
|
|||
const astgen = then_block.astgen;
|
||||
const then_body = then_block.instructionsSliceUpto(else_block);
|
||||
const else_body = else_block.instructionsSlice();
|
||||
const then_body_len = then_body.len;
|
||||
const else_body_len = else_body.len;
|
||||
const extra_len =
|
||||
@typeInfo(Ir.Inst.CondBr).@"struct".fields.len + then_body_len + else_body_len;
|
||||
const extra_len = @typeInfo(Ir.Inst.CondBr).@"struct".fields.len + then_body.len + else_body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_len);
|
||||
|
||||
const inst_data = &astgen.instructions.items[@intFromEnum(condbr)].data;
|
||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.CondBr{
|
||||
.condition = cond,
|
||||
.then_body_len = @intCast(then_body_len),
|
||||
.else_body_len = @intCast(else_body_len),
|
||||
.then_body_len = @intCast(then_body.len),
|
||||
.else_body_len = @intCast(else_body.len),
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -776,229 +772,289 @@ fn expr(gi: *GenIr, scope: *Scope, optional_node: ?*const Ast.Node) InnerError!I
|
|||
.else_branch => unreachable, // Handled in switchStmt, multiIfStmt, and ifStmt
|
||||
.content => unreachable,
|
||||
.inline_logic_expr => unreachable,
|
||||
.inline_if_stmt => unreachable,
|
||||
.invalid => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn exprStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
if (node.data.bin.lhs) |n| {
|
||||
return expr(gi, scope, n);
|
||||
}
|
||||
const data = node.data.bin;
|
||||
if (data.lhs) |lhs| return expr(gi, scope, lhs);
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn inlineLogicExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
if (node.data.bin.lhs) |lhs| {
|
||||
return expr(gi, scope, lhs);
|
||||
}
|
||||
const data = node.data.bin;
|
||||
if (data.lhs) |lhs| return expr(gi, scope, lhs);
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn validateSwitchProngs(gen: *GenIr, stmt_node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gen.astgen;
|
||||
var stmt_has_block: bool = false;
|
||||
var stmt_has_else: bool = false;
|
||||
const case_list = stmt_node.data.switch_stmt.cases;
|
||||
const last_prong = case_list[case_list.len - 1];
|
||||
for (case_list) |case_stmt| {
|
||||
switch (case_stmt.tag) {
|
||||
.block_stmt => stmt_has_block = true,
|
||||
.switch_case, .if_branch => {
|
||||
if (stmt_has_block) {
|
||||
//return gen.fail(.expected_else, case_stmt);
|
||||
}
|
||||
},
|
||||
.else_branch => {
|
||||
if (case_stmt != last_prong) {
|
||||
return fail(astgen, case_stmt, "invalid else stmt", .{});
|
||||
}
|
||||
if (stmt_has_else) {
|
||||
return fail(astgen, case_stmt, "duplicate else stmt", .{});
|
||||
}
|
||||
stmt_has_else = true;
|
||||
},
|
||||
inline else => |tag| @panic("Unexpected node " ++ @tagName(tag)),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn inlineIfStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
const gpa = gi.astgen.gpa;
|
||||
const data = node.data.bin;
|
||||
const cond_expr = data.lhs.?;
|
||||
|
||||
fn ifStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!Ir.Inst.Ref {
|
||||
const astgen = parent_block.astgen;
|
||||
const cond_expr = stmt_node.data.switch_stmt.condition_expr.?;
|
||||
try validateSwitchProngs(parent_block, stmt_node);
|
||||
|
||||
const case_list = stmt_node.data.switch_stmt.cases;
|
||||
const then_node = case_list[0];
|
||||
const last_prong = case_list[case_list.len - 1];
|
||||
|
||||
var block_scope = parent_block.makeSubBlock();
|
||||
var block_scope = gi.makeSubBlock();
|
||||
defer block_scope.unstack();
|
||||
|
||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||
const condbr = try block_scope.addCondBr(.condbr);
|
||||
const block = try parent_block.makePayloadNode(.block);
|
||||
try block_scope.setBlockBody(block); // unstacks block
|
||||
try parent_block.instructions.append(astgen.gpa, block);
|
||||
const block = try gi.makePayloadNode(.block);
|
||||
|
||||
var then_block = parent_block.makeSubBlock();
|
||||
try block_scope.setBlockBody(block);
|
||||
try gi.instructions.append(gpa, block);
|
||||
|
||||
var then_block = gi.makeSubBlock();
|
||||
defer then_block.unstack();
|
||||
|
||||
try blockStmt(&then_block, scope, then_node);
|
||||
_ = try then_block.addBreak(.@"break", then_node, block);
|
||||
if (data.rhs) |rhs| {
|
||||
// TODO: Revisit this. This isn't quite correct.
|
||||
switch (rhs.tag) {
|
||||
.content => _ = try contentExpr(&then_block, scope, rhs),
|
||||
inline else => |tag| @panic("Unexpected node type: " ++ @tagName(tag)),
|
||||
}
|
||||
}
|
||||
if (!then_block.endsWithNoReturn()) {
|
||||
_ = try then_block.addBreak(.@"break", node, block);
|
||||
}
|
||||
|
||||
var else_block = parent_block.makeSubBlock();
|
||||
var else_block = gi.makeSubBlock();
|
||||
defer else_block.unstack();
|
||||
|
||||
if (then_node == last_prong) {
|
||||
_ = try else_block.addBreak(.@"break", then_node, block);
|
||||
_ = try else_block.addBreak(.@"break", node, block);
|
||||
try setCondBrPayload(condbr, cond_inst, &then_block, &else_block);
|
||||
return condbr.toRef();
|
||||
}
|
||||
|
||||
fn validateIfCases(astgen: *AstGen, cases: []const *Ast.Node) InnerError!void {
|
||||
assert(cases.len != 0);
|
||||
|
||||
var seen_else = false;
|
||||
for (cases, 0..) |case_node, i| {
|
||||
switch (case_node.tag) {
|
||||
.block_stmt => {
|
||||
if (i != 0)
|
||||
return fail(astgen, case_node, "unexpected block in conditional prong list", .{});
|
||||
},
|
||||
.if_branch => {
|
||||
if (seen_else)
|
||||
return fail(astgen, case_node, "branch after else is unreachable", .{});
|
||||
},
|
||||
.else_branch => {
|
||||
if (i != cases.len - 1)
|
||||
return fail(astgen, case_node, "'else' case should always be the final case in conditional", .{});
|
||||
if (seen_else)
|
||||
return fail(astgen, case_node, "duplicate else branch", .{});
|
||||
seen_else = true;
|
||||
},
|
||||
else => return fail(astgen, case_node, "unexpected node in conditional prong list", .{}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ifStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
const astgen = gi.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const data = node.data.switch_stmt;
|
||||
const cases = data.cases;
|
||||
const cond_expr = data.condition_expr.?;
|
||||
|
||||
try validateIfCases(astgen, cases);
|
||||
|
||||
var block_scope = gi.makeSubBlock();
|
||||
defer block_scope.unstack();
|
||||
|
||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||
const condbr = try block_scope.addCondBr(.condbr);
|
||||
const block = try gi.makePayloadNode(.block);
|
||||
try block_scope.setBlockBody(block);
|
||||
try gi.instructions.append(gpa, block);
|
||||
|
||||
var then_block = gi.makeSubBlock();
|
||||
defer then_block.unstack();
|
||||
|
||||
const then_body = switch (cases[0].tag) {
|
||||
.block_stmt => cases[0],
|
||||
.if_branch => cases[0].data.bin.rhs.?,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try blockStmt(&then_block, scope, then_body);
|
||||
if (!then_block.endsWithNoReturn()) {
|
||||
_ = try then_block.addBreak(.@"break", then_body, block);
|
||||
}
|
||||
|
||||
var else_block = gi.makeSubBlock();
|
||||
defer else_block.unstack();
|
||||
|
||||
const else_case = if (cases.len > 1) cases[cases.len - 1] else null;
|
||||
if (else_case) |else_stmt| {
|
||||
if (else_stmt.tag == .else_branch) {
|
||||
const else_body = else_stmt.data.bin.rhs.?;
|
||||
try blockStmt(&else_block, scope, else_body);
|
||||
|
||||
if (!else_block.endsWithNoReturn()) {
|
||||
_ = try else_block.addBreak(.@"break", else_body, block);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const block_node = last_prong.data.bin.rhs.?;
|
||||
try blockStmt(&else_block, scope, block_node);
|
||||
_ = try else_block.addBreak(.@"break", then_body, block);
|
||||
}
|
||||
|
||||
try setCondBrPayload(condbr, cond_inst, &then_block, &else_block);
|
||||
return condbr.toRef();
|
||||
}
|
||||
|
||||
fn ifChain(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
branch_list: []const *Ast.Node,
|
||||
) InnerError!Ir.Inst.Ref {
|
||||
const gpa = parent_block.astgen.gpa;
|
||||
if (branch_list.len == 0) return @enumFromInt(0);
|
||||
if (branch_list[0].data.bin.lhs == null) {
|
||||
const body_node = branch_list[0].data.bin.rhs.?;
|
||||
try blockStmt(parent_block, scope, body_node);
|
||||
return @enumFromInt(0);
|
||||
}
|
||||
|
||||
var block_scope = parent_block.makeSubBlock();
|
||||
defer block_scope.unstack();
|
||||
fn ifChain(gi: *GenIr, scope: *Scope, branch_list: []const *Ast.Node) InnerError!void {
|
||||
const gpa = gi.astgen.gpa;
|
||||
if (branch_list.len == 0) return;
|
||||
|
||||
const branch = branch_list[0];
|
||||
const cond_expr = branch.data.bin.lhs.?;
|
||||
const body_node = branch.data.bin.rhs.?;
|
||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||
if (branch.tag == .else_branch) {
|
||||
const data = branch.data.bin;
|
||||
try blockStmt(gi, scope, data.rhs.?);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = branch.data.bin;
|
||||
const body = data.rhs.?;
|
||||
assert(branch.tag == .if_branch);
|
||||
|
||||
var block_scope = gi.makeSubBlock();
|
||||
defer block_scope.unstack();
|
||||
|
||||
const cond_inst = try expr(&block_scope, scope, data.lhs.?);
|
||||
const condbr = try block_scope.addCondBr(.condbr);
|
||||
const block_inst = try parent_block.makePayloadNode(.block);
|
||||
const block_inst = try gi.makePayloadNode(.block);
|
||||
try block_scope.setBlockBody(block_inst);
|
||||
try parent_block.instructions.append(gpa, block_inst);
|
||||
try gi.instructions.append(gpa, block_inst);
|
||||
|
||||
var then_block = parent_block.makeSubBlock();
|
||||
var then_block = gi.makeSubBlock();
|
||||
defer then_block.unstack();
|
||||
try blockStmt(&then_block, scope, body_node);
|
||||
_ = try then_block.addBreak(.@"break", body_node, block_inst);
|
||||
|
||||
var else_block = parent_block.makeSubBlock();
|
||||
try blockStmt(&then_block, scope, body);
|
||||
if (!then_block.endsWithNoReturn()) {
|
||||
_ = try then_block.addBreak(.@"break", body, block_inst);
|
||||
}
|
||||
|
||||
var else_block = gi.makeSubBlock();
|
||||
defer else_block.unstack();
|
||||
const next_branches = branch_list[1..];
|
||||
_ = try ifChain(parent_block, scope, next_branches);
|
||||
_ = try else_block.addBreak(.@"break", body_node, block_inst);
|
||||
|
||||
try ifChain(&else_block, scope, branch_list[1..]);
|
||||
try setCondBrPayload(condbr, cond_inst, &then_block, &else_block);
|
||||
return @enumFromInt(0);
|
||||
}
|
||||
|
||||
fn multiIfStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!Ir.Inst.Ref {
|
||||
try validateSwitchProngs(parent_block, stmt_node);
|
||||
|
||||
const branch_list = stmt_node.data.switch_stmt.cases;
|
||||
if (branch_list[0].data.bin.lhs == null) {
|
||||
const branch = branch_list[0];
|
||||
const body_node = branch.data.bin.rhs.?;
|
||||
try blockStmt(parent_block, scope, body_node);
|
||||
return .none;
|
||||
}
|
||||
_ = try ifChain(parent_block, scope, branch_list);
|
||||
fn multiIfStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
const data = node.data.switch_stmt;
|
||||
try validateIfCases(gi.astgen, data.cases);
|
||||
try ifChain(gi, scope, data.cases);
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn switchStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!Ir.Inst.Ref {
|
||||
const astgen = parent_block.astgen;
|
||||
fn switchStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
const astgen = gi.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const switch_stmt = stmt_node.data.switch_stmt;
|
||||
const data = node.data.switch_stmt;
|
||||
const cases = data.cases;
|
||||
var seen_else = false;
|
||||
|
||||
try validateSwitchProngs(parent_block, stmt_node);
|
||||
assert(cases.len > 0);
|
||||
|
||||
for (cases, 0..) |case_node, i| {
|
||||
const is_last = i == cases.len - 1;
|
||||
switch (case_node.tag) {
|
||||
.switch_case => {
|
||||
if (seen_else)
|
||||
return fail(astgen, case_node, "case after else is unreachable", .{});
|
||||
},
|
||||
.else_branch => {
|
||||
if (!is_last)
|
||||
return fail(astgen, case_node, "'else' case should always be the final case in conditional", .{});
|
||||
if (seen_else)
|
||||
return fail(astgen, case_node, "duplicate else branch", .{});
|
||||
seen_else = true;
|
||||
},
|
||||
else => return fail(astgen, case_node, "unexpected node in switch prong list", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
const cond_inst = try expr(gi, scope, data.condition_expr);
|
||||
const switch_br = try gi.makePayloadNode(.switch_br);
|
||||
|
||||
const cond_inst = try expr(parent_block, scope, switch_stmt.condition_expr);
|
||||
const switch_br = try parent_block.makePayloadNode(.switch_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
||||
try case_indexes.ensureUnusedCapacity(gpa, cases.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
||||
// TODO: Length checks.
|
||||
const switch_cases = switch_stmt.cases[0 .. switch_stmt.cases.len - 1];
|
||||
const switch_cases = if (seen_else) cases[0 .. cases.len - 1] else cases;
|
||||
for (switch_cases) |case_stmt| {
|
||||
// TODO: Maybe make this non-nullable
|
||||
const case_expr = case_stmt.data.bin.lhs.?;
|
||||
assert(case_stmt.tag == .switch_case);
|
||||
const case_data = case_stmt.data.bin;
|
||||
const case_expr = case_data.lhs.?;
|
||||
const operand: Ir.Inst.Ref = switch (case_expr.tag) {
|
||||
.number_literal => try numberLiteral(parent_block, case_expr),
|
||||
.number_literal => try numberLiteral(gi, case_expr),
|
||||
.true_literal => .bool_true,
|
||||
.false_literal => .bool_false,
|
||||
else => return fail(astgen, case_expr, "invalid switch case", .{}),
|
||||
else => return fail(astgen, case_expr, "invalid switch case operand", .{}),
|
||||
};
|
||||
var case_block = parent_block.makeSubBlock();
|
||||
|
||||
var case_block = gi.makeSubBlock();
|
||||
defer case_block.unstack();
|
||||
_ = try blockStmt(&case_block, scope, case_stmt.data.bin.rhs.?);
|
||||
_ = try case_block.addBreak(.@"break", case_stmt, switch_br);
|
||||
|
||||
_ = try blockStmt(&case_block, scope, case_data.rhs.?);
|
||||
if (!case_block.endsWithNoReturn()) {
|
||||
_ = try case_block.addBreak(.@"break", case_stmt, switch_br);
|
||||
}
|
||||
|
||||
const body = case_block.instructionsSlice();
|
||||
const case_extra_len = @typeInfo(Ir.Inst.SwitchBr.Case).@"struct".fields.len + body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, case_extra_len);
|
||||
|
||||
const extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.SwitchBr.Case{
|
||||
.operand = operand,
|
||||
.body_len = @intCast(body.len),
|
||||
},
|
||||
);
|
||||
const extra_index = astgen.addExtraAssumeCapacity(Ir.Inst.SwitchBr.Case{
|
||||
.operand = operand,
|
||||
.body_len = @intCast(body.len),
|
||||
});
|
||||
astgen.appendBlockBody(body);
|
||||
case_indexes.appendAssumeCapacity(extra_index);
|
||||
}
|
||||
|
||||
try parent_block.instructions.append(gpa, switch_br);
|
||||
try gi.instructions.append(gpa, switch_br);
|
||||
|
||||
const else_branch = switch_stmt.cases[switch_stmt.cases.len - 1];
|
||||
var case_block = parent_block.makeSubBlock();
|
||||
defer case_block.unstack();
|
||||
_ = try blockStmt(&case_block, scope, else_branch.data.bin.rhs.?);
|
||||
_ = try case_block.addBreak(.@"break", else_branch, switch_br);
|
||||
var else_block = gi.makeSubBlock();
|
||||
defer else_block.unstack();
|
||||
|
||||
const else_body = case_block.instructionsSlice();
|
||||
if (seen_else) {
|
||||
const else_branch = cases[cases.len - 1];
|
||||
assert(else_branch.tag == .else_branch);
|
||||
const else_data = else_branch.data.bin;
|
||||
_ = try blockStmt(&else_block, scope, else_data.rhs.?);
|
||||
if (!else_block.endsWithNoReturn()) {
|
||||
_ = try else_block.addBreak(.@"break", else_branch, switch_br);
|
||||
}
|
||||
} else {
|
||||
_ = try else_block.addBreak(.@"break", node, switch_br);
|
||||
}
|
||||
|
||||
const else_body = else_block.instructionsSlice();
|
||||
const extra_len =
|
||||
@typeInfo(Ir.Inst.SwitchBr).@"struct".fields.len + case_indexes.items.len + else_body.len;
|
||||
@typeInfo(Ir.Inst.SwitchBr).@"struct".fields.len +
|
||||
case_indexes.items.len +
|
||||
else_body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
|
||||
astgen.instructions.items[@intFromEnum(switch_br)].data.payload = .{
|
||||
.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.SwitchBr{
|
||||
.operand = cond_inst,
|
||||
.cases_len = @intCast(switch_cases.len),
|
||||
.else_body_len = @intCast(else_body.len),
|
||||
},
|
||||
),
|
||||
.src_offset = @intCast(stmt_node.loc.start),
|
||||
.extra_index = astgen.addExtraAssumeCapacity(Ir.Inst.SwitchBr{
|
||||
.operand = cond_inst,
|
||||
.cases_len = @intCast(switch_cases.len),
|
||||
.else_body_len = @intCast(else_body.len),
|
||||
}),
|
||||
.src_offset = @intCast(node.loc.start),
|
||||
};
|
||||
astgen.extra.appendSliceAssumeCapacity(case_indexes.items[0..]);
|
||||
astgen.extra.appendSliceAssumeCapacity(case_indexes.items);
|
||||
astgen.appendBlockBody(else_body);
|
||||
return switch_br.toRef();
|
||||
}
|
||||
|
||||
fn contentExpr(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
// FIXME: This is a placeholder until we figure out what this function should be returning.
|
||||
// TODO: Make sure that this is not nullable.
|
||||
const data = node.data.list;
|
||||
for (data.items) |child_node| {
|
||||
switch (child_node.tag) {
|
||||
|
|
@ -1013,6 +1069,7 @@ fn contentExpr(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!I
|
|||
.if_stmt => _ = try ifStmt(block, scope, child_node),
|
||||
.multi_if_stmt => _ = try multiIfStmt(block, scope, child_node),
|
||||
.switch_stmt => _ = try switchStmt(block, scope, child_node),
|
||||
.inline_if_stmt => _ = try inlineIfStmt(block, scope, child_node),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
|
@ -1031,7 +1088,6 @@ fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
|||
const expr_node = node.data.bin.rhs.?;
|
||||
const name_str = try astgen.strFromNode(identifier_node);
|
||||
|
||||
// TODO: Support globals as well
|
||||
if (scope.lookup(name_str.index)) |decl| {
|
||||
const expr_result = try expr(gi, scope, expr_node);
|
||||
_ = try gi.addBinaryNode(.store, decl.inst_index.toRef(), expr_result);
|
||||
|
|
@ -1356,13 +1412,9 @@ fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
|||
inline else => |e| @panic("Unexpected node: " ++ @tagName(e)),
|
||||
};
|
||||
}
|
||||
if (!gi.endsWithNoReturn()) {
|
||||
_ = try gi.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
}
|
||||
|
||||
fn blockStmt(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
// TODO: Make sure that this value is concrete to omit check.
|
||||
const data = node.data.list;
|
||||
try blockInner(block, scope, data.items);
|
||||
}
|
||||
|
|
@ -1383,6 +1435,9 @@ fn defaultBlock(
|
|||
|
||||
const knot_inst = try decl_scope.makePayloadNode(.decl_knot);
|
||||
try blockInner(&decl_scope, scope, data.items);
|
||||
if (!decl_scope.endsWithNoReturn()) {
|
||||
_ = try decl_scope.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
var stub_scope = decl_scope.makeSubBlock();
|
||||
defer stub_scope.unstack();
|
||||
|
|
@ -1437,6 +1492,9 @@ fn stitchDeclInner(
|
|||
} else {
|
||||
try blockInner(&decl_block, scope, &.{});
|
||||
}
|
||||
if (!decl_block.endsWithNoReturn()) {
|
||||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
const decl_str = try astgen.strFromNode(identifier_node);
|
||||
try setDeclStitchPayload(stitch_inst, &decl_block);
|
||||
|
|
@ -1494,7 +1552,8 @@ fn functionDeclInner(
|
|||
}
|
||||
if (body_node) |body| {
|
||||
try blockStmt(&decl_block, scope, body);
|
||||
} else {
|
||||
}
|
||||
if (!decl_block.endsWithNoReturn()) {
|
||||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
|
|
@ -1591,7 +1650,6 @@ fn file(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
|||
var file_scope = gi.makeSubBlock();
|
||||
defer file_scope.unstack();
|
||||
|
||||
// TODO: Make sure this is non-nullable.
|
||||
if (data.items.len > 0) {
|
||||
const first_child = data.items[0];
|
||||
if (first_child.tag == .block_stmt) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue