diff --git a/.gitignore b/.gitignore index ae163bea1d23a4d4b8708c5171bdf61396efa7e2..2446d06c444a6b07b3495e1013a0c39c12d819ee 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ .zig-cache zig-out +*.spall diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd8175aba330b45c6fc9a28a89615b87102ad39..7fc10bd6e5508a5477d5bbfa780c74c98600168e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ +## 0.1.4 + +- fix(sema): miscompilation using left side of all binary expression for both sides +- fix(sema): handle recursive function calls + ## 0.1.3 -- feat(sema): coersion: numeric\_literal -> float +- feat(sema): coersion: numeric_literal -> float - feat(sema): prevent passing non-runtime compatible types like `type` to opaque functions - feat(sema): properly validate and coerce binary operations - feat(sema): string concat with `+` diff --git a/build.zig b/build.zig index d6729aaeef876a735eb11a9479a9dbe85e04f4ab..a06d4d03ca4118a959f2e2ab4f4b8eafffa66ed0 100644 --- a/build.zig +++ b/build.zig @@ -8,9 +8,18 @@ pub fn build(b: *std.Build) void { const native_target = b.resolveTargetQuery(.{}); const target = b.standardTargetOptions(.{}); - const optimize_fallback = b.standardOptimizeOption(.{}); + + // I disagree with how the standard optimize flag works + const optimize_fallback = switch (b.release_mode) { + .off => b.standardOptimizeOption(.{}), + else => b.option( + std.builtin.OptimizeMode, + "optimize", + "Prioritize performance, safety, or binary size", + ), + }; const optimize: std.builtin.OptimizeMode = switch (b.release_mode) { - .off => optimize_fallback, + .off => optimize_fallback.?, .safe => .ReleaseSafe, .fast => .ReleaseFast, .small => .ReleaseSmall, @@ -28,6 +37,8 @@ pub fn build(b: *std.Build) void { const native_debug = buildWithTarget(b, native_target, .Debug, .none); const main = buildWithTarget(b, target, optimize, tracing); + b.installArtifact(main.compiler); + inline for (.{ .{ main.compiler, "compiler" }, .{ main.lsp, "lsp" }, diff --git a/demo.todo b/demo.todo deleted file mode 100644 index 0a2e8fb7b365173c38ff8aa3b1263685f9b2dc96..0000000000000000000000000000000000000000 --- a/demo.todo +++ /dev/null @@ -1,10 +0,0 @@ -fn something(a: int) -> bool { - if a == 0 { - return false; - } - - a > 100 -} - -let print = @js("console").log; -print(something(0xFF), something(0)); diff --git a/src/core/Comp.zig b/src/core/Comp.zig index 9c9791273104a5940a38ae8a40328ba6785112a9..7a5a6be493cacaeb571011bdf35ccaa30c888e89 100644 --- a/src/core/Comp.zig +++ b/src/core/Comp.zig @@ -214,7 +214,7 @@ pub const File = struct { pub const Decl = struct { name: InternPool.NullTerminatedString, - val: InternPool.Value, + val: ?InternPool.Value, /// The direct parent namespace of the Decl. In the case of the Decl /// corresponding to a file, this is the namespace of the struct, since /// there is no parent. @@ -242,6 +242,9 @@ pub const Decl = struct { /// Semantic analysis for this Decl is running right now. /// This state detects dependency loops. in_progress, + /// Semantic analysis for this Decl is running right now + /// But .value is valid + in_progress_prototype_available, /// The file corresponding to this Decl had a parse error or ZIR error. /// There will be a corresponding ErrorMsg in Zcu.failed_files. file_failure, @@ -348,7 +351,7 @@ pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !N const tracked_inst = try comp.intern_pool.trackInst(comp.gpa, file, decl_index); const decl = try comp.intern_pool.createDecl(comp.gpa, .{ .name = name, - .val = undefined, + .val = null, .src_namespace = ns, .teg_decl_index = tracked_inst.toOptional(), .analysis = .unreferenced, diff --git a/src/core/Report.zig b/src/core/Report.zig index 5cfc4ec59718f2026b2d50a6c3253961e378b679..19f9e105bf58485f40406c4cd14314061a55f8d4 100644 --- a/src/core/Report.zig +++ b/src/core/Report.zig @@ -268,6 +268,18 @@ pub const Err = union(enum) { ); } }, + dependency_loop: struct { + src: LazyNode, + + fn build(data: @This(), ctx: *MsgContext) !void { + const node = try data.src.get(ctx); + try ctx.msgNode( + node, + "type dependency loop (TODO: explain this better, consider using less inferred return types)", + .{}, + ); + } + }, }; pub const Warn = union(enum) { diff --git a/src/core/Sema.zig b/src/core/Sema.zig index dbcef0664f2fbc093f9f44754ecc12b88edcd1e3..6c610b1b64933c06c2dc99cf8aa7aa12e0f3f3e8 100644 --- a/src/core/Sema.zig +++ b/src/core/Sema.zig @@ -160,12 +160,29 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value { fn_decl.return_type, ); + const func_prototype = (try s.ip.get(s.gpa, .{ + .type_function = .{ + .param_types = s.params, + .return_type = return_type, + }, + })).toTypeUnsafe(s.ip); + const value = try s.ip.get(s.gpa, .{ + .func = .{ + .ty = func_prototype, + .owner_decl = s.decl_index, + .teg_body_inst = s.decl.teg_decl_index.unwrap().?, + }, + }); + s.decl.val = value; + + s.decl.analysis = .in_progress_prototype_available; + const root_block = fn_decl.body; switch (root_block.decode()) { - .value => |value| { + .value => |val| { const coerced = try s.coerceValue( s.inst_map.start.op(.operand), - value, + val, return_type, ); const block = try s.addBlock(); @@ -180,20 +197,6 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value { }, } - const func_prototype = (try s.ip.get(s.gpa, .{ - .type_function = .{ - .param_types = s.params, - .return_type = return_type, - }, - })).toTypeUnsafe(s.ip); - const value = try s.ip.get(s.gpa, .{ - .func = .{ - .ty = func_prototype, - .owner_decl = s.decl_index, - .teg_body_inst = s.decl.teg_decl_index.unwrap().?, - }, - }); - s.decl.val = value; return value; } @@ -296,7 +299,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { std.debug.print("did not find {s}\n", .{decl_name.toSlice(s.ip)}); return error.AnalysisFail; }; - const resolved = try s.resolveDecl(decl_index); + const resolved = try s.resolveDecl(in.op(.main_node), decl_index); return resolved.toAir(); }, .param => { @@ -813,7 +816,7 @@ fn ensureValueRuntime(s: *Sema, src: InstOp, ref: Air.Inst.Ref) !Air.Inst.Ref { return ref; } -fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value { +fn resolveDecl(s: *Sema, src: InstOp, decl_index: Decl.Index) Error!Value { const decl = s.ip.declPtr(decl_index); switch (decl.analysis) { .unreferenced => { @@ -846,8 +849,13 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value { return value; }, + .in_progress => { + return s.fail(.dependency_loop, .{ + .src = s.lazyNode(src), + }); + }, else => { - return decl.val; + return decl.val.?; }, } }