authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-03 17:29:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-03 17:29:59-07:00
log609b84611dcde382af5d9fbc2345ede468d31a6f
tree9dab23600c4fd136b10ccd65eb3d908dfe6bb206
parent1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f

stage2: rework runtime, comptime, inline function calls

* ZIR function instructions encode the index of the block that contains the function instruction. This allows Zig to later scan the block and find the parameter instructions, which is needed for semantically analyzing function bodies. * Runtime function calls insert AIR arg instructions and then inserts Sema inst_map entries mapping the ZIR param instructions to them. * comptime/inline function call inserts Sema inst_map entries mapping the ZIR param instructions to the AIR callsite arguments. With this commit we are back to the tests passing.

5 files changed, 117 insertions(+), 78 deletions(-)

BRANCH_TODO-2
...@@ -1,6 +1,4 @@...@@ -1,6 +1,4 @@
1* update arg instructions:1* update arg instructions:
2 - runtime function call inserts AIR arg instructions and Sema map items for them
3 - comptime/inline function call inserts Sema map items for the args
4 - generic instantiation inserts Sema map items for the comptime args only, re-runs the2 - generic instantiation inserts Sema map items for the comptime args only, re-runs the
5 Decl ZIR to get the new Fn.3 Decl ZIR to get the new Fn.
6* generic function call where it makes a new function4* generic function call where it makes a new function
src/AstGen.zig+7
...@@ -1125,6 +1125,7 @@ fn fnProtoExpr(...@@ -1125,6 +1125,7 @@ fn fnProtoExpr(
11251125
1126 const result = try gz.addFunc(.{1126 const result = try gz.addFunc(.{
1127 .src_node = fn_proto.ast.proto_node,1127 .src_node = fn_proto.ast.proto_node,
1128 .param_block = 0,
1128 .ret_ty = return_type_inst,1129 .ret_ty = return_type_inst,
1129 .body = &[0]Zir.Inst.Index{},1130 .body = &[0]Zir.Inst.Index{},
1130 .cc = cc,1131 .cc = cc,
...@@ -3035,6 +3036,7 @@ fn fnDecl(...@@ -3035,6 +3036,7 @@ fn fnDecl(
3035 break :func try decl_gz.addFunc(.{3036 break :func try decl_gz.addFunc(.{
3036 .src_node = decl_node,3037 .src_node = decl_node,
3037 .ret_ty = return_type_inst,3038 .ret_ty = return_type_inst,
3039 .param_block = block_inst,
3038 .body = &[0]Zir.Inst.Index{},3040 .body = &[0]Zir.Inst.Index{},
3039 .cc = cc,3041 .cc = cc,
3040 .align_inst = .none, // passed in the per-decl data3042 .align_inst = .none, // passed in the per-decl data
...@@ -3071,6 +3073,7 @@ fn fnDecl(...@@ -3071,6 +3073,7 @@ fn fnDecl(
30713073
3072 break :func try decl_gz.addFunc(.{3074 break :func try decl_gz.addFunc(.{
3073 .src_node = decl_node,3075 .src_node = decl_node,
3076 .param_block = block_inst,
3074 .ret_ty = return_type_inst,3077 .ret_ty = return_type_inst,
3075 .body = fn_gz.instructions.items,3078 .body = fn_gz.instructions.items,
3076 .cc = cc,3079 .cc = cc,
...@@ -3415,6 +3418,7 @@ fn testDecl(...@@ -3415,6 +3418,7 @@ fn testDecl(
34153418
3416 const func_inst = try decl_block.addFunc(.{3419 const func_inst = try decl_block.addFunc(.{
3417 .src_node = node,3420 .src_node = node,
3421 .param_block = block_inst,
3418 .ret_ty = .void_type,3422 .ret_ty = .void_type,
3419 .body = fn_block.instructions.items,3423 .body = fn_block.instructions.items,
3420 .cc = .none,3424 .cc = .none,
...@@ -9111,6 +9115,7 @@ const GenZir = struct {...@@ -9111,6 +9115,7 @@ const GenZir = struct {
9111 fn addFunc(gz: *GenZir, args: struct {9115 fn addFunc(gz: *GenZir, args: struct {
9112 src_node: ast.Node.Index,9116 src_node: ast.Node.Index,
9113 body: []const Zir.Inst.Index,9117 body: []const Zir.Inst.Index,
9118 param_block: Zir.Inst.Index,
9114 ret_ty: Zir.Inst.Ref,9119 ret_ty: Zir.Inst.Ref,
9115 cc: Zir.Inst.Ref,9120 cc: Zir.Inst.Ref,
9116 align_inst: Zir.Inst.Ref,9121 align_inst: Zir.Inst.Ref,
...@@ -9170,6 +9175,7 @@ const GenZir = struct {...@@ -9170,6 +9175,7 @@ const GenZir = struct {
9170 );9175 );
9171 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{9176 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
9172 .src_node = gz.nodeIndexToRelative(args.src_node),9177 .src_node = gz.nodeIndexToRelative(args.src_node),
9178 .param_block = args.param_block,
9173 .return_type = args.ret_ty,9179 .return_type = args.ret_ty,
9174 .body_len = @intCast(u32, args.body.len),9180 .body_len = @intCast(u32, args.body.len),
9175 });9181 });
...@@ -9212,6 +9218,7 @@ const GenZir = struct {...@@ -9212,6 +9218,7 @@ const GenZir = struct {
9212 );9218 );
92139219
9214 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{9220 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
9221 .param_block = args.param_block,
9215 .return_type = args.ret_ty,9222 .return_type = args.ret_ty,
9216 .body_len = @intCast(u32, args.body.len),9223 .body_len = @intCast(u32, args.body.len),
9217 });9224 });
src/Module.zig+38-19
...@@ -2899,7 +2899,6 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -2899,7 +2899,6 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
2899 .namespace = &struct_obj.namespace,2899 .namespace = &struct_obj.namespace,
2900 .func = null,2900 .func = null,
2901 .owner_func = null,2901 .owner_func = null,
2902 .param_inst_list = &.{},
2903 };2902 };
2904 defer sema.deinit();2903 defer sema.deinit();
2905 var block_scope: Scope.Block = .{2904 var block_scope: Scope.Block = .{
...@@ -2954,7 +2953,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2954,7 +2953,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2954 .namespace = decl.namespace,2953 .namespace = decl.namespace,
2955 .func = null,2954 .func = null,
2956 .owner_func = null,2955 .owner_func = null,
2957 .param_inst_list = &.{},
2958 };2956 };
2959 defer sema.deinit();2957 defer sema.deinit();
29602958
...@@ -3625,8 +3623,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3625,8 +3623,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3625 defer decl.value_arena.?.* = arena.state;3623 defer decl.value_arena.?.* = arena.state;
36263624
3627 const fn_ty = decl.ty;3625 const fn_ty = decl.ty;
3628 const param_inst_list = try gpa.alloc(Air.Inst.Ref, fn_ty.fnParamLen());
3629 defer gpa.free(param_inst_list);
36303626
3631 var sema: Sema = .{3627 var sema: Sema = .{
3632 .mod = mod,3628 .mod = mod,
...@@ -3637,7 +3633,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3637,7 +3633,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3637 .namespace = decl.namespace,3633 .namespace = decl.namespace,
3638 .func = func,3634 .func = func,
3639 .owner_func = func,3635 .owner_func = func,
3640 .param_inst_list = param_inst_list,
3641 };3636 };
3642 defer sema.deinit();3637 defer sema.deinit();
36433638
...@@ -3656,29 +3651,55 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3656,29 +3651,55 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3656 };3651 };
3657 defer inner_block.instructions.deinit(gpa);3652 defer inner_block.instructions.deinit(gpa);
36583653
3659 // AIR requires the arg parameters to be the first N instructions.3654 const fn_info = sema.code.getFnInfo(func.zir_body_inst);
3660 try inner_block.instructions.ensureTotalCapacity(gpa, param_inst_list.len);3655 const zir_tags = sema.code.instructions.items(.tag);
3661 for (param_inst_list) |*param_inst, param_index| {3656
3657 // Here we are performing "runtime semantic analysis" for a function body, which means
3658 // we must map the parameter ZIR instructions to `arg` AIR instructions.
3659 // AIR requires the `arg` parameters to be the first N instructions.
3660 const params_len = @intCast(u32, fn_ty.fnParamLen());
3661 try inner_block.instructions.ensureTotalCapacity(gpa, params_len);
3662 try sema.air_instructions.ensureUnusedCapacity(gpa, params_len * 2); // * 2 for the `addType`
3663 try sema.inst_map.ensureUnusedCapacity(gpa, params_len);
3664
3665 var param_index: usize = 0;
3666 for (fn_info.param_body) |inst| {
3667 const name = switch (zir_tags[inst]) {
3668 .param, .param_comptime => blk: {
3669 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
3670 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
3671 break :blk extra.name;
3672 },
3673
3674 .param_anytype, .param_anytype_comptime => blk: {
3675 const str_tok = sema.code.instructions.items(.data)[inst].str_tok;
3676 break :blk str_tok.start;
3677 },
3678
3679 else => continue,
3680 };
3662 const param_type = fn_ty.fnParamType(param_index);3681 const param_type = fn_ty.fnParamType(param_index);
3682 param_index += 1;
3663 const ty_ref = try sema.addType(param_type);3683 const ty_ref = try sema.addType(param_type);
3664 const arg_index = @intCast(u32, sema.air_instructions.len);3684 const arg_index = @intCast(u32, sema.air_instructions.len);
3665 inner_block.instructions.appendAssumeCapacity(arg_index);3685 inner_block.instructions.appendAssumeCapacity(arg_index);
3666 param_inst.* = Air.indexToRef(arg_index);3686 sema.air_instructions.appendAssumeCapacity(.{
3667 try sema.air_instructions.append(gpa, .{
3668 .tag = .arg,3687 .tag = .arg,
3669 .data = .{3688 .data = .{ .ty_str = .{
3670 .ty_str = .{3689 .ty = ty_ref,
3671 .ty = ty_ref,3690 .str = name,
3672 .str = undefined, // Set in the semantic analysis of the arg instruction.3691 } },
3673 },
3674 },
3675 });3692 });
3693 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
3676 }3694 }
36773695
3678 func.state = .in_progress;3696 func.state = .in_progress;
3679 log.debug("set {s} to in_progress", .{decl.name});3697 log.debug("set {s} to in_progress", .{decl.name});
36803698
3681 try sema.analyzeFnBody(&inner_block, func.zir_body_inst);3699 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
3700 error.NeededSourceLocation => unreachable,
3701 else => |e| return e,
3702 };
36823703
3683 // Copy the block into place and mark that as the main block.3704 // Copy the block into place and mark that as the main block.
3684 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +3705 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
...@@ -4330,7 +4351,6 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void...@@ -4330,7 +4351,6 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void
4330 .namespace = &struct_obj.namespace,4351 .namespace = &struct_obj.namespace,
4331 .owner_func = null,4352 .owner_func = null,
4332 .func = null,4353 .func = null,
4333 .param_inst_list = &.{},
4334 };4354 };
4335 defer sema.deinit();4355 defer sema.deinit();
43364356
...@@ -4484,7 +4504,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) CompileError!void {...@@ -4484,7 +4504,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) CompileError!void {
4484 .namespace = &union_obj.namespace,4504 .namespace = &union_obj.namespace,
4485 .owner_func = null,4505 .owner_func = null,
4486 .func = null,4506 .func = null,
4487 .param_inst_list = &.{},
4488 };4507 };
4489 defer sema.deinit();4508 defer sema.deinit();
44904509
src/Sema.zig+21-54
...@@ -29,13 +29,6 @@ owner_func: ?*Module.Fn,...@@ -29,13 +29,6 @@ owner_func: ?*Module.Fn,
29/// This starts out the same as `owner_func` and then diverges in the case of29/// This starts out the same as `owner_func` and then diverges in the case of
30/// an inline or comptime function call.30/// an inline or comptime function call.
31func: ?*Module.Fn,31func: ?*Module.Fn,
32/// For now, AIR requires arg instructions to be the first N instructions in the
33/// AIR code. We store references here for the purpose of `resolveInst`.
34/// This can get reworked with AIR memory layout changes, into simply:
35/// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
36/// > otherwise it is the number of parameters of the function.
37/// > param_count: u32
38param_inst_list: []const Air.Inst.Ref,
39branch_quota: u32 = 1000,32branch_quota: u32 = 1000,
40branch_count: u32 = 0,33branch_count: u32 = 0,
41/// This field is updated when a new source location becomes active, so that34/// This field is updated when a new source location becomes active, so that
...@@ -85,43 +78,10 @@ pub fn deinit(sema: *Sema) void {...@@ -85,43 +78,10 @@ pub fn deinit(sema: *Sema) void {
85 sema.air_values.deinit(gpa);78 sema.air_values.deinit(gpa);
86 sema.inst_map.deinit(gpa);79 sema.inst_map.deinit(gpa);
87 sema.decl_val_table.deinit(gpa);80 sema.decl_val_table.deinit(gpa);
81 sema.params.deinit(gpa);
88 sema.* = undefined;82 sema.* = undefined;
89}83}
9084
91pub fn analyzeFnBody(
92 sema: *Sema,
93 block: *Scope.Block,
94 fn_body_inst: Zir.Inst.Index,
95) SemaError!void {
96 const tags = sema.code.instructions.items(.tag);
97 const datas = sema.code.instructions.items(.data);
98 const body: []const Zir.Inst.Index = switch (tags[fn_body_inst]) {
99 .func, .func_inferred => blk: {
100 const inst_data = datas[fn_body_inst].pl_node;
101 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
102 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
103 break :blk body;
104 },
105 .extended => blk: {
106 const extended = datas[fn_body_inst].extended;
107 assert(extended.opcode == .func);
108 const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand);
109 const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
110 var extra_index: usize = extra.end;
111 extra_index += @boolToInt(small.has_lib_name);
112 extra_index += @boolToInt(small.has_cc);
113 extra_index += @boolToInt(small.has_align);
114 const body = sema.code.extra[extra_index..][0..extra.data.body_len];
115 break :blk body;
116 },
117 else => unreachable,
118 };
119 _ = sema.analyzeBody(block, body) catch |err| switch (err) {
120 error.NeededSourceLocation => unreachable,
121 else => |e| return e,
122 };
123}
124
125/// Returns only the result from the body that is specified.85/// Returns only the result from the body that is specified.
126/// Only appropriate to call when it is determined at comptime that this body86/// Only appropriate to call when it is determined at comptime that this body
127/// has no peers.87/// has no peers.
...@@ -1066,7 +1026,6 @@ fn zirEnumDecl(...@@ -1066,7 +1026,6 @@ fn zirEnumDecl(
1066 .namespace = &enum_obj.namespace,1026 .namespace = &enum_obj.namespace,
1067 .owner_func = null,1027 .owner_func = null,
1068 .func = null,1028 .func = null,
1069 .param_inst_list = &.{},
1070 .branch_quota = sema.branch_quota,1029 .branch_quota = sema.branch_quota,
1071 .branch_count = sema.branch_count,1030 .branch_count = sema.branch_count,
1072 };1031 };
...@@ -2538,10 +2497,6 @@ fn analyzeCall(...@@ -2538,10 +2497,6 @@ fn analyzeCall(
2538 sema.func = module_fn;2497 sema.func = module_fn;
2539 defer sema.func = parent_func;2498 defer sema.func = parent_func;
25402499
2541 const parent_param_inst_list = sema.param_inst_list;
2542 sema.param_inst_list = args;
2543 defer sema.param_inst_list = parent_param_inst_list;
2544
2545 const parent_next_arg_index = sema.next_arg_index;2500 const parent_next_arg_index = sema.next_arg_index;
2546 sema.next_arg_index = 0;2501 sema.next_arg_index = 0;
2547 defer sema.next_arg_index = parent_next_arg_index;2502 defer sema.next_arg_index = parent_next_arg_index;
...@@ -2565,12 +2520,23 @@ fn analyzeCall(...@@ -2565,12 +2520,23 @@ fn analyzeCall(
2565 try sema.emitBackwardBranch(&child_block, call_src);2520 try sema.emitBackwardBranch(&child_block, call_src);
25662521
2567 // This will have return instructions analyzed as break instructions to2522 // This will have return instructions analyzed as break instructions to
2568 // the block_inst above.2523 // the block_inst above. Here we are performing "comptime/inline semantic analysis"
2569 try sema.analyzeFnBody(&child_block, module_fn.zir_body_inst);2524 // for a function body, which means we must map the parameter ZIR instructions to
25702525 // the AIR instructions of the callsite.
2571 const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges);2526 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
25722527 const zir_tags = sema.code.instructions.items(.tag);
2573 break :res result;2528 var arg_i: usize = 0;
2529 try sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, args.len));
2530 for (fn_info.param_body) |inst| {
2531 switch (zir_tags[inst]) {
2532 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {},
2533 else => continue,
2534 }
2535 sema.inst_map.putAssumeCapacityNoClobber(inst, args[arg_i]);
2536 arg_i += 1;
2537 }
2538 _ = try sema.analyzeBody(&child_block, fn_info.body);
2539 break :res try sema.analyzeBlockBody(block, call_src, &child_block, merges);
2574 } else if (func_ty_info.is_generic) {2540 } else if (func_ty_info.is_generic) {
2575 const func_val = try sema.resolveConstValue(block, func_src, func);2541 const func_val = try sema.resolveConstValue(block, func_src, func);
2576 const module_fn = func_val.castTag(.function).?.data;2542 const module_fn = func_val.castTag(.function).?.data;
...@@ -2601,7 +2567,7 @@ fn analyzeCall(...@@ -2601,7 +2567,7 @@ fn analyzeCall(
2601 // TODO2567 // TODO
26022568
2603 // Queue up a `codegen_func` work item for the new Fn, making sure it will have2569 // Queue up a `codegen_func` work item for the new Fn, making sure it will have
2604 // `analyzeFnBody` called with the Scope which contains the comptime parameters.2570 // `analyzeBody` called with the ZIR parameters mapped appropriately.
2605 // TODO2571 // TODO
26062572
2607 // Save it into the Module's generic function map.2573 // Save it into the Module's generic function map.
...@@ -3344,11 +3310,12 @@ fn funcCommon(...@@ -3344,11 +3310,12 @@ fn funcCommon(
3344 // `resolveSwitchItemVal` to avoid resolving the source location unless3310 // `resolveSwitchItemVal` to avoid resolving the source location unless
3345 // we actually need to report an error.3311 // we actually need to report an error.
3346 const param_src = src;3312 const param_src = src;
3347 param_types[i] = try sema.resolveType(block, param_src, param.ty);3313 param_types[i] = try sema.analyzeAsType(block, param_src, param.ty);
3348 }3314 }
3349 comptime_params[i] = param.is_comptime;3315 comptime_params[i] = param.is_comptime;
3350 any_are_comptime = any_are_comptime or param.is_comptime;3316 any_are_comptime = any_are_comptime or param.is_comptime;
3351 }3317 }
3318 sema.params.clearRetainingCapacity();
33523319
3353 if (align_val.tag() != .null_value) {3320 if (align_val.tag() != .null_value) {
3354 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3321 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
src/Zir.zig+51-3
...@@ -61,7 +61,7 @@ pub const ExtraIndex = enum(u32) {...@@ -61,7 +61,7 @@ pub const ExtraIndex = enum(u32) {
61 _,61 _,
62};62};
6363
64pub fn getMainStruct(zir: Zir) Zir.Inst.Index {64pub fn getMainStruct(zir: Zir) Inst.Index {
65 return zir.extra[@enumToInt(ExtraIndex.main_struct)] -65 return zir.extra[@enumToInt(ExtraIndex.main_struct)] -
66 @intCast(u32, Inst.Ref.typed_value_map.len);66 @intCast(u32, Inst.Ref.typed_value_map.len);
67}67}
...@@ -2260,6 +2260,8 @@ pub const Inst = struct {...@@ -2260,6 +2260,8 @@ pub const Inst = struct {
2260 pub const ExtendedFunc = struct {2260 pub const ExtendedFunc = struct {
2261 src_node: i32,2261 src_node: i32,
2262 return_type: Ref,2262 return_type: Ref,
2263 /// Points to the block that contains the param instructions for this function.
2264 param_block: Index,
2263 body_len: u32,2265 body_len: u32,
22642266
2265 pub const Small = packed struct {2267 pub const Small = packed struct {
...@@ -2297,6 +2299,8 @@ pub const Inst = struct {...@@ -2297,6 +2299,8 @@ pub const Inst = struct {
2297 /// 1. src_locs: SrcLocs // if body_len != 02299 /// 1. src_locs: SrcLocs // if body_len != 0
2298 pub const Func = struct {2300 pub const Func = struct {
2299 return_type: Ref,2301 return_type: Ref,
2302 /// Points to the block that contains the param instructions for this function.
2303 param_block: Index,
2300 body_len: u32,2304 body_len: u32,
23012305
2302 pub const SrcLocs = struct {2306 pub const SrcLocs = struct {
...@@ -4894,10 +4898,54 @@ fn findDeclsSwitchMulti(...@@ -4894,10 +4898,54 @@ fn findDeclsSwitchMulti(
48944898
4895fn findDeclsBody(4899fn findDeclsBody(
4896 zir: Zir,4900 zir: Zir,
4897 list: *std.ArrayList(Zir.Inst.Index),4901 list: *std.ArrayList(Inst.Index),
4898 body: []const Zir.Inst.Index,4902 body: []const Inst.Index,
4899) Allocator.Error!void {4903) Allocator.Error!void {
4900 for (body) |member| {4904 for (body) |member| {
4901 try zir.findDeclsInner(list, member);4905 try zir.findDeclsInner(list, member);
4902 }4906 }
4903}4907}
4908
4909pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) struct {
4910 param_body: []const Inst.Index,
4911 body: []const Inst.Index,
4912} {
4913 const tags = zir.instructions.items(.tag);
4914 const datas = zir.instructions.items(.data);
4915 const info: struct {
4916 param_block: Inst.Index,
4917 body: []const Inst.Index,
4918 } = switch (tags[fn_inst]) {
4919 .func, .func_inferred => blk: {
4920 const inst_data = datas[fn_inst].pl_node;
4921 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
4922 const body = zir.extra[extra.end..][0..extra.data.body_len];
4923 break :blk .{
4924 .param_block = extra.data.param_block,
4925 .body = body,
4926 };
4927 },
4928 .extended => blk: {
4929 const extended = datas[fn_inst].extended;
4930 assert(extended.opcode == .func);
4931 const extra = zir.extraData(Inst.ExtendedFunc, extended.operand);
4932 const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
4933 var extra_index: usize = extra.end;
4934 extra_index += @boolToInt(small.has_lib_name);
4935 extra_index += @boolToInt(small.has_cc);
4936 extra_index += @boolToInt(small.has_align);
4937 const body = zir.extra[extra_index..][0..extra.data.body_len];
4938 break :blk .{
4939 .param_block = extra.data.param_block,
4940 .body = body,
4941 };
4942 },
4943 else => unreachable,
4944 };
4945 assert(tags[info.param_block] == .block or tags[info.param_block] == .block_inline);
4946 const param_block = zir.extraData(Inst.Block, datas[info.param_block].pl_node.payload_index);
4947 return .{
4948 .param_body = zir.extra[param_block.end..][0..param_block.data.body_len],
4949 .body = info.body,
4950 };
4951}