| ... | @@ -810,7 +810,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -810,7 +810,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 810 | .negation => return negation(gz, scope, ri, node), | 810 | .negation => return negation(gz, scope, ri, node), |
| 811 | .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap), | 811 | .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap), |
| 812 | | 812 | |
| 813 | .identifier => return identifier(gz, scope, ri, node), | 813 | .identifier => return identifier(gz, scope, ri, node, null), |
| 814 | | 814 | |
| 815 | .asm_simple, | 815 | .asm_simple, |
| 816 | .@"asm", | 816 | .@"asm", |
| ... | @@ -2006,19 +2006,50 @@ fn comptimeExpr2( | ... | @@ -2006,19 +2006,50 @@ fn comptimeExpr2( |
| 2006 | const main_tokens = tree.nodes.items(.main_token); | 2006 | const main_tokens = tree.nodes.items(.main_token); |
| 2007 | const node_tags = tree.nodes.items(.tag); | 2007 | const node_tags = tree.nodes.items(.tag); |
| 2008 | switch (node_tags[node]) { | 2008 | switch (node_tags[node]) { |
| 2009 | // Any identifier in `primitive_instrs` is trivially comptime. In particular, this includes | | |
| 2010 | // some common types, so we can elide `block_comptime` for a few common type annotations. | | |
| 2011 | .identifier => { | 2009 | .identifier => { |
| 2012 | const ident_token = main_tokens[node]; | 2010 | // Many identifiers can be handled without a `block_comptime`, so `AstGen.identifier` has |
| 2013 | const ident_name_raw = tree.tokenSlice(ident_token); | 2011 | // special handling for this case. |
| 2014 | if (primitive_instrs.get(ident_name_raw)) |zir_const_ref| { | 2012 | return identifier(gz, scope, ri, node, .{ .src_node = src_node, .reason = reason }); |
| 2015 | // No need to worry about result location here, we're not creating a comptime block! | | |
| 2016 | return rvalue(gz, ri, zir_const_ref, node); | | |
| 2017 | } | | |
| 2018 | }, | 2013 | }, |
| 2019 | | 2014 | |
| 2020 | // We can also avoid the block for a few trivial AST tags which are always comptime-known. | 2015 | // These are leaf nodes which are always comptime-known. |
| 2021 | .number_literal, .string_literal, .multiline_string_literal, .enum_literal, .error_value => { | 2016 | .number_literal, |
| | 2017 | .char_literal, |
| | 2018 | .string_literal, |
| | 2019 | .multiline_string_literal, |
| | 2020 | .enum_literal, |
| | 2021 | .error_value, |
| | 2022 | .anyframe_literal, |
| | 2023 | .error_set_decl, |
| | 2024 | // These nodes are not leaves, but will force comptime evaluation of all sub-expressions, and |
| | 2025 | // hence behave the same regardless of whether they're in a comptime scope. |
| | 2026 | .error_union, |
| | 2027 | .merge_error_sets, |
| | 2028 | .optional_type, |
| | 2029 | .anyframe_type, |
| | 2030 | .ptr_type_aligned, |
| | 2031 | .ptr_type_sentinel, |
| | 2032 | .ptr_type, |
| | 2033 | .ptr_type_bit_range, |
| | 2034 | .array_type, |
| | 2035 | .array_type_sentinel, |
| | 2036 | .fn_proto_simple, |
| | 2037 | .fn_proto_multi, |
| | 2038 | .fn_proto_one, |
| | 2039 | .fn_proto, |
| | 2040 | .container_decl, |
| | 2041 | .container_decl_trailing, |
| | 2042 | .container_decl_arg, |
| | 2043 | .container_decl_arg_trailing, |
| | 2044 | .container_decl_two, |
| | 2045 | .container_decl_two_trailing, |
| | 2046 | .tagged_union, |
| | 2047 | .tagged_union_trailing, |
| | 2048 | .tagged_union_enum_tag, |
| | 2049 | .tagged_union_enum_tag_trailing, |
| | 2050 | .tagged_union_two, |
| | 2051 | .tagged_union_two_trailing, |
| | 2052 | => { |
| 2022 | // No need to worry about result location here, we're not creating a comptime block! | 2053 | // No need to worry about result location here, we're not creating a comptime block! |
| 2023 | return expr(gz, scope, ri, node); | 2054 | return expr(gz, scope, ri, node); |
| 2024 | }, | 2055 | }, |
| ... | @@ -8390,11 +8421,17 @@ fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { | ... | @@ -8390,11 +8421,17 @@ fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { |
| 8390 | return x; | 8421 | return x; |
| 8391 | } | 8422 | } |
| 8392 | | 8423 | |
| | 8424 | const ComptimeBlockInfo = struct { |
| | 8425 | src_node: Ast.Node.Index, |
| | 8426 | reason: std.zig.SimpleComptimeReason, |
| | 8427 | }; |
| | 8428 | |
| 8393 | fn identifier( | 8429 | fn identifier( |
| 8394 | gz: *GenZir, | 8430 | gz: *GenZir, |
| 8395 | scope: *Scope, | 8431 | scope: *Scope, |
| 8396 | ri: ResultInfo, | 8432 | ri: ResultInfo, |
| 8397 | ident: Ast.Node.Index, | 8433 | ident: Ast.Node.Index, |
| | 8434 | force_comptime: ?ComptimeBlockInfo, |
| 8398 | ) InnerError!Zir.Inst.Ref { | 8435 | ) InnerError!Zir.Inst.Ref { |
| 8399 | const astgen = gz.astgen; | 8436 | const astgen = gz.astgen; |
| 8400 | const tree = astgen.tree; | 8437 | const tree = astgen.tree; |
| ... | @@ -8413,6 +8450,7 @@ fn identifier( | ... | @@ -8413,6 +8450,7 @@ fn identifier( |
| 8413 | } | 8450 | } |
| 8414 | | 8451 | |
| 8415 | if (ident_name_raw.len >= 2) integer: { | 8452 | if (ident_name_raw.len >= 2) integer: { |
| | 8453 | // Keep in sync with logic in `comptimeExpr2`. |
| 8416 | const first_c = ident_name_raw[0]; | 8454 | const first_c = ident_name_raw[0]; |
| 8417 | if (first_c == 'i' or first_c == 'u') { | 8455 | if (first_c == 'i' or first_c == 'u') { |
| 8418 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { | 8456 | const signedness: std.builtin.Signedness = switch (first_c == 'i') { |
| ... | @@ -8447,8 +8485,31 @@ fn identifier( | ... | @@ -8447,8 +8485,31 @@ fn identifier( |
| 8447 | } | 8485 | } |
| 8448 | } | 8486 | } |
| 8449 | | 8487 | |
| 8450 | // Local variables, including function parameters. | 8488 | // Local variables, including function parameters, and container-level declarations. |
| 8451 | return localVarRef(gz, scope, ri, ident, ident_token); | 8489 | |
| | 8490 | if (force_comptime) |fc| { |
| | 8491 | // Mirrors the logic at the end of `comptimeExpr2`. |
| | 8492 | const block_inst = try gz.makeBlockInst(.block_comptime, fc.src_node); |
| | 8493 | |
| | 8494 | var comptime_gz = gz.makeSubBlock(scope); |
| | 8495 | comptime_gz.is_comptime = true; |
| | 8496 | defer comptime_gz.unstack(); |
| | 8497 | |
| | 8498 | const sub_ri: ResultInfo = .{ |
| | 8499 | .ctx = ri.ctx, |
| | 8500 | .rl = .none, // no point providing a result type, it won't change anything |
| | 8501 | }; |
| | 8502 | const block_result = try localVarRef(&comptime_gz, scope, sub_ri, ident, ident_token); |
| | 8503 | assert(!comptime_gz.endsWithNoReturn()); |
| | 8504 | _ = try comptime_gz.addBreak(.break_inline, block_inst, block_result); |
| | 8505 | |
| | 8506 | try comptime_gz.setBlockComptimeBody(block_inst, fc.reason); |
| | 8507 | try gz.instructions.append(astgen.gpa, block_inst); |
| | 8508 | |
| | 8509 | return rvalue(gz, ri, block_inst.toRef(), fc.src_node); |
| | 8510 | } else { |
| | 8511 | return localVarRef(gz, scope, ri, ident, ident_token); |
| | 8512 | } |
| 8452 | } | 8513 | } |
| 8453 | | 8514 | |
| 8454 | fn localVarRef( | 8515 | fn localVarRef( |