mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 15:19:07 +00:00
Module: mark function body dependencies, don't re-analyze anonymous decls
This commit is contained in:
parent
d5f1a8823e
commit
fac120bc3a
2 changed files with 92 additions and 52 deletions
140
src/Module.zig
140
src/Module.zig
|
|
@ -564,7 +564,23 @@ pub const Decl = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, void);
|
pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);
|
||||||
|
|
||||||
|
/// Later types take priority; e.g. if a dependent decl has both `normal`
|
||||||
|
/// and `function_body` dependencies on another decl, it will be marked as
|
||||||
|
/// having a `function_body` dependency.
|
||||||
|
pub const DepType = enum {
|
||||||
|
/// The dependent references or uses the dependency's value, so must be
|
||||||
|
/// updated whenever it is changed. However, if the dependency is a
|
||||||
|
/// function and its type is unchanged, the dependent does not need to
|
||||||
|
/// be updated.
|
||||||
|
normal,
|
||||||
|
/// The dependent performs an inline or comptime call to the dependency,
|
||||||
|
/// or is a generic instantiation of it. It must therefore be updated
|
||||||
|
/// whenever the dependency is updated, even if the function type
|
||||||
|
/// remained the same.
|
||||||
|
function_body,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn clearName(decl: *Decl, gpa: Allocator) void {
|
pub fn clearName(decl: *Decl, gpa: Allocator) void {
|
||||||
gpa.free(mem.sliceTo(decl.name, 0));
|
gpa.free(mem.sliceTo(decl.name, 0));
|
||||||
|
|
@ -4155,53 +4171,63 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
|
||||||
decl_prog_node.activate();
|
decl_prog_node.activate();
|
||||||
defer decl_prog_node.end();
|
defer decl_prog_node.end();
|
||||||
|
|
||||||
const type_changed = mod.semaDecl(decl_index) catch |err| switch (err) {
|
const type_changed = blk: {
|
||||||
error.AnalysisFail => {
|
if (decl.zir_decl_index == 0 and !mod.declIsRoot(decl_index)) {
|
||||||
if (decl.analysis == .in_progress) {
|
// Anonymous decl. We don't semantically analyze these.
|
||||||
// If this decl caused the compile error, the analysis field would
|
break :blk false; // tv unchanged
|
||||||
// be changed to indicate it was this Decl's fault. Because this
|
}
|
||||||
// did not happen, we infer here that it was a dependency failure.
|
|
||||||
decl.analysis = .dependency_failure;
|
break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
|
||||||
}
|
error.AnalysisFail => {
|
||||||
return error.AnalysisFail;
|
if (decl.analysis == .in_progress) {
|
||||||
},
|
// If this decl caused the compile error, the analysis field would
|
||||||
error.NeededSourceLocation => unreachable,
|
// be changed to indicate it was this Decl's fault. Because this
|
||||||
error.GenericPoison => unreachable,
|
// did not happen, we infer here that it was a dependency failure.
|
||||||
else => |e| {
|
decl.analysis = .dependency_failure;
|
||||||
decl.analysis = .sema_failure_retryable;
|
}
|
||||||
try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
|
return error.AnalysisFail;
|
||||||
mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
|
},
|
||||||
mod.gpa,
|
error.NeededSourceLocation => unreachable,
|
||||||
decl.srcLoc(),
|
error.GenericPoison => unreachable,
|
||||||
"unable to analyze: {s}",
|
else => |e| {
|
||||||
.{@errorName(e)},
|
decl.analysis = .sema_failure_retryable;
|
||||||
));
|
try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
|
||||||
return error.AnalysisFail;
|
mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
|
||||||
},
|
mod.gpa,
|
||||||
|
decl.srcLoc(),
|
||||||
|
"unable to analyze: {s}",
|
||||||
|
.{@errorName(e)},
|
||||||
|
));
|
||||||
|
return error.AnalysisFail;
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if (subsequent_analysis) {
|
if (subsequent_analysis) {
|
||||||
// We may need to chase the dependants and re-analyze them.
|
// Update all dependents which have at least this level of dependency.
|
||||||
// However, if the decl is a function, and the type is the same, we do not need to.
|
// If our type remained the same and we're a function, only update
|
||||||
if (type_changed or decl.ty.zigTypeTag() != .Fn) {
|
// decls which depend on our body; otherwise, update all dependents.
|
||||||
for (decl.dependants.keys()) |dep_index| {
|
const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag() == .Fn) .function_body else .normal;
|
||||||
const dep = mod.declPtr(dep_index);
|
|
||||||
switch (dep.analysis) {
|
|
||||||
.unreferenced => unreachable,
|
|
||||||
.in_progress => continue, // already doing analysis, ok
|
|
||||||
.outdated => continue, // already queued for update
|
|
||||||
|
|
||||||
.file_failure,
|
for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| {
|
||||||
.dependency_failure,
|
if (@enumToInt(dep_type) < @enumToInt(update_level)) continue;
|
||||||
.sema_failure,
|
|
||||||
.sema_failure_retryable,
|
const dep = mod.declPtr(dep_index);
|
||||||
.codegen_failure,
|
switch (dep.analysis) {
|
||||||
.codegen_failure_retryable,
|
.unreferenced => unreachable,
|
||||||
.complete,
|
.in_progress => continue, // already doing analysis, ok
|
||||||
=> if (dep.generation != mod.generation) {
|
.outdated => continue, // already queued for update
|
||||||
try mod.markOutdatedDecl(dep_index);
|
|
||||||
},
|
.file_failure,
|
||||||
}
|
.dependency_failure,
|
||||||
|
.sema_failure,
|
||||||
|
.sema_failure_retryable,
|
||||||
|
.codegen_failure,
|
||||||
|
.codegen_failure_retryable,
|
||||||
|
.complete,
|
||||||
|
=> if (dep.generation != mod.generation) {
|
||||||
|
try mod.markOutdatedDecl(dep_index);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4742,25 +4768,37 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||||
|
|
||||||
/// Returns the depender's index of the dependee.
|
/// Returns the depender's index of the dependee.
|
||||||
pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void {
|
pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void {
|
||||||
|
return mod.declareDeclDependencyType(depender_index, dependee_index, .normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the depender's index of the dependee.
|
||||||
|
pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index, dep_type: Decl.DepType) !void {
|
||||||
if (depender_index == dependee_index) return;
|
if (depender_index == dependee_index) return;
|
||||||
|
|
||||||
const depender = mod.declPtr(depender_index);
|
const depender = mod.declPtr(depender_index);
|
||||||
const dependee = mod.declPtr(dependee_index);
|
const dependee = mod.declPtr(dependee_index);
|
||||||
|
|
||||||
|
if (depender.dependencies.get(dependee_index)) |cur_type| {
|
||||||
|
if (@enumToInt(cur_type) >= @enumToInt(dep_type)) {
|
||||||
|
// We already have this dependency (or stricter) marked
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("{*} ({s}) depends on {*} ({s})", .{
|
log.debug("{*} ({s}) depends on {*} ({s})", .{
|
||||||
depender, depender.name, dependee, dependee.name,
|
depender, depender.name, dependee, dependee.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1);
|
|
||||||
try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1);
|
|
||||||
|
|
||||||
if (dependee.deletion_flag) {
|
if (dependee.deletion_flag) {
|
||||||
dependee.deletion_flag = false;
|
dependee.deletion_flag = false;
|
||||||
assert(mod.deletion_set.swapRemove(dependee_index));
|
assert(mod.deletion_set.swapRemove(dependee_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
dependee.dependants.putAssumeCapacity(depender_index, {});
|
try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1);
|
||||||
depender.dependencies.putAssumeCapacity(dependee_index, {});
|
try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1);
|
||||||
|
|
||||||
|
dependee.dependants.putAssumeCapacity(depender_index, dep_type);
|
||||||
|
depender.dependencies.putAssumeCapacity(dependee_index, dep_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ImportFileResult = struct {
|
pub const ImportFileResult = struct {
|
||||||
|
|
@ -6342,8 +6380,8 @@ pub fn populateTestFunctions(
|
||||||
try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena);
|
try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena);
|
||||||
break :n test_name_decl_index;
|
break :n test_name_decl_index;
|
||||||
};
|
};
|
||||||
array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, {});
|
array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal);
|
||||||
array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, {});
|
array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal);
|
||||||
try mod.linkerUpdateDecl(test_name_decl_index);
|
try mod.linkerUpdateDecl(test_name_decl_index);
|
||||||
|
|
||||||
const field_vals = try arena.create([3]Value);
|
const field_vals = try arena.create([3]Value);
|
||||||
|
|
|
||||||
|
|
@ -6635,6 +6635,8 @@ fn analyzeCall(
|
||||||
sema.code = fn_owner_decl.getFileScope().zir;
|
sema.code = fn_owner_decl.getFileScope().zir;
|
||||||
defer sema.code = parent_zir;
|
defer sema.code = parent_zir;
|
||||||
|
|
||||||
|
try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body);
|
||||||
|
|
||||||
const parent_inst_map = sema.inst_map;
|
const parent_inst_map = sema.inst_map;
|
||||||
sema.inst_map = .{};
|
sema.inst_map = .{};
|
||||||
defer {
|
defer {
|
||||||
|
|
@ -7331,7 +7333,7 @@ fn instantiateGenericCall(
|
||||||
// The generic function Decl is guaranteed to be the first dependency
|
// The generic function Decl is guaranteed to be the first dependency
|
||||||
// of each of its instantiations.
|
// of each of its instantiations.
|
||||||
assert(new_decl.dependencies.keys().len == 0);
|
assert(new_decl.dependencies.keys().len == 0);
|
||||||
try mod.declareDeclDependency(new_decl_index, module_fn.owner_decl);
|
try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body);
|
||||||
|
|
||||||
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
|
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
|
||||||
const new_decl_arena_allocator = new_decl_arena.allocator();
|
const new_decl_arena_allocator = new_decl_arena.allocator();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue