aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorMartin Wickham <spexguy070@gmail.com>2021-09-23 12:17:06 -0500
committerGitHub <noreply@github.com>2021-09-23 13:17:06 -0400
commita0a847f2e40046387e2e2b8a0b8dae9cb27ca22a (patch)
tree2fdaa3bdd0ab7d63eb54e1bd92aca1f1607cca14 /src/Sema.zig
parentf615648d7bdcb5c7ed38ad15169a8fa90bd86ca0 (diff)
downloadzig-a0a847f2e40046387e2e2b8a0b8dae9cb27ca22a.tar.gz
zig-a0a847f2e40046387e2e2b8a0b8dae9cb27ca22a.zip
Stage2: Implement comptime closures and the This builtin (#9823)
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig263
1 files changed, 196 insertions, 67 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index a0e3250e56..cc7a227ca6 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -8,8 +8,12 @@
mod: *Module,
/// Alias to `mod.gpa`.
gpa: *Allocator,
-/// Points to the arena allocator of the Decl.
+/// Points to the temporary arena allocator of the Sema.
+/// This arena will be cleared when the sema is destroyed.
arena: *Allocator,
+/// Points to the arena allocator for the owner_decl.
+/// This arena will persist until the decl is invalidated.
+perm_arena: *Allocator,
code: Zir,
air_instructions: std.MultiArrayList(Air.Inst) = .{},
air_extra: std.ArrayListUnmanaged(u32) = .{},
@@ -80,6 +84,8 @@ const Scope = Module.Scope;
const CompileError = Module.CompileError;
const SemaError = Module.SemaError;
const Decl = Module.Decl;
+const CaptureScope = Module.CaptureScope;
+const WipCaptureScope = Module.WipCaptureScope;
const LazySrcLoc = Module.LazySrcLoc;
const RangeSet = @import("RangeSet.zig");
const target_util = @import("target.zig");
@@ -129,15 +135,29 @@ pub fn analyzeBody(
) CompileError!Zir.Inst.Index {
// No tracy calls here, to avoid interfering with the tail call mechanism.
+ const parent_capture_scope = block.wip_capture_scope;
+
+ var wip_captures = WipCaptureScope{
+ .finalized = true,
+ .scope = parent_capture_scope,
+ .perm_arena = sema.perm_arena,
+ .gpa = sema.gpa,
+ };
+ defer if (wip_captures.scope != parent_capture_scope) {
+ wip_captures.deinit();
+ };
+
const map = &block.sema.inst_map;
const tags = block.sema.code.instructions.items(.tag);
const datas = block.sema.code.instructions.items(.data);
+ var orig_captures: usize = parent_capture_scope.captures.count();
+
// We use a while(true) loop here to avoid a redundant way of breaking out of
// the loop. The only way to break out of the loop is with a `noreturn`
// instruction.
var i: usize = 0;
- while (true) {
+ const result = while (true) {
const inst = body[i];
const air_inst: Air.Inst.Ref = switch (tags[inst]) {
// zig fmt: off
@@ -170,6 +190,7 @@ pub fn analyzeBody(
.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
.call_async => try sema.zirCall(block, inst, .async_kw, false),
+ .closure_get => try sema.zirClosureGet(block, inst),
.cmp_lt => try sema.zirCmp(block, inst, .lt),
.cmp_lte => try sema.zirCmp(block, inst, .lte),
.cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq),
@@ -343,9 +364,6 @@ pub fn analyzeBody(
.trunc => try sema.zirUnaryMath(block, inst),
.round => try sema.zirUnaryMath(block, inst),
- .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
- .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
- .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
@@ -362,13 +380,13 @@ pub fn analyzeBody(
// Instructions that we know to *always* be noreturn based solely on their tag.
// These functions match the return type of analyzeBody so that we can
// tail call them here.
- .compile_error => return sema.zirCompileError(block, inst),
- .ret_coerce => return sema.zirRetCoerce(block, inst),
- .ret_node => return sema.zirRetNode(block, inst),
- .ret_load => return sema.zirRetLoad(block, inst),
- .ret_err_value => return sema.zirRetErrValue(block, inst),
- .@"unreachable" => return sema.zirUnreachable(block, inst),
- .panic => return sema.zirPanic(block, inst),
+ .compile_error => break sema.zirCompileError(block, inst),
+ .ret_coerce => break sema.zirRetCoerce(block, inst),
+ .ret_node => break sema.zirRetNode(block, inst),
+ .ret_load => break sema.zirRetLoad(block, inst),
+ .ret_err_value => break sema.zirRetErrValue(block, inst),
+ .@"unreachable" => break sema.zirUnreachable(block, inst),
+ .panic => break sema.zirPanic(block, inst),
// zig fmt: on
// Instructions that we know can *never* be noreturn based solely on
@@ -503,34 +521,49 @@ pub fn analyzeBody(
i += 1;
continue;
},
+ .closure_capture => {
+ try sema.zirClosureCapture(block, inst);
+ i += 1;
+ continue;
+ },
// Special case instructions to handle comptime control flow.
.@"break" => {
if (block.is_comptime) {
- return inst; // same as break_inline
+ break inst; // same as break_inline
} else {
- return sema.zirBreak(block, inst);
+ break sema.zirBreak(block, inst);
}
},
- .break_inline => return inst,
+ .break_inline => break inst,
.repeat => {
if (block.is_comptime) {
// Send comptime control flow back to the beginning of this block.
const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
try sema.emitBackwardBranch(block, src);
+ if (wip_captures.scope.captures.count() != orig_captures) {
+ try wip_captures.reset(parent_capture_scope);
+ block.wip_capture_scope = wip_captures.scope;
+ orig_captures = 0;
+ }
i = 0;
continue;
} else {
const src_node = sema.code.instructions.items(.data)[inst].node;
const src: LazySrcLoc = .{ .node_offset = src_node };
try sema.requireRuntimeBlock(block, src);
- return always_noreturn;
+ break always_noreturn;
}
},
.repeat_inline => {
// Send comptime control flow back to the beginning of this block.
const src: LazySrcLoc = .{ .node_offset = datas[inst].node };
try sema.emitBackwardBranch(block, src);
+ if (wip_captures.scope.captures.count() != orig_captures) {
+ try wip_captures.reset(parent_capture_scope);
+ block.wip_capture_scope = wip_captures.scope;
+ orig_captures = 0;
+ }
i = 0;
continue;
},
@@ -545,7 +578,7 @@ pub fn analyzeBody(
if (inst == break_data.block_inst) {
break :blk sema.resolveInst(break_data.operand);
} else {
- return break_inst;
+ break break_inst;
}
},
.block => blk: {
@@ -559,7 +592,7 @@ pub fn analyzeBody(
if (inst == break_data.block_inst) {
break :blk sema.resolveInst(break_data.operand);
} else {
- return break_inst;
+ break break_inst;
}
},
.block_inline => blk: {
@@ -572,11 +605,11 @@ pub fn analyzeBody(
if (inst == break_data.block_inst) {
break :blk sema.resolveInst(break_data.operand);
} else {
- return break_inst;
+ break break_inst;
}
},
.condbr => blk: {
- if (!block.is_comptime) return sema.zirCondbr(block, inst);
+ if (!block.is_comptime) break sema.zirCondbr(block, inst);
// Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
const inst_data = datas[inst].pl_node;
const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
@@ -590,7 +623,7 @@ pub fn analyzeBody(
if (inst == break_data.block_inst) {
break :blk sema.resolveInst(break_data.operand);
} else {
- return break_inst;
+ break break_inst;
}
},
.condbr_inline => blk: {
@@ -606,15 +639,22 @@ pub fn analyzeBody(
if (inst == break_data.block_inst) {
break :blk sema.resolveInst(break_data.operand);
} else {
- return break_inst;
+ break break_inst;
}
},
};
if (sema.typeOf(air_inst).isNoReturn())
- return always_noreturn;
+ break always_noreturn;
try map.put(sema.gpa, inst, air_inst);
i += 1;
+ } else unreachable;
+
+ if (!wip_captures.finalized) {
+ try wip_captures.finalize();
+ block.wip_capture_scope = parent_capture_scope;
}
+
+ return result;
}
fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -626,6 +666,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
.struct_decl => return sema.zirStructDecl( block, extended, inst),
.enum_decl => return sema.zirEnumDecl( block, extended),
.union_decl => return sema.zirUnionDecl( block, extended, inst),
+ .opaque_decl => return sema.zirOpaqueDecl( block, extended, inst),
.ret_ptr => return sema.zirRetPtr( block, extended),
.ret_type => return sema.zirRetType( block, extended),
.this => return sema.zirThis( block, extended),
@@ -1011,7 +1052,6 @@ fn zirStructDecl(
}
fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {
- _ = block;
switch (name_strategy) {
.anon => {
// It would be neat to have "struct:line:column" but this name has
@@ -1020,14 +1060,14 @@ fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.Name
// semantically analyzed.
const name_index = sema.mod.getNextAnonNameIndex();
return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
- sema.owner_decl.name, name_index,
+ block.src_decl.name, name_index,
});
},
- .parent => return sema.gpa.dupeZ(u8, mem.spanZ(sema.owner_decl.name)),
+ .parent => return sema.gpa.dupeZ(u8, mem.spanZ(block.src_decl.name)),
.func => {
const name_index = sema.mod.getNextAnonNameIndex();
const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
- sema.owner_decl.name, name_index,
+ block.src_decl.name, name_index,
});
log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{
name,
@@ -1083,17 +1123,6 @@ fn zirEnumDecl(
var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
errdefer new_decl_arena.deinit();
- const tag_ty = blk: {
- if (tag_type_ref != .none) {
- // TODO better source location
- // TODO (needs AstGen fix too) move this eval to the block so it gets allocated
- // in the new decl arena.
- break :blk try sema.resolveType(block, src, tag_type_ref);
- }
- const bits = std.math.log2_int_ceil(usize, fields_len);
- break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits);
- };
-
const enum_obj = try new_decl_arena.allocator.create(Module.EnumFull);
const enum_ty_payload = try new_decl_arena.allocator.create(Type.Payload.EnumFull);
enum_ty_payload.* = .{
@@ -1112,7 +1141,7 @@ fn zirEnumDecl(
enum_obj.* = .{
.owner_decl = new_decl,
- .tag_ty = tag_ty,
+ .tag_ty = Type.initTag(.@"null"),
.fields = .{},
.values = .{},
.node_offset = src.node_offset,
@@ -1140,16 +1169,6 @@ fn zirEnumDecl(
const body_end = extra_index;
extra_index += bit_bags_count;
- try enum_obj.fields.ensureTotalCapacity(&new_decl_arena.allocator, fields_len);
- const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
- if (bag != 0) break true;
- } else false;
- if (any_values) {
- try enum_obj.values.ensureTotalCapacityContext(&new_decl_arena.allocator, fields_len, .{
- .ty = tag_ty,
- });
- }
-
{
// We create a block for the field type instructions because they
// may need to reference Decls from inside the enum namespace.
@@ -1172,10 +1191,14 @@ fn zirEnumDecl(
sema.func = null;
defer sema.func = prev_func;
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
+ defer wip_captures.deinit();
+
var enum_block: Scope.Block = .{
.parent = null,
.sema = sema,
.src_decl = new_decl,
+ .wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -1185,7 +1208,30 @@ fn zirEnumDecl(
if (body.len != 0) {
_ = try sema.analyzeBody(&enum_block, body);
}
+
+ try wip_captures.finalize();
+
+ const tag_ty = blk: {
+ if (tag_type_ref != .none) {
+ // TODO better source location
+ break :blk try sema.resolveType(block, src, tag_type_ref);
+ }
+ const bits = std.math.log2_int_ceil(usize, fields_len);
+ break :blk try Type.Tag.int_unsigned.create(&new_decl_arena.allocator, bits);
+ };
+ enum_obj.tag_ty = tag_ty;
}
+
+ try enum_obj.fields.ensureTotalCapacity(&new_decl_arena.allocator, fields_len);
+ const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
+ if (bag != 0) break true;
+ } else false;
+ if (any_values) {
+ try enum_obj.values.ensureTotalCapacityContext(&new_decl_arena.allocator, fields_len, .{
+ .ty = enum_obj.tag_ty,
+ });
+ }
+
var bit_bag_index: usize = body_end;
var cur_bit_bag: u32 = undefined;
var field_i: u32 = 0;
@@ -1224,10 +1270,10 @@ fn zirEnumDecl(
// that points to this default value expression rather than the struct.
// But only resolve the source location if we need to emit a compile error.
const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val;
- enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
+ enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = enum_obj.tag_ty });
} else if (any_values) {
const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i);
- enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
+ enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = enum_obj.tag_ty });
}
}
@@ -1305,20 +1351,14 @@ fn zirUnionDecl(
fn zirOpaqueDecl(
sema: *Sema,
block: *Scope.Block,
+ extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
- name_strategy: Zir.Inst.NameStrategy,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
-
- _ = name_strategy;
- _ = inst_data;
- _ = src;
- _ = extra;
+ _ = extended;
+ _ = inst;
return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
}
@@ -2160,6 +2200,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
.parent = parent_block,
.sema = sema,
.src_decl = parent_block.src_decl,
+ .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.inlining = parent_block.inlining,
.is_comptime = parent_block.is_comptime,
@@ -2214,7 +2255,7 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
try sema.mod.semaFile(result.file);
const file_root_decl = result.file.root_decl.?;
try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
- return sema.addType(file_root_decl.ty);
+ return sema.addConstant(file_root_decl.ty, file_root_decl.val);
}
fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -2259,6 +2300,7 @@ fn zirBlock(
.parent = parent_block,
.sema = sema,
.src_decl = parent_block.src_decl,
+ .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.label = &label,
.inlining = parent_block.inlining,
@@ -2866,10 +2908,14 @@ fn analyzeCall(
sema.func = module_fn;
defer sema.func = parent_func;
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, module_fn.owner_decl.src_scope);
+ defer wip_captures.deinit();
+
var child_block: Scope.Block = .{
.parent = null,
.sema = sema,
.src_decl = module_fn.owner_decl,
+ .wip_capture_scope = wip_captures.scope,
.instructions = .{},
.label = null,
.inlining = &inlining,
@@ -3034,6 +3080,9 @@ fn analyzeCall(
break :res2 result;
};
+
+ try wip_captures.finalize();
+
break :res res2;
} else if (func_ty_info.is_generic) res: {
const func_val = try sema.resolveConstValue(block, func_src, func);
@@ -3116,7 +3165,8 @@ fn analyzeCall(
try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
// Create a Decl for the new function.
- const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node);
+ const src_decl = namespace.getDecl();
+ const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node, src_decl.src_scope);
// TODO better names for generic function instantiations
const name_index = mod.getNextAnonNameIndex();
new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
@@ -3147,6 +3197,7 @@ fn analyzeCall(
.mod = mod,
.gpa = gpa,
.arena = sema.arena,
+ .perm_arena = &new_decl_arena.allocator,
.code = fn_zir,
.owner_decl = new_decl,
.namespace = namespace,
@@ -3159,10 +3210,14 @@ fn analyzeCall(
};
defer child_sema.deinit();
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
+ defer wip_captures.deinit();
+
var child_block: Scope.Block = .{
.parent = null,
.sema = &child_sema,
.src_decl = new_decl,
+ .wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -3250,6 +3305,8 @@ fn analyzeCall(
arg_i += 1;
}
+ try wip_captures.finalize();
+
// Populate the Decl ty/val with the function and its type.
new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
@@ -5164,6 +5221,7 @@ fn analyzeSwitch(
.parent = block,
.sema = sema,
.src_decl = block.src_decl,
+ .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.label = &label,
.inlining = block.inlining,
@@ -5268,12 +5326,19 @@ fn analyzeSwitch(
const body = sema.code.extra[extra_index..][0..body_len];
extra_index += body_len;
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ defer wip_captures.deinit();
+
case_block.instructions.shrinkRetainingCapacity(0);
+ case_block.wip_capture_scope = wip_captures.scope;
+
const item = sema.resolveInst(item_ref);
// `item` is already guaranteed to be constant known.
_ = try sema.analyzeBody(&case_block, body);
+ try wip_captures.finalize();
+
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
@@ -5301,6 +5366,7 @@ fn analyzeSwitch(
extra_index += items_len;
case_block.instructions.shrinkRetainingCapacity(0);
+ case_block.wip_capture_scope = child_block.wip_capture_scope;
var any_ok: Air.Inst.Ref = .none;
@@ -5379,11 +5445,18 @@ fn analyzeSwitch(
var cond_body = case_block.instructions.toOwnedSlice(gpa);
defer gpa.free(cond_body);
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ defer wip_captures.deinit();
+
case_block.instructions.shrinkRetainingCapacity(0);
+ case_block.wip_capture_scope = wip_captures.scope;
+
const body = sema.code.extra[extra_index..][0..body_len];
extra_index += body_len;
_ = try sema.analyzeBody(&case_block, body);
+ try wip_captures.finalize();
+
if (is_first) {
is_first = false;
first_else_body = cond_body;
@@ -5409,9 +5482,16 @@ fn analyzeSwitch(
var final_else_body: []const Air.Inst.Index = &.{};
if (special.body.len != 0) {
+ var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ defer wip_captures.deinit();
+
case_block.instructions.shrinkRetainingCapacity(0);
+ case_block.wip_capture_scope = wip_captures.scope;
+
_ = try sema.analyzeBody(&case_block, special.body);
+ try wip_captures.finalize();
+
if (is_first) {
final_else_body = case_block.instructions.items;
} else {
@@ -5693,7 +5773,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
try mod.semaFile(result.file);
const file_root_decl = result.file.root_decl.?;
try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
- return sema.addType(file_root_decl.ty);
+ return sema.addConstant(file_root_decl.ty, file_root_decl.val);
}
fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -6536,8 +6616,45 @@ fn zirThis(
block: *Scope.Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const this_decl = block.base.namespace().getDecl();
const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
- return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{});
+ return sema.analyzeDeclVal(block, src, this_decl);
+}
+
+fn zirClosureCapture(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+) CompileError!void {
+ // TODO: Compile error when closed over values are modified
+ const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
+ const tv = try sema.resolveInstConst(block, inst_data.src(), inst_data.operand);
+ try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{
+ .ty = try tv.ty.copy(sema.perm_arena),
+ .val = try tv.val.copy(sema.perm_arena),
+ });
+}
+
+fn zirClosureGet(
+ sema: *Sema,
+ block: *Scope.Block,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
+ // TODO CLOSURE: Test this with inline functions
+ const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
+ var scope: *CaptureScope = block.src_decl.src_scope.?;
+ // Note: The target closure must be in this scope list.
+ // If it's not here, the zir is invalid, or the list is broken.
+ const tv = while (true) {
+ // Note: We don't need to add a dependency here, because
+ // decls always depend on their lexical parents.
+ if (scope.captures.getPtr(inst_data.inst)) |tv| {
+ break tv;
+ }
+ scope = scope.parent.?;
+ } else unreachable;
+
+ return sema.addConstant(tv.ty, tv.val);
}
fn zirRetAddr(
@@ -8615,6 +8732,7 @@ fn addSafetyCheck(
var fail_block: Scope.Block = .{
.parent = parent_block,
.sema = sema,
+ .wip_capture_scope = parent_block.wip_capture_scope,
.src_decl = parent_block.src_decl,
.instructions = .{},
.inlining = parent_block.inlining,
@@ -8714,7 +8832,7 @@ fn safetyPanic(
block: *Scope.Block,
src: LazySrcLoc,
panic_id: PanicId,
-) !Zir.Inst.Index {
+) CompileError!Zir.Inst.Index {
const msg = switch (panic_id) {
.unreach => "reached unreachable code",
.unwrap_null => "attempt to use null value",
@@ -10666,6 +10784,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
sema.namespace = &struct_obj.namespace;
defer sema.namespace = prev_namespace;
+ const old_src = block.src_decl;
+ defer block.src_decl = old_src;
+ block.src_decl = struct_obj.owner_decl;
+
struct_obj.status = .field_types_wip;
try sema.analyzeStructFields(block, struct_obj);
struct_obj.status = .have_field_types;
@@ -10684,6 +10806,10 @@ pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty:
sema.namespace = &union_obj.namespace;
defer sema.namespace = prev_namespace;
+ const old_src = block.src_decl;
+ defer block.src_decl = old_src;
+ block.src_decl = union_obj.owner_decl;
+
union_obj.status = .field_types_wip;
try sema.analyzeUnionFields(block, union_obj);
union_obj.status = .have_field_types;
@@ -10885,9 +11011,11 @@ fn analyzeUnionFields(
const src: LazySrcLoc = .{ .node_offset = union_obj.node_offset };
extra_index += @boolToInt(small.has_src_node);
- if (small.has_tag_type) {
+ const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
+ const ty_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
extra_index += 1;
- }
+ break :blk ty_ref;
+ } else .none;
const body_len = if (small.has_body_len) blk: {
const body_len = zir.extra[extra_index];
@@ -10996,6 +11124,7 @@ fn analyzeUnionFields(
}
// TODO resolve the union tag_type_ref
+ _ = tag_type_ref;
}
fn getBuiltin(