Skip to content

Commit

Permalink
compiler: split Decl into Nav and Cau
Browse files Browse the repository at this point in the history
The type `Zcu.Decl` in the compiler is problematic: over time it has
gained many responsibilities. Every source declaration, container type,
generic instantiation, and `@extern` has a `Decl`. The functions of
these `Decl`s are in some cases entirely disjoint.

After careful analysis, I determined that the two main responsibilities
of `Decl` are as follows:
* A `Decl` acts as the "subject" of semantic analysis at comptime. A
  single unit of analysis is either a runtime function body, or a
  `Decl`. It registers incremental dependencies, tracks analysis errors,
  etc.
* A `Decl` acts as a "global variable": a pointer to it is consistent,
  and it may be lowered to a specific symbol by the codegen backend.

This commit eliminates `Decl` and introduces new types to model these
responsibilities: `Cau` (Comptime Analysis Unit) and `Nav` (Named
Addressable Value).

Every source declaration, and every container type requiring resolution
(so *not* including `opaque`), has a `Cau`. For a source declaration,
this `Cau` performs the resolution of its value. (When ziglang#131 is
implemented, it is unsolved whether type and value resolution will share
a `Cau` or have two distinct `Cau`s.) For a type, this `Cau` is the
context in which type resolution occurs.

Every non-`comptime` source declaration, every generic instantiation,
and every distinct `extern` has a `Nav`. These are sent to codegen/link:
the backends by definition do not care about `Cau`s.

This commit has some minor technically-breaking changes surrounding
`usingnamespace`. I don't think they'll impact anyone, since the changes
are fixes around semantics which were previously inconsistent (the
behavior changed depending on hashmap iteration order!).

Aside from that, this changeset has no significant user-facing changes.
Instead, it is an internal refactor which makes it easier to correctly
model the responsibilities of different objects, particularly regarding
incremental compilation. The performance impact should be negligible,
but I will take measurements before merging this work into `master`.

Co-authored-by: Jacob Young <[email protected]>
Co-authored-by: Jakub Konka <[email protected]>
  • Loading branch information
3 people committed Aug 11, 2024
1 parent 531cd17 commit 548a087
Show file tree
Hide file tree
Showing 49 changed files with 6,380 additions and 7,164 deletions.
227 changes: 76 additions & 151 deletions src/Compilation.zig

Large diffs are not rendered by default.

1,380 changes: 921 additions & 459 deletions src/InternPool.zig

Large diffs are not rendered by default.

2,070 changes: 1,014 additions & 1,056 deletions src/Sema.zig

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Sema/bitcast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ const UnpackValueBits = struct {
.error_set_type,
.inferred_error_set_type,
.variable,
.extern_func,
.@"extern",
.func,
.err,
.error_union,
Expand Down
24 changes: 16 additions & 8 deletions src/Sema/comptime_ptr_access.zig
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,23 @@ fn loadComptimePtrInner(
};

const base_val: MutableValue = switch (ptr.base_addr) {
.decl => |decl_index| val: {
try sema.declareDependency(.{ .decl_val = decl_index });
try sema.ensureDeclAnalyzed(decl_index);
const decl = zcu.declPtr(decl_index);
if (decl.val.getVariable(zcu) != null) return .runtime_load;
break :val .{ .interned = decl.val.toIntern() };
.nav => |nav| val: {
try sema.declareDependency(.{ .nav_val = nav });
try sema.ensureNavResolved(src, nav);
const val = ip.getNav(nav).status.resolved.val;
switch (ip.indexToKey(val)) {
.variable => return .runtime_load,
// We let `.@"extern"` through here if it's a function.
// This allows you to alias `extern fn`s.
.@"extern" => |e| if (Type.fromInterned(e.ty).zigTypeTag(zcu) == .Fn)
break :val .{ .interned = val }
else
return .runtime_load,
else => break :val .{ .interned = val },
}
},
.comptime_alloc => |alloc_index| sema.getComptimeAlloc(alloc_index).val,
.anon_decl => |anon_decl| .{ .interned = anon_decl.val },
.uav => |uav| .{ .interned = uav.val },
.comptime_field => |val| .{ .interned = val },
.int => return .runtime_load,
.eu_payload => |base_ptr_ip| val: {
Expand Down Expand Up @@ -580,7 +588,7 @@ fn prepareComptimePtrStore(

// `base_strat` will not be an error case.
const base_strat: ComptimeStoreStrategy = switch (ptr.base_addr) {
.decl, .anon_decl, .int => return .runtime_store,
.nav, .uav, .int => return .runtime_store,
.comptime_field => return .comptime_field,
.comptime_alloc => |alloc_index| .{ .direct = .{
.alloc = alloc_index,
Expand Down
Loading

0 comments on commit 548a087

Please sign in to comment.