| author | |
| committer | |
| log | 10d7c1ff53ea46517327987a11764dd46ec8cb7f |
| tree | 6e6404866d079425b9c300892d6367140a97f2a8 |
| parent | b081bdf665c0a29b07b59f4c64a9cb85bcfef98a |
| signature | Commit is signed but in an unrecognized format. |
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 @@ |
| 8 | 8 | |
| 9 | 9 | .zig-cache |
| 10 | 10 | zig-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 | ||
| 1 | 6 | ## 0.1.3 |
| 2 | 7 | |
| 3 | - feat(sema): coersion: numeric\_literal -> float | |
| 8 | - feat(sema): coersion: numeric_literal -> float | |
| 4 | 9 | - feat(sema): prevent passing non-runtime compatible types like `type` to opaque functions |
| 5 | 10 | - feat(sema): properly validate and coerce binary operations |
| 6 | 11 | - feat(sema): string concat with `+` |
build.zig+13-2| ... | ... | @@ -8,9 +8,18 @@ pub fn build(b: *std.Build) void { |
| 8 | 8 | |
| 9 | 9 | const native_target = b.resolveTargetQuery(.{}); |
| 10 | 10 | 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 | }; | |
| 12 | 21 | const optimize: std.builtin.OptimizeMode = switch (b.release_mode) { |
| 13 | .off => optimize_fallback, | |
| 22 | .off => optimize_fallback.?, | |
| 14 | 23 | .safe => .ReleaseSafe, |
| 15 | 24 | .fast => .ReleaseFast, |
| 16 | 25 | .small => .ReleaseSmall, |
| ... | ... | @@ -28,6 +37,8 @@ pub fn build(b: *std.Build) void { |
| 28 | 37 | const native_debug = buildWithTarget(b, native_target, .Debug, .none); |
| 29 | 38 | const main = buildWithTarget(b, target, optimize, tracing); |
| 30 | 39 | |
| 40 | b.installArtifact(main.compiler); | |
| 41 | ||
| 31 | 42 | inline for (.{ |
| 32 | 43 | .{ main.compiler, "compiler" }, |
| 33 | 44 | .{ main.lsp, "lsp" }, |
demo.todo deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | fn something(a: int) -> bool { | |
| 2 | if a == 0 { | |
| 3 | return false; | |
| 4 | } | |
| 5 | ||
| 6 | a > 100 | |
| 7 | } | |
| 8 | ||
| 9 | let print = @js("console").log; | |
| 10 | print(something(0xFF), something(0)); |
src/core/Comp.zig+5-2| ... | ... | @@ -214,7 +214,7 @@ pub const File = struct { |
| 214 | 214 | |
| 215 | 215 | pub const Decl = struct { |
| 216 | 216 | name: InternPool.NullTerminatedString, |
| 217 | val: InternPool.Value, | |
| 217 | val: ?InternPool.Value, | |
| 218 | 218 | /// The direct parent namespace of the Decl. In the case of the Decl |
| 219 | 219 | /// corresponding to a file, this is the namespace of the struct, since |
| 220 | 220 | /// there is no parent. |
| ... | ... | @@ -242,6 +242,9 @@ pub const Decl = struct { |
| 242 | 242 | /// Semantic analysis for this Decl is running right now. |
| 243 | 243 | /// This state detects dependency loops. |
| 244 | 244 | in_progress, |
| 245 | /// Semantic analysis for this Decl is running right now | |
| 246 | /// But .value is valid | |
| 247 | in_progress_prototype_available, | |
| 245 | 248 | /// The file corresponding to this Decl had a parse error or ZIR error. |
| 246 | 249 | /// There will be a corresponding ErrorMsg in Zcu.failed_files. |
| 247 | 250 | file_failure, |
| ... | ... | @@ -348,7 +351,7 @@ pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !N |
| 348 | 351 | const tracked_inst = try comp.intern_pool.trackInst(comp.gpa, file, decl_index); |
| 349 | 352 | const decl = try comp.intern_pool.createDecl(comp.gpa, .{ |
| 350 | 353 | .name = name, |
| 351 | .val = undefined, | |
| 354 | .val = null, | |
| 352 | 355 | .src_namespace = ns, |
| 353 | 356 | .teg_decl_index = tracked_inst.toOptional(), |
| 354 | 357 | .analysis = .unreferenced, |
src/core/Report.zig+12| ... | ... | @@ -268,6 +268,18 @@ pub const Err = union(enum) { |
| 268 | 268 | ); |
| 269 | 269 | } |
| 270 | 270 | }, |
| 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 | }, | |
| 271 | 283 | }; |
| 272 | 284 | |
| 273 | 285 | pub const Warn = union(enum) { |
src/core/Sema.zig+27-19| ... | ... | @@ -160,12 +160,29 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value { |
| 160 | 160 | fn_decl.return_type, |
| 161 | 161 | ); |
| 162 | 162 | |
| 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 | ||
| 163 | 180 | const root_block = fn_decl.body; |
| 164 | 181 | switch (root_block.decode()) { |
| 165 | .value => |value| { | |
| 182 | .value => |val| { | |
| 166 | 183 | const coerced = try s.coerceValue( |
| 167 | 184 | s.inst_map.start.op(.operand), |
| 168 | value, | |
| 185 | val, | |
| 169 | 186 | return_type, |
| 170 | 187 | ); |
| 171 | 188 | const block = try s.addBlock(); |
| ... | ... | @@ -180,20 +197,6 @@ pub fn analyzeDeclaration(s: *Sema) Error!Value { |
| 180 | 197 | }, |
| 181 | 198 | } |
| 182 | 199 | |
| 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; | |
| 197 | 200 | return value; |
| 198 | 201 | } |
| 199 | 202 | |
| ... | ... | @@ -296,7 +299,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 296 | 299 | std.debug.print("did not find {s}\n", .{decl_name.toSlice(s.ip)}); |
| 297 | 300 | return error.AnalysisFail; |
| 298 | 301 | }; |
| 299 | const resolved = try s.resolveDecl(decl_index); | |
| 302 | const resolved = try s.resolveDecl(in.op(.main_node), decl_index); | |
| 300 | 303 | return resolved.toAir(); |
| 301 | 304 | }, |
| 302 | 305 | .param => { |
| ... | ... | @@ -813,7 +816,7 @@ fn ensureValueRuntime(s: *Sema, src: InstOp, ref: Air.Inst.Ref) !Air.Inst.Ref { |
| 813 | 816 | return ref; |
| 814 | 817 | } |
| 815 | 818 | |
| 816 | fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value { | |
| 819 | fn resolveDecl(s: *Sema, src: InstOp, decl_index: Decl.Index) Error!Value { | |
| 817 | 820 | const decl = s.ip.declPtr(decl_index); |
| 818 | 821 | switch (decl.analysis) { |
| 819 | 822 | .unreferenced => { |
| ... | ... | @@ -846,8 +849,13 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value { |
| 846 | 849 | |
| 847 | 850 | return value; |
| 848 | 851 | }, |
| 852 | .in_progress => { | |
| 853 | return s.fail(.dependency_loop, .{ | |
| 854 | .src = s.lazyNode(src), | |
| 855 | }); | |
| 856 | }, | |
| 849 | 857 | else => { |
| 850 | return decl.val; | |
| 858 | return decl.val.?; | |
| 851 | 859 | }, |
| 852 | 860 | } |
| 853 | 861 | } |