| ... | @@ -518,6 +518,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins | ... | @@ -518,6 +518,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins |
| 518 | .error_union, | 518 | .error_union, |
| 519 | .merge_error_sets, | 519 | .merge_error_sets, |
| 520 | .switch_range, | 520 | .switch_range, |
| | 521 | .for_range, |
| 521 | .@"await", | 522 | .@"await", |
| 522 | .bit_not, | 523 | .bit_not, |
| 523 | .negation, | 524 | .negation, |
| ... | @@ -646,6 +647,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -646,6 +647,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 646 | .asm_output => unreachable, // Handled in `asmExpr`. | 647 | .asm_output => unreachable, // Handled in `asmExpr`. |
| 647 | .asm_input => unreachable, // Handled in `asmExpr`. | 648 | .asm_input => unreachable, // Handled in `asmExpr`. |
| 648 | | 649 | |
| | 650 | .for_range => unreachable, // Handled in `forExpr`. |
| | 651 | |
| 649 | .assign => { | 652 | .assign => { |
| 650 | try assign(gz, scope, node); | 653 | try assign(gz, scope, node); |
| 651 | return rvalue(gz, ri, .void_value, node); | 654 | return rvalue(gz, ri, .void_value, node); |
| ... | @@ -834,7 +837,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -834,7 +837,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 834 | .@"while", | 837 | .@"while", |
| 835 | => return whileExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false), | 838 | => return whileExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false), |
| 836 | | 839 | |
| 837 | .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false), | 840 | .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullFor(node).?, false), |
| 838 | | 841 | |
| 839 | .slice_open => { | 842 | .slice_open => { |
| 840 | const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); | 843 | const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); |
| ... | @@ -2342,7 +2345,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -2342,7 +2345,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 2342 | .@"while", => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true), | 2345 | .@"while", => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true), |
| 2343 | | 2346 | |
| 2344 | .for_simple, | 2347 | .for_simple, |
| 2345 | .@"for", => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true), | 2348 | .@"for", => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullFor(inner_node).?, true), |
| 2346 | | 2349 | |
| 2347 | else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node), | 2350 | else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node), |
| 2348 | // zig fmt: on | 2351 | // zig fmt: on |
| ... | @@ -6282,7 +6285,7 @@ fn forExpr( | ... | @@ -6282,7 +6285,7 @@ fn forExpr( |
| 6282 | scope: *Scope, | 6285 | scope: *Scope, |
| 6283 | ri: ResultInfo, | 6286 | ri: ResultInfo, |
| 6284 | node: Ast.Node.Index, | 6287 | node: Ast.Node.Index, |
| 6285 | for_full: Ast.full.While, | 6288 | for_full: Ast.full.For, |
| 6286 | is_statement: bool, | 6289 | is_statement: bool, |
| 6287 | ) InnerError!Zir.Inst.Ref { | 6290 | ) InnerError!Zir.Inst.Ref { |
| 6288 | const astgen = parent_gz.astgen; | 6291 | const astgen = parent_gz.astgen; |
| ... | @@ -6295,23 +6298,79 @@ fn forExpr( | ... | @@ -6295,23 +6298,79 @@ fn forExpr( |
| 6295 | const is_inline = parent_gz.force_comptime or for_full.inline_token != null; | 6298 | const is_inline = parent_gz.force_comptime or for_full.inline_token != null; |
| 6296 | const tree = astgen.tree; | 6299 | const tree = astgen.tree; |
| 6297 | const token_tags = tree.tokens.items(.tag); | 6300 | const token_tags = tree.tokens.items(.tag); |
| | 6301 | const node_tags = tree.nodes.items(.tag); |
| | 6302 | const node_data = tree.nodes.items(.data); |
| 6298 | | 6303 | |
| 6299 | const payload_is_ref = if (for_full.payload_token) |payload_token| | 6304 | // Check for unterminated ranges. |
| 6300 | token_tags[payload_token] == .asterisk | 6305 | { |
| 6301 | else | 6306 | var unterminated: ?Ast.Node.Index = null; |
| 6302 | false; | 6307 | for (for_full.ast.inputs) |input| { |
| | 6308 | if (node_tags[input] != .for_range) break; |
| | 6309 | if (node_data[input].rhs != 0) break; |
| | 6310 | unterminated = unterminated orelse input; |
| | 6311 | } else { |
| | 6312 | return astgen.failNode(unterminated.?, "unterminated for range", .{}); |
| | 6313 | } |
| | 6314 | } |
| | 6315 | |
| | 6316 | var lens = astgen.gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len); |
| | 6317 | defer astgen.gpa.free(lens); |
| | 6318 | var indexables = astgen.gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len); |
| | 6319 | defer astgen.gpa.free(indexables); |
| | 6320 | var counters = std.ArrayList(Zir.Inst.Ref).init(astgen.gpa); |
| | 6321 | defer counters.deinit(); |
| 6303 | | 6322 | |
| 6304 | try emitDbgNode(parent_gz, for_full.ast.cond_expr); | 6323 | const counter_alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; |
| | 6324 | |
| | 6325 | { |
| | 6326 | var payload = for_full.payload_token; |
| | 6327 | for (for_full.ast.inputs) |input, i| { |
| | 6328 | const payload_is_ref = token_tags[payload] == .asterisk; |
| | 6329 | const ident_tok = payload + @boolToInt(payload_is_ref); |
| | 6330 | |
| | 6331 | if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and payload_is_ref) { |
| | 6332 | return astgen.failTok(payload, "pointer modifier invalid on discard", .{}); |
| | 6333 | } |
| | 6334 | payload = ident_tok + @as(u32, 2); |
| | 6335 | |
| | 6336 | try emitDbgNode(parent_gz, input); |
| | 6337 | if (node_tags[input] == .for_range) { |
| | 6338 | if (payload_is_ref) { |
| | 6339 | return astgen.failTok(ident_tok, "cannot capture reference to range", .{}); |
| | 6340 | } |
| | 6341 | const counter_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node); |
| | 6342 | const start_val = try expr(parent_gz, scope, node_data[input].lhs, input); |
| | 6343 | _ = try parent_gz.addBin(.store, counter_ptr, start_val); |
| | 6344 | indexables[i] = counter_ptr; |
| | 6345 | try counters.append(counter_ptr); |
| | 6346 | |
| | 6347 | const end_node = node_data[input].rhs; |
| | 6348 | const end_val = if (end_node != 0) try expr(parent_gz, scope, node_data[input].rhs, input) else .none; |
| | 6349 | const range_len = try parent_gz.addPlNode(.for_range_len, input, Zir.Inst.Bin{ |
| | 6350 | .lhs = start_val, |
| | 6351 | .rhs = end_val, |
| | 6352 | }); |
| | 6353 | lens[i] = range_len; |
| | 6354 | } else { |
| | 6355 | const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; |
| | 6356 | const indexable = try expr(parent_gz, scope, cond_ri, input); |
| | 6357 | indexables[i] = indexable; |
| | 6358 | |
| | 6359 | const indexable_len = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input); |
| | 6360 | lens[i] = indexable_len; |
| | 6361 | } |
| | 6362 | } |
| | 6363 | } |
| 6305 | | 6364 | |
| 6306 | const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; | 6365 | const len = "check_for_lens"; |
| 6307 | const array_ptr = try expr(parent_gz, scope, cond_ri, for_full.ast.cond_expr); | | |
| 6308 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); | | |
| 6309 | | 6366 | |
| 6310 | const index_ptr = blk: { | 6367 | const index_ptr = blk: { |
| 6311 | const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; | 6368 | // Future optimization: |
| 6312 | const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); | 6369 | // for loops with only ranges don't need a separate index variable. |
| | 6370 | const index_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node); |
| 6313 | // initialize to zero | 6371 | // initialize to zero |
| 6314 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); | 6372 | _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); |
| | 6373 | try counters.append(index_ptr); |
| 6315 | break :blk index_ptr; | 6374 | break :blk index_ptr; |
| 6316 | }; | 6375 | }; |
| 6317 | | 6376 | |
| ... | @@ -6343,13 +6402,15 @@ fn forExpr( | ... | @@ -6343,13 +6402,15 @@ fn forExpr( |
| 6343 | // cond_block unstacked now, can add new instructions to loop_scope | 6402 | // cond_block unstacked now, can add new instructions to loop_scope |
| 6344 | try loop_scope.instructions.append(astgen.gpa, cond_block); | 6403 | try loop_scope.instructions.append(astgen.gpa, cond_block); |
| 6345 | | 6404 | |
| 6346 | // Increment the index variable. | 6405 | // Increment the index variable and ranges. |
| 6347 | const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); | 6406 | for (counters) |counter_ptr| { |
| 6348 | const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ | 6407 | const counter = try loop_scope.addUnNode(.load, counter_ptr, for_full.ast.cond_expr); |
| 6349 | .lhs = index_2, | 6408 | const counter_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ |
| 6350 | .rhs = .one_usize, | 6409 | .lhs = counter, |
| 6351 | }); | 6410 | .rhs = .one_usize, |
| 6352 | _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); | 6411 | }); |
| | 6412 | _ = try loop_scope.addBin(.store, counter_ptr, counter_plus_one); |
| | 6413 | } |
| 6353 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; | 6414 | const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; |
| 6354 | _ = try loop_scope.addNode(repeat_tag, node); | 6415 | _ = try loop_scope.addNode(repeat_tag, node); |
| 6355 | | 6416 | |
| ... | @@ -6366,64 +6427,62 @@ fn forExpr( | ... | @@ -6366,64 +6427,62 @@ fn forExpr( |
| 6366 | var then_scope = parent_gz.makeSubBlock(&cond_scope.base); | 6427 | var then_scope = parent_gz.makeSubBlock(&cond_scope.base); |
| 6367 | defer then_scope.unstack(); | 6428 | defer then_scope.unstack(); |
| 6368 | | 6429 | |
| 6369 | try then_scope.addDbgBlockBegin(); | 6430 | const then_sub_scope = &then_scope.base; |
| 6370 | var payload_val_scope: Scope.LocalVal = undefined; | 6431 | |
| 6371 | var index_scope: Scope.LocalPtr = undefined; | 6432 | // try then_scope.addDbgBlockBegin(); |
| 6372 | const then_sub_scope = blk: { | 6433 | // var payload_val_scope: Scope.LocalVal = undefined; |
| 6373 | const payload_token = for_full.payload_token.?; | 6434 | // var index_scope: Scope.LocalPtr = undefined; |
| 6374 | const ident = if (token_tags[payload_token] == .asterisk) | 6435 | // const then_sub_scope = blk: { |
| 6375 | payload_token + 1 | 6436 | // const payload_token = for_full.payload_token.?; |
| 6376 | else | 6437 | // const ident = if (token_tags[payload_token] == .asterisk) |
| 6377 | payload_token; | 6438 | // payload_token + 1 |
| 6378 | const is_ptr = ident != payload_token; | 6439 | // else |
| 6379 | const value_name = tree.tokenSlice(ident); | 6440 | // payload_token; |
| 6380 | var payload_sub_scope: *Scope = undefined; | 6441 | // const is_ptr = ident != payload_token; |
| 6381 | if (!mem.eql(u8, value_name, "_")) { | 6442 | // const value_name = tree.tokenSlice(ident); |
| 6382 | const name_str_index = try astgen.identAsString(ident); | 6443 | // var payload_sub_scope: *Scope = undefined; |
| 6383 | const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; | 6444 | // if (!mem.eql(u8, value_name, "_")) { |
| 6384 | const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ | 6445 | // const name_str_index = try astgen.identAsString(ident); |
| 6385 | .lhs = array_ptr, | 6446 | // const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; |
| 6386 | .rhs = index, | 6447 | // const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ |
| 6387 | }); | 6448 | // .lhs = array_ptr, |
| 6388 | try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture); | 6449 | // .rhs = index, |
| 6389 | payload_val_scope = .{ | 6450 | // }); |
| 6390 | .parent = &then_scope.base, | 6451 | // try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture); |
| 6391 | .gen_zir = &then_scope, | 6452 | // payload_val_scope = .{ |
| 6392 | .name = name_str_index, | 6453 | // .parent = &then_scope.base, |
| 6393 | .inst = payload_inst, | 6454 | // .gen_zir = &then_scope, |
| 6394 | .token_src = ident, | 6455 | // .name = name_str_index, |
| 6395 | .id_cat = .capture, | 6456 | // .inst = payload_inst, |
| 6396 | }; | 6457 | // .token_src = ident, |
| 6397 | try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); | 6458 | // .id_cat = .capture, |
| 6398 | payload_sub_scope = &payload_val_scope.base; | 6459 | // }; |
| 6399 | } else if (is_ptr) { | 6460 | // try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); |
| 6400 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | 6461 | // payload_sub_scope = &payload_val_scope.base; |
| 6401 | } else { | 6462 | // } else if (is_ptr) { |
| 6402 | payload_sub_scope = &then_scope.base; | 6463 | // } else { |
| 6403 | } | 6464 | // payload_sub_scope = &then_scope.base; |
| 6404 | | 6465 | // } |
| 6405 | const index_token = if (token_tags[ident + 1] == .comma) | 6466 | |
| 6406 | ident + 2 | 6467 | // const index_token = if (token_tags[ident + 1] == .comma) |
| 6407 | else | 6468 | // ident + 2 |
| 6408 | break :blk payload_sub_scope; | 6469 | // else |
| 6409 | const token_bytes = tree.tokenSlice(index_token); | 6470 | // break :blk payload_sub_scope; |
| 6410 | if (mem.eql(u8, token_bytes, "_")) { | 6471 | // const token_bytes = tree.tokenSlice(index_token); |
| 6411 | return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); | 6472 | // const index_name = try astgen.identAsString(index_token); |
| 6412 | } | 6473 | // try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture"); |
| 6413 | const index_name = try astgen.identAsString(index_token); | 6474 | // index_scope = .{ |
| 6414 | try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture"); | 6475 | // .parent = payload_sub_scope, |
| 6415 | index_scope = .{ | 6476 | // .gen_zir = &then_scope, |
| 6416 | .parent = payload_sub_scope, | 6477 | // .name = index_name, |
| 6417 | .gen_zir = &then_scope, | 6478 | // .ptr = index_ptr, |
| 6418 | .name = index_name, | 6479 | // .token_src = index_token, |
| 6419 | .ptr = index_ptr, | 6480 | // .maybe_comptime = is_inline, |
| 6420 | .token_src = index_token, | 6481 | // .id_cat = .@"loop index capture", |
| 6421 | .maybe_comptime = is_inline, | 6482 | // }; |
| 6422 | .id_cat = .@"loop index capture", | 6483 | // try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); |
| 6423 | }; | 6484 | // break :blk &index_scope.base; |
| 6424 | try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); | 6485 | // }; |
| 6425 | break :blk &index_scope.base; | | |
| 6426 | }; | | |
| 6427 | | 6486 | |
| 6428 | const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr); | 6487 | const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr); |
| 6429 | _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr); | 6488 | _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr); |
| ... | @@ -9021,6 +9080,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_ | ... | @@ -9021,6 +9080,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_ |
| 9021 | .mul_wrap, | 9080 | .mul_wrap, |
| 9022 | .mul_sat, | 9081 | .mul_sat, |
| 9023 | .switch_range, | 9082 | .switch_range, |
| | 9083 | .for_range, |
| 9024 | .field_access, | 9084 | .field_access, |
| 9025 | .sub, | 9085 | .sub, |
| 9026 | .sub_wrap, | 9086 | .sub_wrap, |
| ... | @@ -9310,6 +9370,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev | ... | @@ -9310,6 +9370,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev |
| 9310 | .mul_wrap, | 9370 | .mul_wrap, |
| 9311 | .mul_sat, | 9371 | .mul_sat, |
| 9312 | .switch_range, | 9372 | .switch_range, |
| | 9373 | .for_range, |
| 9313 | .sub, | 9374 | .sub, |
| 9314 | .sub_wrap, | 9375 | .sub_wrap, |
| 9315 | .sub_sat, | 9376 | .sub_sat, |
| ... | @@ -9487,6 +9548,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In | ... | @@ -9487,6 +9548,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In |
| 9487 | .mul_wrap, | 9548 | .mul_wrap, |
| 9488 | .mul_sat, | 9549 | .mul_sat, |
| 9489 | .switch_range, | 9550 | .switch_range, |
| | 9551 | .for_range, |
| 9490 | .field_access, | 9552 | .field_access, |
| 9491 | .sub, | 9553 | .sub, |
| 9492 | .sub_wrap, | 9554 | .sub_wrap, |
| ... | @@ -9731,6 +9793,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { | ... | @@ -9731,6 +9793,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { |
| 9731 | .mul_wrap, | 9793 | .mul_wrap, |
| 9732 | .mul_sat, | 9794 | .mul_sat, |
| 9733 | .switch_range, | 9795 | .switch_range, |
| | 9796 | .for_range, |
| 9734 | .field_access, | 9797 | .field_access, |
| 9735 | .sub, | 9798 | .sub, |
| 9736 | .sub_wrap, | 9799 | .sub_wrap, |