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 {...@@ -207,6 +207,8 @@ pub const Compilation = struct {
207207
208 destroy_handle: promise,208 destroy_handle: promise,
209209
210 have_err_ret_tracing: bool,
211
210 const CompileErrList = std.ArrayList(*errmsg.Msg);212 const CompileErrList = std.ArrayList(*errmsg.Msg);
211213
212 // TODO handle some of these earlier and report them in a way other than error codes214 // TODO handle some of these earlier and report them in a way other than error codes
...@@ -379,6 +381,7 @@ pub const Compilation = struct {...@@ -379,6 +381,7 @@ pub const Compilation = struct {
379381
380 .override_libc = null,382 .override_libc = null,
381 .destroy_handle = undefined,383 .destroy_handle = undefined,
384 .have_err_ret_tracing = false,
382 });385 });
383 errdefer {386 errdefer {
384 comp.arena_allocator.deinit();387 comp.arena_allocator.deinit();
...@@ -660,7 +663,11 @@ pub const Compilation = struct {...@@ -660,7 +663,11 @@ pub const Compilation = struct {
660 while (it.next()) |decl_ptr| {663 while (it.next()) |decl_ptr| {
661 const decl = decl_ptr.*;664 const decl = decl_ptr.*;
662 switch (decl.id) {665 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 },
664 ast.Node.Id.VarDecl => @panic("TODO"),671 ast.Node.Id.VarDecl => @panic("TODO"),
665 ast.Node.Id.FnProto => {672 ast.Node.Id.FnProto => {
666 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);673 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
...@@ -709,6 +716,69 @@ pub const Compilation = struct {...@@ -709,6 +716,69 @@ pub const Compilation = struct {
709 }716 }
710 }717 }
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
712 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {782 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {
713 const is_export = decl.isExported(&decl.parsed_file.tree);783 const is_export = decl.isExported(&decl.parsed_file.tree);
714784
...@@ -931,38 +1001,12 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -931,38 +1001,12 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
931 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);1001 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
932 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };1002 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
9331003
934 const unanalyzed_code = (await (async ir.gen(1004 const analyzed_code = (try await (async comp.genAndAnalyzeCode(
935 comp,
936 body_node,
937 &fndef_scope.base,
938 Span.token(body_node.lastToken()),
939 fn_decl.base.parsed_file,1005 fn_decl.base.parsed_file,
940 ) catch unreachable)) catch |err| switch (err) {1006 &fndef_scope.base,
941 // This poison value should not cause the errdefers to run. It simply means1007 body_node,
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,
958 null,1008 null,
959 ) catch unreachable)) catch |err| switch (err) {1009 ) catch unreachable)) orelse return;
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 };
966 errdefer analyzed_code.destroy(comp.gpa());1010 errdefer analyzed_code.destroy(comp.gpa());
9671011
968 if (comp.verbose_ir) {1012 if (comp.verbose_ir) {
src-self-hosted/ir.zig+446-142
...@@ -46,7 +46,7 @@ pub const IrVal = union(enum) {...@@ -46,7 +46,7 @@ pub const IrVal = union(enum) {
46 }46 }
47};47};
4848
49pub const Instruction = struct {49pub const Inst = struct {
50 id: Id,50 id: Id,
51 scope: *Scope,51 scope: *Scope,
52 debug_id: usize,52 debug_id: usize,
...@@ -59,15 +59,15 @@ pub const Instruction = struct {...@@ -59,15 +59,15 @@ pub const Instruction = struct {
59 is_generated: bool,59 is_generated: bool,
6060
61 /// the instruction that is derived from this one in analysis61 /// the instruction that is derived from this one in analysis
62 child: ?*Instruction,62 child: ?*Inst,
6363
64 /// the instruction that this one derives from in analysis64 /// the instruction that this one derives from in analysis
65 parent: ?*Instruction,65 parent: ?*Inst,
6666
67 /// populated durign codegen67 /// populated durign codegen
68 llvm_value: ?llvm.ValueRef,68 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 {
71 if (base.id == comptime typeToId(T)) {71 if (base.id == comptime typeToId(T)) {
72 return @fieldParentPtr(T, "base", base);72 return @fieldParentPtr(T, "base", base);
73 }73 }
...@@ -77,18 +77,18 @@ pub const Instruction = struct {...@@ -77,18 +77,18 @@ pub const Instruction = struct {
77 pub fn typeToId(comptime T: type) Id {77 pub fn typeToId(comptime T: type) Id {
78 comptime var i = 0;78 comptime var i = 0;
79 inline while (i < @memberCount(Id)) : (i += 1) {79 inline while (i < @memberCount(Id)) : (i += 1) {
80 if (T == @field(Instruction, @memberName(Id, i))) {80 if (T == @field(Inst, @memberName(Id, i))) {
81 return @field(Id, @memberName(Id, i));81 return @field(Id, @memberName(Id, i));
82 }82 }
83 }83 }
84 unreachable;84 unreachable;
85 }85 }
8686
87 pub fn dump(base: *const Instruction) void {87 pub fn dump(base: *const Inst) void {
88 comptime var i = 0;88 comptime var i = 0;
89 inline while (i < @memberCount(Id)) : (i += 1) {89 inline while (i < @memberCount(Id)) : (i += 1) {
90 if (base.id == @field(Id, @memberName(Id, i))) {90 if (base.id == @field(Id, @memberName(Id, i))) {
91 const T = @field(Instruction, @memberName(Id, i));91 const T = @field(Inst, @memberName(Id, i));
92 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));92 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));
93 @fieldParentPtr(T, "base", base).dump();93 @fieldParentPtr(T, "base", base).dump();
94 std.debug.warn(")");94 std.debug.warn(")");
...@@ -98,29 +98,29 @@ pub const Instruction = struct {...@@ -98,29 +98,29 @@ pub const Instruction = struct {
98 unreachable;98 unreachable;
99 }99 }
100100
101 pub fn hasSideEffects(base: *const Instruction) bool {101 pub fn hasSideEffects(base: *const Inst) bool {
102 comptime var i = 0;102 comptime var i = 0;
103 inline while (i < @memberCount(Id)) : (i += 1) {103 inline while (i < @memberCount(Id)) : (i += 1) {
104 if (base.id == @field(Id, @memberName(Id, i))) {104 if (base.id == @field(Id, @memberName(Id, i))) {
105 const T = @field(Instruction, @memberName(Id, i));105 const T = @field(Inst, @memberName(Id, i));
106 return @fieldParentPtr(T, "base", base).hasSideEffects();106 return @fieldParentPtr(T, "base", base).hasSideEffects();
107 }107 }
108 }108 }
109 unreachable;109 unreachable;
110 }110 }
111111
112 pub fn analyze(base: *Instruction, ira: *Analyze) Analyze.Error!*Instruction {112 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
113 comptime var i = 0;113 comptime var i = 0;
114 inline while (i < @memberCount(Id)) : (i += 1) {114 inline while (i < @memberCount(Id)) : (i += 1) {
115 if (base.id == @field(Id, @memberName(Id, i))) {115 if (base.id == @field(Id, @memberName(Id, i))) {
116 const T = @field(Instruction, @memberName(Id, i));116 const T = @field(Inst, @memberName(Id, i));
117 return @fieldParentPtr(T, "base", base).analyze(ira);117 return @fieldParentPtr(T, "base", base).analyze(ira);
118 }118 }
119 }119 }
120 unreachable;120 unreachable;
121 }121 }
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) {
124 switch (base.id) {124 switch (base.id) {
125 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),125 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
126 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),126 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
...@@ -133,14 +133,14 @@ pub const Instruction = struct {...@@ -133,14 +133,14 @@ pub const Instruction = struct {
133 }133 }
134 }134 }
135135
136 fn ref(base: *Instruction, builder: *Builder) void {136 fn ref(base: *Inst, builder: *Builder) void {
137 base.ref_count += 1;137 base.ref_count += 1;
138 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {138 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
139 base.owner_bb.ref();139 base.owner_bb.ref();
140 }140 }
141 }141 }
142142
143 fn getAsParam(param: *Instruction) !*Instruction {143 fn getAsParam(param: *Inst) !*Inst {
144 const child = param.child orelse return error.SemanticAnalysisFailed;144 const child = param.child orelse return error.SemanticAnalysisFailed;
145 switch (child.val) {145 switch (child.val) {
146 IrVal.Unknown => return error.SemanticAnalysisFailed,146 IrVal.Unknown => return error.SemanticAnalysisFailed,
...@@ -149,7 +149,7 @@ pub const Instruction = struct {...@@ -149,7 +149,7 @@ pub const Instruction = struct {
149 }149 }
150150
151 /// asserts that the type is known151 /// asserts that the type is known
152 fn getKnownType(self: *Instruction) *Type {152 fn getKnownType(self: *Inst) *Type {
153 switch (self.val) {153 switch (self.val) {
154 IrVal.KnownType => |typeof| return typeof,154 IrVal.KnownType => |typeof| return typeof,
155 IrVal.KnownValue => |value| return value.typeof,155 IrVal.KnownValue => |value| return value.typeof,
...@@ -157,11 +157,11 @@ pub const Instruction = struct {...@@ -157,11 +157,11 @@ pub const Instruction = struct {
157 }157 }
158 }158 }
159159
160 pub fn setGenerated(base: *Instruction) void {160 pub fn setGenerated(base: *Inst) void {
161 base.is_generated = true;161 base.is_generated = true;
162 }162 }
163163
164 pub fn isNoReturn(base: *const Instruction) bool {164 pub fn isNoReturn(base: *const Inst) bool {
165 switch (base.val) {165 switch (base.val) {
166 IrVal.Unknown => return false,166 IrVal.Unknown => return false,
167 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,167 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,
...@@ -169,11 +169,11 @@ pub const Instruction = struct {...@@ -169,11 +169,11 @@ pub const Instruction = struct {
169 }169 }
170 }170 }
171171
172 pub fn isCompTime(base: *const Instruction) bool {172 pub fn isCompTime(base: *const Inst) bool {
173 return base.val == IrVal.KnownValue;173 return base.val == IrVal.KnownValue;
174 }174 }
175175
176 pub fn linkToParent(self: *Instruction, parent: *Instruction) void {176 pub fn linkToParent(self: *Inst, parent: *Inst) void {
177 assert(self.parent == null);177 assert(self.parent == null);
178 assert(parent.child == null);178 assert(parent.child == null);
179 self.parent = parent;179 self.parent = parent;
...@@ -192,7 +192,7 @@ pub const Instruction = struct {...@@ -192,7 +192,7 @@ pub const Instruction = struct {
192 };192 };
193193
194 pub const Const = struct {194 pub const Const = struct {
195 base: Instruction,195 base: Inst,
196 params: Params,196 params: Params,
197197
198 const Params = struct {};198 const Params = struct {};
...@@ -209,7 +209,7 @@ pub const Instruction = struct {...@@ -209,7 +209,7 @@ pub const Instruction = struct {
209 return false;209 return false;
210 }210 }
211211
212 pub fn analyze(self: *const Const, ira: *Analyze) !*Instruction {212 pub fn analyze(self: *const Const, ira: *Analyze) !*Inst {
213 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});213 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});
214 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };214 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };
215 return new_inst;215 return new_inst;
...@@ -221,11 +221,11 @@ pub const Instruction = struct {...@@ -221,11 +221,11 @@ pub const Instruction = struct {
221 };221 };
222222
223 pub const Return = struct {223 pub const Return = struct {
224 base: Instruction,224 base: Inst,
225 params: Params,225 params: Params,
226226
227 const Params = struct {227 const Params = struct {
228 return_value: *Instruction,228 return_value: *Inst,
229 };229 };
230230
231 const ir_val_init = IrVal.Init.NoReturn;231 const ir_val_init = IrVal.Init.NoReturn;
...@@ -238,7 +238,7 @@ pub const Instruction = struct {...@@ -238,7 +238,7 @@ pub const Instruction = struct {
238 return true;238 return true;
239 }239 }
240240
241 pub fn analyze(self: *const Return, ira: *Analyze) !*Instruction {241 pub fn analyze(self: *const Return, ira: *Analyze) !*Inst {
242 const value = try self.params.return_value.getAsParam();242 const value = try self.params.return_value.getAsParam();
243 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);243 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);
244244
...@@ -261,11 +261,11 @@ pub const Instruction = struct {...@@ -261,11 +261,11 @@ pub const Instruction = struct {
261 };261 };
262262
263 pub const Ref = struct {263 pub const Ref = struct {
264 base: Instruction,264 base: Inst,
265 params: Params,265 params: Params,
266266
267 const Params = struct {267 const Params = struct {
268 target: *Instruction,268 target: *Inst,
269 mut: Type.Pointer.Mut,269 mut: Type.Pointer.Mut,
270 volatility: Type.Pointer.Vol,270 volatility: Type.Pointer.Vol,
271 };271 };
...@@ -278,7 +278,7 @@ pub const Instruction = struct {...@@ -278,7 +278,7 @@ pub const Instruction = struct {
278 return false;278 return false;
279 }279 }
280280
281 pub fn analyze(self: *const Ref, ira: *Analyze) !*Instruction {281 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
282 const target = try self.params.target.getAsParam();282 const target = try self.params.target.getAsParam();
283283
284 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {284 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
...@@ -314,7 +314,7 @@ pub const Instruction = struct {...@@ -314,7 +314,7 @@ pub const Instruction = struct {
314 };314 };
315315
316 pub const DeclVar = struct {316 pub const DeclVar = struct {
317 base: Instruction,317 base: Inst,
318 params: Params,318 params: Params,
319319
320 const Params = struct {320 const Params = struct {
...@@ -329,17 +329,17 @@ pub const Instruction = struct {...@@ -329,17 +329,17 @@ pub const Instruction = struct {
329 return true;329 return true;
330 }330 }
331331
332 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Instruction {332 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Inst {
333 return error.Unimplemented; // TODO333 return error.Unimplemented; // TODO
334 }334 }
335 };335 };
336336
337 pub const CheckVoidStmt = struct {337 pub const CheckVoidStmt = struct {
338 base: Instruction,338 base: Inst,
339 params: Params,339 params: Params,
340340
341 const Params = struct {341 const Params = struct {
342 target: *Instruction,342 target: *Inst,
343 };343 };
344344
345 const ir_val_init = IrVal.Init.Unknown;345 const ir_val_init = IrVal.Init.Unknown;
...@@ -350,18 +350,18 @@ pub const Instruction = struct {...@@ -350,18 +350,18 @@ pub const Instruction = struct {
350 return true;350 return true;
351 }351 }
352352
353 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Instruction {353 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
354 return error.Unimplemented; // TODO354 return error.Unimplemented; // TODO
355 }355 }
356 };356 };
357357
358 pub const Phi = struct {358 pub const Phi = struct {
359 base: Instruction,359 base: Inst,
360 params: Params,360 params: Params,
361361
362 const Params = struct {362 const Params = struct {
363 incoming_blocks: []*BasicBlock,363 incoming_blocks: []*BasicBlock,
364 incoming_values: []*Instruction,364 incoming_values: []*Inst,
365 };365 };
366366
367 const ir_val_init = IrVal.Init.Unknown;367 const ir_val_init = IrVal.Init.Unknown;
...@@ -372,18 +372,18 @@ pub const Instruction = struct {...@@ -372,18 +372,18 @@ pub const Instruction = struct {
372 return false;372 return false;
373 }373 }
374374
375 pub fn analyze(self: *const Phi, ira: *Analyze) !*Instruction {375 pub fn analyze(self: *const Phi, ira: *Analyze) !*Inst {
376 return error.Unimplemented; // TODO376 return error.Unimplemented; // TODO
377 }377 }
378 };378 };
379379
380 pub const Br = struct {380 pub const Br = struct {
381 base: Instruction,381 base: Inst,
382 params: Params,382 params: Params,
383383
384 const Params = struct {384 const Params = struct {
385 dest_block: *BasicBlock,385 dest_block: *BasicBlock,
386 is_comptime: *Instruction,386 is_comptime: *Inst,
387 };387 };
388388
389 const ir_val_init = IrVal.Init.NoReturn;389 const ir_val_init = IrVal.Init.NoReturn;
...@@ -394,17 +394,41 @@ pub const Instruction = struct {...@@ -394,17 +394,41 @@ pub const Instruction = struct {
394 return true;394 return true;
395 }395 }
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 {
398 return error.Unimplemented; // TODO422 return error.Unimplemented; // TODO
399 }423 }
400 };424 };
401425
402 pub const AddImplicitReturnType = struct {426 pub const AddImplicitReturnType = struct {
403 base: Instruction,427 base: Inst,
404 params: Params,428 params: Params,
405429
406 pub const Params = struct {430 pub const Params = struct {
407 target: *Instruction,431 target: *Inst,
408 };432 };
409433
410 const ir_val_init = IrVal.Init.Unknown;434 const ir_val_init = IrVal.Init.Unknown;
...@@ -417,12 +441,117 @@ pub const Instruction = struct {...@@ -417,12 +441,117 @@ pub const Instruction = struct {
417 return true;441 return true;
418 }442 }
419443
420 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {444 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Inst {
421 const target = try self.params.target.getAsParam();445 const target = try self.params.target.getAsParam();
422 try ira.src_implicit_return_type_list.append(target);446 try ira.src_implicit_return_type_list.append(target);
423 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);447 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
424 }448 }
425 };449 };
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 };
426};555};
427556
428pub const Variable = struct {557pub const Variable = struct {
...@@ -434,8 +563,8 @@ pub const BasicBlock = struct {...@@ -434,8 +563,8 @@ pub const BasicBlock = struct {
434 name_hint: [*]const u8, // must be a C string literal563 name_hint: [*]const u8, // must be a C string literal
435 debug_id: usize,564 debug_id: usize,
436 scope: *Scope,565 scope: *Scope,
437 instruction_list: std.ArrayList(*Instruction),566 instruction_list: std.ArrayList(*Inst),
438 ref_instruction: ?*Instruction,567 ref_instruction: ?*Inst,
439568
440 /// for codegen569 /// for codegen
441 llvm_block: llvm.BasicBlockRef,570 llvm_block: llvm.BasicBlockRef,
...@@ -491,10 +620,12 @@ pub const Builder = struct {...@@ -491,10 +620,12 @@ pub const Builder = struct {
491 next_debug_id: usize,620 next_debug_id: usize,
492 parsed_file: *ParsedFile,621 parsed_file: *ParsedFile,
493 is_comptime: bool,622 is_comptime: bool,
623 is_async: bool,
624 begin_scope: ?*Scope,
494625
495 pub const Error = Analyze.Error;626 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 {
498 const code = try comp.gpa().create(Code{629 const code = try comp.gpa().create(Code{
499 .basic_block_list = undefined,630 .basic_block_list = undefined,
500 .arena = std.heap.ArenaAllocator.init(comp.gpa()),631 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
...@@ -510,6 +641,8 @@ pub const Builder = struct {...@@ -510,6 +641,8 @@ pub const Builder = struct {
510 .code = code,641 .code = code,
511 .next_debug_id = 0,642 .next_debug_id = 0,
512 .is_comptime = false,643 .is_comptime = false,
644 .is_async = false,
645 .begin_scope = begin_scope,
513 };646 };
514 }647 }
515648
...@@ -529,7 +662,7 @@ pub const Builder = struct {...@@ -529,7 +662,7 @@ pub const Builder = struct {
529 .name_hint = name_hint,662 .name_hint = name_hint,
530 .debug_id = self.next_debug_id,663 .debug_id = self.next_debug_id,
531 .scope = scope,664 .scope = scope,
532 .instruction_list = std.ArrayList(*Instruction).init(self.arena()),665 .instruction_list = std.ArrayList(*Inst).init(self.arena()),
533 .child = null,666 .child = null,
534 .parent = null,667 .parent = null,
535 .ref_instruction = null,668 .ref_instruction = null,
...@@ -549,66 +682,69 @@ pub const Builder = struct {...@@ -549,66 +682,69 @@ pub const Builder = struct {
549 self.current_basic_block = basic_block;682 self.current_basic_block = basic_block;
550 }683 }
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 {
553 switch (node.id) {686 switch (node.id) {
554 ast.Node.Id.Root => unreachable,687 ast.Node.Id.Root => unreachable,
555 ast.Node.Id.Use => unreachable,688 ast.Node.Id.Use => unreachable,
556 ast.Node.Id.TestDecl => unreachable,689 ast.Node.Id.TestDecl => unreachable,
557 ast.Node.Id.VarDecl => @panic("TODO"),690 ast.Node.Id.VarDecl => return error.Unimplemented,
558 ast.Node.Id.Defer => @panic("TODO"),691 ast.Node.Id.Defer => return error.Unimplemented,
559 ast.Node.Id.InfixOp => @panic("TODO"),692 ast.Node.Id.InfixOp => return error.Unimplemented,
560 ast.Node.Id.PrefixOp => @panic("TODO"),693 ast.Node.Id.PrefixOp => return error.Unimplemented,
561 ast.Node.Id.SuffixOp => @panic("TODO"),694 ast.Node.Id.SuffixOp => return error.Unimplemented,
562 ast.Node.Id.Switch => @panic("TODO"),695 ast.Node.Id.Switch => return error.Unimplemented,
563 ast.Node.Id.While => @panic("TODO"),696 ast.Node.Id.While => return error.Unimplemented,
564 ast.Node.Id.For => @panic("TODO"),697 ast.Node.Id.For => return error.Unimplemented,
565 ast.Node.Id.If => @panic("TODO"),698 ast.Node.Id.If => return error.Unimplemented,
566 ast.Node.Id.ControlFlowExpression => return error.Unimplemented,699 ast.Node.Id.ControlFlowExpression => {
567 ast.Node.Id.Suspend => @panic("TODO"),700 const control_flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", node);
568 ast.Node.Id.VarType => @panic("TODO"),701 return irb.genControlFlowExpr(control_flow_expr, scope, lval);
569 ast.Node.Id.ErrorType => @panic("TODO"),702 },
570 ast.Node.Id.FnProto => @panic("TODO"),703 ast.Node.Id.Suspend => return error.Unimplemented,
571 ast.Node.Id.PromiseType => @panic("TODO"),704 ast.Node.Id.VarType => return error.Unimplemented,
572 ast.Node.Id.IntegerLiteral => @panic("TODO"),705 ast.Node.Id.ErrorType => return error.Unimplemented,
573 ast.Node.Id.FloatLiteral => @panic("TODO"),706 ast.Node.Id.FnProto => return error.Unimplemented,
574 ast.Node.Id.StringLiteral => @panic("TODO"),707 ast.Node.Id.PromiseType => return error.Unimplemented,
575 ast.Node.Id.MultilineStringLiteral => @panic("TODO"),708 ast.Node.Id.IntegerLiteral => return error.Unimplemented,
576 ast.Node.Id.CharLiteral => @panic("TODO"),709 ast.Node.Id.FloatLiteral => return error.Unimplemented,
577 ast.Node.Id.BoolLiteral => @panic("TODO"),710 ast.Node.Id.StringLiteral => return error.Unimplemented,
578 ast.Node.Id.NullLiteral => @panic("TODO"),711 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
579 ast.Node.Id.UndefinedLiteral => @panic("TODO"),712 ast.Node.Id.CharLiteral => return error.Unimplemented,
580 ast.Node.Id.ThisLiteral => @panic("TODO"),713 ast.Node.Id.BoolLiteral => return error.Unimplemented,
581 ast.Node.Id.Unreachable => @panic("TODO"),714 ast.Node.Id.NullLiteral => return error.Unimplemented,
582 ast.Node.Id.Identifier => @panic("TODO"),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,
583 ast.Node.Id.GroupedExpression => {719 ast.Node.Id.GroupedExpression => {
584 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);720 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
585 return irb.genNode(grouped_expr.expr, scope, lval);721 return irb.genNode(grouped_expr.expr, scope, lval);
586 },722 },
587 ast.Node.Id.BuiltinCall => @panic("TODO"),723 ast.Node.Id.BuiltinCall => return error.Unimplemented,
588 ast.Node.Id.ErrorSetDecl => @panic("TODO"),724 ast.Node.Id.ErrorSetDecl => return error.Unimplemented,
589 ast.Node.Id.ContainerDecl => @panic("TODO"),725 ast.Node.Id.ContainerDecl => return error.Unimplemented,
590 ast.Node.Id.Asm => @panic("TODO"),726 ast.Node.Id.Asm => return error.Unimplemented,
591 ast.Node.Id.Comptime => @panic("TODO"),727 ast.Node.Id.Comptime => return error.Unimplemented,
592 ast.Node.Id.Block => {728 ast.Node.Id.Block => {
593 const block = @fieldParentPtr(ast.Node.Block, "base", node);729 const block = @fieldParentPtr(ast.Node.Block, "base", node);
594 return irb.lvalWrap(scope, try irb.genBlock(block, scope), lval);730 return irb.lvalWrap(scope, try irb.genBlock(block, scope), lval);
595 },731 },
596 ast.Node.Id.DocComment => @panic("TODO"),732 ast.Node.Id.DocComment => return error.Unimplemented,
597 ast.Node.Id.SwitchCase => @panic("TODO"),733 ast.Node.Id.SwitchCase => return error.Unimplemented,
598 ast.Node.Id.SwitchElse => @panic("TODO"),734 ast.Node.Id.SwitchElse => return error.Unimplemented,
599 ast.Node.Id.Else => @panic("TODO"),735 ast.Node.Id.Else => return error.Unimplemented,
600 ast.Node.Id.Payload => @panic("TODO"),736 ast.Node.Id.Payload => return error.Unimplemented,
601 ast.Node.Id.PointerPayload => @panic("TODO"),737 ast.Node.Id.PointerPayload => return error.Unimplemented,
602 ast.Node.Id.PointerIndexPayload => @panic("TODO"),738 ast.Node.Id.PointerIndexPayload => return error.Unimplemented,
603 ast.Node.Id.StructField => @panic("TODO"),739 ast.Node.Id.StructField => return error.Unimplemented,
604 ast.Node.Id.UnionTag => @panic("TODO"),740 ast.Node.Id.UnionTag => return error.Unimplemented,
605 ast.Node.Id.EnumTag => @panic("TODO"),741 ast.Node.Id.EnumTag => return error.Unimplemented,
606 ast.Node.Id.ErrorTag => @panic("TODO"),742 ast.Node.Id.ErrorTag => return error.Unimplemented,
607 ast.Node.Id.AsmInput => @panic("TODO"),743 ast.Node.Id.AsmInput => return error.Unimplemented,
608 ast.Node.Id.AsmOutput => @panic("TODO"),744 ast.Node.Id.AsmOutput => return error.Unimplemented,
609 ast.Node.Id.AsyncAttribute => @panic("TODO"),745 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
610 ast.Node.Id.ParamDecl => @panic("TODO"),746 ast.Node.Id.ParamDecl => return error.Unimplemented,
611 ast.Node.Id.FieldInitializer => @panic("TODO"),747 ast.Node.Id.FieldInitializer => return error.Unimplemented,
612 }748 }
613 }749 }
614750
...@@ -630,7 +766,7 @@ pub const Builder = struct {...@@ -630,7 +766,7 @@ pub const Builder = struct {
630 }766 }
631 }767 }
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 {
634 const block_scope = try Scope.Block.create(irb.comp, parent_scope);770 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
635771
636 const outer_block_scope = &block_scope.base;772 const outer_block_scope = &block_scope.base;
...@@ -648,7 +784,7 @@ pub const Builder = struct {...@@ -648,7 +784,7 @@ pub const Builder = struct {
648 }784 }
649785
650 if (block.label) |label| {786 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());
652 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());788 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
653 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");789 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
654 block_scope.is_comptime = try irb.buildConstBool(790 block_scope.is_comptime = try irb.buildConstBool(
...@@ -659,7 +795,7 @@ pub const Builder = struct {...@@ -659,7 +795,7 @@ pub const Builder = struct {
659 }795 }
660796
661 var is_continuation_unreachable = false;797 var is_continuation_unreachable = false;
662 var noreturn_return_value: ?*Instruction = null;798 var noreturn_return_value: ?*Inst = null;
663799
664 var stmt_it = block.statements.iterator(0);800 var stmt_it = block.statements.iterator(0);
665 while (stmt_it.next()) |statement_node_ptr| {801 while (stmt_it.next()) |statement_node_ptr| {
...@@ -686,16 +822,16 @@ pub const Builder = struct {...@@ -686,16 +822,16 @@ pub const Builder = struct {
686 noreturn_return_value = statement_value;822 noreturn_return_value = statement_value;
687 }823 }
688824
689 if (statement_value.cast(Instruction.DeclVar)) |decl_var| {825 if (statement_value.cast(Inst.DeclVar)) |decl_var| {
690 // variable declarations start a new scope826 // variable declarations start a new scope
691 child_scope = decl_var.params.variable.child_scope;827 child_scope = decl_var.params.variable.child_scope;
692 } else if (!is_continuation_unreachable) {828 } else if (!is_continuation_unreachable) {
693 // this statement's value must be void829 // this statement's value must be void
694 _ = irb.build(830 _ = irb.build(
695 Instruction.CheckVoidStmt,831 Inst.CheckVoidStmt,
696 child_scope,832 child_scope,
697 statement_value.span,833 statement_value.span,
698 Instruction.CheckVoidStmt.Params{ .target = statement_value },834 Inst.CheckVoidStmt.Params{ .target = statement_value },
699 );835 );
700 }836 }
701 }837 }
...@@ -707,7 +843,7 @@ pub const Builder = struct {...@@ -707,7 +843,7 @@ pub const Builder = struct {
707 }843 }
708844
709 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);845 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{
711 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),847 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
712 .incoming_values = block_scope.incoming_values.toOwnedSlice(),848 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
713 });849 });
...@@ -720,14 +856,14 @@ pub const Builder = struct {...@@ -720,14 +856,14 @@ pub const Builder = struct {
720 );856 );
721 _ = try irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit);857 _ = 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{
724 .dest_block = block_scope.end_block,860 .dest_block = block_scope.end_block,
725 .is_comptime = block_scope.is_comptime,861 .is_comptime = block_scope.is_comptime,
726 });862 });
727863
728 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);864 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{
731 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),867 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
732 .incoming_values = block_scope.incoming_values.toOwnedSlice(),868 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
733 });869 });
...@@ -737,6 +873,135 @@ pub const Builder = struct {...@@ -737,6 +873,135 @@ pub const Builder = struct {
737 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);873 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
738 }874 }
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
740 fn genDefersForBlock(1005 fn genDefersForBlock(
741 irb: *Builder,1006 irb: *Builder,
742 inner_scope: *Scope,1007 inner_scope: *Scope,
...@@ -764,10 +1029,10 @@ pub const Builder = struct {...@@ -764,10 +1029,10 @@ pub const Builder = struct {
764 is_noreturn = true;1029 is_noreturn = true;
765 } else {1030 } else {
766 _ = try irb.build(1031 _ = try irb.build(
767 Instruction.CheckVoidStmt,1032 Inst.CheckVoidStmt,
768 &defer_expr_scope.base,1033 &defer_expr_scope.base,
769 Span.token(defer_expr_scope.expr_node.lastToken()),1034 Span.token(defer_expr_scope.expr_node.lastToken()),
770 Instruction.CheckVoidStmt.Params{ .target = instruction },1035 Inst.CheckVoidStmt.Params{ .target = instruction },
771 );1036 );
772 }1037 }
773 }1038 }
...@@ -785,13 +1050,13 @@ pub const Builder = struct {...@@ -785,13 +1050,13 @@ pub const Builder = struct {
785 }1050 }
786 }1051 }
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 {
789 switch (lval) {1054 switch (lval) {
790 LVal.None => return instruction,1055 LVal.None => return instruction,
791 LVal.Ptr => {1056 LVal.Ptr => {
792 // We needed a pointer to a value, but we got a value. So we create1057 // We needed a pointer to a value, but we got a value. So we create
793 // an instruction which just makes a const pointer of it.1058 // 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{
795 .target = instruction,1060 .target = instruction,
796 .mut = Type.Pointer.Mut.Const,1061 .mut = Type.Pointer.Mut.Const,
797 .volatility = Type.Pointer.Vol.Non,1062 .volatility = Type.Pointer.Vol.Non,
...@@ -811,10 +1076,10 @@ pub const Builder = struct {...@@ -811,10 +1076,10 @@ pub const Builder = struct {
811 span: Span,1076 span: Span,
812 params: I.Params,1077 params: I.Params,
813 is_generated: bool,1078 is_generated: bool,
814 ) !*Instruction {1079 ) !*Inst {
815 const inst = try self.arena().create(I{1080 const inst = try self.arena().create(I{
816 .base = Instruction{1081 .base = Inst{
817 .id = Instruction.typeToId(I),1082 .id = Inst.typeToId(I),
818 .is_generated = is_generated,1083 .is_generated = is_generated,
819 .scope = scope,1084 .scope = scope,
820 .debug_id = self.next_debug_id,1085 .debug_id = self.next_debug_id,
...@@ -838,8 +1103,8 @@ pub const Builder = struct {...@@ -838,8 +1103,8 @@ pub const Builder = struct {
838 inline while (i < @memberCount(I.Params)) : (i += 1) {1103 inline while (i < @memberCount(I.Params)) : (i += 1) {
839 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));1104 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
840 switch (FieldType) {1105 switch (FieldType) {
841 *Instruction => @field(inst.params, @memberName(I.Params, i)).ref(self),1106 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
842 ?*Instruction => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),1107 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
843 else => {},1108 else => {},
844 }1109 }
845 }1110 }
...@@ -855,7 +1120,7 @@ pub const Builder = struct {...@@ -855,7 +1120,7 @@ pub const Builder = struct {
855 scope: *Scope,1120 scope: *Scope,
856 span: Span,1121 span: Span,
857 params: I.Params,1122 params: I.Params,
858 ) !*Instruction {1123 ) !*Inst {
859 return self.buildExtra(I, scope, span, params, false);1124 return self.buildExtra(I, scope, span, params, false);
860 }1125 }
8611126
...@@ -865,21 +1130,71 @@ pub const Builder = struct {...@@ -865,21 +1130,71 @@ pub const Builder = struct {
865 scope: *Scope,1130 scope: *Scope,
866 span: Span,1131 span: Span,
867 params: I.Params,1132 params: I.Params,
868 ) !*Instruction {1133 ) !*Inst {
869 return self.buildExtra(I, scope, span, params, true);1134 return self.buildExtra(I, scope, span, params, true);
870 }1135 }
8711136
872 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Instruction {1137 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Inst {
873 const inst = try self.build(Instruction.Const, scope, span, Instruction.Const.Params{});1138 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
874 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };1139 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };
875 return inst;1140 return inst;
876 }1141 }
8771142
878 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Instruction {1143 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Inst {
879 const inst = try self.buildExtra(Instruction.Const, scope, span, Instruction.Const.Params{}, is_generated);1144 const inst = try self.buildExtra(Inst.Const, scope, span, Inst.Const.Params{}, is_generated);
880 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };1145 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };
881 return inst;1146 return inst;
882 }1147 }
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 }
883};1198};
8841199
885const Analyze = struct {1200const Analyze = struct {
...@@ -888,7 +1203,7 @@ const Analyze = struct {...@@ -888,7 +1203,7 @@ const Analyze = struct {
888 const_predecessor_bb: ?*BasicBlock,1203 const_predecessor_bb: ?*BasicBlock,
889 parent_basic_block: *BasicBlock,1204 parent_basic_block: *BasicBlock,
890 instruction_index: usize,1205 instruction_index: usize,
891 src_implicit_return_type_list: std.ArrayList(*Instruction),1206 src_implicit_return_type_list: std.ArrayList(*Inst),
892 explicit_return_type: ?*Type,1207 explicit_return_type: ?*Type,
8931208
894 pub const Error = error{1209 pub const Error = error{
...@@ -903,7 +1218,7 @@ const Analyze = struct {...@@ -903,7 +1218,7 @@ const Analyze = struct {
903 };1218 };
9041219
905 pub fn init(comp: *Compilation, parsed_file: *ParsedFile, explicit_return_type: ?*Type) !Analyze {1220 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);
907 errdefer irb.abort();1222 errdefer irb.abort();
9081223
909 return Analyze{1224 return Analyze{
...@@ -912,7 +1227,7 @@ const Analyze = struct {...@@ -912,7 +1227,7 @@ const Analyze = struct {
912 .const_predecessor_bb = null,1227 .const_predecessor_bb = null,
913 .parent_basic_block = undefined, // initialized with startBasicBlock1228 .parent_basic_block = undefined, // initialized with startBasicBlock
914 .instruction_index = undefined, // initialized with startBasicBlock1229 .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()),
916 .explicit_return_type = explicit_return_type,1231 .explicit_return_type = explicit_return_type,
917 };1232 };
918 }1233 }
...@@ -921,7 +1236,7 @@ const Analyze = struct {...@@ -921,7 +1236,7 @@ const Analyze = struct {
921 self.irb.abort();1236 self.irb.abort();
922 }1237 }
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 {
925 if (old_bb.child) |child| {1240 if (old_bb.child) |child| {
926 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)1241 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)
927 return child;1242 return child;
...@@ -984,18 +1299,18 @@ const Analyze = struct {...@@ -984,18 +1299,18 @@ const Analyze = struct {
984 return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args);1299 return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args);
985 }1300 }
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 {
988 // TODO actual implementation1303 // TODO actual implementation
989 return &Type.Void.get(self.irb.comp).base;1304 return &Type.Void.get(self.irb.comp).base;
990 }1305 }
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 {
993 const dest_type = optional_dest_type orelse return target;1308 const dest_type = optional_dest_type orelse return target;
994 @panic("TODO implicitCast");1309 return error.Unimplemented;
995 }1310 }
9961311
997 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Instruction) ?*Value {1312 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {
998 @panic("TODO getCompTimeValOrNullUndefOk");1313 @panic("TODO");
999 }1314 }
10001315
1001 fn getCompTimeRef(1316 fn getCompTimeRef(
...@@ -1005,8 +1320,8 @@ const Analyze = struct {...@@ -1005,8 +1320,8 @@ const Analyze = struct {
1005 mut: Type.Pointer.Mut,1320 mut: Type.Pointer.Mut,
1006 volatility: Type.Pointer.Vol,1321 volatility: Type.Pointer.Vol,
1007 ptr_align: u32,1322 ptr_align: u32,
1008 ) Analyze.Error!*Instruction {1323 ) Analyze.Error!*Inst {
1009 @panic("TODO getCompTimeRef");1324 return error.Unimplemented;
1010 }1325 }
1011};1326};
10121327
...@@ -1014,10 +1329,9 @@ pub async fn gen(...@@ -1014,10 +1329,9 @@ pub async fn gen(
1014 comp: *Compilation,1329 comp: *Compilation,
1015 body_node: *ast.Node,1330 body_node: *ast.Node,
1016 scope: *Scope,1331 scope: *Scope,
1017 end_span: Span,
1018 parsed_file: *ParsedFile,1332 parsed_file: *ParsedFile,
1019) !*Code {1333) !*Code {
1020 var irb = try Builder.init(comp, parsed_file);1334 var irb = try Builder.init(comp, parsed_file, scope);
1021 errdefer irb.abort();1335 errdefer irb.abort();
10221336
1023 const entry_block = try irb.createBasicBlock(scope, c"Entry");1337 const entry_block = try irb.createBasicBlock(scope, c"Entry");
...@@ -1026,18 +1340,8 @@ pub async fn gen(...@@ -1026,18 +1340,8 @@ pub async fn gen(
10261340
1027 const result = try irb.genNode(body_node, scope, LVal.None);1341 const result = try irb.genNode(body_node, scope, LVal.None);
1028 if (!result.isNoReturn()) {1342 if (!result.isNoReturn()) {
1029 _ = irb.buildGen(1343 // no need for save_err_ret_addr because this cannot return error
1030 Instruction.AddImplicitReturnType,1344 _ = try irb.genAsyncReturn(scope, Span.token(body_node.lastToken()), result, true);
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 );
1041 }1345 }
10421346
1043 return irb.finish();1347 return irb.finish();
src-self-hosted/scope.zig+22-2
...@@ -49,6 +49,24 @@ pub const Scope = struct {...@@ -49,6 +49,24 @@ pub const Scope = struct {
49 }49 }
50 }50 }
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
52 pub const Id = enum {70 pub const Id = enum {
53 Decls,71 Decls,
54 Block,72 Block,
...@@ -90,10 +108,10 @@ pub const Scope = struct {...@@ -90,10 +108,10 @@ pub const Scope = struct {
90108
91 pub const Block = struct {109 pub const Block = struct {
92 base: Scope,110 base: Scope,
93 incoming_values: std.ArrayList(*ir.Instruction),111 incoming_values: std.ArrayList(*ir.Inst),
94 incoming_blocks: std.ArrayList(*ir.BasicBlock),112 incoming_blocks: std.ArrayList(*ir.BasicBlock),
95 end_block: *ir.BasicBlock,113 end_block: *ir.BasicBlock,
96 is_comptime: *ir.Instruction,114 is_comptime: *ir.Inst,
97115
98 safety: Safety,116 safety: Safety,
99117
...@@ -242,6 +260,7 @@ pub const Scope = struct {...@@ -242,6 +260,7 @@ pub const Scope = struct {
242 pub const DeferExpr = struct {260 pub const DeferExpr = struct {
243 base: Scope,261 base: Scope,
244 expr_node: *ast.Node,262 expr_node: *ast.Node,
263 reported_err: bool,
245264
246 /// Creates a DeferExpr scope with 1 reference265 /// Creates a DeferExpr scope with 1 reference
247 pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr {266 pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr {
...@@ -252,6 +271,7 @@ pub const Scope = struct {...@@ -252,6 +271,7 @@ pub const Scope = struct {
252 .ref_count = 1,271 .ref_count = 1,
253 },272 },
254 .expr_node = expr_node,273 .expr_node = expr_node,
274 .reported_err = false,
255 });275 });
256 errdefer comp.gpa().destroy(self);276 errdefer comp.gpa().destroy(self);
257277
test/stage2/compile_errors.zig+12
...@@ -9,4 +9,16 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -9,4 +9,16 @@ pub fn addCases(ctx: *TestContext) !void {
9 try ctx.testCompileError(9 try ctx.testCompileError(
10 \\fn() void {}10 \\fn() void {}
11 , "1.zig", 1, 1, "missing function name");11 , "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");
12}24}