From 7f41e20802fd8f9eb19c0218f1e2000e2751592a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 15 Jan 2022 23:13:44 -0700 Subject: [PATCH] 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. --- src/AstGen.zig | 25 +++++++++++++++++-------- test/behavior/array_llvm.zig | 14 ++++++++++++++ test/behavior/array_stage1.zig | 14 -------------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index 7c855fb62a..09d9b02a0e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -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 }; @@ -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), .float_literal => return floatLiteral(gz, rl, node), - .if_simple => return ifExpr(gz, scope, rl, node, tree.ifSimple(node)), - .@"if" => return ifExpr(gz, scope, rl, node, tree.ifFull(node)), + .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)), + .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)), - .while_simple => return whileExpr(gz, scope, rl, node, tree.whileSimple(node)), - .while_cont => return whileExpr(gz, scope, rl, node, tree.whileCont(node)), - .@"while" => return whileExpr(gz, scope, rl, node, tree.whileFull(node)), + .while_simple => return whileExpr(gz, scope, rl.br(), node, tree.whileSimple(node)), + .while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node)), + .@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(node)), - .for_simple => return forExpr(gz, scope, rl, node, tree.forSimple(node)), - .@"for" => return forExpr(gz, scope, rl, node, tree.forFull(node)), + .for_simple => return forExpr(gz, scope, rl.br(), node, tree.forSimple(node)), + .@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(node)), .slice_open => { 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), .array_access => return arrayAccess(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), .@"suspend" => return suspendExpr(gz, scope, node), diff --git a/test/behavior/array_llvm.zig b/test/behavior/array_llvm.zig index 5bbb06cffe..b4b0f1f268 100644 --- a/test/behavior/array_llvm.zig +++ b/test/behavior/array_llvm.zig @@ -179,3 +179,17 @@ test "access the null element of a null terminated array" { 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(); +} diff --git a/test/behavior/array_stage1.zig b/test/behavior/array_stage1.zig index 9344b3ee2b..272199312c 100644 --- a/test/behavior/array_stage1.zig +++ b/test/behavior/array_stage1.zig @@ -4,20 +4,6 @@ const mem = std.mem; const expect = testing.expect; 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" { const S = struct { fn doTheTest() !void {