Commit f58cbef165

Andrew Kelley <andrew@ziglang.org>
2021-08-05 08:02:13
stage2: std.mem.eql works now
* The `indexable_ptr_len` ZIR instruction now uses a `none_or_ref` ResultLoc. This prevents an unnecessary `ref` instruction from being emitted. * Sema: Fix `analyzeCall` using the incorrect ZIR object for the generic function callee. * LLVM backend: `genTypedValue` supports a `Slice` type encoded with the `decl_ref` `Value`.
1 parent d4468af
Changed files (5)
src/codegen/llvm.zig
@@ -701,11 +701,31 @@ pub const DeclGen = struct {
             },
             .Pointer => switch (tv.val.tag()) {
                 .decl_ref => {
-                    const decl = tv.val.castTag(.decl_ref).?.data;
-                    decl.alive = true;
-                    const val = try self.resolveGlobalDecl(decl);
-                    const llvm_type = try self.llvmType(tv.ty);
-                    return val.constBitCast(llvm_type);
+                    if (tv.ty.isSlice()) {
+                        var buf: Type.Payload.ElemType = undefined;
+                        const ptr_ty = tv.ty.slicePtrFieldType(&buf);
+                        var slice_len: Value.Payload.U64 = .{
+                            .base = .{ .tag = .int_u64 },
+                            .data = tv.val.sliceLen(),
+                        };
+                        const fields: [2]*const llvm.Value = .{
+                            try self.genTypedValue(.{
+                                .ty = ptr_ty,
+                                .val = tv.val,
+                            }),
+                            try self.genTypedValue(.{
+                                .ty = Type.initTag(.usize),
+                                .val = Value.initPayload(&slice_len.base),
+                            }),
+                        };
+                        return self.context.constStruct(&fields, fields.len, .False);
+                    } else {
+                        const decl = tv.val.castTag(.decl_ref).?.data;
+                        decl.alive = true;
+                        const val = try self.resolveGlobalDecl(decl);
+                        const llvm_type = try self.llvmType(tv.ty);
+                        return val.constBitCast(llvm_type);
+                    }
                 },
                 .variable => {
                     const decl = tv.val.castTag(.variable).?.data.owner_decl;
src/AstGen.zig
@@ -5423,7 +5423,7 @@ fn forExpr(
     const tree = astgen.tree;
     const token_tags = tree.tokens.items(.tag);
 
-    const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr);
+    const array_ptr = try expr(parent_gz, scope, .none_or_ref, for_full.ast.cond_expr);
     const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
 
     const index_ptr = blk: {
src/Sema.zig
@@ -1306,38 +1306,44 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
 
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
-    const array_ptr = sema.resolveInst(inst_data.operand);
-    const array_ptr_src = src;
+    const array = sema.resolveInst(inst_data.operand);
+    const array_ty = sema.typeOf(array);
 
-    const elem_ty = sema.typeOf(array_ptr).elemType();
-    if (elem_ty.isSlice()) {
-        const slice_inst = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
-        return sema.analyzeSliceLen(block, src, slice_inst);
+    if (array_ty.isSlice()) {
+        return sema.analyzeSliceLen(block, src, array);
     }
-    if (!elem_ty.isIndexable()) {
-        const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
-        const msg = msg: {
-            const msg = try sema.mod.errMsg(
-                &block.base,
-                cond_src,
-                "type '{}' does not support indexing",
-                .{elem_ty},
-            );
-            errdefer msg.destroy(sema.gpa);
-            try sema.mod.errNote(
-                &block.base,
-                cond_src,
-                msg,
-                "for loop operand must be an array, slice, tuple, or vector",
-                .{},
-            );
-            break :msg msg;
-        };
-        return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
+
+    if (array_ty.isSinglePointer()) {
+        const elem_ty = array_ty.elemType();
+        if (elem_ty.isSlice()) {
+            const slice_inst = try sema.analyzeLoad(block, src, array, src);
+            return sema.analyzeSliceLen(block, src, slice_inst);
+        }
+        if (!elem_ty.isIndexable()) {
+            const msg = msg: {
+                const msg = try sema.mod.errMsg(
+                    &block.base,
+                    src,
+                    "type '{}' does not support indexing",
+                    .{elem_ty},
+                );
+                errdefer msg.destroy(sema.gpa);
+                try sema.mod.errNote(
+                    &block.base,
+                    src,
+                    msg,
+                    "for loop operand must be an array, slice, tuple, or vector",
+                    .{},
+                );
+                break :msg msg;
+            };
+            return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
+        }
+        const result_ptr = try sema.fieldPtr(block, src, array, "len", src);
+        return sema.analyzeLoad(block, src, result_ptr, src);
     }
-    const result_ptr = try sema.fieldPtr(block, src, array_ptr, "len", src);
-    const result_ptr_src = array_ptr_src;
-    return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
+
+    return sema.mod.fail(&block.base, src, "TODO implement Sema.zirIndexablePtrLen", .{});
 }
 
 fn zirAllocExtended(
@@ -2520,10 +2526,11 @@ fn analyzeCall(
         // generic Scope only to junk it if it matches an existing instantiation.
         // TODO
 
-        const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
-        const zir_tags = sema.code.instructions.items(.tag);
+        const namespace = module_fn.owner_decl.namespace;
+        const fn_zir = namespace.file_scope.zir;
+        const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
+        const zir_tags = fn_zir.instructions.items(.tag);
         const new_func = new_func: {
-            const namespace = module_fn.owner_decl.namespace;
             try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
 
             // Create a Decl for the new function.
@@ -2558,7 +2565,7 @@ fn analyzeCall(
                 .mod = mod,
                 .gpa = gpa,
                 .arena = sema.arena,
-                .code = sema.code,
+                .code = fn_zir,
                 .owner_decl = new_decl,
                 .namespace = namespace,
                 .func = null,
test/behavior/basic.zig
@@ -1,4 +1,5 @@
 const std = @import("std");
+const mem = std.mem;
 const expect = std.testing.expect;
 
 // normal comment
@@ -83,3 +84,11 @@ test "unicode escape in character literal" {
 test "unicode character in character literal" {
     try expect('💩' == 128169);
 }
+
+fn first4KeysOfHomeRow() []const u8 {
+    return "aoeu";
+}
+
+test "return string from function" {
+    try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
+}
test/behavior/misc.zig
@@ -5,14 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
 const mem = std.mem;
 const builtin = @import("builtin");
 
-fn first4KeysOfHomeRow() []const u8 {
-    return "aoeu";
-}
-
-test "return string from function" {
-    try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
-}
-
 test "memcpy and memset intrinsics" {
     var foo: [20]u8 = undefined;
     var bar: [20]u8 = undefined;