authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-22 19:00:30-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-22 19:00:30-05:00
log11330cbcc55f7d7dbd2de2f5acd7b097cd19788c
tree68f25f32b59d803986f67f80e660fb8b76fc3025
parent691090f3429b8625252dd5cfec101f2a9e171463
parent2b589d71fbcacb2e8bc8746dd4b675e57b3a53df
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10201 from Snektron/stage2-more-coercion

stage2: more in-memory coercion

12 files changed, 388 insertions(+), 339 deletions(-)

src/Sema.zig+97-48
......@@ -12364,31 +12364,6 @@ fn coerce(
1236412364 // T to E!T or E to E!T
1236512365 return sema.wrapErrorUnion(block, dest_ty, inst, inst_src);
1236612366 },
12367 .ErrorSet => switch (inst_ty.zigTypeTag()) {
12368 .ErrorSet => {
12369 // Coercion to `anyerror`. Note that this check can return false positives
12370 // in case the error sets did not get resolved.
12371 if (dest_ty.isAnyError()) {
12372 return sema.coerceCompatibleErrorSets(block, inst, inst_src);
12373 }
12374 // If both are inferred error sets of functions, and
12375 // the dest includes the source function, the coercion is OK.
12376 // This check is important because it works without forcing a full resolution
12377 // of inferred error sets.
12378 if (inst_ty.castTag(.error_set_inferred)) |src_payload| {
12379 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
12380 const src_func = src_payload.data.func;
12381 const dst_func = dst_payload.data.func;
12382
12383 if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {
12384 return sema.coerceCompatibleErrorSets(block, inst, inst_src);
12385 }
12386 }
12387 }
12388 // TODO full error set resolution and compare sets by names.
12389 },
12390 else => {},
12391 },
1239212367 .Union => switch (inst_ty.zigTypeTag()) {
1239312368 .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
1239412369 else => {},
......@@ -12441,16 +12416,110 @@ fn coerceInMemoryAllowed(dest_ty: Type, src_ty: Type, dest_is_mut: bool, target:
1244112416 return coerceInMemoryAllowedPtrs(dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target);
1244212417 }
1244312418
12419 // Functions
12420 if (dest_ty.zigTypeTag() == .Fn and src_ty.zigTypeTag() == .Fn) {
12421 return coerceInMemoryAllowedFns(dest_ty, src_ty, target);
12422 }
12423
12424 // Error Unions
12425 if (dest_ty.zigTypeTag() == .ErrorUnion and src_ty.zigTypeTag() == .ErrorUnion) {
12426 const child = coerceInMemoryAllowed(dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target);
12427 if (child == .no_match) {
12428 return child;
12429 }
12430 return coerceInMemoryAllowed(dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target);
12431 }
12432
12433 // Error Sets
12434 if (dest_ty.zigTypeTag() == .ErrorSet and src_ty.zigTypeTag() == .ErrorSet) {
12435 return coerceInMemoryAllowedErrorSets(dest_ty, src_ty);
12436 }
12437
1244412438 // TODO: arrays
1244512439 // TODO: non-pointer-like optionals
12446 // TODO: error unions
12447 // TODO: error sets
12448 // TODO: functions
1244912440 // TODO: vectors
1245012441
1245112442 return .no_match;
1245212443}
1245312444
12445fn coerceInMemoryAllowedErrorSets(
12446 dest_ty: Type,
12447 src_ty: Type,
12448) InMemoryCoercionResult {
12449 // Coercion to `anyerror`. Note that this check can return false positives
12450 // in case the error sets did not get resolved.
12451 if (dest_ty.isAnyError()) {
12452 return .ok;
12453 }
12454 // If both are inferred error sets of functions, and
12455 // the dest includes the source function, the coercion is OK.
12456 // This check is important because it works without forcing a full resolution
12457 // of inferred error sets.
12458 if (src_ty.castTag(.error_set_inferred)) |src_payload| {
12459 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
12460 const src_func = src_payload.data.func;
12461 const dst_func = dst_payload.data.func;
12462
12463 if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {
12464 return .ok;
12465 }
12466 }
12467 }
12468
12469 // TODO full error set resolution and compare sets by names.
12470 return .no_match;
12471}
12472
12473fn coerceInMemoryAllowedFns(
12474 dest_ty: Type,
12475 src_ty: Type,
12476 target: std.Target,
12477) InMemoryCoercionResult {
12478 const dest_info = dest_ty.fnInfo();
12479 const src_info = src_ty.fnInfo();
12480
12481 if (dest_info.is_var_args != src_info.is_var_args) {
12482 return .no_match;
12483 }
12484
12485 if (dest_info.is_generic != src_info.is_generic) {
12486 return .no_match;
12487 }
12488
12489 if (!src_info.return_type.isNoReturn()) {
12490 const rt = coerceInMemoryAllowed(dest_info.return_type, src_info.return_type, false, target);
12491 if (rt == .no_match) {
12492 return rt;
12493 }
12494 }
12495
12496 if (dest_info.param_types.len != src_info.param_types.len) {
12497 return .no_match;
12498 }
12499
12500 for (dest_info.param_types) |dest_param_ty, i| {
12501 const src_param_ty = src_info.param_types[i];
12502
12503 if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
12504 return .no_match;
12505 }
12506
12507 // TODO: nolias
12508
12509 // Note: Cast direction is reversed here.
12510 const param = coerceInMemoryAllowed(src_param_ty, dest_param_ty, false, target);
12511 if (param == .no_match) {
12512 return param;
12513 }
12514 }
12515
12516 if (dest_info.cc != src_info.cc) {
12517 return .no_match;
12518 }
12519
12520 return .ok;
12521}
12522
1245412523fn coerceInMemoryAllowedPtrs(
1245512524 dest_ty: Type,
1245612525 src_ty: Type,
......@@ -13198,26 +13267,6 @@ fn coerceVectorInMemory(
1319813267 return block.addBitCast(dest_ty, inst);
1319913268}
1320013269
13201fn coerceCompatibleErrorSets(
13202 sema: *Sema,
13203 block: *Block,
13204 err_set: Air.Inst.Ref,
13205 err_set_src: LazySrcLoc,
13206) !Air.Inst.Ref {
13207 if (try sema.resolveDefinedValue(block, err_set_src, err_set)) |err_set_val| {
13208 // Same representation works.
13209 return sema.addConstant(Type.anyerror, err_set_val);
13210 }
13211 try sema.requireRuntimeBlock(block, err_set_src);
13212 return block.addInst(.{
13213 .tag = .bitcast,
13214 .data = .{ .ty_op = .{
13215 .ty = Air.Inst.Ref.anyerror_type,
13216 .operand = err_set,
13217 } },
13218 });
13219}
13220
1322113270fn analyzeDeclVal(
1322213271 sema: *Sema,
1322313272 block: *Block,
test/behavior.zig+1-1
......@@ -58,6 +58,7 @@ test {
5858 _ = @import("behavior/floatop.zig");
5959 _ = @import("behavior/fn.zig");
6060 _ = @import("behavior/for.zig");
61 _ = @import("behavior/generics_llvm.zig");
6162 _ = @import("behavior/math.zig");
6263 _ = @import("behavior/maximum_minimum.zig");
6364 _ = @import("behavior/null_llvm.zig");
......@@ -145,7 +146,6 @@ test {
145146 _ = @import("behavior/fn_delegation.zig");
146147 _ = @import("behavior/fn_in_struct_in_comptime.zig");
147148 _ = @import("behavior/for_stage1.zig");
148 _ = @import("behavior/generics_stage1.zig");
149149 _ = @import("behavior/if_stage1.zig");
150150 _ = @import("behavior/import.zig");
151151 _ = @import("behavior/incomplete_struct_param_tld.zig");
test/behavior/cast.zig+29
......@@ -266,3 +266,32 @@ test "array coersion to undefined at runtime" {
266266 array = undefined;
267267 try expect(std.mem.eql(u8, &array, &undefined_val));
268268}
269
270test "implicitly cast from int to anyerror!?T" {
271 implicitIntLitToOptional();
272 comptime implicitIntLitToOptional();
273}
274fn implicitIntLitToOptional() void {
275 const f: ?i32 = 1;
276 _ = f;
277 const g: anyerror!?i32 = 1;
278 _ = g catch {};
279}
280
281test "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
294test "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" {
6565 var c: *u32 = @ptrCast(*u32, ptr2.?);
6666 try expect(c.* == 1);
6767}
68
69const A = struct {
70 a: i32,
71};
72test "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}
77fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
78 const a: ?*A = null;
79 return a;
80}
81fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
82 return null;
83}
84
85test "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}
93fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
94 if (a) {
95 return &[_]u8{};
96 }
97
98 return slice[0..1];
99}
100
101test "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
106fn castToOptionalSlice() ?[]const u8 {
107 return "hi";
108}
109
110test "cast u128 to f128 and back" {
111 comptime try testCast128();
112 try testCast128();
113}
114
115fn testCast128() !void {
116 try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
117}
118
119fn cast128Int(x: f128) u128 {
120 return @bitCast(u128, x);
121}
122
123fn cast128Float(x: u128) f128 {
124 return @bitCast(f128, x);
125}
126
127test "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
138test "implicit cast from *T to ?*c_void" {
139 var a: u8 = 1;
140 incrementVoidPtrValue(&a);
141 try std.testing.expect(a == 2);
142}
143
144fn incrementVoidPtrValue(value: ?*c_void) void {
145 @ptrCast(*u8, value.?).* += 1;
146}
147
148test "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
153var global_array: [4]u8 = undefined;
154test "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
159test "*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
171test "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
189var global_struct: struct { f0: usize } = undefined;
190test "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
195test "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 {
5858 try expect((b catch unreachable).?.a == 1);
5959}
6060
61test "implicitly cast from int to anyerror!?T" {
62 implicitIntLitToOptional();
63 comptime implicitIntLitToOptional();
64}
65fn implicitIntLitToOptional() void {
66 const f: ?i32 = 1;
67 _ = f;
68 const g: anyerror!?i32 = 1;
69 _ = g catch {};
70}
71
72test "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}
77fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
78 const a: ?*A = null;
79 return a;
80}
81fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
82 return null;
83}
84
85test "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}
93fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
94 if (a) {
95 return &[_]u8{};
96 }
97
98 return slice[0..1];
99}
100
101test "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
106fn castToOptionalSlice() ?[]const u8 {
107 return "hi";
108}
109
11061test "implicitly cast from [0]T to anyerror![]T" {
11162 try testCastZeroArrayToErrSliceMut();
11263 comptime try testCastZeroArrayToErrSliceMut();
......@@ -191,23 +142,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
191142 };
192143}
193144
194test "cast u128 to f128 and back" {
195 comptime try testCast128();
196 try testCast128();
197}
198
199fn testCast128() !void {
200 try expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
201}
202
203fn cast128Int(x: f128) u128 {
204 return @bitCast(u128, x);
205}
206
207fn cast128Float(x: u128) f128 {
208 return @bitCast(f128, x);
209}
210
211145test "single-item pointer of array to slice to unknown length pointer" {
212146 try testCastPtrOfArrayToSliceAndPtr();
213147 comptime try testCastPtrOfArrayToSliceAndPtr();
......@@ -316,27 +250,6 @@ test "@floatCast cast down" {
316250 }
317251}
318252
319test "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
330test "implicit cast from *T to ?*c_void" {
331 var a: u8 = 1;
332 incrementVoidPtrValue(&a);
333 try std.testing.expect(a == 2);
334}
335
336fn incrementVoidPtrValue(value: ?*c_void) void {
337 @ptrCast(*u8, value.?).* += 1;
338}
339
340253test "peer type resolution: unreachable, null, slice" {
341254 const S = struct {
342255 fn doTheTest(num: usize, word: []const u8) !void {
......@@ -374,11 +287,6 @@ test "peer type resolution: unreachable, error set, unreachable" {
374287 try expect(transformed_err == error.SystemResources);
375288}
376289
377test "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
382290test "peer cast *[0]T to E![]const T" {
383291 var buffer: [5]u8 = "abcde".*;
384292 var buf: anyerror![]const u8 = buffer[0..];
......@@ -395,24 +303,6 @@ test "peer cast *[0]T to []const T" {
395303 try expect(mem.eql(u8, "abcde", y));
396304}
397305
398var global_array: [4]u8 = undefined;
399test "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
404test "*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
416306test "peer resolution of string literals" {
417307 const S = struct {
418308 const E = enum { a, b, c, d };
......@@ -502,19 +392,6 @@ test "cast i8 fn call peers to i32 result" {
502392 comptime try S.doTheTest();
503393}
504394
505test "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
518395test "peer type resolution implicit cast to return type" {
519396 const S = struct {
520397 fn doTheTest() !void {
......@@ -553,24 +430,6 @@ test "variable initialization uses result locations properly with regards to the
553430 try expect(x == 1);
554431}
555432
556test "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
574433test "cast between C pointer with different but compatible types" {
575434 const S = struct {
576435 fn foo(arg: [*]c_ushort) u16 {
......@@ -584,13 +443,6 @@ test "cast between C pointer with different but compatible types" {
584443 try S.doTheTest();
585444}
586445
587var global_struct: struct { f0: usize } = undefined;
588
589test "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
594446test "peer type resolve string lit with sentinel-terminated mutable slice" {
595447 var array: [4:0]u8 = undefined;
596448 array[4] = 0; // TODO remove this when #4372 is solved
......@@ -649,14 +501,3 @@ test "comptime float casts" {
649501fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
650502 try expect(@floatToInt(I, f) == i);
651503}
652
653test "cast from ?[*]T to ??[*]T" {
654 const a: ??[*]u8 = @as(?[*]u8, null);
655 try expect(a != null and a.? == null);
656}
657
658test "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/error.zig+16
......@@ -115,3 +115,19 @@ test "implicit cast to optional to error union to return result loc" {
115115 try S.entry();
116116 //comptime S.entry(); TODO
117117}
118
119test "error: fn returning empty error set can be passed as fn returning any error" {
120 entry();
121 comptime entry();
122}
123
124fn entry() void {
125 foo2(bar2);
126}
127
128fn foo2(f: fn () anyerror!void) void {
129 const x = f();
130 x catch {};
131}
132
133fn bar2() (error{}!void) {}
test/behavior/error_stage1.zig-16
......@@ -120,22 +120,6 @@ fn quux_1() !i32 {
120120 return error.C;
121121}
122122
123test "error: fn returning empty error set can be passed as fn returning any error" {
124 entry();
125 comptime entry();
126}
127
128fn entry() void {
129 foo2(bar2);
130}
131
132fn foo2(f: fn () anyerror!void) void {
133 const x = f();
134 x catch {};
135}
136
137fn bar2() (error{}!void) {}
138
139123test "error: Zero sized error set returned with value payload crash" {
140124 _ = foo3(0) catch {};
141125 _ = comptime foo3(0) catch {};
test/behavior/fn.zig+42
......@@ -121,3 +121,45 @@ test "inline function call that calls optional function pointer, return pointer
121121 };
122122 try S.doTheTest();
123123}
124
125test "implicit cast function unreachable return" {
126 wantsFnWithVoid(fnWithUnreachable);
127}
128
129fn wantsFnWithVoid(f: fn () void) void {
130 _ = f;
131}
132
133fn fnWithUnreachable() noreturn {
134 unreachable;
135}
136
137test "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
151const nComplexCallconv = 100;
152fn 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
163test "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 {
2323 _ = foo;
2424}
2525
26test "implicit cast function unreachable return" {
27 wantsFnWithVoid(fnWithUnreachable);
28}
29
30fn wantsFnWithVoid(f: fn () void) void {
31 _ = f;
32}
33
34fn fnWithUnreachable() noreturn {
35 unreachable;
36}
37
3826test "function pointers" {
3927 const fns = [_]@TypeOf(fn1){
4028 fn1,
......@@ -126,20 +114,6 @@ test "pass by non-copying value as method, at comptime" {
126114 }
127115}
128116
129test "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
143117test "implicit cast fn call result to optional in field result" {
144118 const S = struct {
145119 fn entry() !void {
......@@ -204,19 +178,3 @@ test "function with inferred error set but returning no error" {
204178 const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?;
205179 try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len);
206180}
207
208const nComplexCallconv = 100;
209fn 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
220test "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" {
134134fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
135135 return a + b;
136136}
137
138test "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}
145fn getByte(ptr: ?*const u8) u8 {
146 return ptr.?.*;
147}
148fn getFirstByte(comptime T: type, mem: []const T) u8 {
149 return getByte(@ptrCast(*const u8, &mem[0]));
150}
151
152test "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 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const foos = [_]fn (anytype) bool{
5 foo1,
6 foo2,
7};
8
9fn foo1(arg: anytype) bool {
10 return arg;
11}
12fn foo2(arg: anytype) bool {
13 return !arg;
14}
15
16test "array of generic fns" {
17 try expect(foos[0](true));
18 try expect(!foos[1](true));
19}
20
21test "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}
34fn 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 @@
1const std = @import("std");
2const testing = std.testing;
3const expect = testing.expect;
4const expectEqual = testing.expectEqual;
5
6test "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}
19fn 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
29test "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}
36fn getByte(ptr: ?*const u8) u8 {
37 return ptr.?.*;
38}
39fn getFirstByte(comptime T: type, mem: []const T) u8 {
40 return getByte(@ptrCast(*const u8, &mem[0]));
41}
42
43const foos = [_]fn (anytype) bool{
44 foo1,
45 foo2,
46};
47
48fn foo1(arg: anytype) bool {
49 return arg;
50}
51fn foo2(arg: anytype) bool {
52 return !arg;
53}
54
55test "array of generic fns" {
56 try expect(foos[0](true));
57 try expect(!foos[1](true));
58}
59
60test "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}