| author | |
| committer | |
| log | 717b0e827511b55375de82258f570709c07cc59d |
| tree | e546a29c60ebb9ada0188f76e1696077007e73d0 |
| parent | 26140678a5c72604f2baac3cb9d1e5f7b37b6b8d |
This gives zir_sema analysis the ability to check if the current scope
is expected to be comptime.6 files changed, 162 insertions(+), 25 deletions(-)
src-self-hosted/Module.zig+8-3| ... | ... | @@ -725,6 +725,7 @@ pub const Scope = struct { |
| 725 | 725 | /// Points to the arena allocator of DeclAnalysis |
| 726 | 726 | arena: *Allocator, |
| 727 | 727 | label: ?Label = null, |
| 728 | is_comptime: bool, | |
| 728 | 729 | |
| 729 | 730 | pub const Label = struct { |
| 730 | 731 | zir_block: *zir.Inst.Block, |
| ... | ... | @@ -1320,6 +1321,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1320 | 1321 | .decl = decl, |
| 1321 | 1322 | .instructions = .{}, |
| 1322 | 1323 | .arena = &decl_arena.allocator, |
| 1324 | .is_comptime = false, | |
| 1323 | 1325 | }; |
| 1324 | 1326 | defer block_scope.instructions.deinit(self.gpa); |
| 1325 | 1327 | |
| ... | ... | @@ -1457,6 +1459,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1457 | 1459 | .decl = decl, |
| 1458 | 1460 | .instructions = .{}, |
| 1459 | 1461 | .arena = &decl_arena.allocator, |
| 1462 | .is_comptime = true, | |
| 1460 | 1463 | }; |
| 1461 | 1464 | defer block_scope.instructions.deinit(self.gpa); |
| 1462 | 1465 | |
| ... | ... | @@ -1528,7 +1531,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1528 | 1531 | defer gen_scope.instructions.deinit(self.gpa); |
| 1529 | 1532 | const src = tree.token_locs[init_node.firstToken()].start; |
| 1530 | 1533 | |
| 1531 | // TODO comptime scope here | |
| 1532 | 1534 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); |
| 1533 | 1535 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); |
| 1534 | 1536 | |
| ... | ... | @@ -1538,6 +1540,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1538 | 1540 | .decl = decl, |
| 1539 | 1541 | .instructions = .{}, |
| 1540 | 1542 | .arena = &gen_scope_arena.allocator, |
| 1543 | .is_comptime = true, | |
| 1541 | 1544 | }; |
| 1542 | 1545 | defer inner_block.instructions.deinit(self.gpa); |
| 1543 | 1546 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); |
| ... | ... | @@ -1628,8 +1631,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1628 | 1631 | }; |
| 1629 | 1632 | defer gen_scope.instructions.deinit(self.gpa); |
| 1630 | 1633 | |
| 1631 | // TODO comptime scope here | |
| 1632 | _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); | |
| 1634 | _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr); | |
| 1633 | 1635 | |
| 1634 | 1636 | var block_scope: Scope.Block = .{ |
| 1635 | 1637 | .parent = null, |
| ... | ... | @@ -1637,6 +1639,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1637 | 1639 | .decl = decl, |
| 1638 | 1640 | .instructions = .{}, |
| 1639 | 1641 | .arena = &analysis_arena.allocator, |
| 1642 | .is_comptime = true, | |
| 1640 | 1643 | }; |
| 1641 | 1644 | defer block_scope.instructions.deinit(self.gpa); |
| 1642 | 1645 | |
| ... | ... | @@ -2007,6 +2010,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 2007 | 2010 | .decl = decl, |
| 2008 | 2011 | .instructions = .{}, |
| 2009 | 2012 | .arena = &arena.allocator, |
| 2013 | .is_comptime = false, | |
| 2010 | 2014 | }; |
| 2011 | 2015 | defer inner_block.instructions.deinit(self.gpa); |
| 2012 | 2016 | |
| ... | ... | @@ -3432,6 +3436,7 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3432 | 3436 | .decl = parent_block.decl, |
| 3433 | 3437 | .instructions = .{}, |
| 3434 | 3438 | .arena = parent_block.arena, |
| 3439 | .is_comptime = parent_block.is_comptime, | |
| 3435 | 3440 | }; |
| 3436 | 3441 | defer fail_block.instructions.deinit(mod.gpa); |
| 3437 | 3442 |
src-self-hosted/astgen.zig+73-16| ... | ... | @@ -258,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 258 | 258 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), |
| 259 | 259 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), |
| 260 | 260 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), |
| 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?), | |
| 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), | |
| 262 | 262 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| 263 | 263 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 264 | 264 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), |
| ... | ... | @@ -276,6 +276,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 276 | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 278 | 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 279 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), | |
| 279 | 280 | |
| 280 | 281 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 281 | 282 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| ... | ... | @@ -294,11 +295,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 294 | 295 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 295 | 296 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 296 | 297 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 297 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), | |
| 298 | 298 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| 299 | 299 | } |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { | |
| 303 | const tracy = trace(@src()); | |
| 304 | defer tracy.end(); | |
| 305 | ||
| 306 | return comptimeExpr(mod, scope, rl, node.expr); | |
| 307 | } | |
| 308 | ||
| 309 | pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | |
| 310 | const tree = parent_scope.tree(); | |
| 311 | const src = tree.token_locs[node.firstToken()].start; | |
| 312 | ||
| 313 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. | |
| 314 | if (node.castTag(.LabeledBlock)) |block_node| { | |
| 315 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); | |
| 316 | } | |
| 317 | ||
| 318 | // Make a scope to collect generated instructions in the sub-expression. | |
| 319 | var block_scope: Scope.GenZIR = .{ | |
| 320 | .parent = parent_scope, | |
| 321 | .decl = parent_scope.decl().?, | |
| 322 | .arena = parent_scope.arena(), | |
| 323 | .instructions = .{}, | |
| 324 | }; | |
| 325 | defer block_scope.instructions.deinit(mod.gpa); | |
| 326 | ||
| 327 | // No need to capture the result here because block_comptime_flat implies that the final | |
| 328 | // instruction is the block's result value. | |
| 329 | _ = try expr(mod, &block_scope.base, rl, node); | |
| 330 | ||
| 331 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ | |
| 332 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | |
| 333 | }); | |
| 334 | ||
| 335 | return &block.base; | |
| 336 | } | |
| 337 | ||
| 302 | 338 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 303 | 339 | const tree = parent_scope.tree(); |
| 304 | 340 | const src = tree.token_locs[node.ltoken].start; |
| ... | ... | @@ -360,10 +396,13 @@ fn labeledBlockExpr( |
| 360 | 396 | parent_scope: *Scope, |
| 361 | 397 | rl: ResultLoc, |
| 362 | 398 | block_node: *ast.Node.LabeledBlock, |
| 399 | zir_tag: zir.Inst.Tag, | |
| 363 | 400 | ) InnerError!*zir.Inst { |
| 364 | 401 | const tracy = trace(@src()); |
| 365 | 402 | defer tracy.end(); |
| 366 | 403 | |
| 404 | assert(zir_tag == .block or zir_tag == .block_comptime); | |
| 405 | ||
| 367 | 406 | const tree = parent_scope.tree(); |
| 368 | 407 | const src = tree.token_locs[block_node.lbrace].start; |
| 369 | 408 | |
| ... | ... | @@ -373,7 +412,7 @@ fn labeledBlockExpr( |
| 373 | 412 | const block_inst = try gen_zir.arena.create(zir.Inst.Block); |
| 374 | 413 | block_inst.* = .{ |
| 375 | 414 | .base = .{ |
| 376 | .tag = .block, | |
| 415 | .tag = zir_tag, | |
| 377 | 416 | .src = src, |
| 378 | 417 | }, |
| 379 | 418 | .positionals = .{ |
| ... | ... | @@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 773 | 812 | .else_body = undefined, // populated below |
| 774 | 813 | }, .{}); |
| 775 | 814 | |
| 776 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 815 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | |
| 777 | 816 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 778 | 817 | }); |
| 779 | 818 | |
| ... | ... | @@ -946,7 +985,7 @@ fn boolBinOp( |
| 946 | 985 | .else_body = undefined, // populated below |
| 947 | 986 | }, .{}); |
| 948 | 987 | |
| 949 | const block = try addZIRInstBlock(mod, scope, src, .{ | |
| 988 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ | |
| 950 | 989 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 951 | 990 | }); |
| 952 | 991 | |
| ... | ... | @@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1095 | 1134 | .else_body = undefined, // populated below |
| 1096 | 1135 | }, .{}); |
| 1097 | 1136 | |
| 1098 | const block = try addZIRInstBlock(mod, scope, if_src, .{ | |
| 1137 | const block = try addZIRInstBlock(mod, scope, if_src, .block, .{ | |
| 1099 | 1138 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1100 | 1139 | }); |
| 1101 | 1140 | |
| ... | ... | @@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1218 | 1257 | .then_body = undefined, // populated below |
| 1219 | 1258 | .else_body = undefined, // populated below |
| 1220 | 1259 | }, .{}); |
| 1221 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ | |
| 1260 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ | |
| 1222 | 1261 | .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), |
| 1223 | 1262 | }); |
| 1224 | 1263 | // TODO avoid emitting the continue expr when there |
| ... | ... | @@ -1231,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1231 | 1270 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ |
| 1232 | 1271 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1233 | 1272 | }); |
| 1234 | const while_block = try addZIRInstBlock(mod, scope, while_src, .{ | |
| 1273 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ | |
| 1235 | 1274 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), |
| 1236 | 1275 | }); |
| 1237 | 1276 | |
| ... | ... | @@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1365 | 1404 | .then_body = undefined, // populated below |
| 1366 | 1405 | .else_body = undefined, // populated below |
| 1367 | 1406 | }, .{}); |
| 1368 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ | |
| 1407 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{ | |
| 1369 | 1408 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), |
| 1370 | 1409 | }); |
| 1371 | 1410 | |
| ... | ... | @@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1382 | 1421 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ |
| 1383 | 1422 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1384 | 1423 | }); |
| 1385 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ | |
| 1424 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ | |
| 1386 | 1425 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), |
| 1387 | 1426 | }); |
| 1388 | 1427 | |
| ... | ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( |
| 2260 | 2299 | return &inst.base; |
| 2261 | 2300 | } |
| 2262 | 2301 | |
| 2302 | pub fn addZIRInstBlock( | |
| 2303 | mod: *Module, | |
| 2304 | scope: *Scope, | |
| 2305 | src: usize, | |
| 2306 | tag: zir.Inst.Tag, | |
| 2307 | body: zir.Module.Body, | |
| 2308 | ) !*zir.Inst.Block { | |
| 2309 | const gen_zir = scope.getGenZIR(); | |
| 2310 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); | |
| 2311 | const inst = try gen_zir.arena.create(zir.Inst.Block); | |
| 2312 | inst.* = .{ | |
| 2313 | .base = .{ | |
| 2314 | .tag = tag, | |
| 2315 | .src = src, | |
| 2316 | }, | |
| 2317 | .positionals = .{ | |
| 2318 | .body = body, | |
| 2319 | }, | |
| 2320 | .kw_args = .{}, | |
| 2321 | }; | |
| 2322 | gen_zir.instructions.appendAssumeCapacity(&inst.base); | |
| 2323 | return inst; | |
| 2324 | } | |
| 2325 | ||
| 2263 | 2326 | pub fn addZIRInst( |
| 2264 | 2327 | mod: *Module, |
| 2265 | 2328 | scope: *Scope, |
| ... | ... | @@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ |
| 2278 | 2341 | return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); |
| 2279 | 2342 | } |
| 2280 | 2343 | |
| 2281 | /// TODO The existence of this function is a workaround for a bug in stage1. | |
| 2282 | pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { | |
| 2283 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; | |
| 2284 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); | |
| 2285 | } | |
| 2286 | ||
| 2287 | 2344 | /// TODO The existence of this function is a workaround for a bug in stage1. |
| 2288 | 2345 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { |
| 2289 | 2346 | const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type; |
src-self-hosted/ir.zig+9-1| ... | ... | @@ -189,7 +189,7 @@ pub const Inst = struct { |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 191 | pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator { |
| 192 | return switch (self.base.tag) { | |
| 192 | return switch (base.tag) { | |
| 193 | 193 | .cmp_lt => .lt, |
| 194 | 194 | .cmp_lte => .lte, |
| 195 | 195 | .cmp_eq => .eq, |
| ... | ... | @@ -220,6 +220,14 @@ pub const Inst = struct { |
| 220 | 220 | unreachable; |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | pub fn breakBlock(base: *Inst) ?*Block { | |
| 224 | return switch (base.tag) { | |
| 225 | .br => base.castTag(.br).?.block, | |
| 226 | .brvoid => base.castTag(.brvoid).?.block, | |
| 227 | else => null, | |
| 228 | }; | |
| 229 | } | |
| 230 | ||
| 223 | 231 | pub const NoOp = struct { |
| 224 | 232 | base: Inst, |
| 225 | 233 |
src-self-hosted/zir.zig+16-1| ... | ... | @@ -78,6 +78,13 @@ pub const Inst = struct { |
| 78 | 78 | bitor, |
| 79 | 79 | /// A labeled block of code, which can return a value. |
| 80 | 80 | block, |
| 81 | /// A block of code, which can return a value. There are no instructions that break out of | |
| 82 | /// this block; it is implied that the final instruction is the result. | |
| 83 | block_flat, | |
| 84 | /// Same as `block` but additionally makes the inner instructions execute at comptime. | |
| 85 | block_comptime, | |
| 86 | /// Same as `block_flat` but additionally makes the inner instructions execute at comptime. | |
| 87 | block_comptime_flat, | |
| 81 | 88 | /// Boolean NOT. See also `bitnot`. |
| 82 | 89 | boolnot, |
| 83 | 90 | /// Return a value from a `Block`. |
| ... | ... | @@ -338,9 +345,14 @@ pub const Inst = struct { |
| 338 | 345 | .merge_error_sets, |
| 339 | 346 | => BinOp, |
| 340 | 347 | |
| 348 | .block, | |
| 349 | .block_flat, | |
| 350 | .block_comptime, | |
| 351 | .block_comptime_flat, | |
| 352 | => Block, | |
| 353 | ||
| 341 | 354 | .arg => Arg, |
| 342 | 355 | .array_type_sentinel => ArrayTypeSentinel, |
| 343 | .block => Block, | |
| 344 | 356 | .@"break" => Break, |
| 345 | 357 | .breakvoid => BreakVoid, |
| 346 | 358 | .call => Call, |
| ... | ... | @@ -392,6 +404,9 @@ pub const Inst = struct { |
| 392 | 404 | .bitcast_result_ptr, |
| 393 | 405 | .bitor, |
| 394 | 406 | .block, |
| 407 | .block_flat, | |
| 408 | .block_comptime, | |
| 409 | .block_comptime_flat, | |
| 395 | 410 | .boolnot, |
| 396 | 411 | .breakpoint, |
| 397 | 412 | .call, |
src-self-hosted/zir_sema.zig+55-3| ... | ... | @@ -31,7 +31,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 31 | 31 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 32 | 32 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 33 | 33 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?), | |
| 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), | |
| 35 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), | |
| 36 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), | |
| 37 | .block_comptime_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true), | |
| 35 | 38 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 36 | 39 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 37 | 40 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), |
| ... | ... | @@ -147,6 +150,7 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { |
| 147 | 150 | } |
| 148 | 151 | } |
| 149 | 152 | |
| 153 | /// TODO improve this to use .block_comptime_flat | |
| 150 | 154 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { |
| 151 | 155 | try analyzeBody(mod, &block_scope.base, body); |
| 152 | 156 | for (block_scope.instructions.items) |inst| { |
| ... | ... | @@ -517,6 +521,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 517 | 521 | .decl = parent_block.decl, |
| 518 | 522 | .instructions = .{}, |
| 519 | 523 | .arena = parent_block.arena, |
| 524 | .is_comptime = parent_block.is_comptime, | |
| 520 | 525 | }; |
| 521 | 526 | defer child_block.instructions.deinit(mod.gpa); |
| 522 | 527 | |
| ... | ... | @@ -529,7 +534,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 529 | 534 | return &loop_inst.base; |
| 530 | 535 | } |
| 531 | 536 | |
| 532 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | |
| 537 | fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | |
| 538 | const parent_block = scope.cast(Scope.Block).?; | |
| 539 | ||
| 540 | var child_block: Scope.Block = .{ | |
| 541 | .parent = parent_block, | |
| 542 | .func = parent_block.func, | |
| 543 | .decl = parent_block.decl, | |
| 544 | .instructions = .{}, | |
| 545 | .arena = parent_block.arena, | |
| 546 | .label = null, | |
| 547 | .is_comptime = parent_block.is_comptime or is_comptime, | |
| 548 | }; | |
| 549 | defer child_block.instructions.deinit(mod.gpa); | |
| 550 | ||
| 551 | try analyzeBody(mod, &child_block.base, inst.positionals.body); | |
| 552 | ||
| 553 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | |
| 554 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 555 | ||
| 556 | return copied_instructions[copied_instructions.len - 1]; | |
| 557 | } | |
| 558 | ||
| 559 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | |
| 533 | 560 | const parent_block = scope.cast(Scope.Block).?; |
| 534 | 561 | |
| 535 | 562 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | ... | @@ -557,6 +584,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 557 | 584 | .results = .{}, |
| 558 | 585 | .block_inst = block_inst, |
| 559 | 586 | }), |
| 587 | .is_comptime = is_comptime or parent_block.is_comptime, | |
| 560 | 588 | }; |
| 561 | 589 | const label = &child_block.label.?; |
| 562 | 590 | |
| ... | ... | @@ -569,6 +597,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 569 | 597 | assert(child_block.instructions.items.len != 0); |
| 570 | 598 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn()); |
| 571 | 599 | |
| 600 | if (label.results.items.len == 0) { | |
| 601 | // No need for a block instruction. We can put the new instructions directly into the parent block. | |
| 602 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | |
| 603 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 604 | return copied_instructions[copied_instructions.len - 1]; | |
| 605 | } | |
| 606 | if (label.results.items.len == 1) { | |
| 607 | const last_inst_index = child_block.instructions.items.len - 1; | |
| 608 | const last_inst = child_block.instructions.items[last_inst_index]; | |
| 609 | if (last_inst.breakBlock()) |br_block| { | |
| 610 | if (br_block == block_inst) { | |
| 611 | // No need for a block instruction. We can put the new instructions directly into the parent block. | |
| 612 | // Here we omit the break instruction. | |
| 613 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); | |
| 614 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | |
| 615 | return label.results.items[0]; | |
| 616 | } | |
| 617 | } | |
| 618 | } | |
| 619 | // It should be impossible to have the number of results be > 1 in a comptime scope. | |
| 620 | assert(!child_block.is_comptime); // We should have already got a compile error in the condbr condition. | |
| 621 | ||
| 572 | 622 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 573 | 623 | // to emit a jump instruction to after the block when it encounters the break. |
| 574 | 624 | try parent_block.instructions.append(mod.gpa, &block_inst.base); |
| ... | ... | @@ -1083,7 +1133,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1083 | 1133 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); |
| 1084 | 1134 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); |
| 1085 | 1135 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); |
| 1086 | ||
| 1136 | ||
| 1087 | 1137 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { |
| 1088 | 1138 | .Pointer => array_ptr.ty.elemType(), |
| 1089 | 1139 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), |
| ... | ... | @@ -1376,6 +1426,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1376 | 1426 | .decl = parent_block.decl, |
| 1377 | 1427 | .instructions = .{}, |
| 1378 | 1428 | .arena = parent_block.arena, |
| 1429 | .is_comptime = parent_block.is_comptime, | |
| 1379 | 1430 | }; |
| 1380 | 1431 | defer true_block.instructions.deinit(mod.gpa); |
| 1381 | 1432 | try analyzeBody(mod, &true_block.base, inst.positionals.then_body); |
| ... | ... | @@ -1386,6 +1437,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1386 | 1437 | .decl = parent_block.decl, |
| 1387 | 1438 | .instructions = .{}, |
| 1388 | 1439 | .arena = parent_block.arena, |
| 1440 | .is_comptime = parent_block.is_comptime, | |
| 1389 | 1441 | }; |
| 1390 | 1442 | defer false_block.instructions.deinit(mod.gpa); |
| 1391 | 1443 | try analyzeBody(mod, &false_block.base, inst.positionals.else_body); |
test/stage2/test.zig+1-1| ... | ... | @@ -274,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 276 | { |
| 277 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | |
| 277 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); | |
| 278 | 278 | case.addCompareOutput( |
| 279 | 279 | \\export fn _start() noreturn { |
| 280 | 280 | \\ sub(7, 4); |