aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-02-26 12:38:25 +0200
committerVeikka Tuominen <git@vexu.eu>2022-02-26 18:08:11 +0200
commitff72b8a8194573bc1d7f95cbf3228b363194c775 (patch)
treed5608b46018c2cd5c38314134e4d4e10100f7c04 /src
parentdb82c1b9820449f2d1e6ef54dd32ec3ffd3c583f (diff)
downloadzig-ff72b8a8194573bc1d7f95cbf3228b363194c775.tar.gz
zig-ff72b8a8194573bc1d7f95cbf3228b363194c775.zip
stage2: evaluate TypeOf arguments in a separate scope
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig56
-rw-r--r--src/Sema.zig44
-rw-r--r--src/Zir.zig11
-rw-r--r--src/print_zir.zig19
4 files changed, 111 insertions, 19 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 74e3ae17b1..45b074a848 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -2159,6 +2159,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.negate,
.negate_wrap,
.typeof,
+ .typeof_builtin,
.xor,
.optional_type,
.optional_payload_safe,
@@ -6875,29 +6876,54 @@ fn typeOf(
scope: *Scope,
rl: ResultLoc,
node: Ast.Node.Index,
- params: []const Ast.Node.Index,
+ args: []const Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
- if (params.len < 1) {
+ if (args.len < 1) {
return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{});
}
- if (params.len == 1) {
- const expr_result = try reachableExpr(gz, scope, .none, params[0], node);
- const result = try gz.addUnNode(.typeof, expr_result, node);
- return rvalue(gz, rl, result, node);
+ const gpa = gz.astgen.gpa;
+ if (args.len == 1) {
+ const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node);
+
+ var typeof_scope = gz.makeSubBlock(scope);
+ typeof_scope.force_comptime = false;
+ defer typeof_scope.unstack();
+
+ const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, args[0], node);
+ if (!gz.refIsNoReturn(ty_expr)) {
+ _ = try typeof_scope.addBreak(.break_inline, typeof_inst, ty_expr);
+ }
+ try typeof_scope.setBlockBody(typeof_inst);
+
+ // typeof_scope unstacked now, can add new instructions to gz
+ try gz.instructions.append(gpa, typeof_inst);
+ return rvalue(gz, rl, indexToRef(typeof_inst), node);
}
+ const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len;
+ const payload_index = try reserveExtra(gz.astgen, payload_size + args.len);
+ var args_index = payload_index + payload_size;
+
+ const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len);
- const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{
+ var typeof_scope = gz.makeSubBlock(scope);
+ typeof_scope.force_comptime = false;
+
+ for (args) |arg, i| {
+ const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node);
+ gz.astgen.extra.items[args_index + i] = @enumToInt(param_ref);
+ }
+ _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value);
+
+ const body = typeof_scope.instructionsSlice();
+ gz.astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{
+ .body_len = @intCast(u32, body.len),
+ .body_index = @intCast(u32, gz.astgen.extra.items.len),
.src_node = gz.nodeIndexToRelative(node),
});
- var extra_index = try reserveExtra(gz.astgen, params.len);
- for (params) |param| {
- const param_ref = try reachableExpr(gz, scope, .none, param, node);
- gz.astgen.extra.items[extra_index] = @enumToInt(param_ref);
- extra_index += 1;
- }
+ try gz.astgen.extra.appendSlice(gpa, body);
+ typeof_scope.unstack();
- const result = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, params.len);
- return rvalue(gz, rl, result, node);
+ return rvalue(gz, rl, typeof_inst, node);
}
fn builtinCall(
diff --git a/src/Sema.zig b/src/Sema.zig
index ef9ba41bec..eca88f8922 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -124,6 +124,7 @@ pub const Block = struct {
runtime_index: u32 = 0,
is_comptime: bool,
+ is_typeof: bool = false,
/// when null, it is determined by build mode, changed by @setRuntimeSafety
want_safety: ?bool = null,
@@ -181,6 +182,7 @@ pub const Block = struct {
.label = null,
.inlining = parent.inlining,
.is_comptime = parent.is_comptime,
+ .is_typeof = parent.is_typeof,
.runtime_cond = parent.runtime_cond,
.runtime_loop = parent.runtime_loop,
.runtime_index = parent.runtime_index,
@@ -682,6 +684,7 @@ fn analyzeBodyInner(
.size_of => try sema.zirSizeOf(block, inst),
.bit_size_of => try sema.zirBitSizeOf(block, inst),
.typeof => try sema.zirTypeof(block, inst),
+ .typeof_builtin => try sema.zirTypeofBuiltin(block, inst),
.log2_int_type => try sema.zirLog2IntType(block, inst),
.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
.xor => try sema.zirBitwise(block, inst, .xor),
@@ -10574,6 +10577,29 @@ fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
return sema.addType(operand_ty);
}
+fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
+ const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
+ const body = sema.code.extra[extra.end..][0..extra.data.body_len];
+
+ var child_block: Block = .{
+ .parent = block,
+ .sema = sema,
+ .src_decl = block.src_decl,
+ .namespace = block.namespace,
+ .wip_capture_scope = block.wip_capture_scope,
+ .instructions = .{},
+ .inlining = block.inlining,
+ .is_comptime = false,
+ .is_typeof = true,
+ };
+ defer child_block.instructions.deinit(sema.gpa);
+
+ const operand = try sema.resolveBody(&child_block, body, inst);
+ const operand_ty = sema.typeOf(operand);
+ return sema.addType(operand_ty);
+}
+
fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
@@ -10624,8 +10650,24 @@ fn zirTypeofPeer(
const tracy = trace(@src());
defer tracy.end();
- const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
+ const extra = sema.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
+ const body = sema.code.extra[extra.data.body_index..][0..extra.data.body_len];
+
+ var child_block: Block = .{
+ .parent = block,
+ .sema = sema,
+ .src_decl = block.src_decl,
+ .namespace = block.namespace,
+ .wip_capture_scope = block.wip_capture_scope,
+ .instructions = .{},
+ .inlining = block.inlining,
+ .is_comptime = false,
+ .is_typeof = true,
+ };
+ defer child_block.instructions.deinit(sema.gpa);
+ _ = try sema.analyzeBody(&child_block, body);
+
const args = sema.code.refSlice(extra.end, extended.small);
const inst_list = try sema.gpa.alloc(Air.Inst.Ref, args.len);
diff --git a/src/Zir.zig b/src/Zir.zig
index c74b2c1d8f..3795c28daf 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -547,6 +547,9 @@ pub const Inst = struct {
/// Returns the type of a value.
/// Uses the `un_node` field.
typeof,
+ /// Implements `@TypeOf` for one operand.
+ /// Uses the `pl_node` field.
+ typeof_builtin,
/// Given a value, look at the type of it, which must be an integer type.
/// Returns the integer type for the RHS of a shift operation.
/// Uses the `un_node` field.
@@ -1067,6 +1070,7 @@ pub const Inst = struct {
.negate,
.negate_wrap,
.typeof,
+ .typeof_builtin,
.xor,
.optional_type,
.optional_payload_safe,
@@ -1429,6 +1433,7 @@ pub const Inst = struct {
.ptr_cast = .pl_node,
.truncate = .pl_node,
.align_cast = .pl_node,
+ .typeof_builtin = .pl_node,
.has_decl = .pl_node,
.has_field = .pl_node,
@@ -2391,6 +2396,12 @@ pub const Inst = struct {
};
};
+ pub const TypeOfPeer = struct {
+ src_node: i32,
+ body_len: u32,
+ body_index: u32,
+ };
+
pub const BuiltinCall = struct {
options: Ref,
callee: Ref,
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 66c3ad7668..9ef67e3213 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -374,6 +374,7 @@ const Writer = struct {
.validate_array_init,
.validate_array_init_comptime,
.c_import,
+ .typeof_builtin,
=> try self.writePlNodeBlock(stream, inst),
.condbr,
@@ -458,9 +459,8 @@ const Writer = struct {
.variable => try self.writeVarExtended(stream, extended),
.alloc => try self.writeAllocExtended(stream, extended),
- .compile_log,
- .typeof_peer,
- => try self.writeNodeMultiOp(stream, extended),
+ .compile_log => try self.writeNodeMultiOp(stream, extended),
+ .typeof_peer => try self.writeTypeofPeer(stream, extended),
.add_with_overflow,
.sub_with_overflow,
@@ -1966,6 +1966,19 @@ const Writer = struct {
try self.writeSrc(stream, src);
}
+ fn writeTypeofPeer(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
+ const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
+ const body = self.code.extra[extra.data.body_index..][0..extra.data.body_len];
+ try self.writeBracedBody(stream, body);
+ try stream.writeAll(",[");
+ const args = self.code.refSlice(extra.end, extended.small);
+ for (args) |arg, i| {
+ if (i != 0) try stream.writeAll(", ");
+ try self.writeInstRef(stream, arg);
+ }
+ try stream.writeAll("])");
+ }
+
fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].bool_br;
const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);