Commit 2029601cb2

Veikka Tuominen <git@vexu.eu>
2022-06-30 22:59:39
AstGen: use elem_{ptr,val}_node for array access syntax
1 parent a6bf8c2
src/AstGen.zig
@@ -5154,16 +5154,14 @@ fn arrayAccess(
     const tree = astgen.tree;
     const node_datas = tree.nodes.items(.data);
     switch (rl) {
-        .ref => return gz.addBin(
-            .elem_ptr,
-            try expr(gz, scope, .ref, node_datas[node].lhs),
-            try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
-        ),
-        else => return rvalue(gz, rl, try gz.addBin(
-            .elem_val,
-            try expr(gz, scope, .none, node_datas[node].lhs),
-            try expr(gz, scope, .{ .coerced_ty = .usize_type }, node_datas[node].rhs),
-        ), node),
+        .ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{
+            .lhs = try expr(gz, scope, .ref, node_datas[node].lhs),
+            .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
+        }),
+        else => return rvalue(gz, rl, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{
+            .lhs = try expr(gz, scope, .none, node_datas[node].lhs),
+            .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
+        }), node),
     }
 }
 
@@ -5685,7 +5683,7 @@ fn whileExpr(
         try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
     }
     if (while_full.ast.cont_expr != 0) {
-        _ = try expr(&loop_scope, then_sub_scope, .{ .ty = .void_type }, while_full.ast.cont_expr);
+        _ = try unusedResultExpr(&loop_scope, then_sub_scope, while_full.ast.cont_expr);
     }
     try then_scope.addDbgBlockEnd();
     const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
@@ -5890,7 +5888,10 @@ fn forExpr(
         if (!mem.eql(u8, value_name, "_")) {
             const name_str_index = try astgen.identAsString(ident);
             const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
-            const payload_inst = try then_scope.addBin(tag, array_ptr, index);
+            const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{
+                .lhs = array_ptr,
+                .rhs = index,
+            });
             try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name);
             payload_val_scope = .{
                 .parent = &then_scope.base,
src/print_zir.zig
@@ -144,8 +144,6 @@ const Writer = struct {
         switch (tag) {
             .array_type,
             .as,
-            .elem_ptr,
-            .elem_val,
             .store,
             .store_to_block_ptr,
             .store_to_inferred_ptr,
@@ -355,6 +353,8 @@ const Writer = struct {
             .minimum,
             .elem_ptr_node,
             .elem_val_node,
+            .elem_ptr,
+            .elem_val,
             .coerce_result_ptr,
             => try self.writePlNodeBin(stream, inst),
 
src/Sema.zig
@@ -2738,6 +2738,7 @@ fn ensureResultUsed(
     const operand_ty = sema.typeOf(operand);
     switch (operand_ty.zigTypeTag()) {
         .Void, .NoReturn => return,
+        .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is ignored. consider using `try`, `catch`, or `if`", .{}),
         else => return sema.fail(block, src, "expression value is ignored", .{}),
     }
 }
@@ -2751,7 +2752,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
     const src = inst_data.src();
     const operand_ty = sema.typeOf(operand);
     switch (operand_ty.zigTypeTag()) {
-        .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is discardederror is discarded. consider using `try`, `catch`, or `if`", .{}),
+        .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is discarded. consider using `try`, `catch`, or `if`", .{}),
         else => return,
     }
 }
@@ -7092,7 +7093,7 @@ fn funcCommon(
         const param_types = try sema.arena.alloc(Type, block.params.items.len);
         const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
         for (block.params.items) |param, i| {
-            const param_src = LazySrcLoc.nodeOffset(src_node_offset); // TODO better src
+            const param_src = LazySrcLoc.nodeOffset(src_node_offset); // TODO better soruce location
             param_types[i] = param.ty;
             comptime_params[i] = param.is_comptime or
                 try sema.typeRequiresComptime(block, param_src, param.ty);
@@ -7798,12 +7799,12 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const tracy = trace(@src());
     defer tracy.end();
 
-    const bin_inst = sema.code.instructions.items(.data)[inst].bin;
-    const src = sema.src; // TODO better source location
-    const elem_index_src = sema.src; // TODO better source location
-    const array = try sema.resolveInst(bin_inst.lhs);
-    const elem_index = try sema.resolveInst(bin_inst.rhs);
-    return sema.elemVal(block, src, array, elem_index, elem_index_src);
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+    const array = try sema.resolveInst(extra.lhs);
+    const elem_index = try sema.resolveInst(extra.rhs);
+    return sema.elemVal(block, src, array, elem_index, src);
 }
 
 fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -7823,10 +7824,12 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const tracy = trace(@src());
     defer tracy.end();
 
-    const bin_inst = sema.code.instructions.items(.data)[inst].bin;
-    const array_ptr = try sema.resolveInst(bin_inst.lhs);
-    const elem_index = try sema.resolveInst(bin_inst.rhs);
-    return sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src, false);
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+    const array_ptr = try sema.resolveInst(extra.lhs);
+    const elem_index = try sema.resolveInst(extra.rhs);
+    return sema.elemPtr(block, src, array_ptr, elem_index, src, false);
 }
 
 fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -19454,7 +19457,7 @@ fn tupleFieldPtr(
     const tuple_fields = tuple_ty.tupleFields();
 
     if (tuple_fields.types.len == 0) {
-        return sema.fail(block, field_index_src, "indexing into empty tuple", .{});
+        return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
     }
 
     if (field_index >= tuple_fields.types.len) {
@@ -19497,7 +19500,7 @@ fn tupleField(
     const tuple_fields = tuple_ty.tupleFields();
 
     if (tuple_fields.types.len == 0) {
-        return sema.fail(block, field_index_src, "indexing into empty tuple", .{});
+        return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
     }
 
     if (field_index >= tuple_fields.types.len) {
@@ -19538,7 +19541,7 @@ fn elemValArray(
     const elem_ty = array_ty.childType();
 
     if (array_len_s == 0) {
-        return sema.fail(block, elem_index_src, "indexing into empty array", .{});
+        return sema.fail(block, array_src, "indexing into empty array is not allowed", .{});
     }
 
     const maybe_undef_array_val = try sema.resolveMaybeUndefVal(block, array_src, array);
@@ -19618,7 +19621,7 @@ fn elemPtrArray(
     const array_len_s = array_len + @boolToInt(array_sent);
 
     if (array_len_s == 0) {
-        return sema.fail(block, elem_index_src, "indexing into empty array", .{});
+        return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{});
     }
 
     const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(block, array_ptr_src, array_ptr);
@@ -19700,7 +19703,7 @@ fn elemValSlice(
         const slice_len = slice_val.sliceLen(sema.mod);
         const slice_len_s = slice_len + @boolToInt(slice_sent);
         if (slice_len_s == 0) {
-            return sema.fail(block, elem_index_src, "indexing into empty slice", .{});
+            return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
         }
         if (maybe_index_val) |index_val| {
             const index = @intCast(usize, index_val.toUnsignedInt(target));
@@ -19757,7 +19760,7 @@ fn elemPtrSlice(
         const slice_len = slice_val.sliceLen(sema.mod);
         const slice_len_s = slice_len + @boolToInt(slice_sent);
         if (slice_len_s == 0) {
-            return sema.fail(block, elem_index_src, "indexing into empty slice", .{});
+            return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
         }
         if (offset) |index| {
             if (index >= slice_len_s) {
src/type.zig
@@ -189,7 +189,7 @@ pub const Type = extern union {
             .Frame,
             => false,
 
-            .Pointer => is_equality_cmp or ty.isCPtr(),
+            .Pointer => !ty.isSlice() and (is_equality_cmp or ty.isCPtr()),
             .Optional => {
                 if (!is_equality_cmp) return false;
                 var buf: Payload.ElemType = undefined;
src/Zir.zig
@@ -370,24 +370,23 @@ pub const Inst = struct {
         /// Uses the `pl_node` union field. Payload is `Bin`.
         div,
         /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
-        /// the provided index. Uses the `bin` union field. Source location is implied
-        /// to be the same as the previous instruction.
-        elem_ptr,
-        /// Same as `elem_ptr` except also stores a source location node.
+        /// the provided index.
         /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
         elem_ptr_node,
+        /// Same as `elem_ptr_node` but used only for for loop.
+        /// Uses the `pl_node` union field. AST node is the condition of a for loop. Payload is `Bin`.
+        elem_ptr,
         /// Same as `elem_ptr_node` except the index is stored immediately rather than
         /// as a reference to another ZIR instruction.
         /// Uses the `pl_node` union field. AST node is an element inside array initialization
         /// syntax. Payload is `ElemPtrImm`.
         elem_ptr_imm,
         /// Given an array, slice, or pointer, returns the element at the provided index.
-        /// Uses the `bin` union field. Source location is implied to be the same
-        /// as the previous instruction.
-        elem_val,
-        /// Same as `elem_val` except also stores a source location node.
         /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
         elem_val_node,
+        /// Same as `elem_val_node` but used only for for loop.
+        /// Uses the `pl_node` union field. AST node is the condition of a for loop. Payload is `Bin`.
+        elem_val,
         /// Emits a compile error if the operand is not `void`.
         /// Uses the `un_node` field.
         ensure_result_used,
@@ -1627,10 +1626,10 @@ pub const Inst = struct {
                 .decl_val = .str_tok,
                 .load = .un_node,
                 .div = .pl_node,
-                .elem_ptr = .bin,
+                .elem_ptr = .pl_node,
                 .elem_ptr_node = .pl_node,
                 .elem_ptr_imm = .pl_node,
-                .elem_val = .bin,
+                .elem_val = .pl_node,
                 .elem_val_node = .pl_node,
                 .ensure_result_used = .un_node,
                 .ensure_result_non_error = .un_node,
test/cases/compile_errors/stage1/obj/illegal_comparison_of_types.zig
@@ -1,20 +0,0 @@
-fn bad_eql_1(a: []u8, b: []u8) bool {
-    return a == b;
-}
-const EnumWithData = union(enum) {
-    One: void,
-    Two: i32,
-};
-fn bad_eql_2(a: *const EnumWithData, b: *const EnumWithData) bool {
-    return a.* == b.*;
-}
-
-export fn entry1() usize { return @sizeOf(@TypeOf(bad_eql_1)); }
-export fn entry2() usize { return @sizeOf(@TypeOf(bad_eql_2)); }
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:2:14: error: operator not allowed for type '[]u8'
-// tmp.zig:9:16: error: operator not allowed for type 'EnumWithData'
test/cases/compile_errors/stage1/obj/implicit_cast_from_f64_to_f32.zig → test/cases/compile_errors/stage1/implicit_cast_from_f64_to_f32.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/int_to_ptr_of_0_bits.zig → test/cases/compile_errors/stage1/int_to_ptr_of_0_bits.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/ignored_deferred_function_call.zig → test/cases/compile_errors/ignored_deferred_function_call.zig
@@ -4,7 +4,7 @@ export fn foo() void {
 fn bar() anyerror!i32 { return 0; }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:2:14: error: error is ignored. consider using `try`, `catch`, or `if`
+// :2:14: error: error is ignored. consider using `try`, `catch`, or `if`
test/cases/compile_errors/stage1/obj/ignored_expression_in_while_continuation.zig → test/cases/compile_errors/ignored_expression_in_while_continuation.zig
@@ -14,9 +14,9 @@ fn bad() anyerror!void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:2:24: error: error is ignored. consider using `try`, `catch`, or `if`
-// tmp.zig:6:25: error: error is ignored. consider using `try`, `catch`, or `if`
-// tmp.zig:10:25: error: error is ignored. consider using `try`, `catch`, or `if`
+// :2:24: error: error is ignored. consider using `try`, `catch`, or `if`
+// :6:25: error: error is ignored. consider using `try`, `catch`, or `if`
+// :10:25: error: error is ignored. consider using `try`, `catch`, or `if`
test/cases/compile_errors/illegal_comparison_of_types.zig
@@ -0,0 +1,20 @@
+fn bad_eql_1(a: []u8, b: []u8) bool {
+    return a == b;
+}
+const EnumWithData = union(enum) {
+    One: void,
+    Two: i32,
+};
+fn bad_eql_2(a: *const EnumWithData, b: *const EnumWithData) bool {
+    return a.* == b.*;
+}
+
+export fn entry1() usize { return @sizeOf(@TypeOf(&bad_eql_1)); }
+export fn entry2() usize { return @sizeOf(@TypeOf(&bad_eql_2)); }
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:14: error: operator == not allowed for type '[]u8'
+// :9:16: error: operator == not allowed for type 'tmp.EnumWithData'
test/cases/compile_errors/stage1/obj/implicitly_casting_enum_to_tag_type.zig → test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig
@@ -11,7 +11,7 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:9:22: error: expected type 'u2', found 'Small'
+// :9:22: error: expected type 'u2', found 'tmp.Small'
test/cases/compile_errors/stage1/obj/incorrect_return_type.zig → test/cases/compile_errors/incorrect_return_type.zig
@@ -15,7 +15,7 @@
  }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:8:16: error: expected type 'A', found 'B'
+// :8:16: error: expected type 'tmp.A', found 'tmp.B'
test/cases/compile_errors/stage1/obj/indexing_an_array_of_size_zero.zig → test/cases/compile_errors/indexing_an_array_of_size_zero.zig
@@ -5,7 +5,7 @@ export fn foo() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:3:27: error: accessing a zero length array is not allowed
+// :3:27: error: indexing into empty array is not allowed
test/cases/compile_errors/stage1/obj/indexing_an_array_of_size_zero_with_runtime_index.zig → test/cases/compile_errors/indexing_an_array_of_size_zero_with_runtime_index.zig
@@ -6,7 +6,7 @@ export fn foo() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:4:27: error: accessing a zero length array is not allowed
+// :4:27: error: indexing into empty array is not allowed
test/cases/compile_errors/stage1/obj/indexing_single-item_pointer.zig → test/cases/compile_errors/indexing_single-item_pointer.zig
@@ -3,7 +3,7 @@ export fn entry(ptr: *i32) i32 {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:2:15: error: index of single-item pointer
+// :2:15: error: element access of non-indexable type '*i32'
test/cases/compile_errors/stage1/obj/invalid_cast_from_integral_type_to_enum.zig → test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig
@@ -11,7 +11,7 @@ fn foo(x: usize) void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:9:10: error: expected type 'usize', found 'E'
+// :9:10: error: expected type 'usize', found 'tmp.E'
test/cases/compile_errors/runtime_indexing_comptime_array.zig
@@ -24,9 +24,9 @@ pub export fn entry3() void {
 // target=native
 // backend=stage2
 //
-// :6:5: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
-// :6:5: note: use '*const fn() void' for a function pointer type
-// :13:5: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
-// :13:5: note: use '*const fn() void' for a function pointer type
-// :19:5: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
-// :19:5: note: use '*const fn() void' for a function pointer type
+// :7:10: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
+// :7:10: note: use '*const fn() void' for a function pointer type
+// :15:18: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
+// :15:17: note: use '*const fn() void' for a function pointer type
+// :21:19: error: values of type '[2]fn() void' must be comptime known, but index value is runtime known
+// :21:18: note: use '*const fn() void' for a function pointer type