Merge pull request #22352 from mlugg/zir-comptime-reason

Zir: attach reason to `block_comptime` and improve corresponding error reporting
This commit is contained in:
Matthew Lugg 2024-12-31 14:35:28 +00:00 committed by GitHub
commit 0df1f3df2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 1146 additions and 828 deletions

View File

@ -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;

View File

@ -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(&param_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;

View File

@ -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);

View File

@ -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) {

File diff suppressed because it is too large Load Diff

View File

@ -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,
};

View File

@ -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),
@ -1342,17 +1344,22 @@ 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);
try self.writeSrcNode(stream, inst_data.src_node);
}
fn writePlNodeBlockWithoutSrc(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 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 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.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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",