| author | |
| committer | |
| log | 1e5a494603d287ea3005dc35f0528c0311f43515 |
| tree | 7e5d6799a59ca44dc11d6b280dcd4f622ef0ca42 |
| parent | 7f0cf395aa74eb5ea250bd28f7525b3036790a6a |
and error union payload5 files changed, 232 insertions(+), 140 deletions(-)
src/Sema.zig+68-2| ... | @@ -15069,8 +15069,74 @@ fn beginComptimePtrMutation( | ... | @@ -15069,8 +15069,74 @@ fn beginComptimePtrMutation( |
| 15069 | else => unreachable, | 15069 | else => unreachable, |
| 15070 | } | 15070 | } |
| 15071 | }, | 15071 | }, |
| 15072 | .eu_payload_ptr => return sema.fail(block, src, "TODO comptime store to eu_payload_ptr", .{}), | 15072 | .eu_payload_ptr => { |
| 15073 | .opt_payload_ptr => return sema.fail(block, src, "TODO comptime store opt_payload_ptr", .{}), | 15073 | const eu_ptr_val = ptr_val.castTag(.eu_payload_ptr).?.data; |
| 15074 | var parent = try beginComptimePtrMutation(sema, block, src, eu_ptr_val); | ||
| 15075 | const payload_ty = parent.ty.errorUnionPayload(); | ||
| 15076 | switch (parent.val.tag()) { | ||
| 15077 | else => { | ||
| 15078 | // An error union has been initialized to undefined at comptime and now we | ||
| 15079 | // are for the first time setting the payload. We must change the | ||
| 15080 | // representation of the error union from `undef` to `opt_payload`. | ||
| 15081 | const arena = parent.beginArena(sema.gpa); | ||
| 15082 | defer parent.finishArena(); | ||
| 15083 | |||
| 15084 | const payload = try arena.create(Value.Payload.SubValue); | ||
| 15085 | payload.* = .{ | ||
| 15086 | .base = .{ .tag = .eu_payload }, | ||
| 15087 | .data = Value.undef, | ||
| 15088 | }; | ||
| 15089 | |||
| 15090 | parent.val.* = Value.initPayload(&payload.base); | ||
| 15091 | |||
| 15092 | return ComptimePtrMutationKit{ | ||
| 15093 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 15094 | .val = &payload.data, | ||
| 15095 | .ty = payload_ty, | ||
| 15096 | }; | ||
| 15097 | }, | ||
| 15098 | .eu_payload => return ComptimePtrMutationKit{ | ||
| 15099 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 15100 | .val = &parent.val.castTag(.eu_payload).?.data, | ||
| 15101 | .ty = payload_ty, | ||
| 15102 | }, | ||
| 15103 | } | ||
| 15104 | }, | ||
| 15105 | .opt_payload_ptr => { | ||
| 15106 | const opt_ptr_val = ptr_val.castTag(.opt_payload_ptr).?.data; | ||
| 15107 | var parent = try beginComptimePtrMutation(sema, block, src, opt_ptr_val); | ||
| 15108 | const payload_ty = try parent.ty.optionalChildAlloc(sema.arena); | ||
| 15109 | switch (parent.val.tag()) { | ||
| 15110 | .undef, .null_value => { | ||
| 15111 | // An optional has been initialized to undefined at comptime and now we | ||
| 15112 | // are for the first time setting the payload. We must change the | ||
| 15113 | // representation of the optional from `undef` to `opt_payload`. | ||
| 15114 | const arena = parent.beginArena(sema.gpa); | ||
| 15115 | defer parent.finishArena(); | ||
| 15116 | |||
| 15117 | const payload = try arena.create(Value.Payload.SubValue); | ||
| 15118 | payload.* = .{ | ||
| 15119 | .base = .{ .tag = .opt_payload }, | ||
| 15120 | .data = Value.undef, | ||
| 15121 | }; | ||
| 15122 | |||
| 15123 | parent.val.* = Value.initPayload(&payload.base); | ||
| 15124 | |||
| 15125 | return ComptimePtrMutationKit{ | ||
| 15126 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 15127 | .val = &payload.data, | ||
| 15128 | .ty = payload_ty, | ||
| 15129 | }; | ||
| 15130 | }, | ||
| 15131 | .opt_payload => return ComptimePtrMutationKit{ | ||
| 15132 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 15133 | .val = &parent.val.castTag(.opt_payload).?.data, | ||
| 15134 | .ty = payload_ty, | ||
| 15135 | }, | ||
| 15136 | |||
| 15137 | else => unreachable, | ||
| 15138 | } | ||
| 15139 | }, | ||
| 15074 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already | 15140 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already |
| 15075 | else => unreachable, | 15141 | else => unreachable, |
| 15076 | } | 15142 | } |
test/behavior.zig+1-3| ... | @@ -33,7 +33,7 @@ test { | ... | @@ -33,7 +33,7 @@ test { |
| 33 | _ = @import("behavior/hasdecl.zig"); | 33 | _ = @import("behavior/hasdecl.zig"); |
| 34 | _ = @import("behavior/hasfield.zig"); | 34 | _ = @import("behavior/hasfield.zig"); |
| 35 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | 35 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); |
| 36 | _ = @import("behavior/optional_llvm.zig"); | 36 | _ = @import("behavior/optional.zig"); |
| 37 | _ = @import("behavior/prefetch.zig"); | 37 | _ = @import("behavior/prefetch.zig"); |
| 38 | _ = @import("behavior/pub_enum.zig"); | 38 | _ = @import("behavior/pub_enum.zig"); |
| 39 | _ = @import("behavior/slice_sentinel_comptime.zig"); | 39 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| ... | @@ -69,7 +69,6 @@ test { | ... | @@ -69,7 +69,6 @@ test { |
| 69 | _ = @import("behavior/inttoptr.zig"); | 69 | _ = @import("behavior/inttoptr.zig"); |
| 70 | _ = @import("behavior/member_func.zig"); | 70 | _ = @import("behavior/member_func.zig"); |
| 71 | _ = @import("behavior/null.zig"); | 71 | _ = @import("behavior/null.zig"); |
| 72 | _ = @import("behavior/optional.zig"); | ||
| 73 | _ = @import("behavior/pointers.zig"); | 72 | _ = @import("behavior/pointers.zig"); |
| 74 | _ = @import("behavior/ptrcast.zig"); | 73 | _ = @import("behavior/ptrcast.zig"); |
| 75 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 74 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| ... | @@ -154,7 +153,6 @@ test { | ... | @@ -154,7 +153,6 @@ test { |
| 154 | _ = @import("behavior/ir_block_deps.zig"); | 153 | _ = @import("behavior/ir_block_deps.zig"); |
| 155 | _ = @import("behavior/misc.zig"); | 154 | _ = @import("behavior/misc.zig"); |
| 156 | _ = @import("behavior/muladd.zig"); | 155 | _ = @import("behavior/muladd.zig"); |
| 157 | _ = @import("behavior/optional_stage1.zig"); | ||
| 158 | _ = @import("behavior/popcount_stage1.zig"); | 156 | _ = @import("behavior/popcount_stage1.zig"); |
| 159 | _ = @import("behavior/reflection.zig"); | 157 | _ = @import("behavior/reflection.zig"); |
| 160 | _ = @import("behavior/select.zig"); | 158 | _ = @import("behavior/select.zig"); |
test/behavior/optional.zig+163| ... | @@ -1,9 +1,13 @@ | ... | @@ -1,9 +1,13 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("std"); | 2 | const std = @import("std"); |
| 2 | const testing = std.testing; | 3 | const testing = std.testing; |
| 3 | const expect = testing.expect; | 4 | const expect = testing.expect; |
| 4 | const expectEqual = testing.expectEqual; | 5 | const expectEqual = testing.expectEqual; |
| 5 | 6 | ||
| 6 | test "passing an optional integer as a parameter" { | 7 | test "passing an optional integer as a parameter" { |
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 9 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 10 | |||
| 7 | const S = struct { | 11 | const S = struct { |
| 8 | fn entry() bool { | 12 | fn entry() bool { |
| 9 | var x: i32 = 1234; | 13 | var x: i32 = 1234; |
| ... | @@ -21,12 +25,18 @@ test "passing an optional integer as a parameter" { | ... | @@ -21,12 +25,18 @@ test "passing an optional integer as a parameter" { |
| 21 | pub const EmptyStruct = struct {}; | 25 | pub const EmptyStruct = struct {}; |
| 22 | 26 | ||
| 23 | test "optional pointer to size zero struct" { | 27 | test "optional pointer to size zero struct" { |
| 28 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 29 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 30 | |||
| 24 | var e = EmptyStruct{}; | 31 | var e = EmptyStruct{}; |
| 25 | var o: ?*EmptyStruct = &e; | 32 | var o: ?*EmptyStruct = &e; |
| 26 | try expect(o != null); | 33 | try expect(o != null); |
| 27 | } | 34 | } |
| 28 | 35 | ||
| 29 | test "equality compare optional pointers" { | 36 | test "equality compare optional pointers" { |
| 37 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 38 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 39 | |||
| 30 | try testNullPtrsEql(); | 40 | try testNullPtrsEql(); |
| 31 | comptime try testNullPtrsEql(); | 41 | comptime try testNullPtrsEql(); |
| 32 | } | 42 | } |
| ... | @@ -48,6 +58,9 @@ fn testNullPtrsEql() !void { | ... | @@ -48,6 +58,9 @@ fn testNullPtrsEql() !void { |
| 48 | } | 58 | } |
| 49 | 59 | ||
| 50 | test "optional with void type" { | 60 | test "optional with void type" { |
| 61 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 62 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 63 | |||
| 51 | const Foo = struct { | 64 | const Foo = struct { |
| 52 | x: ?void, | 65 | x: ?void, |
| 53 | }; | 66 | }; |
| ... | @@ -56,6 +69,9 @@ test "optional with void type" { | ... | @@ -56,6 +69,9 @@ test "optional with void type" { |
| 56 | } | 69 | } |
| 57 | 70 | ||
| 58 | test "address of unwrap optional" { | 71 | test "address of unwrap optional" { |
| 72 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 73 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 74 | |||
| 59 | const S = struct { | 75 | const S = struct { |
| 60 | const Foo = struct { | 76 | const Foo = struct { |
| 61 | a: i32, | 77 | a: i32, |
| ... | @@ -73,6 +89,9 @@ test "address of unwrap optional" { | ... | @@ -73,6 +89,9 @@ test "address of unwrap optional" { |
| 73 | } | 89 | } |
| 74 | 90 | ||
| 75 | test "nested optional field in struct" { | 91 | test "nested optional field in struct" { |
| 92 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 93 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 94 | |||
| 76 | const S2 = struct { | 95 | const S2 = struct { |
| 77 | y: u8, | 96 | y: u8, |
| 78 | }; | 97 | }; |
| ... | @@ -86,6 +105,9 @@ test "nested optional field in struct" { | ... | @@ -86,6 +105,9 @@ test "nested optional field in struct" { |
| 86 | } | 105 | } |
| 87 | 106 | ||
| 88 | test "equality compare optional with non-optional" { | 107 | test "equality compare optional with non-optional" { |
| 108 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 109 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 110 | |||
| 89 | try test_cmp_optional_non_optional(); | 111 | try test_cmp_optional_non_optional(); |
| 90 | comptime try test_cmp_optional_non_optional(); | 112 | comptime try test_cmp_optional_non_optional(); |
| 91 | } | 113 | } |
| ... | @@ -120,6 +142,9 @@ fn test_cmp_optional_non_optional() !void { | ... | @@ -120,6 +142,9 @@ fn test_cmp_optional_non_optional() !void { |
| 120 | } | 142 | } |
| 121 | 143 | ||
| 122 | test "unwrap function call with optional pointer return value" { | 144 | test "unwrap function call with optional pointer return value" { |
| 145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 146 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 147 | |||
| 123 | const S = struct { | 148 | const S = struct { |
| 124 | fn entry() !void { | 149 | fn entry() !void { |
| 125 | try expect(foo().?.* == 1234); | 150 | try expect(foo().?.* == 1234); |
| ... | @@ -138,6 +163,9 @@ test "unwrap function call with optional pointer return value" { | ... | @@ -138,6 +163,9 @@ test "unwrap function call with optional pointer return value" { |
| 138 | } | 163 | } |
| 139 | 164 | ||
| 140 | test "nested orelse" { | 165 | test "nested orelse" { |
| 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 167 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 168 | |||
| 141 | const S = struct { | 169 | const S = struct { |
| 142 | fn entry() !void { | 170 | fn entry() !void { |
| 143 | try expect(func() == null); | 171 | try expect(func() == null); |
| ... | @@ -159,3 +187,138 @@ test "nested orelse" { | ... | @@ -159,3 +187,138 @@ test "nested orelse" { |
| 159 | try S.entry(); | 187 | try S.entry(); |
| 160 | comptime try S.entry(); | 188 | comptime try S.entry(); |
| 161 | } | 189 | } |
| 190 | |||
| 191 | test "self-referential struct through a slice of optional" { | ||
| 192 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 193 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 194 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 195 | |||
| 196 | const S = struct { | ||
| 197 | const Node = struct { | ||
| 198 | children: []?Node, | ||
| 199 | data: ?u8, | ||
| 200 | |||
| 201 | fn new() Node { | ||
| 202 | return Node{ | ||
| 203 | .children = undefined, | ||
| 204 | .data = null, | ||
| 205 | }; | ||
| 206 | } | ||
| 207 | }; | ||
| 208 | }; | ||
| 209 | |||
| 210 | var n = S.Node.new(); | ||
| 211 | try expect(n.data == null); | ||
| 212 | } | ||
| 213 | |||
| 214 | test "assigning to an unwrapped optional field in an inline loop" { | ||
| 215 | comptime var maybe_pos_arg: ?comptime_int = null; | ||
| 216 | inline for ("ab") |x| { | ||
| 217 | _ = x; | ||
| 218 | maybe_pos_arg = 0; | ||
| 219 | if (maybe_pos_arg.? != 0) { | ||
| 220 | @compileError("bad"); | ||
| 221 | } | ||
| 222 | maybe_pos_arg.? = 10; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | test "coerce an anon struct literal to optional struct" { | ||
| 227 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 228 | |||
| 229 | const S = struct { | ||
| 230 | const Struct = struct { | ||
| 231 | field: u32, | ||
| 232 | }; | ||
| 233 | fn doTheTest() !void { | ||
| 234 | var maybe_dims: ?Struct = null; | ||
| 235 | maybe_dims = .{ .field = 1 }; | ||
| 236 | try expect(maybe_dims.?.field == 1); | ||
| 237 | } | ||
| 238 | }; | ||
| 239 | try S.doTheTest(); | ||
| 240 | comptime try S.doTheTest(); | ||
| 241 | } | ||
| 242 | |||
| 243 | test "0-bit child type coerced to optional return ptr result location" { | ||
| 244 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 245 | |||
| 246 | const S = struct { | ||
| 247 | fn doTheTest() !void { | ||
| 248 | var y = Foo{}; | ||
| 249 | var z = y.thing(); | ||
| 250 | try expect(z != null); | ||
| 251 | } | ||
| 252 | |||
| 253 | const Foo = struct { | ||
| 254 | pub const Bar = struct { | ||
| 255 | field: *Foo, | ||
| 256 | }; | ||
| 257 | |||
| 258 | pub fn thing(self: *Foo) ?Bar { | ||
| 259 | return Bar{ .field = self }; | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | }; | ||
| 263 | try S.doTheTest(); | ||
| 264 | comptime try S.doTheTest(); | ||
| 265 | } | ||
| 266 | |||
| 267 | test "0-bit child type coerced to optional" { | ||
| 268 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 269 | |||
| 270 | const S = struct { | ||
| 271 | fn doTheTest() !void { | ||
| 272 | var it: Foo = .{ | ||
| 273 | .list = undefined, | ||
| 274 | }; | ||
| 275 | try expect(it.foo() != null); | ||
| 276 | } | ||
| 277 | |||
| 278 | const Empty = struct {}; | ||
| 279 | const Foo = struct { | ||
| 280 | list: [10]Empty, | ||
| 281 | |||
| 282 | fn foo(self: *Foo) ?*Empty { | ||
| 283 | const data = &self.list[0]; | ||
| 284 | return data; | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | }; | ||
| 288 | try S.doTheTest(); | ||
| 289 | comptime try S.doTheTest(); | ||
| 290 | } | ||
| 291 | |||
| 292 | test "array of optional unaligned types" { | ||
| 293 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 294 | |||
| 295 | const Enum = enum { one, two, three }; | ||
| 296 | |||
| 297 | const SomeUnion = union(enum) { | ||
| 298 | Num: Enum, | ||
| 299 | Other: u32, | ||
| 300 | }; | ||
| 301 | |||
| 302 | const values = [_]?SomeUnion{ | ||
| 303 | SomeUnion{ .Num = .one }, | ||
| 304 | SomeUnion{ .Num = .two }, | ||
| 305 | SomeUnion{ .Num = .three }, | ||
| 306 | SomeUnion{ .Num = .one }, | ||
| 307 | SomeUnion{ .Num = .two }, | ||
| 308 | SomeUnion{ .Num = .three }, | ||
| 309 | }; | ||
| 310 | |||
| 311 | // The index must be a runtime value | ||
| 312 | var i: usize = 0; | ||
| 313 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 314 | i += 1; | ||
| 315 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 316 | i += 1; | ||
| 317 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 318 | i += 1; | ||
| 319 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 320 | i += 1; | ||
| 321 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 322 | i += 1; | ||
| 323 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 324 | } |
test/behavior/optional_llvm.zig deleted-27| ... | @@ -1,27 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | |||
| 7 | test "self-referential struct through a slice of optional" { | ||
| 8 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | ||
| 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 10 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 11 | const S = struct { | ||
| 12 | const Node = struct { | ||
| 13 | children: []?Node, | ||
| 14 | data: ?u8, | ||
| 15 | |||
| 16 | fn new() Node { | ||
| 17 | return Node{ | ||
| 18 | .children = undefined, | ||
| 19 | .data = null, | ||
| 20 | }; | ||
| 21 | } | ||
| 22 | }; | ||
| 23 | }; | ||
| 24 | |||
| 25 | var n = S.Node.new(); | ||
| 26 | try expect(n.data == null); | ||
| 27 | } | ||
test/behavior/optional_stage1.zig deleted-108| ... | @@ -1,108 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 5 | |||
| 6 | test "assigning to an unwrapped optional field in an inline loop" { | ||
| 7 | comptime var maybe_pos_arg: ?comptime_int = null; | ||
| 8 | inline for ("ab") |x| { | ||
| 9 | _ = x; | ||
| 10 | maybe_pos_arg = 0; | ||
| 11 | if (maybe_pos_arg.? != 0) { | ||
| 12 | @compileError("bad"); | ||
| 13 | } | ||
| 14 | maybe_pos_arg.? = 10; | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | test "coerce an anon struct literal to optional struct" { | ||
| 19 | const S = struct { | ||
| 20 | const Struct = struct { | ||
| 21 | field: u32, | ||
| 22 | }; | ||
| 23 | fn doTheTest() !void { | ||
| 24 | var maybe_dims: ?Struct = null; | ||
| 25 | maybe_dims = .{ .field = 1 }; | ||
| 26 | try expect(maybe_dims.?.field == 1); | ||
| 27 | } | ||
| 28 | }; | ||
| 29 | try S.doTheTest(); | ||
| 30 | comptime try S.doTheTest(); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "0-bit child type coerced to optional return ptr result location" { | ||
| 34 | const S = struct { | ||
| 35 | fn doTheTest() !void { | ||
| 36 | var y = Foo{}; | ||
| 37 | var z = y.thing(); | ||
| 38 | try expect(z != null); | ||
| 39 | } | ||
| 40 | |||
| 41 | const Foo = struct { | ||
| 42 | pub const Bar = struct { | ||
| 43 | field: *Foo, | ||
| 44 | }; | ||
| 45 | |||
| 46 | pub fn thing(self: *Foo) ?Bar { | ||
| 47 | return Bar{ .field = self }; | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | try S.doTheTest(); | ||
| 52 | comptime try S.doTheTest(); | ||
| 53 | } | ||
| 54 | |||
| 55 | test "0-bit child type coerced to optional" { | ||
| 56 | const S = struct { | ||
| 57 | fn doTheTest() !void { | ||
| 58 | var it: Foo = .{ | ||
| 59 | .list = undefined, | ||
| 60 | }; | ||
| 61 | try expect(it.foo() != null); | ||
| 62 | } | ||
| 63 | |||
| 64 | const Empty = struct {}; | ||
| 65 | const Foo = struct { | ||
| 66 | list: [10]Empty, | ||
| 67 | |||
| 68 | fn foo(self: *Foo) ?*Empty { | ||
| 69 | const data = &self.list[0]; | ||
| 70 | return data; | ||
| 71 | } | ||
| 72 | }; | ||
| 73 | }; | ||
| 74 | try S.doTheTest(); | ||
| 75 | comptime try S.doTheTest(); | ||
| 76 | } | ||
| 77 | |||
| 78 | test "array of optional unaligned types" { | ||
| 79 | const Enum = enum { one, two, three }; | ||
| 80 | |||
| 81 | const SomeUnion = union(enum) { | ||
| 82 | Num: Enum, | ||
| 83 | Other: u32, | ||
| 84 | }; | ||
| 85 | |||
| 86 | const values = [_]?SomeUnion{ | ||
| 87 | SomeUnion{ .Num = .one }, | ||
| 88 | SomeUnion{ .Num = .two }, | ||
| 89 | SomeUnion{ .Num = .three }, | ||
| 90 | SomeUnion{ .Num = .one }, | ||
| 91 | SomeUnion{ .Num = .two }, | ||
| 92 | SomeUnion{ .Num = .three }, | ||
| 93 | }; | ||
| 94 | |||
| 95 | // The index must be a runtime value | ||
| 96 | var i: usize = 0; | ||
| 97 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 98 | i += 1; | ||
| 99 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 100 | i += 1; | ||
| 101 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 102 | i += 1; | ||
| 103 | try expectEqual(Enum.one, values[i].?.Num); | ||
| 104 | i += 1; | ||
| 105 | try expectEqual(Enum.two, values[i].?.Num); | ||
| 106 | i += 1; | ||
| 107 | try expectEqual(Enum.three, values[i].?.Num); | ||
| 108 | } | ||