authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-06-02 21:00:16-07:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-06-02 21:00:16-07:00
log10d7c1ff53ea46517327987a11764dd46ec8cb7f
tree6e6404866d079425b9c300892d6367140a97f2a8
parentb081bdf665c0a29b07b59f4c64a9cb85bcfef98a
signature Commit is signed but in an unrecognized format.

fix(sema): handle recursion better

after analyzing return type, we put the decl into a new state, `in_progress_prototype_available`, which means the .value of the decl is now set, and that recursive types can use this function. when inferred return types are added, this logic will have to change, but it is likely this logic is changed regardless to support some form of "decl values with incomplete types", as just the fact of referencing a declaration should not be an error if it is recursive, but only when you call it.

7 files changed, 64 insertions(+), 34 deletions(-)

.gitignore+1
......@@ -8,3 +8,4 @@
88
99.zig-cache
1010zig-out
11*.spall
CHANGELOG.md+6-1
......@@ -1,6 +1,11 @@
1## 0.1.4
2
3- fix(sema): miscompilation using left side of all binary expression for both sides
4- fix(sema): handle recursive function calls
5
16## 0.1.3
27
3- feat(sema): coersion: numeric\_literal -> float
8- feat(sema): coersion: numeric_literal -> float
49- feat(sema): prevent passing non-runtime compatible types like `type` to opaque functions
510- feat(sema): properly validate and coerce binary operations
611- feat(sema): string concat with `+`
build.zig+13-2
......@@ -8,9 +8,18 @@ pub fn build(b: *std.Build) void {
88
99 const native_target = b.resolveTargetQuery(.{});
1010 const target = b.standardTargetOptions(.{});
11 const optimize_fallback = b.standardOptimizeOption(.{});
11
12 // I disagree with how the standard optimize flag works
13 const optimize_fallback = switch (b.release_mode) {
14 .off => b.standardOptimizeOption(.{}),
15 else => b.option(
16 std.builtin.OptimizeMode,
17 "optimize",
18 "Prioritize performance, safety, or binary size",
19 ),
20 };
1221 const optimize: std.builtin.OptimizeMode = switch (b.release_mode) {
13 .off => optimize_fallback,
22 .off => optimize_fallback.?,
1423 .safe => .ReleaseSafe,
1524 .fast => .ReleaseFast,
1625 .small => .ReleaseSmall,
......@@ -28,6 +37,8 @@ pub fn build(b: *std.Build) void {
2837 const native_debug = buildWithTarget(b, native_target, .Debug, .none);
2938 const main = buildWithTarget(b, target, optimize, tracing);
3039
40 b.installArtifact(main.compiler);
41
3142 inline for (.{
3243 .{ main.compiler, "compiler" },
3344 .{ main.lsp, "lsp" },
demo.todo deleted-10
......@@ -1,10 +0,0 @@
1fn something(a: int) -> bool {
2 if a == 0 {
3 return false;
4 }
5
6 a > 100
7}
8
9let print = @js("console").log;
10print(something(0xFF), something(0));
src/core/Comp.zig+5-2
......@@ -214,7 +214,7 @@ pub const File = struct {
214214
215215pub const Decl = struct {
216216 name: InternPool.NullTerminatedString,
217 val: InternPool.Value,
217 val: ?InternPool.Value,
218218 /// The direct parent namespace of the Decl. In the case of the Decl
219219 /// corresponding to a file, this is the namespace of the struct, since
220220 /// there is no parent.
......@@ -242,6 +242,9 @@ pub const Decl = struct {
242242 /// Semantic analysis for this Decl is running right now.
243243 /// This state detects dependency loops.
244244 in_progress,
245 /// Semantic analysis for this Decl is running right now
246 /// But .value is valid
247 in_progress_prototype_available,
245248 /// The file corresponding to this Decl had a parse error or ZIR error.
246249 /// There will be a corresponding ErrorMsg in Zcu.failed_files.
247250 file_failure,
......@@ -348,7 +351,7 @@ pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !N
348351 const tracked_inst = try comp.intern_pool.trackInst(comp.gpa, file, decl_index);
349352 const decl = try comp.intern_pool.createDecl(comp.gpa, .{
350353 .name = name,
351 .val = undefined,
354 .val = null,
352355 .src_namespace = ns,
353356 .teg_decl_index = tracked_inst.toOptional(),
354357 .analysis = .unreferenced,
src/core/Report.zig+12
......@@ -268,6 +268,18 @@ pub const Err = union(enum) {
268268 );
269269 }
270270 },
271 dependency_loop: struct {
272 src: LazyNode,
273
274 fn build(data: @This(), ctx: *MsgContext) !void {
275 const node = try data.src.get(ctx);
276 try ctx.msgNode(
277 node,
278 "type dependency loop (TODO: explain this better, consider using less inferred return types)",
279 .{},
280 );
281 }
282 },
271283};
272284
273285pub const Warn = union(enum) {
src/core/Sema.zig+27-19
......@@ -160,12 +160,29 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value {
160160 fn_decl.return_type,
161161 );
162162
163 const func_prototype = (try s.ip.get(s.gpa, .{
164 .type_function = .{
165 .param_types = s.params,
166 .return_type = return_type,
167 },
168 })).toTypeUnsafe(s.ip);
169 const value = try s.ip.get(s.gpa, .{
170 .func = .{
171 .ty = func_prototype,
172 .owner_decl = s.decl_index,
173 .teg_body_inst = s.decl.teg_decl_index.unwrap().?,
174 },
175 });
176 s.decl.val = value;
177
178 s.decl.analysis = .in_progress_prototype_available;
179
163180 const root_block = fn_decl.body;
164181 switch (root_block.decode()) {
165 .value => |value| {
182 .value => |val| {
166183 const coerced = try s.coerceValue(
167184 s.inst_map.start.op(.operand),
168 value,
185 val,
169186 return_type,
170187 );
171188 const block = try s.addBlock();
......@@ -180,20 +197,6 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value {
180197 },
181198 }
182199
183 const func_prototype = (try s.ip.get(s.gpa, .{
184 .type_function = .{
185 .param_types = s.params,
186 .return_type = return_type,
187 },
188 })).toTypeUnsafe(s.ip);
189 const value = try s.ip.get(s.gpa, .{
190 .func = .{
191 .ty = func_prototype,
192 .owner_decl = s.decl_index,
193 .teg_body_inst = s.decl.teg_decl_index.unwrap().?,
194 },
195 });
196 s.decl.val = value;
197200 return value;
198201}
199202
......@@ -296,7 +299,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
296299 std.debug.print("did not find {s}\n", .{decl_name.toSlice(s.ip)});
297300 return error.AnalysisFail;
298301 };
299 const resolved = try s.resolveDecl(decl_index);
302 const resolved = try s.resolveDecl(in.op(.main_node), decl_index);
300303 return resolved.toAir();
301304 },
302305 .param => {
......@@ -813,7 +816,7 @@ fn ensureValueRuntime(s: *Sema, src: InstOp, ref: Air.Inst.Ref) !Air.Inst.Ref {
813816 return ref;
814817}
815818
816fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value {
819fn resolveDecl(s: *Sema, src: InstOp, decl_index: Decl.Index) Error!Value {
817820 const decl = s.ip.declPtr(decl_index);
818821 switch (decl.analysis) {
819822 .unreferenced => {
......@@ -846,8 +849,13 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value {
846849
847850 return value;
848851 },
852 .in_progress => {
853 return s.fail(.dependency_loop, .{
854 .src = s.lazyNode(src),
855 });
856 },
849857 else => {
850 return decl.val;
858 return decl.val.?;
851859 },
852860 }
853861}