| ... | @@ -141,7 +141,8 @@ const Analyze = struct { | ... | @@ -141,7 +141,8 @@ const Analyze = struct { |
| 141 | }; | 141 | }; |
| 142 | | 142 | |
| 143 | const NewInst = struct { | 143 | const NewInst = struct { |
| 144 | ptr: *Inst, | 144 | /// null means a semantic analysis error happened |
| | 145 | ptr: ?*Inst, |
| 145 | }; | 146 | }; |
| 146 | | 147 | |
| 147 | const Fn = struct { | 148 | const Fn = struct { |
| ... | @@ -163,9 +164,12 @@ const Analyze = struct { | ... | @@ -163,9 +164,12 @@ const Analyze = struct { |
| 163 | | 164 | |
| 164 | fn resolveInst(self: *Analyze, opt_func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst { | 165 | fn resolveInst(self: *Analyze, opt_func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst { |
| 165 | if (opt_func) |func| { | 166 | if (opt_func) |func| { |
| 166 | const kv = func.inst_table.get(old_inst) orelse return error.AnalysisFail; | 167 | if (func.inst_table.get(old_inst)) |kv| { |
| 167 | return kv.value.ptr; | 168 | return kv.value.ptr orelse return error.AnalysisFail; |
| 168 | } else if (self.decl_table.get(old_inst)) |kv| { | 169 | } |
| | 170 | } |
| | 171 | |
| | 172 | if (self.decl_table.get(old_inst)) |kv| { |
| 169 | return kv.value.ptr orelse return error.AnalysisFail; | 173 | return kv.value.ptr orelse return error.AnalysisFail; |
| 170 | } else { | 174 | } else { |
| 171 | const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) { | 175 | const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) { |
| ... | @@ -275,7 +279,7 @@ const Analyze = struct { | ... | @@ -275,7 +279,7 @@ const Analyze = struct { |
| 275 | .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 279 | .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 276 | .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 280 | .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 277 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 281 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 278 | .as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 282 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| 279 | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 283 | .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 280 | .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 284 | .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 281 | .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?), | 285 | .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?), |
| ... | @@ -305,6 +309,7 @@ const Analyze = struct { | ... | @@ -305,6 +309,7 @@ const Analyze = struct { |
| 305 | for (fn_inst.positionals.body.instructions) |src_inst| { | 309 | for (fn_inst.positionals.body.instructions) |src_inst| { |
| 306 | const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| { | 310 | const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| { |
| 307 | self.fns.items[new_func.fn_index].analysis_status = .failure; | 311 | self.fns.items[new_func.fn_index].analysis_status = .failure; |
| | 312 | try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = null }); |
| 308 | return err; | 313 | return err; |
| 309 | }; | 314 | }; |
| 310 | try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst }); | 315 | try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst }); |
| ... | @@ -324,8 +329,8 @@ const Analyze = struct { | ... | @@ -324,8 +329,8 @@ const Analyze = struct { |
| 324 | }); | 329 | }); |
| 325 | } | 330 | } |
| 326 | | 331 | |
| 327 | fn analyzeInstFnType(self: *Analyze, opt_func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst { | 332 | fn analyzeInstFnType(self: *Analyze, func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst { |
| 328 | const return_type = try self.resolveType(opt_func, fntype.positionals.return_type); | 333 | const return_type = try self.resolveType(func, fntype.positionals.return_type); |
| 329 | | 334 | |
| 330 | if (return_type.zigTypeTag() == .NoReturn and | 335 | if (return_type.zigTypeTag() == .NoReturn and |
| 331 | fntype.positionals.param_types.len == 0 and | 336 | fntype.positionals.param_types.len == 0 and |
| ... | @@ -337,10 +342,16 @@ const Analyze = struct { | ... | @@ -337,10 +342,16 @@ const Analyze = struct { |
| 337 | return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{}); | 342 | return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{}); |
| 338 | } | 343 | } |
| 339 | | 344 | |
| 340 | fn analyzeInstPrimitive(self: *Analyze, opt_func: ?*Fn, primitive: *text.Inst.Primitive) InnerError!*Inst { | 345 | fn analyzeInstPrimitive(self: *Analyze, func: ?*Fn, primitive: *text.Inst.Primitive) InnerError!*Inst { |
| 341 | return self.constType(primitive.base.src, primitive.positionals.tag.toType()); | 346 | return self.constType(primitive.base.src, primitive.positionals.tag.toType()); |
| 342 | } | 347 | } |
| 343 | | 348 | |
| | 349 | fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst { |
| | 350 | const dest_type = try self.resolveType(func, as.positionals.dest_type); |
| | 351 | const new_inst = try self.resolveInst(func, as.positionals.value); |
| | 352 | return self.coerce(dest_type, new_inst); |
| | 353 | } |
| | 354 | |
| 344 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 355 | fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| 345 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); | 356 | const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); |
| 346 | if (in_memory_result == .ok) { | 357 | if (in_memory_result == .ok) { |
| ... | @@ -363,7 +374,11 @@ const Analyze = struct { | ... | @@ -363,7 +374,11 @@ const Analyze = struct { |
| 363 | } | 374 | } |
| 364 | | 375 | |
| 365 | fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 376 | fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |
| 366 | return self.fail(inst.src, "TODO implement bitcast analysis", .{}); | 377 | if (inst.value()) |val| { |
| | 378 | // Keep the comptime Value representation; take the new type. |
| | 379 | return self.constInst(inst.src, .{ .ty = dest_type, .val = val }); |
| | 380 | } |
| | 381 | return self.fail(inst.src, "TODO implement runtime bitcast", .{}); |
| 367 | } | 382 | } |
| 368 | | 383 | |
| 369 | fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { | 384 | fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { |