Skip to content

Commit

Permalink
stage2: implement error notes and regress -femit-zir
Browse files Browse the repository at this point in the history
 * Implement error notes
   - note: other symbol exported here
   - note: previous else prong is here
   - note: previous '_' prong is here
 * Add Compilation.CObject.ErrorMsg. This object properly converts to
   AllErrors.Message when the time comes.
 * Add Compilation.CObject.failure_retryable. Properly handles
   out-of-memory and other transient failures.
 * Introduce Module.SrcLoc which has not only a byte offset but also
   references the file which the byte offset applies to.
 * Scope.Block now contains both a pointer to the "owner" Decl and the
   "source" Decl. As an example, during inline function call, the
   "owner" will be the Decl of the caller and the "source" will be the
   Decl of the callee.
 * Module.ErrorMsg now sports a `file_scope` field so that notes can
   refer to source locations in a file other than the parent error
   message.
 * Some instances where a `*Scope` was stored, now store a
   `*Scope.Container`.
 * Some methods in the `Scope` namespace were moved to the more specific
   type, since there was only an implementation for one particular tag.
   - `removeDecl` moved to `Scope.Container`
   - `destroy` moved to `Scope.File`
 * Two kinds of Scope deleted:
   - zir_module
   - decl
 * astgen: properly use DeclVal / DeclRef. DeclVal was incorrectly
   changed to be a reference; this commit fixes it. Fewer ZIR
   instructions processed as a result.
   - declval_in_module is renamed to declval
   - previous declval ZIR instruction is deleted; it was only for .zir
     files.
 * Test harness: friendlier diagnostics when an unexpected set of errors
   is encountered.
 * zir_sema: fix analyzeInstBlockFlat by properly calling resolvingInst
   on the last zir instruction in the block.

Compile log implementation:
 * Write to a buffer rather than directly to stderr.
 * Only keep track of 1 callsite per Decl.
 * No longer mutate the ZIR Inst struct data.
 * "Compile log statement found" errors are only emitted when there are
   no other compile errors.

-femit-zir and support for .zir source files is regressed. If we wanted
to support this again, outputting .zir would need to be done as yet
another backend rather than in the haphazard way it was previously
implemented.

For parsing .zir, it was implemented previously in a way that was not
helpful for debugging. We need tighter integration with the test harness
for it to be useful; so clearly a rewrite is needed. Given that a
rewrite is needed, and it was getting in the way of progress and
organization of the rest of stage2, I regressed the feature.
  • Loading branch information
andrewrk committed Jan 17, 2021
1 parent 8436134 commit 8c9ac4d
Show file tree
Hide file tree
Showing 18 changed files with 904 additions and 2,618 deletions.
305 changes: 179 additions & 126 deletions src/Compilation.zig

Large diffs are not rendered by default.

764 changes: 281 additions & 483 deletions src/Module.zig

Large diffs are not rendered by default.

77 changes: 56 additions & 21 deletions src/astgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as
// Make a scope to collect generated instructions in the sub-expression.
var block_scope: Scope.GenZIR = .{
.parent = parent_scope,
.decl = parent_scope.decl().?,
.decl = parent_scope.ownerDecl().?,
.arena = parent_scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -474,7 +474,7 @@ fn labeledBlockExpr(

var block_scope: Scope.GenZIR = .{
.parent = parent_scope,
.decl = parent_scope.decl().?,
.decl = parent_scope.ownerDecl().?,
.arena = gen_zir.arena,
.instructions = .{},
.break_result_loc = rl,
Expand Down Expand Up @@ -899,7 +899,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con

var gen_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1028,7 +1028,13 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
.ty = Type.initTag(.type),
.val = val,
});
return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));
if (rl == .ref) {
return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{});
} else {
return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{
.decl = decl,
}, .{}));
}
}

fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
Expand Down Expand Up @@ -1084,7 +1090,7 @@ fn orelseCatchExpr(

var block_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1266,7 +1272,7 @@ fn boolBinOp(

var block_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1412,7 +1418,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
}
var block_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1513,7 +1519,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W

var expr_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1649,7 +1655,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)

var for_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1843,7 +1849,7 @@ fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst {
var block_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1885,7 +1891,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node

var item_scope: Scope.GenZIR = .{
.parent = scope,
.decl = scope.decl().?,
.decl = scope.ownerDecl().?,
.arena = scope.arena(),
.instructions = .{},
};
Expand Down Expand Up @@ -1922,8 +1928,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
// Check for else/_ prong, those are handled last.
if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
if (else_src) |src| {
return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});
// TODO notes "previous else prong is here"
const msg = try mod.errMsg(
scope,
case_src,
"multiple else prongs in switch expression",
.{},
);
errdefer msg.destroy(mod.gpa);
try mod.errNote(scope, src, msg, "previous else prong is here", .{});
return mod.failWithOwnedErrorMsg(scope, msg);
}
else_src = case_src;
special_case = case;
Expand All @@ -1932,8 +1945,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
{
if (underscore_src) |src| {
return mod.fail(scope, case_src, "multiple '_' prongs in switch expression", .{});
// TODO notes "previous '_' prong is here"
const msg = try mod.errMsg(
scope,
case_src,
"multiple '_' prongs in switch expression",
.{},
);
errdefer msg.destroy(mod.gpa);
try mod.errNote(scope, src, msg, "previous '_' prong is here", .{});
return mod.failWithOwnedErrorMsg(scope, msg);
}
underscore_src = case_src;
special_case = case;
Expand All @@ -1942,9 +1962,16 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node

if (else_src) |some_else| {
if (underscore_src) |some_underscore| {
return mod.fail(scope, switch_src, "else and '_' prong in switch expression", .{});
// TODO notes "else prong is here"
// TODO notes "'_' prong is here"
const msg = try mod.errMsg(
scope,
switch_src,
"else and '_' prong in switch expression",
.{},
);
errdefer msg.destroy(mod.gpa);
try mod.errNote(scope, some_else, msg, "else prong is here", .{});
try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{});
return mod.failWithOwnedErrorMsg(scope, msg);
}
}

Expand Down Expand Up @@ -2162,7 +2189,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
}

if (mod.lookupDeclName(scope, ident_name)) |decl| {
return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));
if (rl == .ref) {
return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{});
} else {
return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{
.decl = decl,
}, .{}));
}
}

return mod.failNode(scope, &ident.base, "use of undeclared identifier '{s}'", .{ident_name});
Expand Down Expand Up @@ -2927,6 +2960,8 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul
return rlWrap(mod, scope, rl, void_inst);
}

/// TODO go over all the callsites and see where we can introduce "by-value" ZIR instructions
/// to save ZIR memory. For example, see DeclVal vs DeclRef.
fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst {
if (rl == .ref) return ptr;

Expand Down Expand Up @@ -3032,7 +3067,7 @@ pub fn addZIRInstBlock(
scope: *Scope,
src: usize,
tag: zir.Inst.Tag,
body: zir.Module.Body,
body: zir.Body,
) !*zir.Inst.Block {
const gen_zir = scope.getGenZIR();
try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
Expand Down Expand Up @@ -3070,7 +3105,7 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ
}

/// TODO The existence of this function is a workaround for a bug in stage1.
pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop {
pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Body) !*zir.Inst.Loop {
const P = std.meta.fieldInfo(zir.Inst.Loop, .positionals).field_type;
return addZIRInstSpecial(mod, scope, src, zir.Inst.Loop, P{ .body = body }, .{});
}
Loading

0 comments on commit 8c9ac4d

Please sign in to comment.