aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2024-03-05 07:22:47 +0000
committermlugg <mlugg@mlugg.co.uk>2024-03-06 21:26:38 +0000
commit2c4ac44f25743f5b7ae9db6bc570ab71f15fd83b (patch)
tree5936a2c47c13ea1fcd5bd37ce523754517be38cf /src/Sema.zig
parentd0c022f7347b5cda34751a986a535aee3b1f45dc (diff)
downloadzig-2c4ac44f25743f5b7ae9db6bc570ab71f15fd83b.tar.gz
zig-2c4ac44f25743f5b7ae9db6bc570ab71f15fd83b.zip
compiler: treat decl_val/decl_ref of potentially generic decls as captures
This fixes an issue with the implementation of #18816. Consider the following code: ```zig pub fn Wrap(comptime T: type) type { return struct { pub const T1 = T; inner: struct { x: T1 }, }; } ``` Previously, the type of `inner` was not considered to be "capturing" any value, as `T1` is a decl. However, since it is declared within a generic function, this decl reference depends on the context, and thus should be treated as a capture. AstGen has been augmented to tunnel references to decls through closure when the decl was declared in a potentially-generic context (i.e. within a function).
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig32
1 files changed, 21 insertions, 11 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index d4a95027c3..dba0983739 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -2671,26 +2671,34 @@ fn analyzeAsInt(
/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
-fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
+fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
const zcu = sema.mod;
const ip = &zcu.intern_pool;
- const parent_captures: InternPool.CaptureValue.Slice = if (parent_namespace) |p| parent: {
- break :parent zcu.namespacePtr(p).ty.getCaptures(zcu);
- } else undefined; // never used so `undefined` is safe
+ const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).ty.getCaptures(zcu);
const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| {
- const zir_capture: Zir.Inst.Capture = @enumFromInt(raw);
+ const zir_capture: Zir.Inst.Capture = @bitCast(raw);
capture.* = switch (zir_capture.unwrap()) {
- .inst => |inst| InternPool.CaptureValue.wrap(capture: {
+ .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
+ .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
const air_ref = try sema.resolveInst(inst.toRef());
if (try sema.resolveValueResolveLazy(air_ref)) |val| {
break :capture .{ .@"comptime" = val.toIntern() };
}
break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
}),
- .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
+ .decl_val => |str| capture: {
+ const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
+ break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl });
+ },
+ .decl_ref => |str| capture: {
+ const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
+ break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl });
+ },
};
}
@@ -2727,7 +2735,7 @@ fn zirStructDecl(
break :blk decls_len;
} else 0;
- const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
extra_index += captures_len;
if (small.has_backing_int) {
@@ -2944,7 +2952,7 @@ fn zirEnumDecl(
break :blk decls_len;
} else 0;
- const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
extra_index += captures_len;
const decls = sema.code.bodySlice(extra_index, decls_len);
@@ -3209,7 +3217,7 @@ fn zirUnionDecl(
break :blk decls_len;
} else 0;
- const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
extra_index += captures_len;
const wip_ty = switch (try ip.getUnionType(gpa, .{
@@ -3315,7 +3323,7 @@ fn zirOpaqueDecl(
break :blk decls_len;
} else 0;
- const captures = try sema.getCaptures(block.namespace, extra_index, captures_len);
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
extra_index += captures_len;
const wip_ty = switch (try ip.getOpaqueType(gpa, .{
@@ -17268,6 +17276,8 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) {
.@"comptime" => |index| return Air.internedToRef(index),
.runtime => |index| index,
+ .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index),
+ .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index),
};
// The comptime case is handled already above. Runtime case below.