diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 4002eb75cb11..7af8bacb3459 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -718,6 +718,165 @@ pub const EnvVar = enum { } }; +pub const SimpleComptimeReason = enum(u32) { + // Evaluating at comptime because a builtin operand must be comptime-known. + // These messages all mention a specific builtin. + operand_Type, + operand_setEvalBranchQuota, + operand_setFloatMode, + operand_branchHint, + operand_setRuntimeSafety, + operand_embedFile, + operand_cImport, + operand_cDefine_macro_name, + operand_cDefine_macro_value, + operand_cInclude_file_name, + operand_cUndef_macro_name, + operand_shuffle_mask, + operand_atomicRmw_operation, + operand_reduce_operation, + + // Evaluating at comptime because an operand must be comptime-known. + // These messages do not mention a specific builtin (and may not be about a builtin at all). + export_target, + export_options, + extern_options, + prefetch_options, + call_modifier, + compile_error_string, + inline_assembly_code, + atomic_order, + array_mul_factor, + slice_cat_operand, + comptime_call_target, + wasm_memory_index, + work_group_dim_index, + + // Evaluating at comptime because types must be comptime-known. + // Reasons other than `.type` are just more specific messages. + type, + array_sentinel, + pointer_sentinel, + slice_sentinel, + array_length, + vector_length, + error_set_contents, + struct_fields, + enum_fields, + union_fields, + function_ret_ty, + function_parameters, + + // Evaluating at comptime because decl/field name must be comptime-known. + decl_name, + field_name, + struct_field_name, + enum_field_name, + union_field_name, + tuple_field_name, + tuple_field_index, + + // Evaluating at comptime because it is an attribute of a global declaration. + container_var_init, + @"callconv", + @"align", + @"addrspace", + @"linksection", + + // Miscellaneous reasons. + comptime_keyword, + comptime_call_modifier, + switch_item, + tuple_field_default_value, + struct_field_default_value, + enum_field_tag_value, + slice_single_item_ptr_bounds, + comptime_param_arg, + stored_to_comptime_field, + stored_to_comptime_var, + casted_to_comptime_enum, + casted_to_comptime_int, + casted_to_comptime_float, + panic_handler, + + pub fn message(r: SimpleComptimeReason) []const u8 { + return switch (r) { + // zig fmt: off + .operand_Type => "operand to '@Type' must be comptime-known", + .operand_setEvalBranchQuota => "operand to '@setEvalBranchQuota' must be comptime-known", + .operand_setFloatMode => "operand to '@setFloatMode' must be comptime-known", + .operand_branchHint => "operand to '@branchHint' must be comptime-known", + .operand_setRuntimeSafety => "operand to '@setRuntimeSafety' must be comptime-known", + .operand_embedFile => "operand to '@embedFile' must be comptime-known", + .operand_cImport => "operand to '@cImport' is evaluated at comptime", + .operand_cDefine_macro_name => "'@cDefine' macro name must be comptime-known", + .operand_cDefine_macro_value => "'@cDefine' macro value must be comptime-known", + .operand_cInclude_file_name => "'@cInclude' file name must be comptime-known", + .operand_cUndef_macro_name => "'@cUndef' macro name must be comptime-known", + .operand_shuffle_mask => "'@shuffle' mask must be comptime-known", + .operand_atomicRmw_operation => "'@atomicRmw' operation must be comptime-known", + .operand_reduce_operation => "'@reduce' operation must be comptime-known", + + .export_target => "export target must be comptime-known", + .export_options => "export options must be comptime-known", + .extern_options => "extern options must be comptime-known", + .prefetch_options => "prefetch options must be comptime-known", + .call_modifier => "call modifier must be comptime-known", + .compile_error_string => "compile error string must be comptime-known", + .inline_assembly_code => "inline assembly code must be comptime-known", + .atomic_order => "atomic order must be comptime-known", + .array_mul_factor => "array multiplication factor must be comptime-known", + .slice_cat_operand => "slice being concatenated must be comptime-known", + .comptime_call_target => "function being called at comptime must be comptime-known", + .wasm_memory_index => "wasm memory index must be comptime-known", + .work_group_dim_index => "work group dimension index must be comptime-known", + + .type => "types must be comptime-known", + .array_sentinel => "array sentinel value must be comptime-known", + .pointer_sentinel => "pointer sentinel value must be comptime-known", + .slice_sentinel => "slice sentinel value must be comptime-known", + .array_length => "array length must be comptime-known", + .vector_length => "vector length must be comptime-known", + .error_set_contents => "error set contents must be comptime-known", + .struct_fields => "struct fields must be comptime-known", + .enum_fields => "enum fields must be comptime-known", + .union_fields => "union fields must be comptime-known", + .function_ret_ty => "function return type must be comptime-known", + .function_parameters => "function parameters must be comptime-known", + + .decl_name => "declaration name must be comptime-known", + .field_name => "field name must be comptime-known", + .struct_field_name => "struct field name must be comptime-known", + .enum_field_name => "enum field name must be comptime-known", + .union_field_name => "union field name must be comptime-known", + .tuple_field_name => "tuple field name must be comptime-known", + .tuple_field_index => "tuple field index must be comptime-known", + + .container_var_init => "initializer of container-level variable must be comptime-known", + .@"callconv" => "calling convention must be comptime-known", + .@"align" => "alignment must be comptime-known", + .@"addrspace" => "address space must be comptime-known", + .@"linksection" => "linksection must be comptime-known", + + .comptime_keyword => "'comptime' keyword forces comptime evaluation", + .comptime_call_modifier => "'.compile_time' call modifier forces comptime evaluation", + .switch_item => "switch prong values must be comptime-known", + .tuple_field_default_value => "tuple field default value must be comptime-known", + .struct_field_default_value => "struct field default value must be comptime-known", + .enum_field_tag_value => "enum field tag value must be comptime-known", + .slice_single_item_ptr_bounds => "slice of single-item pointer must have comptime-known bounds", + .comptime_param_arg => "argument to comptime parameter must be comptime-known", + .stored_to_comptime_field => "value stored to a comptime field must be comptime-known", + .stored_to_comptime_var => "value stored to a comptime variable must be comptime-known", + .casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known", + .casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known", + .casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known", + .panic_handler => "panic handler must be comptime-known", + // zig fmt: on + }; + } +}; + test { _ = Ast; _ = AstRlAnnotate; diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 6e424b597f3c..d3cce5b6f218 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -97,6 +97,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void { Zir.Inst.Ref, Zir.Inst.Index, Zir.Inst.Declaration.Name, + std.zig.SimpleComptimeReason, Zir.NullTerminatedString, => @intFromEnum(@field(extra, field.name)), @@ -379,7 +380,7 @@ const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } }; const coerced_bool_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .bool_type } }; fn typeExpr(gz: *GenZir, scope: *Scope, type_node: Ast.Node.Index) InnerError!Zir.Inst.Ref { - return comptimeExpr(gz, scope, coerced_type_ri, type_node); + return comptimeExpr(gz, scope, coerced_type_ri, type_node, .type); } fn reachableTypeExpr( @@ -388,7 +389,7 @@ fn reachableTypeExpr( type_node: Ast.Node.Index, reachable_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { - return reachableExprComptime(gz, scope, coerced_type_ri, type_node, reachable_node, true); + return reachableExprComptime(gz, scope, coerced_type_ri, type_node, reachable_node, .type); } /// Same as `expr` but fails with a compile error if the result type is `noreturn`. @@ -399,7 +400,7 @@ fn reachableExpr( node: Ast.Node.Index, reachable_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { - return reachableExprComptime(gz, scope, ri, node, reachable_node, false); + return reachableExprComptime(gz, scope, ri, node, reachable_node, null); } fn reachableExprComptime( @@ -408,10 +409,11 @@ fn reachableExprComptime( ri: ResultInfo, node: Ast.Node.Index, reachable_node: Ast.Node.Index, - force_comptime: bool, + /// If `null`, the expression is not evaluated in a comptime context. + comptime_reason: ?std.zig.SimpleComptimeReason, ) InnerError!Zir.Inst.Ref { - const result_inst = if (force_comptime) - try comptimeExpr(gz, scope, ri, node) + const result_inst = if (comptime_reason) |r| + try comptimeExpr(gz, scope, ri, node, r) else try expr(gz, scope, ri, node); @@ -782,13 +784,22 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE const result = try gz.addPlNode(.array_mul, node, Zir.Inst.ArrayMul{ .res_ty = if (try ri.rl.resultType(gz, node)) |t| t else .none, .lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs), - .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs), + .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs, .array_mul_factor), }); return rvalue(gz, ri, result, node); }, - .error_union => return simpleBinOp(gz, scope, ri, node, .error_union_type), - .merge_error_sets => return simpleBinOp(gz, scope, ri, node, .merge_error_sets), + .error_union, .merge_error_sets => |tag| { + const inst_tag: Zir.Inst.Tag = switch (tag) { + .error_union => .error_union_type, + .merge_error_sets => .merge_error_sets, + else => unreachable, + }; + const lhs = try reachableTypeExpr(gz, scope, node_datas[node].lhs, node); + const rhs = try reachableTypeExpr(gz, scope, node_datas[node].rhs, node); + const result = try gz.addPlNode(inst_tag, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }); + return rvalue(gz, ri, result, node); + }, .bool_and => return boolBinOp(gz, scope, ri, node, .bool_br_and), .bool_or => return boolBinOp(gz, scope, ri, node, .bool_br_or), @@ -799,7 +810,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .negation => return negation(gz, scope, ri, node), .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap), - .identifier => return identifier(gz, scope, ri, node), + .identifier => return identifier(gz, scope, ri, node, null), .asm_simple, .@"asm", @@ -1364,6 +1375,7 @@ fn fnProtoExprInner( assert(param_type_node != 0); var param_gz = block_scope.makeSubBlock(scope); defer param_gz.unstack(); + param_gz.is_comptime = true; const param_type = try fullBodyExpr(¶m_gz, scope, coerced_type_ri, param_type_node, .normal); const param_inst_expected: Zir.Inst.Index = @enumFromInt(astgen.instructions.len + 1); _ = try param_gz.addBreakWithSrcNode(.break_inline, param_inst_expected, param_type, param_type_node); @@ -1380,18 +1392,19 @@ fn fnProtoExprInner( }; const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) - try expr( + try comptimeExpr( &block_scope, scope, .{ .rl = .{ .coerced_ty = try block_scope.addBuiltinValue(fn_proto.ast.callconv_expr, .calling_convention) } }, fn_proto.ast.callconv_expr, + .@"callconv", ) else if (implicit_ccc) try block_scope.addBuiltinValue(node, .calling_convention_c) else .none; - const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); + const ret_ty = try comptimeExpr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type, .function_ret_ty); const result = try block_scope.addFunc(.{ .src_node = fn_proto.ast.proto_node, @@ -1453,7 +1466,7 @@ fn arrayInitExpr( }); break :inst .{ array_type_inst, elem_type }; } else { - const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel); + const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel, .array_sentinel); const array_type_inst = try gz.addPlNode( .array_type_sentinel, array_init.ast.type_expr, @@ -1721,7 +1734,7 @@ fn structInitExpr( .rhs = elem_type, }); } else blk: { - const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel); + const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel, .array_sentinel); break :blk try gz.addPlNode( .array_type_sentinel, struct_init.ast.type_expr, @@ -1966,6 +1979,20 @@ fn comptimeExpr( scope: *Scope, ri: ResultInfo, node: Ast.Node.Index, + reason: std.zig.SimpleComptimeReason, +) InnerError!Zir.Inst.Ref { + return comptimeExpr2(gz, scope, ri, node, node, reason); +} + +/// Like `comptimeExpr`, but draws a distinction between `node`, the expression to evaluate at comptime, +/// and `src_node`, the node to attach to the `block_comptime`. +fn comptimeExpr2( + gz: *GenZir, + scope: *Scope, + ri: ResultInfo, + node: Ast.Node.Index, + src_node: Ast.Node.Index, + reason: std.zig.SimpleComptimeReason, ) InnerError!Zir.Inst.Ref { if (gz.is_comptime) { // No need to change anything! @@ -1979,19 +2006,50 @@ fn comptimeExpr( const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); switch (node_tags[node]) { - // Any identifier in `primitive_instrs` is trivially comptime. In particular, this includes - // some common types, so we can elide `block_comptime` for a few common type annotations. .identifier => { - const ident_token = main_tokens[node]; - const ident_name_raw = tree.tokenSlice(ident_token); - if (primitive_instrs.get(ident_name_raw)) |zir_const_ref| { - // No need to worry about result location here, we're not creating a comptime block! - return rvalue(gz, ri, zir_const_ref, node); - } + // Many identifiers can be handled without a `block_comptime`, so `AstGen.identifier` has + // special handling for this case. + return identifier(gz, scope, ri, node, .{ .src_node = src_node, .reason = reason }); }, - // We can also avoid the block for a few trivial AST tags which are always comptime-known. - .number_literal, .string_literal, .multiline_string_literal, .enum_literal, .error_value => { + // These are leaf nodes which are always comptime-known. + .number_literal, + .char_literal, + .string_literal, + .multiline_string_literal, + .enum_literal, + .error_value, + .anyframe_literal, + .error_set_decl, + // These nodes are not leaves, but will force comptime evaluation of all sub-expressions, and + // hence behave the same regardless of whether they're in a comptime scope. + .error_union, + .merge_error_sets, + .optional_type, + .anyframe_type, + .ptr_type_aligned, + .ptr_type_sentinel, + .ptr_type, + .ptr_type_bit_range, + .array_type, + .array_type_sentinel, + .fn_proto_simple, + .fn_proto_multi, + .fn_proto_one, + .fn_proto, + .container_decl, + .container_decl_trailing, + .container_decl_arg, + .container_decl_arg_trailing, + .container_decl_two, + .container_decl_two_trailing, + .tagged_union, + .tagged_union_trailing, + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + .tagged_union_two, + .tagged_union_two_trailing, + => { // No need to worry about result location here, we're not creating a comptime block! return expr(gz, scope, ri, node); }, @@ -2049,23 +2107,23 @@ fn comptimeExpr( block_scope.is_comptime = true; defer block_scope.unstack(); - const block_inst = try gz.makeBlockInst(.block_comptime, node); + const block_inst = try gz.makeBlockInst(.block_comptime, src_node); // Replace result location and copy back later - see above. const ty_only_ri: ResultInfo = .{ .ctx = ri.ctx, - .rl = if (try ri.rl.resultType(gz, node)) |res_ty| + .rl = if (try ri.rl.resultType(gz, src_node)) |res_ty| .{ .coerced_ty = res_ty } else .none, }; const block_result = try fullBodyExpr(&block_scope, scope, ty_only_ri, node, .normal); if (!gz.refIsNoReturn(block_result)) { - _ = try block_scope.addBreak(.@"break", block_inst, block_result); + _ = try block_scope.addBreak(.break_inline, block_inst, block_result); } - try block_scope.setBlockBody(block_inst); + try block_scope.setBlockComptimeBody(block_inst, reason); try gz.instructions.append(gz.astgen.gpa, block_inst); - return rvalue(gz, ri, block_inst.toRef(), node); + return rvalue(gz, ri, block_inst.toRef(), src_node); } /// This one is for an actual `comptime` syntax, and will emit a compile error if @@ -2084,7 +2142,7 @@ fn comptimeExprAst( const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const body_node = node_datas[node].lhs; - return comptimeExpr(gz, scope, ri, body_node); + return comptimeExpr2(gz, scope, ri, body_node, node, .comptime_keyword); } /// Restore the error return trace index. Performs the restore only if the result is a non-error or @@ -2494,10 +2552,10 @@ fn labeledBlockExpr( // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct // so that break statements can reference it. - const block_tag: Zir.Inst.Tag = if (force_comptime) .block_comptime else .block; - const block_inst = try gz.makeBlockInst(block_tag, block_node); + const block_inst = try gz.makeBlockInst(if (force_comptime) .block_comptime else .block, block_node); try gz.instructions.append(astgen.gpa, block_inst); var block_scope = gz.makeSubBlock(parent_scope); + block_scope.is_inline = force_comptime; block_scope.label = GenZir.Label{ .token = label_token, .block_inst = block_inst, @@ -2511,14 +2569,20 @@ fn labeledBlockExpr( // As our last action before the return, "pop" the error trace if needed _ = try gz.addRestoreErrRetIndex(.{ .block = block_inst }, .always, block_node); const result = try rvalue(gz, block_scope.break_result_info, .void_value, block_node); - _ = try block_scope.addBreak(.@"break", block_inst, result); + const break_tag: Zir.Inst.Tag = if (force_comptime) .break_inline else .@"break"; + _ = try block_scope.addBreak(break_tag, block_inst, result); } if (!block_scope.label.?.used) { try astgen.appendErrorTok(label_token, "unused block label", .{}); } - try block_scope.setBlockBody(block_inst); + if (force_comptime) { + try block_scope.setBlockComptimeBody(block_inst, .comptime_keyword); + } else { + try block_scope.setBlockBody(block_inst); + } + if (need_result_rvalue) { return rvalue(gz, ri, block_inst.toRef(), block_node); } else { @@ -2941,6 +3005,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .validate_array_init_result_ty, .validate_ptr_array_init, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, => break :b true, @@ -3255,9 +3320,10 @@ fn varDecl( } else .{ .rl = .none, .ctx = .const_init }; const prev_anon_name_strategy = gz.anon_name_strategy; gz.anon_name_strategy = .dbg_var; - const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, force_comptime); + const init_inst = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null); gz.anon_name_strategy = prev_anon_name_strategy; + _ = try gz.addUnNode(.validate_const, init_inst, var_decl.ast.init_node); try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); // The const init expression may have modified the error return trace, so signal @@ -3321,7 +3387,7 @@ fn varDecl( const prev_anon_name_strategy = gz.anon_name_strategy; gz.anon_name_strategy = .dbg_var; defer gz.anon_name_strategy = prev_anon_name_strategy; - const init_inst = try reachableExprComptime(gz, scope, init_result_info, var_decl.ast.init_node, node, force_comptime); + const init_inst = try reachableExprComptime(gz, scope, init_result_info, var_decl.ast.init_node, node, if (force_comptime) .comptime_keyword else null); // The const init expression may have modified the error return trace, so signal // to Sema that it should save the new index for restoring later. @@ -3393,7 +3459,14 @@ fn varDecl( }; const prev_anon_name_strategy = gz.anon_name_strategy; gz.anon_name_strategy = .dbg_var; - _ = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, is_comptime); + _ = try reachableExprComptime( + gz, + scope, + result_info, + var_decl.ast.init_node, + node, + if (var_decl.comptime_token != null) .comptime_keyword else null, + ); gz.anon_name_strategy = prev_anon_name_strategy; const final_ptr: Zir.Inst.Ref = if (resolve_inferred) ptr: { break :ptr try gz.addUnNode(.resolve_inferred_alloc, alloc, node); @@ -3501,8 +3574,8 @@ fn assignDestructure(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerErro if (full.comptime_token) |_| { const comptime_block_inst = try gz.makeBlockInst(.block_comptime, node); - _ = try inner_gz.addBreak(.@"break", comptime_block_inst, .void_value); - try inner_gz.setBlockBody(comptime_block_inst); + _ = try inner_gz.addBreak(.break_inline, comptime_block_inst, .void_value); + try inner_gz.setBlockComptimeBody(comptime_block_inst, .comptime_keyword); try gz.instructions.append(gz.astgen.gpa, comptime_block_inst); } } @@ -3673,8 +3746,8 @@ fn assignDestructureMaybeDecls( // Finish the block_comptime. Inferred alloc resolution etc will occur // in the parent block. const comptime_block_inst = try gz.makeBlockInst(.block_comptime, node); - _ = try inner_gz.addBreak(.@"break", comptime_block_inst, .void_value); - try inner_gz.setBlockBody(comptime_block_inst); + _ = try inner_gz.addBreak(.break_inline, comptime_block_inst, .void_value); + try inner_gz.setBlockComptimeBody(comptime_block_inst, .comptime_keyword); try gz.instructions.append(gz.astgen.gpa, comptime_block_inst); } @@ -3867,7 +3940,16 @@ fn ptrType( gz.astgen.source_line = source_line; gz.astgen.source_column = source_column; - sentinel_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel); + sentinel_ref = try comptimeExpr( + gz, + scope, + .{ .rl = .{ .ty = elem_type } }, + ptr_info.ast.sentinel, + switch (ptr_info.size) { + .Slice => .slice_sentinel, + else => .pointer_sentinel, + }, + ); trailing_count += 1; } if (ptr_info.ast.addrspace_node != 0) { @@ -3876,7 +3958,7 @@ fn ptrType( gz.astgen.source_column = source_column; const addrspace_ty = try gz.addBuiltinValue(ptr_info.ast.addrspace_node, .address_space); - addrspace_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = addrspace_ty } }, ptr_info.ast.addrspace_node); + addrspace_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = addrspace_ty } }, ptr_info.ast.addrspace_node, .@"addrspace"); trailing_count += 1; } if (ptr_info.ast.align_node != 0) { @@ -3884,13 +3966,13 @@ fn ptrType( gz.astgen.source_line = source_line; gz.astgen.source_column = source_column; - align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node); + align_ref = try comptimeExpr(gz, scope, coerced_align_ri, ptr_info.ast.align_node, .@"align"); trailing_count += 1; } if (ptr_info.ast.bit_range_start != 0) { assert(ptr_info.ast.bit_range_end != 0); - bit_start_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_start); - bit_end_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_end); + bit_start_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_start, .type); + bit_end_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_end, .type); trailing_count += 2; } @@ -3953,7 +4035,7 @@ fn arrayType(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) ! { return astgen.failNode(len_node, "unable to infer array size", .{}); } - const len = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node); + const len = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node, .type); const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); const result = try gz.addPlNode(.array_type, node, Zir.Inst.Bin{ @@ -3977,9 +4059,9 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node. { return astgen.failNode(len_node, "unable to infer array size", .{}); } - const len = try reachableExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node); + const len = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node, .array_length); const elem_type = try typeExpr(gz, scope, extra.elem_type); - const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, true); + const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, .array_sentinel); const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{ .len = len, @@ -5321,7 +5403,7 @@ fn tupleDecl( astgen.scratch.appendAssumeCapacity(@intFromEnum(field_type_ref)); if (field.ast.value_expr != 0) { - const field_init_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_type_ref } }, field.ast.value_expr); + const field_init_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_type_ref } }, field.ast.value_expr, .tuple_field_default_value); astgen.scratch.appendAssumeCapacity(@intFromEnum(field_init_ref)); } else { astgen.scratch.appendAssumeCapacity(@intFromEnum(Zir.Inst.Ref.none)); @@ -5693,7 +5775,7 @@ fn containerDecl( namespace.base.tag = .namespace; const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) - try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, container_decl.ast.arg) + try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, container_decl.ast.arg, .type) else .none; @@ -7573,7 +7655,7 @@ fn switchExprErrUnion( if (node_tags[item_node] == .switch_range) continue; items_len += 1; - const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); + const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node, .switch_item); try payloads.append(gpa, @intFromEnum(item_inst)); } @@ -7583,8 +7665,8 @@ fn switchExprErrUnion( if (node_tags[range] != .switch_range) continue; ranges_len += 1; - const first = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].lhs); - const last = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].rhs); + const first = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].lhs, .switch_item); + const last = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].rhs, .switch_item); try payloads.appendSlice(gpa, &[_]u32{ @intFromEnum(first), @intFromEnum(last), }); @@ -7602,7 +7684,7 @@ fn switchExprErrUnion( scalar_case_index += 1; try payloads.resize(gpa, header_index + 2); // item, body_len const item_node = case.ast.values[0]; - const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); + const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node, .switch_item); payloads.items[header_index] = @intFromEnum(item_inst); break :blk header_index + 1; }; @@ -8046,7 +8128,7 @@ fn switchExpr( if (node_tags[item_node] == .switch_range) continue; items_len += 1; - const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); + const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node, .switch_item); try payloads.append(gpa, @intFromEnum(item_inst)); } @@ -8056,8 +8138,8 @@ fn switchExpr( if (node_tags[range] != .switch_range) continue; ranges_len += 1; - const first = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].lhs); - const last = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].rhs); + const first = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].lhs, .switch_item); + const last = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].rhs, .switch_item); try payloads.appendSlice(gpa, &[_]u32{ @intFromEnum(first), @intFromEnum(last), }); @@ -8075,7 +8157,7 @@ fn switchExpr( scalar_case_index += 1; try payloads.resize(gpa, header_index + 2); // item, body_len const item_node = case.ast.values[0]; - const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); + const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node, .switch_item); payloads.items[header_index] = @intFromEnum(item_inst); break :blk header_index + 1; }; @@ -8339,11 +8421,17 @@ fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { return x; } +const ComptimeBlockInfo = struct { + src_node: Ast.Node.Index, + reason: std.zig.SimpleComptimeReason, +}; + fn identifier( gz: *GenZir, scope: *Scope, ri: ResultInfo, ident: Ast.Node.Index, + force_comptime: ?ComptimeBlockInfo, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -8362,6 +8450,7 @@ fn identifier( } if (ident_name_raw.len >= 2) integer: { + // Keep in sync with logic in `comptimeExpr2`. const first_c = ident_name_raw[0]; if (first_c == 'i' or first_c == 'u') { const signedness: std.builtin.Signedness = switch (first_c == 'i') { @@ -8396,8 +8485,31 @@ fn identifier( } } - // Local variables, including function parameters. - return localVarRef(gz, scope, ri, ident, ident_token); + // Local variables, including function parameters, and container-level declarations. + + if (force_comptime) |fc| { + // Mirrors the logic at the end of `comptimeExpr2`. + const block_inst = try gz.makeBlockInst(.block_comptime, fc.src_node); + + var comptime_gz = gz.makeSubBlock(scope); + comptime_gz.is_comptime = true; + defer comptime_gz.unstack(); + + const sub_ri: ResultInfo = .{ + .ctx = ri.ctx, + .rl = .none, // no point providing a result type, it won't change anything + }; + const block_result = try localVarRef(&comptime_gz, scope, sub_ri, ident, ident_token); + assert(!comptime_gz.endsWithNoReturn()); + _ = try comptime_gz.addBreak(.break_inline, block_inst, block_result); + + try comptime_gz.setBlockComptimeBody(block_inst, fc.reason); + try gz.instructions.append(astgen.gpa, block_inst); + + return rvalue(gz, ri, block_inst.toRef(), fc.src_node); + } else { + return localVarRef(gz, scope, ri, ident, ident_token); + } } fn localVarRef( @@ -8836,7 +8948,7 @@ fn asmExpr( }, else => .{ .tag = .asm_expr, - .tmpl = @enumFromInt(@intFromEnum(try comptimeExpr(gz, scope, .{ .rl = .none }, full.ast.template))), + .tmpl = @enumFromInt(@intFromEnum(try comptimeExpr(gz, scope, .{ .rl = .none }, full.ast.template, .inline_assembly_code))), }, }; @@ -8973,7 +9085,7 @@ fn unionInit( params: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const union_type = try typeExpr(gz, scope, params[0]); - const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]); + const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .union_field_name); const field_type = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{ .container_type = union_type, .field_name = field_name, @@ -9078,7 +9190,7 @@ fn ptrCast( const flags_int: FlagsInt = @bitCast(flags); const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node); const parent_ptr_type = try ri.rl.resultTypeForCast(gz, root_node, "@alignCast"); - const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, node_datas[node].lhs); + const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, node_datas[node].lhs, .field_name); const field_ptr = try expr(gz, scope, .{ .rl = .none }, node_datas[node].rhs); try emitDbgStmt(gz, cursor); const result = try gz.addExtendedPayloadSmall(.field_parent_ptr, flags_int, Zir.Inst.FieldParentPtr{ @@ -9279,7 +9391,7 @@ fn builtinCall( return astgen.failNode(node, "'@branchHint' must appear as the first statement in a function or conditional branch", .{}); } const hint_ty = try gz.addBuiltinValue(node, .branch_hint); - const hint_val = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = hint_ty } }, params[0]); + const hint_val = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = hint_ty } }, params[0], .operand_branchHint); _ = try gz.addExtendedPayload(.branch_hint, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = hint_val, @@ -9326,18 +9438,18 @@ fn builtinCall( if (ri.rl == .ref or ri.rl == .ref_coerced_ty) { return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), - .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]), + .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name), }); } const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), - .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]), + .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name), }); return rvalue(gz, ri, result, node); }, .FieldType => { const ty_inst = try typeExpr(gz, scope, params[0]); - const name_inst = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]); + const name_inst = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name); const result = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{ .container_type = ty_inst, .field_name = name_inst, @@ -9358,7 +9470,7 @@ fn builtinCall( .@"export" => { const exported = try expr(gz, scope, .{ .rl = .none }, params[0]); const export_options_ty = try gz.addBuiltinValue(node, .export_options); - const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1], .export_options); _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ .exported = exported, .options = options, @@ -9368,7 +9480,7 @@ fn builtinCall( .@"extern" => { const type_inst = try typeExpr(gz, scope, params[0]); const extern_options_ty = try gz.addBuiltinValue(node, .extern_options); - const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = extern_options_ty } }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = extern_options_ty } }, params[1], .extern_options); const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = type_inst, @@ -9560,7 +9672,7 @@ fn builtinCall( // zig fmt: on .wasm_memory_size => { - const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .wasm_memory_index); const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -9568,7 +9680,7 @@ fn builtinCall( return rvalue(gz, ri, result, node); }, .wasm_memory_grow => { - const index_arg = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); + const index_arg = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .wasm_memory_index); const delta_arg = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[1]); const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), @@ -9579,8 +9691,8 @@ fn builtinCall( }, .c_define => { if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); - const name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0]); - const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); + const name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .operand_cDefine_macro_name); + const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1], .operand_cDefine_macro_value); const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = name, @@ -9666,7 +9778,7 @@ fn builtinCall( }, .call => { const call_modifier_ty = try gz.addBuiltinValue(node, .call_modifier); - const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = call_modifier_ty } }, params[0]); + const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = call_modifier_ty } }, params[0], .call_modifier); const callee = try expr(gz, scope, .{ .rl = .none }, params[1]); const args = try expr(gz, scope, .{ .rl = .none }, params[2]); const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ @@ -9682,7 +9794,7 @@ fn builtinCall( }, .field_parent_ptr => { const parent_ptr_type = try ri.rl.resultTypeForCast(gz, node, builtin_name); - const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0]); + const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .field_name); const result = try gz.addExtendedPayloadSmall(.field_parent_ptr, 0, Zir.Inst.FieldParentPtr{ .src_node = gz.nodeIndexToRelative(node), .parent_ptr_type = parent_ptr_type, @@ -9713,7 +9825,7 @@ fn builtinCall( .elem_type = try typeExpr(gz, scope, params[0]), .a = try expr(gz, scope, .{ .rl = .none }, params[1]), .b = try expr(gz, scope, .{ .rl = .none }, params[2]), - .mask = try comptimeExpr(gz, scope, .{ .rl = .none }, params[3]), + .mask = try comptimeExpr(gz, scope, .{ .rl = .none }, params[3], .operand_shuffle_mask), }); return rvalue(gz, ri, result, node); }, @@ -9739,7 +9851,7 @@ fn builtinCall( }, .Vector => { const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ - .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]), + .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .type), .rhs = try typeExpr(gz, scope, params[1]), }); return rvalue(gz, ri, result, node); @@ -9747,7 +9859,7 @@ fn builtinCall( .prefetch => { const prefetch_options_ty = try gz.addBuiltinValue(node, .prefetch_options); const ptr = try expr(gz, scope, .{ .rl = .none }, params[0]); - const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = prefetch_options_ty } }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = prefetch_options_ty } }, params[1], .prefetch_options); _ = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = ptr, @@ -9785,7 +9897,7 @@ fn builtinCall( }, .work_item_id => { - const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index); const result = try gz.addExtendedPayload(.work_item_id, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -9793,7 +9905,7 @@ fn builtinCall( return rvalue(gz, ri, result, node); }, .work_group_size => { - const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index); const result = try gz.addExtendedPayload(.work_group_size, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -9801,7 +9913,7 @@ fn builtinCall( return rvalue(gz, ri, result, node); }, .work_group_id => { - const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index); const result = try gz.addExtendedPayload(.work_group_id, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -9821,7 +9933,13 @@ fn hasDeclOrField( tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const container_type = try typeExpr(gz, scope, lhs_node); - const name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, rhs_node); + const name = try comptimeExpr( + gz, + scope, + .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, + rhs_node, + if (tag == .has_decl) .decl_name else .field_name, + ); const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ .lhs = container_type, .rhs = name, @@ -9874,7 +9992,7 @@ fn simpleUnOp( ) InnerError!Zir.Inst.Ref { const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); const operand = if (tag == .compile_error) - try comptimeExpr(gz, scope, operand_ri, operand_node) + try comptimeExpr(gz, scope, operand_ri, operand_node, .compile_error_string) else try expr(gz, scope, operand_ri, operand_node); switch (tag) { @@ -9972,7 +10090,13 @@ fn simpleCBuiltin( ) InnerError!Zir.Inst.Ref { const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); - const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, operand_node); + const operand = try comptimeExpr( + gz, + scope, + .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, + operand_node, + if (tag == .c_undef) .operand_cUndef_macro_name else .operand_cInclude_file_name, + ); _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -9990,7 +10114,7 @@ fn offsetOf( tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const type_inst = try typeExpr(gz, scope, lhs_node); - const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, rhs_node); + const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, rhs_node, .field_name); const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ .lhs = type_inst, .rhs = field_name, @@ -11996,11 +12120,16 @@ const GenZir = struct { } /// Assumes nothing stacked on `gz`. Unstacks `gz`. + /// Asserts `inst` is not a `block_comptime`. fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void { const astgen = gz.astgen; const gpa = astgen.gpa; const body = gz.instructionsSlice(); const body_len = astgen.countBodyLenAfterFixups(body); + + const zir_tags = astgen.instructions.items(.tag); + assert(zir_tags[@intFromEnum(inst)] != .block_comptime); // use `setComptimeBlockBody` instead + try astgen.extra.ensureUnusedCapacity( gpa, @typeInfo(Zir.Inst.Block).@"struct".fields.len + body_len, @@ -12013,6 +12142,32 @@ const GenZir = struct { gz.unstack(); } + /// Assumes nothing stacked on `gz`. Unstacks `gz`. + /// Asserts `inst` is a `block_comptime`. + fn setBlockComptimeBody(gz: *GenZir, inst: Zir.Inst.Index, comptime_reason: std.zig.SimpleComptimeReason) !void { + const astgen = gz.astgen; + const gpa = astgen.gpa; + const body = gz.instructionsSlice(); + const body_len = astgen.countBodyLenAfterFixups(body); + + const zir_tags = astgen.instructions.items(.tag); + assert(zir_tags[@intFromEnum(inst)] == .block_comptime); // use `setBlockBody` instead + + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.BlockComptime).@"struct".fields.len + body_len, + ); + const zir_datas = astgen.instructions.items(.data); + zir_datas[@intFromEnum(inst)].pl_node.payload_index = astgen.addExtraAssumeCapacity( + Zir.Inst.BlockComptime{ + .reason = comptime_reason, + .body_len = body_len, + }, + ); + astgen.appendBodyWithFixups(body); + gz.unstack(); + } + /// Assumes nothing stacked on `gz`. Unstacks `gz`. fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void { const astgen = gz.astgen; diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 0f9611aa308a..9f420d217190 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -78,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) { Inst.Ref, Inst.Index, Inst.Declaration.Name, + std.zig.SimpleComptimeReason, NullTerminatedString, => @enumFromInt(code.extra[i]), @@ -291,7 +292,8 @@ pub const Inst = struct { /// Uses the `pl_node` union field. Payload is `Block`. block, /// Like `block`, but forces full evaluation of its contents at compile-time. - /// Uses the `pl_node` union field. Payload is `Block`. + /// Exited with `break_inline`. + /// Uses the `pl_node` union field. Payload is `BlockComptime`. block_comptime, /// A list of instructions which are analyzed in the parent context, without /// generating a runtime block. Must terminate with an "inline" variant of @@ -709,6 +711,12 @@ pub const Inst = struct { /// operator. Emit a compile error if not. /// Uses the `un_tok` union field. Token is the `&` operator. Operand is the type. validate_ref_ty, + /// Given a value, check whether it is a valid local constant in this scope. + /// In a runtime scope, this is always a nop. + /// In a comptime scope, raises a compile error if the value is runtime-known. + /// Result is always void. + /// Uses the `un_node` union field. Node is the initializer. Operand is the initializer value. + validate_const, /// Given a type `T`, construct the type `E!T`, where `E` is this function's error set, to be used /// as the result type of a `try` operand. Generic poison is propagated. /// Uses the `un_node` union field. Node is the `try` expression. Operand is the type `T`. @@ -1291,6 +1299,7 @@ pub const Inst = struct { .array_init_elem_type, .array_init_elem_ptr, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, .restore_err_ret_index_unconditional, @@ -1351,6 +1360,7 @@ pub const Inst = struct { .validate_array_init_result_ty, .validate_ptr_array_init, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, => true, @@ -1734,6 +1744,7 @@ pub const Inst = struct { .opt_eu_base_ptr_init = .un_node, .coerce_ptr_elem_ty = .pl_node, .validate_ref_ty = .un_tok, + .validate_const = .un_node, .try_operand_ty = .un_node, .try_ref_operand_ty = .un_node, @@ -2547,6 +2558,13 @@ pub const Inst = struct { body_len: u32, }; + /// Trailing: + /// * inst: Index // for each `body_len` + pub const BlockComptime = struct { + reason: std.zig.SimpleComptimeReason, + body_len: u32, + }; + /// Trailing: /// * inst: Index // for each `body_len` pub const BoolBr = struct { @@ -4134,6 +4152,7 @@ fn findTrackableInner( .opt_eu_base_ptr_init, .coerce_ptr_elem_ty, .validate_ref_ty, + .validate_const, .try_operand_ty, .try_ref_operand_ty, .struct_init_empty, @@ -4517,7 +4536,6 @@ fn findTrackableInner( // Block instructions, recurse over the bodies. .block, - .block_comptime, .block_inline, .c_import, .typeof_builtin, @@ -4528,6 +4546,12 @@ fn findTrackableInner( const body = zir.bodySlice(extra.end, extra.data.body_len); return zir.findTrackableBody(gpa, contents, defers, body); }, + .block_comptime => { + const inst_data = datas[@intFromEnum(inst)].pl_node; + const extra = zir.extraData(Inst.BlockComptime, inst_data.payload_index); + const body = zir.bodySlice(extra.end, extra.data.body_len); + return zir.findTrackableBody(gpa, contents, defers, body); + }, .condbr, .condbr_inline => { const inst_data = datas[@intFromEnum(inst)].pl_node; const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); diff --git a/src/Compilation.zig b/src/Compilation.zig index 28c5efab6c9a..cee9513ac53d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3435,6 +3435,7 @@ pub fn addModuleErrorMsg( var notes: std.ArrayHashMapUnmanaged(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .empty; defer notes.deinit(gpa); + var last_note_loc: ?std.zig.Loc = null; for (module_err_msg.notes) |module_note| { const note_src_loc = module_note.src_loc.upgrade(zcu); const source = try note_src_loc.file_scope.getSource(gpa); @@ -3443,6 +3444,9 @@ pub fn addModuleErrorMsg( const note_file_path = try note_src_loc.file_scope.fullPath(gpa); defer gpa.free(note_file_path); + const omit_source_line = loc.eql(err_loc) or (last_note_loc != null and loc.eql(last_note_loc.?)); + last_note_loc = loc; + const gop = try notes.getOrPutContext(gpa, .{ .msg = try eb.addString(module_note.msg), .src_loc = try eb.addSourceLocation(.{ @@ -3452,7 +3456,7 @@ pub fn addModuleErrorMsg( .span_end = span.end, .line = @intCast(loc.line), .column = @intCast(loc.column), - .source_line = if (err_loc.eql(loc)) 0 else try eb.addString(loc.source_line), + .source_line = if (omit_source_line) 0 else try eb.addString(loc.source_line), }), }, .{ .eb = eb }); if (gop.found_existing) { diff --git a/src/Sema.zig b/src/Sema.zig index ccc9f63a5699..32c4134d9bb7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -377,9 +377,7 @@ pub const Block = struct { runtime_index: RuntimeIndex = .zero, inline_block: Zir.Inst.OptionalIndex = .none, - comptime_reason: ?*const ComptimeReason = null, - // TODO is_comptime and comptime_reason should probably be merged together. - is_comptime: bool, + comptime_reason: ?BlockComptimeReason = null, is_typeof: bool = false, /// Keep track of the active error return trace index around blocks so that we can correctly @@ -419,6 +417,10 @@ pub const Block = struct { }; } + fn isComptime(block: Block) bool { + return block.comptime_reason != null; + } + fn builtinCallArgSrc(block: *Block, builtin_call_node: i32, arg_index: u32) LazySrcLoc { return block.src(.{ .node_offset_builtin_call_arg = .{ .builtin_call_node = builtin_call_node, @@ -434,44 +436,6 @@ pub const Block = struct { return block.src(.{ .token_offset = tok_offset }); } - const ComptimeReason = union(enum) { - c_import: struct { - src: LazySrcLoc, - }, - comptime_ret_ty: struct { - func: Air.Inst.Ref, - func_src: LazySrcLoc, - return_ty: Type, - }, - - fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Zcu.ErrorMsg) !void { - const parent = msg orelse return; - const pt = sema.pt; - const prefix = "expression is evaluated at comptime because "; - switch (cr) { - .c_import => |ci| { - try sema.errNote(ci.src, parent, prefix ++ "it is inside a @cImport", .{}); - }, - .comptime_ret_ty => |rt| { - const ret_ty_src: LazySrcLoc = if (try sema.funcDeclSrcInst(rt.func)) |fn_decl_inst| .{ - .base_node_inst = fn_decl_inst, - .offset = .{ .node_offset_fn_type_ret_ty = 0 }, - } else rt.func_src; - if (rt.return_ty.isGenericPoison()) { - return sema.errNote(ret_ty_src, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{}); - } - try sema.errNote( - ret_ty_src, - parent, - prefix ++ "the function returns a comptime-only type '{}'", - .{rt.return_ty.fmt(pt)}, - ); - try sema.explainWhyTypeIsComptime(parent, ret_ty_src, rt.return_ty); - }, - } - } - }; - const Param = struct { /// `none` means `anytype`. ty: InternPool.Index, @@ -539,7 +503,6 @@ pub const Block = struct { .instructions = .{}, .label = null, .inlining = parent.inlining, - .is_comptime = parent.is_comptime, .comptime_reason = parent.comptime_reason, .is_typeof = parent.is_typeof, .runtime_cond = parent.runtime_cond, @@ -860,6 +823,83 @@ pub const Block = struct { .inst = inst, }); } + + /// Returns the `*Block` that should be passed to `Sema.failWithOwnedErrorMsg`, because all inline + /// calls below it have already been reported with "called at comptime from here" notes. + fn explainWhyBlockIsComptime(start_block: *Block, err_msg: *Zcu.ErrorMsg) !*Block { + const sema = start_block.sema; + var block = start_block; + while (true) { + switch (block.comptime_reason.?) { + .inlining_parent => { + const inlining = block.inlining.?; + try sema.errNote(inlining.call_src, err_msg, "called at comptime from here", .{}); + block = inlining.call_block; + }, + .reason => |r| { + try r.r.explain(sema, r.src, err_msg); + return block; + }, + } + } + } +}; + +/// Represents the reason we are resolving a value or evaluating code at comptime. +/// Most reasons are represented by a `std.zig.SimpleComptimeReason`, which provides a plain message. +const ComptimeReason = union(enum) { + /// Evaluating at comptime for a reason in the `std.zig.SimpleComptimeReason` enum. + simple: std.zig.SimpleComptimeReason, + + /// Evaluating at comptime because of a comptime-only type. This field is separate so that + /// the type in question can be included in the error message. AstGen could never emit this + /// reason, because it knows nothing of types. + /// The format string looks like "foo '{}' bar", where "{}" is the comptime-only type. + /// We will then explain why this type is comptime-only. + comptime_only: struct { + ty: Type, + msg: enum { + union_init, + struct_init, + tuple_init, + param_ty_arg, + ret_ty_call, + ret_ty_generic_call, + }, + }, + + fn explain(reason: ComptimeReason, sema: *Sema, src: LazySrcLoc, err_msg: *Zcu.ErrorMsg) !void { + switch (reason) { + .simple => |simple| { + try sema.errNote(src, err_msg, "{s}", .{simple.message()}); + }, + .comptime_only => |co| { + const pre, const post = switch (co.msg) { + .union_init => .{ "initializer of comptime-only union", "must be comptime-known" }, + .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" }, + .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" }, + .param_ty_arg => .{ "argument to parameter with comptime-only type", "must be comptime-known" }, + .ret_ty_call => .{ "function with comptime-only return type", "is evaluated at comptime" }, + .ret_ty_generic_call => .{ "generic function instantiated with comptime-only return type", "is evaluated at comptime" }, + }; + try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post }); + try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); + }, + } + } +}; + +/// Represents the reason a `Block` is being evaluated at comptime. +const BlockComptimeReason = union(enum) { + /// This block inherits being comptime-only from the `inlining` call site. + inlining_parent, + + /// Comptime evaluation began somewhere in the current function for a given `ComptimeReason`. + reason: struct { + /// The source location which this reason originates from. `r` is reported here. + src: LazySrcLoc, + r: ComptimeReason, + }, }; const LabeledBlock = struct { @@ -885,12 +925,6 @@ const InferredAlloc = struct { prongs: std.ArrayListUnmanaged(Air.Inst.Index) = .empty, }; -const NeededComptimeReason = struct { - needed_comptime_reason: []const u8, - value_comptime_reason: ?[]const u8 = null, - block_comptime_reason: ?*const Block.ComptimeReason = null, -}; - pub fn deinit(sema: *Sema) void { const gpa = sema.gpa; sema.air_instructions.deinit(gpa); @@ -954,7 +988,7 @@ pub fn analyzeFnBody( /// we are evaluating at comptime, semantically analyze the body and return the result from it. /// Returns `null` if control flow did not break from this block, but instead terminated with some /// other runtime noreturn instruction. Compile-time breaks to blocks further up the stack still -/// return `error.ComptimeBreak`. If `block.is_comptime`, this function will never return `null`. +/// return `error.ComptimeBreak`. If `block.isComptime()`, this function will never return `null`. fn analyzeInlineBody( sema: *Sema, block: *Block, @@ -1003,7 +1037,7 @@ pub fn resolveInlineBody( /// If this function returns normally, the merges of `block` were populated with all possible /// (runtime) results of this block. Peer type resolution should be performed on the result, /// and relevant runtime instructions written to perform necessary coercions and breaks. See -/// `resolveAnalyzedBlock`. This form of return is impossible if `block.is_comptime == true`. +/// `resolveAnalyzedBlock`. This form of return is impossible if `block.isComptime()`. /// /// Alternatively, this function may return `error.ComptimeBreak`. This indicates that comptime /// control flow is happening, and we are breaking at comptime from a block indicated by the @@ -1340,7 +1374,7 @@ fn analyzeBodyInner( continue; }, .breakpoint => { - if (!block.is_comptime) { + if (!block.isComptime()) { _ = try block.addNoOp(.breakpoint); } i += 1; @@ -1474,6 +1508,11 @@ fn analyzeBodyInner( i += 1; continue; }, + .validate_const => { + try sema.zirValidateConst(block, inst); + i += 1; + continue; + }, .@"export" => { try sema.zirExport(block, inst); i += 1; @@ -1515,7 +1554,7 @@ fn analyzeBodyInner( continue; }, .check_comptime_control_flow => { - if (!block.is_comptime) { + if (!block.isComptime()) { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const inline_block = inst_data.operand.toIndex().?; @@ -1562,7 +1601,7 @@ fn analyzeBodyInner( // Special case instructions to handle comptime control flow. .@"break" => { - if (block.is_comptime) { + if (block.isComptime()) { sema.comptime_break_inst = inst; return error.ComptimeBreak; } else { @@ -1575,7 +1614,7 @@ fn analyzeBodyInner( return error.ComptimeBreak; }, .repeat => { - if (block.is_comptime) { + if (block.isComptime()) { // Send comptime control flow back to the beginning of this block. const src = block.nodeOffset(datas[@intFromEnum(inst)].node); try sema.emitBackwardBranch(block, src); @@ -1597,7 +1636,7 @@ fn analyzeBodyInner( i = 0; continue; }, - .switch_continue => if (block.is_comptime) { + .switch_continue => if (block.isComptime()) { sema.comptime_break_inst = inst; return error.ComptimeBreak; } else { @@ -1605,17 +1644,40 @@ fn analyzeBodyInner( break; }, - .loop => if (block.is_comptime) { + .loop => if (block.isComptime()) { continue :inst .block_inline; } else try sema.zirLoop(block, inst), - .block => if (block.is_comptime) { + .block => if (block.isComptime()) { continue :inst .block_inline; - } else try sema.zirBlock(block, inst, false), + } else try sema.zirBlock(block, inst), - .block_comptime => if (block.is_comptime) { - continue :inst .block_inline; - } else try sema.zirBlock(block, inst, true), + .block_comptime => { + const pl_node = datas[@intFromEnum(inst)].pl_node; + const src = block.nodeOffset(pl_node.src_node); + const extra = sema.code.extraData(Zir.Inst.BlockComptime, pl_node.payload_index); + const block_body = sema.code.bodySlice(extra.end, extra.data.body_len); + + if (block.isComptime()) { + // No need for a sub-block; just resolve the other body directly! + break :inst try sema.resolveInlineBody(block, block_body, inst); + } + + var child_block = block.makeSubBlock(); + defer child_block.instructions.deinit(sema.gpa); + child_block.comptime_reason = .{ .reason = .{ + .src = src, + .r = .{ .simple = extra.data.reason }, + } }; + + const result = try sema.resolveInlineBody(&child_block, block_body, inst); + + if (!try sema.isComptimeKnown(result)) { + return sema.failWithNeededComptime(&child_block, src, null); + } + + break :inst result; + }, .block_inline => blk: { // Directly analyze the block body without introducing a new block. @@ -1725,7 +1787,7 @@ fn analyzeBodyInner( return error.ComptimeBreak; } }, - .condbr => if (block.is_comptime) { + .condbr => if (block.isComptime()) { continue :inst .condbr_inline; } else { try sema.zirCondbr(block, inst); @@ -1742,10 +1804,7 @@ fn analyzeBodyInner( ); const uncasted_cond = try sema.resolveInst(extra.data.condition); const cond = try sema.coerce(block, Type.bool, uncasted_cond, cond_src); - const cond_val = try sema.resolveConstDefinedValue(block, cond_src, cond, .{ - .needed_comptime_reason = "condition in comptime branch must be comptime-known", - .block_comptime_reason = block.comptime_reason, - }); + const cond_val = try sema.resolveConstDefinedValue(block, cond_src, cond, null); const inline_body = if (cond_val.toBool()) then_body else else_body; try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src); @@ -1756,7 +1815,7 @@ fn analyzeBodyInner( break :inst result; }, .@"try" => blk: { - if (!block.is_comptime) break :blk try sema.zirTry(block, inst); + if (!block.isComptime()) break :blk try sema.zirTry(block, inst); const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node }); @@ -1771,10 +1830,7 @@ fn analyzeBodyInner( } const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); assert(is_non_err != .none); - const is_non_err_val = try sema.resolveConstDefinedValue(block, operand_src, is_non_err, .{ - .needed_comptime_reason = "try operand inside comptime block must be comptime-known", - .block_comptime_reason = block.comptime_reason, - }); + const is_non_err_val = try sema.resolveConstDefinedValue(block, operand_src, is_non_err, null); if (is_non_err_val.toBool()) { break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); } @@ -1782,7 +1838,7 @@ fn analyzeBodyInner( break :blk result; }, .try_ptr => blk: { - if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst); + if (!block.isComptime()) break :blk try sema.zirTryPtr(block, inst); const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node }); @@ -1792,10 +1848,7 @@ fn analyzeBodyInner( const err_union = try sema.analyzeLoad(block, src, operand, operand_src); const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); assert(is_non_err != .none); - const is_non_err_val = try sema.resolveConstDefinedValue(block, operand_src, is_non_err, .{ - .needed_comptime_reason = "try operand inside comptime block must be comptime-known", - .block_comptime_reason = block.comptime_reason, - }); + const is_non_err_val = try sema.resolveConstDefinedValue(block, operand_src, is_non_err, null); if (is_non_err_val.toBool()) { break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); } @@ -1873,7 +1926,7 @@ fn resolveConstBool( block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, - reason: NeededComptimeReason, + reason: ComptimeReason, ) !bool { const air_inst = try sema.resolveInst(zir_ref); const wanted_type = Type.bool; @@ -1887,7 +1940,7 @@ fn resolveConstString( block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, - reason: NeededComptimeReason, + reason: ComptimeReason, ) ![]u8 { const air_inst = try sema.resolveInst(zir_ref); return sema.toConstString(block, src, air_inst, reason); @@ -1898,7 +1951,7 @@ pub fn toConstString( block: *Block, src: LazySrcLoc, air_inst: Air.Inst.Ref, - reason: NeededComptimeReason, + reason: ComptimeReason, ) ![]u8 { const pt = sema.pt; const coerced_inst = try sema.coerce(block, Type.slice_const_u8, air_inst, src); @@ -1912,7 +1965,7 @@ pub fn resolveConstStringIntern( block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, - reason: NeededComptimeReason, + reason: ComptimeReason, ) !InternPool.NullTerminatedString { const air_inst = try sema.resolveInst(zir_ref); const wanted_type = Type.slice_const_u8; @@ -2063,9 +2116,7 @@ fn analyzeAsType( ) !Type { const wanted_type = Type.type; const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); - const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ - .needed_comptime_reason = "types must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = .type }); return val.toType(); } @@ -2077,7 +2128,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) const ip = &zcu.intern_pool; if (!comp.config.any_error_tracing) return; - assert(!block.is_comptime); + assert(!block.isComptime()); var err_trace_block = block.makeSubBlock(); defer err_trace_block.instructions.deinit(gpa); @@ -2148,7 +2199,7 @@ fn resolveConstValue( block: *Block, src: LazySrcLoc, inst: Air.Inst.Ref, - reason: NeededComptimeReason, + reason: ?ComptimeReason, ) CompileError!Value { return try sema.resolveValue(inst) orelse { return sema.failWithNeededComptime(block, src, reason); @@ -2177,7 +2228,7 @@ fn resolveConstDefinedValue( block: *Block, src: LazySrcLoc, air_ref: Air.Inst.Ref, - reason: NeededComptimeReason, + reason: ?ComptimeReason, ) CompileError!Value { const val = try sema.resolveConstValue(block, src, air_ref, reason); if (val.isUndef(sema.pt.zcu)) return sema.failWithUseOfUndef(block, src); @@ -2217,15 +2268,16 @@ pub fn resolveFinalDeclValue( const val: Value = .fromInterned(ip_index); break :rt_ptr val.isPtrRuntimeValue(zcu); }; - const value_comptime_reason: ?[]const u8 = if (is_runtime_ptr) - "thread local and dll imported variables have runtime-known addresses" - else - null; - return sema.failWithNeededComptime(block, src, .{ - .needed_comptime_reason = "global variable initializer must be comptime-known", - .value_comptime_reason = value_comptime_reason, - }); + switch (sema.failWithNeededComptime(block, src, .{ .simple = .container_var_init })) { + error.AnalysisFail => |e| { + if (sema.err != null and is_runtime_ptr) { + try sema.errNote(src, sema.err.?, "threadlocal and dll imported variables have runtime-known addresses", .{}); + } + return e; + }, + else => |e| return e, + } }; if (val.canMutateComptimeVarState(zcu)) { @@ -2235,21 +2287,19 @@ pub fn resolveFinalDeclValue( return val; } -fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: NeededComptimeReason) CompileError { - const msg = msg: { +fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: ?ComptimeReason) CompileError { + const msg, const fail_block = msg: { const msg = try sema.errMsg(src, "unable to resolve comptime value", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(src, msg, "{s}", .{reason.needed_comptime_reason}); - if (reason.value_comptime_reason) |value_comptime_reason| { - try sema.errNote(src, msg, "{s}", .{value_comptime_reason}); - } - - if (reason.block_comptime_reason) |block_comptime_reason| { - try block_comptime_reason.explain(sema, msg); - } - break :msg msg; + const fail_block = if (reason) |r| b: { + try r.explain(sema, src, msg); + break :b block; + } else b: { + break :b try block.explainWhyBlockIsComptime(msg); + }; + break :msg .{ msg, fail_block }; }; - return sema.failWithOwnedErrorMsg(block, msg); + return sema.failWithOwnedErrorMsg(fail_block, msg); } fn failWithUseOfUndef(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError { @@ -2578,9 +2628,7 @@ pub fn analyzeAsAlign( src: LazySrcLoc, air_ref: Air.Inst.Ref, ) !Alignment { - const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ - .needed_comptime_reason = "alignment must be comptime-known", - }); + const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ .simple = .@"align" }); return sema.validateAlign(block, src, alignment_big); } @@ -2615,7 +2663,7 @@ fn resolveInt( src: LazySrcLoc, zir_ref: Zir.Inst.Ref, dest_ty: Type, - reason: NeededComptimeReason, + reason: ComptimeReason, ) !u64 { const air_ref = try sema.resolveInst(zir_ref); return sema.analyzeAsInt(block, src, air_ref, dest_ty, reason); @@ -2627,7 +2675,7 @@ fn analyzeAsInt( src: LazySrcLoc, air_ref: Air.Inst.Ref, dest_ty: Type, - reason: NeededComptimeReason, + reason: ComptimeReason, ) !u64 { const coerced = try sema.coerce(block, dest_ty, air_ref, src); const val = try sema.resolveConstDefinedValue(block, src, coerced, reason); @@ -2687,9 +2735,7 @@ fn zirTupleDecl( if (zir_field_init != .none) { const uncoerced_field_init = try sema.resolveInst(zir_field_init); const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src); - const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ - .needed_comptime_reason = "tuple field default value must be comptime-known", - }); + const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value }); if (field_init_val.canMutateComptimeVarState(zcu)) { return sema.fail(block, init_src, "field default value contains reference to comptime-mutable memory", .{}); } @@ -3414,7 +3460,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const pt = sema.pt; - if (block.is_comptime or try sema.fn_ret_ty.comptimeOnlySema(pt)) { + if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) { try sema.fn_ret_ty.resolveFields(pt); return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none); } @@ -3608,7 +3654,7 @@ fn zirAllocExtended( break :blk try sema.resolveAlign(block, align_src, align_ref); } else .none; - if (block.is_comptime or small.is_comptime) { + if (block.isComptime() or small.is_comptime) { if (small.has_type) { return sema.analyzeComptimeAlloc(block, var_ty, alignment); } else { @@ -4075,7 +4121,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - if (block.is_comptime or try var_ty.comptimeOnlySema(pt)) { + if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) { return sema.analyzeComptimeAlloc(block, var_ty, .none); } if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { @@ -4103,7 +4149,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - if (block.is_comptime) { + if (block.isComptime()) { return sema.analyzeComptimeAlloc(block, var_ty, .none); } if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { @@ -4129,7 +4175,7 @@ fn zirAllocInferred( const gpa = sema.gpa; - if (block.is_comptime) { + if (block.isComptime()) { try sema.air_instructions.append(gpa, .{ .tag = .inferred_alloc_comptime, .data = .{ .inferred_alloc_comptime = .{ @@ -4579,6 +4625,17 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr } } +fn zirValidateConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { + if (!block.isComptime()) return; + + const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; + const src = block.nodeOffset(un_node.src_node); + const init_ref = try sema.resolveInst(un_node.operand); + if (!try sema.isComptimeKnown(init_ref)) { + return sema.failWithNeededComptime(block, src, null); + } +} + fn zirValidateArrayInitRefTy( sema: *Sema, block: *Block, @@ -4778,7 +4835,7 @@ fn validateUnionInit( return sema.failWithOwnedErrorMsg(block, msg); } - if (block.is_comptime and + if (block.isComptime() and (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null) { // In this case, comptime machinery already did everything. No work to do here. @@ -4897,9 +4954,11 @@ fn validateUnionInit( try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); return; } else if (try union_ty.comptimeOnlySema(pt)) { - return sema.failWithNeededComptime(block, block.nodeOffset(field_ptr_data.src_node), .{ - .needed_comptime_reason = "initializer of comptime only union must be comptime-known", - }); + const src = block.nodeOffset(field_ptr_data.src_node); + return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{ + .ty = union_ty, + .msg = .union_init, + } }); } if (init_ref) |v| try sema.validateRuntimeValue(block, block.nodeOffset(field_ptr_data.src_node), v); @@ -4953,7 +5012,7 @@ fn validateStructInit( errdefer if (root_msg) |msg| msg.destroy(sema.gpa); const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); - if (block.is_comptime and + if (block.isComptime() and (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) { try struct_ty.resolveLayout(pt); @@ -5081,9 +5140,11 @@ fn validateStructInit( field_values[i] = val.toIntern(); } else if (require_comptime) { const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node; - return sema.failWithNeededComptime(block, block.nodeOffset(field_ptr_data.src_node), .{ - .needed_comptime_reason = "initializer of comptime only struct must be comptime-known", - }); + const src = block.nodeOffset(field_ptr_data.src_node); + return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{ + .ty = struct_ty, + .msg = .struct_init, + } }); } else { struct_is_comptime = false; } @@ -5253,7 +5314,7 @@ fn zirValidatePtrArrayInit( else => unreachable, }; - if (block.is_comptime and + if (block.isComptime() and (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null) { // In this case the comptime machinery will have evaluated the store instructions @@ -5629,9 +5690,7 @@ fn storeToInferredAllocComptime( // There will be only one store_to_inferred_ptr because we are running at comptime. // The alloc will turn into a Decl or a ComptimeAlloc. const operand_val = try sema.resolveValue(operand) orelse { - return sema.failWithNeededComptime(block, src, .{ - .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known", - }); + return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var }); }; const alloc_ty = try pt.ptrTypeSema(.{ .child = operand_ty.toIntern(), @@ -5663,9 +5722,7 @@ fn storeToInferredAllocComptime( fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); - const quota: u32 = @intCast(try sema.resolveInt(block, src, inst_data.operand, Type.u32, .{ - .needed_comptime_reason = "eval branch quota must be comptime-known", - })); + const quota: u32 = @intCast(try sema.resolveInt(block, src, inst_data.operand, .u32, .{ .simple = .operand_setEvalBranchQuota })); sema.branch_quota = @max(sema.branch_quota, quota); sema.allow_memoize = false; } @@ -5794,9 +5851,7 @@ fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); - const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, .{ - .needed_comptime_reason = "compile error string must be comptime-known", - }); + const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, .{ .simple = .compile_error_string }); return sema.fail(block, src, "{s}", .{msg}); } @@ -5848,7 +5903,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void // source location if we do it here. const coerced_msg = try sema.coerce(block, Type.slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0)); - if (block.is_comptime) { + if (block.isComptime()) { return sema.fail(block, src, "encountered @panic at comptime", .{}); } @@ -5864,7 +5919,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const src_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].node; const src = block.nodeOffset(src_node); - if (block.is_comptime) + if (block.isComptime()) return sema.fail(block, src, "encountered @trap at comptime", .{}); _ = try block.addNoOp(.trap); } @@ -5974,15 +6029,16 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr var c_import_buf = std.ArrayList(u8).init(gpa); defer c_import_buf.deinit(); - const comptime_reason: Block.ComptimeReason = .{ .c_import = .{ .src = src } }; var child_block: Block = .{ .parent = parent_block, .sema = sema, .namespace = parent_block.namespace, .instructions = .{}, .inlining = parent_block.inlining, - .is_comptime = true, - .comptime_reason = &comptime_reason, + .comptime_reason = .{ .reason = .{ + .src = src, + .r = .{ .simple = .operand_cImport }, + } }, .c_import_buf = &c_import_buf, .runtime_cond = parent_block.runtime_cond, .runtime_loop = parent_block.runtime_loop, @@ -6073,7 +6129,7 @@ fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) Comp return sema.failWithUseOfAsync(parent_block, src); } -fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Air.Inst.Ref { +fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -6109,7 +6165,6 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt .instructions = .{}, .label = &label, .inlining = parent_block.inlining, - .is_comptime = parent_block.is_comptime or force_comptime, .comptime_reason = parent_block.comptime_reason, .is_typeof = parent_block.is_typeof, .want_safety = parent_block.want_safety, @@ -6143,7 +6198,7 @@ fn resolveBlockBody( body_inst: Zir.Inst.Index, merges: *Block.Merges, ) CompileError!Air.Inst.Ref { - if (child_block.is_comptime) { + if (child_block.isComptime()) { return sema.resolveInlineBody(child_block, body, body_inst); } else { assert(sema.air_instructions.items(.tag)[@intFromEnum(merges.block_inst)] == .block); @@ -6303,7 +6358,7 @@ fn resolveAnalyzedBlock( } } // It is impossible to have the number of results be > 1 in a comptime scope. - assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition. + assert(!child_block.isComptime()); // Should already got a compile error in the condbr condition. // Note that we'll always create an AIR block here, so `need_debug_scope` is irrelevant. @@ -6425,9 +6480,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const options_src = block.builtinCallArgSrc(inst_data.src_node, 1); const ptr = try sema.resolveInst(extra.exported); - const ptr_val = try sema.resolveConstDefinedValue(block, ptr_src, ptr, .{ - .needed_comptime_reason = "export target must be comptime-known", - }); + const ptr_val = try sema.resolveConstDefinedValue(block, ptr_src, ptr, .{ .simple = .export_target }); const ptr_ty = ptr_val.typeOf(zcu); const options = try sema.resolveExportOptions(block, options_src, extra.options); @@ -6553,17 +6606,13 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src = block.builtinCallArgSrc(extra.node, 0); - block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", .{ - .needed_comptime_reason = "operand to @setFloatMode must be comptime-known", - }); + block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", .{ .simple = .operand_setFloatMode }); } fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); - block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, .{ - .needed_comptime_reason = "operand to @setRuntimeSafety must be comptime-known", - }); + block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, .{ .simple = .operand_setRuntimeSafety }); } fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { @@ -6650,7 +6699,7 @@ fn zirSwitchContinue(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) Com } fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - if (block.is_comptime or block.ownerModule().strip) return; + if (block.isComptime() or block.ownerModule().strip) return; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; @@ -6676,7 +6725,7 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi } fn zirDbgEmptyStmt(_: *Sema, block: *Block, _: Zir.Inst.Index) CompileError!void { - if (block.is_comptime or block.ownerModule().strip) return; + if (block.isComptime() or block.ownerModule().strip) return; _ = try block.addNoOp(.dbg_empty_stmt); } @@ -6699,7 +6748,7 @@ fn addDbgVar( air_tag: Air.Inst.Tag, name: []const u8, ) CompileError!void { - if (block.is_comptime or block.ownerModule().strip) return; + if (block.isComptime() or block.ownerModule().strip) return; const pt = sema.pt; const zcu = pt.zcu; @@ -6931,7 +6980,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const zcu = pt.zcu; const gpa = sema.gpa; - if (block.is_comptime or block.is_typeof) { + if (block.isComptime() or block.is_typeof) { const index_val = try pt.intValue_u64(Type.usize, sema.comptime_err_ret_trace.items.len); return Air.internedToRef(index_val.toIntern()); } @@ -7134,7 +7183,7 @@ fn zirCall( } if (block.ownerModule().error_tracing and - !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) + !block.isComptime() and !block.is_typeof and (input_is_error or pop_error_return_trace)) { const return_ty = sema.typeOf(call_inst); if (modifier != .always_tail and return_ty.isNoReturn(zcu)) @@ -7404,12 +7453,14 @@ const CallArgsInfo = union(enum) { }; // Generate args to comptime params in comptime block - const parent_comptime = block.is_comptime; - defer block.is_comptime = parent_comptime; + const parent_comptime = block.comptime_reason; + defer block.comptime_reason = parent_comptime; // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx` if (arg_index < @min(param_count, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) { - block.is_comptime = true; - // TODO set comptime_reason + block.comptime_reason = .{ .reason = .{ + .src = cai.argSrc(block, arg_index), + .r = .{ .simple = .comptime_param_arg }, + } }; } // Give the arg its result type const provide_param_ty = if (maybe_param_ty) |t| t else Type.generic_poison; @@ -7611,23 +7662,37 @@ fn analyzeCall( const gpa = sema.gpa; + const func_ret_ty_src: LazySrcLoc = if (try sema.funcDeclSrcInst(func)) |fn_decl_inst| .{ + .base_node_inst = fn_decl_inst, + .offset = .{ .node_offset_fn_type_ret_ty = 0 }, + } else func_src; + + // If this is not `null`, the call is comptime. + var comptime_call_reason: ?BlockComptimeReason = cr: { + if (block.comptime_reason) |r| break :cr r; + if (modifier == .compile_time) break :cr .{ .reason = .{ + .src = call_src, + .r = .{ .simple = .comptime_call_modifier }, + } }; + break :cr null; + }; + const is_generic_call = func_ty_info.is_generic; - var is_comptime_call = block.is_comptime or modifier == .compile_time; - var is_inline_call = is_comptime_call or modifier == .always_inline or func_ty_info.cc == .@"inline"; - var comptime_reason: ?*const Block.ComptimeReason = null; - if (!is_inline_call and !is_comptime_call) { + var is_inline_call = comptime_call_reason != null or modifier == .always_inline or func_ty_info.cc == .@"inline"; + if (!is_inline_call) { if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) { - is_comptime_call = true; is_inline_call = true; - comptime_reason = &.{ .comptime_ret_ty = .{ - .func = func, - .func_src = func_src, - .return_ty = Type.fromInterned(func_ty_info.return_type), + comptime_call_reason = .{ .reason = .{ + .src = func_ret_ty_src, + .r = .{ .comptime_only = .{ + .ty = .fromInterned(func_ty_info.return_type), + .msg = .ret_ty_call, + } }, } }; } } - if (sema.func_is_naked and !is_inline_call and !is_comptime_call) { + if (sema.func_is_naked and !is_inline_call) { const msg = msg: { const msg = try sema.errMsg(call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)}); errdefer msg.destroy(sema.gpa); @@ -7642,6 +7707,7 @@ fn analyzeCall( } if (!is_inline_call and is_generic_call) { + var comptime_ret_ty: Type = undefined; if (sema.instantiateGenericCall( block, func, @@ -7651,6 +7717,7 @@ fn analyzeCall( args_info, call_tag, call_dbg_node, + &comptime_ret_ty, )) |some| { return some; } else |err| switch (err) { @@ -7659,26 +7726,34 @@ fn analyzeCall( }, error.ComptimeReturn => { is_inline_call = true; - is_comptime_call = true; - comptime_reason = &.{ .comptime_ret_ty = .{ - .func = func, - .func_src = func_src, - .return_ty = Type.fromInterned(func_ty_info.return_type), + comptime_call_reason = .{ .reason = .{ + .src = func_ret_ty_src, + .r = .{ + .comptime_only = .{ + .ty = comptime_ret_ty, + .msg = .ret_ty_generic_call, + }, + }, } }; }, else => |e| return e, } } + const is_comptime_call = comptime_call_reason != null; + // `comptime_call_reason` shouldn't be mutated again + defer assert(is_comptime_call == (comptime_call_reason != null)); + if (is_comptime_call and modifier == .never_inline) { return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{}); } const result: Air.Inst.Ref = if (is_inline_call) res: { - const func_val = try sema.resolveConstDefinedValue(block, func_src, func, .{ - .needed_comptime_reason = "function being called at comptime must be comptime-known", - .block_comptime_reason = comptime_reason, - }); + const old_comptime_reason = block.comptime_reason; + block.comptime_reason = comptime_call_reason; + defer block.comptime_reason = old_comptime_reason; + + const func_val = try sema.resolveConstDefinedValue(block, func_src, func, .{ .simple = .comptime_call_target }); const module_fn_index = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { .@"extern" => return sema.fail(block, call_src, "{s} call of extern function", .{ @as([]const u8, if (is_comptime_call) "comptime" else "inline"), @@ -7767,8 +7842,7 @@ fn analyzeCall( .label = null, .inlining = &inlining, .is_typeof = block.is_typeof, - .is_comptime = is_comptime_call, - .comptime_reason = comptime_reason, + .comptime_reason = if (is_comptime_call) .inlining_parent else null, .error_return_trace_index = block.error_return_trace_index, .runtime_cond = block.runtime_cond, .runtime_loop = block.runtime_loop, @@ -7857,11 +7931,16 @@ fn analyzeCall( // on parameters, we must now do the same for the return type as we just did with // each of the parameters, resolving the return type and providing it to the child // `Sema` so that it can be used for the `ret_ptr` instruction. - const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) - try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail) - else - try sema.resolveInst(fn_info.ret_ty_ref); const ret_ty_src: LazySrcLoc = .{ .base_node_inst = module_fn.zir_body_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 } }; + const ret_ty_inst = if (fn_info.ret_ty_body.len != 0) r: { + const old_child_comptime_reason = child_block.comptime_reason; + defer child_block.comptime_reason = old_child_comptime_reason; + child_block.comptime_reason = .{ .reason = .{ + .src = ret_ty_src, + .r = .{ .simple = .function_ret_ty }, + } }; + break :r try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail); + } else try sema.resolveInst(fn_info.ret_ty_ref); sema.fn_ret_ty = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst); if (module_fn.analysisUnordered(ip).inferred_error_set) { // Create a fresh inferred error set type for inline/comptime calls. @@ -8136,23 +8215,18 @@ fn analyzeInlineCallArg( return casted_arg; } const arg_src = args_info.argSrc(arg_block, arg_i.*); - if (try Type.fromInterned(param_ty).comptimeOnlySema(ics.callee().pt)) { - _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ - .needed_comptime_reason = "argument to parameter with comptime-only type must be comptime-known", - .block_comptime_reason = param_block.comptime_reason, - }); - } else if (!is_comptime_call and zir_tags[@intFromEnum(inst)] == .param_comptime) { - _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ - .needed_comptime_reason = "parameter is comptime", - }); + if (zir_tags[@intFromEnum(inst)] == .param_comptime) { + _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ .simple = .comptime_param_arg }); + } else if (!is_comptime_call and try Type.fromInterned(param_ty).comptimeOnlySema(ics.callee().pt)) { + _ = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ .comptime_only = .{ + .ty = .fromInterned(param_ty), + .msg = .param_ty_arg, + } }); } if (is_comptime_call) { ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg); - const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, .{ - .needed_comptime_reason = "argument to function being called at comptime must be comptime-known", - .block_comptime_reason = param_block.comptime_reason, - }); + const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, casted_arg, null); switch (arg_val.toIntern()) { .generic_poison, .generic_poison_type => { // This function is currently evaluated as part of an as-of-yet unresolvable @@ -8188,10 +8262,7 @@ fn analyzeInlineCallArg( if (is_comptime_call) { ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); - const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, .{ - .needed_comptime_reason = "argument to function being called at comptime must be comptime-known", - .block_comptime_reason = param_block.comptime_reason, - }); + const arg_val = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, null); switch (arg_val.toIntern()) { .generic_poison, .generic_poison_type => { // This function is currently evaluated as part of an as-of-yet unresolvable @@ -8208,9 +8279,7 @@ fn analyzeInlineCallArg( memoized_arg_values[arg_i.*] = resolved_arg_val.toIntern(); } else { if (zir_tags[@intFromEnum(inst)] == .param_anytype_comptime) { - _ = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, .{ - .needed_comptime_reason = "parameter is comptime", - }); + _ = try ics.caller().resolveConstValue(arg_block, arg_src, uncasted_arg, .{ .simple = .comptime_param_arg }); } ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); } @@ -8237,15 +8306,18 @@ fn instantiateGenericCall( args_info: CallArgsInfo, call_tag: Air.Inst.Tag, call_dbg_node: ?Zir.Inst.Index, + /// Populated when `error.ComptimeReturn` is returned. + comptime_ret_ty: *Type, ) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; const gpa = sema.gpa; const ip = &zcu.intern_pool; - const func_val = try sema.resolveConstDefinedValue(block, func_src, func, .{ - .needed_comptime_reason = "generic function being called must be comptime-known", - }); + // Generic function pointers are comptime-only types, so `func` is definitely comptime-known. + const func_val = (sema.resolveValue(func) catch unreachable).?; + if (func_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, func_src); + const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { .func => func_val.toIntern(), .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.fully_resolved.val, @@ -8310,7 +8382,7 @@ fn instantiateGenericCall( .namespace = fn_nav.analysis.?.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = undefined, // set as needed .src_base_inst = fn_nav.analysis.?.zir_index, .type_name_ctx = fn_nav.fqn, }; @@ -8354,12 +8426,13 @@ fn instantiateGenericCall( child_sema.generic_call_src = prev_generic_call_src; } + const param_ty_src = child_block.tokenOffset(param_data.src_tok); + child_block.comptime_reason = .{ .reason = .{ + .src = param_ty_src, + .r = .{ .simple = .type }, + } }; const param_ty_inst = try child_sema.resolveInlineBody(&child_block, param_ty_body, param_inst); - break :param_ty try child_sema.analyzeAsType( - &child_block, - child_block.tokenOffset(param_data.src_tok), - param_ty_inst, - ); + break :param_ty try child_sema.analyzeAsType(&child_block, param_ty_src, param_ty_inst); }, else => unreachable, } @@ -8452,6 +8525,10 @@ fn instantiateGenericCall( // We've already handled parameters, so don't resolve the whole body. Instead, just // do the instructions after the params (i.e. the func itself). + child_block.comptime_reason = .{ .reason = .{ + .src = call_src, + .r = .{ .simple = .type }, + } }; const new_func_inst = try child_sema.resolveInlineBody(&child_block, fn_info.param_body[args_info.count()..], fn_info.param_body_inst); const callee_index = (child_sema.resolveConstDefinedValue(&child_block, LazySrcLoc.unneeded, new_func_inst, undefined) catch unreachable).toIntern(); @@ -8465,6 +8542,7 @@ fn instantiateGenericCall( // If the call evaluated to a return type that requires comptime, never mind // our generic instantiation. Instead we need to perform a comptime call. if (try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) { + comptime_ret_ty.* = .fromInterned(func_ty_info.return_type); return error.ComptimeReturn; } // Similarly, if the call evaluated to a generic type we need to instead @@ -8622,9 +8700,7 @@ fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const len_src = block.builtinCallArgSrc(inst_data.src_node, 0); const elem_type_src = block.builtinCallArgSrc(inst_data.src_node, 1); const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; - const len: u32 = @intCast(try sema.resolveInt(block, len_src, extra.lhs, Type.u32, .{ - .needed_comptime_reason = "vector length must be comptime-known", - })); + const len: u32 = @intCast(try sema.resolveInt(block, len_src, extra.lhs, Type.u32, .{ .simple = .vector_length })); const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); try sema.checkVectorElemType(block, elem_type_src, elem_type); const vector_type = try sema.pt.vectorType(.{ @@ -8642,9 +8718,7 @@ fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node }); const elem_src = block.src(.{ .node_offset_array_type_elem = inst_data.src_node }); - const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, .{ - .needed_comptime_reason = "array length must be comptime-known", - }); + const len = try sema.resolveInt(block, len_src, extra.lhs, Type.usize, .{ .simple = .array_length }); const elem_type = try sema.resolveType(block, elem_src, extra.rhs); try sema.validateArrayElemType(block, elem_type, elem_src); const array_ty = try sema.pt.arrayType(.{ @@ -8664,16 +8738,12 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node }); const sentinel_src = block.src(.{ .node_offset_array_type_sentinel = inst_data.src_node }); const elem_src = block.src(.{ .node_offset_array_type_elem = inst_data.src_node }); - const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, .{ - .needed_comptime_reason = "array length must be comptime-known", - }); + const len = try sema.resolveInt(block, len_src, extra.len, Type.usize, .{ .simple = .array_length }); const elem_type = try sema.resolveType(block, elem_src, extra.elem_type); try sema.validateArrayElemType(block, elem_type, elem_src); const uncasted_sentinel = try sema.resolveInst(extra.sentinel); const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); - const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ - .needed_comptime_reason = "array sentinel value must be comptime-known", - }); + const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel }); const array_ty = try sema.pt.arrayType(.{ .len = len, .sentinel = sentinel_val.toIntern(), @@ -9071,9 +9141,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } if (dest_ty.intTagType(zcu).zigTypeTag(zcu) == .comptime_int) { - return sema.failWithNeededComptime(block, operand_src, .{ - .needed_comptime_reason = "value being casted to enum with 'comptime_int' tag type must be comptime-known", - }); + return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum }); } if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { @@ -9487,9 +9555,7 @@ fn zirFunc( const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_body_len); extra_index += ret_ty_body.len; - const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, .{ - .needed_comptime_reason = "return type must be comptime-known", - }); + const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, .{ .simple = .function_ret_ty }); break :blk ret_ty_val.toType(); }, }; @@ -9556,7 +9622,7 @@ fn resolveGenericBody( body: []const Zir.Inst.Index, func_inst: Zir.Inst.Index, dest_ty: Type, - reason: NeededComptimeReason, + reason: ComptimeReason, ) !Value { assert(body.len != 0); @@ -9894,7 +9960,7 @@ fn funcCommon( }; return sema.failWithOwnedErrorMsg(block, msg); } - if (is_source_decl and requires_comptime and !param_is_comptime and has_body and !block.is_comptime) { + if (is_source_decl and requires_comptime and !param_is_comptime and has_body and !block.isComptime()) { const msg = msg: { const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{ param_ty.fmt(pt), @@ -10132,7 +10198,7 @@ fn finishFunc( // If the return type is comptime-only but not dependent on parameters then // all parameter types also need to be comptime. - if (is_source_decl and opt_func_index != .none and ret_ty_requires_comptime and !block.is_comptime) comptime_check: { + if (is_source_decl and opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: { for (block.params.items(.is_comptime)) |is_comptime| { if (!is_comptime) break; } else break :comptime_check; @@ -10547,9 +10613,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; const object = try sema.resolveInst(extra.lhs); - const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ - .needed_comptime_reason = "field name must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name }); return sema.fieldVal(block, src, object, field_name, field_name_src); } @@ -10562,9 +10626,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; const object_ptr = try sema.resolveInst(extra.lhs); - const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ - .needed_comptime_reason = "field name must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name }); return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); } @@ -11923,7 +11985,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp .instructions = .{}, .label = &label, .inlining = block.inlining, - .is_comptime = block.is_comptime, .comptime_reason = block.comptime_reason, .is_typeof = block.is_typeof, .c_import_buf = block.c_import_buf, @@ -12027,11 +12088,8 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp }; } - if (child_block.is_comptime) { - _ = try sema.resolveConstDefinedValue(&child_block, main_operand_src, raw_operand_val, .{ - .needed_comptime_reason = "condition in comptime switch must be comptime-known", - .block_comptime_reason = child_block.comptime_reason, - }); + if (child_block.isComptime()) { + _ = try sema.resolveConstDefinedValue(&child_block, main_operand_src, raw_operand_val, null); unreachable; } @@ -12148,7 +12206,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r const operand_ty = sema.typeOf(val); - if (extra.data.bits.has_continue and !block.is_comptime) { + if (extra.data.bits.has_continue and !block.isComptime()) { // Even if the operand is comptime-known, this `switch` is runtime. if (try operand_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { @@ -12707,7 +12765,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r .instructions = .{}, .label = &label, .inlining = block.inlining, - .is_comptime = block.is_comptime, .comptime_reason = block.comptime_reason, .is_typeof = block.is_typeof, .c_import_buf = block.c_import_buf, @@ -12790,11 +12847,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r }, } - if (child_block.is_comptime) { - _ = try sema.resolveConstDefinedValue(&child_block, operand_src, operand.simple.cond, .{ - .needed_comptime_reason = "condition in comptime switch must be comptime-known", - .block_comptime_reason = child_block.comptime_reason, - }); + if (child_block.isComptime()) { + _ = try sema.resolveConstDefinedValue(&child_block, operand_src, operand.simple.cond, null); unreachable; } @@ -13582,10 +13636,7 @@ fn resolveSwitchComptimeLoop( const cond_ref = try sema.switchCond(child_block, src, val); - cond_val = try sema.resolveConstDefinedValue(child_block, src, cond_ref, .{ - .needed_comptime_reason = "condition in comptime switch must be comptime-known", - .block_comptime_reason = child_block.comptime_reason, - }); + cond_val = try sema.resolveConstDefinedValue(child_block, src, cond_ref, null); spa.operand = .{ .simple = .{ .by_val = val, .by_ref = ref, @@ -13825,9 +13876,7 @@ fn resolveSwitchItemVal( const item = try sema.coerce(block, coerce_ty, uncoerced_item, item_src); - const maybe_lazy = try sema.resolveConstDefinedValue(block, item_src, item, .{ - .needed_comptime_reason = "switch prong values must be comptime-known", - }); + const maybe_lazy = try sema.resolveConstDefinedValue(block, item_src, item, .{ .simple = .switch_item }); const val = try sema.resolveLazyValue(maybe_lazy); const new_item = if (val.toIntern() != maybe_lazy.toIntern()) blk: { @@ -14295,9 +14344,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); const name_src = block.builtinCallArgSrc(inst_data.src_node, 1); const ty = try sema.resolveType(block, ty_src, extra.lhs); - const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ - .needed_comptime_reason = "field name must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name }); try ty.resolveFields(pt); const ip = &zcu.intern_pool; @@ -14344,9 +14391,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0); const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1); const container_type = try sema.resolveType(block, lhs_src, extra.lhs); - const decl_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, .{ - .needed_comptime_reason = "decl name must be comptime-known", - }); + const decl_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, .{ .simple = .decl_name }); try sema.checkNamespaceType(block, lhs_src, container_type); @@ -14399,9 +14444,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const pt = sema.pt; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); - const name = try sema.resolveConstString(block, operand_src, inst_data.operand, .{ - .needed_comptime_reason = "file path name must be comptime-known", - }); + const name = try sema.resolveConstString(block, operand_src, inst_data.operand, .{ .simple = .operand_embedFile }); if (name.len == 0) { return sema.fail(block, operand_src, "file path name cannot be empty", .{}); @@ -14589,7 +14632,7 @@ fn zirShl( }), } }, }); - const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); + const ov_bit = try sema.tupleFieldValByIndex(block, op_ov, 1, op_ov_tuple_ty); const any_ov_bit = if (lhs_ty.zigTypeTag(zcu) == .vector) try block.addInst(.{ .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce, @@ -14604,7 +14647,7 @@ fn zirShl( const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); try sema.addSafetyCheck(block, src, no_ov, .shl_overflow); - return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); + return sema.tupleFieldValByIndex(block, op_ov, 0, op_ov_tuple_ty); } } return block.addBinOp(air_tag, lhs, new_rhs); @@ -14932,20 +14975,12 @@ fn analyzeTupleCat( const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); var i: u32 = 0; while (i < lhs_len) : (i += 1) { - const operand_src = block.src(.{ .array_cat_lhs = .{ - .array_cat_offset = src_node, - .elem_index = i, - } }); - element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, i, lhs_ty); + element_refs[i] = try sema.tupleFieldValByIndex(block, lhs, i, lhs_ty); } i = 0; while (i < rhs_len) : (i += 1) { - const operand_src = block.src(.{ .array_cat_rhs = .{ - .array_cat_offset = src_node, - .elem_index = i, - } }); element_refs[i + lhs_len] = - try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); + try sema.tupleFieldValByIndex(block, rhs, i, rhs_ty); } return block.addAggregateInit(Type.fromInterned(tuple_ty), element_refs); @@ -14985,7 +15020,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const resolved_elem_ty = t: { var trash_block = block.makeSubBlock(); - trash_block.is_comptime = false; + trash_block.comptime_reason = null; defer trash_block.instructions.deinit(sema.gpa); const instructions = [_]Air.Inst.Ref{ @@ -15268,9 +15303,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins const ptr_info = operand_ty.ptrInfo(zcu); switch (ptr_info.flags.size) { .Slice => { - const val = try sema.resolveConstDefinedValue(block, src, operand, .{ - .needed_comptime_reason = "slice value being concatenated must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(block, src, operand, .{ .simple = .slice_cat_operand }); return Type.ArrayInfo{ .elem_type = Type.fromInterned(ptr_info.child), .sentinel = switch (ptr_info.sentinel) { @@ -15365,11 +15398,7 @@ fn analyzeTupleMul( const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len); var i: u32 = 0; while (i < tuple_len) : (i += 1) { - const operand_src = block.src(.{ .array_cat_lhs = .{ - .array_cat_offset = src_node, - .elem_index = i, - } }); - element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(i), operand_ty); + element_refs[i] = try sema.tupleFieldValByIndex(block, operand, @intCast(i), operand_ty); } i = 1; while (i < factor) : (i += 1) { @@ -15431,9 +15460,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (lhs_ty.isTuple(zcu)) { // In `**` rhs must be comptime-known, but lhs can be runtime-known - const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, .{ - .needed_comptime_reason = "array multiplication factor must be comptime-known", - }); + const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, .{ .simple = .array_mul_factor }); const factor_casted = try sema.usizeCast(block, rhs_src, factor); return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted); } @@ -15455,9 +15482,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }; // In `**` rhs must be comptime-known, but lhs can be runtime-known - const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, .{ - .needed_comptime_reason = "array multiplication factor must be comptime-known", - }); + const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, .{ .simple = .array_mul_factor }); const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch return sema.fail(block, rhs_src, "operation results in overflow", .{}); @@ -17471,7 +17496,7 @@ fn analyzeArithmetic( }), } }, }); - const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); + const ov_bit = try sema.tupleFieldValByIndex(block, op_ov, 1, op_ov_tuple_ty); const any_ov_bit = if (resolved_type.zigTypeTag(zcu) == .vector) try block.addInst(.{ .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce, @@ -17486,7 +17511,7 @@ fn analyzeArithmetic( const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); try sema.addSafetyCheck(block, src, no_ov, .integer_overflow); - return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); + return sema.tupleFieldValByIndex(block, op_ov, 0, op_ov_tuple_ty); } } } @@ -17635,12 +17660,9 @@ fn zirAsm( const is_global_assembly = sema.func_index == .none; const zir_tags = sema.code.instructions.items(.tag); - const asm_source: []const u8 = if (tmpl_is_expr) blk: { + const asm_source: []const u8 = if (tmpl_is_expr) s: { const tmpl: Zir.Inst.Ref = @enumFromInt(@intFromEnum(extra.data.asm_source)); - const s: []const u8 = try sema.resolveConstString(block, src, tmpl, .{ - .needed_comptime_reason = "assembly code must be comptime-known", - }); - break :blk s; + break :s try sema.resolveConstString(block, src, tmpl, .{ .simple = .inline_assembly_code }); } else sema.code.nullTerminatedString(extra.data.asm_source); if (is_global_assembly) { @@ -18203,7 +18225,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat return sema.failWithOwnedErrorMsg(block, msg); } - if (!block.is_typeof and !block.is_comptime and sema.func_index != .none) { + if (!block.is_typeof and !block.isComptime() and sema.func_index != .none) { const msg = msg: { const name = name: { const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?; @@ -18244,7 +18266,7 @@ fn zirRetAddr( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { _ = extended; - if (block.is_comptime) { + if (block.isComptime()) { // TODO: we could give a meaningful lazy value here. #14938 return sema.pt.intRef(Type.usize, 0); } else { @@ -19342,7 +19364,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr .namespace = block.namespace, .instructions = .{}, .inlining = block.inlining, - .is_comptime = false, + .comptime_reason = null, .is_typeof = true, .want_safety = false, .error_return_trace_index = block.error_return_trace_index, @@ -19422,7 +19444,7 @@ fn zirTypeofPeer( .namespace = block.namespace, .instructions = .{}, .inlining = block.inlining, - .is_comptime = false, + .comptime_reason = null, .is_typeof = true, .runtime_cond = block.runtime_cond, .runtime_loop = block.runtime_loop, @@ -19980,7 +20002,7 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label .instructions = .{}, .label = &labeled_block.label, .inlining = block.inlining, - .is_comptime = block.is_comptime, + .comptime_reason = block.comptime_reason, .src_base_inst = block.src_base_inst, .type_name_ctx = block.type_name_ctx, }, @@ -20013,7 +20035,7 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"unreachable"; const src = block.nodeOffset(inst_data.src_node); - if (block.is_comptime) { + if (block.isComptime()) { return sema.fail(block, src, "reached unreachable code", .{}); } // TODO Add compile error for @optimizeFor occurring too late in a scope. @@ -20066,7 +20088,7 @@ fn zirRetImplicit( const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok; const r_brace_src = block.tokenOffset(inst_data.src_tok); if (block.inlining == null and sema.func_is_naked) { - assert(!block.is_comptime); + assert(!block.isComptime()); if (block.wantSafety()) { // Calling a safety function from a naked function would not be legal. _ = try block.addNoOp(.trap); @@ -20123,7 +20145,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi const src = block.nodeOffset(inst_data.src_node); const ret_ptr = try sema.resolveInst(inst_data.operand); - if (block.is_comptime or block.inlining != null or sema.func_is_naked) { + if (block.isComptime() or block.inlining != null or sema.func_is_naked) { const operand = try sema.analyzeLoad(block, src, ret_ptr, src); return sema.analyzeRet(block, operand, src, block.src(.{ .node_offset_return_operand = inst_data.src_node })); } @@ -20215,7 +20237,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE if (!block.ownerModule().error_tracing) return; // This is only relevant at runtime. - if (block.is_comptime or block.is_typeof) return; + if (block.isComptime() or block.is_typeof) return; const save_index = inst_data.operand == .none or b: { const operand = try sema.resolveInst(inst_data.operand); @@ -20268,7 +20290,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_ const operand = try sema.resolveInstAllowNone(operand_zir); - if (start_block.is_comptime or start_block.is_typeof) { + if (start_block.isComptime() or start_block.is_typeof) { const is_non_error = if (operand != .none) blk: { const is_non_error_inst = try sema.analyzeIsNonErr(start_block, src, operand); const cond_val = try sema.resolveDefinedValue(start_block, src, is_non_error_inst); @@ -20345,10 +20367,8 @@ fn analyzeRet( }; if (block.inlining) |inlining| { - if (block.is_comptime) { - const ret_val = try sema.resolveConstValue(block, operand_src, operand, .{ - .needed_comptime_reason = "value being returned at comptime must be comptime-known", - }); + if (block.isComptime()) { + const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); inlining.comptime_result = operand; if (sema.fn_ret_ty.isError(zcu) and ret_val.getErrorName(zcu) != .none) { @@ -20362,7 +20382,7 @@ fn analyzeRet( try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?); try inlining.merges.src_locs.append(sema.gpa, operand_src); return; - } else if (block.is_comptime) { + } else if (block.isComptime()) { return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{}); } else if (sema.func_is_naked) { const msg = msg: { @@ -20436,9 +20456,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]); extra_i += 1; const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src); - const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ - .needed_comptime_reason = "pointer sentinel value must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ .simple = .pointer_sentinel }); try checkSentinelType(sema, block, sentinel_src, elem_ty); break :blk val.toIntern(); } else .none; @@ -20447,9 +20465,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]); extra_i += 1; const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); - const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ - .needed_comptime_reason = "pointer alignment must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" }); // Check if this happens to be the lazy alignment of our element type, in // which case we can make this 0 without resolving it. switch (zcu.intern_pool.indexToKey(val.toIntern())) { @@ -20472,18 +20488,14 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const bit_offset: u16 = if (inst_data.flags.has_bit_range) blk: { const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]); extra_i += 1; - const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, .{ - .needed_comptime_reason = "pointer bit-offset must be comptime-known", - }); + const bit_offset = try sema.resolveInt(block, bitoffset_src, ref, Type.u16, .{ .simple = .type }); break :blk @intCast(bit_offset); } else 0; const host_size: u16 = if (inst_data.flags.has_bit_range) blk: { const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]); extra_i += 1; - const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, .{ - .needed_comptime_reason = "pointer host size must be comptime-known", - }); + const host_size = try sema.resolveInt(block, hostsize_src, ref, Type.u16, .{ .simple = .type }); break :blk @intCast(host_size); } else 0; @@ -20671,9 +20683,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (union_ty.zigTypeTag(pt.zcu) != .@"union") { return sema.fail(block, ty_src, "expected union type, found '{}'", .{union_ty.fmt(pt)}); } - const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ - .needed_comptime_reason = "name of field being initialized must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name }); const init = try sema.resolveInst(extra.init); return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); } @@ -20800,9 +20810,7 @@ fn zirStructInit( try resolved_ty.resolveStructFieldInits(pt); if (try resolved_ty.structFieldValueComptime(pt, field_index)) |default_value| { const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { - return sema.failWithNeededComptime(block, field_src, .{ - .needed_comptime_reason = "value stored in comptime field must be comptime-known", - }); + return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); }; if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) { @@ -20862,9 +20870,10 @@ fn zirStructInit( } if (try resolved_ty.comptimeOnlySema(pt)) { - return sema.failWithNeededComptime(block, field_src, .{ - .needed_comptime_reason = "initializer of comptime only union must be comptime-known", - }); + return sema.failWithNeededComptime(block, field_src, .{ .comptime_only = .{ + .ty = resolved_ty, + .msg = .union_init, + } }); } try sema.validateRuntimeValue(block, field_src, init_inst); @@ -21003,9 +21012,10 @@ fn finishStructInit( return sema.failWithNeededComptime(block, block.src(.{ .init_elem = .{ .init_node_offset = init_src.offset.node_offset.x, .elem_index = @intCast(runtime_index), - } }), .{ - .needed_comptime_reason = "initializer of comptime only struct must be comptime-known", - }); + } }), .{ .comptime_only = .{ + .ty = struct_ty, + .msg = .struct_init, + } }); } for (field_inits) |field_init| { @@ -21315,11 +21325,7 @@ fn zirArrayInit( if (array_ty.structFieldIsComptime(i, zcu)) try array_ty.resolveStructFieldInits(pt); if (try array_ty.structFieldValueComptime(pt, i)) |field_val| { - const init_val = try sema.resolveValue(dest.*) orelse { - return sema.failWithNeededComptime(block, elem_src, .{ - .needed_comptime_reason = "value stored in comptime field must be comptime-known", - }); - }; + const init_val = try sema.resolveConstValue(block, elem_src, dest.*, .{ .simple = .stored_to_comptime_field }); if (!field_val.eql(init_val, elem_ty, zcu)) { return sema.failWithInvalidComptimeFieldStore(block, elem_src, array_ty, i); } @@ -21508,9 +21514,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); const field_src = block.builtinCallArgSrc(inst_data.src_node, 1); const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); - const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ - .needed_comptime_reason = "field name must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name }); return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); } @@ -21890,9 +21894,7 @@ fn zirReify( const type_info_ty = try sema.getBuiltinType("Type"); const uncasted_operand = try sema.resolveInst(extra.operand); const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); - const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ - .needed_comptime_reason = "operand to @Type must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ .simple = .operand_Type }); const union_val = ip.indexToKey(val.toIntern()).un; if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) { return sema.failWithUseOfUndef(block, operand_src); @@ -22136,9 +22138,7 @@ fn zirReify( const payload_val = Value.fromInterned(union_val.val).optionalValue(zcu) orelse return Air.internedToRef(Type.anyerror.toIntern()); - const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ - .needed_comptime_reason = "error set contents must be comptime-known", - }); + const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ .simple = .error_set_contents }); const len = try sema.usizeCast(block, src, names_val.typeOf(zcu).arrayLen(zcu)); var names: InferredErrorSet.NameMap = .{}; @@ -22151,9 +22151,7 @@ fn zirReify( try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), ).?); - const name = try sema.sliceToIpString(block, src, name_val, .{ - .needed_comptime_reason = "error set contents must be comptime-known", - }); + const name = try sema.sliceToIpString(block, src, name_val, .{ .simple = .error_set_contents }); _ = try pt.getErrorValue(name); const gop = names.getOrPutAssumeCapacity(name); if (gop.found_existing) { @@ -22200,9 +22198,7 @@ fn zirReify( return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); } - const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ - .needed_comptime_reason = "struct fields must be comptime-known", - }); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .struct_fields }); if (is_tuple_val.toBool()) { switch (layout) { @@ -22238,9 +22234,7 @@ fn zirReify( return sema.fail(block, src, "reified enums must have no decls", .{}); } - const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ - .needed_comptime_reason = "enum fields must be comptime-known", - }); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .enum_fields }); return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy); }, @@ -22311,9 +22305,7 @@ fn zirReify( } const layout = zcu.toEnum(std.builtin.Type.ContainerLayout, layout_val); - const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ - .needed_comptime_reason = "union fields must be comptime-known", - }); + const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields }); return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy); }, @@ -22354,9 +22346,7 @@ fn zirReify( const return_type = return_type_val.optionalValue(zcu) orelse return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); - const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ - .needed_comptime_reason = "function parameters must be comptime-known", - }); + const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ .simple = .function_parameters }); const args_len = try sema.usizeCast(block, src, params_val.typeOf(zcu).arrayLen(zcu)); const param_types = try sema.arena.alloc(InternPool.Index, args_len); @@ -22444,9 +22434,7 @@ fn reifyEnum( const field_name_val = try field_info.fieldValue(pt, 0); const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1)); - const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ - .needed_comptime_reason = "enum field name must be comptime-known", - }); + const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .enum_field_name }); std.hash.autoHash(&hasher, .{ field_name, @@ -22591,9 +22579,7 @@ fn reifyUnion( const field_type_val = try field_info.fieldValue(pt, 1); const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2)); - const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ - .needed_comptime_reason = "union field name must be comptime-known", - }); + const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name }); std.hash.autoHash(&hasher, .{ field_name, @@ -22835,9 +22821,7 @@ fn reifyTuple( const field_is_comptime_val = try field_info.fieldValue(pt, 3); const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4)); - const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ - .needed_comptime_reason = "tuple field name must be comptime-known", - }); + const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .tuple_field_name }); const field_type = field_type_val.toType(); const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: { const ptr_ty = try pt.singleConstPtrType(field_type_val.toType()); @@ -22845,7 +22829,7 @@ fn reifyTuple( const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime( block, src, - .{ .needed_comptime_reason = "tuple field default value must be comptime-known" }, + .{ .simple = .tuple_field_default_value }, ); // Resolve the value so that lazy values do not create distinct types. break :d (try sema.resolveLazyValue(val)).toIntern(); @@ -22951,9 +22935,7 @@ fn reifyStruct( const field_is_comptime_val = try field_info.fieldValue(pt, 3); const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4)); - const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ - .needed_comptime_reason = "struct field name must be comptime-known", - }); + const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .struct_field_name }); const field_is_comptime = field_is_comptime_val.toBool(); const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: { const ptr_ty = try pt.singleConstPtrType(field_type_val.toType()); @@ -22961,7 +22943,7 @@ fn reifyStruct( const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime( block, src, - .{ .needed_comptime_reason = "struct field default value must be comptime-known" }, + .{ .simple = .struct_field_default_value }, ); // Resolve the value so that lazy values do not create distinct types. break :d (try sema.resolveLazyValue(val)).toIntern(); @@ -23285,9 +23267,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty, .truncate); return Air.internedToRef(result_val.toIntern()); } else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) { - return sema.failWithNeededComptime(block, operand_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known", - }); + return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_int }); } try sema.requireRuntimeBlock(block, src, operand_src); @@ -23368,9 +23348,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, pt, .sema); return Air.internedToRef(result_val.toIntern()); } else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) { - return sema.failWithNeededComptime(block, operand_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known", - }); + return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_float }); } try sema.requireRuntimeBlock(block, src, operand_src); @@ -24394,9 +24372,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const ty = try sema.resolveType(block, lhs_src, extra.lhs); - const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, .{ - .needed_comptime_reason = "name of field must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, .{ .simple = .field_name }); const pt = sema.pt; const zcu = pt.zcu; @@ -24850,31 +24826,21 @@ fn resolveExportOptions( const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src); - const name = try sema.toConstString(block, name_src, name_operand, .{ - .needed_comptime_reason = "name of exported value must be comptime-known", - }); + const name = try sema.toConstString(block, name_src, name_operand, .{ .simple = .export_options }); const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src); - const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ - .needed_comptime_reason = "linkage of exported value must be comptime-known", - }); + const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ .simple = .export_options }); const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val); const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "section", .no_embedded_nulls), section_src); - const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ - .needed_comptime_reason = "linksection of exported value must be comptime-known", - }); + const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ .simple = .export_options }); const section = if (section_opt_val.optionalValue(zcu)) |section_val| - try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{ - .needed_comptime_reason = "linksection of exported value must be comptime-known", - }) + try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{ .simple = .export_options }) else null; const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src); - const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ - .needed_comptime_reason = "visibility of exported value must be comptime-known", - }); + const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_operand, .{ .simple = .export_options }); const visibility = zcu.toEnum(std.builtin.SymbolVisibility, visibility_val); if (name.len < 1) { @@ -24901,7 +24867,7 @@ fn resolveBuiltinEnum( src: LazySrcLoc, zir_ref: Zir.Inst.Ref, comptime name: []const u8, - reason: NeededComptimeReason, + reason: ComptimeReason, ) CompileError!@field(std.builtin, name) { const pt = sema.pt; const ty = try sema.getBuiltinType(name); @@ -24916,7 +24882,7 @@ fn resolveAtomicOrder( block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref, - reason: NeededComptimeReason, + reason: ComptimeReason, ) CompileError!std.builtin.AtomicOrder { return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicOrder", reason); } @@ -24927,9 +24893,7 @@ fn resolveAtomicRmwOp( src: LazySrcLoc, zir_ref: Zir.Inst.Ref, ) CompileError!std.builtin.AtomicRmwOp { - return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicRmwOp", .{ - .needed_comptime_reason = "@atomicRmW operation must be comptime-known", - }); + return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicRmwOp", .{ .simple = .operand_atomicRmw_operation }); } fn zirCmpxchg( @@ -24967,12 +24931,8 @@ fn zirCmpxchg( const uncasted_ptr = try sema.resolveInst(extra.ptr); const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src); - const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, .{ - .needed_comptime_reason = "atomic order of cmpxchg success must be comptime-known", - }); - const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, .{ - .needed_comptime_reason = "atomic order of cmpxchg failure must be comptime-known", - }); + const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, .{ .simple = .atomic_order }); + const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, .{ .simple = .atomic_order }); if (@intFromEnum(success_order) < @intFromEnum(std.builtin.AtomicOrder.monotonic)) { return sema.fail(block, success_order_src, "success atomic ordering must be monotonic or stricter", .{}); @@ -25113,9 +25073,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const op_src = block.builtinCallArgSrc(inst_data.src_node, 0); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 1); - const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", .{ - .needed_comptime_reason = "@reduce operation must be comptime-known", - }); + const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", .{ .simple = .operand_reduce_operation }); const operand = try sema.resolveInst(extra.rhs); const operand_ty = sema.typeOf(operand); const pt = sema.pt; @@ -25204,9 +25162,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .child = .i32_type, }); mask = try sema.coerce(block, mask_ty, mask, mask_src); - const mask_val = try sema.resolveConstValue(block, mask_src, mask, .{ - .needed_comptime_reason = "shuffle mask must be comptime-known", - }); + const mask_val = try sema.resolveConstValue(block, mask_src, mask, .{ .simple = .operand_shuffle_mask }); return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(mask_len)); } @@ -25474,9 +25430,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); const uncasted_ptr = try sema.resolveInst(extra.ptr); const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); - const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ - .needed_comptime_reason = "atomic order of @atomicLoad must be comptime-known", - }); + const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order }); switch (order) { .release, .acq_rel => { @@ -25542,9 +25496,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A }, else => {}, } - const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ - .needed_comptime_reason = "atomic order of @atomicRmW must be comptime-known", - }); + const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order }); if (order == .unordered) { return sema.fail(block, order_src, "@atomicRmw atomic ordering must not be unordered", .{}); @@ -25611,9 +25563,7 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const elem_ty = sema.typeOf(operand); const uncasted_ptr = try sema.resolveInst(extra.ptr); const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); - const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ - .needed_comptime_reason = "atomic order of @atomicStore must be comptime-known", - }); + const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order }); const air_tag: Air.Inst.Tag = switch (order) { .acquire, .acq_rel => { @@ -25716,14 +25666,12 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const modifier_ty = try sema.getBuiltinType("CallModifier"); const air_ref = try sema.resolveInst(extra.modifier); const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); - const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ - .needed_comptime_reason = "call modifier must be comptime-known", - }); + const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier }); var modifier = zcu.toEnum(std.builtin.CallModifier, modifier_val); switch (modifier) { // These can be upgraded to comptime or nosuspend calls. .auto, .never_tail, .no_async => { - if (block.is_comptime) { + if (block.isComptime()) { if (modifier == .never_tail) { return sema.fail(block, modifier_src, "unable to perform 'never_tail' call at compile-time", .{}); } @@ -25738,12 +25686,12 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(modifier)}); }; - if (block.is_comptime) { + if (block.isComptime()) { modifier = .compile_time; } }, .always_tail => { - if (block.is_comptime) { + if (block.isComptime()) { modifier = .compile_time; } }, @@ -25751,12 +25699,12 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError if (extra.flags.is_nosuspend) { return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); } - if (block.is_comptime) { + if (block.isComptime()) { return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{}); } }, .never_inline => { - if (block.is_comptime) { + if (block.isComptime()) { return sema.fail(block, modifier_src, "unable to perform 'never_inline' call at compile-time", .{}); } }, @@ -25771,7 +25719,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(zcu)); for (resolved_args, 0..) |*resolved, i| { - resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(i), args_ty); + resolved.* = try sema.tupleFieldValByIndex(block, args, @intCast(i), args_ty); } const callee_ty = sema.typeOf(func); @@ -25820,9 +25768,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins } try parent_ty.resolveLayout(pt); - const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ - .needed_comptime_reason = "field name must be comptime-known", - }); + const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name }); const field_index = switch (parent_ty.zigTypeTag(zcu)) { .@"struct" => blk: { if (parent_ty.isTuple(zcu)) { @@ -26680,9 +26626,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A extra_index += body.len; const cc_ty = try sema.getBuiltinType("CallingConvention"); - const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, .{ - .needed_comptime_reason = "calling convention must be comptime-known", - }); + const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, .{ .simple = .@"callconv" }); break :blk try sema.analyzeValueAsCallconv(block, cc_src, val); } else if (extra.data.bits.has_cc_ref) blk: { const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); @@ -26690,9 +26634,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const cc_ty = try sema.getBuiltinType("CallingConvention"); const uncoerced_cc = try sema.resolveInst(cc_ref); const coerced_cc = try sema.coerce(block, cc_ty, uncoerced_cc, cc_src); - const cc_val = try sema.resolveConstDefinedValue(block, cc_src, coerced_cc, .{ - .needed_comptime_reason = "calling convention must be comptime-known", - }); + const cc_val = try sema.resolveConstDefinedValue(block, cc_src, coerced_cc, .{ .simple = .@"callconv" }); break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val); } else cc: { if (has_body) { @@ -26730,9 +26672,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const body = sema.code.bodySlice(extra_index, body_len); extra_index += body.len; - const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, .{ - .needed_comptime_reason = "return type must be comptime-known", - }); + const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, .{ .simple = .function_ret_ty }); const ty = val.toType(); break :blk ty; } else if (extra.data.bits.has_ret_ty_ref) blk: { @@ -26742,9 +26682,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A error.GenericPoison => break :blk Type.generic_poison, else => |e| return e, }; - const ret_ty_val = sema.resolveConstDefinedValue(block, ret_src, ret_ty_air_ref, .{ - .needed_comptime_reason = "return type must be comptime-known", - }) catch |err| switch (err) { + const ret_ty_val = sema.resolveConstDefinedValue(block, ret_src, ret_ty_air_ref, .{ .simple = .function_ret_ty }) catch |err| switch (err) { error.GenericPoison => break :blk Type.generic_poison, else => |e| return e, }; @@ -26790,9 +26728,7 @@ fn zirCUndef( const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src = block.builtinCallArgSrc(extra.node, 0); - const name = try sema.resolveConstString(block, src, extra.operand, .{ - .needed_comptime_reason = "name of macro being undefined must be comptime-known", - }); + const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cUndef_macro_name }); try block.c_import_buf.?.writer().print("#undef {s}\n", .{name}); return .void_value; } @@ -26805,9 +26741,7 @@ fn zirCInclude( const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src = block.builtinCallArgSrc(extra.node, 0); - const name = try sema.resolveConstString(block, src, extra.operand, .{ - .needed_comptime_reason = "path being included must be comptime-known", - }); + const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cInclude_file_name }); try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); return .void_value; } @@ -26823,14 +26757,10 @@ fn zirCDefine( const name_src = block.builtinCallArgSrc(extra.node, 0); const val_src = block.builtinCallArgSrc(extra.node, 1); - const name = try sema.resolveConstString(block, name_src, extra.lhs, .{ - .needed_comptime_reason = "name of macro being undefined must be comptime-known", - }); + const name = try sema.resolveConstString(block, name_src, extra.lhs, .{ .simple = .operand_cDefine_macro_name }); const rhs = try sema.resolveInst(extra.rhs); if (sema.typeOf(rhs).zigTypeTag(zcu) != .void) { - const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ - .needed_comptime_reason = "value of macro being undefined must be comptime-known", - }); + const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ .simple = .operand_cDefine_macro_value }); try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); } else { try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); @@ -26851,9 +26781,7 @@ fn zirWasmMemorySize( return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); } - const index: u32 = @intCast(try sema.resolveInt(block, index_src, extra.operand, Type.u32, .{ - .needed_comptime_reason = "wasm memory size index must be comptime-known", - })); + const index: u32 = @intCast(try sema.resolveInt(block, index_src, extra.operand, Type.u32, .{ .simple = .wasm_memory_index })); try sema.requireRuntimeBlock(block, builtin_src, null); return block.addInst(.{ .tag = .wasm_memory_size, @@ -26878,9 +26806,7 @@ fn zirWasmMemoryGrow( return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); } - const index: u32 = @intCast(try sema.resolveInt(block, index_src, extra.lhs, Type.u32, .{ - .needed_comptime_reason = "wasm memory size index must be comptime-known", - })); + const index: u32 = @intCast(try sema.resolveInt(block, index_src, extra.lhs, Type.u32, .{ .simple = .wasm_memory_index })); const delta = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.rhs), delta_src); try sema.requireRuntimeBlock(block, builtin_src, null); @@ -26911,19 +26837,13 @@ fn resolvePrefetchOptions( const cache_src = block.src(.{ .init_field_cache = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "rw", .no_embedded_nulls), rw_src); - const rw_val = try sema.resolveConstDefinedValue(block, rw_src, rw, .{ - .needed_comptime_reason = "prefetch read/write must be comptime-known", - }); + const rw_val = try sema.resolveConstDefinedValue(block, rw_src, rw, .{ .simple = .prefetch_options }); const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "locality", .no_embedded_nulls), locality_src); - const locality_val = try sema.resolveConstDefinedValue(block, locality_src, locality, .{ - .needed_comptime_reason = "prefetch locality must be comptime-known", - }); + const locality_val = try sema.resolveConstDefinedValue(block, locality_src, locality, .{ .simple = .prefetch_options }); const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "cache", .no_embedded_nulls), cache_src); - const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ - .needed_comptime_reason = "prefetch cache must be comptime-known", - }); + const cache_val = try sema.resolveConstDefinedValue(block, cache_src, cache, .{ .simple = .prefetch_options }); return std.builtin.PrefetchOptions{ .rw = zcu.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), @@ -26945,7 +26865,7 @@ fn zirPrefetch( const options = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs); - if (!block.is_comptime) { + if (!block.isComptime()) { _ = try block.addInst(.{ .tag = .prefetch, .data = .{ .prefetch = .{ @@ -26987,30 +26907,20 @@ fn resolveExternOptions( const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node }); const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src); - const name = try sema.toConstString(block, name_src, name_ref, .{ - .needed_comptime_reason = "name of the extern symbol must be comptime-known", - }); + const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options }); const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "library_name", .no_embedded_nulls), library_src); - const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ - .needed_comptime_reason = "library in which extern symbol is must be comptime-known", - }); + const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ .simple = .extern_options }); const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "linkage", .no_embedded_nulls), linkage_src); - const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ - .needed_comptime_reason = "linkage of the extern symbol must be comptime-known", - }); + const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options }); const linkage = zcu.toEnum(std.builtin.GlobalLinkage, linkage_val); const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src); - const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ - .needed_comptime_reason = "threadlocality of the extern symbol must be comptime-known", - }); + const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options }); const library_name = if (library_name_val.optionalValue(zcu)) |library_name_payload| library_name: { - const library_name = try sema.toConstString(block, library_src, Air.internedToRef(library_name_payload.toIntern()), .{ - .needed_comptime_reason = "library in which extern symbol is must be comptime-known", - }); + const library_name = try sema.toConstString(block, library_src, Air.internedToRef(library_name_payload.toIntern()), .{ .simple = .extern_options }); if (library_name.len == 0) { return sema.fail(block, library_src, "library name cannot be empty", .{}); } @@ -27019,9 +26929,7 @@ fn resolveExternOptions( } else null; const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src); - const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ - .needed_comptime_reason = "it must be comptime-known if the symbol is imported from a dll", - }); + const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options }); if (name.len == 0) { return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); @@ -27134,9 +27042,7 @@ fn zirWorkItem( }, } - const dimension: u32 = @intCast(try sema.resolveInt(block, dimension_src, extra.operand, Type.u32, .{ - .needed_comptime_reason = "dimension must be comptime-known", - })); + const dimension: u32 = @intCast(try sema.resolveInt(block, dimension_src, extra.operand, Type.u32, .{ .simple = .work_group_dim_index })); try sema.requireRuntimeBlock(block, builtin_src, null); return block.addInst(.{ @@ -27158,7 +27064,7 @@ fn zirInComptime( block: *Block, ) CompileError!Air.Inst.Ref { _ = sema; - return if (block.is_comptime) .bool_true else .bool_false; + return if (block.isComptime()) .bool_true else .bool_false; } fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { @@ -27249,9 +27155,7 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const hint_ty = try sema.getBuiltinType("BranchHint"); const coerced_hint = try sema.coerce(block, hint_ty, uncoerced_hint, operand_src); - const hint_val = try sema.resolveConstDefinedValue(block, operand_src, coerced_hint, .{ - .needed_comptime_reason = "operand to '@branchHint' must be comptime-known", - }); + const hint_val = try sema.resolveConstDefinedValue(block, operand_src, coerced_hint, .{ .simple = .operand_branchHint }); // We only apply the first hint in a branch. // This allows user-provided hints to override implicit cold hints. @@ -27261,20 +27165,20 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat } fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void { - if (block.is_comptime) { - const msg = msg: { + if (block.isComptime()) { + const msg, const fail_block = msg: { const msg = try sema.errMsg(src, "unable to evaluate comptime expression", .{}); errdefer msg.destroy(sema.gpa); if (runtime_src) |some| { try sema.errNote(some, msg, "operation is runtime due to this operand", .{}); } - if (block.comptime_reason) |some| { - try some.explain(sema, msg); - } - break :msg msg; + + const fail_block = try block.explainWhyBlockIsComptime(msg); + + break :msg .{ msg, fail_block }; }; - return sema.failWithOwnedErrorMsg(block, msg); + return sema.failWithOwnedErrorMsg(fail_block, msg); } } @@ -27759,7 +27663,7 @@ fn addSafetyCheck( panic_id: Zcu.PanicId, ) !void { const gpa = sema.gpa; - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); var fail_block: Block = .{ .parent = parent_block, @@ -27767,7 +27671,7 @@ fn addSafetyCheck( .namespace = parent_block.namespace, .instructions = .{}, .inlining = parent_block.inlining, - .is_comptime = false, + .comptime_reason = null, .src_base_inst = parent_block.src_base_inst, .type_name_ctx = parent_block.type_name_ctx, }; @@ -27874,7 +27778,7 @@ fn addSafetyCheckUnwrapError( unwrap_err_tag: Air.Inst.Tag, is_non_err_tag: Air.Inst.Tag, ) !void { - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); const ok = try parent_block.addUnOp(is_non_err_tag, operand); const gpa = sema.gpa; @@ -27884,7 +27788,7 @@ fn addSafetyCheckUnwrapError( .namespace = parent_block.namespace, .instructions = .{}, .inlining = parent_block.inlining, - .is_comptime = false, + .comptime_reason = null, .src_base_inst = parent_block.src_base_inst, .type_name_ctx = parent_block.type_name_ctx, }; @@ -27918,7 +27822,7 @@ fn addSafetyCheckIndexOob( len: Air.Inst.Ref, cmp_op: Air.Inst.Tag, ) !void { - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); const ok = try parent_block.addBinOp(cmp_op, index, len); return addSafetyCheckCall(sema, parent_block, src, ok, "outOfBounds", &.{ index, len }); } @@ -27930,7 +27834,7 @@ fn addSafetyCheckInactiveUnionField( active_tag: Air.Inst.Ref, wanted_tag: Air.Inst.Ref, ) !void { - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag); return addSafetyCheckCall(sema, parent_block, src, ok, "inactiveUnionField", &.{ active_tag, wanted_tag }); } @@ -27944,7 +27848,7 @@ fn addSafetyCheckSentinelMismatch( ptr: Air.Inst.Ref, sentinel_index: Air.Inst.Ref, ) !void { - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); const pt = sema.pt; const zcu = pt.zcu; const expected_sentinel_val = maybe_sentinel orelse return; @@ -27986,7 +27890,7 @@ fn addSafetyCheckCall( func_name: []const u8, args: []const Air.Inst.Ref, ) !void { - assert(!parent_block.is_comptime); + assert(!parent_block.isComptime()); const gpa = sema.gpa; const pt = sema.pt; const zcu = pt.zcu; @@ -27997,7 +27901,7 @@ fn addSafetyCheckCall( .namespace = parent_block.namespace, .instructions = .{}, .inlining = parent_block.inlining, - .is_comptime = false, + .comptime_reason = null, .src_base_inst = parent_block.src_base_inst, .type_name_ctx = parent_block.type_name_ctx, }; @@ -28203,7 +28107,7 @@ fn fieldVal( const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); return sema.analyzeLoad(block, src, field_ptr, object_src); } else { - return sema.structFieldVal(block, src, object, field_name, field_name_src, inner_ty); + return sema.structFieldVal(block, object, field_name, field_name_src, inner_ty); }, .@"union" => if (is_pointer_to) { // Avoid loading the entire union by fetching a pointer and loading that @@ -28823,14 +28727,12 @@ fn structFieldPtrByIndex( return Air.internedToRef(val); } - try sema.requireRuntimeBlock(block, src, null); return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty); } fn structFieldVal( sema: *Sema, block: *Block, - src: LazySrcLoc, struct_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, @@ -28866,12 +28768,11 @@ fn structFieldVal( return Air.internedToRef((try struct_val.fieldValue(pt, field_index)).toIntern()); } - try sema.requireRuntimeBlock(block, src, null); try field_ty.resolveLayout(pt); return block.addStructFieldVal(struct_byval, field_index, field_ty); }, .tuple_type => { - return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); + return sema.tupleFieldVal(block, struct_byval, field_name, field_name_src, struct_ty); }, else => unreachable, } @@ -28880,7 +28781,6 @@ fn structFieldVal( fn tupleFieldVal( sema: *Sema, block: *Block, - src: LazySrcLoc, tuple_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, @@ -28892,7 +28792,7 @@ fn tupleFieldVal( return pt.intRef(Type.usize, tuple_ty.structFieldCount(zcu)); } const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); - return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty); + return sema.tupleFieldValByIndex(block, tuple_byval, field_index, tuple_ty); } /// Asserts that `field_name` is not "len". @@ -28921,7 +28821,6 @@ fn tupleFieldIndex( fn tupleFieldValByIndex( sema: *Sema, block: *Block, - src: LazySrcLoc, tuple_byval: Air.Inst.Ref, field_index: u32, tuple_ty: Type, @@ -28951,7 +28850,6 @@ fn tupleFieldValByIndex( }; } - try sema.requireRuntimeBlock(block, src, null); try field_ty.resolveLayout(pt); return block.addStructFieldVal(tuple_byval, field_index, field_ty); } @@ -29049,7 +28947,6 @@ fn unionFieldPtr( return Air.internedToRef(field_ptr_val.toIntern()); } - try sema.requireRuntimeBlock(block, src, null); if (!initializing and union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1) { @@ -29126,7 +29023,6 @@ fn unionFieldVal( } } - try sema.requireRuntimeBlock(block, src, null); if (union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1) { @@ -29168,9 +29064,7 @@ fn elemPtr( .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), .@"struct" => blk: { // Tuple field access. - const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ - .needed_comptime_reason = "tuple field access index must be comptime-known", - }); + const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); }, @@ -29207,16 +29101,15 @@ fn elemPtrOneLayerOnly( .Many, .C => { const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); - const runtime_src = rs: { - const ptr_val = maybe_ptr_val orelse break :rs indexable_src; - const index_val = maybe_index_val orelse break :rs elem_index_src; + ct: { + const ptr_val = maybe_ptr_val orelse break :ct; + const index_val = maybe_index_val orelse break :ct; const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); const elem_ptr = try ptr_val.ptrElem(index, pt); return Air.internedToRef(elem_ptr.toIntern()); - }; + } const result_ty = try indexable_ty.elemPtrType(null, pt); - try sema.requireRuntimeBlock(block, src, runtime_src); return block.addPtrElemPtr(indexable, elem_index, result_ty); }, .One => { @@ -29225,9 +29118,7 @@ fn elemPtrOneLayerOnly( .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety), .@"struct" => blk: { assert(child_ty.isTuple(zcu)); - const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ - .needed_comptime_reason = "tuple field access index must be comptime-known", - }); + const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false); }, @@ -29266,22 +29157,19 @@ fn elemVal( const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); - const runtime_src = rs: { - const indexable_val = maybe_indexable_val orelse break :rs indexable_src; - const index_val = maybe_index_val orelse break :rs elem_index_src; + ct: { + const indexable_val = maybe_indexable_val orelse break :ct; + const index_val = maybe_index_val orelse break :ct; const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); const elem_ty = indexable_ty.elemType2(zcu); const many_ptr_ty = try pt.manyConstPtrType(elem_ty); const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); const elem_ptr_ty = try pt.singleConstPtrType(elem_ty); const elem_ptr_val = try many_ptr_val.ptrElem(index, pt); - if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { - return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern()); - } - break :rs indexable_src; - }; + const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct; + return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern()); + } - try sema.requireRuntimeBlock(block, src, runtime_src); return block.addBinOp(.ptr_elem_val, indexable, elem_index); }, .One => { @@ -29305,9 +29193,7 @@ fn elemVal( }, .@"struct" => { // Tuple field access. - const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ - .needed_comptime_reason = "tuple field access index must be comptime-known", - }); + const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); }, @@ -29396,7 +29282,6 @@ fn tupleFieldPtr( try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src); } - try sema.requireRuntimeBlock(block, tuple_ptr_src, null); return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); } @@ -29439,7 +29324,6 @@ fn tupleField( try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); - try sema.requireRuntimeBlock(block, tuple_src, null); try field_ty.resolveLayout(pt); return block.addStructFieldVal(tuple, field_index, field_ty); } @@ -29495,7 +29379,6 @@ fn elemValArray( try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); - const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; if (oob_safety and block.wantSafety()) { // Runtime check is only needed if unable to comptime check. if (maybe_index_val == null) { @@ -29508,7 +29391,6 @@ fn elemValArray( if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_val| return Air.internedToRef(elem_val.toIntern()); - try sema.requireRuntimeBlock(block, src, runtime_src); return block.addBinOp(.array_elem_val, array, elem_index); } @@ -29562,9 +29444,6 @@ fn elemPtrArray( try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src); } - const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; - try sema.requireRuntimeBlock(block, src, runtime_src); - // Runtime check is only needed if unable to comptime check. if (oob_safety and block.wantSafety() and offset == null) { const len_inst = try pt.intRef(Type.usize, array_len); @@ -29621,7 +29500,6 @@ fn elemValSlice( try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); - try sema.requireRuntimeBlock(block, src, runtime_src); if (oob_safety and block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| try pt.intRef(Type.usize, try slice_val.sliceLen(pt)) @@ -29678,8 +29556,6 @@ fn elemPtrSlice( try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); - const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; - try sema.requireRuntimeBlock(block, src, runtime_src); if (oob_safety and block.wantSafety()) { const len_inst = len: { if (maybe_undef_slice_val) |slice_val| @@ -30093,9 +29969,7 @@ fn coerceExtra( const val = maybe_inst_val orelse { if (dest_ty.zigTypeTag(zcu) == .comptime_int) { if (!opts.report_err) return error.NotCoercible; - return sema.failWithNeededComptime(block, inst_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known", - }); + return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_int }); } break :float; }; @@ -30120,9 +29994,7 @@ fn coerceExtra( if (dest_ty.zigTypeTag(zcu) == .comptime_int) { if (!opts.report_err) return error.NotCoercible; if (opts.no_cast_to_comptime_int) return inst; - return sema.failWithNeededComptime(block, inst_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_int' must be comptime-known", - }); + return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_int }); } // integer widening @@ -30158,9 +30030,7 @@ fn coerceExtra( return Air.internedToRef(result_val.toIntern()); } else if (dest_ty.zigTypeTag(zcu) == .comptime_float) { if (!opts.report_err) return error.NotCoercible; - return sema.failWithNeededComptime(block, inst_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known", - }); + return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_float }); } // float widening @@ -30175,9 +30045,7 @@ fn coerceExtra( const val = maybe_inst_val orelse { if (dest_ty.zigTypeTag(zcu) == .comptime_float) { if (!opts.report_err) return error.NotCoercible; - return sema.failWithNeededComptime(block, inst_src, .{ - .needed_comptime_reason = "value being casted to 'comptime_float' must be comptime-known", - }); + return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_float }); } break :int; }; @@ -32435,9 +32303,7 @@ fn coerceTupleToStruct( field_refs[struct_field_index] = coerced; if (struct_type.fieldIsComptime(ip, struct_field_index)) { const init_val = try sema.resolveValue(coerced) orelse { - return sema.failWithNeededComptime(block, field_src, .{ - .needed_comptime_reason = "value stored in comptime field must be comptime-known", - }); + return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); }; const field_init = Value.fromInterned(struct_type.field_inits.get(ip)[struct_field_index]); @@ -32550,9 +32416,7 @@ fn coerceTupleToTuple( field_refs[field_index] = coerced; if (default_val != .none) { const init_val = (try sema.resolveValue(coerced)) orelse { - return sema.failWithNeededComptime(block, field_src, .{ - .needed_comptime_reason = "value stored in comptime field must be comptime-known", - }); + return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); }; if (!init_val.eql(Value.fromInterned(default_val), Type.fromInterned(field_ty), pt.zcu)) { @@ -32816,12 +32680,12 @@ fn analyzeRef( // In a comptime context, the store would fail, since the operand is runtime-known. But that's // okay; we don't actually need this store to succeed, since we're creating a runtime value in a // comptime scope, so the value can never be used aside from to get its type. - if (!block.is_comptime) { + if (!block.isComptime()) { try sema.storePtr(block, src, alloc, operand); } // Cast to the constant pointer type. We do this directly rather than going via `coerce` to - // avoid errors in the `block.is_comptime` case. + // avoid errors in the `block.isComptime()` case. return block.addBitCast(ptr_type, alloc); } @@ -33184,24 +33048,24 @@ fn analyzeSlice( array_ty = double_child_ty; elem_ty = double_child_ty.childType(zcu); } else { - const bounds_error_message = "slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1]"; if (uncasted_end_opt == .none) { - return sema.fail(block, src, bounds_error_message, .{}); + return sema.fail(block, src, "slice of single-item pointer must be bounded", .{}); } const start_value = try sema.resolveConstDefinedValue( block, start_src, uncasted_start, - .{ .needed_comptime_reason = bounds_error_message }, + .{ .simple = .slice_single_item_ptr_bounds }, ); const end_value = try sema.resolveConstDefinedValue( block, end_src, uncasted_end_opt, - .{ .needed_comptime_reason = bounds_error_message }, + .{ .simple = .slice_single_item_ptr_bounds }, ); + const bounds_error_message = "slice of single-item pointer must have bounds [0..0], [0..1], or [1..1]"; if (try sema.compareScalar(start_value, .neq, end_value, Type.comptime_int)) { if (try sema.compareScalar(start_value, .neq, Value.zero_comptime_int, Type.comptime_int)) { const msg = msg: { @@ -33416,9 +33280,7 @@ fn analyzeSlice( if (sentinel_opt != .none) { const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src); try checkSentinelType(sema, block, sentinel_src, elem_ty); - break :s try sema.resolveConstDefinedValue(block, sentinel_src, casted, .{ - .needed_comptime_reason = "slice sentinel must be comptime-known", - }); + break :s try sema.resolveConstDefinedValue(block, sentinel_src, casted, .{ .simple = .slice_sentinel }); } // If we are slicing to the end of something that is sentinel-terminated // then the resulting slice type is also sentinel-terminated. @@ -33499,9 +33361,9 @@ fn analyzeSlice( runtime_src = end_src; } - if (!checked_start_lte_end and block.wantSafety() and !block.is_comptime) { + if (!checked_start_lte_end and block.wantSafety() and !block.isComptime()) { // requirement: start <= end - assert(!block.is_comptime); + assert(!block.isComptime()); try sema.requireRuntimeBlock(block, src, runtime_src.?); const ok = try block.addBinOp(.cmp_lte, start, end); try sema.addSafetyCheckCall(block, src, ok, "startGreaterThanEnd", &.{ start, end }); @@ -35859,7 +35721,7 @@ fn backingIntType( .namespace = struct_type.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = null, // set below if needed .src_base_inst = struct_type.zir_index, .type_name_ctx = struct_type.name, }; @@ -35899,6 +35761,10 @@ fn backingIntType( .base_node_inst = struct_type.zir_index, .offset = .{ .node_offset_container_tag = 0 }, }; + block.comptime_reason = .{ .reason = .{ + .src = backing_int_src, + .r = .{ .simple = .type }, + } }; const backing_int_ty = blk: { if (backing_int_body_len == 0) { const backing_int_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); @@ -36512,7 +36378,13 @@ fn structFields( .namespace = namespace_index, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = .{ .reason = .{ + .src = .{ + .base_node_inst = struct_type.zir_index, + .offset = .nodeOffset(0), + }, + .r = .{ .simple = .struct_fields }, + } }, .src_base_inst = struct_type.zir_index, .type_name_ctx = struct_type.name, }; @@ -36698,7 +36570,7 @@ fn structFieldInits( .namespace = namespace_index, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = undefined, // set when `block_scope` is used .src_base_inst = struct_type.zir_index, .type_name_ctx = struct_type.name, }; @@ -36776,13 +36648,13 @@ fn structFieldInits( .offset = .{ .container_field_value = @intCast(field_i) }, }; + block_scope.comptime_reason = .{ .reason = .{ + .src = init_src, + .r = .{ .simple = .struct_field_default_value }, + } }; const init = try sema.resolveInlineBody(&block_scope, body, zir_index); const coerced = try sema.coerce(&block_scope, field_ty, init, init_src); - const default_val = try sema.resolveValue(coerced) orelse { - return sema.failWithNeededComptime(&block_scope, init_src, .{ - .needed_comptime_reason = "struct field default value must be comptime-known", - }); - }; + const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null); if (default_val.canMutateComptimeVarState(zcu)) { return sema.fail(&block_scope, init_src, "field default value contains reference to comptime-mutable memory", .{}); @@ -36850,20 +36722,26 @@ fn unionFields( const body = zir.bodySlice(extra_index, body_len); extra_index += body.len; + const src: LazySrcLoc = .{ + .base_node_inst = union_type.zir_index, + .offset = .nodeOffset(0), + }; + var block_scope: Block = .{ .parent = null, .sema = sema, .namespace = union_type.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = .{ .reason = .{ + .src = src, + .r = .{ .simple = .union_fields }, + } }, .src_base_inst = union_type.zir_index, .type_name_ctx = union_type.name, }; defer assert(block_scope.instructions.items.len == 0); - const src = block_scope.nodeOffset(0); - if (body.len != 0) { _ = try sema.analyzeInlineBody(&block_scope, body, zir_index); } @@ -36993,9 +36871,7 @@ fn unionFields( if (enum_field_vals.capacity() > 0) { const enum_tag_val = if (tag_ref != .none) blk: { const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, value_src); - const val = try sema.resolveConstDefinedValue(&block_scope, value_src, coerced, .{ - .needed_comptime_reason = "enum tag value must be comptime-known", - }); + const val = try sema.resolveConstDefinedValue(&block_scope, value_src, coerced, .{ .simple = .enum_field_tag_value }); last_tag_val = val; break :blk val; @@ -37669,9 +37545,7 @@ pub fn analyzeAsAddressSpace( const zcu = pt.zcu; const addrspace_ty = try sema.getBuiltinType("AddressSpace"); const coerced = try sema.coerce(block, addrspace_ty, air_ref, src); - const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ - .needed_comptime_reason = "address space must be comptime-known", - }); + const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ .simple = .@"addrspace" }); const address_space = zcu.toEnum(std.builtin.AddressSpace, addrspace_val); const target = pt.zcu.getTarget(); const arch = target.cpu.arch; @@ -38560,7 +38434,7 @@ fn sliceToIpString( block: *Block, src: LazySrcLoc, slice_val: Value, - reason: NeededComptimeReason, + reason: ComptimeReason, ) CompileError!InternPool.NullTerminatedString { const pt = sema.pt; const zcu = pt.zcu; @@ -38580,7 +38454,7 @@ fn derefSliceAsArray( block: *Block, src: LazySrcLoc, slice_val: Value, - reason: NeededComptimeReason, + reason: ComptimeReason, ) CompileError!Value { return try sema.maybeDerefSliceAsArray(block, src, slice_val) orelse { return sema.failWithNeededComptime(block, src, reason); @@ -38734,7 +38608,10 @@ pub fn resolveDeclaredEnum( .namespace = namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = .{ .reason = .{ + .src = src, + .r = .{ .simple = .enum_fields }, + } }, .src_base_inst = tracked_inst, .type_name_ctx = type_name, }; @@ -38798,9 +38675,7 @@ pub fn resolveDeclaredEnum( last_tag_val = try sema.resolveConstDefinedValue(&block, .{ .base_node_inst = tracked_inst, .offset = .{ .container_field_name = field_i }, - }, tag_inst, .{ - .needed_comptime_reason = "enum tag value must be comptime-known", - }); + }, tag_inst, .{ .simple = .enum_field_tag_value }); if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { @@ -38879,9 +38754,7 @@ fn getPanicInnerFn( const inner_name_ip = try ip.getOrPutString(gpa, pt.tid, inner_name, .no_embedded_nulls); const opt_fn_ref = try namespaceLookupVal(sema, block, src, outer_ty.getNamespaceIndex(zcu), inner_name_ip); const fn_ref = opt_fn_ref orelse return sema.fail(block, src, "std.builtin.Panic missing {s}", .{inner_name}); - const fn_val = try sema.resolveConstValue(block, src, fn_ref, .{ - .needed_comptime_reason = "panic handler must be comptime-known", - }); + const fn_val = try sema.resolveConstValue(block, src, fn_ref, .{ .simple = .panic_handler }); if (fn_val.typeOf(zcu).zigTypeTag(zcu) != .@"fn") { return sema.fail(block, src, "std.builtin.Panic.{s} is not a function", .{inner_name}); } @@ -38963,9 +38836,7 @@ pub fn resolveNavPtrModifiers( const @"linksection": InternPool.OptionalNullTerminatedString = ls: { const linksection_body = zir_decl.linksection_body orelse break :ls .none; const linksection_ref = try sema.resolveInlineBody(block, linksection_body, decl_inst); - const bytes = try sema.toConstString(block, section_src, linksection_ref, .{ - .needed_comptime_reason = "linksection must be comptime-known", - }); + const bytes = try sema.toConstString(block, section_src, linksection_ref, .{ .simple = .@"linksection" }); if (std.mem.indexOfScalar(u8, bytes, 0) != null) { return sema.fail(block, section_src, "linksection cannot contain null bytes", .{}); } else if (bytes.len == 0) { diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 21908f769f50..d304ee3533cb 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -682,7 +682,13 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu .namespace = comptime_unit.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = .{ .reason = .{ + .src = .{ + .base_node_inst = comptime_unit.zir_index, + .offset = .{ .token_offset = 0 }, + }, + .r = .{ .simple = .comptime_keyword }, + } }, .src_base_inst = comptime_unit.zir_index, .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{ Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip), @@ -878,7 +884,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr .namespace = old_nav.analysis.?.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = undefined, // set below .src_base_inst = old_nav.analysis.?.zir_index, .type_name_ctx = old_nav.fqn, }; @@ -893,6 +899,11 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr const section_src = block.src(.{ .node_offset_var_decl_section = 0 }); const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 }); + block.comptime_reason = .{ .reason = .{ + .src = init_src, + .r = .{ .simple = .container_var_init }, + } }; + const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: { // Since we have a type body, the type is resolved separately! // Of course, we need to make sure we depend on it properly. @@ -1253,7 +1264,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr .namespace = old_nav.analysis.?.namespace, .instructions = .{}, .inlining = null, - .is_comptime = true, + .comptime_reason = undefined, // set below .src_base_inst = old_nav.analysis.?.zir_index, .type_name_ctx = old_nav.fqn, }; @@ -1262,6 +1273,13 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr const zir_decl = zir.getDeclaration(inst_resolved.inst); assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace")); + const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 }); + + block.comptime_reason = .{ .reason = .{ + .src = ty_src, + .r = .{ .simple = .type }, + } }; + const type_body = zir_decl.type_body orelse { // The type of this `Nav` is inferred from the value. // In other words, this `nav_ty` depends on the corresponding `nav_val`. @@ -1279,8 +1297,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr return .{ .type_changed = true }; }; - const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 }); - const resolved_ty: Type = ty: { const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_resolved.inst); const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src); @@ -2442,7 +2458,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE .namespace = decl_nav.analysis.?.namespace, .instructions = .{}, .inlining = null, - .is_comptime = false, + .comptime_reason = null, .src_base_inst = decl_nav.analysis.?.zir_index, .type_name_ctx = func_nav.fqn, }; diff --git a/src/print_zir.zig b/src/print_zir.zig index 80fbb908b678..14502d8ba1f7 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -273,6 +273,7 @@ const Writer = struct { .@"await", .make_ptr_const, .validate_deref, + .validate_const, .check_comptime_control_flow, .opt_eu_base_ptr_init, .restore_err_ret_index_unconditional, @@ -437,7 +438,6 @@ const Writer = struct { .field_call => try self.writeCall(stream, inst, .field), .block, - .block_comptime, .block_inline, .suspend_block, .loop, @@ -445,6 +445,8 @@ const Writer = struct { .typeof_builtin, => try self.writeBlock(stream, inst), + .block_comptime => try self.writeBlockComptime(stream, inst), + .condbr, .condbr_inline, => try self.writeCondBr(stream, inst), @@ -1343,16 +1345,21 @@ const Writer = struct { fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; - try self.writePlNodeBlockWithoutSrc(stream, inst); + const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); + const body = self.code.bodySlice(extra.end, extra.data.body_len); + try self.writeBracedBody(stream, body); + try stream.writeAll(") "); try self.writeSrcNode(stream, inst_data.src_node); } - fn writePlNodeBlockWithoutSrc(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + fn writeBlockComptime(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; - const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index); + const extra = self.code.extraData(Zir.Inst.BlockComptime, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.body_len); + try stream.print("reason={s}, ", .{@tagName(extra.data.reason)}); try self.writeBracedBody(stream, body); try stream.writeAll(") "); + try self.writeSrcNode(stream, inst_data.src_node); } fn writeCondBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { diff --git a/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig index 1a6b649094ab..904a31cddb5a 100644 --- a/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig +++ b/test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig @@ -10,5 +10,5 @@ pub export fn entry() void { // target=native // // :2:36: error: unable to resolve comptime value -// :2:36: note: global variable initializer must be comptime-known -// :2:36: note: thread local and dll imported variables have runtime-known addresses +// :2:36: note: initializer of container-level variable must be comptime-known +// :2:36: note: threadlocal and dll imported variables have runtime-known addresses diff --git a/test/cases/compile_errors/anytype_param_requires_comptime.zig b/test/cases/compile_errors/anytype_param_requires_comptime.zig index ddcb0a7b9b00..94a08ac1194b 100644 --- a/test/cases/compile_errors/anytype_param_requires_comptime.zig +++ b/test/cases/compile_errors/anytype_param_requires_comptime.zig @@ -13,8 +13,8 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :7:25: error: unable to resolve comptime value -// :7:25: note: initializer of comptime only struct must be comptime-known +// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_166.C' must be comptime-known +// :4:16: note: struct requires comptime because of this field +// :4:16: note: types are not available at runtime diff --git a/test/cases/compile_errors/array_mult_with_number_type.zig b/test/cases/compile_errors/array_mult_with_number_type.zig index bd47c3b56f7b..5c8b47f3256f 100644 --- a/test/cases/compile_errors/array_mult_with_number_type.zig +++ b/test/cases/compile_errors/array_mult_with_number_type.zig @@ -1,10 +1,9 @@ -export fn entry(base: f32, exponent: f32) f32 { +const exponent: f32 = 1.0; +export fn entry(base: f32) f32 { return base ** exponent; } // error -// backend=stage2 -// target=native // -// :2:12: error: expected indexable; found 'f32' -// :2:17: note: this operator multiplies arrays; use std.math.pow for exponentiation +// :3:12: error: expected indexable; found 'f32' +// :3:17: note: this operator multiplies arrays; use std.math.pow for exponentiation diff --git a/test/cases/compile_errors/asm_at_compile_time.zig b/test/cases/compile_errors/asm_at_compile_time.zig index 49624d68052b..1d588a7df4f1 100644 --- a/test/cases/compile_errors/asm_at_compile_time.zig +++ b/test/cases/compile_errors/asm_at_compile_time.zig @@ -15,4 +15,5 @@ fn doSomeAsm() void { // target=native // // :6:5: error: unable to evaluate comptime expression -// :2:14: note: called from here +// :2:14: note: called at comptime from here +// :1:1: note: 'comptime' keyword forces comptime evaluation diff --git a/test/cases/compile_errors/attempted_double_pipe_on_boolean_values.zig b/test/cases/compile_errors/attempted_double_pipe_on_boolean_values.zig index 59b5bde8af6f..6cd4d0ebe825 100644 --- a/test/cases/compile_errors/attempted_double_pipe_on_boolean_values.zig +++ b/test/cases/compile_errors/attempted_double_pipe_on_boolean_values.zig @@ -1,13 +1,11 @@ -export fn entry(a: bool, b: bool) i32 { - if (a || b) { +export fn entry() i32 { + if (true || false) { return 1234; } return 5678; } // error -// backend=stage2 -// target=native // // :2:9: error: expected error set type, found 'bool' -// :2:11: note: '||' merges error sets; 'or' performs boolean OR +// :2:14: note: '||' merges error sets; 'or' performs boolean OR diff --git a/test/cases/compile_errors/branch_in_comptime_only_scope_uses_condbr_inline.zig b/test/cases/compile_errors/branch_in_comptime_only_scope_uses_condbr_inline.zig index c072c7ef9d97..6ff3e57154e9 100644 --- a/test/cases/compile_errors/branch_in_comptime_only_scope_uses_condbr_inline.zig +++ b/test/cases/compile_errors/branch_in_comptime_only_scope_uses_condbr_inline.zig @@ -20,4 +20,6 @@ pub export fn entry2() void { // // :5:15: error: unable to evaluate comptime expression // :5:13: note: operation is runtime due to this operand +// :4:72: note: '@shuffle' mask must be comptime-known // :13:11: error: unable to evaluate comptime expression +// :12:72: note: '@shuffle' mask must be comptime-known diff --git a/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig b/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig index 4a85ee8aab39..66951a03a009 100644 --- a/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig +++ b/test/cases/compile_errors/builtin_extern_in_comptime_scope.zig @@ -11,8 +11,8 @@ pub export fn entry2() void { // target=native // // :1:16: error: unable to resolve comptime value -// :1:16: note: global variable initializer must be comptime-known -// :1:16: note: thread local and dll imported variables have runtime-known addresses +// :1:16: note: initializer of container-level variable must be comptime-known +// :1:16: note: threadlocal and dll imported variables have runtime-known addresses // :2:17: error: unable to resolve comptime value -// :2:17: note: global variable initializer must be comptime-known -// :2:17: note: thread local and dll imported variables have runtime-known addresses +// :2:17: note: initializer of container-level variable must be comptime-known +// :2:17: note: threadlocal and dll imported variables have runtime-known addresses diff --git a/test/cases/compile_errors/compile_time_struct_field.zig b/test/cases/compile_errors/compile_time_struct_field.zig index 8ca502f645a0..adfcc440e66f 100644 --- a/test/cases/compile_errors/compile_time_struct_field.zig +++ b/test/cases/compile_errors/compile_time_struct_field.zig @@ -4,16 +4,15 @@ const S = struct { }; export fn a() void { - var value: u32 = 3; - const comptimeStruct = S { - .normal_ptr = &value, - }; - _ = comptimeStruct; + var value: u32 = 3; + const comptimeStruct = S{ + .normal_ptr = &value, + }; + _ = comptimeStruct; } // error -// backend=stage2 -// target=native // -// 9:6: error: unable to resolve comptime value -// 9:6: note: initializer of comptime only struct must be comptime-known +// :9:10: error: unable to resolve comptime value +// :9:10: note: initializer of comptime-only struct 'tmp.S' must be comptime-known +// :2:21: note: struct requires comptime because of this field diff --git a/test/cases/compile_errors/condition_comptime_reason_explained.zig b/test/cases/compile_errors/condition_comptime_reason_explained.zig index 2e9c47522aed..d641b6176ba7 100644 --- a/test/cases/compile_errors/condition_comptime_reason_explained.zig +++ b/test/cases/compile_errors/condition_comptime_reason_explained.zig @@ -33,18 +33,14 @@ pub export fn entry2() void { } // error -// backend=stage2 -// target=native // // :8:9: error: unable to resolve comptime value -// :8:9: note: condition in comptime branch must be comptime-known -// :7:13: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S' +// :19:15: note: called at comptime from here +// :7:13: note: function with comptime-only return type 'tmp.S' is evaluated at comptime // :2:12: note: struct requires comptime because of this field // :2:12: note: use '*const fn () void' for a function pointer type -// :19:15: note: called from here // :22:13: error: unable to resolve comptime value -// :22:13: note: condition in comptime switch must be comptime-known -// :21:17: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S' +// :32:19: note: called at comptime from here +// :21:17: note: function with comptime-only return type 'tmp.S' is evaluated at comptime // :2:12: note: struct requires comptime because of this field // :2:12: note: use '*const fn () void' for a function pointer type -// :32:19: note: called from here diff --git a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig b/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig index e259bb5634ca..eab95cd9da26 100644 --- a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig +++ b/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig @@ -11,4 +11,4 @@ export fn entry() void { // target=native // // :6:31: error: unable to resolve comptime value -// :6:31: note: value being casted to enum with 'comptime_int' tag type must be comptime-known +// :6:31: note: value casted to enum with 'comptime_int' tag type must be comptime-known diff --git a/test/cases/compile_errors/error_in_typeof_param.zig b/test/cases/compile_errors/error_in_typeof_param.zig index 073bd29bc302..469c9e5e1eaf 100644 --- a/test/cases/compile_errors/error_in_typeof_param.zig +++ b/test/cases/compile_errors/error_in_typeof_param.zig @@ -11,4 +11,4 @@ pub export fn entry() void { // target=native // // :6:31: error: unable to resolve comptime value -// :6:31: note: value being casted to 'comptime_int' must be comptime-known +// :6:31: note: value casted to 'comptime_int' must be comptime-known diff --git a/test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig b/test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig index e8232543a39e..7901808f3c9d 100644 --- a/test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig +++ b/test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig @@ -4,7 +4,7 @@ const S = struct { }; fn bar() void {} -fn foo(comptime a: *u8) S { +fn foo(a: *u8) S { return .{ .fnPtr = bar, .a = a.* }; } pub export fn entry() void { @@ -13,11 +13,8 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :12:13: error: unable to resolve comptime value -// :12:13: note: argument to function being called at comptime must be comptime-known -// :7:25: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S' +// :7:16: note: function with comptime-only return type 'tmp.S' is evaluated at comptime // :2:12: note: struct requires comptime because of this field // :2:12: note: use '*const fn () void' for a function pointer type diff --git a/test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig b/test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig index aada601c79bf..cfec89d5a785 100644 --- a/test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig +++ b/test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig @@ -15,9 +15,8 @@ pub export fn entry() void { _ = foo(a, fn () void); } // error -// backend=stage2 -// target=native // // :15:13: error: unable to resolve comptime value -// :15:13: note: argument to function being called at comptime must be comptime-known -// :9:38: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type +// :9:38: note: generic function instantiated with comptime-only return type 'tmp.S(fn () void)' is evaluated at comptime +// :3:16: note: struct requires comptime because of this field +// :3:16: note: use '*const fn () void' for a function pointer type diff --git a/test/cases/compile_errors/global_var_struct_init_in_comptim_block.zig b/test/cases/compile_errors/global_var_struct_init_in_comptime_block.zig similarity index 80% rename from test/cases/compile_errors/global_var_struct_init_in_comptim_block.zig rename to test/cases/compile_errors/global_var_struct_init_in_comptime_block.zig index 2ffb3747fe13..000fe434186b 100644 --- a/test/cases/compile_errors/global_var_struct_init_in_comptim_block.zig +++ b/test/cases/compile_errors/global_var_struct_init_in_comptime_block.zig @@ -12,3 +12,4 @@ comptime { // // :6:17: error: unable to evaluate comptime expression // :6:17: note: operation is runtime due to this operand +// :5:1: note: 'comptime' keyword forces comptime evaluation diff --git a/test/cases/compile_errors/global_variable_stored_in_global_const.zig b/test/cases/compile_errors/global_variable_stored_in_global_const.zig index 594498f1c186..b7990f65ffe9 100644 --- a/test/cases/compile_errors/global_variable_stored_in_global_const.zig +++ b/test/cases/compile_errors/global_variable_stored_in_global_const.zig @@ -5,8 +5,6 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :2:11: error: unable to resolve comptime value -// :2:11: note: global variable initializer must be comptime-known +// :2:11: note: initializer of container-level variable must be comptime-known diff --git a/test/cases/compile_errors/incorrect_pointer_dereference_syntax.zig b/test/cases/compile_errors/incorrect_pointer_dereference_syntax.zig index 4f80b6186507..04f4ddf2897f 100644 --- a/test/cases/compile_errors/incorrect_pointer_dereference_syntax.zig +++ b/test/cases/compile_errors/incorrect_pointer_dereference_syntax.zig @@ -1,12 +1,9 @@ pub export fn entry() void { - var a: *u32 = undefined; + const a: *u32 = undefined; _ = *a; - _ = &a; } // error -// backend=stage2 -// target=native // // :3:10: error: expected type 'type', found '*u32' // :3:10: note: use '.*' to dereference pointer diff --git a/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig b/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig index 2b3738cd2f7e..67079c8a2dad 100644 --- a/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig +++ b/test/cases/compile_errors/inline_call_runtime_value_to_comptime_param.zig @@ -14,4 +14,4 @@ pub export fn entry() void { // target=native // // :5:18: error: unable to resolve comptime value -// :5:18: note: parameter is comptime +// :5:18: note: argument to comptime parameter must be comptime-known diff --git a/test/cases/compile_errors/int-float_conversion_to_comptime_int-float.zig b/test/cases/compile_errors/int-float_conversion_to_comptime_int-float.zig index d6bf372a88ce..4b118664c56d 100644 --- a/test/cases/compile_errors/int-float_conversion_to_comptime_int-float.zig +++ b/test/cases/compile_errors/int-float_conversion_to_comptime_int-float.zig @@ -10,10 +10,8 @@ export fn bar() void { } // error -// backend=stage2 -// target=native // // :4:41: error: unable to resolve comptime value -// :4:41: note: value being casted to 'comptime_int' must be comptime-known +// :4:41: note: value casted to 'comptime_int' must be comptime-known // :9:43: error: unable to resolve comptime value -// :9:43: note: value being casted to 'comptime_float' must be comptime-known +// :9:43: note: value casted to 'comptime_float' must be comptime-known diff --git a/test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig b/test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig index d9bd0dd2b223..ad3c9325acf3 100644 --- a/test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig +++ b/test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig @@ -13,9 +13,8 @@ export fn entry() usize { } // error -// backend=stage2 -// target=native // // :6:24: error: unable to evaluate comptime expression // :6:5: note: operation is runtime due to this operand -// :4:17: note: called from here +// :4:17: note: called at comptime from here +// :4:17: note: initializer of container-level variable must be comptime-known diff --git a/test/cases/compile_errors/non-pure_function_returns_type.zig b/test/cases/compile_errors/non-pure_function_returns_type.zig index d7d07668d433..3b83c73b6ce5 100644 --- a/test/cases/compile_errors/non-pure_function_returns_type.zig +++ b/test/cases/compile_errors/non-pure_function_returns_type.zig @@ -23,4 +23,5 @@ export fn function_with_return_type_type() void { // // :3:7: error: unable to evaluate comptime expression // :3:5: note: operation is runtime due to this operand -// :16:19: note: called from here +// :16:19: note: called at comptime from here +// :16:19: note: types must be comptime-known diff --git a/test/cases/compile_errors/non_comptime_param_in_comptime_function.zig b/test/cases/compile_errors/non_comptime_param_in_comptime_function.zig index a902ffe9399a..cfb68bbcf6f5 100644 --- a/test/cases/compile_errors/non_comptime_param_in_comptime_function.zig +++ b/test/cases/compile_errors/non_comptime_param_in_comptime_function.zig @@ -9,10 +9,7 @@ export fn entry() void { } // error -// backend=stage2 -// target=native // // :8:11: error: unable to resolve comptime value -// :8:11: note: argument to function being called at comptime must be comptime-known -// :1:20: note: expression is evaluated at comptime because the function returns a comptime-only type 'type' +// :1:20: note: function with comptime-only return type 'type' is evaluated at comptime // :1:20: note: types are not available at runtime diff --git a/test/cases/compile_errors/non_constant_expression_in_array_size.zig b/test/cases/compile_errors/non_constant_expression_in_array_size.zig index 70d1655eb7b2..cbc0455bc348 100644 --- a/test/cases/compile_errors/non_constant_expression_in_array_size.zig +++ b/test/cases/compile_errors/non_constant_expression_in_array_size.zig @@ -15,5 +15,5 @@ export fn entry() usize { // target=native // // :6:12: error: unable to resolve comptime value -// :6:12: note: value being returned at comptime must be comptime-known -// :2:12: note: called from here +// :2:12: note: called at comptime from here +// :1:13: note: struct fields must be comptime-known diff --git a/test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig b/test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig index c2bec83afdd3..38ab6a7566c2 100644 --- a/test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig +++ b/test/cases/compile_errors/runtime_assignment_to_comptime_struct_type.zig @@ -10,8 +10,8 @@ export fn f() void { } // error -// backend=stage2 -// target=native // // :7:23: error: unable to resolve comptime value -// :7:23: note: initializer of comptime only struct must be comptime-known +// :7:23: note: initializer of comptime-only struct 'tmp.Foo' must be comptime-known +// :3:10: note: struct requires comptime because of this field +// :3:10: note: types are not available at runtime diff --git a/test/cases/compile_errors/runtime_assignment_to_comptime_union_type.zig b/test/cases/compile_errors/runtime_assignment_to_comptime_union_type.zig index 21b00ac545fc..a198ff8e73bf 100644 --- a/test/cases/compile_errors/runtime_assignment_to_comptime_union_type.zig +++ b/test/cases/compile_errors/runtime_assignment_to_comptime_union_type.zig @@ -10,8 +10,8 @@ export fn f() void { } // error -// backend=stage2 -// target=native // // :8:23: error: unable to resolve comptime value -// :8:23: note: initializer of comptime only union must be comptime-known +// :8:23: note: initializer of comptime-only union 'tmp.Foo' must be comptime-known +// :3:10: note: union requires comptime because of this field +// :3:10: note: types are not available at runtime diff --git a/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig new file mode 100644 index 000000000000..8c1d31adf299 --- /dev/null +++ b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig @@ -0,0 +1,36 @@ +export fn entry1() void { + foo(); +} + +comptime { + qux(); +} + +inline fn foo() void { + _ = bar(); +} + +fn bar() type { + qux(); + return u8; +} + +fn qux() void { + rt = 123; +} + +var rt: u32 = undefined; + +// error +// +// :19:8: error: unable to evaluate comptime expression +// :19:5: note: operation is runtime due to this operand +// :14:8: note: called at comptime from here +// :10:12: note: called at comptime from here +// :13:10: note: function with comptime-only return type 'type' is evaluated at comptime +// :13:10: note: types are not available at runtime +// :2:8: note: called from here +// :19:8: error: unable to evaluate comptime expression +// :19:5: note: operation is runtime due to this operand +// :6:8: note: called at comptime from here +// :5:1: note: 'comptime' keyword forces comptime evaluation diff --git a/test/cases/compile_errors/runtime_to_comptime_num.zig b/test/cases/compile_errors/runtime_to_comptime_num.zig index eb5d5fc6309d..4cf24ceb1769 100644 --- a/test/cases/compile_errors/runtime_to_comptime_num.zig +++ b/test/cases/compile_errors/runtime_to_comptime_num.zig @@ -26,10 +26,10 @@ pub export fn entry4() void { // target=native // // :4:27: error: unable to resolve comptime value -// :4:27: note: value being casted to 'comptime_int' must be comptime-known +// :4:27: note: value casted to 'comptime_int' must be comptime-known // :9:29: error: unable to resolve comptime value -// :9:29: note: value being casted to 'comptime_float' must be comptime-known +// :9:29: note: value casted to 'comptime_float' must be comptime-known // :15:10: error: unable to resolve comptime value -// :15:10: note: value being casted to 'comptime_float' must be comptime-known +// :15:10: note: value casted to 'comptime_float' must be comptime-known // :21:10: error: unable to resolve comptime value -// :21:10: note: value being casted to 'comptime_int' must be comptime-known +// :21:10: note: value casted to 'comptime_int' must be comptime-known diff --git a/test/cases/compile_errors/runtime_value_in_comptime_scope.zig b/test/cases/compile_errors/runtime_value_in_comptime_scope.zig new file mode 100644 index 000000000000..37c6b46dbaa6 --- /dev/null +++ b/test/cases/compile_errors/runtime_value_in_comptime_scope.zig @@ -0,0 +1,61 @@ +var rt_val: [5]u32 = .{ 1, 2, 3, 4, 5 }; + +comptime { + _ = rt_val; // fine +} + +comptime { + const a = rt_val; // error + _ = a; +} + +comptime { + const l = rt_val.len; // fine + @compileLog(l); +} + +export fn foo() void { + _ = comptime rt_val; // error +} + +export fn bar() void { + const l = comptime rt_val.len; // fine + @compileLog(l); +} + +export fn baz() void { + const S = struct { + fn inner() void { + _ = comptime rt_val; + } + }; + comptime S.inner(); // fine; inner comptime is a nop + S.inner(); // error +} + +export fn qux() void { + const S = struct { + fn inner() void { + const a = rt_val; + _ = a; + } + }; + S.inner(); // fine; everything is runtime + comptime S.inner(); // error +} + +// error +// +// :8:15: error: unable to resolve comptime value +// :7:1: note: 'comptime' keyword forces comptime evaluation +// :18:9: error: unable to resolve comptime value +// :18:9: note: 'comptime' keyword forces comptime evaluation +// :29:17: error: unable to resolve comptime value +// :29:17: note: 'comptime' keyword forces comptime evaluation +// :39:23: error: unable to resolve comptime value +// :44:21: note: called at comptime from here +// :44:5: note: 'comptime' keyword forces comptime evaluation +// +// Compile Log Output: +// @as(usize, 5) +// @as(usize, 5) diff --git a/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig b/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig index 8b43842f230b..6038b4ea260f 100644 --- a/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig +++ b/test/cases/compile_errors/slice_of_single-item_pointer_bounds.zig @@ -31,13 +31,13 @@ export fn entry2() void { // error // -// :5:12: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] -// :9:13: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :5:12: error: slice of single-item pointer must be bounded +// :9:13: error: slice of single-item pointer must have bounds [0..0], [0..1], or [1..1] // :9:13: note: expected '0', found '1' -// :13:16: error: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :13:16: error: slice of single-item pointer must have bounds [0..0], [0..1], or [1..1] // :13:16: note: expected '1', found '2' // :17:16: error: end index 2 out of bounds for slice of single-item pointer // :23:13: error: unable to resolve comptime value -// :23:13: note: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :23:13: note: slice of single-item pointer must have comptime-known bounds // :29:16: error: unable to resolve comptime value -// :29:16: note: slice of single-item pointer must have comptime-known bounds [0..0], [0..1], or [1..1] +// :29:16: note: slice of single-item pointer must have comptime-known bounds diff --git a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig index a383961cf467..561b39a4e817 100644 --- a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig +++ b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig @@ -33,12 +33,13 @@ pub export fn entry3() void { } // error -// backend=stage2 -// target=native // // :7:13: error: unable to evaluate comptime expression // :7:16: note: operation is runtime due to this operand +// :7:13: note: initializer of container-level variable must be comptime-known // :13:13: error: unable to evaluate comptime expression // :13:16: note: operation is runtime due to this operand +// :13:13: note: initializer of container-level variable must be comptime-known // :22:9: error: unable to evaluate comptime expression // :22:21: note: operation is runtime due to this operand +// :21:13: note: enum fields must be comptime-known diff --git a/test/cases/compile_errors/unable_to_evaluate_expr_inside_cimport.zig b/test/cases/compile_errors/unable_to_evaluate_expr_inside_cimport.zig index 9460a5899303..ab98dcd673e2 100644 --- a/test/cases/compile_errors/unable_to_evaluate_expr_inside_cimport.zig +++ b/test/cases/compile_errors/unable_to_evaluate_expr_inside_cimport.zig @@ -12,4 +12,4 @@ export fn entry() void { // // :2:11: error: unable to evaluate comptime expression // :2:13: note: operation is runtime due to this operand -// :1:11: note: expression is evaluated at comptime because it is inside a @cImport +// :1:11: note: operand to '@cImport' is evaluated at comptime diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 447984d2779a..f566464bac77 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -57,8 +57,8 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { \\} , &[_][]const u8{ ":3:12: error: unable to resolve comptime value", - ":3:12: note: argument to function being called at comptime must be comptime-known", - ":2:55: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type", + ":2:55: note: generic function instantiated with comptime-only return type '?fn () void' is evaluated at comptime", + ":2:55: note: use '*const fn () void' for a function pointer type", }); case.addSourceFile("b.zig", \\pub const ElfDynLib = struct { @@ -198,7 +198,9 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { ":8:36: error: runtime-known argument passed to comptime parameter", ":2:41: note: declared comptime here", ":13:32: error: unable to resolve comptime value", - ":13:32: note: initializer of comptime only struct must be comptime-known", + ":13:32: note: initializer of comptime-only struct 'tmp.callAnytypeFunctionWithRuntimeComptimeOnlyType.S' must be comptime-known", + ":12:35: note: struct requires comptime because of this field", + ":12:35: note: types are not available at runtime", }); case.addSourceFile("import.zig",