authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-10 11:50:01-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-10 11:50:01-07:00
log275e926cf851144ef6a4c64963e47f3b955870cc
treeed1717db1a7f6c8c931d5c08e244a11a2334ff93
parent0461a64a93f0596e98b62d596bb547e5455577d2
parentf32b9bc776bfffe0a1adadc013ff3fa3e5d6d34b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16604 from mlugg/result-type-shenanigans

Fix RLS issues, fix crash on invalid result type for `@splat`, refactor some bits of generic instantiations

18 files changed, 858 insertions(+), 491 deletions(-)

src/Air.zig+4-2
......@@ -1528,11 +1528,13 @@ pub fn refToInterned(ref: Inst.Ref) ?InternPool.Index {
15281528}
15291529
15301530pub fn internedToRef(ip_index: InternPool.Index) Inst.Ref {
1531 assert(@intFromEnum(ip_index) >> 31 == 0);
15321531 return switch (ip_index) {
15331532 .var_args_param_type => .var_args_param_type,
15341533 .none => .none,
1535 else => @enumFromInt(@as(u31, @intCast(@intFromEnum(ip_index)))),
1534 else => {
1535 assert(@intFromEnum(ip_index) >> 31 == 0);
1536 return @enumFromInt(@as(u31, @intCast(@intFromEnum(ip_index))));
1537 },
15361538 };
15371539}
15381540
src/AstGen.zig+35-17
......@@ -1509,9 +1509,11 @@ fn arrayInitExpr(
15091509 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
15101510 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
15111511 },
1512 .ty, .coerced_ty => {
1513 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
1514 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
1512 .ty, .coerced_ty => |ty_inst| {
1513 const arr_ty = if (types.array != .none) types.array else blk: {
1514 break :blk try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
1515 };
1516 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, arr_ty, types.elem, .array_init);
15151517 return rvalue(gz, ri, result, node);
15161518 },
15171519 .ptr => |ptr_res| {
......@@ -1748,7 +1750,9 @@ fn structInitExpr(
17481750 },
17491751 .ty, .coerced_ty => |ty_inst| {
17501752 if (struct_init.ast.type_expr == 0) {
1751 const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon);
1753 const struct_ty_inst = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
1754 _ = try gz.addUnNode(.validate_struct_init_ty, struct_ty_inst, node);
1755 const result = try structInitExprRlTy(gz, scope, node, struct_init, struct_ty_inst, .struct_init);
17521756 return rvalue(gz, ri, result, node);
17531757 }
17541758 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
......@@ -2565,6 +2569,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25652569 .array_type_sentinel,
25662570 .elem_type_index,
25672571 .elem_type,
2572 .vector_elem_type,
25682573 .vector_type,
25692574 .indexable_ptr_len,
25702575 .anyframe_type,
......@@ -2743,6 +2748,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27432748 .for_len,
27442749 .@"try",
27452750 .try_ptr,
2751 .opt_eu_base_ty,
27462752 => break :b false,
27472753
27482754 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
......@@ -8314,7 +8320,10 @@ fn builtinCall(
83148320 local_val.used = ident_token;
83158321 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
83168322 .operand = local_val.inst,
8317 .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]),
8323 // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but
8324 // that currently hits assertions in Sema due to type resolution issues.
8325 // See #16603
8326 .options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]),
83188327 });
83198328 return rvalue(gz, ri, .void_value, node);
83208329 }
......@@ -8329,7 +8338,10 @@ fn builtinCall(
83298338 const loaded = try gz.addUnNode(.load, local_ptr.ptr, node);
83308339 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
83318340 .operand = loaded,
8332 .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]),
8341 // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but
8342 // that currently hits assertions in Sema due to type resolution issues.
8343 // See #16603
8344 .options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]),
83338345 });
83348346 return rvalue(gz, ri, .void_value, node);
83358347 }
......@@ -8363,7 +8375,10 @@ fn builtinCall(
83638375 },
83648376 else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}),
83658377 }
8366 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .export_options_type } }, params[1]);
8378 // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but
8379 // that currently hits assertions in Sema due to type resolution issues.
8380 // See #16603
8381 const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]);
83678382 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{
83688383 .namespace = namespace,
83698384 .decl_name = decl_name,
......@@ -8373,7 +8388,10 @@ fn builtinCall(
83738388 },
83748389 .@"extern" => {
83758390 const type_inst = try typeExpr(gz, scope, params[0]);
8376 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .extern_options_type } }, params[1]);
8391 // TODO: the result location here should be `.{ .coerced_ty = .extern_options_type }`, but
8392 // that currently hits assertions in Sema due to type resolution issues.
8393 // See #16603
8394 const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]);
83778395 const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{
83788396 .node = gz.nodeIndexToRelative(node),
83798397 .lhs = type_inst,
......@@ -8477,7 +8495,10 @@ fn builtinCall(
84778495 // zig fmt: on
84788496
84798497 .Type => {
8480 const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .type_info_type } }, params[0]);
8498 // TODO: the result location here should be `.{ .coerced_ty = .type_info_type }`, but
8499 // that currently hits assertions in Sema due to type resolution issues.
8500 // See #16603
8501 const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
84818502
84828503 const gpa = gz.astgen.gpa;
84838504
......@@ -8604,13 +8625,7 @@ fn builtinCall(
86048625
86058626 .splat => {
86068627 const result_type = try ri.rl.resultType(gz, node, "@splat");
8607 const elem_type = try gz.add(.{
8608 .tag = .elem_type_index,
8609 .data = .{ .bin = .{
8610 .lhs = result_type,
8611 .rhs = @as(Zir.Inst.Ref, @enumFromInt(0)),
8612 } },
8613 });
8628 const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
86148629 const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
86158630 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
86168631 .lhs = result_type,
......@@ -8755,7 +8770,10 @@ fn builtinCall(
87558770 },
87568771 .prefetch => {
87578772 const ptr = try expr(gz, scope, .{ .rl = .none }, params[0]);
8758 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .prefetch_options_type } }, params[1]);
8773 // TODO: the result location here should be `.{ .coerced_ty = .preftech_options_type }`, but
8774 // that currently hits assertions in Sema due to type resolution issues.
8775 // See #16603
8776 const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]);
87598777 _ = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{
87608778 .node = gz.nodeIndexToRelative(node),
87618779 .lhs = ptr,
src/Module.zig-29
......@@ -5938,35 +5938,6 @@ pub fn paramSrc(
59385938 unreachable;
59395939}
59405940
5941pub fn argSrc(
5942 mod: *Module,
5943 call_node_offset: i32,
5944 decl: *Decl,
5945 start_arg_i: usize,
5946 bound_arg_src: ?LazySrcLoc,
5947) LazySrcLoc {
5948 @setCold(true);
5949 const gpa = mod.gpa;
5950 if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?;
5951 const arg_i = start_arg_i - @intFromBool(bound_arg_src != null);
5952 const tree = decl.getFileScope(mod).getTree(gpa) catch |err| {
5953 // In this case we emit a warning + a less precise source location.
5954 log.warn("unable to load {s}: {s}", .{
5955 decl.getFileScope(mod).sub_file_path, @errorName(err),
5956 });
5957 return LazySrcLoc.nodeOffset(0);
5958 };
5959 const node = decl.relativeToNodeIndex(call_node_offset);
5960 var args: [1]Ast.Node.Index = undefined;
5961 const call_full = tree.fullCall(&args, node) orelse {
5962 assert(tree.nodes.items(.tag)[node] == .builtin_call);
5963 const call_args_node = tree.extra_data[tree.nodes.items(.data)[node].rhs - 1];
5964 const call_args_offset = decl.nodeIndexToRelative(call_args_node);
5965 return mod.initSrc(call_args_offset, decl, arg_i);
5966 };
5967 return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(call_full.ast.params[arg_i]));
5968}
5969
59705941pub fn initSrc(
59715942 mod: *Module,
59725943 init_node_offset: i32,
src/Sema.zig+693-437
......@@ -70,7 +70,6 @@ generic_owner: InternPool.Index = .none,
7070/// instantiation can point back to the instantiation site in addition to the
7171/// declaration site.
7272generic_call_src: LazySrcLoc = .unneeded,
73generic_bound_arg_src: ?LazySrcLoc = null,
7473/// Corresponds to `generic_call_src`.
7574generic_call_decl: Decl.OptionalIndex = .none,
7675/// The key is types that must be fully resolved prior to machine code
......@@ -1022,6 +1021,7 @@ fn analyzeBodyInner(
10221021 .elem_val_node => try sema.zirElemValNode(block, inst),
10231022 .elem_type_index => try sema.zirElemTypeIndex(block, inst),
10241023 .elem_type => try sema.zirElemType(block, inst),
1024 .vector_elem_type => try sema.zirVectorElemType(block, inst),
10251025 .enum_literal => try sema.zirEnumLiteral(block, inst),
10261026 .int_from_enum => try sema.zirIntFromEnum(block, inst),
10271027 .enum_from_int => try sema.zirEnumFromInt(block, inst),
......@@ -1125,6 +1125,7 @@ fn analyzeBodyInner(
11251125 .array_base_ptr => try sema.zirArrayBasePtr(block, inst),
11261126 .field_base_ptr => try sema.zirFieldBasePtr(block, inst),
11271127 .for_len => try sema.zirForLen(block, inst),
1128 .opt_eu_base_ty => try sema.zirOptEuBaseTy(block, inst),
11281129
11291130 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
11301131 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
......@@ -1359,12 +1360,12 @@ fn analyzeBodyInner(
13591360 continue;
13601361 },
13611362 .validate_array_init_ty => {
1362 try sema.validateArrayInitTy(block, inst);
1363 try sema.zirValidateArrayInitTy(block, inst);
13631364 i += 1;
13641365 continue;
13651366 },
13661367 .validate_struct_init_ty => {
1367 try sema.validateStructInitTy(block, inst);
1368 try sema.zirValidateStructInitTy(block, inst);
13681369 i += 1;
13691370 continue;
13701371 },
......@@ -1399,22 +1400,22 @@ fn analyzeBodyInner(
13991400 continue;
14001401 },
14011402 .param => {
1402 try sema.zirParam(block, inst, i, false);
1403 try sema.zirParam(block, inst, false);
14031404 i += 1;
14041405 continue;
14051406 },
14061407 .param_comptime => {
1407 try sema.zirParam(block, inst, i, true);
1408 try sema.zirParam(block, inst, true);
14081409 i += 1;
14091410 continue;
14101411 },
14111412 .param_anytype => {
1412 try sema.zirParamAnytype(block, inst, i, false);
1413 try sema.zirParamAnytype(block, inst, false);
14131414 i += 1;
14141415 continue;
14151416 },
14161417 .param_anytype_comptime => {
1417 try sema.zirParamAnytype(block, inst, i, true);
1418 try sema.zirParamAnytype(block, inst, true);
14181419 i += 1;
14191420 continue;
14201421 },
......@@ -4312,7 +4313,31 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
43124313 return len;
43134314}
43144315
4315fn validateArrayInitTy(
4316fn zirOptEuBaseTy(
4317 sema: *Sema,
4318 block: *Block,
4319 inst: Zir.Inst.Index,
4320) CompileError!Air.Inst.Ref {
4321 const mod = sema.mod;
4322 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4323 var ty = sema.resolveType(block, .unneeded, inst_data.operand) catch |err| switch (err) {
4324 // Since this is a ZIR instruction that returns a type, encountering
4325 // generic poison should not result in a failed compilation, but the
4326 // generic poison type. This prevents unnecessary failures when
4327 // constructing types at compile-time.
4328 error.GenericPoison => return .generic_poison_type,
4329 else => |e| return e,
4330 };
4331 while (true) {
4332 switch (ty.zigTypeTag(mod)) {
4333 .Optional => ty = ty.optionalChild(mod),
4334 .ErrorUnion => ty = ty.errorUnionPayload(mod),
4335 else => return sema.addType(ty),
4336 }
4337 }
4338}
4339
4340fn zirValidateArrayInitTy(
43164341 sema: *Sema,
43174342 block: *Block,
43184343 inst: Zir.Inst.Index,
......@@ -4322,7 +4347,11 @@ fn validateArrayInitTy(
43224347 const src = inst_data.src();
43234348 const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node };
43244349 const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
4325 const ty = try sema.resolveType(block, ty_src, extra.ty);
4350 const ty = sema.resolveType(block, ty_src, extra.ty) catch |err| switch (err) {
4351 // It's okay for the type to be unknown: this will result in an anonymous array init.
4352 error.GenericPoison => return,
4353 else => |e| return e,
4354 };
43264355
43274356 switch (ty.zigTypeTag(mod)) {
43284357 .Array => {
......@@ -4358,7 +4387,7 @@ fn validateArrayInitTy(
43584387 return sema.failWithArrayInitNotSupported(block, ty_src, ty);
43594388}
43604389
4361fn validateStructInitTy(
4390fn zirValidateStructInitTy(
43624391 sema: *Sema,
43634392 block: *Block,
43644393 inst: Zir.Inst.Index,
......@@ -4366,7 +4395,11 @@ fn validateStructInitTy(
43664395 const mod = sema.mod;
43674396 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
43684397 const src = inst_data.src();
4369 const ty = try sema.resolveType(block, src, inst_data.operand);
4398 const ty = sema.resolveType(block, src, inst_data.operand) catch |err| switch (err) {
4399 // It's okay for the type to be unknown: this will result in an anonymous struct init.
4400 error.GenericPoison => return,
4401 else => |e| return e,
4402 };
43704403
43714404 switch (ty.zigTypeTag(mod)) {
43724405 .Struct, .Union => return,
......@@ -6502,7 +6535,6 @@ fn zirCall(
65026535 defer tracy.end();
65036536
65046537 const mod = sema.mod;
6505 const ip = &mod.intern_pool;
65066538 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
65076539 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
65086540 const call_src = inst_data.src();
......@@ -6526,96 +6558,62 @@ fn zirCall(
65266558 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
65276559 },
65286560 };
6529 var resolved_args: []Air.Inst.Ref = undefined;
6530 var bound_arg_src: ?LazySrcLoc = null;
6531 var func: Air.Inst.Ref = undefined;
6532 var arg_index: u32 = 0;
6533 switch (callee) {
6534 .direct => |func_inst| {
6535 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6536 func = func_inst;
6537 },
6538 .method => |method| {
6539 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6540 func = method.func_inst;
6541 resolved_args[0] = method.arg0_inst;
6542 arg_index += 1;
6543 bound_arg_src = callee_src;
6544 },
6545 }
6561 const func: Air.Inst.Ref = switch (callee) {
6562 .direct => |func_inst| func_inst,
6563 .method => |method| method.func_inst,
6564 };
65466565
65476566 const callee_ty = sema.typeOf(func);
6548 const total_args = args_len + @intFromBool(bound_arg_src != null);
6549 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
6550
6551 const args_body = sema.code.extra[extra.end..];
6567 const total_args = args_len + @intFromBool(callee == .method);
6568 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, callee == .method);
65526569
6553 var input_is_error = false;
6570 // The block index before the call, so we can potentially insert an error trace save here later.
65546571 const block_index: Air.Inst.Index = @intCast(block.instructions.items.len);
65556572
6556 const func_ty_info = mod.typeToFunc(func_ty).?;
6557 const fn_params_len = func_ty_info.param_types.len;
6558 const parent_comptime = block.is_comptime;
6559 // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
6560 var extra_index: usize = 0;
6561 var arg_start: u32 = args_len;
6562 while (extra_index < args_len) : ({
6563 extra_index += 1;
6564 arg_index += 1;
6565 }) {
6566 const arg_end = sema.code.extra[extra.end + extra_index];
6567 defer arg_start = arg_end;
6568
6569 // Generate args to comptime params in comptime block.
6570 defer block.is_comptime = parent_comptime;
6571 if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) {
6572 block.is_comptime = true;
6573 // TODO set comptime_reason
6574 }
6575
6576 sema.inst_map.putAssumeCapacity(inst, inst: {
6577 if (arg_index >= fn_params_len)
6578 break :inst Air.Inst.Ref.var_args_param_type;
6573 // This will be set by `analyzeCall` to indicate whether any parameter was an error (making the
6574 // error trace potentially dirty).
6575 var input_is_error = false;
65796576
6580 if (func_ty_info.param_types.get(ip)[arg_index] == .generic_poison_type)
6581 break :inst Air.Inst.Ref.generic_poison_type;
6577 const args_info: CallArgsInfo = .{ .zir_call = .{
6578 .bound_arg = switch (callee) {
6579 .direct => .none,
6580 .method => |method| method.arg0_inst,
6581 },
6582 .bound_arg_src = callee_src,
6583 .call_inst = inst,
6584 .call_node_offset = inst_data.src_node,
6585 .num_args = args_len,
6586 .args_body = sema.code.extra[extra.end..],
6587 .any_arg_is_error = &input_is_error,
6588 } };
65826589
6583 break :inst try sema.addType(func_ty_info.param_types.get(ip)[arg_index].toType());
6584 });
6590 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
6591 const call_dbg_node = inst - 1;
6592 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
65856593
6586 const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
6587 const resolved_ty = sema.typeOf(resolved);
6588 if (resolved_ty.zigTypeTag(mod) == .NoReturn) {
6589 return resolved;
6590 }
6591 if (resolved_ty.isError(mod)) {
6592 input_is_error = true;
6593 }
6594 resolved_args[arg_index] = resolved;
6595 }
65966594 if (sema.owner_func_index == .none or
6597 !ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn)
6595 !mod.intern_pool.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn)
65986596 {
6599 input_is_error = false; // input was an error type, but no errorable fn's were actually called
6597 // No errorable fn actually called; we have no error return trace
6598 input_is_error = false;
66006599 }
66016600
6602 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
6603 const call_dbg_node = inst - 1;
6604
66056601 if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and
66066602 !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
66076603 {
6608 const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
6609 break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
6610 };
6611
66126604 const return_ty = sema.typeOf(call_inst);
66136605 if (modifier != .always_tail and return_ty.isNoReturn(mod))
66146606 return call_inst; // call to "fn(...) noreturn", don't pop
66156607
6608 // TODO: we don't fix up the error trace for always_tail correctly, we should be doing it
6609 // *before* the recursive call. This will be a bit tricky to do and probably requires
6610 // moving this logic into analyzeCall. But that's probably a good idea anyway.
6611 if (modifier == .always_tail)
6612 return call_inst;
6613
66166614 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only
66176615 // need to clean-up our own trace if we were passed to a non-error-handling expression.
6618 if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) {
6616 if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) {
66196617 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
66206618 const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
66216619 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index");
......@@ -6635,12 +6633,9 @@ fn zirCall(
66356633 try sema.popErrorReturnTrace(block, call_src, operand, save_inst);
66366634 }
66376635
6638 if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
6639 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
6640
66416636 return call_inst;
66426637 } else {
6643 return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
6638 return call_inst;
66446639 }
66456640}
66466641
......@@ -6747,7 +6742,19 @@ fn callBuiltin(
67476742 if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {
67486743 std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });
67496744 }
6750 _ = try sema.analyzeCall(block, builtin_fn, func_ty, call_src, call_src, modifier, false, args, null, null, operation);
6745
6746 _ = try sema.analyzeCall(
6747 block,
6748 builtin_fn,
6749 func_ty,
6750 call_src,
6751 call_src,
6752 modifier,
6753 false,
6754 .{ .resolved = .{ .src = call_src, .args = args } },
6755 null,
6756 operation,
6757 );
67516758}
67526759
67536760const CallOperation = enum {
......@@ -6758,6 +6765,251 @@ const CallOperation = enum {
67586765 @"error return",
67596766};
67606767
6768const CallArgsInfo = union(enum) {
6769 /// The full list of resolved (but uncoerced) arguments is known ahead of time.
6770 resolved: struct {
6771 src: LazySrcLoc,
6772 args: []const Air.Inst.Ref,
6773 },
6774
6775 /// The list of resolved (but uncoerced) arguments is known ahead of time, but
6776 /// originated from a usage of the @call builtin at the given node offset.
6777 call_builtin: struct {
6778 call_node_offset: i32,
6779 args: []const Air.Inst.Ref,
6780 },
6781
6782 /// This call corresponds to a ZIR call instruction. The arguments have not yet been
6783 /// resolved. They must be resolved by `analyzeCall` so that argument resolution and
6784 /// generic instantiation may be interleaved. This is required for RLS to work on
6785 /// generic parameters.
6786 zir_call: struct {
6787 /// This may be `none`, in which case it is ignored. Otherwise, it is the
6788 /// already-resolved value of the first argument, from method call syntax.
6789 bound_arg: Air.Inst.Ref,
6790 /// The source location of `bound_arg` if it is not `null`. Otherwise `undefined`.
6791 bound_arg_src: LazySrcLoc,
6792 /// The ZIR call instruction. The parameter type is placed at this index while
6793 /// analyzing arguments.
6794 call_inst: Zir.Inst.Index,
6795 /// The node offset of `call_inst`.
6796 call_node_offset: i32,
6797 /// The number of arguments to this call, not including `bound_arg`.
6798 num_args: u32,
6799 /// The ZIR corresponding to all function arguments (other than `bound_arg`, if it
6800 /// is not `none`). Format is precisely the same as trailing data of ZIR `call`.
6801 args_body: []const Zir.Inst.Index,
6802 /// This bool will be set to true if any argument evaluated turns out to have an error set or error union type.
6803 /// This is used by the caller to restore the error return trace when necessary.
6804 any_arg_is_error: *bool,
6805 },
6806
6807 fn count(cai: CallArgsInfo) usize {
6808 return switch (cai) {
6809 inline .resolved, .call_builtin => |resolved| resolved.args.len,
6810 .zir_call => |zir_call| zir_call.num_args + @intFromBool(zir_call.bound_arg != .none),
6811 };
6812 }
6813
6814 fn argSrc(cai: CallArgsInfo, block: *Block, arg_index: usize) LazySrcLoc {
6815 return switch (cai) {
6816 .resolved => |resolved| resolved.src,
6817 .call_builtin => |call_builtin| .{ .call_arg = .{
6818 .decl = block.src_decl,
6819 .call_node_offset = call_builtin.call_node_offset,
6820 .arg_index = @intCast(arg_index),
6821 } },
6822 .zir_call => |zir_call| if (arg_index == 0 and zir_call.bound_arg != .none) {
6823 return zir_call.bound_arg_src;
6824 } else .{ .call_arg = .{
6825 .decl = block.src_decl,
6826 .call_node_offset = zir_call.call_node_offset,
6827 .arg_index = @intCast(arg_index - @intFromBool(zir_call.bound_arg != .none)),
6828 } },
6829 };
6830 }
6831
6832 /// Analyzes the arg at `arg_index` and coerces it to `param_ty`.
6833 /// `param_ty` may be `generic_poison` or `var_args_param`.
6834 /// `func_ty_info` may be the type before instantiation, even if a generic
6835 /// instantiation has been partially completed.
6836 fn analyzeArg(
6837 cai: CallArgsInfo,
6838 sema: *Sema,
6839 block: *Block,
6840 arg_index: usize,
6841 param_ty: Type,
6842 func_ty_info: InternPool.Key.FuncType,
6843 func_inst: Air.Inst.Ref,
6844 ) CompileError!Air.Inst.Ref {
6845 const mod = sema.mod;
6846 const param_count = func_ty_info.param_types.len;
6847 switch (param_ty.toIntern()) {
6848 .generic_poison_type, .var_args_param_type => {},
6849 else => try sema.queueFullTypeResolution(param_ty),
6850 }
6851 const uncoerced_arg: Air.Inst.Ref = switch (cai) {
6852 inline .resolved, .call_builtin => |resolved| resolved.args[arg_index],
6853 .zir_call => |zir_call| arg_val: {
6854 const has_bound_arg = zir_call.bound_arg != .none;
6855 if (arg_index == 0 and has_bound_arg) {
6856 break :arg_val zir_call.bound_arg;
6857 }
6858 const real_arg_idx = arg_index - @intFromBool(has_bound_arg);
6859
6860 const arg_body = if (real_arg_idx == 0) blk: {
6861 const start = zir_call.num_args;
6862 const end = zir_call.args_body[0];
6863 break :blk zir_call.args_body[start..end];
6864 } else blk: {
6865 const start = zir_call.args_body[real_arg_idx - 1];
6866 const end = zir_call.args_body[real_arg_idx];
6867 break :blk zir_call.args_body[start..end];
6868 };
6869
6870 // Generate args to comptime params in comptime block
6871 const parent_comptime = block.is_comptime;
6872 defer block.is_comptime = parent_comptime;
6873 // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx`
6874 if (arg_index < @min(param_count, 32) and func_ty_info.paramIsComptime(@intCast(arg_index))) {
6875 block.is_comptime = true;
6876 // TODO set comptime_reason
6877 }
6878 // Give the arg its result type
6879 sema.inst_map.putAssumeCapacity(zir_call.call_inst, try sema.addType(param_ty));
6880 // Resolve the arg!
6881 const uncoerced_arg = try sema.resolveBody(block, arg_body, zir_call.call_inst);
6882
6883 if (sema.typeOf(uncoerced_arg).zigTypeTag(mod) == .NoReturn) {
6884 // This terminates resolution of arguments. The caller should
6885 // propagate this.
6886 return uncoerced_arg;
6887 }
6888
6889 if (sema.typeOf(uncoerced_arg).isError(mod)) {
6890 zir_call.any_arg_is_error.* = true;
6891 }
6892
6893 break :arg_val uncoerced_arg;
6894 },
6895 };
6896 switch (param_ty.toIntern()) {
6897 .generic_poison_type => return uncoerced_arg,
6898 .var_args_param_type => return sema.coerceVarArgParam(block, uncoerced_arg, cai.argSrc(block, arg_index)),
6899 else => return sema.coerceExtra(
6900 block,
6901 param_ty,
6902 uncoerced_arg,
6903 cai.argSrc(block, arg_index),
6904 .{ .param_src = .{
6905 .func_inst = func_inst,
6906 .param_i = @intCast(arg_index),
6907 } },
6908 ) catch |err| switch (err) {
6909 error.NotCoercible => unreachable,
6910 else => |e| return e,
6911 },
6912 }
6913 }
6914};
6915
6916/// While performing an inline call, we need to switch between two Sema states a few times: the
6917/// state for the caller (with the callee's `code`, `fn_ret_ty`, etc), and the state for the callee.
6918/// These cannot be two separate Sema instances as they must share AIR.
6919/// Therefore, this struct acts as a helper to switch between the two.
6920/// This switching is required during argument evaluation, where function argument analysis must be
6921/// interleaved with resolving generic parameter types.
6922const InlineCallSema = struct {
6923 sema: *Sema,
6924 cur: enum {
6925 caller,
6926 callee,
6927 },
6928
6929 other_code: Zir,
6930 other_func_index: InternPool.Index,
6931 other_fn_ret_ty: Type,
6932 other_fn_ret_ty_ies: ?*InferredErrorSet,
6933 other_inst_map: InstMap,
6934 other_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
6935 other_generic_owner: InternPool.Index,
6936 other_generic_call_src: LazySrcLoc,
6937 other_generic_call_decl: Decl.OptionalIndex,
6938
6939 /// Sema should currently be set up for the caller (i.e. unchanged yet). This init will not
6940 /// change that. The other parameters contain data for the callee Sema. The other modified
6941 /// Sema fields are all initialized to default values for the callee.
6942 /// Must call deinit on the result.
6943 fn init(
6944 sema: *Sema,
6945 callee_code: Zir,
6946 callee_func_index: InternPool.Index,
6947 callee_error_return_trace_index_on_fn_entry: Air.Inst.Ref,
6948 ) InlineCallSema {
6949 return .{
6950 .sema = sema,
6951 .cur = .caller,
6952 .other_code = callee_code,
6953 .other_func_index = callee_func_index,
6954 .other_fn_ret_ty = Type.void,
6955 .other_fn_ret_ty_ies = null,
6956 .other_inst_map = .{},
6957 .other_error_return_trace_index_on_fn_entry = callee_error_return_trace_index_on_fn_entry,
6958 .other_generic_owner = .none,
6959 .other_generic_call_src = .unneeded,
6960 .other_generic_call_decl = .none,
6961 };
6962 }
6963
6964 /// Switch back to the caller Sema if necessary and free all temporary state of the callee Sema.
6965 fn deinit(ics: *InlineCallSema) void {
6966 switch (ics.cur) {
6967 .caller => {},
6968 .callee => ics.swap(),
6969 }
6970 // Callee Sema owns the inst_map memory
6971 ics.other_inst_map.deinit(ics.sema.gpa);
6972 ics.* = undefined;
6973 }
6974
6975 /// Returns a Sema instance suitable for usage from the caller context.
6976 fn caller(ics: *InlineCallSema) *Sema {
6977 switch (ics.cur) {
6978 .caller => {},
6979 .callee => ics.swap(),
6980 }
6981 return ics.sema;
6982 }
6983
6984 /// Returns a Sema instance suitable for usage from the callee context.
6985 fn callee(ics: *InlineCallSema) *Sema {
6986 switch (ics.cur) {
6987 .caller => ics.swap(),
6988 .callee => {},
6989 }
6990 return ics.sema;
6991 }
6992
6993 /// Internal use only. Swaps to the other Sema state.
6994 fn swap(ics: *InlineCallSema) void {
6995 ics.cur = switch (ics.cur) {
6996 .caller => .callee,
6997 .callee => .caller,
6998 };
6999 // zig fmt: off
7000 std.mem.swap(Zir, &ics.sema.code, &ics.other_code);
7001 std.mem.swap(InternPool.Index, &ics.sema.func_index, &ics.other_func_index);
7002 std.mem.swap(Type, &ics.sema.fn_ret_ty, &ics.other_fn_ret_ty);
7003 std.mem.swap(?*InferredErrorSet, &ics.sema.fn_ret_ty_ies, &ics.other_fn_ret_ty_ies);
7004 std.mem.swap(InstMap, &ics.sema.inst_map, &ics.other_inst_map);
7005 std.mem.swap(InternPool.Index, &ics.sema.generic_owner, &ics.other_generic_owner);
7006 std.mem.swap(LazySrcLoc, &ics.sema.generic_call_src, &ics.other_generic_call_src);
7007 std.mem.swap(Decl.OptionalIndex, &ics.sema.generic_call_decl, &ics.other_generic_call_decl);
7008 std.mem.swap(Air.Inst.Ref, &ics.sema.error_return_trace_index_on_fn_entry, &ics.other_error_return_trace_index_on_fn_entry);
7009 // zig fmt: on
7010 }
7011};
7012
67617013fn analyzeCall(
67627014 sema: *Sema,
67637015 block: *Block,
......@@ -6767,8 +7019,7 @@ fn analyzeCall(
67677019 call_src: LazySrcLoc,
67687020 modifier: std.builtin.CallModifier,
67697021 ensure_result_used: bool,
6770 uncasted_args: []const Air.Inst.Ref,
6771 bound_arg_src: ?LazySrcLoc,
7022 args_info: CallArgsInfo,
67727023 call_dbg_node: ?Zir.Inst.Index,
67737024 operation: CallOperation,
67747025) CompileError!Air.Inst.Ref {
......@@ -6777,7 +7028,6 @@ fn analyzeCall(
67777028
67787029 const callee_ty = sema.typeOf(func);
67797030 const func_ty_info = mod.typeToFunc(func_ty).?;
6780 const fn_params_len = func_ty_info.param_types.len;
67817031 const cc = func_ty_info.cc;
67827032 if (cc == .Naked) {
67837033 const maybe_decl = try sema.funcDeclSrc(func);
......@@ -6862,9 +7112,8 @@ fn analyzeCall(
68627112 func_src,
68637113 call_src,
68647114 ensure_result_used,
6865 uncasted_args,
7115 args_info,
68667116 call_tag,
6867 bound_arg_src,
68687117 call_dbg_node,
68697118 )) |some| {
68707119 return some;
......@@ -6939,31 +7188,23 @@ fn analyzeCall(
69397188 .block_inst = block_inst,
69407189 },
69417190 };
6942 // In order to save a bit of stack space, directly modify Sema rather
6943 // than create a child one.
6944 const parent_zir = sema.code;
7191
69457192 const module_fn = mod.funcInfo(module_fn_index);
69467193 const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
6947 sema.code = fn_owner_decl.getFileScope(mod).zir;
6948 defer sema.code = parent_zir;
6949
6950 try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body);
69517194
6952 const parent_inst_map = sema.inst_map;
6953 sema.inst_map = .{};
6954 defer {
6955 sema.src = call_src;
6956 sema.inst_map.deinit(gpa);
6957 sema.inst_map = parent_inst_map;
6958 }
6959
6960 const parent_func_index = sema.func_index;
6961 sema.func_index = module_fn_index;
6962 defer sema.func_index = parent_func_index;
7195 // We effectively want a child Sema here, but can't literally do that, because we need AIR
7196 // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in
7197 // scope, we should use its `caller`/`callee` methods rather than using `sema` directly
7198 // whenever performing an operation where the difference matters.
7199 var ics = InlineCallSema.init(
7200 sema,
7201 fn_owner_decl.getFileScope(mod).zir,
7202 module_fn_index,
7203 block.error_return_trace_index,
7204 );
7205 defer ics.deinit();
69637206
6964 const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry;
6965 sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index;
6966 defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index;
7207 try mod.declareDeclDependencyType(ics.callee().owner_decl_index, module_fn.owner_decl, .function_body);
69677208
69687209 var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);
69697210 defer wip_captures.deinit();
......@@ -7019,37 +7260,37 @@ fn analyzeCall(
70197260 // the AIR instructions of the callsite. The callee could be a generic function
70207261 // which means its parameter type expressions must be resolved in order and used
70217262 // to successively coerce the arguments.
7022 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
7023 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, fn_info.param_body);
7263 const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst);
7264 try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
70247265
70257266 var has_comptime_args = false;
70267267 var arg_i: u32 = 0;
70277268 for (fn_info.param_body) |inst| {
7028 const arg_src: LazySrcLoc = if (arg_i == 0 and bound_arg_src != null)
7029 bound_arg_src.?
7030 else
7031 .{ .call_arg = .{
7032 .decl = block.src_decl,
7033 .call_node_offset = call_src.node_offset.x,
7034 .arg_index = arg_i - @intFromBool(bound_arg_src != null),
7035 } };
7036 try sema.analyzeInlineCallArg(
7269 const opt_noreturn_ref = try analyzeInlineCallArg(
7270 &ics,
70377271 block,
70387272 &child_block,
7039 arg_src,
70407273 inst,
70417274 new_fn_info.param_types,
70427275 &arg_i,
7043 uncasted_args,
7276 args_info,
70447277 is_comptime_call,
70457278 &should_memoize,
70467279 memoized_arg_values,
7047 func_ty_info.param_types,
7280 func_ty_info,
70487281 func,
70497282 &has_comptime_args,
70507283 );
7284 if (opt_noreturn_ref) |ref| {
7285 // Analyzing this argument gave a ref of a noreturn type. Terminate argument analysis here.
7286 return ref;
7287 }
70517288 }
70527289
7290 // From here, we only really need to use the callee Sema. Make it the active one, then we
7291 // can just use `sema` directly.
7292 _ = ics.callee();
7293
70537294 if (!has_comptime_args and module_fn.analysis(ip).state == .sema_failure)
70547295 return error.AnalysisFail;
70557296
......@@ -7073,26 +7314,7 @@ fn analyzeCall(
70737314 else
70747315 try sema.resolveInst(fn_info.ret_ty_ref);
70757316 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
7076 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
7077 const parent_fn_ret_ty = sema.fn_ret_ty;
7078 const parent_fn_ret_ty_ies = sema.fn_ret_ty_ies;
7079 const parent_generic_owner = sema.generic_owner;
7080 const parent_generic_call_src = sema.generic_call_src;
7081 const parent_generic_bound_arg_src = sema.generic_bound_arg_src;
7082 const parent_generic_call_decl = sema.generic_call_decl;
7083 sema.fn_ret_ty = bare_return_type;
7084 sema.fn_ret_ty_ies = null;
7085 sema.generic_owner = .none;
7086 sema.generic_call_src = .unneeded;
7087 sema.generic_bound_arg_src = null;
7088 sema.generic_call_decl = .none;
7089 defer sema.fn_ret_ty = parent_fn_ret_ty;
7090 defer sema.fn_ret_ty_ies = parent_fn_ret_ty_ies;
7091 defer sema.generic_owner = parent_generic_owner;
7092 defer sema.generic_call_src = parent_generic_call_src;
7093 defer sema.generic_bound_arg_src = parent_generic_bound_arg_src;
7094 defer sema.generic_call_decl = parent_generic_call_decl;
7095
7317 sema.fn_ret_ty = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
70967318 if (module_fn.analysis(ip).inferred_error_set) {
70977319 // Create a fresh inferred error set type for inline/comptime calls.
70987320 const ies = try sema.arena.create(InferredErrorSet);
......@@ -7100,7 +7322,7 @@ fn analyzeCall(
71007322 sema.fn_ret_ty_ies = ies;
71017323 sema.fn_ret_ty = (try ip.get(gpa, .{ .error_union_type = .{
71027324 .error_set_type = .adhoc_inferred_error_set_type,
7103 .payload_type = bare_return_type.toIntern(),
7325 .payload_type = sema.fn_ret_ty.toIntern(),
71047326 } })).toType();
71057327 }
71067328
......@@ -7123,7 +7345,7 @@ fn analyzeCall(
71237345 new_fn_info.return_type = sema.fn_ret_ty.toIntern();
71247346 const new_func_resolved_ty = try mod.funcType(new_fn_info);
71257347 if (!is_comptime_call and !block.is_typeof) {
7126 try sema.emitDbgInline(block, parent_func_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
7348 try sema.emitDbgInline(block, sema.func_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
71277349
71287350 const zir_tags = sema.code.instructions.items(.tag);
71297351 for (fn_info.param_body) |param| switch (zir_tags[param]) {
......@@ -7157,7 +7379,7 @@ fn analyzeCall(
71577379 const err_msg = sema.err orelse return err;
71587380 if (mem.eql(u8, err_msg.msg, recursive_msg)) return err;
71597381 try sema.errNote(block, call_src, err_msg, "called from here", .{});
7160 err_msg.clearTrace(sema.gpa);
7382 err_msg.clearTrace(gpa);
71617383 return err;
71627384 },
71637385 else => |e| return e,
......@@ -7171,8 +7393,8 @@ fn analyzeCall(
71717393 try sema.emitDbgInline(
71727394 block,
71737395 module_fn_index,
7174 parent_func_index,
7175 mod.funcOwnerDeclPtr(parent_func_index).ty,
7396 sema.func_index,
7397 mod.funcOwnerDeclPtr(sema.func_index).ty,
71767398 .dbg_inline_end,
71777399 );
71787400 }
......@@ -7217,47 +7439,16 @@ fn analyzeCall(
72177439 } else res: {
72187440 assert(!func_ty_info.is_generic);
72197441
7220 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
7221 for (uncasted_args, 0..) |uncasted_arg, i| {
7222 if (i < fn_params_len) {
7223 const opts: CoerceOpts = .{ .param_src = .{
7224 .func_inst = func,
7225 .param_i = @intCast(i),
7226 } };
7227 const param_ty = func_ty_info.param_types.get(ip)[i].toType();
7228 args[i] = sema.analyzeCallArg(
7229 block,
7230 .unneeded,
7231 param_ty,
7232 uncasted_arg,
7233 opts,
7234 ) catch |err| switch (err) {
7235 error.NeededSourceLocation => {
7236 const decl = mod.declPtr(block.src_decl);
7237 _ = try sema.analyzeCallArg(
7238 block,
7239 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
7240 param_ty,
7241 uncasted_arg,
7242 opts,
7243 );
7244 unreachable;
7245 },
7246 else => |e| return e,
7247 };
7248 } else {
7249 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
7250 error.NeededSourceLocation => {
7251 const decl = mod.declPtr(block.src_decl);
7252 _ = try sema.coerceVarArgParam(
7253 block,
7254 uncasted_arg,
7255 mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
7256 );
7257 unreachable;
7258 },
7259 else => |e| return e,
7260 };
7442 const args = try sema.arena.alloc(Air.Inst.Ref, args_info.count());
7443 for (args, 0..) |*arg_out, arg_idx| {
7444 // Non-generic, so param types are already resolved
7445 const param_ty = if (arg_idx < func_ty_info.param_types.len) ty: {
7446 break :ty func_ty_info.param_types.get(ip)[arg_idx].toType();
7447 } else InternPool.Index.var_args_param_type.toType();
7448 assert(!param_ty.isGenericPoison());
7449 arg_out.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, func);
7450 if (sema.typeOf(arg_out.*).zigTypeTag(mod) == .NoReturn) {
7451 return arg_out.*;
72617452 }
72627453 }
72637454
......@@ -7341,25 +7532,25 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ
73417532 return Air.Inst.Ref.unreachable_value;
73427533}
73437534
7535/// Usually, returns null. If an argument was noreturn, returns that ref (which should become the call result).
73447536fn analyzeInlineCallArg(
7345 sema: *Sema,
7537 ics: *InlineCallSema,
73467538 arg_block: *Block,
73477539 param_block: *Block,
7348 arg_src: LazySrcLoc,
73497540 inst: Zir.Inst.Index,
73507541 new_param_types: []InternPool.Index,
73517542 arg_i: *u32,
7352 uncasted_args: []const Air.Inst.Ref,
7543 args_info: CallArgsInfo,
73537544 is_comptime_call: bool,
73547545 should_memoize: *bool,
73557546 memoized_arg_values: []InternPool.Index,
7356 raw_param_types: InternPool.Index.Slice,
7547 func_ty_info: InternPool.Key.FuncType,
73577548 func_inst: Air.Inst.Ref,
73587549 has_comptime_args: *bool,
7359) !void {
7360 const mod = sema.mod;
7550) !?Air.Inst.Ref {
7551 const mod = ics.sema.mod;
73617552 const ip = &mod.intern_pool;
7362 const zir_tags = sema.code.instructions.items(.tag);
7553 const zir_tags = ics.callee().code.instructions.items(.tag);
73637554 switch (zir_tags[inst]) {
73647555 .param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
73657556 else => {},
......@@ -7368,39 +7559,36 @@ fn analyzeInlineCallArg(
73687559 .param, .param_comptime => {
73697560 // Evaluate the parameter type expression now that previous ones have
73707561 // been mapped, and coerce the corresponding argument to it.
7371 const pl_tok = sema.code.instructions.items(.data)[inst].pl_tok;
7562 const pl_tok = ics.callee().code.instructions.items(.data)[inst].pl_tok;
73727563 const param_src = pl_tok.src();
7373 const extra = sema.code.extraData(Zir.Inst.Param, pl_tok.payload_index);
7374 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
7564 const extra = ics.callee().code.extraData(Zir.Inst.Param, pl_tok.payload_index);
7565 const param_body = ics.callee().code.extra[extra.end..][0..extra.data.body_len];
73757566 const param_ty = param_ty: {
7376 const raw_param_ty = raw_param_types.get(ip)[arg_i.*];
7567 const raw_param_ty = func_ty_info.param_types.get(ip)[arg_i.*];
73777568 if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;
7378 const param_ty_inst = try sema.resolveBody(param_block, param_body, inst);
7379 const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
7569 const param_ty_inst = try ics.callee().resolveBody(param_block, param_body, inst);
7570 const param_ty = try ics.callee().analyzeAsType(param_block, param_src, param_ty_inst);
73807571 break :param_ty param_ty.toIntern();
73817572 };
73827573 new_param_types[arg_i.*] = param_ty;
7383 const uncasted_arg = uncasted_args[arg_i.*];
7384 if (try sema.typeRequiresComptime(param_ty.toType())) {
7385 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
7386 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
7574 const casted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, param_ty.toType(), func_ty_info, func_inst);
7575 if (ics.caller().typeOf(casted_arg).zigTypeTag(mod) == .NoReturn) {
7576 return casted_arg;
7577 }
7578 const arg_src = args_info.argSrc(arg_block, arg_i.*);
7579 if (try ics.callee().typeRequiresComptime(param_ty.toType())) {
7580 _ = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
7581 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
73877582 return err;
73887583 };
73897584 } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) {
7390 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
7585 _ = try ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "parameter is comptime");
73917586 }
7392 const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{
7393 .func_inst = func_inst,
7394 .param_i = @intCast(arg_i.*),
7395 } }) catch |err| switch (err) {
7396 error.NotCoercible => unreachable,
7397 else => |e| return e,
7398 };
73997587
74007588 if (is_comptime_call) {
7401 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
7402 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7403 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
7589 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
7590 const arg_val = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7591 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
74047592 return err;
74057593 };
74067594 switch (arg_val.toIntern()) {
......@@ -7414,14 +7602,14 @@ fn analyzeInlineCallArg(
74147602 // Needed so that lazy values do not trigger
74157603 // assertion due to type not being resolved
74167604 // when the hash function is called.
7417 const resolved_arg_val = try sema.resolveLazyValue(arg_val);
7605 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
74187606 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
74197607 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod);
74207608 } else {
7421 sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
7609 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
74227610 }
74237611
7424 if (try sema.resolveMaybeUndefVal(casted_arg)) |_| {
7612 if (try ics.caller().resolveMaybeUndefVal(casted_arg)) |_| {
74257613 has_comptime_args.* = true;
74267614 }
74277615
......@@ -7429,13 +7617,17 @@ fn analyzeInlineCallArg(
74297617 },
74307618 .param_anytype, .param_anytype_comptime => {
74317619 // No coercion needed.
7432 const uncasted_arg = uncasted_args[arg_i.*];
7433 new_param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern();
7620 const uncasted_arg = try args_info.analyzeArg(ics.caller(), arg_block, arg_i.*, Type.generic_poison, func_ty_info, func_inst);
7621 if (ics.caller().typeOf(uncasted_arg).zigTypeTag(mod) == .NoReturn) {
7622 return uncasted_arg;
7623 }
7624 const arg_src = args_info.argSrc(arg_block, arg_i.*);
7625 new_param_types[arg_i.*] = ics.caller().typeOf(uncasted_arg).toIntern();
74347626
74357627 if (is_comptime_call) {
7436 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
7437 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7438 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
7628 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
7629 const arg_val = ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
7630 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(ics.caller(), ics.caller().err);
74397631 return err;
74407632 };
74417633 switch (arg_val.toIntern()) {
......@@ -7449,17 +7641,17 @@ fn analyzeInlineCallArg(
74497641 // Needed so that lazy values do not trigger
74507642 // assertion due to type not being resolved
74517643 // when the hash function is called.
7452 const resolved_arg_val = try sema.resolveLazyValue(arg_val);
7644 const resolved_arg_val = try ics.caller().resolveLazyValue(arg_val);
74537645 should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
7454 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod);
7646 memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(ics.caller().typeOf(uncasted_arg), mod);
74557647 } else {
74567648 if (zir_tags[inst] == .param_anytype_comptime) {
7457 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
7649 _ = try ics.caller().resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
74587650 }
7459 sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
7651 ics.callee().inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
74607652 }
74617653
7462 if (try sema.resolveMaybeUndefVal(uncasted_arg)) |_| {
7654 if (try ics.caller().resolveMaybeUndefVal(uncasted_arg)) |_| {
74637655 has_comptime_args.* = true;
74647656 }
74657657
......@@ -7467,6 +7659,8 @@ fn analyzeInlineCallArg(
74677659 },
74687660 else => {},
74697661 }
7662
7663 return null;
74707664}
74717665
74727666fn analyzeCallArg(
......@@ -7491,9 +7685,8 @@ fn instantiateGenericCall(
74917685 func_src: LazySrcLoc,
74927686 call_src: LazySrcLoc,
74937687 ensure_result_used: bool,
7494 uncasted_args: []const Air.Inst.Ref,
7688 args_info: CallArgsInfo,
74957689 call_tag: Air.Inst.Tag,
7496 bound_arg_src: ?LazySrcLoc,
74977690 call_dbg_node: ?Zir.Inst.Index,
74987691) CompileError!Air.Inst.Ref {
74997692 const mod = sema.mod;
......@@ -7507,6 +7700,7 @@ fn instantiateGenericCall(
75077700 else => unreachable,
75087701 };
75097702 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
7703 const generic_owner_ty_info = mod.typeToFunc(generic_owner_func.ty.toType()).?;
75107704
75117705 // Even though there may already be a generic instantiation corresponding
75127706 // to this callsite, we must evaluate the expressions of the generic
......@@ -7522,9 +7716,13 @@ fn instantiateGenericCall(
75227716 const fn_zir = namespace.file_scope.zir;
75237717 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst);
75247718
7525 const comptime_args = try sema.arena.alloc(InternPool.Index, uncasted_args.len);
7719 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
75267720 @memset(comptime_args, .none);
75277721
7722 // We may overestimate the number of runtime args, but this will definitely be sufficient.
7723 const max_runtime_args = args_info.count() - @popCount(generic_owner_ty_info.comptime_bits);
7724 var runtime_args = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(sema.arena, max_runtime_args);
7725
75287726 // Re-run the block that creates the function, with the comptime parameters
75297727 // pre-populated inside `inst_map`. This causes `param_comptime` and
75307728 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
......@@ -7549,7 +7747,6 @@ fn instantiateGenericCall(
75497747 .comptime_args = comptime_args,
75507748 .generic_owner = generic_owner,
75517749 .generic_call_src = call_src,
7552 .generic_bound_arg_src = bound_arg_src,
75537750 .generic_call_decl = block.src_decl.toOptional(),
75547751 .branch_quota = sema.branch_quota,
75557752 .branch_count = sema.branch_count,
......@@ -7574,30 +7771,145 @@ fn instantiateGenericCall(
75747771
75757772 try child_sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
75767773
7577 for (fn_info.param_body[0..uncasted_args.len], uncasted_args, 0..) |inst, arg, i| {
7578 // `child_sema` will use a different `inst_map` which means we have to
7579 // convert from parent-relative `Air.Inst.Ref` to child-relative here.
7580 // Constants are simple; runtime-known values need a new instruction.
7581 child_sema.inst_map.putAssumeCapacityNoClobber(inst, if (try sema.resolveMaybeUndefVal(arg)) |val|
7582 Air.internedToRef(val.toIntern())
7583 else
7584 // We insert into the map an instruction which is runtime-known
7585 // but has the type of the argument.
7586 try child_block.addInst(.{
7774 for (fn_info.param_body[0..args_info.count()], 0..) |param_inst, arg_index| {
7775 const param_tag = fn_zir.instructions.items(.tag)[param_inst];
7776
7777 const param_ty = switch (generic_owner_ty_info.param_types.get(ip)[arg_index]) {
7778 else => |ty| ty.toType(), // parameter is not generic, so type is already resolved
7779 .generic_poison_type => param_ty: {
7780 // We have every parameter before this one, so can resolve this parameter's type now.
7781 // However, first check the param type, since it may be anytype.
7782 switch (param_tag) {
7783 .param_anytype, .param_anytype_comptime => {
7784 // The parameter doesn't have a type.
7785 break :param_ty Type.generic_poison;
7786 },
7787 .param, .param_comptime => {
7788 // We now know every prior parameter, so can resolve this
7789 // parameter's type. The child sema has these types.
7790 const param_data = fn_zir.instructions.items(.data)[param_inst].pl_tok;
7791 const param_extra = fn_zir.extraData(Zir.Inst.Param, param_data.payload_index);
7792 const param_ty_body = fn_zir.extra[param_extra.end..][0..param_extra.data.body_len];
7793
7794 // Make sure any nested instructions don't clobber our work.
7795 const prev_params = child_block.params;
7796 const prev_no_partial_func_ty = child_sema.no_partial_func_ty;
7797 const prev_generic_owner = child_sema.generic_owner;
7798 const prev_generic_call_src = child_sema.generic_call_src;
7799 const prev_generic_call_decl = child_sema.generic_call_decl;
7800 child_block.params = .{};
7801 child_sema.no_partial_func_ty = true;
7802 child_sema.generic_owner = .none;
7803 child_sema.generic_call_src = .unneeded;
7804 child_sema.generic_call_decl = .none;
7805 defer {
7806 child_block.params = prev_params;
7807 child_sema.no_partial_func_ty = prev_no_partial_func_ty;
7808 child_sema.generic_owner = prev_generic_owner;
7809 child_sema.generic_call_src = prev_generic_call_src;
7810 child_sema.generic_call_decl = prev_generic_call_decl;
7811 }
7812
7813 const param_ty_inst = try child_sema.resolveBody(&child_block, param_ty_body, param_inst);
7814 break :param_ty try child_sema.analyzeAsType(&child_block, param_data.src(), param_ty_inst);
7815 },
7816 else => unreachable,
7817 }
7818 },
7819 };
7820 const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);
7821 const arg_ty = sema.typeOf(arg_ref);
7822 if (arg_ty.zigTypeTag(mod) == .NoReturn) {
7823 // This terminates argument analysis.
7824 return arg_ref;
7825 }
7826
7827 const arg_is_comptime = switch (param_tag) {
7828 .param_comptime, .param_anytype_comptime => true,
7829 .param, .param_anytype => try sema.typeRequiresComptime(arg_ty),
7830 else => unreachable,
7831 };
7832
7833 if (arg_is_comptime) {
7834 if (try sema.resolveMaybeUndefVal(arg_ref)) |arg_val| {
7835 comptime_args[arg_index] = arg_val.toIntern();
7836 child_sema.inst_map.putAssumeCapacityNoClobber(
7837 param_inst,
7838 Air.internedToRef(arg_val.toIntern()),
7839 );
7840 } else switch (param_tag) {
7841 .param_comptime,
7842 .param_anytype_comptime,
7843 => return sema.failWithOwnedErrorMsg(msg: {
7844 const arg_src = args_info.argSrc(block, arg_index);
7845 const msg = try sema.errMsg(block, arg_src, "runtime-known argument passed to comptime parameter", .{});
7846 errdefer msg.destroy(sema.gpa);
7847 const param_src = switch (param_tag) {
7848 .param_comptime => fn_zir.instructions.items(.data)[param_inst].pl_tok.src(),
7849 .param_anytype_comptime => fn_zir.instructions.items(.data)[param_inst].str_tok.src(),
7850 else => unreachable,
7851 };
7852 try child_sema.errNote(&child_block, param_src, msg, "declared comptime here", .{});
7853 break :msg msg;
7854 }),
7855
7856 .param,
7857 .param_anytype,
7858 => return sema.failWithOwnedErrorMsg(msg: {
7859 const arg_src = args_info.argSrc(block, arg_index);
7860 const msg = try sema.errMsg(block, arg_src, "runtime-known argument passed to parameter of comptime-only type", .{});
7861 errdefer msg.destroy(sema.gpa);
7862 const param_src = switch (param_tag) {
7863 .param => fn_zir.instructions.items(.data)[param_inst].pl_tok.src(),
7864 .param_anytype => fn_zir.instructions.items(.data)[param_inst].str_tok.src(),
7865 else => unreachable,
7866 };
7867 try child_sema.errNote(&child_block, param_src, msg, "declared here", .{});
7868 const src_decl = mod.declPtr(block.src_decl);
7869 try sema.explainWhyTypeIsComptime(msg, arg_src.toSrcLoc(src_decl, mod), arg_ty);
7870 break :msg msg;
7871 }),
7872
7873 else => unreachable,
7874 }
7875 } else {
7876 // The parameter is runtime-known.
7877 try sema.queueFullTypeResolution(arg_ty);
7878 child_sema.inst_map.putAssumeCapacityNoClobber(param_inst, try child_block.addInst(.{
75877879 .tag = .arg,
75887880 .data = .{ .arg = .{
7589 .ty = Air.internedToRef(sema.typeOf(arg).toIntern()),
7590 .src_index = @intCast(i),
7881 .ty = Air.internedToRef(arg_ty.toIntern()),
7882 .src_index = @intCast(arg_index),
75917883 } },
75927884 }));
7885 const param_name: Zir.NullTerminatedString = switch (param_tag) {
7886 .param_anytype => @enumFromInt(fn_zir.instructions.items(.data)[param_inst].str_tok.start),
7887 .param => name: {
7888 const inst_data = fn_zir.instructions.items(.data)[param_inst].pl_tok;
7889 const extra = fn_zir.extraData(Zir.Inst.Param, inst_data.payload_index);
7890 break :name @enumFromInt(extra.data.name);
7891 },
7892 else => unreachable,
7893 };
7894 try child_block.params.append(sema.arena, .{
7895 .ty = arg_ty.toIntern(), // This is the type after coercion
7896 .is_comptime = false, // We're adding only runtime args to the instantiation
7897 .name = param_name,
7898 });
7899 runtime_args.appendAssumeCapacity(arg_ref);
7900 }
75937901 }
75947902
7595 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);
7903 // We've already handled parameters, so don't resolve the whole body. Instead, just
7904 // do the instructions after the params (i.e. the func itself).
7905 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body[args_info.count()..], fn_info.param_body_inst);
75967906 const callee_index = (child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable).toIntern();
75977907
75987908 const callee = mod.funcInfo(callee_index);
75997909 callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota);
76007910
7911 try sema.addReferencedBy(block, call_src, callee.owner_decl);
7912
76017913 // Make a runtime call to the new function, making sure to omit the comptime args.
76027914 const func_ty = callee.ty.toType();
76037915 const func_ty_info = mod.typeToFunc(func_ty).?;
......@@ -7615,33 +7927,7 @@ fn instantiateGenericCall(
76157927 return error.GenericPoison;
76167928 }
76177929
7618 const runtime_args_len: u32 = func_ty_info.param_types.len;
7619 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
7620 {
7621 var runtime_i: u32 = 0;
7622 for (uncasted_args, 0..) |uncasted_arg, total_i| {
7623 // In the case of a function call generated by the language, the LazySrcLoc
7624 // provided for `call_src` may not point to anything interesting.
7625 const arg_src: LazySrcLoc = if (total_i == 0 and bound_arg_src != null)
7626 bound_arg_src.?
7627 else if (call_src == .node_offset) .{ .call_arg = .{
7628 .decl = block.src_decl,
7629 .call_node_offset = call_src.node_offset.x,
7630 .arg_index = @intCast(total_i - @intFromBool(bound_arg_src != null)),
7631 } } else .unneeded;
7632
7633 const comptime_arg = callee.comptime_args.get(ip)[total_i];
7634 if (comptime_arg == .none) {
7635 const param_ty = func_ty_info.param_types.get(ip)[runtime_i].toType();
7636 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
7637 try sema.queueFullTypeResolution(param_ty);
7638 runtime_args[runtime_i] = casted_arg;
7639 runtime_i += 1;
7640 }
7641 }
7642
7643 try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
7644 }
7930 try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
76457931
76467932 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
76477933
......@@ -7653,18 +7939,17 @@ fn instantiateGenericCall(
76537939
76547940 try mod.ensureFuncBodyAnalysisQueued(callee_index);
76557941
7656 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
7657 runtime_args_len);
7942 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args.items.len);
76587943 const result = try block.addInst(.{
76597944 .tag = call_tag,
76607945 .data = .{ .pl_op = .{
76617946 .operand = Air.internedToRef(callee_index),
76627947 .payload = sema.addExtraAssumeCapacity(Air.Call{
7663 .args_len = runtime_args_len,
7948 .args_len = @intCast(runtime_args.items.len),
76647949 }),
76657950 } },
76667951 });
7667 sema.appendRefsAssumeCapacity(runtime_args);
7952 sema.appendRefsAssumeCapacity(runtime_args.items);
76687953
76697954 if (ensure_result_used) {
76707955 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
......@@ -7744,7 +8029,15 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
77448029fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
77458030 const mod = sema.mod;
77468031 const bin = sema.code.instructions.items(.data)[inst].bin;
7747 const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
8032 const operand = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) {
8033 // Since this is a ZIR instruction that returns a type, encountering
8034 // generic poison should not result in a failed compilation, but the
8035 // generic poison type. This prevents unnecessary failures when
8036 // constructing types at compile-time.
8037 error.GenericPoison => return .generic_poison_type,
8038 else => |e| return e,
8039 };
8040 const indexable_ty = try sema.resolveTypeFields(operand);
77488041 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
77498042 if (indexable_ty.zigTypeTag(mod) == .Struct) {
77508043 const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod);
......@@ -7763,6 +8056,23 @@ fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
77638056 return sema.addType(ptr_ty.childType(mod));
77648057}
77658058
8059fn zirVectorElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
8060 const mod = sema.mod;
8061 const un_node = sema.code.instructions.items(.data)[inst].un_node;
8062 const vec_ty = sema.resolveType(block, .unneeded, un_node.operand) catch |err| switch (err) {
8063 // Since this is a ZIR instruction that returns a type, encountering
8064 // generic poison should not result in a failed compilation, but the
8065 // generic poison type. This prevents unnecessary failures when
8066 // constructing types at compile-time.
8067 error.GenericPoison => return .generic_poison_type,
8068 else => |e| return e,
8069 };
8070 if (!vec_ty.isVector(mod)) {
8071 return sema.fail(block, un_node.src(), "expected vector type, found '{}'", .{vec_ty.fmt(mod)});
8072 }
8073 return sema.addType(vec_ty.childType(mod));
8074}
8075
77668076fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
77678077 const mod = sema.mod;
77688078 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
......@@ -8588,20 +8898,17 @@ fn resolveGenericBody(
85888898 const prev_no_partial_func_type = sema.no_partial_func_ty;
85898899 const prev_generic_owner = sema.generic_owner;
85908900 const prev_generic_call_src = sema.generic_call_src;
8591 const prev_generic_bound_arg_src = sema.generic_bound_arg_src;
85928901 const prev_generic_call_decl = sema.generic_call_decl;
85938902 block.params = .{};
85948903 sema.no_partial_func_ty = true;
85958904 sema.generic_owner = .none;
85968905 sema.generic_call_src = .unneeded;
8597 sema.generic_bound_arg_src = null;
85988906 sema.generic_call_decl = .none;
85998907 defer {
86008908 block.params = prev_params;
86018909 sema.no_partial_func_ty = prev_no_partial_func_type;
86028910 sema.generic_owner = prev_generic_owner;
86038911 sema.generic_call_src = prev_generic_call_src;
8604 sema.generic_bound_arg_src = prev_generic_bound_arg_src;
86058912 sema.generic_call_decl = prev_generic_call_decl;
86068913 }
86078914
......@@ -9219,37 +9526,18 @@ fn finishFunc(
92199526 return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
92209527}
92219528
9222fn genericArgSrcLoc(sema: *Sema, block: *Block, param_index: u32, param_src: LazySrcLoc) Module.SrcLoc {
9223 const mod = sema.mod;
9224 if (sema.generic_owner == .none) return param_src.toSrcLoc(mod.declPtr(block.src_decl), mod);
9225 const arg_decl = sema.generic_call_decl.unwrap().?;
9226 const arg_src: LazySrcLoc = if (param_index == 0 and sema.generic_bound_arg_src != null)
9227 sema.generic_bound_arg_src.?
9228 else
9229 .{ .call_arg = .{
9230 .decl = arg_decl,
9231 .call_node_offset = sema.generic_call_src.node_offset.x,
9232 .arg_index = param_index - @intFromBool(sema.generic_bound_arg_src != null),
9233 } };
9234 return arg_src.toSrcLoc(mod.declPtr(arg_decl), mod);
9235}
9236
92379529fn zirParam(
92389530 sema: *Sema,
92399531 block: *Block,
92409532 inst: Zir.Inst.Index,
9241 param_index: u32,
92429533 comptime_syntax: bool,
92439534) CompileError!void {
9244 const gpa = sema.gpa;
92459535 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
92469536 const src = inst_data.src();
92479537 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
92489538 const param_name: Zir.NullTerminatedString = @enumFromInt(extra.data.name);
92499539 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
92509540
9251 // We could be in a generic function instantiation, or we could be evaluating a generic
9252 // function without any comptime args provided.
92539541 const param_ty = param_ty: {
92549542 const err = err: {
92559543 // Make sure any nested param instructions don't clobber our work.
......@@ -9257,20 +9545,17 @@ fn zirParam(
92579545 const prev_no_partial_func_type = sema.no_partial_func_ty;
92589546 const prev_generic_owner = sema.generic_owner;
92599547 const prev_generic_call_src = sema.generic_call_src;
9260 const prev_generic_bound_arg_src = sema.generic_bound_arg_src;
92619548 const prev_generic_call_decl = sema.generic_call_decl;
92629549 block.params = .{};
92639550 sema.no_partial_func_ty = true;
92649551 sema.generic_owner = .none;
92659552 sema.generic_call_src = .unneeded;
9266 sema.generic_bound_arg_src = null;
92679553 sema.generic_call_decl = .none;
92689554 defer {
92699555 block.params = prev_params;
92709556 sema.no_partial_func_ty = prev_no_partial_func_type;
92719557 sema.generic_owner = prev_generic_owner;
92729558 sema.generic_call_src = prev_generic_call_src;
9273 sema.generic_bound_arg_src = prev_generic_bound_arg_src;
92749559 sema.generic_call_decl = prev_generic_call_decl;
92759560 }
92769561
......@@ -9282,11 +9567,6 @@ fn zirParam(
92829567 };
92839568 switch (err) {
92849569 error.GenericPoison => {
9285 if (sema.inst_map.contains(inst)) {
9286 // A generic function is about to evaluate to another generic function.
9287 // Return an error instead.
9288 return error.GenericPoison;
9289 }
92909570 // The type is not available until the generic instantiation.
92919571 // We result the param instruction with a poison value and
92929572 // insert an anytype parameter.
......@@ -9304,11 +9584,6 @@ fn zirParam(
93049584
93059585 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
93069586 error.GenericPoison => {
9307 if (sema.inst_map.contains(inst)) {
9308 // A generic function is about to evaluate to another generic function.
9309 // Return an error instead.
9310 return error.GenericPoison;
9311 }
93129587 // The type is not available until the generic instantiation.
93139588 // We result the param instruction with a poison value and
93149589 // insert an anytype parameter.
......@@ -9323,46 +9598,6 @@ fn zirParam(
93239598 else => |e| return e,
93249599 } or comptime_syntax;
93259600
9326 if (sema.inst_map.get(inst)) |arg| {
9327 if (is_comptime and sema.generic_owner != .none) {
9328 // We have a comptime value for this parameter so it should be elided from the
9329 // function type of the function instruction in this block.
9330 const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) {
9331 error.NeededSourceLocation => {
9332 // We are instantiating a generic function and a comptime arg
9333 // cannot be coerced to the param type, but since we don't
9334 // have the callee source location return `GenericPoison`
9335 // so that the instantiation is failed and the coercion
9336 // is handled by comptime call logic instead.
9337 assert(sema.generic_owner != .none);
9338 return error.GenericPoison;
9339 },
9340 else => |e| return e,
9341 };
9342 sema.inst_map.putAssumeCapacity(inst, coerced_arg);
9343 if (try sema.resolveMaybeUndefVal(coerced_arg)) |val| {
9344 sema.comptime_args[param_index] = val.toIntern();
9345 return;
9346 }
9347 const msg = msg: {
9348 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9349 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9350 @as([]const u8, "runtime-known argument passed to comptime parameter"),
9351 });
9352 errdefer msg.destroy(gpa);
9353
9354 if (sema.generic_call_decl != .none) {
9355 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared comptime here")});
9356 }
9357 break :msg msg;
9358 };
9359 return sema.failWithOwnedErrorMsg(msg);
9360 }
9361 // Even though a comptime argument is provided, the generic function wants to treat
9362 // this as a runtime parameter.
9363 assert(sema.inst_map.remove(inst));
9364 }
9365
93669601 try block.params.append(sema.arena, .{
93679602 .ty = param_ty.toIntern(),
93689603 .is_comptime = comptime_syntax,
......@@ -9388,75 +9623,10 @@ fn zirParamAnytype(
93889623 sema: *Sema,
93899624 block: *Block,
93909625 inst: Zir.Inst.Index,
9391 param_index: u32,
93929626 comptime_syntax: bool,
93939627) CompileError!void {
9394 const gpa = sema.gpa;
93959628 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
93969629 const param_name: Zir.NullTerminatedString = @enumFromInt(inst_data.start);
9397 const src = inst_data.src();
9398
9399 if (sema.inst_map.get(inst)) |air_ref| {
9400 const param_ty = sema.typeOf(air_ref);
9401 // If we have a comptime value for this parameter, it should be elided
9402 // from the function type of the function instruction in this block.
9403 if (try sema.typeHasOnePossibleValue(param_ty)) |opv| {
9404 sema.comptime_args[param_index] = opv.toIntern();
9405 return;
9406 }
9407
9408 if (comptime_syntax) {
9409 if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
9410 sema.comptime_args[param_index] = val.toIntern();
9411 return;
9412 }
9413 const msg = msg: {
9414 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9415 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9416 @as([]const u8, "runtime-known argument passed to comptime parameter"),
9417 });
9418 errdefer msg.destroy(gpa);
9419
9420 if (sema.generic_call_decl != .none) {
9421 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared comptime here")});
9422 }
9423 break :msg msg;
9424 };
9425 return sema.failWithOwnedErrorMsg(msg);
9426 }
9427
9428 if (try sema.typeRequiresComptime(param_ty)) {
9429 if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
9430 sema.comptime_args[param_index] = val.toIntern();
9431 return;
9432 }
9433 const msg = msg: {
9434 const src_loc = sema.genericArgSrcLoc(block, param_index, src);
9435 const msg = try Module.ErrorMsg.create(gpa, src_loc, "{s}", .{
9436 @as([]const u8, "runtime-known argument passed to comptime-only type parameter"),
9437 });
9438 errdefer msg.destroy(gpa);
9439
9440 if (sema.generic_call_decl != .none) {
9441 try sema.errNote(block, src, msg, "{s}", .{@as([]const u8, "declared here")});
9442 }
9443
9444 try sema.explainWhyTypeIsComptime(msg, src_loc, param_ty);
9445
9446 break :msg msg;
9447 };
9448 return sema.failWithOwnedErrorMsg(msg);
9449 }
9450
9451 // The parameter is runtime-known.
9452 // The map is already populated but we do need to add a runtime parameter.
9453 try block.params.append(sema.arena, .{
9454 .ty = param_ty.toIntern(),
9455 .is_comptime = false,
9456 .name = param_name,
9457 });
9458 return;
9459 }
94609630
94619631 // We are evaluating a generic function without any comptime args provided.
94629632
......@@ -18794,7 +18964,13 @@ fn zirStructInit(
1879418964 const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
1879518965 const first_field_type_data = zir_datas[first_item.field_type].pl_node;
1879618966 const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
18797 const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type);
18967 const resolved_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) {
18968 error.GenericPoison => {
18969 // The type wasn't actually known, so treat this as an anon struct init.
18970 return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref);
18971 },
18972 else => |e| return e,
18973 };
1879818974 try sema.resolveTypeLayout(resolved_ty);
1879918975
1880018976 if (resolved_ty.zigTypeTag(mod) == .Struct) {
......@@ -19037,26 +19213,57 @@ fn zirStructInitAnon(
1903719213 inst: Zir.Inst.Index,
1903819214 is_ref: bool,
1903919215) CompileError!Air.Inst.Ref {
19040 const mod = sema.mod;
19041 const gpa = sema.gpa;
1904219216 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1904319217 const src = inst_data.src();
1904419218 const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
19045 const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len);
19219 return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, is_ref);
19220}
19221
19222fn structInitAnon(
19223 sema: *Sema,
19224 block: *Block,
19225 src: LazySrcLoc,
19226 /// It is possible for a typed struct_init to be downgraded to an anonymous init due to a
19227 /// generic poison type. In this case, we need to know to interpret the extra data differently.
19228 comptime kind: enum { anon_init, typed_init },
19229 extra_data: switch (kind) {
19230 .anon_init => Zir.Inst.StructInitAnon,
19231 .typed_init => Zir.Inst.StructInit,
19232 },
19233 extra_end: usize,
19234 is_ref: bool,
19235) CompileError!Air.Inst.Ref {
19236 const mod = sema.mod;
19237 const gpa = sema.gpa;
19238 const zir_datas = sema.code.instructions.items(.data);
19239
19240 const types = try sema.arena.alloc(InternPool.Index, extra_data.fields_len);
1904619241 const values = try sema.arena.alloc(InternPool.Index, types.len);
19242
1904719243 var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena);
1904819244 try fields.ensureUnusedCapacity(types.len);
1904919245
1905019246 // Find which field forces the expression to be runtime, if any.
1905119247 const opt_runtime_index = rs: {
1905219248 var runtime_index: ?usize = null;
19053 var extra_index = extra.end;
19249 var extra_index = extra_end;
1905419250 for (types, 0..) |*field_ty, i_usize| {
19055 const i = @as(u32, @intCast(i_usize));
19056 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
19251 const i: u32 = @intCast(i_usize);
19252 const item = switch (kind) {
19253 .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index),
19254 .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index),
19255 };
1905719256 extra_index = item.end;
1905819257
19059 const name = sema.code.nullTerminatedString(item.data.field_name);
19258 const name = switch (kind) {
19259 .anon_init => sema.code.nullTerminatedString(item.data.field_name),
19260 .typed_init => name: {
19261 // `item.data.field_type` references a `field_type` instruction
19262 const field_type_data = zir_datas[item.data.field_type].pl_node;
19263 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index);
19264 break :name sema.code.nullTerminatedString(field_type_extra.data.name_start);
19265 },
19266 };
1906019267 const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
1906119268 const gop = fields.getOrPutAssumeCapacity(name_ip);
1906219269 if (gop.found_existing) {
......@@ -19129,10 +19336,13 @@ fn zirStructInitAnon(
1912919336 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1913019337 });
1913119338 const alloc = try block.addTy(.alloc, alloc_ty);
19132 var extra_index = extra.end;
19339 var extra_index = extra_end;
1913319340 for (types, 0..) |field_ty, i_usize| {
1913419341 const i = @as(u32, @intCast(i_usize));
19135 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
19342 const item = switch (kind) {
19343 .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index),
19344 .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index),
19345 };
1913619346 extra_index = item.end;
1913719347
1913819348 const field_ptr_ty = try mod.ptrType(.{
......@@ -19150,9 +19360,12 @@ fn zirStructInitAnon(
1915019360 }
1915119361
1915219362 const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len);
19153 var extra_index = extra.end;
19363 var extra_index = extra_end;
1915419364 for (types, 0..) |_, i| {
19155 const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
19365 const item = switch (kind) {
19366 .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index),
19367 .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index),
19368 };
1915619369 extra_index = item.end;
1915719370 element_refs[i] = try sema.resolveInst(item.data.init);
1915819371 }
......@@ -19175,14 +19388,21 @@ fn zirArrayInit(
1917519388 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
1917619389 assert(args.len >= 2); // array_ty + at least one element
1917719390
19178 const array_ty = try sema.resolveType(block, src, args[0]);
19391 const array_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) {
19392 error.GenericPoison => {
19393 // The type wasn't actually known, so treat this as an anon array init.
19394 return sema.arrayInitAnon(block, src, args[1..], is_ref);
19395 },
19396 else => |e| return e,
19397 };
19398 const is_tuple = array_ty.zigTypeTag(mod) == .Struct;
1917919399 const sentinel_val = array_ty.sentinel(mod);
1918019400
1918119401 const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @intFromBool(sentinel_val != null));
1918219402 defer gpa.free(resolved_args);
1918319403 for (args[1..], 0..) |arg, i| {
1918419404 const resolved_arg = try sema.resolveInst(arg);
19185 const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct)
19405 const elem_ty = if (is_tuple)
1918619406 array_ty.structFieldType(i, mod)
1918719407 else
1918819408 array_ty.elemType2(mod);
......@@ -19195,6 +19415,18 @@ fn zirArrayInit(
1919519415 },
1919619416 else => return err,
1919719417 };
19418 if (is_tuple) if (try array_ty.structFieldValueComptime(mod, i)) |field_val| {
19419 const init_val = try sema.resolveMaybeUndefVal(resolved_args[i]) orelse {
19420 const decl = mod.declPtr(block.src_decl);
19421 const elem_src = mod.initSrc(src.node_offset.x, decl, i);
19422 return sema.failWithNeededComptime(block, elem_src, "value stored in comptime field must be comptime-known");
19423 };
19424 if (!field_val.eql(init_val, elem_ty, mod)) {
19425 const decl = mod.declPtr(block.src_decl);
19426 const elem_src = mod.initSrc(src.node_offset.x, decl, i);
19427 return sema.failWithInvalidComptimeFieldStore(block, elem_src, array_ty, i);
19428 }
19429 };
1919819430 }
1919919431
1920019432 if (sentinel_val) |some| {
......@@ -19283,6 +19515,16 @@ fn zirArrayInitAnon(
1928319515 const src = inst_data.src();
1928419516 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
1928519517 const operands = sema.code.refSlice(extra.end, extra.data.operands_len);
19518 return sema.arrayInitAnon(block, src, operands, is_ref);
19519}
19520
19521fn arrayInitAnon(
19522 sema: *Sema,
19523 block: *Block,
19524 src: LazySrcLoc,
19525 operands: []const Zir.Inst.Ref,
19526 is_ref: bool,
19527) CompileError!Air.Inst.Ref {
1928619528 const mod = sema.mod;
1928719529
1928819530 const types = try sema.arena.alloc(InternPool.Index, operands.len);
......@@ -23034,7 +23276,21 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2303423276 const callee_ty = sema.typeOf(func);
2303523277 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
2303623278 const ensure_result_used = extra.flags.ensure_result_used;
23037 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null, .@"@call");
23279 return sema.analyzeCall(
23280 block,
23281 func,
23282 func_ty,
23283 func_src,
23284 call_src,
23285 modifier,
23286 ensure_result_used,
23287 .{ .call_builtin = .{
23288 .call_node_offset = inst_data.src_node,
23289 .args = resolved_args,
23290 } },
23291 null,
23292 .@"@call",
23293 );
2303823294}
2303923295
2304023296fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/Zir.zig+15
......@@ -248,6 +248,9 @@ pub const Inst = struct {
248248 /// Given a pointer type, returns its element type.
249249 /// Uses the `un_node` field.
250250 elem_type,
251 /// Given a vector type, returns its element type.
252 /// Uses the `un_node` field.
253 vector_elem_type,
251254 /// Given a pointer to an indexable object, returns the len property. This is
252255 /// used by for loops. This instruction also emits a for-loop specific compile
253256 /// error if the indexable object is not indexable.
......@@ -700,10 +703,16 @@ pub const Inst = struct {
700703 /// *?S returns *S
701704 /// Uses the `un_node` field.
702705 field_base_ptr,
706 /// Given a type, strips all optional and error union types wrapping it.
707 /// e.g. `E!?u32` becomes `u32`, `[]u8` becomes `[]u8`.
708 /// Uses the `un_node` field.
709 opt_eu_base_ty,
703710 /// Checks that the type supports array init syntax.
711 /// Returns the underlying indexable type (since the given type may be e.g. an optional).
704712 /// Uses the `un_node` field.
705713 validate_array_init_ty,
706714 /// Checks that the type supports struct init syntax.
715 /// Returns the underlying struct type (since the given type may be e.g. an optional).
707716 /// Uses the `un_node` field.
708717 validate_struct_init_ty,
709718 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
......@@ -1023,6 +1032,7 @@ pub const Inst = struct {
10231032 .vector_type,
10241033 .elem_type_index,
10251034 .elem_type,
1035 .vector_elem_type,
10261036 .indexable_ptr_len,
10271037 .anyframe_type,
10281038 .as,
......@@ -1234,6 +1244,7 @@ pub const Inst = struct {
12341244 .save_err_ret_index,
12351245 .restore_err_ret_index,
12361246 .for_len,
1247 .opt_eu_base_ty,
12371248 => false,
12381249
12391250 .@"break",
......@@ -1327,6 +1338,7 @@ pub const Inst = struct {
13271338 .vector_type,
13281339 .elem_type_index,
13291340 .elem_type,
1341 .vector_elem_type,
13301342 .indexable_ptr_len,
13311343 .anyframe_type,
13321344 .as,
......@@ -1522,6 +1534,7 @@ pub const Inst = struct {
15221534 .for_len,
15231535 .@"try",
15241536 .try_ptr,
1537 .opt_eu_base_ty,
15251538 => false,
15261539
15271540 .extended => switch (data.extended.opcode) {
......@@ -1557,6 +1570,7 @@ pub const Inst = struct {
15571570 .vector_type = .pl_node,
15581571 .elem_type_index = .bin,
15591572 .elem_type = .un_node,
1573 .vector_elem_type = .un_node,
15601574 .indexable_ptr_len = .un_node,
15611575 .anyframe_type = .un_node,
15621576 .as = .bin,
......@@ -1676,6 +1690,7 @@ pub const Inst = struct {
16761690 .switch_block_ref = .pl_node,
16771691 .array_base_ptr = .un_node,
16781692 .field_base_ptr = .un_node,
1693 .opt_eu_base_ty = .un_node,
16791694 .validate_array_init_ty = .pl_node,
16801695 .validate_struct_init_ty = .un_node,
16811696 .validate_struct_init = .pl_node,
src/print_zir.zig+2
......@@ -155,6 +155,7 @@ const Writer = struct {
155155 .alloc_mut,
156156 .alloc_comptime_mut,
157157 .elem_type,
158 .vector_elem_type,
158159 .indexable_ptr_len,
159160 .anyframe_type,
160161 .bit_not,
......@@ -229,6 +230,7 @@ const Writer = struct {
229230 .make_ptr_const,
230231 .validate_deref,
231232 .check_comptime_control_flow,
233 .opt_eu_base_ty,
232234 => try self.writeUnNode(stream, inst),
233235
234236 .ref,
src/type.zig+1
......@@ -3039,6 +3039,7 @@ pub const Type = struct {
30393039 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
30403040 .struct_type => |struct_type| {
30413041 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3042 assert(struct_obj.haveFieldTypes());
30423043 return struct_obj.fields.values()[index].ty;
30433044 },
30443045 .union_type => |union_type| {
test/behavior/array.zig+14
......@@ -761,3 +761,17 @@ test "slicing array of zero-sized values" {
761761 for (arr[0..]) |zero|
762762 try expect(zero == 0);
763763}
764
765test "array init with no result pointer sets field result types" {
766 const S = struct {
767 // A function parameter has a result type, but no result pointer.
768 fn f(arr: [1]u32) u32 {
769 return arr[0];
770 }
771 };
772
773 const x: u64 = 123;
774 const y = S.f(.{@intCast(x)});
775
776 try expect(y == x);
777}
test/behavior/call.zig+61
......@@ -430,3 +430,64 @@ test "method call as parameter type" {
430430 try expectEqual(@as(u64, 123), S.foo(S{}, 123));
431431 try expectEqual(@as(u64, 500), S.foo(S{}, 500));
432432}
433
434test "non-anytype generic parameters provide result type" {
435 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
440 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
441
442 const S = struct {
443 fn f(comptime T: type, y: T) !void {
444 try expectEqual(@as(T, 123), y);
445 }
446
447 fn g(x: anytype, y: @TypeOf(x)) !void {
448 try expectEqual(@as(@TypeOf(x), 0x222), y);
449 }
450 };
451
452 var rt_u16: u16 = 123;
453 var rt_u32: u32 = 0x10000222;
454
455 try S.f(u8, @intCast(rt_u16));
456 try S.f(u8, @intCast(123));
457
458 try S.g(rt_u16, @truncate(rt_u32));
459 try S.g(rt_u16, @truncate(0x10000222));
460
461 try comptime S.f(u8, @intCast(123));
462 try comptime S.g(@as(u16, undefined), @truncate(0x99990222));
463}
464
465test "argument to generic function has correct result type" {
466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
472
473 const S = struct {
474 fn foo(_: anytype, e: enum { a, b }) bool {
475 return e == .b;
476 }
477
478 fn doTheTest() !void {
479 var t = true;
480
481 // Since the enum literal passes through a runtime conditional here, these can only
482 // compile if RLS provides the correct result type to the argument
483 try expect(foo({}, if (!t) .a else .b));
484 try expect(!foo("dummy", if (t) .a else .b));
485 try expect(foo({}, if (t) .b else .a));
486 try expect(!foo(123, if (t) .a else .a));
487 try expect(foo(123, if (t) .b else .b));
488 }
489 };
490
491 try S.doTheTest();
492 try comptime S.doTheTest();
493}
test/behavior/struct.zig+14
......@@ -1724,3 +1724,17 @@ test "packed struct field in anonymous struct" {
17241724fn countFields(v: anytype) usize {
17251725 return @typeInfo(@TypeOf(v)).Struct.fields.len;
17261726}
1727
1728test "struct init with no result pointer sets field result types" {
1729 const S = struct {
1730 // A function parameter has a result type, but no result pointer.
1731 fn f(s: struct { x: u32 }) u32 {
1732 return s.x;
1733 }
1734 };
1735
1736 const x: u64 = 123;
1737 const y = S.f(.{ .x = @intCast(x) });
1738
1739 try expect(y == x);
1740}
test/cases/compile_errors/anytype_param_requires_comptime.zig+1-1
......@@ -16,7 +16,7 @@ pub export fn entry() void {
1616// backend=stage2
1717// target=native
1818//
19// :7:14: error: runtime-known argument passed to comptime-only type parameter
19// :7:14: error: runtime-known argument passed to parameter of comptime-only type
2020// :9:12: note: declared here
2121// :4:16: note: struct requires comptime because of this field
2222// :4:16: note: types are not available at runtime
test/cases/compile_errors/error_in_typeof_param.zig+1-1
......@@ -11,4 +11,4 @@ pub export fn entry() void {
1111// target=native
1212//
1313// :6:31: error: unable to resolve comptime value
14// :6:31: note: argument to parameter with comptime-only type must be comptime-known
14// :6:31: note: value being casted to 'comptime_int' must be comptime-known
test/cases/compile_errors/generic_method_call_with_invalid_param.zig+2
......@@ -25,6 +25,8 @@ const S = struct {
2525// target=native
2626//
2727// :3:18: error: expected type 'bool', found 'void'
28// :18:43: note: parameter type declared here
2829// :8:18: error: expected type 'void', found 'bool'
30// :19:43: note: parameter type declared here
2931// :14:26: error: runtime-known argument passed to comptime parameter
3032// :20:57: note: declared comptime here
test/cases/compile_errors/invalid_store_to_comptime_field.zig+3-2
......@@ -76,8 +76,9 @@ pub export fn entry8() void {
7676// :19:38: error: value stored in comptime field does not match the default value of the field
7777// :31:19: error: value stored in comptime field does not match the default value of the field
7878// :25:29: note: default value set here
79// :41:16: error: value stored in comptime field does not match the default value of the field
79// :41:19: error: value stored in comptime field does not match the default value of the field
80// :35:29: note: default value set here
8081// :45:12: error: value stored in comptime field does not match the default value of the field
81// :53:16: error: value stored in comptime field does not match the default value of the field
82// :53:25: error: value stored in comptime field does not match the default value of the field
8283// :66:43: error: value stored in comptime field does not match the default value of the field
8384// :59:35: error: value stored in comptime field does not match the default value of the field
test/cases/compile_errors/splat_result_type_non_vector.zig created+9
......@@ -0,0 +1,9 @@
1export fn f() void {
2 _ = @as(u32, @splat(5));
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:18: error: expected vector type, found 'u32'
test/cases/compile_errors/wrong_types_given_to_export.zig+1-1
......@@ -7,5 +7,5 @@ comptime {
77// backend=stage2
88// target=native
99//
10// :3:51: error: expected type 'builtin.GlobalLinkage', found 'u32'
10// :3:21: error: expected type 'builtin.GlobalLinkage', found 'u32'
1111// :?:?: note: enum declared here
test/cases/compile_errors/zero-bit_generic_args_are_coerced_to_param_type.zig+1
......@@ -8,3 +8,4 @@ pub export fn entry() void {
88// target=native
99//
1010// :3:21: error: expected type 'u0', found '*const [4:0]u8'
11// :1:23: note: parameter type declared here
test/compile_errors.zig+1-1
......@@ -207,7 +207,7 @@ pub fn addCases(ctx: *Cases) !void {
207207 ":1:38: note: declared comptime here",
208208 ":8:36: error: runtime-known argument passed to comptime parameter",
209209 ":2:41: note: declared comptime here",
210 ":13:29: error: runtime-known argument passed to comptime-only type parameter",
210 ":13:29: error: runtime-known argument passed to parameter of comptime-only type",
211211 ":3:24: note: declared here",
212212 ":12:35: note: struct requires comptime because of this field",
213213 ":12:35: note: types are not available at runtime",