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