-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
compiler: more progress on incremental #19273
Changes from 3 commits
0096906
48af67c
7c4793f
d4ce1ec
42fedb3
7ba8641
1421d32
075c103
347196f
7c32370
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4083,26 +4083,69 @@ pub fn scanNamespace( | |
const gpa = zcu.gpa; | ||
const namespace = zcu.namespacePtr(namespace_index); | ||
|
||
var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; | ||
defer seen_decls.deinit(gpa); | ||
|
||
try zcu.comp.work_queue.ensureUnusedCapacity(decls.len); | ||
try namespace.decls.ensureTotalCapacity(gpa, decls.len); | ||
|
||
var scan_decl_iter: ScanDeclIter = .{ | ||
.zcu = zcu, | ||
.namespace_index = namespace_index, | ||
.parent_decl = parent_decl, | ||
.seen_decls = &seen_decls, | ||
.pass = .named, | ||
}; | ||
for (decls) |decl_inst| { | ||
try scanDecl(&scan_decl_iter, decl_inst); | ||
} | ||
scan_decl_iter.pass = .unnamed; | ||
for (decls) |decl_inst| { | ||
try scanDecl(&scan_decl_iter, decl_inst); | ||
} | ||
|
||
if (seen_decls.count() != namespace.decls.count()) { | ||
// Do a pass over the namespace contents and remove any decls from the last update | ||
// which were removed in this one. | ||
var i: usize = 0; | ||
while (i < namespace.decls.count()) { | ||
const decl_index = namespace.decls.keys()[i]; | ||
const decl = zcu.declPtr(decl_index); | ||
if (!seen_decls.contains(decl.name)) { | ||
// We must preserve namespace ordering for @typeInfo. | ||
namespace.decls.orderedRemoveAt(i); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't put a orderedRemove() inside a loop. That's O(N^2). I would have considered this to be a merge blocker. Looks like this is some big strides forward otherwise though. Nice! 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, apologies - I didn't think of that. This code is only hit in the incremental path, and it'll probably be changed again anyway after the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! |
||
i -= 1; | ||
} | ||
} | ||
} | ||
} | ||
|
||
const ScanDeclIter = struct { | ||
zcu: *Zcu, | ||
namespace_index: Namespace.Index, | ||
parent_decl: *Decl, | ||
seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), | ||
/// Decl scanning is run in two passes, so that we can detect when a generated | ||
/// name would clash with an explicit name and use a different one. | ||
pass: enum { named, unnamed }, | ||
usingnamespace_index: usize = 0, | ||
comptime_index: usize = 0, | ||
unnamed_test_index: usize = 0, | ||
|
||
fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString { | ||
const zcu = iter.zcu; | ||
const gpa = zcu.gpa; | ||
const ip = &zcu.intern_pool; | ||
var name = try ip.getOrPutStringFmt(gpa, fmt, args); | ||
var gop = try iter.seen_decls.getOrPut(gpa, name); | ||
var next_suffix: u32 = 0; | ||
while (gop.found_existing) { | ||
name = try ip.getOrPutStringFmt(gpa, fmt ++ "_{d}", args ++ .{next_suffix}); | ||
gop = try iter.seen_decls.getOrPut(gpa, name); | ||
next_suffix += 1; | ||
} | ||
return name; | ||
} | ||
}; | ||
|
||
fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void { | ||
|
@@ -4126,49 +4169,63 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void | |
// Every Decl needs a name. | ||
const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) { | ||
.@"comptime" => info: { | ||
if (iter.pass != .unnamed) return; | ||
const i = iter.comptime_index; | ||
iter.comptime_index += 1; | ||
break :info .{ | ||
try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}), | ||
try iter.avoidNameConflict("comptime_{d}", .{i}), | ||
.@"comptime", | ||
false, | ||
}; | ||
}, | ||
.@"usingnamespace" => info: { | ||
if (iter.pass != .unnamed) return; | ||
const i = iter.usingnamespace_index; | ||
iter.usingnamespace_index += 1; | ||
break :info .{ | ||
try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}), | ||
try iter.avoidNameConflict("usingnamespace_{d}", .{i}), | ||
.@"usingnamespace", | ||
false, | ||
}; | ||
}, | ||
.unnamed_test => info: { | ||
if (iter.pass != .unnamed) return; | ||
const i = iter.unnamed_test_index; | ||
iter.unnamed_test_index += 1; | ||
break :info .{ | ||
try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}), | ||
try iter.avoidNameConflict("test_{d}", .{i}), | ||
.@"test", | ||
false, | ||
}; | ||
}, | ||
.decltest => info: { | ||
// We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary. | ||
if (iter.pass != .unnamed) return; | ||
assert(declaration.flags.has_doc_comment); | ||
const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end])); | ||
break :info .{ | ||
try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}), | ||
try iter.avoidNameConflict("decltest.{s}", .{name}), | ||
.@"test", | ||
true, | ||
}; | ||
}, | ||
_ => if (declaration.name.isNamedTest(zir)) .{ | ||
try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}), | ||
.@"test", | ||
true, | ||
} else .{ | ||
try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)), | ||
.named, | ||
false, | ||
_ => if (declaration.name.isNamedTest(zir)) info: { | ||
// We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary. | ||
if (iter.pass != .unnamed) return; | ||
break :info .{ | ||
try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}), | ||
.@"test", | ||
true, | ||
}; | ||
} else info: { | ||
if (iter.pass != .named) return; | ||
const name = try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)); | ||
try iter.seen_decls.putNoClobber(gpa, name, {}); | ||
break :info .{ | ||
name, | ||
.named, | ||
false, | ||
}; | ||
}, | ||
}; | ||
|
||
|
@@ -4226,24 +4283,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void | |
} | ||
const decl_index = gop.key_ptr.*; | ||
const decl = zcu.declPtr(decl_index); | ||
if (kind == .@"test") { | ||
const src_loc = SrcLoc{ | ||
.file_scope = decl.getFileScope(zcu), | ||
.parent_decl_node = decl.src_node, | ||
.lazy = .{ .token_offset = 1 }, | ||
}; | ||
const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{ | ||
decl_name.fmt(ip), | ||
}); | ||
errdefer msg.destroy(gpa); | ||
try zcu.failed_decls.putNoClobber(gpa, decl_index, msg); | ||
const other_src_loc = SrcLoc{ | ||
.file_scope = namespace.file_scope, | ||
.parent_decl_node = decl_node, | ||
.lazy = .{ .token_offset = 1 }, | ||
}; | ||
try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{}); | ||
} | ||
// Update the AST node of the decl; even if its contents are unchanged, it may | ||
// have been re-ordered. | ||
decl.src_node = decl_node; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
comptime { | ||
@compileError("should be reached"); | ||
} | ||
const comptime_0 = {}; | ||
|
||
// error | ||
// | ||
// :2:5: error: should be reached |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing
i += 1
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4294 should make it unnecessary but 4295 would immediately crash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, you're totally right, good spot! Luckily this doesn't affect code built without incremental, and this is going to be changed a lot again soon anyway, but thank you for pointing out the issue.