Skip to content

Sema: add missing error and test for bool not on vector of ints #24162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 52 additions & 30 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1171,11 +1171,11 @@ fn analyzeBodyInner(
.as_node => try sema.zirAsNode(block, inst),
.as_shift_operand => try sema.zirAsShiftOperand(block, inst),
.bit_and => try sema.zirBitwise(block, inst, .bit_and),
.bit_not => try sema.zirBitNot(block, inst, false),
.bit_not => try sema.zirBitNot(block, inst),
.bit_or => try sema.zirBitwise(block, inst, .bit_or),
.bitcast => try sema.zirBitcast(block, inst),
.suspend_block => try sema.zirSuspendBlock(block, inst),
.bool_not => try sema.zirBitNot(block, inst, true),
.bool_not => try sema.zirBoolNot(block, inst),
.bool_br_and => try sema.zirBoolBr(block, inst, false),
.bool_br_or => try sema.zirBoolBr(block, inst, true),
.c_import => try sema.zirCImport(block, inst),
Expand Down Expand Up @@ -14442,57 +14442,55 @@ fn zirBitwise(
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
}

fn zirBitNot(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
is_bool_not: bool,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();

fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });

const src = block.nodeOffset(inst_data.src_node);
const operand = try sema.resolveInst(inst_data.operand);
const operand_type = sema.typeOf(operand);
const scalar_type = operand_type.scalarType(zcu);
const scalar_tag = scalar_type.zigTypeTag(zcu);
const operand_ty = sema.typeOf(operand);
const scalar_ty = operand_ty.scalarType(zcu);
const scalar_tag = scalar_ty.zigTypeTag(zcu);

const is_finite_int_or_bool = scalar_tag == .int or scalar_tag == .bool;
const is_allowed_type = if (is_bool_not) scalar_tag == .bool else is_finite_int_or_bool;
if (scalar_tag != .int and scalar_tag != .bool)
return sema.fail(block, operand_src, "bitwise not operation on type '{}'", .{operand_ty.fmt(pt)});

if (!is_allowed_type) {
return sema.fail(block, src, "unable to perform {s} not operation on type '{}'", .{
if (is_bool_not) "boolean" else "binary", operand_type.fmt(pt),
});
}
return analyzeBitNot(sema, block, operand, src);
}

fn analyzeBitNot(
sema: *Sema,
block: *Block,
operand: Air.Inst.Ref,
src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const operand_ty = sema.typeOf(operand);
const scalar_ty = operand_ty.scalarType(zcu);
if (try sema.resolveValue(operand)) |val| {
if (val.isUndef(zcu)) {
return pt.undefRef(operand_type);
} else if (operand_type.zigTypeTag(zcu) == .vector) {
const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(zcu));
return pt.undefRef(operand_ty);
} else if (operand_ty.zigTypeTag(zcu) == .vector) {
const vec_len = try sema.usizeCast(block, src, operand_ty.vectorLen(zcu));
const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
const elem_val = try val.elemValue(pt, i);
elem.* = (try elem_val.bitwiseNot(scalar_type, sema.arena, pt)).toIntern();
elem.* = (try elem_val.bitwiseNot(scalar_ty, sema.arena, pt)).toIntern();
}
return Air.internedToRef((try pt.intern(.{ .aggregate = .{
.ty = operand_type.toIntern(),
.ty = operand_ty.toIntern(),
.storage = .{ .elems = elems },
} })));
} else {
const result_val = try val.bitwiseNot(operand_type, sema.arena, pt);
const result_val = try val.bitwiseNot(operand_ty, sema.arena, pt);
return Air.internedToRef(result_val.toIntern());
}
}

try sema.requireRuntimeBlock(block, src, null);
return block.addTyOp(.not, operand_type, operand);
return block.addTyOp(.not, operand_ty, operand);
}

fn analyzeTupleCat(
Expand Down Expand Up @@ -18345,6 +18343,30 @@ fn zirTypeofPeer(
return Air.internedToRef(result_type.toIntern());
}

fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
const uncasted_operand = try sema.resolveInst(inst_data.operand);
const uncasted_ty = sema.typeOf(uncasted_operand);
if (uncasted_ty.isVector(zcu)) {
if (uncasted_ty.scalarType(zcu).zigTypeTag(zcu) != .bool) {
return sema.fail(block, operand_src, "boolean not operation on type '{}'", .{
uncasted_ty.fmt(pt),
});
}
return analyzeBitNot(sema, block, uncasted_operand, src);
}
const operand = try sema.coerce(block, .bool, uncasted_operand, operand_src);
if (try sema.resolveValue(operand)) |val| {
return if (val.isUndef(zcu)) .undef_bool else if (val.toBool()) .bool_false else .bool_true;
}
try sema.requireRuntimeBlock(block, src, null);
return block.addTyOp(.not, .bool, operand);
}

fn zirBoolBr(
sema: *Sema,
parent_block: *Block,
Expand Down
2 changes: 1 addition & 1 deletion test/cases/compile_errors/binary_not_on_number_literal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export fn entry() usize {
// backend=stage2
// target=native
//
// :3:60: error: unable to perform binary not operation on type 'comptime_int'
// :3:61: error: bitwise not operation on type 'comptime_int'
10 changes: 10 additions & 0 deletions test/cases/compile_errors/bool_not_on_vector_of_ints.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export fn foo() void {
var x: @Vector(2, u1) = .{ 0, 1 };
x = !x;
}

// error
// backend=stage2
// target=native
//
// :3:10: error: boolean not operation on type '@Vector(2, u1)'