mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 11:13:08 +00:00
AstGen: emit as instructions for branching expressions
There is a mechanism to avoid redundant `as` ZIR instructions which is to pass `ResultLoc.coerced_ty` instead of `ResultLoc.ty` when it is known by AstGen that Sema will do the coercion. This commit downgrades `coerced_ty` to `ty` when a result location passes through an expression that branches, such as `if`, `switch`, `while`, and `for`, causing the `as` ZIR instruction to be emitted. This ensures that the type of a result location will be applied to, e.g. a `comptime_int` on either side of a branch on a runtime condition.
This commit is contained in:
parent
7c6f5d26ea
commit
7f41e20802
@ -281,6 +281,15 @@ pub const ResultLoc = union(enum) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turns a `coerced_ty` back into a `ty`. Should be called at branch points
|
||||||
|
/// such as if and switch expressions.
|
||||||
|
fn br(rl: ResultLoc) ResultLoc {
|
||||||
|
return switch (rl) {
|
||||||
|
.coerced_ty => |ty| .{ .ty = ty },
|
||||||
|
else => rl,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const align_rl: ResultLoc = .{ .ty = .u16_type };
|
pub const align_rl: ResultLoc = .{ .ty = .u16_type };
|
||||||
@ -748,15 +757,15 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
.field_access => return fieldAccess(gz, scope, rl, node),
|
.field_access => return fieldAccess(gz, scope, rl, node),
|
||||||
.float_literal => return floatLiteral(gz, rl, node),
|
.float_literal => return floatLiteral(gz, rl, node),
|
||||||
|
|
||||||
.if_simple => return ifExpr(gz, scope, rl, node, tree.ifSimple(node)),
|
.if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)),
|
||||||
.@"if" => return ifExpr(gz, scope, rl, node, tree.ifFull(node)),
|
.@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)),
|
||||||
|
|
||||||
.while_simple => return whileExpr(gz, scope, rl, node, tree.whileSimple(node)),
|
.while_simple => return whileExpr(gz, scope, rl.br(), node, tree.whileSimple(node)),
|
||||||
.while_cont => return whileExpr(gz, scope, rl, node, tree.whileCont(node)),
|
.while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node)),
|
||||||
.@"while" => return whileExpr(gz, scope, rl, node, tree.whileFull(node)),
|
.@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(node)),
|
||||||
|
|
||||||
.for_simple => return forExpr(gz, scope, rl, node, tree.forSimple(node)),
|
.for_simple => return forExpr(gz, scope, rl.br(), node, tree.forSimple(node)),
|
||||||
.@"for" => return forExpr(gz, scope, rl, node, tree.forFull(node)),
|
.@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(node)),
|
||||||
|
|
||||||
.slice_open => {
|
.slice_open => {
|
||||||
const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
|
const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
|
||||||
@ -943,7 +952,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||||||
.error_set_decl => return errorSetDecl(gz, rl, node),
|
.error_set_decl => return errorSetDecl(gz, rl, node),
|
||||||
.array_access => return arrayAccess(gz, scope, rl, node),
|
.array_access => return arrayAccess(gz, scope, rl, node),
|
||||||
.@"comptime" => return comptimeExprAst(gz, scope, rl, node),
|
.@"comptime" => return comptimeExprAst(gz, scope, rl, node),
|
||||||
.@"switch", .switch_comma => return switchExpr(gz, scope, rl, node),
|
.@"switch", .switch_comma => return switchExpr(gz, scope, rl.br(), node),
|
||||||
|
|
||||||
.@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
|
.@"nosuspend" => return nosuspendExpr(gz, scope, rl, node),
|
||||||
.@"suspend" => return suspendExpr(gz, scope, node),
|
.@"suspend" => return suspendExpr(gz, scope, node),
|
||||||
|
|||||||
@ -179,3 +179,17 @@ test "access the null element of a null terminated array" {
|
|||||||
try S.doTheTest();
|
try S.doTheTest();
|
||||||
comptime try S.doTheTest();
|
comptime try S.doTheTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "type deduction for array subscript expression" {
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest() !void {
|
||||||
|
var array = [_]u8{ 0x55, 0xAA };
|
||||||
|
var v0 = true;
|
||||||
|
try expect(@as(u8, 0xAA) == array[if (v0) 1 else 0]);
|
||||||
|
var v1 = false;
|
||||||
|
try expect(@as(u8, 0x55) == array[if (v1) 1 else 0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try S.doTheTest();
|
||||||
|
comptime try S.doTheTest();
|
||||||
|
}
|
||||||
|
|||||||
@ -4,20 +4,6 @@ const mem = std.mem;
|
|||||||
const expect = testing.expect;
|
const expect = testing.expect;
|
||||||
const expectEqual = testing.expectEqual;
|
const expectEqual = testing.expectEqual;
|
||||||
|
|
||||||
test "type deduction for array subscript expression" {
|
|
||||||
const S = struct {
|
|
||||||
fn doTheTest() !void {
|
|
||||||
var array = [_]u8{ 0x55, 0xAA };
|
|
||||||
var v0 = true;
|
|
||||||
try expect(@as(u8, 0xAA) == array[if (v0) 1 else 0]);
|
|
||||||
var v1 = false;
|
|
||||||
try expect(@as(u8, 0x55) == array[if (v1) 1 else 0]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try S.doTheTest();
|
|
||||||
comptime try S.doTheTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
test "sentinel element count towards the ABI size calculation" {
|
test "sentinel element count towards the ABI size calculation" {
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user