Commit bf014d529a

Vexu <git@vexu.eu>
2020-08-25 18:59:35
stage2: array access astgen
1 parent bcd0408
Changed files (4)
src-self-hosted
test
src-self-hosted/astgen.zig
@@ -274,6 +274,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),
         .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
         .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
+        .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
 
         .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
         .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
@@ -283,7 +284,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
         .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
         .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
-        .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
         .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
         .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
         .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
@@ -797,6 +797,16 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix
     return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}));
 }
 
+fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst {
+    const tree = scope.tree();
+    const src = tree.token_locs[node.rtoken].start;
+
+    const array_ptr = try expr(mod, scope, .ref, node.lhs);
+    const index = try expr(mod, scope, .none, node.index_expr);
+
+    return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));
+}
+
 fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
     const tree = scope.tree();
     const src = tree.token_locs[node.rtoken].start;
src-self-hosted/zir_sema.zig
@@ -1076,9 +1076,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
     const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
     const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);
     const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);
+    
+    const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
+        .Pointer => array_ptr.ty.elemType(),
+        else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
+    };
+    if (!elem_ty.isIndexable()) {
+        return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty});
+    }
 
-    if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {
-        if (array_ptr.value()) |array_ptr_val| {
+    if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
+        // we have to deref the ptr operand to get the actual array pointer
+        const array_ptr_deref = try mod.analyzeDeref(scope, inst.base.src, array_ptr, inst.positionals.array_ptr.src);
+        if (array_ptr_deref.value()) |array_ptr_val| {
             if (elem_index.value()) |index_val| {
                 // Both array pointer and index are compile-time known.
                 const index_u64 = index_val.toUnsignedInt();
@@ -1089,7 +1099,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
                 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
                 type_payload.* = .{
                     .base = .{ .tag = .single_const_pointer },
-                    .pointee_type = array_ptr.ty.elemType().elemType(),
+                    .pointee_type = elem_ty.elemType().elemType(),
                 };
 
                 return mod.constInst(scope, inst.base.src, .{
test/stage2/test.zig
@@ -820,6 +820,31 @@ pub fn addCases(ctx: *TestContext) !void {
         ,
             "",
         );
+
+        // Array access.
+        case.addCompareOutput(
+            \\export fn _start() noreturn {
+            \\    assert("hello"[0] == 'h');
+            \\
+            \\    exit();
+            \\}
+            \\
+            \\pub fn assert(ok: bool) void {
+            \\    if (!ok) unreachable; // assertion failure
+            \\}
+            \\
+            \\fn exit() noreturn {
+            \\    asm volatile ("syscall"
+            \\        :
+            \\        : [number] "{rax}" (231),
+            \\          [arg1] "{rdi}" (0)
+            \\        : "rcx", "r11", "memory"
+            \\    );
+            \\    unreachable;
+            \\}
+        ,
+            "",
+        );
     }
 
     {
test/stage2/zir.zig
@@ -43,10 +43,11 @@ pub fn addCases(ctx: *TestContext) !void {
         \\
         \\@entry = fn(@fnty, {
         \\  %a = str("\x32\x08\x01\x0a")
-        \\  %eptr0 = elemptr(%a, @0)
-        \\  %eptr1 = elemptr(%a, @1)
-        \\  %eptr2 = elemptr(%a, @2)
-        \\  %eptr3 = elemptr(%a, @3)
+        \\  %a_ref = ref(%a)
+        \\  %eptr0 = elemptr(%a_ref, @0)
+        \\  %eptr1 = elemptr(%a_ref, @1)
+        \\  %eptr2 = elemptr(%a_ref, @2)
+        \\  %eptr3 = elemptr(%a_ref, @3)
         \\  %v0 = deref(%eptr0)
         \\  %v1 = deref(%eptr1)
         \\  %v2 = deref(%eptr2)