| ... | @@ -261,6 +261,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -261,6 +261,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 261 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), | 261 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), |
| 262 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), | 262 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), |
| 263 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), | 263 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| | 264 | .Continue => return rlWrap(mod, scope, rl, try continueExpr(mod, scope, node.castTag(.Continue).?)), |
| 264 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), | 265 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 265 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), | 266 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), |
| 266 | .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), | 267 | .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), |
| ... | @@ -291,7 +292,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -291,7 +292,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 291 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), | 292 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), |
| 292 | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), | 293 | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), |
| 293 | .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), | 294 | .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), |
| 294 | .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}), | | |
| 295 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), | 295 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 296 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), | 296 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 297 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), | 297 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| ... | @@ -339,48 +339,97 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr | ... | @@ -339,48 +339,97 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr |
| 339 | const tree = parent_scope.tree(); | 339 | const tree = parent_scope.tree(); |
| 340 | const src = tree.token_locs[node.ltoken].start; | 340 | const src = tree.token_locs[node.ltoken].start; |
| 341 | | 341 | |
| 342 | if (node.getLabel()) |break_label| { | 342 | // Look for the label in the scope. |
| 343 | // Look for the label in the scope. | 343 | var scope = parent_scope; |
| 344 | var scope = parent_scope; | 344 | while (true) { |
| 345 | while (true) { | 345 | switch (scope.tag) { |
| 346 | switch (scope.tag) { | 346 | .gen_zir => { |
| 347 | .gen_zir => { | 347 | const gen_zir = scope.cast(Scope.GenZIR).?; |
| 348 | const gen_zir = scope.cast(Scope.GenZIR).?; | 348 | |
| | 349 | const block_inst = blk: { |
| | 350 | if (node.getLabel()) |break_label| { |
| | 351 | if (gen_zir.label) |label| { |
| | 352 | if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { |
| | 353 | break :blk label.block_inst; |
| | 354 | } |
| | 355 | } |
| | 356 | } else if (gen_zir.break_block) |inst| { |
| | 357 | break :blk inst; |
| | 358 | } |
| | 359 | scope = gen_zir.parent; |
| | 360 | continue; |
| | 361 | }; |
| | 362 | |
| | 363 | if (node.getRHS()) |rhs| { |
| | 364 | // Most result location types can be forwarded directly; however |
| | 365 | // if we need to write to a pointer which has an inferred type, |
| | 366 | // proper type inference requires peer type resolution on the block's |
| | 367 | // break operand expressions. |
| | 368 | const branch_rl: ResultLoc = switch (gen_zir.break_result_loc) { |
| | 369 | .discard, .none, .ty, .ptr, .ref => gen_zir.break_result_loc, |
| | 370 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block_inst }, |
| | 371 | }; |
| | 372 | const operand = try expr(mod, parent_scope, branch_rl, rhs); |
| | 373 | return try addZIRInst(mod, parent_scope, src, zir.Inst.Break, .{ |
| | 374 | .block = block_inst, |
| | 375 | .operand = operand, |
| | 376 | }, .{}); |
| | 377 | } else { |
| | 378 | return try addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ |
| | 379 | .block = block_inst, |
| | 380 | }, .{}); |
| | 381 | } |
| | 382 | }, |
| | 383 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| | 384 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| | 385 | else => if (node.getLabel()) |break_label| { |
| | 386 | const label_name = try identifierTokenString(mod, parent_scope, break_label); |
| | 387 | return mod.failTok(parent_scope, break_label, "label not found: '{}'", .{label_name}); |
| | 388 | } else { |
| | 389 | return mod.failTok(parent_scope, src, "break expression outside loop", .{}); |
| | 390 | }, |
| | 391 | } |
| | 392 | } |
| | 393 | } |
| | 394 | |
| | 395 | fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| | 396 | const tree = parent_scope.tree(); |
| | 397 | const src = tree.token_locs[node.ltoken].start; |
| | 398 | |
| | 399 | // Look for the label in the scope. |
| | 400 | var scope = parent_scope; |
| | 401 | while (true) { |
| | 402 | switch (scope.tag) { |
| | 403 | .gen_zir => { |
| | 404 | const gen_zir = scope.cast(Scope.GenZIR).?; |
| | 405 | const continue_block = gen_zir.continue_block orelse { |
| | 406 | scope = gen_zir.parent; |
| | 407 | continue; |
| | 408 | }; |
| | 409 | if (node.getLabel()) |break_label| blk: { |
| 349 | if (gen_zir.label) |label| { | 410 | if (gen_zir.label) |label| { |
| 350 | if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { | 411 | if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) { |
| 351 | if (node.getRHS()) |rhs| { | 412 | break :blk; |
| 352 | // Most result location types can be forwarded directly; however | | |
| 353 | // if we need to write to a pointer which has an inferred type, | | |
| 354 | // proper type inference requires peer type resolution on the block's | | |
| 355 | // break operand expressions. | | |
| 356 | const branch_rl: ResultLoc = switch (label.result_loc) { | | |
| 357 | .discard, .none, .ty, .ptr, .ref => label.result_loc, | | |
| 358 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst }, | | |
| 359 | }; | | |
| 360 | const operand = try expr(mod, parent_scope, branch_rl, rhs); | | |
| 361 | return try addZIRInst(mod, scope, src, zir.Inst.Break, .{ | | |
| 362 | .block = label.block_inst, | | |
| 363 | .operand = operand, | | |
| 364 | }, .{}); | | |
| 365 | } else { | | |
| 366 | return try addZIRInst(mod, scope, src, zir.Inst.BreakVoid, .{ | | |
| 367 | .block = label.block_inst, | | |
| 368 | }, .{}); | | |
| 369 | } | | |
| 370 | } | 413 | } |
| 371 | } | 414 | } |
| | 415 | // found continue but either it has a different label, or no label |
| 372 | scope = gen_zir.parent; | 416 | scope = gen_zir.parent; |
| 373 | }, | 417 | continue; |
| 374 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, | 418 | } |
| 375 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, | 419 | |
| 376 | else => { | 420 | return addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{ |
| 377 | const label_name = try identifierTokenString(mod, parent_scope, break_label); | 421 | .block = continue_block, |
| 378 | return mod.failTok(parent_scope, break_label, "label not found: '{}'", .{label_name}); | 422 | }, .{}); |
| 379 | }, | 423 | }, |
| 380 | } | 424 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| | 425 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| | 426 | else => if (node.getLabel()) |break_label| { |
| | 427 | const label_name = try identifierTokenString(mod, parent_scope, break_label); |
| | 428 | return mod.failTok(parent_scope, break_label, "label not found: '{}'", .{label_name}); |
| | 429 | } else { |
| | 430 | return mod.failTok(parent_scope, src, "continue expression outside loop", .{}); |
| | 431 | }, |
| 381 | } | 432 | } |
| 382 | } else { | | |
| 383 | return mod.failNode(parent_scope, &node.base, "TODO implement break from loop", .{}); | | |
| 384 | } | 433 | } |
| 385 | } | 434 | } |
| 386 | | 435 | |
| ... | @@ -426,11 +475,11 @@ fn labeledBlockExpr( | ... | @@ -426,11 +475,11 @@ fn labeledBlockExpr( |
| 426 | .decl = parent_scope.decl().?, | 475 | .decl = parent_scope.decl().?, |
| 427 | .arena = gen_zir.arena, | 476 | .arena = gen_zir.arena, |
| 428 | .instructions = .{}, | 477 | .instructions = .{}, |
| | 478 | .break_result_loc = rl, |
| 429 | // TODO @as here is working around a stage1 miscompilation bug :( | 479 | // TODO @as here is working around a stage1 miscompilation bug :( |
| 430 | .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ | 480 | .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| 431 | .token = block_node.label, | 481 | .token = block_node.label, |
| 432 | .block_inst = block_inst, | 482 | .block_inst = block_inst, |
| 433 | .result_loc = rl, | | |
| 434 | }), | 483 | }), |
| 435 | }; | 484 | }; |
| 436 | defer block_scope.instructions.deinit(mod.gpa); | 485 | defer block_scope.instructions.deinit(mod.gpa); |
| ... | @@ -1289,9 +1338,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1289,9 +1338,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1289 | } | 1338 | } |
| 1290 | } | 1339 | } |
| 1291 | | 1340 | |
| 1292 | if (while_node.label) |tok| | | |
| 1293 | return mod.failTok(scope, tok, "TODO labeled while", .{}); | | |
| 1294 | | | |
| 1295 | if (while_node.inline_token) |tok| | 1341 | if (while_node.inline_token) |tok| |
| 1296 | return mod.failTok(scope, tok, "TODO inline while", .{}); | 1342 | return mod.failTok(scope, tok, "TODO inline while", .{}); |
| 1297 | | 1343 | |
| ... | @@ -1308,6 +1354,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1308,6 +1354,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1308 | .decl = expr_scope.decl, | 1354 | .decl = expr_scope.decl, |
| 1309 | .arena = expr_scope.arena, | 1355 | .arena = expr_scope.arena, |
| 1310 | .instructions = .{}, | 1356 | .instructions = .{}, |
| | 1357 | .break_result_loc = rl, |
| 1311 | }; | 1358 | }; |
| 1312 | defer loop_scope.instructions.deinit(mod.gpa); | 1359 | defer loop_scope.instructions.deinit(mod.gpa); |
| 1313 | | 1360 | |
| ... | @@ -1348,6 +1395,14 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1348,6 +1395,14 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1348 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ | 1395 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ |
| 1349 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), | 1396 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), |
| 1350 | }); | 1397 | }); |
| | 1398 | loop_scope.break_block = while_block; |
| | 1399 | loop_scope.continue_block = cond_block; |
| | 1400 | if (while_node.label) |some| { |
| | 1401 | loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| | 1402 | .token = some, |
| | 1403 | .block_inst = while_block, |
| | 1404 | }); |
| | 1405 | } |
| 1351 | | 1406 | |
| 1352 | const then_src = tree.token_locs[while_node.body.lastToken()].start; | 1407 | const then_src = tree.token_locs[while_node.body.lastToken()].start; |
| 1353 | var then_scope: Scope.GenZIR = .{ | 1408 | var then_scope: Scope.GenZIR = .{ |
| ... | @@ -1414,9 +1469,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1414,9 +1469,6 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1414 | } | 1469 | } |
| 1415 | | 1470 | |
| 1416 | fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst { | 1471 | fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst { |
| 1417 | if (for_node.label) |tok| | | |
| 1418 | return mod.failTok(scope, tok, "TODO labeled for", .{}); | | |
| 1419 | | | |
| 1420 | if (for_node.inline_token) |tok| | 1472 | if (for_node.inline_token) |tok| |
| 1421 | return mod.failTok(scope, tok, "TODO inline for", .{}); | 1473 | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| 1422 | | 1474 | |
| ... | @@ -1458,6 +1510,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1458,6 +1510,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1458 | .decl = for_scope.decl, | 1510 | .decl = for_scope.decl, |
| 1459 | .arena = for_scope.arena, | 1511 | .arena = for_scope.arena, |
| 1460 | .instructions = .{}, | 1512 | .instructions = .{}, |
| | 1513 | .break_result_loc = rl, |
| 1461 | }; | 1514 | }; |
| 1462 | defer loop_scope.instructions.deinit(mod.gpa); | 1515 | defer loop_scope.instructions.deinit(mod.gpa); |
| 1463 | | 1516 | |
| ... | @@ -1499,6 +1552,14 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1499,6 +1552,14 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1499 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ | 1552 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ |
| 1500 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), | 1553 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), |
| 1501 | }); | 1554 | }); |
| | 1555 | loop_scope.break_block = for_block; |
| | 1556 | loop_scope.continue_block = cond_block; |
| | 1557 | if (for_node.label) |some| { |
| | 1558 | loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| | 1559 | .token = some, |
| | 1560 | .block_inst = for_block, |
| | 1561 | }); |
| | 1562 | } |
| 1502 | | 1563 | |
| 1503 | // while body | 1564 | // while body |
| 1504 | const then_src = tree.token_locs[for_node.body.lastToken()].start; | 1565 | const then_src = tree.token_locs[for_node.body.lastToken()].start; |