authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-15 22:35:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-15 22:36:46-07:00
log4006a3afb31f89be28721bdcd50fa64de63d6cbb
treec18eb51e9a24550554dbe39b0d66aea6e22afa27
parentbbf5a4d7c5726baf933e303e6c61c6bba38b694b

astgen: update more expression types to new mem layout

additionally introduce a new file to centralize all the data about builtin functions that we have, including: * enum tag identifying the builtin function * number of parameters. * whether the expression may need a memory location. * whether the expression allows an lvalue (currently only true for `@field`). Now there is only one ComptimeStringMap that has this data as the value, and we dispatch on the enum tag in order to asgen the builtin function. In particular this simplifies the logic for checking the number of parameters. This removes some untested code paths from if and while, which need to be restored with #7929 in mind. After this there are only a handful left of expression types to rework to the new memory layout, and then it will be only compile errors left to solve.

2 files changed, 1357 insertions(+), 559 deletions(-)

src/BuiltinFn.zig created+841
......@@ -0,0 +1,841 @@
1const std = @import("std");
2
3pub const Tag = enum {
4 add_with_overflow,
5 align_cast,
6 align_of,
7 as,
8 async_call,
9 atomic_load,
10 atomic_rmw,
11 atomic_store,
12 bit_cast,
13 bit_offset_of,
14 bool_to_int,
15 bit_size_of,
16 breakpoint,
17 mul_add,
18 byte_swap,
19 bit_reverse,
20 byte_offset_of,
21 call,
22 c_define,
23 c_import,
24 c_include,
25 clz,
26 cmpxchg_strong,
27 cmpxchg_weak,
28 compile_error,
29 compile_log,
30 ctz,
31 c_undef,
32 div_exact,
33 div_floor,
34 div_trunc,
35 embed_file,
36 enum_to_int,
37 error_name,
38 error_return_trace,
39 error_to_int,
40 err_set_cast,
41 @"export",
42 fence,
43 field,
44 field_parent_ptr,
45 float_cast,
46 float_to_int,
47 frame,
48 Frame,
49 frame_address,
50 frame_size,
51 has_decl,
52 has_field,
53 import,
54 int_cast,
55 int_to_enum,
56 int_to_error,
57 int_to_float,
58 int_to_ptr,
59 memcpy,
60 memset,
61 wasm_memory_size,
62 wasm_memory_grow,
63 mod,
64 mul_with_overflow,
65 panic,
66 pop_count,
67 ptr_cast,
68 ptr_to_int,
69 rem,
70 return_address,
71 set_align_stack,
72 set_cold,
73 set_eval_branch_quota,
74 set_float_mode,
75 set_runtime_safety,
76 shl_exact,
77 shl_with_overflow,
78 shr_exact,
79 shuffle,
80 size_of,
81 splat,
82 reduce,
83 src,
84 sqrt,
85 sin,
86 cos,
87 exp,
88 exp2,
89 log,
90 log2,
91 log10,
92 fabs,
93 floor,
94 ceil,
95 trunc,
96 round,
97 sub_with_overflow,
98 tag_name,
99 This,
100 truncate,
101 Type,
102 type_info,
103 type_name,
104 TypeOf,
105 union_init,
106};
107
108tag: Tag,
109
110/// `true` if the builtin call can take advantage of a result location pointer.
111needs_mem_loc: bool = false,
112/// `true` if the builtin call can be the left-hand side of an expression (assigned to).
113allows_lvalue: bool = false,
114/// The number of parameters to this builtin function. `null` means variable number
115/// of parameters.
116param_count: ?u8,
117
118pub const list = std.ComptimeStringMap(@This(), .{
119 .{
120 "@addWithOverflow",
121 .{
122 .tag = .add_with_overflow,
123 .param_count = 4,
124 },
125 },
126 .{
127 "@alignCast",
128 .{
129 .tag = align_cast,
130 .param_count = 1,
131 },
132 },
133 .{
134 "@alignOf",
135 .{
136 .tag = .align_of,
137 .param_count = 1,
138 },
139 },
140 .{
141 "@as",
142 .{
143 .tag = .as,
144 .needs_mem_loc = true,
145 .param_count = 2,
146 },
147 },
148 .{
149 "@asyncCall",
150 .{
151 .tag = .async_call,
152 .param_count = null,
153 },
154 },
155 .{
156 "@atomicLoad",
157 .{
158 .tag = .atomic_load,
159 .param_count = 3,
160 },
161 },
162 .{
163 "@atomicRmw",
164 .{
165 .tag = .atomic_rmw,
166 .param_count = 5,
167 },
168 },
169 .{
170 "@atomicStore",
171 .{
172 .tag = .atomic_store,
173 .param_count = 4,
174 },
175 },
176 .{
177 "@bitCast",
178 .{
179 .tag = .bit_cast,
180 .needs_mem_loc = true,
181 .param_count = 2,
182 },
183 },
184 .{
185 "@bitOffsetOf",
186 .{
187 .tag = .bit_offset_of,
188 .param_count = 2,
189 },
190 },
191 .{
192 "@boolToInt",
193 .{
194 .tag = .bool_to_int,
195 .param_count = 1,
196 },
197 },
198 .{
199 "@bitSizeOf",
200 .{
201 .tag = .bit_size_of,
202 .param_count = 1,
203 },
204 },
205 .{
206 "@breakpoint",
207 .{
208 .tag = .breakpoint,
209 .param_count = 0,
210 },
211 },
212 .{
213 "@mulAdd",
214 .{
215 .tag = .mul_add,
216 .param_count = 4,
217 },
218 },
219 .{
220 "@byteSwap",
221 .{
222 .tag = .byte_swap,
223 .param_count = 2,
224 },
225 },
226 .{
227 "@bitReverse",
228 .{
229 .tag = .bit_reverse,
230 .param_count = 2,
231 },
232 },
233 .{
234 "@byteOffsetOf",
235 .{
236 .tag = .byte_offset_of,
237 .param_count = 2,
238 },
239 },
240 .{
241 "@call",
242 .{
243 .tag = .call,
244 .needs_mem_loc = true,
245 .param_count = 3,
246 },
247 },
248 .{
249 "@cDefine",
250 .{
251 .tag = .c_define,
252 .param_count = 2,
253 },
254 },
255 .{
256 "@cImport",
257 .{
258 .tag = .c_import,
259 .param_count = 1,
260 },
261 },
262 .{
263 "@cInclude",
264 .{
265 .tag = .c_include,
266 .param_count = 1,
267 },
268 },
269 .{
270 "@clz",
271 .{
272 .tag = .clz,
273 .param_count = 2,
274 },
275 },
276 .{
277 "@cmpxchgStrong",
278 .{
279 .tag = .cmpxchg_strong,
280 .param_count = 6,
281 },
282 },
283 .{
284 "@cmpxchgWeak",
285 .{
286 .tag = .cmpxchg_weak,
287 .param_count = 6,
288 },
289 },
290 .{
291 "@compileError",
292 .{
293 .tag = .compile_error,
294 .param_count = 1,
295 },
296 },
297 .{
298 "@compileLog",
299 .{
300 .tag = .compile_log,
301 .param_count = null,
302 },
303 },
304 .{
305 "@ctz",
306 .{
307 .tag = .ctz,
308 .param_count = 2,
309 },
310 },
311 .{
312 "@cUndef",
313 .{
314 .tag = .c_undef,
315 .param_count = 1,
316 },
317 },
318 .{
319 "@divExact",
320 .{
321 .tag = .div_exact,
322 .param_count = 2,
323 },
324 },
325 .{
326 "@divFloor",
327 .{
328 .tag = .div_floor,
329 .param_count = 2,
330 },
331 },
332 .{
333 "@divTrunc",
334 .{
335 .tag = .div_trunc,
336 .param_count = 2,
337 },
338 },
339 .{
340 "@embedFile",
341 .{
342 .tag = .embed_file,
343 .param_count = 1,
344 },
345 },
346 .{
347 "@enumToInt",
348 .{
349 .tag = .enum_to_int,
350 .param_count = 1,
351 },
352 },
353 .{
354 "@errorName",
355 .{
356 .tag = .error_name,
357 .param_count = 1,
358 },
359 },
360 .{
361 "@errorReturnTrace",
362 .{
363 .tag = .error_return_trace,
364 .param_count = 0,
365 },
366 },
367 .{
368 "@errorToInt",
369 .{
370 .tag = .error_to_int,
371 .param_count = 1,
372 },
373 },
374 .{
375 "@errSetCast",
376 .{
377 .tag = .err_set_cast,
378 .param_count = 2,
379 },
380 },
381 .{
382 "@export",
383 .{
384 .tag = .@"export",
385 .param_count = 2,
386 },
387 },
388 .{
389 "@fence",
390 .{
391 .tag = .fence,
392 .param_count = 0,
393 },
394 },
395 .{
396 "@field",
397 .{
398 .tag = .field,
399 .needs_mem_loc = true,
400 .param_count = 2,
401 .allows_lvalue = true,
402 },
403 },
404 .{
405 "@fieldParentPtr",
406 .{
407 .tag = .field_parent_ptr,
408 .param_count = 3,
409 },
410 },
411 .{
412 "@floatCast",
413 .{
414 .tag = .float_cast,
415 .param_count = 1,
416 },
417 },
418 .{
419 "@floatToInt",
420 .{
421 .tag = .float_to_int,
422 .param_count = 1,
423 },
424 },
425 .{
426 "@frame",
427 .{
428 .tag = .frame,
429 .param_count = 0,
430 },
431 },
432 .{
433 "@Frame",
434 .{
435 .tag = .Frame,
436 .param_count = 1,
437 },
438 },
439 .{
440 "@frameAddress",
441 .{
442 .tag = .frame_address,
443 .param_count = 0,
444 },
445 },
446 .{
447 "@frameSize",
448 .{
449 .tag = .frame_size,
450 .param_count = 1,
451 },
452 },
453 .{
454 "@hasDecl",
455 .{
456 .tag = .has_decl,
457 .param_count = 2,
458 },
459 },
460 .{
461 "@hasField",
462 .{
463 .tag = .has_field,
464 .param_count = 2,
465 },
466 },
467 .{
468 "@import",
469 .{
470 .tag = .import,
471 .param_count = 1,
472 },
473 },
474 .{
475 "@intCast",
476 .{
477 .tag = .int_cast,
478 .param_count = 1,
479 },
480 },
481 .{
482 "@intToEnum",
483 .{
484 .tag = .int_to_enum,
485 .param_count = 1,
486 },
487 },
488 .{
489 "@intToError",
490 .{
491 .tag = .int_to_error,
492 .param_count = 1,
493 },
494 },
495 .{
496 "@intToFloat",
497 .{
498 .tag = .int_to_float,
499 .param_count = 1,
500 },
501 },
502 .{
503 "@intToPtr",
504 .{
505 .tag = .int_to_ptr,
506 .param_count = 2,
507 },
508 },
509 .{
510 "@memcpy",
511 .{
512 .tag = .memcpy,
513 .param_count = 3,
514 },
515 },
516 .{
517 "@memset",
518 .{
519 .tag = .memset,
520 .param_count = 3,
521 },
522 },
523 .{
524 "@wasmMemorySize",
525 .{
526 .tag = .wasm_memory_size,
527 .param_count = 1,
528 },
529 },
530 .{
531 "@wasmMemoryGrow",
532 .{
533 .tag = .wasm_memory_grow,
534 .param_count = 2,
535 },
536 },
537 .{
538 "@mod",
539 .{
540 .tag = .mod,
541 .param_count = 2,
542 },
543 },
544 .{
545 "@mulWithOverflow",
546 .{
547 .tag = .mul_with_overflow,
548 .param_count = 4,
549 },
550 },
551 .{
552 "@panic",
553 .{
554 .tag = .panic,
555 .param_count = 1,
556 },
557 },
558 .{
559 "@popCount",
560 .{
561 .tag = .pop_count,
562 .param_count = 2,
563 },
564 },
565 .{
566 "@ptrCast",
567 .{
568 .tag = .ptr_cast,
569 .param_count = 2,
570 },
571 },
572 .{
573 "@ptrToInt",
574 .{
575 .tag = .ptr_to_int,
576 .param_count = 1,
577 },
578 },
579 .{
580 "@rem",
581 .{
582 .tag = .rem,
583 .param_count = 2,
584 },
585 },
586 .{
587 "@returnAddress",
588 .{
589 .tag = .return_address,
590 .param_count = 0,
591 },
592 },
593 .{
594 "@setAlignStack",
595 .{
596 .tag = .set_align_stack,
597 .param_count = 1,
598 },
599 },
600 .{
601 "@setCold",
602 .{
603 .tag = .set_cold,
604 .param_count = 1,
605 },
606 },
607 .{
608 "@setEvalBranchQuota",
609 .{
610 .tag = .set_eval_branch_quota,
611 .param_count = 1,
612 },
613 },
614 .{
615 "@setFloatMode",
616 .{
617 .tag = .set_float_mode,
618 .param_count = 1,
619 },
620 },
621 .{
622 "@setRuntimeSafety",
623 .{
624 .tag = .set_runtime_safety,
625 .param_count = 1,
626 },
627 },
628 .{
629 "@shlExact",
630 .{
631 .tag = .shl_exact,
632 .param_count = 2,
633 },
634 },
635 .{
636 "@shlWithOverflow",
637 .{
638 .tag = .shl_with_overflow,
639 .param_count = 4,
640 },
641 },
642 .{
643 "@shrExact",
644 .{
645 .tag = .shr_exact,
646 .param_count = 2,
647 },
648 },
649 .{
650 "@shuffle",
651 .{
652 .tag = .shuffle,
653 .param_count = 4,
654 },
655 },
656 .{
657 "@sizeOf",
658 .{
659 .tag = .size_of,
660 .param_count = 1,
661 },
662 },
663 .{
664 "@splat",
665 .{
666 .tag = .splat,
667 .needs_mem_loc = true,
668 .param_count = 2,
669 },
670 },
671 .{
672 "@reduce",
673 .{
674 .tag = .reduce,
675 .param_count = 2,
676 },
677 },
678 .{
679 "@src",
680 .{
681 .tag = .src,
682 .needs_mem_loc = true,
683 .param_count = 0,
684 },
685 },
686 .{
687 "@sqrt",
688 .{
689 .tag = .sqrt,
690 .param_count = 1,
691 },
692 },
693 .{
694 "@sin",
695 .{
696 .tag = .sin,
697 .param_count = 1,
698 },
699 },
700 .{
701 "@cos",
702 .{
703 .tag = .cos,
704 .param_count = 1,
705 },
706 },
707 .{
708 "@exp",
709 .{
710 .tag = .exp,
711 .param_count = 1,
712 },
713 },
714 .{
715 "@exp2",
716 .{
717 .tag = .exp2,
718 .param_count = 1,
719 },
720 },
721 .{
722 "@log",
723 .{
724 .tag = .log,
725 .param_count = 1,
726 },
727 },
728 .{
729 "@log2",
730 .{
731 .tag = .log2,
732 .param_count = 1,
733 },
734 },
735 .{
736 "@log10",
737 .{
738 .tag = .log10,
739 .param_count = 1,
740 },
741 },
742 .{
743 "@fabs",
744 .{
745 .tag = .fabs,
746 .param_count = 1,
747 },
748 },
749 .{
750 "@floor",
751 .{
752 .tag = .floor,
753 .param_count = 1,
754 },
755 },
756 .{
757 "@ceil",
758 .{
759 .tag = .ceil,
760 .param_count = 1,
761 },
762 },
763 .{
764 "@trunc",
765 .{
766 .tag = .trunc,
767 .param_count = 1,
768 },
769 },
770 .{
771 "@round",
772 .{
773 .tag = .round,
774 .param_count = 1,
775 },
776 },
777 .{
778 "@subWithOverflow",
779 .{
780 .tag = .sub_with_overflow,
781 .param_count = 4,
782 },
783 },
784 .{
785 "@tagName",
786 .{
787 .tag = .tag_name,
788 .param_count = 1,
789 },
790 },
791 .{
792 "@This",
793 .{
794 .tag = .This,
795 .param_count = 0,
796 },
797 },
798 .{
799 "@truncate",
800 .{
801 .tag = .truncate,
802 .param_count = 2,
803 },
804 },
805 .{
806 "@Type",
807 .{
808 .tag = .Type,
809 .param_count = 1,
810 },
811 },
812 .{
813 "@typeInfo",
814 .{
815 .tag = .type_info,
816 .param_count = 1,
817 },
818 },
819 .{
820 "@typeName",
821 .{
822 .tag = .type_name,
823 .param_count = 1,
824 },
825 },
826 .{
827 "@TypeOf",
828 .{
829 .tag = .TypeOf,
830 .param_count = null,
831 },
832 },
833 .{
834 "@unionInit",
835 .{
836 .tag = .union_init,
837 .needs_mem_loc = true,
838 .param_count = 3,
839 },
840 },
841});
src/astgen.zig+516-559
......@@ -1,16 +1,18 @@
11const std = @import("std");
22const mem = std.mem;
33const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;
5
46const Value = @import("value.zig").Value;
57const Type = @import("type.zig").Type;
68const TypedValue = @import("TypedValue.zig");
7const assert = std.debug.assert;
89const zir = @import("zir.zig");
910const Module = @import("Module.zig");
1011const ast = std.zig.ast;
1112const trace = @import("tracy.zig").trace;
1213const Scope = Module.Scope;
1314const InnerError = Module.InnerError;
15const BuiltinFn = @import("BuiltinFn.zig");
1416
1517pub const ResultLoc = union(enum) {
1618 /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the
......@@ -172,16 +174,21 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.I
172174 .ContainerDecl,
173175 .@"comptime",
174176 .@"nosuspend",
175 .builtin_call,
176 .builtin_call_comma,
177177 => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
178178
179 // `@field` can be assigned to.
180 .builtin_call_two, .builtin_call_two_comma => {
179 .builtin_call,
180 .builtin_call_comma,
181 .builtin_call_two,
182 .builtin_call_two_comma,
183 => {
181184 const builtin_token = main_tokens[node];
182185 const builtin_name = tree.tokenSlice(builtin_token);
183 if (!mem.eql(u8, builtin_name, "@field")) {
184 return mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
186 // If the builtin is an invalid name, we don't cause an error here; instead
187 // let it pass, and the error will be "invalid builtin function" later.
188 if (BuiltinFn.list.get(builtin_name)) |info| {
189 if (!info.allows_lvalue) {
190 return mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
191 }
185192 }
186193 },
187194
......@@ -276,22 +283,111 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
276283 .multiline_string_literal => return multilineStringLiteral(mod, scope, rl, node),
277284
278285 .integer_literal => return integerLiteral(mod, scope, rl, node),
286
279287 .builtin_call => return builtinCall(mod, scope, rl, node),
280 .call => return callExpr(mod, scope, rl, node),
281 .@"unreachable" => return unreach(mod, scope, node),
288
289 .builtin_call_two, .builtin_call_two_comma => {
290 if (datas[node].lhs == 0) {
291 const params = [_]ast.Node.Index{};
292 return builtinCall(mod, scope, rl, node, &params);
293 } else if (datas[node].rhs == 0) {
294 const params = [_]ast.Node.Index{datas[node].lhs};
295 return builtinCall(mod, scope, rl, node, &params);
296 } else {
297 const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
298 return builtinCall(mod, scope, rl, node, &params);
299 }
300 },
301 .builtin_call, .builtin_call_comma => {
302 const params = tree.extra_data[datas[node].lhs..datas[node].rhs];
303 return builtinCall(mod, scope, rl, node, params);
304 },
305
306 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
307 var params: [1]ast.Node.Index = undefined;
308 return callExpr(mod, scope, rl, tree.callOne(&params, node));
309 },
310 .call, .call_comma, .async_call, .async_call_comma => {
311 return callExpr(mod, scope, rl, tree.callFull(node));
312 },
313
314 .@"unreachable" => {
315 const main_token = main_tokens[node];
316 const src = token_starts[main_token];
317 return addZIRNoOp(mod, scope, src, .unreachable_safe);
318 },
282319 .@"return" => return ret(mod, scope, node),
283 .@"if" => return ifExpr(mod, scope, rl, node),
284 .@"while" => return whileExpr(mod, scope, rl, node),
285320 .period => return field(mod, scope, rl, node),
286 .deref => return rvalue(mod, scope, rl, try deref(mod, scope, node)),
287 .address_of => return rvalue(mod, scope, rl, try addressOf(mod, scope, node)),
288 .float_literal => return rvalue(mod, scope, rl, try floatLiteral(mod, scope, node)),
289 .undefined_literal => return rvalue(mod, scope, rl, try undefLiteral(mod, scope, node)),
290 .bool_literal => return rvalue(mod, scope, rl, try boolLiteral(mod, scope, node)),
291 .null_literal => return rvalue(mod, scope, rl, try nullLiteral(mod, scope, node)),
292 .optional_type => return rvalue(mod, scope, rl, try optionalType(mod, scope, node)),
293 .unwrap_optional => return unwrapOptional(mod, scope, rl, node),
321 .float_literal => return floatLiteral(mod, scope, rl, node),
322
323 .if_simple => return ifExpr(mod, scope, rl, tree.ifSimple(node)),
324 .@"if" => return ifExpr(mode, scope, rl, tree.ifFull(node)),
325
326 .while_simple => return whileExpr(mod, scope, rl, tree.whileSimple(node)),
327 .while_cont => return whileExpr(mod, scope, tree.whileCont(node)),
328 .@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)),
294329
330 .deref => {
331 const lhs = try expr(mod, scope, .none, node_datas[node].lhs);
332 const src = token_starts[main_tokens[node]];
333 const result = try addZIRUnOp(mod, scope, src, .deref, lhs);
334 return rvalue(mod, scope, rl, result);
335 },
336 .address_of => {
337 const result = try expr(mod, scope, .ref, node_datas[node].lhs);
338 return rvalue(mod, scope, rl, result);
339 },
340 .undefined_literal => {
341 const main_token = main_tokens[node];
342 const src = token_starts[main_token];
343 const result = try addZIRInstConst(mod, scope, src, .{
344 .ty = Type.initTag(.@"undefined"),
345 .val = Value.initTag(.undef),
346 });
347 return rvalue(mod, scope, rl, result);
348 },
349 .true_literal => {
350 const main_token = main_tokens[node];
351 const src = token_starts[main_token];
352 const result = try addZIRInstConst(mod, scope, src, .{
353 .ty = Type.initTag(.bool),
354 .val = Value.initTag(.bool_true),
355 });
356 return rvalue(mod, scope, rl, result);
357 },
358 .false_literal => {
359 const main_token = main_tokens[node];
360 const src = token_starts[main_token];
361 const result = try addZIRInstConst(mod, scope, src, .{
362 .ty = Type.initTag(.bool),
363 .val = Value.initTag(.bool_false),
364 });
365 return rvalue(mod, scope, rl, result);
366 },
367 .null_literal => {
368 const main_token = main_tokens[node];
369 const src = token_starts[main_token];
370 const result = try addZIRInstConst(mod, scope, src, .{
371 .ty = Type.initTag(.@"null"),
372 .val = Value.initTag(.null_value),
373 });
374 return rvalue(mod, scope, rl, result);
375 },
376 .optional_type => {
377 const src = token_starts[main_tokens[node]];
378 const operand = try typeExpr(mod, scope, node_datas[node].lhs);
379 const result = try addZIRUnOp(mod, scope, src, .optional_type, operand);
380 return rvalue(mod, scope, rl, result);
381 },
382 .unwrap_optional => {
383 const operand = try expr(mod, scope, rl, node.lhs);
384 const op: zir.Inst.Tag = switch (rl) {
385 .ref => .optional_payload_safe_ptr,
386 else => .optional_payload_safe,
387 };
388 const src = token_starts[main_tokens[node]];
389 return addZIRUnOp(mod, scope, src, op, operand);
390 },
295391 .block_two, .block_two_semicolon => {
296392 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
297393 if (node_datas[node].lhs == 0) {
......@@ -307,7 +403,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
307403 return blockExpr(mod, scope, rl, node, statements);
308404 },
309405
310 .labeled_block => return labeledBlockExpr(mod, scope, rl, node, .block),
311406 .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)),
312407 .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)),
313408 .grouped_expression => return expr(mod, scope, rl, node.expr),
......@@ -521,7 +616,12 @@ pub fn blockExpr(
521616 const tracy = trace(@src());
522617 defer tracy.end();
523618
524 try blockExprStmts(mod, scope, &block_node.base, statements);
619 const lbrace = main_tokens[node];
620 if (token_tags[lbrace - 1] == .colon) {
621 return labeledBlockExpr(mod, scope, rl, block_node, .block);
622 }
623
624 try blockExprStmts(mod, scope, block_node, statements);
525625 return rvalueVoid(mod, scope, rl, block_node, {});
526626}
527627
......@@ -983,17 +1083,6 @@ fn negation(
9831083 return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
9841084}
9851085
986fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
987 return expr(mod, scope, .ref, node.rhs);
988}
989
990fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
991 const tree = scope.tree();
992 const src = token_starts[node.op_token];
993 const operand = try typeExpr(mod, scope, node.rhs);
994 return addZIRUnOp(mod, scope, src, .optional_type, operand);
995}
996
9971086fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.slice_type) InnerError!*zir.Inst {
9981087 const tree = scope.tree();
9991088 const src = token_starts[node.op_token];
......@@ -1123,18 +1212,6 @@ fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.enum_literal) !*zir.
11231212 return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
11241213}
11251214
1126fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
1127 const tree = scope.tree();
1128 const src = token_starts[node.rtoken];
1129
1130 const operand = try expr(mod, scope, rl, node.lhs);
1131 const op: zir.Inst.Tag = switch (rl) {
1132 .ref => .optional_payload_safe_ptr,
1133 else => .optional_payload_safe,
1134 };
1135 return addZIRUnOp(mod, scope, src, op, operand);
1136}
1137
11381215fn containerField(
11391216 mod: *Module,
11401217 scope: *Scope,
......@@ -1583,51 +1660,25 @@ fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: as
15831660 return mem.eql(u8, ident_name_1, ident_name_2);
15841661}
15851662
1586pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
1663pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst {
15871664 const tree = scope.tree();
1588 const src = token_starts[node.op_token];
1589 // TODO custom AST node for field access so that we don't have to go through a node cast here
1590 const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.identifier).?.token);
1665 const token_starts = tree.tokens.items(.start);
1666 const main_tokens = tree.nodes.items(.main_token);
1667 const dot_token = main_tokens[node];
1668 const src = token_starts[dot_token];
1669 const field_ident = dot_token + 1;
1670 const field_name = try mod.identifierTokenString(scope, field_ident);
15911671 if (rl == .ref) {
15921672 return addZirInstTag(mod, scope, src, .field_ptr, .{
15931673 .object = try expr(mod, scope, .ref, node.lhs),
15941674 .field_name = field_name,
15951675 });
1676 } else {
1677 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{
1678 .object = try expr(mod, scope, .none, node.lhs),
1679 .field_name = field_name,
1680 }));
15961681 }
1597 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{
1598 .object = try expr(mod, scope, .none, node.lhs),
1599 .field_name = field_name,
1600 }));
1601}
1602
1603fn namedField(
1604 mod: *Module,
1605 scope: *Scope,
1606 rl: ResultLoc,
1607 call: *ast.Node.builtin_call,
1608) InnerError!*zir.Inst {
1609 try ensureBuiltinParamCount(mod, scope, call, 2);
1610
1611 const tree = scope.tree();
1612 const src = token_starts[call.builtin_token];
1613 const params = call.params();
1614
1615 const string_type = try addZIRInstConst(mod, scope, src, .{
1616 .ty = Type.initTag(.type),
1617 .val = Value.initTag(.const_slice_u8_type),
1618 });
1619 const string_rl: ResultLoc = .{ .ty = string_type };
1620
1621 if (rl == .ref) {
1622 return addZirInstTag(mod, scope, src, .field_ptr_named, .{
1623 .object = try expr(mod, scope, .ref, params[0]),
1624 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
1625 });
1626 }
1627 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{
1628 .object = try expr(mod, scope, .none, params[0]),
1629 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
1630 }));
16311682}
16321683
16331684fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.array_access) InnerError!*zir.Inst {
......@@ -1681,13 +1732,6 @@ fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.slice) InnerError!*zir
16811732 );
16821733}
16831734
1684fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
1685 const tree = scope.tree();
1686 const src = token_starts[node.rtoken];
1687 const lhs = try expr(mod, scope, .none, node.lhs);
1688 return addZIRUnOp(mod, scope, src, .deref, lhs);
1689}
1690
16911735fn simpleBinOp(
16921736 mod: *Module,
16931737 scope: *Scope,
......@@ -1794,83 +1838,12 @@ fn boolBinOp(
17941838 return rvalue(mod, scope, rl, &block.base);
17951839}
17961840
1797const CondKind = union(enum) {
1798 bool,
1799 optional: ?*zir.Inst,
1800 err_union: ?*zir.Inst,
1801
1802 fn cond(self: *CondKind, mod: *Module, block_scope: *Scope.GenZIR, src: usize, cond_node: *ast.Node) !*zir.Inst {
1803 switch (self.*) {
1804 .bool => {
1805 const bool_type = try addZIRInstConst(mod, &block_scope.base, src, .{
1806 .ty = Type.initTag(.type),
1807 .val = Value.initTag(.bool_type),
1808 });
1809 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
1810 },
1811 .optional => {
1812 const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
1813 self.* = .{ .optional = cond_ptr };
1814 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
1815 return try addZIRUnOp(mod, &block_scope.base, src, .is_non_null, result);
1816 },
1817 .err_union => {
1818 const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
1819 self.* = .{ .err_union = err_ptr };
1820 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
1821 return try addZIRUnOp(mod, &block_scope.base, src, .is_err, result);
1822 },
1823 }
1824 }
1825
1826 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
1827 if (self == .bool) return &then_scope.base;
1828
1829 const payload = payload_node.?.castTag(.PointerPayload) orelse {
1830 // condition is error union and payload is not explicitly ignored
1831 _ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?);
1832 return &then_scope.base;
1833 };
1834 const is_ptr = payload.ptr_token != null;
1835 const ident_node = payload.value_symbol.castTag(.identifier).?;
1836
1837 // This intentionally does not support @"_" syntax.
1838 const ident_name = then_scope.base.tree().tokenSlice(ident_node.token);
1839 if (mem.eql(u8, ident_name, "_")) {
1840 if (is_ptr)
1841 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
1842 return &then_scope.base;
1843 }
1844
1845 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{});
1846 }
1847
1848 fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
1849 if (self != .err_union) return &else_scope.base;
1850
1851 const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .err_union_payload_unsafe_ptr, self.err_union.?);
1852
1853 const payload = payload_node.?.castTag(.Payload).?;
1854 const ident_node = payload.error_symbol.castTag(.identifier).?;
1855
1856 // This intentionally does not support @"_" syntax.
1857 const ident_name = else_scope.base.tree().tokenSlice(ident_node.token);
1858 if (mem.eql(u8, ident_name, "_")) {
1859 return &else_scope.base;
1860 }
1861
1862 return mod.failNode(&else_scope.base, payload.error_symbol, "TODO implement payload symbols", .{});
1863 }
1864};
1865
1866fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if") InnerError!*zir.Inst {
1867 var cond_kind: CondKind = .bool;
1868 if (if_node.payload) |_| cond_kind = .{ .optional = null };
1869 if (if_node.@"else") |else_node| {
1870 if (else_node.payload) |payload| {
1871 cond_kind = .{ .err_union = null };
1872 }
1873 }
1841fn ifExpr(
1842 mod: *Module,
1843 scope: *Scope,
1844 rl: ResultLoc,
1845 if_full: ast.full.If,
1846) InnerError!*zir.Inst {
18741847 var block_scope: Scope.GenZIR = .{
18751848 .parent = scope,
18761849 .decl = scope.ownerDecl().?,
......@@ -1884,8 +1857,22 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if")
18841857 const tree = scope.tree();
18851858 const node_datas = tree.nodes.items(.data);
18861859 const main_tokens = tree.nodes.items(.main_token);
1887 const if_src = token_starts[if_node.if_token];
1888 const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition);
1860 const if_src = token_starts[if_full.ast.if_token];
1861
1862 const cond = c: {
1863 // TODO https://github.com/ziglang/zig/issues/7929
1864 if (if_full.ast.error_token) |error_token| {
1865 return mod.failTok(scope, error_token, "TODO implement if error union", .{});
1866 } else if (if_full.payload_token) |payload_token| {
1867 return mod.failTok(scope, payload_token, "TODO implement if optional", .{});
1868 } else {
1869 const bool_type = try addZIRInstConst(mod, &block_scope.base, if_src, .{
1870 .ty = Type.initTag(.type),
1871 .val = Value.initTag(.bool_type),
1872 });
1873 break :c try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_full.ast.cond_expr);
1874 }
1875 };
18891876
18901877 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{
18911878 .condition = cond,
......@@ -1897,7 +1884,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if")
18971884 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
18981885 });
18991886
1900 const then_src = token_starts[if_node.body.lastToken()];
1887 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];
19011888 var then_scope: Scope.GenZIR = .{
19021889 .parent = scope,
19031890 .decl = block_scope.decl,
......@@ -1908,10 +1895,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if")
19081895 defer then_scope.instructions.deinit(mod.gpa);
19091896
19101897 // declare payload to the then_scope
1911 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload);
1898 const then_sub_scope = &then_scope.base;
19121899
19131900 block_scope.break_count += 1;
1914 const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, if_node.body);
1901 const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr);
19151902 // We hold off on the break instructions as well as copying the then/else
19161903 // instructions into place until we know whether to keep store_to_block_ptr
19171904 // instructions or not.
......@@ -1925,20 +1912,19 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if")
19251912 };
19261913 defer else_scope.instructions.deinit(mod.gpa);
19271914
1928 var else_src: usize = undefined;
1929 var else_sub_scope: *Module.Scope = undefined;
1930 const else_result: ?*zir.Inst = if (if_node.@"else") |else_node| blk: {
1931 else_src = token_starts[else_node.body.lastToken()];
1932 // declare payload to the then_scope
1933 else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
1934
1915 const else_node = if_full.ast.else_expr;
1916 const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
19351917 block_scope.break_count += 1;
1936 break :blk try expr(mod, else_sub_scope, block_scope.break_result_loc, else_node.body);
1937 } else blk: {
1938 else_src = token_starts[if_node.lastToken()];
1939 else_sub_scope = &else_scope.base;
1940 break :blk null;
1941 };
1918 const sub_scope = &else_scope.base;
1919 break :blk .{
1920 .src = token_starts[tree.lastToken(else_node)],
1921 .result = try expr(mod, sub_scope, block_scope.break_result_loc, else_node),
1922 };
1923 } else
1924 .{
1925 .src = token_starts[tree.lastToken(if_full.then_expr)],
1926 .result = null,
1927 };
19421928
19431929 return finishThenElseBlock(
19441930 mod,
......@@ -1950,9 +1936,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if")
19501936 &condbr.positionals.then_body,
19511937 &condbr.positionals.else_body,
19521938 then_src,
1953 else_src,
1939 else_info.src,
19541940 then_result,
1955 else_result,
1941 else_info.result,
19561942 block,
19571943 block,
19581944 );
......@@ -1983,23 +1969,15 @@ fn whileExpr(
19831969 mod: *Module,
19841970 scope: *Scope,
19851971 rl: ResultLoc,
1986 while_node: *ast.Node.@"while",
1972 while_full: ast.full.While,
19871973) InnerError!*zir.Inst {
1988 var cond_kind: CondKind = .bool;
1989 if (while_node.payload) |_| cond_kind = .{ .optional = null };
1990 if (while_node.@"else") |else_node| {
1991 if (else_node.payload) |payload| {
1992 cond_kind = .{ .err_union = null };
1993 }
1974 if (while_full.label_token) |label_token| {
1975 try checkLabelRedefinition(mod, scope, label_token);
19941976 }
1995
1996 if (while_node.label) |label| {
1997 try checkLabelRedefinition(mod, scope, label);
1977 if (while_full.inline_token) |inline_token| {
1978 return mod.failTok(scope, inline_token, "TODO inline while", .{});
19981979 }
19991980
2000 if (while_node.inline_token) |tok|
2001 return mod.failTok(scope, tok, "TODO inline while", .{});
2002
20031981 var loop_scope: Scope.GenZIR = .{
20041982 .parent = scope,
20051983 .decl = scope.ownerDecl().?,
......@@ -2022,12 +2000,25 @@ fn whileExpr(
20222000 const tree = scope.tree();
20232001 const node_datas = tree.nodes.items(.data);
20242002 const main_tokens = tree.nodes.items(.main_token);
2025 const while_src = token_starts[while_node.while_token];
2003 const while_src = token_starts[while_full.ast.while_token];
20262004 const void_type = try addZIRInstConst(mod, scope, while_src, .{
20272005 .ty = Type.initTag(.type),
20282006 .val = Value.initTag(.void_type),
20292007 });
2030 const cond = try cond_kind.cond(mod, &continue_scope, while_src, while_node.condition);
2008 const cond = c: {
2009 // TODO https://github.com/ziglang/zig/issues/7929
2010 if (while_full.ast.error_token) |error_token| {
2011 return mod.failTok(scope, error_token, "TODO implement while error union", .{});
2012 } else if (while_full.payload_token) |payload_token| {
2013 return mod.failTok(scope, payload_token, "TODO implement while optional", .{});
2014 } else {
2015 const bool_type = try addZIRInstConst(mod, &block_scope.base, while_src, .{
2016 .ty = Type.initTag(.type),
2017 .val = Value.initTag(.bool_type),
2018 });
2019 break :c try expr(mod, &block_scope.base, .{ .ty = bool_type }, while_full.ast.cond_expr);
2020 }
2021 };
20312022
20322023 const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{
20332024 .condition = cond,
......@@ -2041,8 +2032,8 @@ fn whileExpr(
20412032 // are no jumps to it. This happens when the last statement of a while body is noreturn
20422033 // and there are no `continue` statements.
20432034 // The "repeat" at the end of a loop body is implied.
2044 if (while_node.continue_expr) |cont_expr| {
2045 _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);
2035 if (while_full.ast.cont_expr != 0) {
2036 _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, while_full.ast.cont_expr);
20462037 }
20472038 const loop = try scope.arena().create(zir.Inst.Loop);
20482039 loop.* = .{
......@@ -2062,14 +2053,14 @@ fn whileExpr(
20622053 });
20632054 loop_scope.break_block = while_block;
20642055 loop_scope.continue_block = cond_block;
2065 if (while_node.label) |some| {
2056 if (while_full.label_token) |label_token| {
20662057 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
2067 .token = some,
2058 .token = label_token,
20682059 .block_inst = while_block,
20692060 });
20702061 }
20712062
2072 const then_src = token_starts[while_node.body.lastToken()];
2063 const then_src = token_starts[tree.lastToken(while_full.ast.then_expr)];
20732064 var then_scope: Scope.GenZIR = .{
20742065 .parent = &continue_scope.base,
20752066 .decl = continue_scope.decl,
......@@ -2080,10 +2071,10 @@ fn whileExpr(
20802071 defer then_scope.instructions.deinit(mod.gpa);
20812072
20822073 // declare payload to the then_scope
2083 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload);
2074 const then_sub_scope = &then_scope.base;
20842075
20852076 loop_scope.break_count += 1;
2086 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_node.body);
2077 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
20872078
20882079 var else_scope: Scope.GenZIR = .{
20892080 .parent = &continue_scope.base,
......@@ -2094,18 +2085,20 @@ fn whileExpr(
20942085 };
20952086 defer else_scope.instructions.deinit(mod.gpa);
20962087
2097 var else_src: usize = undefined;
2098 const else_result: ?*zir.Inst = if (while_node.@"else") |else_node| blk: {
2099 else_src = token_starts[else_node.body.lastToken()];
2100 // declare payload to the then_scope
2101 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
2102
2088 const else_node = if_full.ast.else_expr;
2089 const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
21032090 loop_scope.break_count += 1;
2104 break :blk try expr(mod, else_sub_scope, loop_scope.break_result_loc, else_node.body);
2105 } else blk: {
2106 else_src = token_starts[while_node.lastToken()];
2107 break :blk null;
2108 };
2091 const sub_scope = &else_scope.base;
2092 break :blk .{
2093 .src = token_starts[tree.lastToken(else_node)],
2094 .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node),
2095 };
2096 } else
2097 .{
2098 .src = token_starts[tree.lastToken(then_node)],
2099 .result = null,
2100 };
2101
21092102 if (loop_scope.label) |some| {
21102103 if (!some.used) {
21112104 return mod.fail(scope, token_starts[some.token], "unused while label", .{});
......@@ -2121,9 +2114,9 @@ fn whileExpr(
21212114 &condbr.positionals.then_body,
21222115 &condbr.positionals.else_body,
21232116 then_src,
2124 else_src,
2117 else_info.src,
21252118 then_result,
2126 else_result,
2119 else_info.result,
21272120 while_block,
21282121 cond_block,
21292122 );
......@@ -2630,12 +2623,13 @@ fn switchCaseExpr(
26302623 }
26312624}
26322625
2633fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
2626fn ret(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
26342627 const tree = scope.tree();
26352628 const node_datas = tree.nodes.items(.data);
26362629 const main_tokens = tree.nodes.items(.main_token);
2637 const src = token_starts[cfe.ltoken];
2638 if (cfe.getRHS()) |rhs_node| {
2630 const src = token_starts[main_tokens[node]];
2631 const rhs_node = node_datas[node].lhs;
2632 if (rhs_node != 0) {
26392633 if (nodeMayNeedMemoryLocation(rhs_node, scope)) {
26402634 const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr);
26412635 const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
......@@ -2885,64 +2879,29 @@ fn integerLiteral(
28852879 }
28862880}
28872881
2888fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
2882fn floatLiteral(
2883 mod: *Module,
2884 scope: *Scope,
2885 rl: ResultLoc,
2886 float_lit: ast.Node.Index,
2887) InnerError!*zir.Inst {
28892888 const arena = scope.arena();
28902889 const tree = scope.tree();
2891 const node_datas = tree.nodes.items(.data);
28922890 const main_tokens = tree.nodes.items(.main_token);
2893 const bytes = tree.tokenSlice(float_lit.token);
2891 const main_token = main_tokens[float_lit];
2892 const bytes = tree.tokenSlice(main_token);
28942893 if (bytes.len > 2 and bytes[1] == 'x') {
2895 return mod.failTok(scope, float_lit.token, "TODO hex floats", .{});
2894 return mod.failTok(scope, main_token, "TODO implement hex floats", .{});
28962895 }
2897
28982896 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
28992897 error.InvalidCharacter => unreachable, // validated by tokenizer
29002898 };
2901 const src = token_starts[float_lit.token];
2902 return addZIRInstConst(mod, scope, src, .{
2899 const src = token_starts[main_token];
2900 const result = try addZIRInstConst(mod, scope, src, .{
29032901 .ty = Type.initTag(.comptime_float),
29042902 .val = try Value.Tag.float_128.create(arena, float_number),
29052903 });
2906}
2907
2908fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
2909 const arena = scope.arena();
2910 const tree = scope.tree();
2911 const node_datas = tree.nodes.items(.data);
2912 const main_tokens = tree.nodes.items(.main_token);
2913 const src = token_starts[node.token];
2914 return addZIRInstConst(mod, scope, src, .{
2915 .ty = Type.initTag(.@"undefined"),
2916 .val = Value.initTag(.undef),
2917 });
2918}
2919
2920fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
2921 const arena = scope.arena();
2922 const tree = scope.tree();
2923 const node_datas = tree.nodes.items(.data);
2924 const main_tokens = tree.nodes.items(.main_token);
2925 const src = token_starts[node.token];
2926 return addZIRInstConst(mod, scope, src, .{
2927 .ty = Type.initTag(.bool),
2928 .val = switch (tree.token_ids[node.token]) {
2929 .keyword_true => Value.initTag(.bool_true),
2930 .keyword_false => Value.initTag(.bool_false),
2931 else => unreachable,
2932 },
2933 });
2934}
2935
2936fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
2937 const arena = scope.arena();
2938 const tree = scope.tree();
2939 const node_datas = tree.nodes.items(.data);
2940 const main_tokens = tree.nodes.items(.main_token);
2941 const src = token_starts[node.token];
2942 return addZIRInstConst(mod, scope, src, .{
2943 .ty = Type.initTag(.@"null"),
2944 .val = Value.initTag(.null_value),
2945 });
2904 return rvalue(mod, scope, rl, result);
29462905}
29472906
29482907fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!*zir.Inst {
......@@ -2987,76 +2946,36 @@ fn assembly(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) Inne
29872946 return rvalue(mod, scope, rl, asm_inst);
29882947}
29892948
2990fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call, count: u32) !void {
2991 if (call.params_len == count)
2992 return;
2993
2994 const s = if (count == 1) "" else "s";
2995 return mod.failTok(scope, call.builtin_token, "expected {d} parameter{s}, found {d}", .{ count, s, call.params_len });
2996}
2997
2998fn simpleCast(
2999 mod: *Module,
3000 scope: *Scope,
3001 rl: ResultLoc,
3002 call: *ast.Node.builtin_call,
3003 inst_tag: zir.Inst.Tag,
3004) InnerError!*zir.Inst {
3005 try ensureBuiltinParamCount(mod, scope, call, 2);
3006 const tree = scope.tree();
3007 const node_datas = tree.nodes.items(.data);
3008 const main_tokens = tree.nodes.items(.main_token);
3009 const src = token_starts[call.builtin_token];
3010 const params = call.params();
3011 const dest_type = try typeExpr(mod, scope, params[0]);
3012 const rhs = try expr(mod, scope, .none, params[1]);
3013 const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs);
3014 return rvalue(mod, scope, rl, result);
3015}
3016
3017fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3018 try ensureBuiltinParamCount(mod, scope, call, 1);
3019 const operand = try expr(mod, scope, .none, call.params()[0]);
3020 const tree = scope.tree();
3021 const node_datas = tree.nodes.items(.data);
3022 const main_tokens = tree.nodes.items(.main_token);
3023 const src = token_starts[call.builtin_token];
3024 return addZIRUnOp(mod, scope, src, .ptrtoint, operand);
3025}
3026
30272949fn as(
30282950 mod: *Module,
30292951 scope: *Scope,
30302952 rl: ResultLoc,
3031 call: *ast.Node.builtin_call,
2953 builtin_token: ast.TokenIndex,
2954 src: usize,
2955 lhs: ast.Node.Index,
2956 rhs: ast.Node.Index,
30322957) InnerError!*zir.Inst {
3033 try ensureBuiltinParamCount(mod, scope, call, 2);
3034 const tree = scope.tree();
3035 const node_datas = tree.nodes.items(.data);
3036 const main_tokens = tree.nodes.items(.main_token);
3037 const src = token_starts[call.builtin_token];
3038 const params = call.params();
3039 const dest_type = try typeExpr(mod, scope, params[0]);
2958 const dest_type = try typeExpr(mod, scope, lhs);
30402959 switch (rl) {
30412960 .none, .discard, .ref, .ty => {
3042 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
2961 const result = try expr(mod, scope, .{ .ty = dest_type }, rhs);
30432962 return rvalue(mod, scope, rl, result);
30442963 },
30452964
30462965 .ptr => |result_ptr| {
3047 return asRlPtr(mod, scope, rl, src, result_ptr, params[1], dest_type);
2966 return asRlPtr(mod, scope, rl, src, result_ptr, rhs, dest_type);
30482967 },
30492968 .block_ptr => |block_scope| {
3050 return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, params[1], dest_type);
2969 return asRlPtr(mod, scope, rl, src, block_scope.rl_ptr.?, rhs, dest_type);
30512970 },
30522971
30532972 .bitcasted_ptr => |bitcasted_ptr| {
30542973 // TODO here we should be able to resolve the inference; we now have a type for the result.
3055 return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{});
2974 return mod.failTok(scope, builtin_token, "TODO implement @as with result location @bitCast", .{});
30562975 },
30572976 .inferred_ptr => |result_alloc| {
30582977 // TODO here we should be able to resolve the inference; we now have a type for the result.
3059 return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{});
2978 return mod.failTok(scope, builtin_token, "TODO implement @as with inferred-type result location pointer", .{});
30602979 },
30612980 }
30622981}
......@@ -3105,170 +3024,290 @@ fn asRlPtr(
31053024 }
31063025}
31073026
3108fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3109 try ensureBuiltinParamCount(mod, scope, call, 2);
3110 const tree = scope.tree();
3111 const node_datas = tree.nodes.items(.data);
3112 const main_tokens = tree.nodes.items(.main_token);
3113 const src = token_starts[call.builtin_token];
3114 const params = call.params();
3115 const dest_type = try typeExpr(mod, scope, params[0]);
3027fn bitCast(
3028 mod: *Module,
3029 scope: *Scope,
3030 rl: ResultLoc,
3031 builtin_token: ast.TokenIndex,
3032 src: usize,
3033 lhs: ast.Node.Index,
3034 rhs: ast.Node.Index,
3035) InnerError!*zir.Inst {
3036 const dest_type = try typeExpr(mod, scope, lhs);
31163037 switch (rl) {
31173038 .none => {
3118 const operand = try expr(mod, scope, .none, params[1]);
3039 const operand = try expr(mod, scope, .none, rhs);
31193040 return addZIRBinOp(mod, scope, src, .bitcast, dest_type, operand);
31203041 },
31213042 .discard => {
3122 const operand = try expr(mod, scope, .none, params[1]);
3043 const operand = try expr(mod, scope, .none, rhs);
31233044 const result = try addZIRBinOp(mod, scope, src, .bitcast, dest_type, operand);
31243045 _ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
31253046 return result;
31263047 },
31273048 .ref => {
3128 const operand = try expr(mod, scope, .ref, params[1]);
3049 const operand = try expr(mod, scope, .ref, rhs);
31293050 const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand);
31303051 return result;
31313052 },
31323053 .ty => |result_ty| {
3133 const result = try expr(mod, scope, .none, params[1]);
3054 const result = try expr(mod, scope, .none, rhs);
31343055 const bitcasted = try addZIRBinOp(mod, scope, src, .bitcast, dest_type, result);
31353056 return addZIRBinOp(mod, scope, src, .as, result_ty, bitcasted);
31363057 },
31373058 .ptr => |result_ptr| {
31383059 const casted_result_ptr = try addZIRUnOp(mod, scope, src, .bitcast_result_ptr, result_ptr);
3139 return expr(mod, scope, .{ .bitcasted_ptr = casted_result_ptr.castTag(.bitcast_result_ptr).? }, params[1]);
3060 return expr(mod, scope, .{ .bitcasted_ptr = casted_result_ptr.castTag(.bitcast_result_ptr).? }, rhs);
31403061 },
31413062 .bitcasted_ptr => |bitcasted_ptr| {
3142 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location another @bitCast", .{});
3063 return mod.failTok(scope, builtin_token, "TODO implement @bitCast with result location another @bitCast", .{});
31433064 },
31443065 .block_ptr => |block_ptr| {
3145 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location inferred peer types", .{});
3066 return mod.failTok(scope, builtin_token, "TODO implement @bitCast with result location inferred peer types", .{});
31463067 },
31473068 .inferred_ptr => |result_alloc| {
31483069 // TODO here we should be able to resolve the inference; we now have a type for the result.
3149 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with inferred-type result location pointer", .{});
3070 return mod.failTok(scope, builtin_token, "TODO implement @bitCast with inferred-type result location pointer", .{});
31503071 },
31513072 }
31523073}
31533074
3154fn import(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3155 try ensureBuiltinParamCount(mod, scope, call, 1);
3156 const tree = scope.tree();
3157 const node_datas = tree.nodes.items(.data);
3158 const main_tokens = tree.nodes.items(.main_token);
3159 const src = token_starts[call.builtin_token];
3160 const params = call.params();
3161 const target = try expr(mod, scope, .none, params[0]);
3162 return addZIRUnOp(mod, scope, src, .import, target);
3163}
3164
3165fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3166 try ensureBuiltinParamCount(mod, scope, call, 1);
3167 const tree = scope.tree();
3168 const node_datas = tree.nodes.items(.data);
3169 const main_tokens = tree.nodes.items(.main_token);
3170 const src = token_starts[call.builtin_token];
3171 const params = call.params();
3172 const target = try expr(mod, scope, .none, params[0]);
3173 return addZIRUnOp(mod, scope, src, .compile_error, target);
3174}
3175
3176fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3177 try ensureBuiltinParamCount(mod, scope, call, 1);
3178 const tree = scope.tree();
3179 const node_datas = tree.nodes.items(.data);
3180 const main_tokens = tree.nodes.items(.main_token);
3181 const src = token_starts[call.builtin_token];
3182 const params = call.params();
3183 const u32_type = try addZIRInstConst(mod, scope, src, .{
3184 .ty = Type.initTag(.type),
3185 .val = Value.initTag(.u32_type),
3186 });
3187 const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]);
3188 return addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota);
3189}
3190
3191fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3192 const tree = scope.tree();
3193 const node_datas = tree.nodes.items(.data);
3194 const main_tokens = tree.nodes.items(.main_token);
3195 const arena = scope.arena();
3196 const src = token_starts[call.builtin_token];
3197 const params = call.params();
3075fn typeOf(
3076 mod: *Module,
3077 scope: *Scope,
3078 rl: ResultLoc,
3079 builtin_token: ast.TokenIndex,
3080 src: usize,
3081 params: []const ast.Node.Index,
3082) InnerError!*zir.Inst {
31983083 if (params.len < 1) {
3199 return mod.failTok(scope, call.builtin_token, "expected at least 1 argument, found 0", .{});
3084 return mod.failTok(scope, builtin_token, "expected at least 1 argument, found 0", .{});
32003085 }
32013086 if (params.len == 1) {
32023087 return rvalue(mod, scope, rl, try addZIRUnOp(mod, scope, src, .typeof, try expr(mod, scope, .none, params[0])));
32033088 }
3089 const arena = scope.arena();
32043090 var items = try arena.alloc(*zir.Inst, params.len);
32053091 for (params) |param, param_i|
32063092 items[param_i] = try expr(mod, scope, .none, param);
32073093 return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.TypeOfPeer, .{ .items = items }, .{}));
32083094}
3209fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3210 const tree = scope.tree();
3211 const node_datas = tree.nodes.items(.data);
3212 const main_tokens = tree.nodes.items(.main_token);
3213 const arena = scope.arena();
3214 const src = token_starts[call.builtin_token];
3215 const params = call.params();
3216 var targets = try arena.alloc(*zir.Inst, params.len);
3217 for (params) |param, param_i|
3218 targets[param_i] = try expr(mod, scope, .none, param);
3219 return addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{});
3220}
32213095
3222fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst {
3096fn builtinCall(
3097 mod: *Module,
3098 scope: *Scope,
3099 rl: ResultLoc,
3100 call: ast.Node.Index,
3101 params: []const ast.Node.Index,
3102) InnerError!*zir.Inst {
32233103 const tree = scope.tree();
32243104 const node_datas = tree.nodes.items(.data);
32253105 const main_tokens = tree.nodes.items(.main_token);
3226 const builtin_name = tree.tokenSlice(call.builtin_token);
3106 const builtin_token = main_tokens[call];
3107 const builtin_name = tree.tokenSlice(builtin_token);
32273108
32283109 // We handle the different builtins manually because they have different semantics depending
32293110 // on the function. For example, `@as` and others participate in result location semantics,
32303111 // and `@cImport` creates a special scope that collects a .c source code text buffer.
32313112 // Also, some builtins have a variable number of parameters.
32323113
3233 if (mem.eql(u8, builtin_name, "@ptrToInt")) {
3234 return rvalue(mod, scope, rl, try ptrToInt(mod, scope, call));
3235 } else if (mem.eql(u8, builtin_name, "@as")) {
3236 return as(mod, scope, rl, call);
3237 } else if (mem.eql(u8, builtin_name, "@floatCast")) {
3238 return simpleCast(mod, scope, rl, call, .floatcast);
3239 } else if (mem.eql(u8, builtin_name, "@intCast")) {
3240 return simpleCast(mod, scope, rl, call, .intcast);
3241 } else if (mem.eql(u8, builtin_name, "@bitCast")) {
3242 return bitCast(mod, scope, rl, call);
3243 } else if (mem.eql(u8, builtin_name, "@TypeOf")) {
3244 return typeOf(mod, scope, rl, call);
3245 } else if (mem.eql(u8, builtin_name, "@breakpoint")) {
3246 const src = token_starts[call.builtin_token];
3247 return rvalue(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));
3248 } else if (mem.eql(u8, builtin_name, "@import")) {
3249 return rvalue(mod, scope, rl, try import(mod, scope, call));
3250 } else if (mem.eql(u8, builtin_name, "@compileError")) {
3251 return compileError(mod, scope, call);
3252 } else if (mem.eql(u8, builtin_name, "@setEvalBranchQuota")) {
3253 return setEvalBranchQuota(mod, scope, call);
3254 } else if (mem.eql(u8, builtin_name, "@compileLog")) {
3255 return compileLog(mod, scope, call);
3256 } else if (mem.eql(u8, builtin_name, "@field")) {
3257 return namedField(mod, scope, rl, call);
3258 } else {
3259 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name});
3114 const info = BuiltinFn.list.get(builtin_name) orelse {
3115 return mod.failTok(scope, builtin_token, "invalid builtin function: '{s}'", .{
3116 builtin_name,
3117 });
3118 };
3119 if (info.param_count != params.len) {
3120 const s = if (params.len == 1) "" else "s";
3121 return mod.failTok(scope, builtin_token, "expected {d} parameter{s}, found {d}", .{
3122 expected, s, found,
3123 });
3124 }
3125 const src = token_starts[builtin_token];
3126
3127 switch (info.tag) {
3128 .ptr_to_int => {
3129 const operand = try expr(mod, scope, .none, params[0]);
3130 const result = try addZIRUnOp(mod, scope, src, .ptrtoint, operand);
3131 return rvalue(mod, scope, rl, result);
3132 },
3133 .float_cast => {
3134 const dest_type = try typeExpr(mod, scope, params[0]);
3135 const rhs = try expr(mod, scope, .none, params[1]);
3136 const result = try addZIRBinOp(mod, scope, src, .floatcast, dest_type, rhs);
3137 return rvalue(mod, scope, rl, result);
3138 },
3139 .int_cast => {
3140 const dest_type = try typeExpr(mod, scope, params[0]);
3141 const rhs = try expr(mod, scope, .none, params[1]);
3142 const result = try addZIRBinOp(mod, scope, src, .intcast, dest_type, rhs);
3143 return rvalue(mod, scope, rl, result);
3144 },
3145 .breakpoint => {
3146 const result = try addZIRNoOp(mod, scope, src, .breakpoint);
3147 return rvalue(mod, scope, rl, result);
3148 },
3149 .import => {
3150 const target = try expr(mod, scope, .none, params[0]);
3151 const result = try addZIRUnOp(mod, scope, src, .import, target);
3152 return rvalue(mod, scope, rl, result);
3153 },
3154 .compile_error => {
3155 const target = try expr(mod, scope, .none, params[0]);
3156 const result = addZIRUnOp(mod, scope, src, .compile_error, target);
3157 return rvalue(mod, scope, rl, result);
3158 },
3159 .set_eval_branch_quota => {
3160 const u32_type = try addZIRInstConst(mod, scope, src, .{
3161 .ty = Type.initTag(.type),
3162 .val = Value.initTag(.u32_type),
3163 });
3164 const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]);
3165 const result = try addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota);
3166 return rvalue(mod, scope, rl, result);
3167 },
3168 .compile_log => {
3169 const arena = scope.arena();
3170 var targets = try arena.alloc(*zir.Inst, params.len);
3171 for (params) |param, param_i|
3172 targets[param_i] = try expr(mod, scope, .none, param);
3173 const result = try addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{});
3174 return rvalue(mod, scope, rl, result);
3175 },
3176 .field => {
3177 const string_type = try addZIRInstConst(mod, scope, src, .{
3178 .ty = Type.initTag(.type),
3179 .val = Value.initTag(.const_slice_u8_type),
3180 });
3181 const string_rl: ResultLoc = .{ .ty = string_type };
3182
3183 if (rl == .ref) {
3184 return addZirInstTag(mod, scope, src, .field_ptr_named, .{
3185 .object = try expr(mod, scope, .ref, params[0]),
3186 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
3187 });
3188 }
3189 return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{
3190 .object = try expr(mod, scope, .none, params[0]),
3191 .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
3192 }));
3193 },
3194 .as => return as(mod, scope, rl, builtin_token, src, params[0], params[1]),
3195 .bit_cast => return bitCast(mod, scope, rl, builtin_token, src, params[0], params[1]),
3196 .TypeOf => return typeOf(mod, scope, rl, builtin_token, src, params),
3197
3198 .add_with_overflow,
3199 .align_cast,
3200 .align_of,
3201 .async_call,
3202 .atomic_load,
3203 .atomic_rmw,
3204 .atomic_store,
3205 .bit_offset_of,
3206 .bool_to_int,
3207 .bit_size_of,
3208 .mul_add,
3209 .byte_swap,
3210 .bit_reverse,
3211 .byte_offset_of,
3212 .call,
3213 .c_define,
3214 .c_import,
3215 .c_include,
3216 .clz,
3217 .cmpxchg_strong,
3218 .cmpxchg_weak,
3219 .ctz,
3220 .c_undef,
3221 .div_exact,
3222 .div_floor,
3223 .div_trunc,
3224 .embed_file,
3225 .enum_to_int,
3226 .error_name,
3227 .error_return_trace,
3228 .error_to_int,
3229 .err_set_cast,
3230 .@"export",
3231 .fence,
3232 .field_parent_ptr,
3233 .float_to_int,
3234 .frame,
3235 .Frame,
3236 .frame_address,
3237 .frame_size,
3238 .has_decl,
3239 .has_field,
3240 .int_to_enum,
3241 .int_to_error,
3242 .int_to_float,
3243 .int_to_ptr,
3244 .memcpy,
3245 .memset,
3246 .wasm_memory_size,
3247 .wasm_memory_grow,
3248 .mod,
3249 .mul_with_overflow,
3250 .panic,
3251 .pop_count,
3252 .ptr_cast,
3253 .rem,
3254 .return_address,
3255 .set_align_stack,
3256 .set_cold,
3257 .set_float_mode,
3258 .set_runtime_safety,
3259 .shl_exact,
3260 .shl_with_overflow,
3261 .shr_exact,
3262 .shuffle,
3263 .size_of,
3264 .splat,
3265 .reduce,
3266 .src,
3267 .sqrt,
3268 .sin,
3269 .cos,
3270 .exp,
3271 .exp2,
3272 .log,
3273 .log2,
3274 .log10,
3275 .fabs,
3276 .floor,
3277 .ceil,
3278 .trunc,
3279 .round,
3280 .sub_with_overflow,
3281 .tag_name,
3282 .This,
3283 .truncate,
3284 .Type,
3285 .type_info,
3286 .type_name,
3287 .union_init,
3288 => return mod.failTok(scope, builtin_token, "TODO: implement builtin function {s}", .{
3289 builtin_name,
3290 }),
32603291 }
32613292}
32623293
3263fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.call) InnerError!*zir.Inst {
3294fn callExpr(
3295 mod: *Module,
3296 scope: *Scope,
3297 rl: ResultLoc,
3298 call: ast.full.Call,
3299) InnerError!*zir.Inst {
3300 if (call.async_token) |async_token| {
3301 return mod.failTok(scope, async_token, "TODO implement async fn call", .{});
3302 }
3303
32643304 const tree = scope.tree();
32653305 const node_datas = tree.nodes.items(.data);
32663306 const main_tokens = tree.nodes.items(.main_token);
3267 const lhs = try expr(mod, scope, .none, node.lhs);
3307 const lhs = try expr(mod, scope, .none, call.ast.fn_expr);
32683308
3269 const param_nodes = node.params();
3270 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);
3271 for (param_nodes) |param_node, i| {
3309 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, call.ast.params.len);
3310 for (call.ast.params) |param_node, i| {
32723311 const param_src = token_starts[tree.firstToken(param_node)];
32733312 const param_type = try addZIRInst(mod, scope, param_src, zir.Inst.ParamType, .{
32743313 .func = lhs,
......@@ -3277,7 +3316,7 @@ fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.call) In
32773316 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
32783317 }
32793318
3280 const src = token_starts[node.lhs.firstToken()];
3319 const src = token_starts[call.ast.lparen];
32813320 const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{
32823321 .func = lhs,
32833322 .args = args,
......@@ -3286,14 +3325,6 @@ fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.call) In
32863325 return rvalue(mod, scope, rl, result);
32873326}
32883327
3289fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst {
3290 const tree = scope.tree();
3291 const node_datas = tree.nodes.items(.data);
3292 const main_tokens = tree.nodes.items(.main_token);
3293 const src = token_starts[unreach_node.token];
3294 return addZIRNoOp(mod, scope, src, .unreachable_safe);
3295}
3296
32973328fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
32983329 const simple_types = std.ComptimeStringMap(Value.Tag, .{
32993330 .{ "u8", .u8_type },
......@@ -3430,17 +3461,25 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
34303461 .deref,
34313462 .array_access,
34323463 .block,
3464 .while_simple, // This variant cannot have an else expression.
3465 .while_cont, // This variant cannot have an else expression.
3466 .for_simple, // This variant cannot have an else expression.
3467 .if_simple, // This variant cannot have an else expression.
34333468 => return false,
34343469
3435 // Forward the question to a sub-expression.
3436 .grouped_expression => node = node.castTag(.grouped_expression).?.expr,
3437 .@"try" => node = node.castTag(.@"try").?.rhs,
3438 .@"await" => node = node.castTag(.@"await").?.rhs,
3439 .@"catch" => node = node.castTag(.@"catch").?.rhs,
3440 .@"orelse" => node = node.castTag(.@"orelse").?.rhs,
3441 .@"comptime" => node = node.castTag(.@"comptime").?.expr,
3442 .@"nosuspend" => node = node.castTag(.@"nosuspend").?.expr,
3443 .unwrap_optional => node = node.castTag(.unwrap_optional).?.lhs,
3470 // Forward the question to the LHS sub-expression.
3471 .grouped_expression,
3472 .@"try",
3473 .@"await",
3474 .@"comptime",
3475 .@"nosuspend",
3476 .unwrap_optional,
3477 => node = datas[node].lhs,
3478
3479 // Forward the question to the RHS sub-expression.
3480 .@"catch",
3481 .@"orelse",
3482 => node = datas[node].rhs,
34443483
34453484 // True because these are exactly the expressions we need memory locations for.
34463485 .ArrayInitializer,
......@@ -3451,125 +3490,43 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool {
34513490
34523491 // True because depending on comptime conditions, sub-expressions
34533492 // may be the kind that need memory locations.
3454 .@"while",
3455 .@"for",
3493 .@"while", // This variant always has an else expression.
3494 .@"if", // This variant always has an else expression.
3495 .@"for", // This variant always has an else expression.
34563496 .@"switch",
3497 .call_one,
3498 .call_one_comma,
3499 .async_call_one,
3500 .async_call_one_comma,
34573501 .call,
3458 .labeled_block,
3502 .call_comma,
3503 .async_call,
3504 .async_call_comma,
34593505 => return true,
34603506
3461 .builtin_call => {
3462 @setEvalBranchQuota(5000);
3463 const builtin_needs_mem_loc = std.ComptimeStringMap(bool, .{
3464 .{ "@addWithOverflow", false },
3465 .{ "@alignCast", false },
3466 .{ "@alignOf", false },
3467 .{ "@as", true },
3468 .{ "@asyncCall", false },
3469 .{ "@atomicLoad", false },
3470 .{ "@atomicRmw", false },
3471 .{ "@atomicStore", false },
3472 .{ "@bitCast", true },
3473 .{ "@bitOffsetOf", false },
3474 .{ "@boolToInt", false },
3475 .{ "@bitSizeOf", false },
3476 .{ "@breakpoint", false },
3477 .{ "@mulAdd", false },
3478 .{ "@byteSwap", false },
3479 .{ "@bitReverse", false },
3480 .{ "@byteOffsetOf", false },
3481 .{ "@call", true },
3482 .{ "@cDefine", false },
3483 .{ "@cImport", false },
3484 .{ "@cInclude", false },
3485 .{ "@clz", false },
3486 .{ "@cmpxchgStrong", false },
3487 .{ "@cmpxchgWeak", false },
3488 .{ "@compileError", false },
3489 .{ "@compileLog", false },
3490 .{ "@ctz", false },
3491 .{ "@cUndef", false },
3492 .{ "@divExact", false },
3493 .{ "@divFloor", false },
3494 .{ "@divTrunc", false },
3495 .{ "@embedFile", false },
3496 .{ "@enumToInt", false },
3497 .{ "@errorName", false },
3498 .{ "@errorReturnTrace", false },
3499 .{ "@errorToInt", false },
3500 .{ "@errSetCast", false },
3501 .{ "@export", false },
3502 .{ "@fence", false },
3503 .{ "@field", true },
3504 .{ "@fieldParentPtr", false },
3505 .{ "@floatCast", false },
3506 .{ "@floatToInt", false },
3507 .{ "@frame", false },
3508 .{ "@Frame", false },
3509 .{ "@frameAddress", false },
3510 .{ "@frameSize", false },
3511 .{ "@hasDecl", false },
3512 .{ "@hasField", false },
3513 .{ "@import", false },
3514 .{ "@intCast", false },
3515 .{ "@intToEnum", false },
3516 .{ "@intToError", false },
3517 .{ "@intToFloat", false },
3518 .{ "@intToPtr", false },
3519 .{ "@memcpy", false },
3520 .{ "@memset", false },
3521 .{ "@wasmMemorySize", false },
3522 .{ "@wasmMemoryGrow", false },
3523 .{ "@mod", false },
3524 .{ "@mulWithOverflow", false },
3525 .{ "@panic", false },
3526 .{ "@popCount", false },
3527 .{ "@ptrCast", false },
3528 .{ "@ptrToInt", false },
3529 .{ "@rem", false },
3530 .{ "@returnAddress", false },
3531 .{ "@setAlignStack", false },
3532 .{ "@setCold", false },
3533 .{ "@setEvalBranchQuota", false },
3534 .{ "@setFloatMode", false },
3535 .{ "@setRuntimeSafety", false },
3536 .{ "@shlExact", false },
3537 .{ "@shlWithOverflow", false },
3538 .{ "@shrExact", false },
3539 .{ "@shuffle", false },
3540 .{ "@sizeOf", false },
3541 .{ "@splat", true },
3542 .{ "@reduce", false },
3543 .{ "@src", true },
3544 .{ "@sqrt", false },
3545 .{ "@sin", false },
3546 .{ "@cos", false },
3547 .{ "@exp", false },
3548 .{ "@exp2", false },
3549 .{ "@log", false },
3550 .{ "@log2", false },
3551 .{ "@log10", false },
3552 .{ "@fabs", false },
3553 .{ "@floor", false },
3554 .{ "@ceil", false },
3555 .{ "@trunc", false },
3556 .{ "@round", false },
3557 .{ "@subWithOverflow", false },
3558 .{ "@tagName", false },
3559 .{ "@This", false },
3560 .{ "@truncate", false },
3561 .{ "@Type", false },
3562 .{ "@typeInfo", false },
3563 .{ "@typeName", false },
3564 .{ "@TypeOf", false },
3565 .{ "@unionInit", true },
3566 });
3567 const name = scope.tree().tokenSlice(node.castTag(.builtin_call).?.builtin_token);
3568 return builtin_needs_mem_loc.get(name).?;
3507 block_two,
3508 block_two_semicolon,
3509 block,
3510 block_semicolon,
3511 => {
3512 const lbrace = main_tokens[node];
3513 if (token_tags[lbrace - 1] == .colon) {
3514 // Labeled blocks may need a memory location to forward
3515 // to their break statements.
3516 return true;
3517 } else {
3518 return false;
3519 }
35693520 },
35703521
3571 // Depending on AST properties, they may need memory locations.
3572 .@"if" => return node.castTag(.@"if").?.@"else" != null,
3522 .builtin_call => {
3523 const builtin_token = main_tokens[node];
3524 const builtin_name = tree.tokenSlice(builtin_token);
3525 // If the builtin is an invalid name, we don't cause an error here; instead
3526 // let it pass, and the error will be "invalid builtin function" later.
3527 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false;
3528 return builtin_info.needs_mem_loc;
3529 },
35733530 }
35743531 }
35753532}