authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-18 17:40:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-18 17:43:36-04:00
logbd1c55d2c2c9b68b5b6de175219cf95c815bf275
tree2f0e49f22faca592450f5a9e3c9451bb83df41c6
parentaa3b41247f297b4fd8b3bdb7920cb479f5aa004b

self-hosted: compile errors for return in wrong place

* outside fn definition * inside defer expression

4 files changed, 555 insertions(+), 175 deletions(-)

src-self-hosted/compilation.zig+75-31
......@@ -207,6 +207,8 @@ pub const Compilation = struct {
207207
208208 destroy_handle: promise,
209209
210 have_err_ret_tracing: bool,
211
210212 const CompileErrList = std.ArrayList(*errmsg.Msg);
211213
212214 // TODO handle some of these earlier and report them in a way other than error codes
......@@ -379,6 +381,7 @@ pub const Compilation = struct {
379381
380382 .override_libc = null,
381383 .destroy_handle = undefined,
384 .have_err_ret_tracing = false,
382385 });
383386 errdefer {
384387 comp.arena_allocator.deinit();
......@@ -660,7 +663,11 @@ pub const Compilation = struct {
660663 while (it.next()) |decl_ptr| {
661664 const decl = decl_ptr.*;
662665 switch (decl.id) {
663 ast.Node.Id.Comptime => @panic("TODO"),
666 ast.Node.Id.Comptime => {
667 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl);
668
669 try decl_group.call(addCompTimeBlock, self, parsed_file, &decls.base, comptime_node);
670 },
664671 ast.Node.Id.VarDecl => @panic("TODO"),
665672 ast.Node.Id.FnProto => {
666673 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
......@@ -709,6 +716,69 @@ pub const Compilation = struct {
709716 }
710717 }
711718
719 /// caller takes ownership of resulting Code
720 async fn genAndAnalyzeCode(
721 comp: *Compilation,
722 parsed_file: *ParsedFile,
723 scope: *Scope,
724 node: *ast.Node,
725 expected_type: ?*Type,
726 ) !?*ir.Code {
727 const unanalyzed_code = (await (async ir.gen(
728 comp,
729 node,
730 scope,
731 parsed_file,
732 ) catch unreachable)) catch |err| switch (err) {
733 // This poison value should not cause the errdefers to run. It simply means
734 // that self.compile_errors is populated.
735 // TODO https://github.com/ziglang/zig/issues/769
736 error.SemanticAnalysisFailed => return null,
737 else => return err,
738 };
739 defer unanalyzed_code.destroy(comp.gpa());
740
741 if (comp.verbose_ir) {
742 std.debug.warn("unanalyzed:\n");
743 unanalyzed_code.dump();
744 }
745
746 const analyzed_code = (await (async ir.analyze(
747 comp,
748 parsed_file,
749 unanalyzed_code,
750 expected_type,
751 ) catch unreachable)) catch |err| switch (err) {
752 // This poison value should not cause the errdefers to run. It simply means
753 // that self.compile_errors is populated.
754 // TODO https://github.com/ziglang/zig/issues/769
755 error.SemanticAnalysisFailed => return null,
756 else => return err,
757 };
758 errdefer analyzed_code.destroy(comp.gpa());
759
760 return analyzed_code;
761 }
762
763 async fn addCompTimeBlock(
764 comp: *Compilation,
765 parsed_file: *ParsedFile,
766 scope: *Scope,
767 comptime_node: *ast.Node.Comptime,
768 ) !void {
769 const void_type = Type.Void.get(comp);
770 defer void_type.base.base.deref(comp);
771
772 const analyzed_code = (try await (async genAndAnalyzeCode(
773 comp,
774 parsed_file,
775 scope,
776 comptime_node.expr,
777 &void_type.base,
778 ) catch unreachable)) orelse return;
779 analyzed_code.destroy(comp.gpa());
780 }
781
712782 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {
713783 const is_export = decl.isExported(&decl.parsed_file.tree);
714784
......@@ -931,38 +1001,12 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
9311001 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
9321002 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
9331003
934 const unanalyzed_code = (await (async ir.gen(
935 comp,
936 body_node,
937 &fndef_scope.base,
938 Span.token(body_node.lastToken()),
1004 const analyzed_code = (try await (async comp.genAndAnalyzeCode(
9391005 fn_decl.base.parsed_file,
940 ) catch unreachable)) catch |err| switch (err) {
941 // This poison value should not cause the errdefers to run. It simply means
942 // that self.compile_errors is populated.
943 // TODO https://github.com/ziglang/zig/issues/769
944 error.SemanticAnalysisFailed => return {},
945 else => return err,
946 };
947 defer unanalyzed_code.destroy(comp.gpa());
948
949 if (comp.verbose_ir) {
950 std.debug.warn("unanalyzed:\n");
951 unanalyzed_code.dump();
952 }
953
954 const analyzed_code = (await (async ir.analyze(
955 comp,
956 fn_decl.base.parsed_file,
957 unanalyzed_code,
1006 &fndef_scope.base,
1007 body_node,
9581008 null,
959 ) catch unreachable)) catch |err| switch (err) {
960 // This poison value should not cause the errdefers to run. It simply means
961 // that self.compile_errors is populated.
962 // TODO https://github.com/ziglang/zig/issues/769
963 error.SemanticAnalysisFailed => return {},
964 else => return err,
965 };
1009 ) catch unreachable)) orelse return;
9661010 errdefer analyzed_code.destroy(comp.gpa());
9671011
9681012 if (comp.verbose_ir) {
src-self-hosted/ir.zig+446-142
......@@ -46,7 +46,7 @@ pub const IrVal = union(enum) {
4646 }
4747};
4848
49pub const Instruction = struct {
49pub const Inst = struct {
5050 id: Id,
5151 scope: *Scope,
5252 debug_id: usize,
......@@ -59,15 +59,15 @@ pub const Instruction = struct {
5959 is_generated: bool,
6060
6161 /// the instruction that is derived from this one in analysis
62 child: ?*Instruction,
62 child: ?*Inst,
6363
6464 /// the instruction that this one derives from in analysis
65 parent: ?*Instruction,
65 parent: ?*Inst,
6666
6767 /// populated durign codegen
6868 llvm_value: ?llvm.ValueRef,
6969
70 pub fn cast(base: *Instruction, comptime T: type) ?*T {
70 pub fn cast(base: *Inst, comptime T: type) ?*T {
7171 if (base.id == comptime typeToId(T)) {
7272 return @fieldParentPtr(T, "base", base);
7373 }
......@@ -77,18 +77,18 @@ pub const Instruction = struct {
7777 pub fn typeToId(comptime T: type) Id {
7878 comptime var i = 0;
7979 inline while (i < @memberCount(Id)) : (i += 1) {
80 if (T == @field(Instruction, @memberName(Id, i))) {
80 if (T == @field(Inst, @memberName(Id, i))) {
8181 return @field(Id, @memberName(Id, i));
8282 }
8383 }
8484 unreachable;
8585 }
8686
87 pub fn dump(base: *const Instruction) void {
87 pub fn dump(base: *const Inst) void {
8888 comptime var i = 0;
8989 inline while (i < @memberCount(Id)) : (i += 1) {
9090 if (base.id == @field(Id, @memberName(Id, i))) {
91 const T = @field(Instruction, @memberName(Id, i));
91 const T = @field(Inst, @memberName(Id, i));
9292 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));
9393 @fieldParentPtr(T, "base", base).dump();
9494 std.debug.warn(")");
......@@ -98,29 +98,29 @@ pub const Instruction = struct {
9898 unreachable;
9999 }
100100
101 pub fn hasSideEffects(base: *const Instruction) bool {
101 pub fn hasSideEffects(base: *const Inst) bool {
102102 comptime var i = 0;
103103 inline while (i < @memberCount(Id)) : (i += 1) {
104104 if (base.id == @field(Id, @memberName(Id, i))) {
105 const T = @field(Instruction, @memberName(Id, i));
105 const T = @field(Inst, @memberName(Id, i));
106106 return @fieldParentPtr(T, "base", base).hasSideEffects();
107107 }
108108 }
109109 unreachable;
110110 }
111111
112 pub fn analyze(base: *Instruction, ira: *Analyze) Analyze.Error!*Instruction {
112 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
113113 comptime var i = 0;
114114 inline while (i < @memberCount(Id)) : (i += 1) {
115115 if (base.id == @field(Id, @memberName(Id, i))) {
116 const T = @field(Instruction, @memberName(Id, i));
116 const T = @field(Inst, @memberName(Id, i));
117117 return @fieldParentPtr(T, "base", base).analyze(ira);
118118 }
119119 }
120120 unreachable;
121121 }
122122
123 pub fn render(base: *Instruction, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
123 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
124124 switch (base.id) {
125125 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
126126 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
......@@ -133,14 +133,14 @@ pub const Instruction = struct {
133133 }
134134 }
135135
136 fn ref(base: *Instruction, builder: *Builder) void {
136 fn ref(base: *Inst, builder: *Builder) void {
137137 base.ref_count += 1;
138138 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
139139 base.owner_bb.ref();
140140 }
141141 }
142142
143 fn getAsParam(param: *Instruction) !*Instruction {
143 fn getAsParam(param: *Inst) !*Inst {
144144 const child = param.child orelse return error.SemanticAnalysisFailed;
145145 switch (child.val) {
146146 IrVal.Unknown => return error.SemanticAnalysisFailed,
......@@ -149,7 +149,7 @@ pub const Instruction = struct {
149149 }
150150
151151 /// asserts that the type is known
152 fn getKnownType(self: *Instruction) *Type {
152 fn getKnownType(self: *Inst) *Type {
153153 switch (self.val) {
154154 IrVal.KnownType => |typeof| return typeof,
155155 IrVal.KnownValue => |value| return value.typeof,
......@@ -157,11 +157,11 @@ pub const Instruction = struct {
157157 }
158158 }
159159
160 pub fn setGenerated(base: *Instruction) void {
160 pub fn setGenerated(base: *Inst) void {
161161 base.is_generated = true;
162162 }
163163
164 pub fn isNoReturn(base: *const Instruction) bool {
164 pub fn isNoReturn(base: *const Inst) bool {
165165 switch (base.val) {
166166 IrVal.Unknown => return false,
167167 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,
......@@ -169,11 +169,11 @@ pub const Instruction = struct {
169169 }
170170 }
171171
172 pub fn isCompTime(base: *const Instruction) bool {
172 pub fn isCompTime(base: *const Inst) bool {
173173 return base.val == IrVal.KnownValue;
174174 }
175175
176 pub fn linkToParent(self: *Instruction, parent: *Instruction) void {
176 pub fn linkToParent(self: *Inst, parent: *Inst) void {
177177 assert(self.parent == null);
178178 assert(parent.child == null);
179179 self.parent = parent;
......@@ -192,7 +192,7 @@ pub const Instruction = struct {
192192 };
193193
194194 pub const Const = struct {
195 base: Instruction,
195 base: Inst,
196196 params: Params,
197197
198198 const Params = struct {};
......@@ -209,7 +209,7 @@ pub const Instruction = struct {
209209 return false;
210210 }
211211
212 pub fn analyze(self: *const Const, ira: *Analyze) !*Instruction {
212 pub fn analyze(self: *const Const, ira: *Analyze) !*Inst {
213213 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});
214214 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };
215215 return new_inst;
......@@ -221,11 +221,11 @@ pub const Instruction = struct {
221221 };
222222
223223 pub const Return = struct {
224 base: Instruction,
224 base: Inst,
225225 params: Params,
226226
227227 const Params = struct {
228 return_value: *Instruction,
228 return_value: *Inst,
229229 };
230230
231231 const ir_val_init = IrVal.Init.NoReturn;
......@@ -238,7 +238,7 @@ pub const Instruction = struct {
238238 return true;
239239 }
240240
241 pub fn analyze(self: *const Return, ira: *Analyze) !*Instruction {
241 pub fn analyze(self: *const Return, ira: *Analyze) !*Inst {
242242 const value = try self.params.return_value.getAsParam();
243243 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);
244244
......@@ -261,11 +261,11 @@ pub const Instruction = struct {
261261 };
262262
263263 pub const Ref = struct {
264 base: Instruction,
264 base: Inst,
265265 params: Params,
266266
267267 const Params = struct {
268 target: *Instruction,
268 target: *Inst,
269269 mut: Type.Pointer.Mut,
270270 volatility: Type.Pointer.Vol,
271271 };
......@@ -278,7 +278,7 @@ pub const Instruction = struct {
278278 return false;
279279 }
280280
281 pub fn analyze(self: *const Ref, ira: *Analyze) !*Instruction {
281 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
282282 const target = try self.params.target.getAsParam();
283283
284284 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
......@@ -314,7 +314,7 @@ pub const Instruction = struct {
314314 };
315315
316316 pub const DeclVar = struct {
317 base: Instruction,
317 base: Inst,
318318 params: Params,
319319
320320 const Params = struct {
......@@ -329,17 +329,17 @@ pub const Instruction = struct {
329329 return true;
330330 }
331331
332 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Instruction {
332 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Inst {
333333 return error.Unimplemented; // TODO
334334 }
335335 };
336336
337337 pub const CheckVoidStmt = struct {
338 base: Instruction,
338 base: Inst,
339339 params: Params,
340340
341341 const Params = struct {
342 target: *Instruction,
342 target: *Inst,
343343 };
344344
345345 const ir_val_init = IrVal.Init.Unknown;
......@@ -350,18 +350,18 @@ pub const Instruction = struct {
350350 return true;
351351 }
352352
353 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Instruction {
353 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
354354 return error.Unimplemented; // TODO
355355 }
356356 };
357357
358358 pub const Phi = struct {
359 base: Instruction,
359 base: Inst,
360360 params: Params,
361361
362362 const Params = struct {
363363 incoming_blocks: []*BasicBlock,
364 incoming_values: []*Instruction,
364 incoming_values: []*Inst,
365365 };
366366
367367 const ir_val_init = IrVal.Init.Unknown;
......@@ -372,18 +372,18 @@ pub const Instruction = struct {
372372 return false;
373373 }
374374
375 pub fn analyze(self: *const Phi, ira: *Analyze) !*Instruction {
375 pub fn analyze(self: *const Phi, ira: *Analyze) !*Inst {
376376 return error.Unimplemented; // TODO
377377 }
378378 };
379379
380380 pub const Br = struct {
381 base: Instruction,
381 base: Inst,
382382 params: Params,
383383
384384 const Params = struct {
385385 dest_block: *BasicBlock,
386 is_comptime: *Instruction,
386 is_comptime: *Inst,
387387 };
388388
389389 const ir_val_init = IrVal.Init.NoReturn;
......@@ -394,17 +394,41 @@ pub const Instruction = struct {
394394 return true;
395395 }
396396
397 pub fn analyze(self: *const Br, ira: *Analyze) !*Instruction {
397 pub fn analyze(self: *const Br, ira: *Analyze) !*Inst {
398 return error.Unimplemented; // TODO
399 }
400 };
401
402 pub const CondBr = struct {
403 base: Inst,
404 params: Params,
405
406 const Params = struct {
407 condition: *Inst,
408 then_block: *BasicBlock,
409 else_block: *BasicBlock,
410 is_comptime: *Inst,
411 };
412
413 const ir_val_init = IrVal.Init.NoReturn;
414
415 pub fn dump(inst: *const CondBr) void {}
416
417 pub fn hasSideEffects(inst: *const CondBr) bool {
418 return true;
419 }
420
421 pub fn analyze(self: *const CondBr, ira: *Analyze) !*Inst {
398422 return error.Unimplemented; // TODO
399423 }
400424 };
401425
402426 pub const AddImplicitReturnType = struct {
403 base: Instruction,
427 base: Inst,
404428 params: Params,
405429
406430 pub const Params = struct {
407 target: *Instruction,
431 target: *Inst,
408432 };
409433
410434 const ir_val_init = IrVal.Init.Unknown;
......@@ -417,12 +441,117 @@ pub const Instruction = struct {
417441 return true;
418442 }
419443
420 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {
444 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Inst {
421445 const target = try self.params.target.getAsParam();
422446 try ira.src_implicit_return_type_list.append(target);
423447 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
424448 }
425449 };
450
451 pub const TestErr = struct {
452 base: Inst,
453 params: Params,
454
455 pub const Params = struct {
456 target: *Inst,
457 };
458
459 const ir_val_init = IrVal.Init.Unknown;
460
461 pub fn dump(inst: *const TestErr) void {
462 std.debug.warn("#{}", inst.params.target.debug_id);
463 }
464
465 pub fn hasSideEffects(inst: *const TestErr) bool {
466 return false;
467 }
468
469 pub fn analyze(self: *const TestErr, ira: *Analyze) !*Inst {
470 const target = try self.params.target.getAsParam();
471 const target_type = target.getKnownType();
472 switch (target_type.id) {
473 Type.Id.ErrorUnion => {
474 return error.Unimplemented;
475 // if (instr_is_comptime(value)) {
476 // ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
477 // if (!err_union_val)
478 // return ira->codegen->builtin_types.entry_invalid;
479
480 // if (err_union_val->special != ConstValSpecialRuntime) {
481 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
482 // out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
483 // return ira->codegen->builtin_types.entry_bool;
484 // }
485 // }
486
487 // TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
488 // if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
489 // return ira->codegen->builtin_types.entry_invalid;
490 // }
491 // if (!type_is_global_error_set(err_set_type) &&
492 // err_set_type->data.error_set.err_count == 0)
493 // {
494 // assert(err_set_type->data.error_set.infer_fn == nullptr);
495 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
496 // out_val->data.x_bool = false;
497 // return ira->codegen->builtin_types.entry_bool;
498 // }
499
500 // ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
501 // return ira->codegen->builtin_types.entry_bool;
502 },
503 Type.Id.ErrorSet => {
504 return ira.irb.buildConstBool(self.base.scope, self.base.span, true);
505 },
506 else => {
507 return ira.irb.buildConstBool(self.base.scope, self.base.span, false);
508 },
509 }
510 }
511 };
512
513 pub const TestCompTime = struct {
514 base: Inst,
515 params: Params,
516
517 pub const Params = struct {
518 target: *Inst,
519 };
520
521 const ir_val_init = IrVal.Init.Unknown;
522
523 pub fn dump(inst: *const TestCompTime) void {
524 std.debug.warn("#{}", inst.params.target.debug_id);
525 }
526
527 pub fn hasSideEffects(inst: *const TestCompTime) bool {
528 return false;
529 }
530
531 pub fn analyze(self: *const TestCompTime, ira: *Analyze) !*Inst {
532 const target = try self.params.target.getAsParam();
533 return ira.irb.buildConstBool(self.base.scope, self.base.span, target.isCompTime());
534 }
535 };
536
537 pub const SaveErrRetAddr = struct {
538 base: Inst,
539 params: Params,
540
541 const Params = struct {};
542
543 const ir_val_init = IrVal.Init.Unknown;
544
545 pub fn dump(inst: *const SaveErrRetAddr) void {}
546
547 pub fn hasSideEffects(inst: *const SaveErrRetAddr) bool {
548 return true;
549 }
550
551 pub fn analyze(self: *const SaveErrRetAddr, ira: *Analyze) !*Inst {
552 return ira.irb.build(Inst.SaveErrRetAddr, self.base.scope, self.base.span, Params{});
553 }
554 };
426555};
427556
428557pub const Variable = struct {
......@@ -434,8 +563,8 @@ pub const BasicBlock = struct {
434563 name_hint: [*]const u8, // must be a C string literal
435564 debug_id: usize,
436565 scope: *Scope,
437 instruction_list: std.ArrayList(*Instruction),
438 ref_instruction: ?*Instruction,
566 instruction_list: std.ArrayList(*Inst),
567 ref_instruction: ?*Inst,
439568
440569 /// for codegen
441570 llvm_block: llvm.BasicBlockRef,
......@@ -491,10 +620,12 @@ pub const Builder = struct {
491620 next_debug_id: usize,
492621 parsed_file: *ParsedFile,
493622 is_comptime: bool,
623 is_async: bool,
624 begin_scope: ?*Scope,
494625
495626 pub const Error = Analyze.Error;
496627
497 pub fn init(comp: *Compilation, parsed_file: *ParsedFile) !Builder {
628 pub fn init(comp: *Compilation, parsed_file: *ParsedFile, begin_scope: ?*Scope) !Builder {
498629 const code = try comp.gpa().create(Code{
499630 .basic_block_list = undefined,
500631 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
......@@ -510,6 +641,8 @@ pub const Builder = struct {
510641 .code = code,
511642 .next_debug_id = 0,
512643 .is_comptime = false,
644 .is_async = false,
645 .begin_scope = begin_scope,
513646 };
514647 }
515648
......@@ -529,7 +662,7 @@ pub const Builder = struct {
529662 .name_hint = name_hint,
530663 .debug_id = self.next_debug_id,
531664 .scope = scope,
532 .instruction_list = std.ArrayList(*Instruction).init(self.arena()),
665 .instruction_list = std.ArrayList(*Inst).init(self.arena()),
533666 .child = null,
534667 .parent = null,
535668 .ref_instruction = null,
......@@ -549,66 +682,69 @@ pub const Builder = struct {
549682 self.current_basic_block = basic_block;
550683 }
551684
552 pub fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Instruction {
685 pub fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
553686 switch (node.id) {
554687 ast.Node.Id.Root => unreachable,
555688 ast.Node.Id.Use => unreachable,
556689 ast.Node.Id.TestDecl => unreachable,
557 ast.Node.Id.VarDecl => @panic("TODO"),
558 ast.Node.Id.Defer => @panic("TODO"),
559 ast.Node.Id.InfixOp => @panic("TODO"),
560 ast.Node.Id.PrefixOp => @panic("TODO"),
561 ast.Node.Id.SuffixOp => @panic("TODO"),
562 ast.Node.Id.Switch => @panic("TODO"),
563 ast.Node.Id.While => @panic("TODO"),
564 ast.Node.Id.For => @panic("TODO"),
565 ast.Node.Id.If => @panic("TODO"),
566 ast.Node.Id.ControlFlowExpression => return error.Unimplemented,
567 ast.Node.Id.Suspend => @panic("TODO"),
568 ast.Node.Id.VarType => @panic("TODO"),
569 ast.Node.Id.ErrorType => @panic("TODO"),
570 ast.Node.Id.FnProto => @panic("TODO"),
571 ast.Node.Id.PromiseType => @panic("TODO"),
572 ast.Node.Id.IntegerLiteral => @panic("TODO"),
573 ast.Node.Id.FloatLiteral => @panic("TODO"),
574 ast.Node.Id.StringLiteral => @panic("TODO"),
575 ast.Node.Id.MultilineStringLiteral => @panic("TODO"),
576 ast.Node.Id.CharLiteral => @panic("TODO"),
577 ast.Node.Id.BoolLiteral => @panic("TODO"),
578 ast.Node.Id.NullLiteral => @panic("TODO"),
579 ast.Node.Id.UndefinedLiteral => @panic("TODO"),
580 ast.Node.Id.ThisLiteral => @panic("TODO"),
581 ast.Node.Id.Unreachable => @panic("TODO"),
582 ast.Node.Id.Identifier => @panic("TODO"),
690 ast.Node.Id.VarDecl => return error.Unimplemented,
691 ast.Node.Id.Defer => return error.Unimplemented,
692 ast.Node.Id.InfixOp => return error.Unimplemented,
693 ast.Node.Id.PrefixOp => return error.Unimplemented,
694 ast.Node.Id.SuffixOp => return error.Unimplemented,
695 ast.Node.Id.Switch => return error.Unimplemented,
696 ast.Node.Id.While => return error.Unimplemented,
697 ast.Node.Id.For => return error.Unimplemented,
698 ast.Node.Id.If => return error.Unimplemented,
699 ast.Node.Id.ControlFlowExpression => {
700 const control_flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", node);
701 return irb.genControlFlowExpr(control_flow_expr, scope, lval);
702 },
703 ast.Node.Id.Suspend => return error.Unimplemented,
704 ast.Node.Id.VarType => return error.Unimplemented,
705 ast.Node.Id.ErrorType => return error.Unimplemented,
706 ast.Node.Id.FnProto => return error.Unimplemented,
707 ast.Node.Id.PromiseType => return error.Unimplemented,
708 ast.Node.Id.IntegerLiteral => return error.Unimplemented,
709 ast.Node.Id.FloatLiteral => return error.Unimplemented,
710 ast.Node.Id.StringLiteral => return error.Unimplemented,
711 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
712 ast.Node.Id.CharLiteral => return error.Unimplemented,
713 ast.Node.Id.BoolLiteral => return error.Unimplemented,
714 ast.Node.Id.NullLiteral => return error.Unimplemented,
715 ast.Node.Id.UndefinedLiteral => return error.Unimplemented,
716 ast.Node.Id.ThisLiteral => return error.Unimplemented,
717 ast.Node.Id.Unreachable => return error.Unimplemented,
718 ast.Node.Id.Identifier => return error.Unimplemented,
583719 ast.Node.Id.GroupedExpression => {
584720 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
585721 return irb.genNode(grouped_expr.expr, scope, lval);
586722 },
587 ast.Node.Id.BuiltinCall => @panic("TODO"),
588 ast.Node.Id.ErrorSetDecl => @panic("TODO"),
589 ast.Node.Id.ContainerDecl => @panic("TODO"),
590 ast.Node.Id.Asm => @panic("TODO"),
591 ast.Node.Id.Comptime => @panic("TODO"),
723 ast.Node.Id.BuiltinCall => return error.Unimplemented,
724 ast.Node.Id.ErrorSetDecl => return error.Unimplemented,
725 ast.Node.Id.ContainerDecl => return error.Unimplemented,
726 ast.Node.Id.Asm => return error.Unimplemented,
727 ast.Node.Id.Comptime => return error.Unimplemented,
592728 ast.Node.Id.Block => {
593729 const block = @fieldParentPtr(ast.Node.Block, "base", node);
594730 return irb.lvalWrap(scope, try irb.genBlock(block, scope), lval);
595731 },
596 ast.Node.Id.DocComment => @panic("TODO"),
597 ast.Node.Id.SwitchCase => @panic("TODO"),
598 ast.Node.Id.SwitchElse => @panic("TODO"),
599 ast.Node.Id.Else => @panic("TODO"),
600 ast.Node.Id.Payload => @panic("TODO"),
601 ast.Node.Id.PointerPayload => @panic("TODO"),
602 ast.Node.Id.PointerIndexPayload => @panic("TODO"),
603 ast.Node.Id.StructField => @panic("TODO"),
604 ast.Node.Id.UnionTag => @panic("TODO"),
605 ast.Node.Id.EnumTag => @panic("TODO"),
606 ast.Node.Id.ErrorTag => @panic("TODO"),
607 ast.Node.Id.AsmInput => @panic("TODO"),
608 ast.Node.Id.AsmOutput => @panic("TODO"),
609 ast.Node.Id.AsyncAttribute => @panic("TODO"),
610 ast.Node.Id.ParamDecl => @panic("TODO"),
611 ast.Node.Id.FieldInitializer => @panic("TODO"),
732 ast.Node.Id.DocComment => return error.Unimplemented,
733 ast.Node.Id.SwitchCase => return error.Unimplemented,
734 ast.Node.Id.SwitchElse => return error.Unimplemented,
735 ast.Node.Id.Else => return error.Unimplemented,
736 ast.Node.Id.Payload => return error.Unimplemented,
737 ast.Node.Id.PointerPayload => return error.Unimplemented,
738 ast.Node.Id.PointerIndexPayload => return error.Unimplemented,
739 ast.Node.Id.StructField => return error.Unimplemented,
740 ast.Node.Id.UnionTag => return error.Unimplemented,
741 ast.Node.Id.EnumTag => return error.Unimplemented,
742 ast.Node.Id.ErrorTag => return error.Unimplemented,
743 ast.Node.Id.AsmInput => return error.Unimplemented,
744 ast.Node.Id.AsmOutput => return error.Unimplemented,
745 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
746 ast.Node.Id.ParamDecl => return error.Unimplemented,
747 ast.Node.Id.FieldInitializer => return error.Unimplemented,
612748 }
613749 }
614750
......@@ -630,7 +766,7 @@ pub const Builder = struct {
630766 }
631767 }
632768
633 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Instruction {
769 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
634770 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
635771
636772 const outer_block_scope = &block_scope.base;
......@@ -648,7 +784,7 @@ pub const Builder = struct {
648784 }
649785
650786 if (block.label) |label| {
651 block_scope.incoming_values = std.ArrayList(*Instruction).init(irb.arena());
787 block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena());
652788 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
653789 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
654790 block_scope.is_comptime = try irb.buildConstBool(
......@@ -659,7 +795,7 @@ pub const Builder = struct {
659795 }
660796
661797 var is_continuation_unreachable = false;
662 var noreturn_return_value: ?*Instruction = null;
798 var noreturn_return_value: ?*Inst = null;
663799
664800 var stmt_it = block.statements.iterator(0);
665801 while (stmt_it.next()) |statement_node_ptr| {
......@@ -686,16 +822,16 @@ pub const Builder = struct {
686822 noreturn_return_value = statement_value;
687823 }
688824
689 if (statement_value.cast(Instruction.DeclVar)) |decl_var| {
825 if (statement_value.cast(Inst.DeclVar)) |decl_var| {
690826 // variable declarations start a new scope
691827 child_scope = decl_var.params.variable.child_scope;
692828 } else if (!is_continuation_unreachable) {
693829 // this statement's value must be void
694830 _ = irb.build(
695 Instruction.CheckVoidStmt,
831 Inst.CheckVoidStmt,
696832 child_scope,
697833 statement_value.span,
698 Instruction.CheckVoidStmt.Params{ .target = statement_value },
834 Inst.CheckVoidStmt.Params{ .target = statement_value },
699835 );
700836 }
701837 }
......@@ -707,7 +843,7 @@ pub const Builder = struct {
707843 }
708844
709845 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
710 return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{
846 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
711847 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
712848 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
713849 });
......@@ -720,14 +856,14 @@ pub const Builder = struct {
720856 );
721857 _ = try irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit);
722858
723 _ = try irb.buildGen(Instruction.Br, parent_scope, Span.token(block.rbrace), Instruction.Br.Params{
859 _ = try irb.buildGen(Inst.Br, parent_scope, Span.token(block.rbrace), Inst.Br.Params{
724860 .dest_block = block_scope.end_block,
725861 .is_comptime = block_scope.is_comptime,
726862 });
727863
728864 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
729865
730 return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{
866 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
731867 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
732868 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
733869 });
......@@ -737,6 +873,135 @@ pub const Builder = struct {
737873 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
738874 }
739875
876 pub fn genControlFlowExpr(
877 irb: *Builder,
878 control_flow_expr: *ast.Node.ControlFlowExpression,
879 scope: *Scope,
880 lval: LVal,
881 ) !*Inst {
882 switch (control_flow_expr.kind) {
883 ast.Node.ControlFlowExpression.Kind.Break => |arg| return error.Unimplemented,
884 ast.Node.ControlFlowExpression.Kind.Continue => |arg| return error.Unimplemented,
885 ast.Node.ControlFlowExpression.Kind.Return => {
886 const src_span = Span.token(control_flow_expr.ltoken);
887 if (scope.findFnDef() == null) {
888 try irb.comp.addCompileError(
889 irb.parsed_file,
890 src_span,
891 "return expression outside function definition",
892 );
893 return error.SemanticAnalysisFailed;
894 }
895
896 if (scope.findDeferExpr()) |scope_defer_expr| {
897 if (!scope_defer_expr.reported_err) {
898 try irb.comp.addCompileError(
899 irb.parsed_file,
900 src_span,
901 "cannot return from defer expression",
902 );
903 scope_defer_expr.reported_err = true;
904 }
905 return error.SemanticAnalysisFailed;
906 }
907
908 const outer_scope = irb.begin_scope.?;
909 const return_value = if (control_flow_expr.rhs) |rhs| blk: {
910 break :blk try irb.genNode(rhs, scope, LVal.None);
911 } else blk: {
912 break :blk try irb.buildConstVoid(scope, src_span, true);
913 };
914
915 const defer_counts = irb.countDefers(scope, outer_scope);
916 const have_err_defers = defer_counts.error_exit != 0;
917 if (have_err_defers or irb.comp.have_err_ret_tracing) {
918 const err_block = try irb.createBasicBlock(scope, c"ErrRetErr");
919 const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk");
920 if (!have_err_defers) {
921 _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit);
922 }
923
924 const is_err = try irb.build(
925 Inst.TestErr,
926 scope,
927 src_span,
928 Inst.TestErr.Params{ .target = return_value },
929 );
930
931 const err_is_comptime = try irb.buildTestCompTime(scope, src_span, is_err);
932
933 _ = try irb.buildGen(Inst.CondBr, scope, src_span, Inst.CondBr.Params{
934 .condition = is_err,
935 .then_block = err_block,
936 .else_block = ok_block,
937 .is_comptime = err_is_comptime,
938 });
939
940 const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt");
941
942 try irb.setCursorAtEndAndAppendBlock(err_block);
943 if (have_err_defers) {
944 _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ErrorExit);
945 }
946 if (irb.comp.have_err_ret_tracing and !irb.isCompTime(scope)) {
947 _ = try irb.build(Inst.SaveErrRetAddr, scope, src_span, Inst.SaveErrRetAddr.Params{});
948 }
949 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
950 .dest_block = ret_stmt_block,
951 .is_comptime = err_is_comptime,
952 });
953
954 try irb.setCursorAtEndAndAppendBlock(ok_block);
955 if (have_err_defers) {
956 _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit);
957 }
958 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
959 .dest_block = ret_stmt_block,
960 .is_comptime = err_is_comptime,
961 });
962
963 try irb.setCursorAtEndAndAppendBlock(ret_stmt_block);
964 return irb.genAsyncReturn(scope, src_span, return_value, false);
965 } else {
966 _ = try irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit);
967 return irb.genAsyncReturn(scope, src_span, return_value, false);
968 }
969 },
970 }
971 }
972
973 const DeferCounts = struct {
974 scope_exit: usize,
975 error_exit: usize,
976 };
977
978 fn countDefers(irb: *Builder, inner_scope: *Scope, outer_scope: *Scope) DeferCounts {
979 var result = DeferCounts{ .scope_exit = 0, .error_exit = 0 };
980
981 var scope = inner_scope;
982 while (scope != outer_scope) {
983 switch (scope.id) {
984 Scope.Id.Defer => {
985 const defer_scope = @fieldParentPtr(Scope.Defer, "base", scope);
986 switch (defer_scope.kind) {
987 Scope.Defer.Kind.ScopeExit => result.scope_exit += 1,
988 Scope.Defer.Kind.ErrorExit => result.error_exit += 1,
989 }
990 scope = scope.parent orelse break;
991 },
992 Scope.Id.FnDef => break,
993
994 Scope.Id.CompTime,
995 Scope.Id.Block,
996 => scope = scope.parent orelse break,
997
998 Scope.Id.DeferExpr => unreachable,
999 Scope.Id.Decls => unreachable,
1000 }
1001 }
1002 return result;
1003 }
1004
7401005 fn genDefersForBlock(
7411006 irb: *Builder,
7421007 inner_scope: *Scope,
......@@ -764,10 +1029,10 @@ pub const Builder = struct {
7641029 is_noreturn = true;
7651030 } else {
7661031 _ = try irb.build(
767 Instruction.CheckVoidStmt,
1032 Inst.CheckVoidStmt,
7681033 &defer_expr_scope.base,
7691034 Span.token(defer_expr_scope.expr_node.lastToken()),
770 Instruction.CheckVoidStmt.Params{ .target = instruction },
1035 Inst.CheckVoidStmt.Params{ .target = instruction },
7711036 );
7721037 }
7731038 }
......@@ -785,13 +1050,13 @@ pub const Builder = struct {
7851050 }
7861051 }
7871052
788 pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Instruction, lval: LVal) !*Instruction {
1053 pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Inst, lval: LVal) !*Inst {
7891054 switch (lval) {
7901055 LVal.None => return instruction,
7911056 LVal.Ptr => {
7921057 // We needed a pointer to a value, but we got a value. So we create
7931058 // an instruction which just makes a const pointer of it.
794 return irb.build(Instruction.Ref, scope, instruction.span, Instruction.Ref.Params{
1059 return irb.build(Inst.Ref, scope, instruction.span, Inst.Ref.Params{
7951060 .target = instruction,
7961061 .mut = Type.Pointer.Mut.Const,
7971062 .volatility = Type.Pointer.Vol.Non,
......@@ -811,10 +1076,10 @@ pub const Builder = struct {
8111076 span: Span,
8121077 params: I.Params,
8131078 is_generated: bool,
814 ) !*Instruction {
1079 ) !*Inst {
8151080 const inst = try self.arena().create(I{
816 .base = Instruction{
817 .id = Instruction.typeToId(I),
1081 .base = Inst{
1082 .id = Inst.typeToId(I),
8181083 .is_generated = is_generated,
8191084 .scope = scope,
8201085 .debug_id = self.next_debug_id,
......@@ -838,8 +1103,8 @@ pub const Builder = struct {
8381103 inline while (i < @memberCount(I.Params)) : (i += 1) {
8391104 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
8401105 switch (FieldType) {
841 *Instruction => @field(inst.params, @memberName(I.Params, i)).ref(self),
842 ?*Instruction => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
1106 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
1107 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
8431108 else => {},
8441109 }
8451110 }
......@@ -855,7 +1120,7 @@ pub const Builder = struct {
8551120 scope: *Scope,
8561121 span: Span,
8571122 params: I.Params,
858 ) !*Instruction {
1123 ) !*Inst {
8591124 return self.buildExtra(I, scope, span, params, false);
8601125 }
8611126
......@@ -865,21 +1130,71 @@ pub const Builder = struct {
8651130 scope: *Scope,
8661131 span: Span,
8671132 params: I.Params,
868 ) !*Instruction {
1133 ) !*Inst {
8691134 return self.buildExtra(I, scope, span, params, true);
8701135 }
8711136
872 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Instruction {
873 const inst = try self.build(Instruction.Const, scope, span, Instruction.Const.Params{});
1137 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Inst {
1138 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
8741139 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };
8751140 return inst;
8761141 }
8771142
878 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Instruction {
879 const inst = try self.buildExtra(Instruction.Const, scope, span, Instruction.Const.Params{}, is_generated);
1143 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Inst {
1144 const inst = try self.buildExtra(Inst.Const, scope, span, Inst.Const.Params{}, is_generated);
8801145 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };
8811146 return inst;
8821147 }
1148
1149 /// If the code is explicitly set to be comptime, then builds a const bool,
1150 /// otherwise builds a TestCompTime instruction.
1151 fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst {
1152 if (self.isCompTime(scope)) {
1153 return self.buildConstBool(scope, span, true);
1154 } else {
1155 return self.build(
1156 Inst.TestCompTime,
1157 scope,
1158 span,
1159 Inst.TestCompTime.Params{ .target = target },
1160 );
1161 }
1162 }
1163
1164 fn genAsyncReturn(irb: *Builder, scope: *Scope, span: Span, result: *Inst, is_gen: bool) !*Inst {
1165 _ = irb.buildGen(
1166 Inst.AddImplicitReturnType,
1167 scope,
1168 span,
1169 Inst.AddImplicitReturnType.Params{ .target = result },
1170 );
1171
1172 if (!irb.is_async) {
1173 return irb.buildExtra(
1174 Inst.Return,
1175 scope,
1176 span,
1177 Inst.Return.Params{ .return_value = result },
1178 is_gen,
1179 );
1180 }
1181 return error.Unimplemented;
1182
1183 //ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
1184 //IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
1185 // get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
1186 //// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
1187 //IrInstruction *replacement_value = irb->exec->coro_handle;
1188 //IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
1189 // promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
1190 // AtomicRmwOp_xchg, AtomicOrderSeqCst);
1191 //ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
1192 //IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
1193 //IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
1194 //return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
1195 // is_comptime);
1196 //// the above blocks are rendered by ir_gen after the rest of codegen
1197 }
8831198};
8841199
8851200const Analyze = struct {
......@@ -888,7 +1203,7 @@ const Analyze = struct {
8881203 const_predecessor_bb: ?*BasicBlock,
8891204 parent_basic_block: *BasicBlock,
8901205 instruction_index: usize,
891 src_implicit_return_type_list: std.ArrayList(*Instruction),
1206 src_implicit_return_type_list: std.ArrayList(*Inst),
8921207 explicit_return_type: ?*Type,
8931208
8941209 pub const Error = error{
......@@ -903,7 +1218,7 @@ const Analyze = struct {
9031218 };
9041219
9051220 pub fn init(comp: *Compilation, parsed_file: *ParsedFile, explicit_return_type: ?*Type) !Analyze {
906 var irb = try Builder.init(comp, parsed_file);
1221 var irb = try Builder.init(comp, parsed_file, null);
9071222 errdefer irb.abort();
9081223
9091224 return Analyze{
......@@ -912,7 +1227,7 @@ const Analyze = struct {
9121227 .const_predecessor_bb = null,
9131228 .parent_basic_block = undefined, // initialized with startBasicBlock
9141229 .instruction_index = undefined, // initialized with startBasicBlock
915 .src_implicit_return_type_list = std.ArrayList(*Instruction).init(irb.arena()),
1230 .src_implicit_return_type_list = std.ArrayList(*Inst).init(irb.arena()),
9161231 .explicit_return_type = explicit_return_type,
9171232 };
9181233 }
......@@ -921,7 +1236,7 @@ const Analyze = struct {
9211236 self.irb.abort();
9221237 }
9231238
924 pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Instruction) !*BasicBlock {
1239 pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Inst) !*BasicBlock {
9251240 if (old_bb.child) |child| {
9261241 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)
9271242 return child;
......@@ -984,18 +1299,18 @@ const Analyze = struct {
9841299 return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args);
9851300 }
9861301
987 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Instruction) Analyze.Error!*Type {
1302 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type {
9881303 // TODO actual implementation
9891304 return &Type.Void.get(self.irb.comp).base;
9901305 }
9911306
992 fn implicitCast(self: *Analyze, target: *Instruction, optional_dest_type: ?*Type) Analyze.Error!*Instruction {
1307 fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst {
9931308 const dest_type = optional_dest_type orelse return target;
994 @panic("TODO implicitCast");
1309 return error.Unimplemented;
9951310 }
9961311
997 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Instruction) ?*Value {
998 @panic("TODO getCompTimeValOrNullUndefOk");
1312 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {
1313 @panic("TODO");
9991314 }
10001315
10011316 fn getCompTimeRef(
......@@ -1005,8 +1320,8 @@ const Analyze = struct {
10051320 mut: Type.Pointer.Mut,
10061321 volatility: Type.Pointer.Vol,
10071322 ptr_align: u32,
1008 ) Analyze.Error!*Instruction {
1009 @panic("TODO getCompTimeRef");
1323 ) Analyze.Error!*Inst {
1324 return error.Unimplemented;
10101325 }
10111326};
10121327
......@@ -1014,10 +1329,9 @@ pub async fn gen(
10141329 comp: *Compilation,
10151330 body_node: *ast.Node,
10161331 scope: *Scope,
1017 end_span: Span,
10181332 parsed_file: *ParsedFile,
10191333) !*Code {
1020 var irb = try Builder.init(comp, parsed_file);
1334 var irb = try Builder.init(comp, parsed_file, scope);
10211335 errdefer irb.abort();
10221336
10231337 const entry_block = try irb.createBasicBlock(scope, c"Entry");
......@@ -1026,18 +1340,8 @@ pub async fn gen(
10261340
10271341 const result = try irb.genNode(body_node, scope, LVal.None);
10281342 if (!result.isNoReturn()) {
1029 _ = irb.buildGen(
1030 Instruction.AddImplicitReturnType,
1031 scope,
1032 end_span,
1033 Instruction.AddImplicitReturnType.Params{ .target = result },
1034 );
1035 _ = irb.buildGen(
1036 Instruction.Return,
1037 scope,
1038 end_span,
1039 Instruction.Return.Params{ .return_value = result },
1040 );
1343 // no need for save_err_ret_addr because this cannot return error
1344 _ = try irb.genAsyncReturn(scope, Span.token(body_node.lastToken()), result, true);
10411345 }
10421346
10431347 return irb.finish();
src-self-hosted/scope.zig+22-2
......@@ -49,6 +49,24 @@ pub const Scope = struct {
4949 }
5050 }
5151
52 pub fn findDeferExpr(base: *Scope) ?*DeferExpr {
53 var scope = base;
54 while (true) {
55 switch (scope.id) {
56 Id.DeferExpr => return @fieldParentPtr(DeferExpr, "base", base),
57
58 Id.FnDef,
59 Id.Decls,
60 => return null,
61
62 Id.Block,
63 Id.Defer,
64 Id.CompTime,
65 => scope = scope.parent orelse return null,
66 }
67 }
68 }
69
5270 pub const Id = enum {
5371 Decls,
5472 Block,
......@@ -90,10 +108,10 @@ pub const Scope = struct {
90108
91109 pub const Block = struct {
92110 base: Scope,
93 incoming_values: std.ArrayList(*ir.Instruction),
111 incoming_values: std.ArrayList(*ir.Inst),
94112 incoming_blocks: std.ArrayList(*ir.BasicBlock),
95113 end_block: *ir.BasicBlock,
96 is_comptime: *ir.Instruction,
114 is_comptime: *ir.Inst,
97115
98116 safety: Safety,
99117
......@@ -242,6 +260,7 @@ pub const Scope = struct {
242260 pub const DeferExpr = struct {
243261 base: Scope,
244262 expr_node: *ast.Node,
263 reported_err: bool,
245264
246265 /// Creates a DeferExpr scope with 1 reference
247266 pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr {
......@@ -252,6 +271,7 @@ pub const Scope = struct {
252271 .ref_count = 1,
253272 },
254273 .expr_node = expr_node,
274 .reported_err = false,
255275 });
256276 errdefer comp.gpa().destroy(self);
257277
test/stage2/compile_errors.zig+12
......@@ -9,4 +9,16 @@ pub fn addCases(ctx: *TestContext) !void {
99 try ctx.testCompileError(
1010 \\fn() void {}
1111 , "1.zig", 1, 1, "missing function name");
12
13 try ctx.testCompileError(
14 \\comptime {
15 \\ return;
16 \\}
17 , "1.zig", 2, 5, "return expression outside function definition");
18
19 try ctx.testCompileError(
20 \\export fn entry() void {
21 \\ defer return;
22 \\}
23 , "1.zig", 2, 11, "cannot return from defer expression");
1224}