Commit 58caed1c71

Veikka Tuominen <git@vexu.eu>
2022-12-15 20:18:42
Sema: make is_non_{null,err} stricter about types
Closes #13023
1 parent 90477e5
Changed files (5)
src/link/MachO/load_commands.zig
@@ -36,7 +36,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
     // LC_DYLD_INFO_ONLY
     sizeofcmds += @sizeOf(macho.dyld_info_command);
     // LC_FUNCTION_STARTS
-    if (has_text_segment and ctx.wants_function_starts) |_| {
+    if (has_text_segment and ctx.wants_function_starts) {
         sizeofcmds += @sizeOf(macho.linkedit_data_command);
     }
     // LC_DATA_IN_CODE
src/AstGen.zig
@@ -6071,7 +6071,7 @@ fn whileExpr(
             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
             break :c .{
                 .inst = err_union,
-                .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.then_expr),
+                .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.cond_expr),
             };
         } else if (while_full.payload_token) |_| {
             const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
@@ -6079,7 +6079,7 @@ fn whileExpr(
             const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;
             break :c .{
                 .inst = optional,
-                .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.then_expr),
+                .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.cond_expr),
             };
         } else {
             const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr);
src/Sema.zig
@@ -16356,6 +16356,15 @@ fn finishCondBr(
     return Air.indexToRef(block_inst);
 }
 
+fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+    switch (ty.zigTypeTag()) {
+        .Optional, .Null, .Undefined => return,
+        .Pointer => if (ty.isPtrLikeOptional()) return,
+        else => {},
+    }
+    return sema.failWithExpectedOptionalType(block, src, ty);
+}
+
 fn zirIsNonNull(
     sema: *Sema,
     block: *Block,
@@ -16367,6 +16376,7 @@ fn zirIsNonNull(
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const operand = try sema.resolveInst(inst_data.operand);
+    try sema.checkNullableType(block, src, sema.typeOf(operand));
     return sema.analyzeIsNull(block, src, operand, true);
 }
 
@@ -16381,6 +16391,7 @@ fn zirIsNonNullPtr(
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const ptr = try sema.resolveInst(inst_data.operand);
+    try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2());
     if ((try sema.resolveMaybeUndefVal(ptr)) == null) {
         return block.addUnOp(.is_non_null_ptr, ptr);
     }
@@ -16388,12 +16399,23 @@ fn zirIsNonNullPtr(
     return sema.analyzeIsNull(block, src, loaded, true);
 }
 
+fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+    switch (ty.zigTypeTag()) {
+        .ErrorSet, .ErrorUnion, .Undefined => return,
+        else => return sema.fail(block, src, "expected error union type, found '{}'", .{
+            ty.fmt(sema.mod),
+        }),
+    }
+}
+
 fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const tracy = trace(@src());
     defer tracy.end();
 
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
     const operand = try sema.resolveInst(inst_data.operand);
+    try sema.checkErrorType(block, src, sema.typeOf(operand));
     return sema.analyzeIsNonErr(block, inst_data.src(), operand);
 }
 
@@ -16404,6 +16426,7 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const ptr = try sema.resolveInst(inst_data.operand);
+    try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2());
     const loaded = try sema.analyzeLoad(block, src, ptr, src);
     return sema.analyzeIsNonErr(block, src, loaded);
 }
test/cases/compile_errors/stage1/obj/invalid_maybe_type.zig
@@ -1,9 +0,0 @@
-export fn f() void {
-    if (true) |x| { _ = x; }
-}
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:2:9: error: expected optional type, found 'bool'
test/cases/compile_errors/invalid_capture_type.zig
@@ -0,0 +1,24 @@
+export fn f1() void {
+    if (true) |x| { _ = x; }
+}
+export fn f2() void {
+    if (@as(usize, 5)) |_| {}
+}
+export fn f3() void {
+    if (@as(usize, 5)) |_| {} else |_| {}
+}
+export fn f4() void {
+    if (null) |_| {}
+}
+export fn f5() void {
+    if (error.Foo) |_| {} else |_| {}
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:9: error: expected optional type, found 'bool'
+// :5:9: error: expected optional type, found 'usize'
+// :8:9: error: expected error union type, found 'usize'
+// :14:9: error: expected error union type, found 'error{Foo}'