authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-09-16 16:53:43-04:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-09-16 16:53:43-04:00
log9daf72539c78ad1f4e42de7e54a86d258d188e3d
tree4d7616561fb287fb6016c75c3bdefa4ad426ba7b
parent4f36df95e5a809e6859d7e927c5d4f71c2c5b861
signature Commit is signed but in an unrecognized format.

feat: inferred return type


15 files changed, 237 insertions(+), 131 deletions(-)

CHANGELOG.md+1
......@@ -14,6 +14,7 @@
1414- feat: allow instantiating `@extern` at compile time
1515- feat: implement tuples
1616- feat: implement multiline string literals
17- feat: implement inferred return type
1718- fix: crash when printing unused struct declaration error
1819- fix: provide array result type to sema
1920- fix: crash when analyzing an empty array without a result type
src/Cli.zig+1-3
......@@ -268,7 +268,6 @@ pub fn parse(
268268 args,
269269 stderr.get(),
270270 stderr.tty,
271 true,
272271 ) catch |e| switch (e) {
273272 error.InvalidArguments => {
274273 stderr.buffered_writer.flush() catch {};
......@@ -287,9 +286,8 @@ pub fn parseWithErrorWriter(
287286 args: []const []const u8,
288287 err: std.io.AnyWriter,
289288 tty: std.io.tty.Config,
290 comptime exit_on_error: bool,
291289) ParseError!p.Parsed() {
292 _ = exit_on_error; // autofix
290 @setEvalBranchQuota(std.math.maxInt(u32));
293291 var out: p.Parsed() = .{};
294292 var had_errors = false;
295293 var positionals_counted: usize = 0;
src/core/Air.zig+2-3
......@@ -388,9 +388,8 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
388388 .call => {
389389 const base_type = air.typeOf(air.instData(.call, index).base, ip);
390390 if (base_type == .@"opaque") return .@"opaque";
391 return base_type.toFunctionPrototype(ip).?.return_type orelse
392 // unreachable // return type was not resolved
393 @panic("TODO: resolve return type");
391 return base_type.toUnresolvedFunctionPrototype(ip).?.return_type orelse
392 unreachable; // return type was not resolved
394393 },
395394
396395 // Field accesses on structs are special-cased by storing the field
src/core/Comp.zig+37-24
......@@ -119,8 +119,16 @@ pub fn enqueueEntryModule(comp: *Comp, file: *File) !Decl.Index {
119119
120120 const ns = try comp.indexTegModule(file, .main_module_inst);
121121 const main_str = try comp.intern_pool.getOrPutString(comp.gpa, "main", .no_embedded_nulls);
122 const decl_index = comp.intern_pool.namespacePtr(ns).lookupDirect(comp, main_str) orelse
123 @panic("missing 'fn main' in root module");
122 const decl_index = comp.intern_pool.namespacePtr(ns).lookupDirect(comp, main_str) orelse {
123 // TODO: add a helper function into Report to render a single error
124 var rb = Report.Builder.init(comp.gpa);
125 defer rb.deinit();
126 try rb.err(.no_main_func, .{});
127 const r: Report = try rb.finalize();
128 defer r.deinit(comp.gpa);
129 try r.dump(.{ .comp = .{ .comp = comp, .file = file } }, comp.out);
130 return error.TransformFail;
131 };
124132
125133 try comp.jobs.writeItem(.{ .analysis = .{ .au = .wrap(.{ .decl = decl_index }) } });
126134
......@@ -136,7 +144,14 @@ pub fn runAllJobs(comp: *Comp) !void {
136144 }
137145 }
138146
139 assert(comp.ongoing_analysis.size == 0);
147 if (core.assertFailed(comp.ongoing_analysis.size == 0)) {
148 std.debug.print("Unresumed AnalysisUnits:\n", .{});
149 var it = comp.ongoing_analysis.keyIterator();
150 while (it.next()) |au| {
151 std.debug.print("- {}\n", .{au.dump(&comp.intern_pool)});
152 }
153 std.debug.panic("runAllJobs returned with {d} remaining ongoing_analysis", .{comp.ongoing_analysis.size});
154 }
140155}
141156
142157const AnalysisJobError = Allocator.Error || error{ AnalysisFail, TooManyValues };
......@@ -166,10 +181,17 @@ fn runAnalysisJob(comp: *Comp, unit: InternPool.AnalysisUnit, first_blocked_sema
166181 errdefer _ = sema.deinit(.free_all);
167182 gop.value_ptr.* = sema;
168183
184 switch (unit.unwrap()) {
185 .decl => decl.analysis = .in_progress,
186 .func => |v| {
187 v.toKey(&comp.intern_pool).func.analysis.set(&comp.intern_pool, .in_progress);
188 },
189 }
190
169191 if (first_blocked_sema) |blocked_sema|
170192 try sema.blocked_semas.append(comp.gpa, blocked_sema);
171 } else {
172 assert(first_blocked_sema == null);
193 } else if (first_blocked_sema) |blocked_sema| {
194 try gop.value_ptr.*.blocked_semas.append(comp.gpa, blocked_sema);
173195 }
174196
175197 const sema: *Sema = gop.value_ptr.*;
......@@ -194,6 +216,15 @@ fn runAnalysisJob(comp: *Comp, unit: InternPool.AnalysisUnit, first_blocked_sema
194216 },
195217 };
196218
219 switch (unit.unwrap()) {
220 .decl => |index| {
221 comp.intern_pool.declPtr(index).analysis = .complete;
222 },
223 .func => |v| {
224 v.toKey(&comp.intern_pool).func.analysis.set(&comp.intern_pool, .complete);
225 },
226 }
227
197228 comp.ongoing_analysis.removeByPtr(gop.key_ptr);
198229 try comp.jobs.ensureUnusedCapacity(sema.blocked_semas.items.len);
199230 for (sema.blocked_semas.items) |other_sema| {
......@@ -453,29 +484,13 @@ pub const Decl = struct {
453484 /// the function type is analyzed with this set to `in_progress`; however, the semantic
454485 /// analysis of the function body is performed with this value set to `success`. Functions
455486 /// have their own analysis status field.
456 analysis: enum {
457 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
458 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
459 unreferenced,
460 in_progress,
461 waiting,
462 complete,
463 },
487 analysis: InternPool.AnalysisState,
464488
465489 pub fn value(decl: *const Decl) InternPool.Value {
466490 assert(decl.analysis == .complete);
467491 return decl.raw_value orelse unreachable;
468492 }
469493
470 pub fn @"type"(decl: *const Decl, ip: *const InternPool) InternPool.Type {
471 return switch (decl.analysis) {
472 .unreferenced => unreachable,
473 .in_progress => unreachable,
474 .in_progress_prototype_available => decl.raw_value.?.toTypeUnsafe(ip),
475 .complete => decl.raw_value.?.typeOf(ip),
476 };
477 }
478
479494 pub fn fmtJson(decl: *const Decl, comp: *const Comp) JsonFormatter {
480495 return .{ .decl = decl, .comp = comp };
481496 }
......@@ -516,8 +531,6 @@ pub const Decl = struct {
516531 pub const Index = InternPool.DeclIndex;
517532};
518533
519pub const Func = struct {};
520
521534/// A namespace is a container for declarations. Currently the only form of
522535/// namespace that exists is file-scope. In the future, the `module` keyword
523536/// will create nested namespaces, and it is probable that `struct` and other
src/core/InternPool.zig+38-30
......@@ -73,6 +73,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index)
7373/// Dependencies on the value of a Decl.
7474/// Value is index into `dep_entries` of the first dependency on this Decl value.
7575decl_val_deps: std.AutoArrayHashMapUnmanaged(DeclIndex, DepEntry.Index) = .{},
76/// Dependencies on the value of a Decl.
77/// Value is index into `dep_entries` of the first dependency on this Decl value.
78resolved_func_deps: std.AutoArrayHashMapUnmanaged(Value, DepEntry.Index) = .{},
7679
7780/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
7881/// matches. The `next_dependee` field can be used to iterate all such entries
......@@ -176,6 +179,8 @@ pub const Tag = enum(u8) {
176179 owner_decl: DeclIndex,
177180 ty: Type,
178181 teg_body_inst: TrackedInst.Index,
182
183 pub const ty_index = 2;
179184 };
180185
181186 /// Trailing:
......@@ -458,7 +463,7 @@ pub const Type = enum(u32) {
458463 return @enumFromInt(@intFromEnum(ty.value().valueTag(ip)));
459464 }
460465
461 pub fn toFunctionPrototype(ty: Type, ip: *const InternPool) ?Key.FunctionType {
466 pub fn toUnresolvedFunctionPrototype(ty: Type, ip: *const InternPool) ?Key.FunctionType {
462467 if (ty.tag(ip) != .function_type) return null;
463468 return ip.valueToKey(ty.value()).function_type;
464469 }
......@@ -571,7 +576,7 @@ pub const Type = enum(u32) {
571576 switch (ty.tag(ip)) {
572577 .simple_type => unreachable, // all simple types are already printed
573578 .function_type => {
574 const function_type = ty.toFunctionPrototype(ip).?;
579 const function_type = ty.toUnresolvedFunctionPrototype(ip).?;
575580 try writer.writeAll("fn(");
576581 for (function_type.param_types, 0..) |param, i| {
577582 if (i != 0) try writer.writeAll(", ");
......@@ -672,30 +677,8 @@ pub const static_keys = [_]Key{
672677/// State that is mutable during semantic analysis. This data is not used for
673678/// equality or hashing.
674679pub const FuncAnalysis = packed struct(u32) {
675 state: State,
676
677 pub const State = enum(u32) {
678 none,
679 // /// This function has not yet undergone analysis, because we have not
680 // /// seen a potential runtime call. It may be analyzed in future. none,
681 // /// Analysis for this function has been queued, but not yet completed.
682 // queued,
683 // /// This function intentionally only has ZIR generated because it is marked
684 // /// inline, which means no runtime version of the function will be generated.
685 // inline_only,
686 // in_progress,
687 // /// There will be a corresponding ErrorMsg in Module.failed_decls
688 // sema_failure,
689 // /// This function might be OK but it depends on another Decl which did not
690 // /// successfully complete semantic analysis.
691 // dependency_failure,
692 // /// There will be a corresponding ErrorMsg in Module.failed_decls.
693 // /// Indicates that semantic analysis succeeded, but code generation for
694 // /// this function failed.
695 // codegen_failure,
696 // /// Semantic analysis and code generation of this function succeeded.
697 // success,
698 };
680 state: AnalysisState,
681 _: u30 = 0,
699682};
700683
701684/// An index into `string_bytes`.
......@@ -977,6 +960,11 @@ pub const Key = union(enum) {
977960 /// the resolved return type.
978961 return_type: ?Type,
979962
963 pub const Resolved = struct {
964 param_types: []Type,
965 return_type: Type,
966 };
967
980968 pub fn hash(self: FunctionType, hasher: *Hash) void {
981969 const t = tracer.trace(@src());
982970 defer t.end();
......@@ -1066,12 +1054,19 @@ pub const Key = union(enum) {
10661054 ty: Type,
10671055 owner_decl: DeclIndex,
10681056 teg_body_inst: TrackedInst.Index,
1057 analysis: ExtraIndex(AnalysisState),
10691058
10701059 pub fn hash(self: Func, hasher: *Hash) void {
10711060 std.hash.autoHash(hasher, self.ty);
10721061 std.hash.autoHash(hasher, self.owner_decl);
10731062 std.hash.autoHash(hasher, self.teg_body_inst);
10741063 }
1064
1065 /// This should only be used to convert an inferred return type into a reified return type.
1066 pub fn updateType(self: Func, ip: *InternPool, new_type: Type) void {
1067 assert(new_type.tag(ip) == .function_type);
1068 ip.extra.set(Type, @intFromEnum(self.analysis) + Tag.FuncDecl.ty_index, new_type);
1069 }
10751070 };
10761071
10771072 pub fn hash32(key: Key, ip: *const InternPool) u32 {
......@@ -1260,9 +1255,21 @@ pub const AnalysisUnit = packed struct(u32) {
12601255 }
12611256};
12621257
1258/// Every AU has a state.
1259/// For Decls, state is stored on the decl
1260/// For Functions, state is stored on the Key.Func
1261pub const AnalysisState = enum(u2) {
1262 /// This Unit corresponds to an AST Node that has not been referenced yet, and therefore
1263 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
1264 unreferenced,
1265 in_progress,
1266 complete,
1267};
1268
12631269pub const Dependee = union(enum) {
12641270 src_hash: TrackedInst.Index,
12651271 decl_val: DeclIndex,
1272 resolved_func: Value,
12661273};
12671274
12681275pub const DepEntry = extern struct {
......@@ -1393,11 +1400,13 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
13931400 },
13941401 .string => .{ .string = data.decode(.string, item.tag).get(ip).toSlice(ip) },
13951402 .func => {
1396 const func = data.decode(.func, item.tag).get(ip);
1403 const base_index = data.decode(.func, item.tag);
1404 const func = base_index.get(ip);
13971405 return .{ .func = .{
13981406 .ty = func.ty,
13991407 .owner_decl = func.owner_decl,
14001408 .teg_body_inst = func.teg_body_inst,
1409 .analysis = @enumFromInt(@intFromEnum(base_index)),
14011410 } };
14021411 },
14031412 .function_type => .{
......@@ -1497,9 +1506,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
14971506 ),
14981507 .func => |f| brk: {
14991508 const extra = try ip.extra.append(gpa, Tag.FuncDecl, .{
1500 .analysis = .{
1501 .state = .none,
1502 },
1509 .analysis = .{ .state = .unreferenced },
15031510 .owner_decl = f.owner_decl,
15041511 .ty = f.ty,
15051512 .teg_body_inst = f.teg_body_inst,
......@@ -1687,6 +1694,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalysisUnit, de
16871694 const gop = try switch (tag) {
16881695 .src_hash => ip.src_hash_deps,
16891696 .decl_val => ip.decl_val_deps,
1697 .resolved_func => ip.resolved_func_deps,
16901698 }.getOrPut(gpa, dependee_payload);
16911699
16921700 if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {
src/core/Report.zig+13-3
......@@ -56,14 +56,20 @@ pub const Err = union(enum) {
5656 src: LazyNode,
5757
5858 fn build(data: @This(), ctx: *MsgContext) !void {
59 try ctx.msgNode(try data.src.get(ctx), "Value must be known at compile-time", .{});
59 try ctx.msgNode(try data.src.get(ctx), "value must be known at compile-time", .{});
6060 }
6161 },
6262 cannot_be_comptime: struct {
6363 src: LazyNode,
6464
6565 fn build(data: @This(), ctx: *MsgContext) !void {
66 try ctx.msgNode(try data.src.get(ctx), "Operation cannot be performed at compile-time (TODO: make this error more specific)", .{});
66 try ctx.msgNode(try data.src.get(ctx), "operation cannot be performed at compile-time (TODO: make this error more specific)", .{});
67 }
68 },
69 no_main_func: struct {
70 fn build(_: @This(), ctx: *MsgContext) !void {
71 // TODO: variant that includes file, but no location
72 try ctx.msgToken(0, "missing top-level function \"main\"", .{});
6773 }
6874 },
6975 unknown_identifier: struct {
......@@ -154,7 +160,7 @@ pub const Err = union(enum) {
154160 fn build(data: @This(), ctx: *MsgContext) !void {
155161 try ctx.msgNode(
156162 data.node,
157 "Cannot infer struct initialization type",
163 "cannot infer struct initialization type",
158164 .{},
159165 );
160166 }
......@@ -1055,6 +1061,10 @@ pub const MsgContext = struct {
10551061 components: ArrayListUnmanaged(Component),
10561062
10571063 pub fn msg(m: *MsgContext, highlight: Highlight, comptime fmt: []const u8, args: anytype) !void {
1064 comptime if (!std.mem.startsWith(u8, fmt, "TODO")) switch (fmt[0]) {
1065 'A'...'Z' => @compileError("template invalid: " ++ fmt), // style guide: lowercase
1066 else => {},
1067 };
10581068 var arr: std.ArrayListUnmanaged(u8) = .{};
10591069 try std.fmt.format(arr.writer(m.arena), fmt, args);
10601070 try m.components.append(m.arena, .{
src/core/Sema.zig+89-27
......@@ -419,22 +419,36 @@ pub fn run(s: *Sema) Error!void {
419419 switch (s.owner.unwrap()) {
420420 .decl => |decl_index| {
421421 const decl = s.ip.declPtr(decl_index);
422 decl.raw_value = result;
422 decl.raw_value = result.value() orelse unreachable;
423423 decl.analysis = .complete;
424424 },
425425 .func => |value| {
426 const type_of_result = s.typeOfRef(result);
426427 const air = try s.func.?.finalize(s.gpa);
427428 try s.comp.jobs.writeItem(.{ .codegen_func = .{
428429 .value = value,
429430 .air = air,
430431 } });
432
433 // If needed, update the function with its resolved return type
434 const ty = value.typeOf(s.ip);
435 const proto = ty.toUnresolvedFunctionPrototype(s.ip) orelse
436 unreachable; // must be a function type
437
438 if (proto.return_type == null) {
439 const new_type = try s.makeType(.{ .function_type = .{
440 .param_types = proto.param_types,
441 .return_type = type_of_result,
442 } });
443 value.toKey(s.ip).func.updateType(s.ip, new_type);
444 }
431445 },
432446 }
433447 return;
434448 };
435449}
436450
437pub fn step(s: *Sema) Error!?Value {
451pub fn step(s: *Sema) Error!?Air.Inst.Ref {
438452 s.instruction_step_lock.lock(); // Semantic analysis must not be recursive
439453 defer s.instruction_step_lock.unlock();
440454
......@@ -463,10 +477,7 @@ pub fn step(s: *Sema) Error!?Value {
463477 // the instruction pointer has been moved already
464478 assert(s.frame.currentIndex() != start_index); // control flow loop
465479 },
466 .stop => return switch (s.owner.kind) {
467 .decl => s.inst_map.get(s.frame.block_index).decode().value,
468 .func => .void,
469 },
480 .stop => return s.inst_map.get(s.frame.block_index),
470481 },
471482 }
472483 },
......@@ -527,7 +538,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag)
527538 const param: Teg.DataNode = s.frame.currentData(.param);
528539 assert(s.frame.mode == .run_time); // never emitted in a comptime block
529540 assert(s.owner.kind == .func); // only emitted in function body
530 const param_types = s.owner.unwrap().func.toKey(s.ip).func.ty.toFunctionPrototype(s.ip).?.param_types;
541 const param_types = s.owner.unwrap().func.toKey(s.ip).func.ty.toUnresolvedFunctionPrototype(s.ip).?.param_types;
531542 return s.addRef(.arg, .{
532543 .type = param_types[param.data],
533544 .arg_number = param.data,
......@@ -724,7 +735,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag)
724735 const scratch = try s.arena().alloc(Air.Inst.Ref, call.args.len);
725736 defer s.arena().free(scratch);
726737 if (base_type != .@"opaque") {
727 const proto = base_type.toFunctionPrototype(s.ip) orelse {
738 const proto = try s.resolveFunctionPrototype(base, base_type) orelse {
728739 return s.fail(.call_non_function, .{
729740 .call = s.lazyNode(.operand),
730741 .ty = base_type,
......@@ -981,21 +992,29 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag)
981992 const mark = core.U32Stack.Mark{ .stack = &s.scratch, .index = s.frame.mark_index };
982993
983994 if (s.frame_stack.items.len == 0) {
984 s.inst_map.add(s.frame.block_index, operand);
985
986995 if (s.func) |*func| {
996 const proto = s.owner.unwrap().func.typeOf(s.ip).toUnresolvedFunctionPrototype(s.ip) orelse
997 unreachable; // must be a function
998 const coerced = if (proto.return_type) |return_coercion|
999 try s.coerceRef(s.lazyNode(.operand), operand, return_coercion)
1000 else
1001 operand;
1002 s.inst_map.add(s.frame.block_index, coerced);
1003
9871004 const indexes = mark.slice(u32);
9881005 try func.extra.list.ensureUnusedCapacity(s.gpa, indexes.len + 1);
9891006 const start = func.extra.list.items.len;
9901007 func.extra.list.appendSliceAssumeCapacity(indexes);
9911008 func.extra.list.appendAssumeCapacity(@intFromEnum(try s.addIndexUntracked(.@"break", .{
9921009 .block = .main_block,
993 .value = operand,
1010 .value = coerced,
9941011 })));
9951012 func.instructions.items(.data)[0] = .encode(.block, .{
9961013 .start = @intCast(start),
9971014 .len = @intCast(indexes.len + 1),
9981015 });
1016 } else {
1017 s.inst_map.add(s.frame.block_index, operand);
9991018 }
10001019
10011020 return .stop;
......@@ -1420,7 +1439,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag)
14201439 const operand = s.getRef(result.call_base, .no_mark);
14211440 const ty = s.typeOfRef(operand);
14221441
1423 const func: InternPool.Key.FunctionType = ty.toFunctionPrototype(s.ip) orelse
1442 const func: InternPool.Key.FunctionType = ty.toUnresolvedFunctionPrototype(s.ip) orelse
14241443 return Value.opaque_type.toAir();
14251444
14261445 if (result.argument >= func.param_types.len)
......@@ -1837,11 +1856,18 @@ fn ensureValueRuntime(s: *Sema, src: LazyNode, ref: Air.Inst.Ref) Error!Air.Inst
18371856 .type = ty,
18381857 }),
18391858 .@"opaque" => @panic("TODO: represent comptime-known opaques better"),
1840 _ => if (!ty.hasPossibleRepresentation(s.ip)) {
1841 return s.fail(.runtime_incompatible_type, .{
1842 .src = src,
1843 .type = ty,
1844 });
1859 _ => {
1860 if (!ty.hasPossibleRepresentation(s.ip)) {
1861 return s.fail(.runtime_incompatible_type, .{
1862 .src = src,
1863 .type = ty,
1864 });
1865 }
1866
1867 // When a function is used as a runtime operand, it needs to
1868 // have a resolved return type, so that calling it later is
1869 // able to know what it returns.
1870 _ = try s.resolveFunctionPrototype(ref, ty);
18451871 },
18461872 }
18471873 },
......@@ -1959,23 +1985,24 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) InternPool.DeclIndex {
19591985 }
19601986}
19611987
1962fn getDecl(sema: *Sema, decl_index: Decl.Index) !Value {
1963 if (sema.owner.kind == .decl) {
1964 if (decl_index == sema.owner.unwrap().decl) {
1965 return sema.ip.declPtr(decl_index).value();
1988fn getDecl(s: *Sema, decl_index: Decl.Index) !Value {
1989 if (s.owner.kind == .decl) {
1990 if (decl_index == s.owner.unwrap().decl) {
1991 return s.ip.declPtr(decl_index).value();
19661992 }
19671993 }
1968 const decl_data = sema.ip.declPtr(decl_index);
1969 try sema.declareDependency(.{ .decl_val = decl_index });
1994 const decl_data = s.ip.declPtr(decl_index);
1995 try s.declareDependency(.{ .decl_val = decl_index });
19701996 const au: AnalysisUnit = .wrap(.{ .decl = decl_index });
19711997 switch (decl_data.analysis) {
19721998 .unreferenced => {
1973 try sema.comp.jobs.writeItem(.{ .analysis = .{ .au = au, .first_blocked_sema = sema } });
1999 try s.comp.jobs.writeItem(.{ .analysis = .{ .au = au, .first_blocked_sema = s } });
19742000 return error.Interrupt;
19752001 },
1976 .waiting, .in_progress => {
1977 const other_sema = sema.comp.ongoing_analysis.get(au) orelse unreachable;
1978 try other_sema.blocked_semas.append(sema.gpa, sema);
2002 .in_progress => {
2003 const other_sema = s.comp.ongoing_analysis.get(au) orelse
2004 unreachable; // analysis stopped but did not update state
2005 try other_sema.blocked_semas.append(s.gpa, s);
19792006 return error.Interrupt;
19802007 },
19812008 .complete => {
......@@ -1984,6 +2011,39 @@ fn getDecl(sema: *Sema, decl_index: Decl.Index) !Value {
19842011 }
19852012}
19862013
2014/// Interrupts if there is an unresolved inferred return type.
2015fn resolveFunctionPrototype(s: *Sema, ref: Air.Inst.Ref, ty: Type) !?InternPool.Key.FunctionType.Resolved {
2016 const proto = ty.toUnresolvedFunctionPrototype(s.ip) orelse
2017 return null; // not a function prototype
2018
2019 if (proto.return_type) |return_type|
2020 return .{
2021 .param_types = proto.param_types,
2022 .return_type = return_type,
2023 };
2024
2025 const value = ref.value() orelse
2026 unreachable; // cast functions cannot have inferred return types.
2027
2028 try s.declareDependency(.{ .resolved_func = value });
2029
2030 const func = value.toKey(s.ip).func;
2031 const au: AnalysisUnit = .wrap(.{ .func = value });
2032 switch (func.analysis.get(s.ip)) {
2033 .unreferenced => {
2034 try s.comp.jobs.writeItem(.{ .analysis = .{ .au = au, .first_blocked_sema = s } });
2035 return error.Interrupt;
2036 },
2037 .in_progress => {
2038 const other_sema = s.comp.ongoing_analysis.get(au) orelse
2039 unreachable; // analysis stopped but did not update state
2040 try other_sema.blocked_semas.append(s.gpa, s);
2041 return error.Interrupt;
2042 },
2043 .complete => unreachable, // analyzed but did not set return type
2044 }
2045}
2046
19872047fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
19882048 try sema.ip.addDependency(sema.gpa, sema.owner, dependee);
19892049}
......@@ -2122,11 +2182,13 @@ fn postVisitFunctionPrototype(s: *Sema, reserve: FunctionReserve, return_type: ?
21222182 .return_type = return_type,
21232183 },
21242184 });
2185 // TODO: make a dedicated function to insert a new function
21252186 const func_value = try s.makeValue(.{
21262187 .func = .{
21272188 .ty = func_type,
21282189 .owner_decl = s.techDebtDeclIndex(), // TODO: ooh, this is a fun one!
21292190 .teg_body_inst = tracked_inst,
2191 .analysis = undefined, // not used when appending
21302192 },
21312193 });
21322194
src/core/array.zig+36-33
......@@ -2,40 +2,40 @@ const extra = @This();
22
33pub const Mutability = enum { @"const", @"var" };
44
5fn setAsU32(items: []u32, comptime T: type, index: usize, payload: T) void {
6 const fields = std.meta.fields(@TypeOf(payload));
7 var i = index;
8 inline for (fields) |field| {
9 const value = @field(payload, field.name);
10 switch (field.type) {
11 u32 => items[i] = value,
12 i32 => items[i] = @bitCast(value),
13
14 [16]u8 => {
15 const u32s: [4]u32 = @bitCast(value);
16 items[i] = u32s[0];
17 items[i + 1] = u32s[1];
18 items[i + 2] = u32s[2];
19 items[i + 3] = u32s[3];
20 },
5fn setAsU32(items: []u32, comptime T: type, i: usize, payload: T) void {
6 switch (T) {
7 u32 => items[i] = payload,
8 i32 => items[i] = @bitCast(payload),
9
10 [16]u8 => {
11 const u32s: [4]u32 = @bitCast(payload);
12 items[i] = u32s[0];
13 items[i + 1] = u32s[1];
14 items[i + 2] = u32s[2];
15 items[i + 3] = u32s[3];
16 },
2117
22 else => brk: {
23 const info = @typeInfo(field.type);
24 if (info == .@"enum") {
25 items[i] = @intFromEnum(value);
26 break :brk;
27 }
18 else => brk: {
19 const info = @typeInfo(T);
20 if (info == .@"enum") {
21 items[i] = @intFromEnum(payload);
22 break :brk;
23 }
2824
29 const struct_data = info.@"struct";
30 if (struct_data.layout == .@"packed") {
31 items[i] = @bitCast(value);
32 break :brk;
33 }
25 const struct_data = info.@"struct";
26 if (struct_data.layout == .@"packed") {
27 items[i] = @bitCast(payload);
28 break :brk;
29 }
3430
35 @call(.always_inline, setAsU32, .{ items, field.type, i, value });
36 },
37 }
38 i += extraSizeOf(field.type);
31 const fields = std.meta.fields(@TypeOf(payload));
32 comptime var idx: usize = 0;
33 inline for (fields) |field| {
34 const value = @field(payload, field.name);
35 @call(.always_inline, setAsU32, .{ items, field.type, i + idx, value });
36 idx += comptime extraSizeOf(field.type);
37 }
38 },
3939 }
4040}
4141
......@@ -116,11 +116,14 @@ fn ExtraWrap(comptime kind: StoreKind) type {
116116 return enum(u32) {
117117 _,
118118
119 // Reads the data from `store.extra` and returns it.
120119 pub fn get(index: @This(), owner: anytype) T {
121120 return kind.resolveStoreConst(owner).get(T, @intFromEnum(index));
122121 }
123122
123 pub fn set(index: @This(), owner: anytype, payload: T) void {
124 return kind.resolveStoreMut(owner).set(T, @intFromEnum(index), payload);
125 }
126
124127 /// Returns data with a trailing reader to read data stored immediately after
125128 /// the main data structure. What is stored should be documented on `T`
126129 pub fn getTrail(index: @This(), owner: anytype) struct {
......@@ -196,7 +199,7 @@ pub fn EncodedData(comptime Tag: type, backing_type: type) type {
196199}
197200
198201/// The number of 'u32's this type consumes in `ip.extra`.
199pub fn extraSizeOf(comptime T: type) usize {
202pub inline fn extraSizeOf(comptime T: type) usize {
200203 return switch (T) {
201204 u32,
202205 i32,
src/core/js/Js.zig+1-1
......@@ -32,7 +32,7 @@ pub fn handleFunctionAir(
3232 try ng.build();
3333
3434 const tree = try ng.finalize();
35 try backend.codegen_map.put(comp.gpa, value, tree);
35 try backend.codegen_map.putNoClobber(comp.gpa, value, tree);
3636
3737 return 0;
3838}
src/main.zig+4-1
......@@ -324,7 +324,10 @@ fn cmdBuildOrRun(ctx: Context, comptime mode: enum { build, run }) !void {
324324 try teg.dumpToWriter(stderr, null);
325325 }
326326
327 const entry_point = try comp.enqueueEntryModule(main_file);
327 const entry_point = comp.enqueueEntryModule(main_file) catch |err| switch (err) {
328 error.TransformFail => std.process.exit(1),
329 else => |e| return e,
330 };
328331 comp.runAllJobs() catch |err| switch (err) {
329332 error.AnalysisFail => {
330333 // error is already printed
src/manual/generate-man.zig+1-1
......@@ -310,7 +310,7 @@ fn processMarkdown(
310310 defer prog.end();
311311
312312 var prog_step = prog.start("Compile", 1);
313 var build = std.process.Child.init(&.{ compiler_path, "/dev/stdin" }, gpa);
313 var build = std.process.Child.init(&.{ compiler_path, "build", "/dev/stdin" }, gpa);
314314 build.stdin_behavior = .Pipe;
315315 build.stdout_behavior = .Pipe;
316316 build.stderr_behavior = .Pipe;
test/behavior/arithmetic+2-2
......@@ -16,7 +16,7 @@ fn main {
1616 assertEqual(subInt(528, -43), i(571));
1717}
1818
19fn f(a: float) -> float { a }
19fn f(a: float) { a }
2020
2121fn addFloat(a: float, b: float) -> float {
2222 a + b
......@@ -42,7 +42,7 @@ fn divFloat(a: float, b: float) -> float {
4242// a ** b
4343// }
4444
45fn i(a: int) -> int { a }
45fn i(a: int) { a }
4646
4747fn addInt(a: int, b: int) -> int {
4848 a + b
test/behavior/array+1-1
......@@ -11,4 +11,4 @@ fn main {
1111 assertEqual(array[i(1) + 2] + array[i(2) + 2], i(2));
1212}
1313
14fn i(a: int) -> int { a }
14fn i(a: int) { a }
test/behavior/inferred_return_type created+10
......@@ -0,0 +1,10 @@
1let assertEqual = @extern("assertEqual");
2
3fn getString() {
4 "hello"
5}
6
7fn main {
8 let str = getString();
9 assertEqual(str, "hello");
10}
test/behavior/tuple+1-2
......@@ -1,8 +1,7 @@
11let assertEqual = @extern("assertEqual");
22
33fn hello() -> tuple (int, float) {
4 let x: tuple (int, float) = (5, 2.5);
5 x
4 (5, 2.5)
65}
76
87fn main {