diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-02-26 12:38:25 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-02-26 18:08:11 +0200 |
| commit | ff72b8a8194573bc1d7f95cbf3228b363194c775 (patch) | |
| tree | d5608b46018c2cd5c38314134e4d4e10100f7c04 /src | |
| parent | db82c1b9820449f2d1e6ef54dd32ec3ffd3c583f (diff) | |
| download | zig-ff72b8a8194573bc1d7f95cbf3228b363194c775.tar.gz zig-ff72b8a8194573bc1d7f95cbf3228b363194c775.zip | |
stage2: evaluate TypeOf arguments in a separate scope
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 56 | ||||
| -rw-r--r-- | src/Sema.zig | 44 | ||||
| -rw-r--r-- | src/Zir.zig | 11 | ||||
| -rw-r--r-- | src/print_zir.zig | 19 |
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); |
