mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
Merge 6b2e01d019 into 53e615b920
This commit is contained in:
commit
3bf2507de2
2 changed files with 73 additions and 5 deletions
60
src/Sema.zig
60
src/Sema.zig
|
|
@ -9676,6 +9676,21 @@ fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
|
|||
return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true);
|
||||
}
|
||||
|
||||
fn validateCastDestType(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
dest_ty: Type,
|
||||
src: LazySrcLoc,
|
||||
) CompileError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
switch (dest_ty.zigTypeTag(zcu)) {
|
||||
.@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}),
|
||||
.noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzeAs(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
|
|
@ -9686,13 +9701,48 @@ fn analyzeAs(
|
|||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
// Optimize nested cast builtins to prevent redundant coercion and circular dependencies.
|
||||
if (zir_operand.toIndex()) |operand_index| {
|
||||
const operand_tag = sema.code.instructions.items(.tag)[@intFromEnum(operand_index)];
|
||||
switch (operand_tag) {
|
||||
// These builtins perform their own type-directed casting
|
||||
.int_cast, .float_cast, .ptr_cast, .truncate => {
|
||||
// Resolve dest_ty first so inner cast can use it as type context
|
||||
const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse {
|
||||
return sema.resolveInst(zir_operand);
|
||||
};
|
||||
|
||||
try sema.validateCastDestType(block, dest_ty, src);
|
||||
|
||||
// Now analyze inner cast with dest_ty already resolved
|
||||
const operand = try sema.resolveInst(zir_operand);
|
||||
|
||||
// If inner cast already produced the correct type, skip redundant coercion
|
||||
if (sema.typeOf(operand).eql(dest_ty, zcu)) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
// Otherwise perform outer coercion (handles vectors/arrays and other edge cases)
|
||||
const is_ret = if (zir_dest_type.toIndex()) |ptr_index|
|
||||
sema.code.instructions.items(.tag)[@intFromEnum(ptr_index)] == .ret_type
|
||||
else
|
||||
false;
|
||||
return sema.coerceExtra(block, dest_ty, operand, src, .{
|
||||
.is_ret = is_ret,
|
||||
.no_cast_to_comptime_int = no_cast_to_comptime_int
|
||||
}) catch |err| switch (err) {
|
||||
error.NotCoercible => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
const operand = try sema.resolveInst(zir_operand);
|
||||
const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand;
|
||||
switch (dest_ty.zigTypeTag(zcu)) {
|
||||
.@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}),
|
||||
.noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}),
|
||||
else => {},
|
||||
}
|
||||
try sema.validateCastDestType(block, dest_ty, src);
|
||||
|
||||
const is_ret = if (zir_dest_type.toIndex()) |ptr_index|
|
||||
sema.code.instructions.items(.tag)[@intFromEnum(ptr_index)] == .ret_type
|
||||
|
|
|
|||
|
|
@ -251,3 +251,21 @@ test "load non byte-sized value in union" {
|
|||
try expect(pieces[1].type == .PAWN);
|
||||
try expect(pieces[1].color == .BLACK);
|
||||
}
|
||||
test "@as with nested @intCast in loop with optional" {
|
||||
// Regression test for circular dependency bug in Sema.analyzeAs
|
||||
// where @as(DestType, @intCast(value)) would cause compilation timeout
|
||||
// in complex control flow contexts (loop + short-circuit OR + optional unwrap)
|
||||
const arr = [_]bool{ true, false, true };
|
||||
var opt: ?[]const bool = &arr;
|
||||
var pid: u32 = 1;
|
||||
_ = .{ &opt, &pid };
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 3) : (i += 1) {
|
||||
// This pattern previously caused infinite recursion during compilation
|
||||
if (opt == null or (opt.?)[@as(usize, @intCast(pid))] == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try expect(i == 0); // Should break immediately since arr[1] == false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue