| author | |
| committer | |
| log | 2b589d71fbcacb2e8bc8746dd4b675e57b3a53df |
| tree | 83fda2aa57b2f48c958a522a9393c4ba900943ef |
| parent | cb248898ab41378c2e9bcf94d05c7c42577a7bab |
9 files changed, 275 insertions(+), 275 deletions(-)
test/behavior.zig+1-1| ... | @@ -58,6 +58,7 @@ test { | ... | @@ -58,6 +58,7 @@ test { |
| 58 | _ = @import("behavior/floatop.zig"); | 58 | _ = @import("behavior/floatop.zig"); |
| 59 | _ = @import("behavior/fn.zig"); | 59 | _ = @import("behavior/fn.zig"); |
| 60 | _ = @import("behavior/for.zig"); | 60 | _ = @import("behavior/for.zig"); |
| 61 | _ = @import("behavior/generics_llvm.zig"); | ||
| 61 | _ = @import("behavior/math.zig"); | 62 | _ = @import("behavior/math.zig"); |
| 62 | _ = @import("behavior/maximum_minimum.zig"); | 63 | _ = @import("behavior/maximum_minimum.zig"); |
| 63 | _ = @import("behavior/null_llvm.zig"); | 64 | _ = @import("behavior/null_llvm.zig"); |
| ... | @@ -145,7 +146,6 @@ test { | ... | @@ -145,7 +146,6 @@ test { |
| 145 | _ = @import("behavior/fn_delegation.zig"); | 146 | _ = @import("behavior/fn_delegation.zig"); |
| 146 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); | 147 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); |
| 147 | _ = @import("behavior/for_stage1.zig"); | 148 | _ = @import("behavior/for_stage1.zig"); |
| 148 | _ = @import("behavior/generics_stage1.zig"); | ||
| 149 | _ = @import("behavior/if_stage1.zig"); | 149 | _ = @import("behavior/if_stage1.zig"); |
| 150 | _ = @import("behavior/import.zig"); | 150 | _ = @import("behavior/import.zig"); |
| 151 | _ = @import("behavior/incomplete_struct_param_tld.zig"); | 151 | _ = @import("behavior/incomplete_struct_param_tld.zig"); |
test/behavior/cast.zig+29| ... | @@ -266,3 +266,32 @@ test "array coersion to undefined at runtime" { | ... | @@ -266,3 +266,32 @@ test "array coersion to undefined at runtime" { |
| 266 | array = undefined; | 266 | array = undefined; |
| 267 | try expect(std.mem.eql(u8, &array, &undefined_val)); | 267 | try expect(std.mem.eql(u8, &array, &undefined_val)); |
| 268 | } | 268 | } |
| 269 | |||
| 270 | test "implicitly cast from int to anyerror!?T" { | ||
| 271 | implicitIntLitToOptional(); | ||
| 272 | comptime implicitIntLitToOptional(); | ||
| 273 | } | ||
| 274 | fn implicitIntLitToOptional() void { | ||
| 275 | const f: ?i32 = 1; | ||
| 276 | _ = f; | ||
| 277 | const g: anyerror!?i32 = 1; | ||
| 278 | _ = g catch {}; | ||
| 279 | } | ||
| 280 | |||
| 281 | test "return u8 coercing into ?u32 return type" { | ||
| 282 | const S = struct { | ||
| 283 | fn doTheTest() !void { | ||
| 284 | try expect(foo(123).? == 123); | ||
| 285 | } | ||
| 286 | fn foo(arg: u8) ?u32 { | ||
| 287 | return arg; | ||
| 288 | } | ||
| 289 | }; | ||
| 290 | try S.doTheTest(); | ||
| 291 | comptime try S.doTheTest(); | ||
| 292 | } | ||
| 293 | |||
| 294 | test "cast from ?[*]T to ??[*]T" { | ||
| 295 | const a: ??[*]u8 = @as(?[*]u8, null); | ||
| 296 | try expect(a != null and a.? == null); | ||
| 297 | } |
test/behavior/cast_llvm.zig+132| ... | @@ -65,3 +65,135 @@ test "implicit ptr to *c_void" { | ... | @@ -65,3 +65,135 @@ test "implicit ptr to *c_void" { |
| 65 | var c: *u32 = @ptrCast(*u32, ptr2.?); | 65 | var c: *u32 = @ptrCast(*u32, ptr2.?); |
| 66 | try expect(c.* == 1); | 66 | try expect(c.* == 1); |
| 67 | } | 67 | } |
| 68 | |||
| 69 | const A = struct { | ||
| 70 | a: i32, | ||
| 71 | }; | ||
| 72 | test "return null from fn() anyerror!?&T" { | ||
| 73 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 74 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 75 | try expect((try a) == null and (try b) == null); | ||
| 76 | } | ||
| 77 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 78 | const a: ?*A = null; | ||
| 79 | return a; | ||
| 80 | } | ||
| 81 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 82 | return null; | ||
| 83 | } | ||
| 84 | |||
| 85 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 86 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 87 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 88 | comptime { | ||
| 89 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 90 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 94 | if (a) { | ||
| 95 | return &[_]u8{}; | ||
| 96 | } | ||
| 97 | |||
| 98 | return slice[0..1]; | ||
| 99 | } | ||
| 100 | |||
| 101 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 102 | try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 103 | comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 104 | } | ||
| 105 | |||
| 106 | fn castToOptionalSlice() ?[]const u8 { | ||
| 107 | return "hi"; | ||
| 108 | } | ||
| 109 | |||
| 110 | test "cast u128 to f128 and back" { | ||
| 111 | comptime try testCast128(); | ||
| 112 | try testCast128(); | ||
| 113 | } | ||
| 114 | |||
| 115 | fn testCast128() !void { | ||
| 116 | try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 117 | } | ||
| 118 | |||
| 119 | fn cast128Int(x: f128) u128 { | ||
| 120 | return @bitCast(u128, x); | ||
| 121 | } | ||
| 122 | |||
| 123 | fn cast128Float(x: u128) f128 { | ||
| 124 | return @bitCast(f128, x); | ||
| 125 | } | ||
| 126 | |||
| 127 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 128 | var x: ?[*]u16 = null; | ||
| 129 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 130 | |||
| 131 | x = &y; | ||
| 132 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 133 | x.?[0] = 8; | ||
| 134 | y[3] = 6; | ||
| 135 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 136 | } | ||
| 137 | |||
| 138 | test "implicit cast from *T to ?*c_void" { | ||
| 139 | var a: u8 = 1; | ||
| 140 | incrementVoidPtrValue(&a); | ||
| 141 | try std.testing.expect(a == 2); | ||
| 142 | } | ||
| 143 | |||
| 144 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 145 | @ptrCast(*u8, value.?).* += 1; | ||
| 146 | } | ||
| 147 | |||
| 148 | test "implicit cast *[0]T to E![]const u8" { | ||
| 149 | var x = @as(anyerror![]const u8, &[0]u8{}); | ||
| 150 | try expect((x catch unreachable).len == 0); | ||
| 151 | } | ||
| 152 | |||
| 153 | var global_array: [4]u8 = undefined; | ||
| 154 | test "cast from array reference to fn" { | ||
| 155 | const f = @ptrCast(fn () callconv(.C) void, &global_array); | ||
| 156 | try expect(@ptrToInt(f) == @ptrToInt(&global_array)); | ||
| 157 | } | ||
| 158 | |||
| 159 | test "*const [N]null u8 to ?[]const u8" { | ||
| 160 | const S = struct { | ||
| 161 | fn doTheTest() !void { | ||
| 162 | var a = "Hello"; | ||
| 163 | var b: ?[]const u8 = a; | ||
| 164 | try expect(mem.eql(u8, b.?, "Hello")); | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | try S.doTheTest(); | ||
| 168 | comptime try S.doTheTest(); | ||
| 169 | } | ||
| 170 | |||
| 171 | test "cast between [*c]T and ?[*:0]T on fn parameter" { | ||
| 172 | const S = struct { | ||
| 173 | const Handler = ?fn ([*c]const u8) callconv(.C) void; | ||
| 174 | fn addCallback(handler: Handler) void { | ||
| 175 | _ = handler; | ||
| 176 | } | ||
| 177 | |||
| 178 | fn myCallback(cstr: ?[*:0]const u8) callconv(.C) void { | ||
| 179 | _ = cstr; | ||
| 180 | } | ||
| 181 | |||
| 182 | fn doTheTest() void { | ||
| 183 | addCallback(myCallback); | ||
| 184 | } | ||
| 185 | }; | ||
| 186 | S.doTheTest(); | ||
| 187 | } | ||
| 188 | |||
| 189 | var global_struct: struct { f0: usize } = undefined; | ||
| 190 | test "assignment to optional pointer result loc" { | ||
| 191 | var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; | ||
| 192 | try expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); | ||
| 193 | } | ||
| 194 | |||
| 195 | test "cast between *[N]void and []void" { | ||
| 196 | var a: [4]void = undefined; | ||
| 197 | var b: []void = &a; | ||
| 198 | try expect(b.len == 4); | ||
| 199 | } |
test/behavior/cast_stage1.zig-159| ... | @@ -58,55 +58,6 @@ fn castToOptionalTypeError(z: i32) !void { | ... | @@ -58,55 +58,6 @@ fn castToOptionalTypeError(z: i32) !void { |
| 58 | try expect((b catch unreachable).?.a == 1); | 58 | try expect((b catch unreachable).?.a == 1); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | test "implicitly cast from int to anyerror!?T" { | ||
| 62 | implicitIntLitToOptional(); | ||
| 63 | comptime implicitIntLitToOptional(); | ||
| 64 | } | ||
| 65 | fn implicitIntLitToOptional() void { | ||
| 66 | const f: ?i32 = 1; | ||
| 67 | _ = f; | ||
| 68 | const g: anyerror!?i32 = 1; | ||
| 69 | _ = g catch {}; | ||
| 70 | } | ||
| 71 | |||
| 72 | test "return null from fn() anyerror!?&T" { | ||
| 73 | const a = returnNullFromOptionalTypeErrorRef(); | ||
| 74 | const b = returnNullLitFromOptionalTypeErrorRef(); | ||
| 75 | try expect((try a) == null and (try b) == null); | ||
| 76 | } | ||
| 77 | fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 78 | const a: ?*A = null; | ||
| 79 | return a; | ||
| 80 | } | ||
| 81 | fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { | ||
| 82 | return null; | ||
| 83 | } | ||
| 84 | |||
| 85 | test "peer type resolution: [0]u8 and []const u8" { | ||
| 86 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 87 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 88 | comptime { | ||
| 89 | try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); | ||
| 90 | try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { | ||
| 94 | if (a) { | ||
| 95 | return &[_]u8{}; | ||
| 96 | } | ||
| 97 | |||
| 98 | return slice[0..1]; | ||
| 99 | } | ||
| 100 | |||
| 101 | test "implicitly cast from [N]T to ?[]const T" { | ||
| 102 | try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 103 | comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); | ||
| 104 | } | ||
| 105 | |||
| 106 | fn castToOptionalSlice() ?[]const u8 { | ||
| 107 | return "hi"; | ||
| 108 | } | ||
| 109 | |||
| 110 | test "implicitly cast from [0]T to anyerror![]T" { | 61 | test "implicitly cast from [0]T to anyerror![]T" { |
| 111 | try testCastZeroArrayToErrSliceMut(); | 62 | try testCastZeroArrayToErrSliceMut(); |
| 112 | comptime try testCastZeroArrayToErrSliceMut(); | 63 | comptime try testCastZeroArrayToErrSliceMut(); |
| ... | @@ -191,23 +142,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { | ... | @@ -191,23 +142,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { |
| 191 | }; | 142 | }; |
| 192 | } | 143 | } |
| 193 | 144 | ||
| 194 | test "cast u128 to f128 and back" { | ||
| 195 | comptime try testCast128(); | ||
| 196 | try testCast128(); | ||
| 197 | } | ||
| 198 | |||
| 199 | fn testCast128() !void { | ||
| 200 | try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); | ||
| 201 | } | ||
| 202 | |||
| 203 | fn cast128Int(x: f128) u128 { | ||
| 204 | return @bitCast(u128, x); | ||
| 205 | } | ||
| 206 | |||
| 207 | fn cast128Float(x: u128) f128 { | ||
| 208 | return @bitCast(f128, x); | ||
| 209 | } | ||
| 210 | |||
| 211 | test "single-item pointer of array to slice to unknown length pointer" { | 145 | test "single-item pointer of array to slice to unknown length pointer" { |
| 212 | try testCastPtrOfArrayToSliceAndPtr(); | 146 | try testCastPtrOfArrayToSliceAndPtr(); |
| 213 | comptime try testCastPtrOfArrayToSliceAndPtr(); | 147 | comptime try testCastPtrOfArrayToSliceAndPtr(); |
| ... | @@ -316,27 +250,6 @@ test "@floatCast cast down" { | ... | @@ -316,27 +250,6 @@ test "@floatCast cast down" { |
| 316 | } | 250 | } |
| 317 | } | 251 | } |
| 318 | 252 | ||
| 319 | test "implicit cast from *[N]T to ?[*]T" { | ||
| 320 | var x: ?[*]u16 = null; | ||
| 321 | var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; | ||
| 322 | |||
| 323 | x = &y; | ||
| 324 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 325 | x.?[0] = 8; | ||
| 326 | y[3] = 6; | ||
| 327 | try expect(std.mem.eql(u16, x.?[0..4], y[0..4])); | ||
| 328 | } | ||
| 329 | |||
| 330 | test "implicit cast from *T to ?*c_void" { | ||
| 331 | var a: u8 = 1; | ||
| 332 | incrementVoidPtrValue(&a); | ||
| 333 | try std.testing.expect(a == 2); | ||
| 334 | } | ||
| 335 | |||
| 336 | fn incrementVoidPtrValue(value: ?*c_void) void { | ||
| 337 | @ptrCast(*u8, value.?).* += 1; | ||
| 338 | } | ||
| 339 | |||
| 340 | test "peer type resolution: unreachable, null, slice" { | 253 | test "peer type resolution: unreachable, null, slice" { |
| 341 | const S = struct { | 254 | const S = struct { |
| 342 | fn doTheTest(num: usize, word: []const u8) !void { | 255 | fn doTheTest(num: usize, word: []const u8) !void { |
| ... | @@ -374,11 +287,6 @@ test "peer type resolution: unreachable, error set, unreachable" { | ... | @@ -374,11 +287,6 @@ test "peer type resolution: unreachable, error set, unreachable" { |
| 374 | try expect(transformed_err == error.SystemResources); | 287 | try expect(transformed_err == error.SystemResources); |
| 375 | } | 288 | } |
| 376 | 289 | ||
| 377 | test "implicit cast *[0]T to E![]const u8" { | ||
| 378 | var x = @as(anyerror![]const u8, &[0]u8{}); | ||
| 379 | try expect((x catch unreachable).len == 0); | ||
| 380 | } | ||
| 381 | |||
| 382 | test "peer cast *[0]T to E![]const T" { | 290 | test "peer cast *[0]T to E![]const T" { |
| 383 | var buffer: [5]u8 = "abcde".*; | 291 | var buffer: [5]u8 = "abcde".*; |
| 384 | var buf: anyerror![]const u8 = buffer[0..]; | 292 | var buf: anyerror![]const u8 = buffer[0..]; |
| ... | @@ -395,24 +303,6 @@ test "peer cast *[0]T to []const T" { | ... | @@ -395,24 +303,6 @@ test "peer cast *[0]T to []const T" { |
| 395 | try expect(mem.eql(u8, "abcde", y)); | 303 | try expect(mem.eql(u8, "abcde", y)); |
| 396 | } | 304 | } |
| 397 | 305 | ||
| 398 | var global_array: [4]u8 = undefined; | ||
| 399 | test "cast from array reference to fn" { | ||
| 400 | const f = @ptrCast(fn () callconv(.C) void, &global_array); | ||
| 401 | try expect(@ptrToInt(f) == @ptrToInt(&global_array)); | ||
| 402 | } | ||
| 403 | |||
| 404 | test "*const [N]null u8 to ?[]const u8" { | ||
| 405 | const S = struct { | ||
| 406 | fn doTheTest() !void { | ||
| 407 | var a = "Hello"; | ||
| 408 | var b: ?[]const u8 = a; | ||
| 409 | try expect(mem.eql(u8, b.?, "Hello")); | ||
| 410 | } | ||
| 411 | }; | ||
| 412 | try S.doTheTest(); | ||
| 413 | comptime try S.doTheTest(); | ||
| 414 | } | ||
| 415 | |||
| 416 | test "peer resolution of string literals" { | 306 | test "peer resolution of string literals" { |
| 417 | const S = struct { | 307 | const S = struct { |
| 418 | const E = enum { a, b, c, d }; | 308 | const E = enum { a, b, c, d }; |
| ... | @@ -502,19 +392,6 @@ test "cast i8 fn call peers to i32 result" { | ... | @@ -502,19 +392,6 @@ test "cast i8 fn call peers to i32 result" { |
| 502 | comptime try S.doTheTest(); | 392 | comptime try S.doTheTest(); |
| 503 | } | 393 | } |
| 504 | 394 | ||
| 505 | test "return u8 coercing into ?u32 return type" { | ||
| 506 | const S = struct { | ||
| 507 | fn doTheTest() !void { | ||
| 508 | try expect(foo(123).? == 123); | ||
| 509 | } | ||
| 510 | fn foo(arg: u8) ?u32 { | ||
| 511 | return arg; | ||
| 512 | } | ||
| 513 | }; | ||
| 514 | try S.doTheTest(); | ||
| 515 | comptime try S.doTheTest(); | ||
| 516 | } | ||
| 517 | |||
| 518 | test "peer type resolution implicit cast to return type" { | 395 | test "peer type resolution implicit cast to return type" { |
| 519 | const S = struct { | 396 | const S = struct { |
| 520 | fn doTheTest() !void { | 397 | fn doTheTest() !void { |
| ... | @@ -553,24 +430,6 @@ test "variable initialization uses result locations properly with regards to the | ... | @@ -553,24 +430,6 @@ test "variable initialization uses result locations properly with regards to the |
| 553 | try expect(x == 1); | 430 | try expect(x == 1); |
| 554 | } | 431 | } |
| 555 | 432 | ||
| 556 | test "cast between [*c]T and ?[*:0]T on fn parameter" { | ||
| 557 | const S = struct { | ||
| 558 | const Handler = ?fn ([*c]const u8) callconv(.C) void; | ||
| 559 | fn addCallback(handler: Handler) void { | ||
| 560 | _ = handler; | ||
| 561 | } | ||
| 562 | |||
| 563 | fn myCallback(cstr: ?[*:0]const u8) callconv(.C) void { | ||
| 564 | _ = cstr; | ||
| 565 | } | ||
| 566 | |||
| 567 | fn doTheTest() void { | ||
| 568 | addCallback(myCallback); | ||
| 569 | } | ||
| 570 | }; | ||
| 571 | S.doTheTest(); | ||
| 572 | } | ||
| 573 | |||
| 574 | test "cast between C pointer with different but compatible types" { | 433 | test "cast between C pointer with different but compatible types" { |
| 575 | const S = struct { | 434 | const S = struct { |
| 576 | fn foo(arg: [*]c_ushort) u16 { | 435 | fn foo(arg: [*]c_ushort) u16 { |
| ... | @@ -584,13 +443,6 @@ test "cast between C pointer with different but compatible types" { | ... | @@ -584,13 +443,6 @@ test "cast between C pointer with different but compatible types" { |
| 584 | try S.doTheTest(); | 443 | try S.doTheTest(); |
| 585 | } | 444 | } |
| 586 | 445 | ||
| 587 | var global_struct: struct { f0: usize } = undefined; | ||
| 588 | |||
| 589 | test "assignment to optional pointer result loc" { | ||
| 590 | var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; | ||
| 591 | try expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); | ||
| 592 | } | ||
| 593 | |||
| 594 | test "peer type resolve string lit with sentinel-terminated mutable slice" { | 446 | test "peer type resolve string lit with sentinel-terminated mutable slice" { |
| 595 | var array: [4:0]u8 = undefined; | 447 | var array: [4:0]u8 = undefined; |
| 596 | array[4] = 0; // TODO remove this when #4372 is solved | 448 | array[4] = 0; // TODO remove this when #4372 is solved |
| ... | @@ -649,14 +501,3 @@ test "comptime float casts" { | ... | @@ -649,14 +501,3 @@ test "comptime float casts" { |
| 649 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { | 501 | fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { |
| 650 | try expect(@floatToInt(I, f) == i); | 502 | try expect(@floatToInt(I, f) == i); |
| 651 | } | 503 | } |
| 652 | |||
| 653 | test "cast from ?[*]T to ??[*]T" { | ||
| 654 | const a: ??[*]u8 = @as(?[*]u8, null); | ||
| 655 | try expect(a != null and a.? == null); | ||
| 656 | } | ||
| 657 | |||
| 658 | test "cast between *[N]void and []void" { | ||
| 659 | var a: [4]void = undefined; | ||
| 660 | var b: []void = &a; | ||
| 661 | try expect(b.len == 4); | ||
| 662 | } |
test/behavior/fn.zig+42| ... | @@ -121,3 +121,45 @@ test "inline function call that calls optional function pointer, return pointer | ... | @@ -121,3 +121,45 @@ test "inline function call that calls optional function pointer, return pointer |
| 121 | }; | 121 | }; |
| 122 | try S.doTheTest(); | 122 | try S.doTheTest(); |
| 123 | } | 123 | } |
| 124 | |||
| 125 | test "implicit cast function unreachable return" { | ||
| 126 | wantsFnWithVoid(fnWithUnreachable); | ||
| 127 | } | ||
| 128 | |||
| 129 | fn wantsFnWithVoid(f: fn () void) void { | ||
| 130 | _ = f; | ||
| 131 | } | ||
| 132 | |||
| 133 | fn fnWithUnreachable() noreturn { | ||
| 134 | unreachable; | ||
| 135 | } | ||
| 136 | |||
| 137 | test "extern struct with stdcallcc fn pointer" { | ||
| 138 | const S = extern struct { | ||
| 139 | ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32, | ||
| 140 | |||
| 141 | fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 { | ||
| 142 | return 1234; | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 146 | var s: S = undefined; | ||
| 147 | s.ptr = S.foo; | ||
| 148 | try expect(s.ptr() == 1234); | ||
| 149 | } | ||
| 150 | |||
| 151 | const nComplexCallconv = 100; | ||
| 152 | fn fComplexCallconvRet(x: u32) callconv(blk: { | ||
| 153 | const s: struct { n: u32 } = .{ .n = nComplexCallconv }; | ||
| 154 | break :blk switch (s.n) { | ||
| 155 | 0 => .C, | ||
| 156 | 1 => .Inline, | ||
| 157 | else => .Unspecified, | ||
| 158 | }; | ||
| 159 | }) struct { x: u32 } { | ||
| 160 | return .{ .x = x * x }; | ||
| 161 | } | ||
| 162 | |||
| 163 | test "function with complex callconv and return type expressions" { | ||
| 164 | try expect(fComplexCallconvRet(3).x == 9); | ||
| 165 | } |
test/behavior/fn_stage1.zig-42| ... | @@ -23,18 +23,6 @@ fn acceptsString(foo: []u8) void { | ... | @@ -23,18 +23,6 @@ fn acceptsString(foo: []u8) void { |
| 23 | _ = foo; | 23 | _ = foo; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | test "implicit cast function unreachable return" { | ||
| 27 | wantsFnWithVoid(fnWithUnreachable); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn wantsFnWithVoid(f: fn () void) void { | ||
| 31 | _ = f; | ||
| 32 | } | ||
| 33 | |||
| 34 | fn fnWithUnreachable() noreturn { | ||
| 35 | unreachable; | ||
| 36 | } | ||
| 37 | |||
| 38 | test "function pointers" { | 26 | test "function pointers" { |
| 39 | const fns = [_]@TypeOf(fn1){ | 27 | const fns = [_]@TypeOf(fn1){ |
| 40 | fn1, | 28 | fn1, |
| ... | @@ -126,20 +114,6 @@ test "pass by non-copying value as method, at comptime" { | ... | @@ -126,20 +114,6 @@ test "pass by non-copying value as method, at comptime" { |
| 126 | } | 114 | } |
| 127 | } | 115 | } |
| 128 | 116 | ||
| 129 | test "extern struct with stdcallcc fn pointer" { | ||
| 130 | const S = extern struct { | ||
| 131 | ptr: fn () callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32, | ||
| 132 | |||
| 133 | fn foo() callconv(if (builtin.target.cpu.arch == .i386) .Stdcall else .C) i32 { | ||
| 134 | return 1234; | ||
| 135 | } | ||
| 136 | }; | ||
| 137 | |||
| 138 | var s: S = undefined; | ||
| 139 | s.ptr = S.foo; | ||
| 140 | try expect(s.ptr() == 1234); | ||
| 141 | } | ||
| 142 | |||
| 143 | test "implicit cast fn call result to optional in field result" { | 117 | test "implicit cast fn call result to optional in field result" { |
| 144 | const S = struct { | 118 | const S = struct { |
| 145 | fn entry() !void { | 119 | fn entry() !void { |
| ... | @@ -204,19 +178,3 @@ test "function with inferred error set but returning no error" { | ... | @@ -204,19 +178,3 @@ test "function with inferred error set but returning no error" { |
| 204 | const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; | 178 | const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?; |
| 205 | try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); | 179 | try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len); |
| 206 | } | 180 | } |
| 207 | |||
| 208 | const nComplexCallconv = 100; | ||
| 209 | fn fComplexCallconvRet(x: u32) callconv(blk: { | ||
| 210 | const s: struct { n: u32 } = .{ .n = nComplexCallconv }; | ||
| 211 | break :blk switch (s.n) { | ||
| 212 | 0 => .C, | ||
| 213 | 1 => .Inline, | ||
| 214 | else => .Unspecified, | ||
| 215 | }; | ||
| 216 | }) struct { x: u32 } { | ||
| 217 | return .{ .x = x * x }; | ||
| 218 | } | ||
| 219 | |||
| 220 | test "function with complex callconv and return type expressions" { | ||
| 221 | try expect(fComplexCallconvRet(3).x == 9); | ||
| 222 | } |
test/behavior/generics.zig+29| ... | @@ -134,3 +134,32 @@ test "use generic param in generic param" { | ... | @@ -134,3 +134,32 @@ test "use generic param in generic param" { |
| 134 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { | 134 | fn aGenericFn(comptime T: type, comptime a: T, b: T) T { |
| 135 | return a + b; | 135 | return a + b; |
| 136 | } | 136 | } |
| 137 | |||
| 138 | test "generic fn with implicit cast" { | ||
| 139 | try expect(getFirstByte(u8, &[_]u8{13}) == 13); | ||
| 140 | try expect(getFirstByte(u16, &[_]u16{ | ||
| 141 | 0, | ||
| 142 | 13, | ||
| 143 | }) == 0); | ||
| 144 | } | ||
| 145 | fn getByte(ptr: ?*const u8) u8 { | ||
| 146 | return ptr.?.*; | ||
| 147 | } | ||
| 148 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 149 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 150 | } | ||
| 151 | |||
| 152 | test "generic fn keeps non-generic parameter types" { | ||
| 153 | const A = 128; | ||
| 154 | |||
| 155 | const S = struct { | ||
| 156 | fn f(comptime T: type, s: []T) !void { | ||
| 157 | try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment); | ||
| 158 | } | ||
| 159 | }; | ||
| 160 | |||
| 161 | // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that | ||
| 162 | // `x` type not affect `s` parameter type. | ||
| 163 | var x: [16]u8 align(A) = undefined; | ||
| 164 | try S.f(u8, &x); | ||
| 165 | } |
test/behavior/generics_llvm.zig created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const foos = [_]fn (anytype) bool{ | ||
| 5 | foo1, | ||
| 6 | foo2, | ||
| 7 | }; | ||
| 8 | |||
| 9 | fn foo1(arg: anytype) bool { | ||
| 10 | return arg; | ||
| 11 | } | ||
| 12 | fn foo2(arg: anytype) bool { | ||
| 13 | return !arg; | ||
| 14 | } | ||
| 15 | |||
| 16 | test "array of generic fns" { | ||
| 17 | try expect(foos[0](true)); | ||
| 18 | try expect(!foos[1](true)); | ||
| 19 | } | ||
| 20 | |||
| 21 | test "generic struct" { | ||
| 22 | var a1 = GenNode(i32){ | ||
| 23 | .value = 13, | ||
| 24 | .next = null, | ||
| 25 | }; | ||
| 26 | var b1 = GenNode(bool){ | ||
| 27 | .value = true, | ||
| 28 | .next = null, | ||
| 29 | }; | ||
| 30 | try expect(a1.value == 13); | ||
| 31 | try expect(a1.value == a1.getVal()); | ||
| 32 | try expect(b1.getVal()); | ||
| 33 | } | ||
| 34 | fn GenNode(comptime T: type) type { | ||
| 35 | return struct { | ||
| 36 | value: T, | ||
| 37 | next: ?*GenNode(T), | ||
| 38 | fn getVal(n: *const GenNode(T)) T { | ||
| 39 | return n.value; | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | } | ||
test/behavior/generics_stage1.zig deleted-73| ... | @@ -1,73 +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 "generic struct" { | ||
| 7 | var a1 = GenNode(i32){ | ||
| 8 | .value = 13, | ||
| 9 | .next = null, | ||
| 10 | }; | ||
| 11 | var b1 = GenNode(bool){ | ||
| 12 | .value = true, | ||
| 13 | .next = null, | ||
| 14 | }; | ||
| 15 | try expect(a1.value == 13); | ||
| 16 | try expect(a1.value == a1.getVal()); | ||
| 17 | try expect(b1.getVal()); | ||
| 18 | } | ||
| 19 | fn GenNode(comptime T: type) type { | ||
| 20 | return struct { | ||
| 21 | value: T, | ||
| 22 | next: ?*GenNode(T), | ||
| 23 | fn getVal(n: *const GenNode(T)) T { | ||
| 24 | return n.value; | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | test "generic fn with implicit cast" { | ||
| 30 | try expect(getFirstByte(u8, &[_]u8{13}) == 13); | ||
| 31 | try expect(getFirstByte(u16, &[_]u16{ | ||
| 32 | 0, | ||
| 33 | 13, | ||
| 34 | }) == 0); | ||
| 35 | } | ||
| 36 | fn getByte(ptr: ?*const u8) u8 { | ||
| 37 | return ptr.?.*; | ||
| 38 | } | ||
| 39 | fn getFirstByte(comptime T: type, mem: []const T) u8 { | ||
| 40 | return getByte(@ptrCast(*const u8, &mem[0])); | ||
| 41 | } | ||
| 42 | |||
| 43 | const foos = [_]fn (anytype) bool{ | ||
| 44 | foo1, | ||
| 45 | foo2, | ||
| 46 | }; | ||
| 47 | |||
| 48 | fn foo1(arg: anytype) bool { | ||
| 49 | return arg; | ||
| 50 | } | ||
| 51 | fn foo2(arg: anytype) bool { | ||
| 52 | return !arg; | ||
| 53 | } | ||
| 54 | |||
| 55 | test "array of generic fns" { | ||
| 56 | try expect(foos[0](true)); | ||
| 57 | try expect(!foos[1](true)); | ||
| 58 | } | ||
| 59 | |||
| 60 | test "generic fn keeps non-generic parameter types" { | ||
| 61 | const A = 128; | ||
| 62 | |||
| 63 | const S = struct { | ||
| 64 | fn f(comptime T: type, s: []T) !void { | ||
| 65 | try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment); | ||
| 66 | } | ||
| 67 | }; | ||
| 68 | |||
| 69 | // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that | ||
| 70 | // `x` type not affect `s` parameter type. | ||
| 71 | var x: [16]u8 align(A) = undefined; | ||
| 72 | try S.f(u8, &x); | ||
| 73 | } | ||