master
  1const builtin = @import("builtin");
  2const std = @import("std");
  3const expect = std.testing.expect;
  4const expectEqual = std.testing.expectEqual;
  5
  6test "if statements" {
  7    shouldBeEqual(1, 1);
  8    firstEqlThird(2, 1, 2);
  9}
 10fn shouldBeEqual(a: i32, b: i32) void {
 11    if (a != b) {
 12        unreachable;
 13    } else {
 14        return;
 15    }
 16}
 17fn firstEqlThird(a: i32, b: i32, c: i32) void {
 18    if (a == b) {
 19        unreachable;
 20    } else if (b == c) {
 21        unreachable;
 22    } else if (a == c) {
 23        return;
 24    } else {
 25        unreachable;
 26    }
 27}
 28
 29test "else if expression" {
 30    try expect(elseIfExpressionF(1) == 1);
 31}
 32fn elseIfExpressionF(c: u8) u8 {
 33    if (c == 0) {
 34        return 0;
 35    } else if (c == 1) {
 36        return 1;
 37    } else {
 38        return @as(u8, 2);
 39    }
 40}
 41
 42// #2297
 43var global_with_val: anyerror!u32 = 0;
 44var global_with_err: anyerror!u32 = error.SomeError;
 45
 46test "unwrap mutable global var" {
 47    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 48
 49    if (global_with_val) |v| {
 50        try expect(v == 0);
 51    } else |_| {
 52        unreachable;
 53    }
 54    if (global_with_err) |_| {
 55        unreachable;
 56    } else |e| {
 57        try expect(e == error.SomeError);
 58    }
 59}
 60
 61test "labeled break inside comptime if inside runtime if" {
 62    var answer: i32 = 0;
 63    var c = true;
 64    _ = &c;
 65    if (c) {
 66        answer = if (true) blk: {
 67            break :blk @as(i32, 42);
 68        };
 69    }
 70    try expect(answer == 42);
 71}
 72
 73test "const result loc, runtime if cond, else unreachable" {
 74    const Num = enum { One, Two };
 75
 76    var t = true;
 77    _ = &t;
 78    const x = if (t) Num.Two else unreachable;
 79    try expect(x == .Two);
 80}
 81
 82test "if copies its payload" {
 83    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 84    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 85
 86    const S = struct {
 87        fn doTheTest() !void {
 88            var tmp: ?i32 = 10;
 89            if (tmp) |value| {
 90                // Modify the original variable
 91                tmp = null;
 92                try expect(value == 10);
 93            } else unreachable;
 94        }
 95    };
 96    try S.doTheTest();
 97    try comptime S.doTheTest();
 98}
 99
100test "if prongs cast to expected type instead of peer type resolution" {
101    const S = struct {
102        fn doTheTest(f: bool) !void {
103            var x: i32 = 0;
104            x = if (f) 1 else 2;
105            try expect(x == 2);
106
107            var b = true;
108            _ = &b;
109            const y: i32 = if (b) 1 else 2;
110            try expect(y == 1);
111        }
112    };
113    try S.doTheTest(false);
114    try comptime S.doTheTest(false);
115}
116
117test "if peer expressions inferred optional type" {
118    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
119    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
121
122    var self: []const u8 = "abcdef";
123    var index: usize = 0;
124    _ = .{ &self, &index };
125    const left_index = (index << 1) + 1;
126    const right_index = left_index + 1;
127    const left = if (left_index < self.len) self[left_index] else null;
128    const right = if (right_index < self.len) self[right_index] else null;
129    try expect(left_index < self.len);
130    try expect(right_index < self.len);
131    try expect(left.? == 98);
132    try expect(right.? == 99);
133}
134
135test "if-else expression with runtime condition result location is inferred optional" {
136    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
137    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138
139    const A = struct { b: u64, c: u64 };
140    var d: bool = true;
141    _ = &d;
142    const e = if (d) A{ .b = 15, .c = 30 } else null;
143    try expect(e != null);
144}
145
146test "result location with inferred type ends up being pointer to comptime_int" {
147    var a: ?u32 = 1234;
148    var b: u32 = 2000;
149    _ = .{ &a, &b };
150    const c = if (a) |d| blk: {
151        if (d < b) break :blk @as(u32, 1);
152        break :blk 0;
153    } else @as(u32, 0);
154    try expect(c == 1);
155}
156
157test "if-@as-if chain" {
158    var fast = true;
159    var very_fast = false;
160    _ = .{ &fast, &very_fast };
161
162    const num_frames = if (fast)
163        @as(u32, if (very_fast) 16 else 4)
164    else
165        1;
166
167    try expect(num_frames == 4);
168}
169
170fn returnTrue() bool {
171    return true;
172}
173
174test "if value shouldn't be load-elided if used later (structs)" {
175    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176
177    const Foo = struct { x: i32 };
178
179    var a = Foo{ .x = 1 };
180    var b = Foo{ .x = 1 };
181
182    const c = if (@call(.never_inline, returnTrue, .{})) a else b;
183    // The second variable is superfluous with the current
184    // state of codegen optimizations, but in future
185    // "if (smthg) a else a" may be optimized simply into "a".
186
187    a.x = 2;
188    b.x = 3;
189
190    try std.testing.expectEqual(c.x, 1);
191}
192
193test "if value shouldn't be load-elided if used later (optionals)" {
194    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
195
196    var a: ?i32 = 1;
197    var b: ?i32 = 1;
198
199    const c = if (@call(.never_inline, returnTrue, .{})) a else b;
200
201    a = 2;
202    b = 3;
203
204    try std.testing.expectEqual(c, 1);
205}
206
207test "variable type inferred from if expression" {
208    var a = if (true) {
209        return;
210    } else true;
211    _ = &a;
212    return error.TestFailed;
213}