mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
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 #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 <jacobly0@users.noreply.github.com> Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
117 lines
2.9 KiB
Zig
117 lines
2.9 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const expect = std.testing.expect;
|
|
|
|
const A = struct {
|
|
pub const B = bool;
|
|
};
|
|
|
|
const C = struct {
|
|
usingnamespace A;
|
|
};
|
|
|
|
test "basic usingnamespace" {
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
try std.testing.expect(C.B == bool);
|
|
}
|
|
|
|
fn Foo(comptime T: type) type {
|
|
return struct {
|
|
usingnamespace T;
|
|
};
|
|
}
|
|
|
|
test "usingnamespace inside a generic struct" {
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
const std2 = Foo(std);
|
|
const testing2 = Foo(std.testing);
|
|
try std2.testing.expect(true);
|
|
try testing2.expect(true);
|
|
}
|
|
|
|
usingnamespace struct {
|
|
pub const foo = 42;
|
|
};
|
|
|
|
test "usingnamespace does not redeclare an imported variable" {
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
try comptime std.testing.expect(@This().foo == 42);
|
|
}
|
|
|
|
usingnamespace @import("usingnamespace/foo.zig");
|
|
test "usingnamespace omits mixing in private functions" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
try expect(@This().privateFunction());
|
|
try expect(!@This().printText());
|
|
}
|
|
fn privateFunction() bool {
|
|
return true;
|
|
}
|
|
|
|
test {
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
_ = @import("usingnamespace/import_segregation.zig");
|
|
}
|
|
|
|
usingnamespace @import("usingnamespace/a.zig");
|
|
test "two files usingnamespace import each other" {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
try expect(@This().ok());
|
|
}
|
|
|
|
test {
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
const AA = struct {
|
|
x: i32,
|
|
fn b(x: i32) @This() {
|
|
return .{ .x = x };
|
|
}
|
|
fn c() type {
|
|
return if (true) struct {
|
|
const expected: i32 = 42;
|
|
} else struct {};
|
|
}
|
|
usingnamespace c();
|
|
};
|
|
const a = AA.b(42);
|
|
try expect(a.x == AA.c().expected);
|
|
}
|
|
|
|
const Bar = struct {
|
|
usingnamespace Mixin;
|
|
};
|
|
|
|
const Mixin = struct {
|
|
pub fn two(self: Bar) void {
|
|
_ = self;
|
|
}
|
|
};
|
|
|
|
test "container member access usingnamespace decls" {
|
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
|
|
var foo = Bar{};
|
|
foo.two();
|
|
}
|
|
|
|
usingnamespace opaque {};
|
|
|
|
usingnamespace @Type(.{ .Struct = .{
|
|
.layout = .auto,
|
|
.fields = &.{},
|
|
.decls = &.{},
|
|
.is_tuple = false,
|
|
} });
|