Commit 50010447bd

Andrew Kelley <andrew@ziglang.org>
2021-03-21 01:09:06
astgen: implement function calls
1 parent 907142a
src/astgen.zig
@@ -3402,10 +3402,6 @@ fn callExpr(
     node: ast.Node.Index,
     call: ast.full.Call,
 ) InnerError!zir.Inst.Ref {
-    if (true) {
-        @panic("TODO update for zir-memory-layout branch");
-    }
-
     if (call.async_token) |async_token| {
         return mod.failTok(scope, async_token, "TODO implement async fn call", .{});
     }
@@ -3414,11 +3410,14 @@ fn callExpr(
     const args = try mod.gpa.alloc(zir.Inst.Index, call.ast.params.len);
     defer mod.gpa.free(args);
 
-    const gen_zir = scope.getGenZir();
+    const gz = scope.getGenZir();
     for (call.ast.params) |param_node, i| {
-        const param_type = try gen_zir.addParamType(.{
-            .callee = lhs,
-            .param_index = i,
+        const param_type = try gz.add(.{
+            .tag = .param_type,
+            .data = .{ .param_type = .{
+                .callee = lhs,
+                .param_index = @intCast(u32, i),
+            } },
         });
         args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
     }
@@ -3430,7 +3429,7 @@ fn callExpr(
     const result: zir.Inst.Index = res: {
         const tag: zir.Inst.Tag = switch (modifier) {
             .auto => switch (args.len == 0) {
-                true => break :res try gen_zir.addCallNone(lhs, node),
+                true => break :res try gz.addUnNode(.call_none, lhs, node),
                 false => .call,
             },
             .async_kw => .call_async_kw,
@@ -3441,9 +3440,9 @@ fn callExpr(
             .always_inline => unreachable,
             .compile_time => .call_compile_time,
         };
-        break :res try gen_zir.addCall(tag, lhs, args, node);
+        break :res try gz.addCall(tag, lhs, args, node);
     };
-    return rvalue(mod, scope, rl, result); // TODO function call with result location
+    return rvalue(mod, scope, rl, result, node); // TODO function call with result location
 }
 
 fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {
src/Module.zig
@@ -237,12 +237,20 @@ pub const Decl = struct {
         }
     }
 
-    pub fn tokSrcLoc(decl: *Decl, token_index: ast.TokenIndex) LazySrcLoc {
+    pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {
+        return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.srcNode()));
+    }
+
+    pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {
+        return @bitCast(i32, node_index) - @bitCast(i32, decl.srcNode());
+    }
+
+    pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
         return .{ .token_offset = token_index - decl.srcToken() };
     }
 
-    pub fn nodeSrcLoc(decl: *Decl, node_index: ast.Node.Index) LazySrcLoc {
-        return .{ .node_offset = node_index - decl.srcNode() };
+    pub fn nodeSrcLoc(decl: Decl, node_index: ast.Node.Index) LazySrcLoc {
+        return .{ .node_offset = decl.nodeIndexToRelative(node_index) };
     }
 
     pub fn srcLoc(decl: *Decl) SrcLoc {
@@ -1076,6 +1084,40 @@ pub const Scope = struct {
             return new_index + gz.zir_code.ref_start_index;
         }
 
+        pub fn addCall(
+            gz: *GenZir,
+            tag: zir.Inst.Tag,
+            callee: zir.Inst.Ref,
+            args: []const zir.Inst.Ref,
+            /// Absolute node index. This function does the conversion to offset from Decl.
+            abs_node_index: ast.Node.Index,
+        ) !zir.Inst.Index {
+            assert(callee != 0);
+            assert(abs_node_index != 0);
+            const gpa = gz.zir_code.gpa;
+            try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
+            try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
+            try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.items.len +
+                @typeInfo(zir.Inst.Call).Struct.fields.len + args.len);
+
+            const payload_index = gz.zir_code.addExtra(zir.Inst.Call{
+                .callee = callee,
+                .args_len = @intCast(u32, args.len),
+            }) catch unreachable; // Capacity is ensured above.
+            gz.zir_code.extra.appendSliceAssumeCapacity(args);
+
+            const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
+            gz.zir_code.instructions.appendAssumeCapacity(.{
+                .tag = tag,
+                .data = .{ .pl_node = .{
+                    .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),
+                    .payload_index = payload_index,
+                } },
+            });
+            gz.instructions.appendAssumeCapacity(new_index);
+            return new_index + gz.zir_code.ref_start_index;
+        }
+
         pub fn addInt(gz: *GenZir, integer: u64) !zir.Inst.Ref {
             return gz.add(.{
                 .tag = .int,
@@ -1095,7 +1137,7 @@ pub const Scope = struct {
                 .tag = tag,
                 .data = .{ .un_node = .{
                     .operand = operand,
-                    .src_node = abs_node_index - gz.zir_code.decl.srcNode(),
+                    .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),
                 } },
             });
         }
@@ -1116,7 +1158,7 @@ pub const Scope = struct {
             gz.zir_code.instructions.appendAssumeCapacity(.{
                 .tag = tag,
                 .data = .{ .pl_node = .{
-                    .src_node = gz.zir_code.decl.srcNode() - abs_node_index,
+                    .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),
                     .payload_index = payload_index,
                 } },
             });
@@ -1177,7 +1219,7 @@ pub const Scope = struct {
         ) !zir.Inst.Ref {
             return gz.add(.{
                 .tag = tag,
-                .data = .{ .node = abs_node_index - gz.zir_code.decl.srcNode() },
+                .data = .{ .node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index) },
             });
         }
 
@@ -1205,14 +1247,14 @@ pub const Scope = struct {
             try gz.zir_code.instructions.append(gz.zir_code.gpa, .{
                 .tag = tag,
                 .data = .{ .pl_node = .{
-                    .src_node = node - gz.zir_code.decl.srcNode(),
+                    .src_node = gz.zir_code.decl.nodeIndexToRelative(node),
                     .payload_index = undefined,
                 } },
             });
             return new_index;
         }
 
-        fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
+        pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
             const gpa = gz.zir_code.gpa;
             try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
             try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
@@ -1593,7 +1635,7 @@ pub const SrcLoc = struct {
             },
             .node_offset => |node_off| {
                 const decl = src_loc.container.decl;
-                const node_index = decl.srcNode() + node_off;
+                const node_index = decl.relativeToNodeIndex(node_off);
                 const tree = decl.container.file_scope.base.tree();
                 const tok_index = tree.firstToken(node_index);
                 const token_starts = tree.tokens.items(.start);
@@ -1659,84 +1701,84 @@ pub const LazySrcLoc = union(enum) {
     /// The source location points to an AST node, which is this value offset
     /// from its containing Decl node AST index.
     /// The Decl is determined contextually.
-    node_offset: u32,
+    node_offset: i32,
     /// The source location points to a variable declaration type expression,
     /// found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a variable declaration AST node. Next, navigate
     /// to the type expression.
     /// The Decl is determined contextually.
-    node_offset_var_decl_ty: u32,
+    node_offset_var_decl_ty: i32,
     /// The source location points to a for loop condition expression,
     /// found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a for loop AST node. Next, navigate
     /// to the condition expression.
     /// The Decl is determined contextually.
-    node_offset_for_cond: u32,
+    node_offset_for_cond: i32,
     /// The source location points to the first parameter of a builtin
     /// function call, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a builtin call AST node. Next, navigate
     /// to the first parameter.
     /// The Decl is determined contextually.
-    node_offset_builtin_call_arg0: u32,
+    node_offset_builtin_call_arg0: i32,
     /// Same as `node_offset_builtin_call_arg0` except arg index 1.
-    node_offset_builtin_call_arg1: u32,
+    node_offset_builtin_call_arg1: i32,
     /// Same as `node_offset_builtin_call_arg0` except the arg index is contextually
     /// determined.
-    node_offset_builtin_call_argn: u32,
+    node_offset_builtin_call_argn: i32,
     /// The source location points to the index expression of an array access
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to an array access AST node. Next, navigate
     /// to the index expression.
     /// The Decl is determined contextually.
-    node_offset_array_access_index: u32,
+    node_offset_array_access_index: i32,
     /// The source location points to the sentinel expression of a slice
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a slice AST node. Next, navigate
     /// to the sentinel expression.
     /// The Decl is determined contextually.
-    node_offset_slice_sentinel: u32,
+    node_offset_slice_sentinel: i32,
     /// The source location points to the callee expression of a function
     /// call expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a function call AST node. Next, navigate
     /// to the callee expression.
     /// The Decl is determined contextually.
-    node_offset_call_func: u32,
+    node_offset_call_func: i32,
     /// The source location points to the field name of a field access expression,
     /// found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a field access AST node. Next, navigate
     /// to the field name token.
     /// The Decl is determined contextually.
-    node_offset_field_name: u32,
+    node_offset_field_name: i32,
     /// The source location points to the pointer of a pointer deref expression,
     /// found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a pointer deref AST node. Next, navigate
     /// to the pointer expression.
     /// The Decl is determined contextually.
-    node_offset_deref_ptr: u32,
+    node_offset_deref_ptr: i32,
     /// The source location points to the assembly source code of an inline assembly
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to inline assembly AST node. Next, navigate
     /// to the asm template source code.
     /// The Decl is determined contextually.
-    node_offset_asm_source: u32,
+    node_offset_asm_source: i32,
     /// The source location points to the return type of an inline assembly
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to inline assembly AST node. Next, navigate
     /// to the return type expression.
     /// The Decl is determined contextually.
-    node_offset_asm_ret_ty: u32,
+    node_offset_asm_ret_ty: i32,
     /// The source location points to the condition expression of an if
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to an if expression AST node. Next, navigate
     /// to the condition expression.
     /// The Decl is determined contextually.
-    node_offset_if_cond: u32,
+    node_offset_if_cond: i32,
     /// The source location points to the type expression of an `anyframe->T`
     /// expression, found by taking this AST node index offset from the containing
     /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
     /// to the type expression.
     /// The Decl is determined contextually.
-    node_offset_anyframe_type: u32,
+    node_offset_anyframe_type: i32,
 
     /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope.
     pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
@@ -3678,8 +3720,7 @@ pub fn failTok(
     comptime format: []const u8,
     args: anytype,
 ) InnerError {
-    const decl_token = scope.srcDecl().?.srcToken();
-    const src: LazySrcLoc = .{ .token_offset = token_index - decl_token };
+    const src = scope.srcDecl().?.tokSrcLoc(token_index);
     return mod.fail(scope, src, format, args);
 }
 
@@ -3692,8 +3733,7 @@ pub fn failNode(
     comptime format: []const u8,
     args: anytype,
 ) InnerError {
-    const decl_node = scope.srcDecl().?.srcNode();
-    const src: LazySrcLoc = .{ .node_offset = decl_node - node_index };
+    const src = scope.srcDecl().?.nodeSrcLoc(node_index);
     return mod.fail(scope, src, format, args);
 }
 
src/Sema.zig
@@ -618,7 +618,7 @@ fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr
     const tracy = trace(@src());
     defer tracy.end();
 
-    const src: LazySrcLoc = .todo;
+    const src: LazySrcLoc = .unneeded;
     const inst_data = sema.code.instructions.items(.data)[inst].param_type;
     const fn_inst = try sema.resolveInst(inst_data.callee);
     const param_index = inst_data.param_index;
src/zir.zig
@@ -1019,7 +1019,7 @@ pub const Inst = struct {
         /// Used for unary operators, with an AST node source location.
         un_node: struct {
             /// Offset from Decl AST node index.
-            src_node: ast.Node.Index,
+            src_node: i32,
             /// The meaning of this operand depends on the corresponding `Tag`.
             operand: Ref,
 
@@ -1041,7 +1041,7 @@ pub const Inst = struct {
         pl_node: struct {
             /// Offset from Decl AST node index.
             /// `Tag` determines which kind of AST node this points to.
-            src_node: ast.Node.Index,
+            src_node: i32,
             /// index into extra.
             /// `Tag` determines what lives there.
             payload_index: u32,
@@ -1092,7 +1092,7 @@ pub const Inst = struct {
         /// Offset from Decl AST token index.
         tok: ast.TokenIndex,
         /// Offset from Decl AST node index.
-        node: ast.Node.Index,
+        node: i32,
         int: u64,
         array_type_sentinel: struct {
             len: Ref,
@@ -1400,9 +1400,10 @@ const Writer = struct {
             .slice_sentinel,
             .typeof_peer,
             .suspend_block,
-            .as_node,
             => try self.writePlNode(stream, inst),
 
+            .as_node => try self.writeAs(stream, inst),
+
             .breakpoint,
             .dbg_stmt_node,
             .ret_ptr,
@@ -1544,6 +1545,16 @@ const Writer = struct {
         try self.writeSrc(stream, inst_data.src());
     }
 
+    fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void {
+        const inst_data = self.code.instructions.items(.data)[inst].pl_node;
+        const extra = self.code.extraData(Inst.As, inst_data.payload_index).data;
+        try self.writeInstRef(stream, extra.dest_type);
+        try stream.writeAll(", ");
+        try self.writeInstRef(stream, extra.operand);
+        try stream.writeAll(") ");
+        try self.writeSrc(stream, inst_data.src());
+    }
+
     fn writeNode(
         self: *Writer,
         stream: anytype,
@@ -1560,8 +1571,8 @@ const Writer = struct {
         stream: anytype,
         inst: Inst.Index,
     ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
-        const inst_data = self.code.instructions.items(.data)[inst].decl;
-        try stream.writeAll("TODO)");
+        const decl = self.code.instructions.items(.data)[inst].decl;
+        try stream.print("{s})", .{decl.name});
     }
 
     fn writeStrTok(