From 426e737292ffb3ec1d4c5780bd3c0511d4cdbc2b Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Fri, 21 Jul 2023 18:45:15 +0200 Subject: [PATCH] autodoc: avoid recursing reference loops in call instructions --- src/Autodoc.zig | 591 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 537 insertions(+), 54 deletions(-) diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 7dbe506cdd37..2a4fb1d15148 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -328,7 +328,14 @@ pub fn generateZirData(self: *Autodoc) !void { }); try self.files.put(self.arena, file, main_type_index); - _ = try self.walkInstruction(file, &root_scope, .{}, Zir.main_struct_inst, false); + _ = try self.walkInstruction( + file, + &root_scope, + .{}, + Zir.main_struct_inst, + false, + null, + ); if (self.ref_paths_pending_on_decls.count() > 0) { @panic("some decl paths were never fully analized (pending on decls)"); @@ -979,6 +986,15 @@ const AutodocErrors = error{ UnexpectedEndOfFile, } || std.fs.File.OpenError || std.fs.File.ReadError; +/// `call` instructions will have loopy references to themselves +/// whenever an as_node is required for a complex expression. +/// This type is used to keep track of dangerous instruction +/// numbers that we definitely don't want to recurse into. +const CallContext = struct { + inst: usize, + prev: ?*const CallContext, +}; + /// Called when we need to analyze a Zir instruction. /// For example it gets called by `generateZirData` on instruction 0, /// which represents the top-level struct corresponding to the root file. @@ -994,6 +1010,7 @@ fn walkInstruction( parent_src: SrcLocInfo, inst_index: usize, need_type: bool, // true if the caller needs us to provide also a typeRef + call_ctx: ?*const CallContext, ) AutodocErrors!DocData.WalkResult { const tags = file.zir.instructions.items(.tag); const data = file.zir.instructions.items(.data); @@ -1082,6 +1099,7 @@ fn walkInstruction( .{}, Zir.main_struct_inst, false, + call_ctx, ); } @@ -1113,6 +1131,7 @@ fn walkInstruction( .{}, Zir.main_struct_inst, need_type, + call_ctx, ); }, .ret_type => { @@ -1123,7 +1142,14 @@ fn walkInstruction( }, .ret_node => { const un_node = data[inst_index].un_node; - return self.walkRef(file, parent_scope, parent_src, un_node.operand, false); + return self.walkRef( + file, + parent_scope, + parent_src, + un_node.operand, + false, + call_ctx, + ); }, .ret_load => { const un_node = data[inst_index].un_node; @@ -1154,7 +1180,14 @@ fn walkInstruction( } if (result_ref) |rr| { - return self.walkRef(file, parent_scope, parent_src, rr, need_type); + return self.walkRef( + file, + parent_scope, + parent_src, + rr, + need_type, + call_ctx, + ); } return DocData.WalkResult{ @@ -1163,11 +1196,25 @@ fn walkInstruction( }, .closure_get => { const inst_node = data[inst_index].inst_node; - return try self.walkInstruction(file, parent_scope, parent_src, inst_node.inst, need_type); + return try self.walkInstruction( + file, + parent_scope, + parent_src, + inst_node.inst, + need_type, + call_ctx, + ); }, .closure_capture => { const un_tok = data[inst_index].un_tok; - return try self.walkRef(file, parent_scope, parent_src, un_tok.operand, need_type); + return try self.walkRef( + file, + parent_scope, + parent_src, + un_tok.operand, + need_type, + call_ctx, + ); }, .str => { const str = data[inst_index].str.get(file.zir); @@ -1214,6 +1261,7 @@ fn walkInstruction( parent_src, un_node.operand, false, + call_ctx, ); const operand_index = self.exprs.items.len; @@ -1284,6 +1332,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var start: DocData.WalkResult = try self.walkRef( file, @@ -1291,6 +1340,7 @@ fn walkInstruction( parent_src, extra.data.start, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1317,6 +1367,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var start: DocData.WalkResult = try self.walkRef( file, @@ -1324,6 +1375,7 @@ fn walkInstruction( parent_src, extra.data.start, false, + call_ctx, ); var end: DocData.WalkResult = try self.walkRef( file, @@ -1331,6 +1383,7 @@ fn walkInstruction( parent_src, extra.data.end, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1359,6 +1412,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var start: DocData.WalkResult = try self.walkRef( file, @@ -1366,6 +1420,7 @@ fn walkInstruction( parent_src, extra.data.start, false, + call_ctx, ); var end: DocData.WalkResult = try self.walkRef( file, @@ -1373,6 +1428,7 @@ fn walkInstruction( parent_src, extra.data.end, false, + call_ctx, ); var sentinel: DocData.WalkResult = try self.walkRef( file, @@ -1380,6 +1436,7 @@ fn walkInstruction( parent_src, extra.data.sentinel, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1410,6 +1467,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var start: DocData.WalkResult = try self.walkRef( file, @@ -1417,6 +1475,7 @@ fn walkInstruction( parent_src, extra.data.start, false, + call_ctx, ); var len: DocData.WalkResult = try self.walkRef( file, @@ -1424,6 +1483,7 @@ fn walkInstruction( parent_src, extra.data.len, false, + call_ctx, ); var sentinel_opt: ?DocData.WalkResult = if (extra.data.sentinel != .none) try self.walkRef( @@ -1432,6 +1492,7 @@ fn walkInstruction( parent_src, extra.data.sentinel, false, + call_ctx, ) else null; @@ -1492,6 +1553,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var rhs: DocData.WalkResult = try self.walkRef( file, @@ -1499,6 +1561,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1536,6 +1599,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var rhs: DocData.WalkResult = try self.walkRef( file, @@ -1543,6 +1607,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1599,7 +1664,14 @@ fn walkInstruction( const un_node = data[inst_index].un_node; const bin_index = self.exprs.items.len; try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } }); - const param = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false); + const param = try self.walkRef( + file, + parent_scope, + parent_src, + un_node.operand, + false, + call_ctx, + ); const param_index = self.exprs.items.len; try self.exprs.append(self.arena, param.expr); @@ -1623,6 +1695,7 @@ fn walkInstruction( parent_src, bool_br.lhs, false, + call_ctx, ); const lhs_index = self.exprs.items.len; try self.exprs.append(self.arena, lhs.expr); @@ -1634,6 +1707,7 @@ fn walkInstruction( parent_src, file.zir.extra[extra.end..][extra.data.body_len - 1], false, + call_ctx, ); const rhs_index = self.exprs.items.len; try self.exprs.append(self.arena, rhs.expr); @@ -1656,6 +1730,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const bin_index = self.exprs.items.len; @@ -1670,6 +1745,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[inst_index]), .param = rhs_index } }; @@ -1718,6 +1794,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var rhs: DocData.WalkResult = try self.walkRef( file, @@ -1725,6 +1802,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const lhs_index = self.exprs.items.len; @@ -1748,6 +1826,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var rhs: DocData.WalkResult = try self.walkRef( file, @@ -1755,6 +1834,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const type_slot_index = self.types.items.len; @@ -1778,6 +1858,7 @@ fn walkInstruction( parent_src, extra.data.lhs, false, + call_ctx, ); var rhs: DocData.WalkResult = try self.walkRef( file, @@ -1785,6 +1866,7 @@ fn walkInstruction( parent_src, extra.data.rhs, false, + call_ctx, ); const type_slot_index = self.types.items.len; try self.types.append(self.arena, .{ .ErrorUnion = .{ @@ -1820,6 +1902,7 @@ fn walkInstruction( parent_src, extra.data.elem_type, false, + call_ctx, ); // @check if `addrspace`, `bit_start` and `host_size` really need to be @@ -1827,7 +1910,14 @@ fn walkInstruction( var sentinel: ?DocData.Expr = null; if (ptr.flags.has_sentinel) { const ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); + const ref_result = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + call_ctx, + ); sentinel = ref_result.expr; extra_index += 1; } @@ -1835,21 +1925,42 @@ fn walkInstruction( var @"align": ?DocData.Expr = null; if (ptr.flags.has_align) { const ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); + const ref_result = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + call_ctx, + ); @"align" = ref_result.expr; extra_index += 1; } var address_space: ?DocData.Expr = null; if (ptr.flags.has_addrspace) { const ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); + const ref_result = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + call_ctx, + ); address_space = ref_result.expr; extra_index += 1; } var bit_start: ?DocData.Expr = null; if (ptr.flags.has_bit_range) { const ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); + const ref_result = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + call_ctx, + ); address_space = ref_result.expr; extra_index += 1; } @@ -1857,7 +1968,14 @@ fn walkInstruction( var host_size: ?DocData.Expr = null; if (ptr.flags.has_bit_range) { const ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); + const ref_result = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + call_ctx, + ); host_size = ref_result.expr; } @@ -1888,8 +2006,22 @@ fn walkInstruction( const pl_node = data[inst_index].pl_node; const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data; - const len = try self.walkRef(file, parent_scope, parent_src, bin.lhs, false); - const child = try self.walkRef(file, parent_scope, parent_src, bin.rhs, false); + const len = try self.walkRef( + file, + parent_scope, + parent_src, + bin.lhs, + false, + call_ctx, + ); + const child = try self.walkRef( + file, + parent_scope, + parent_src, + bin.rhs, + false, + call_ctx, + ); const type_slot_index = self.types.items.len; try self.types.append(self.arena, .{ @@ -1907,9 +2039,30 @@ fn walkInstruction( .array_type_sentinel => { const pl_node = data[inst_index].pl_node; const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index); - const len = try self.walkRef(file, parent_scope, parent_src, extra.data.len, false); - const sentinel = try self.walkRef(file, parent_scope, parent_src, extra.data.sentinel, false); - const elem_type = try self.walkRef(file, parent_scope, parent_src, extra.data.elem_type, false); + const len = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.len, + false, + call_ctx, + ); + const sentinel = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.sentinel, + false, + call_ctx, + ); + const elem_type = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.elem_type, + false, + call_ctx, + ); const type_slot_index = self.types.items.len; try self.types.append(self.arena, .{ @@ -1931,10 +2084,24 @@ fn walkInstruction( const array_data = try self.arena.alloc(usize, operands.len - 1); std.debug.assert(operands.len > 0); - var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false); + var array_type = try self.walkRef( + file, + parent_scope, + parent_src, + operands[0], + false, + call_ctx, + ); for (operands[1..], 0..) |op, idx| { - const wr = try self.walkRef(file, parent_scope, parent_src, op, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + op, + false, + call_ctx, + ); const expr_index = self.exprs.items.len; try self.exprs.append(self.arena, wr.expr); array_data[idx] = expr_index; @@ -1952,7 +2119,14 @@ fn walkInstruction( const array_data = try self.arena.alloc(usize, operands.len); for (operands, 0..) |op, idx| { - const wr = try self.walkRef(file, parent_scope, parent_src, op, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + op, + false, + call_ctx, + ); const expr_index = self.exprs.items.len; try self.exprs.append(self.arena, wr.expr); array_data[idx] = expr_index; @@ -1970,10 +2144,24 @@ fn walkInstruction( const array_data = try self.arena.alloc(usize, operands.len - 1); std.debug.assert(operands.len > 0); - var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false); + var array_type = try self.walkRef( + file, + parent_scope, + parent_src, + operands[0], + false, + call_ctx, + ); for (operands[1..], 0..) |op, idx| { - const wr = try self.walkRef(file, parent_scope, parent_src, op, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + op, + false, + call_ctx, + ); const expr_index = self.exprs.items.len; try self.exprs.append(self.arena, wr.expr); array_data[idx] = expr_index; @@ -2002,7 +2190,14 @@ fn walkInstruction( const array_data = try self.arena.alloc(usize, operands.len); for (operands, 0..) |op, idx| { - const wr = try self.walkRef(file, parent_scope, parent_src, op, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + op, + false, + call_ctx, + ); const expr_index = self.exprs.items.len; try self.exprs.append(self.arena, wr.expr); array_data[idx] = expr_index; @@ -2041,6 +2236,7 @@ fn walkInstruction( parent_src, un_node.operand, need_type, + call_ctx, ); switch (operand.expr) { .int => |*int| int.negated = true, @@ -2065,6 +2261,7 @@ fn walkInstruction( parent_src, un_node.operand, false, + call_ctx, ); const operand_index = self.exprs.items.len; try self.exprs.append(self.arena, operand.expr); @@ -2083,6 +2280,7 @@ fn walkInstruction( parent_src, un_node.operand, need_type, + call_ctx, ); const operand_index = self.exprs.items.len; try self.exprs.append(self.arena, operand.expr); @@ -2101,6 +2299,7 @@ fn walkInstruction( parent_src, un_node.operand, false, + call_ctx, ); const operand_index = self.exprs.items.len; try self.exprs.append(self.arena, operand.expr); @@ -2115,7 +2314,14 @@ fn walkInstruction( const pl_node = data[inst_index].pl_node; const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index); - const switch_cond = try self.walkRef(file, parent_scope, parent_src, extra.data.operand, false); + const switch_cond = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.operand, + false, + call_ctx, + ); const cond_index = self.exprs.items.len; try self.exprs.append(self.arena, switch_cond.expr); _ = cond_index; @@ -2162,6 +2368,7 @@ fn walkInstruction( parent_src, un_node.operand, need_type, + call_ctx, ); const operand_index = self.exprs.items.len; try self.exprs.append(self.arena, operand.expr); @@ -2181,6 +2388,7 @@ fn walkInstruction( parent_src, data[body].@"break".operand, false, + call_ctx, ); const operand_index = self.exprs.items.len; @@ -2201,6 +2409,7 @@ fn walkInstruction( parent_src, un_node.operand, need_type, + call_ctx, ); const operand_index = self.exprs.items.len; @@ -2214,12 +2423,31 @@ fn walkInstruction( .as_node, .as_shift_operand => { const pl_node = data[inst_index].pl_node; const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index); + + // Skip the as_node if the destination type is a call instruction + if (Zir.refToIndex(extra.data.dest_type)) |dti| { + var maybe_cc = call_ctx; + while (maybe_cc) |cc| : (maybe_cc = cc.prev) { + if (cc.inst == dti) { + return try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.operand, + false, + call_ctx, + ); + } + } + } + const dest_type_walk = try self.walkRef( file, parent_scope, parent_src, extra.data.dest_type, false, + call_ctx, ); const operand = try self.walkRef( @@ -2228,6 +2456,7 @@ fn walkInstruction( parent_src, extra.data.operand, false, + call_ctx, ); const operand_idx = self.exprs.items.len; @@ -2257,6 +2486,7 @@ fn walkInstruction( parent_src, un_node.operand, false, + call_ctx, ); const operand_idx = self.types.items.len; @@ -2332,7 +2562,14 @@ fn walkInstruction( } } - break :blk try self.walkRef(file, parent_scope, parent_src, lhs_ref, false); + break :blk try self.walkRef( + file, + parent_scope, + parent_src, + lhs_ref, + false, + call_ctx, + ); }; try path.append(self.arena, wr.expr); @@ -2400,6 +2637,7 @@ fn walkInstruction( return res; }, need_type, + call_ctx, ); }, .break_inline => { @@ -2410,6 +2648,7 @@ fn walkInstruction( parent_src, @"break".operand, need_type, + call_ctx, ); }, .struct_init => { @@ -2448,6 +2687,7 @@ fn walkInstruction( field_src, field_extra.data.container_type, false, + call_ctx, ); type_ref = wr.expr; } @@ -2459,6 +2699,7 @@ fn walkInstruction( parent_src, init_extra.data.init, need_type, + call_ctx, ); fv.* = .{ .name = field_name, .val = value }; } @@ -2477,6 +2718,7 @@ fn walkInstruction( parent_src, un_node.operand, false, + call_ctx, ); return DocData.WalkResult{ @@ -2503,6 +2745,7 @@ fn walkInstruction( parent_src, init_extra.data.init, need_type, + call_ctx, ); fv.* = .{ .name = field_name, .val = value }; idx = init_extra.end; @@ -2576,7 +2819,14 @@ fn walkInstruction( const pl_node = data[inst_index].pl_node; const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index); - const callee = try self.walkRef(file, parent_scope, parent_src, extra.data.callee, need_type); + const callee = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.callee, + need_type, + call_ctx, + ); const args_len = extra.data.flags.args_len; var args = try self.arena.alloc(DocData.Expr, args_len); @@ -2591,7 +2841,17 @@ fn walkInstruction( // to show discrepancies between the types of provided // arguments and the types declared in the function // signature for its parameters. - const wr = try self.walkRef(file, parent_scope, parent_src, ref, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + ref, + false, + &.{ + .inst = inst_index, + .prev = call_ctx, + }, + ); args[i] = wr.expr; } @@ -2639,6 +2899,7 @@ fn walkInstruction( self_ast_node_index, type_slot_index, tags[inst_index] == .func_inferred, + call_ctx, ); return result; @@ -2654,6 +2915,7 @@ fn walkInstruction( inst_index, self_ast_node_index, type_slot_index, + call_ctx, ); return result; @@ -2678,7 +2940,14 @@ fn walkInstruction( var array_type: ?DocData.Expr = null; for (args, 0..) |arg, idx| { - const wr = try self.walkRef(file, parent_scope, parent_src, arg, idx == 0); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + arg, + idx == 0, + call_ctx, + ); if (idx == 0) { array_type = wr.typeRef; } @@ -2740,6 +3009,7 @@ fn walkInstruction( src_info, &decl_indexes, &priv_decl_indexes, + call_ctx, ); self.types.items[type_slot_index] = .{ @@ -2778,7 +3048,14 @@ fn walkInstruction( if (small.has_lib_name) extra_index += 1; if (small.has_align) extra_index += 1; - const var_type = try self.walkRef(file, parent_scope, parent_src, extra.data.var_type, need_type); + const var_type = try self.walkRef( + file, + parent_scope, + parent_src, + extra.data.var_type, + need_type, + call_ctx, + ); var value: DocData.WalkResult = .{ .typeRef = var_type.expr, @@ -2787,7 +3064,14 @@ fn walkInstruction( if (small.has_init) { const var_init_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index])); - const var_init = try self.walkRef(file, parent_scope, parent_src, var_init_ref, need_type); + const var_init = try self.walkRef( + file, + parent_scope, + parent_src, + var_init_ref, + need_type, + call_ctx, + ); value.expr = var_init.expr; value.typeRef = var_init.typeRef; } @@ -2853,6 +3137,7 @@ fn walkInstruction( src_info, &decl_indexes, &priv_decl_indexes, + call_ctx, ); // Analyze the tag once all decls have been analyzed @@ -2862,6 +3147,7 @@ fn walkInstruction( parent_src, tt_ref, false, + call_ctx, )).expr else null; // Fields @@ -2883,6 +3169,7 @@ fn walkInstruction( &field_type_refs, &field_name_indexes, extra_index, + call_ctx, ); self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; @@ -2948,7 +3235,14 @@ fn walkInstruction( const tag_type = file.zir.extra[extra_index]; extra_index += 1; const tag_ref = @as(Ref, @enumFromInt(tag_type)); - const wr = try self.walkRef(file, parent_scope, parent_src, tag_ref, false); + const wr = try self.walkRef( + file, + parent_scope, + parent_src, + tag_ref, + false, + call_ctx, + ); break :blk wr.expr; } else null; @@ -2974,6 +3268,7 @@ fn walkInstruction( src_info, &decl_indexes, &priv_decl_indexes, + call_ctx, ); // const body = file.zir.extra[extra_index..][0..body_len]; @@ -3005,7 +3300,14 @@ fn walkInstruction( const value_expr: ?DocData.Expr = if (has_value) blk: { const value_ref = file.zir.extra[extra_index]; extra_index += 1; - const value = try self.walkRef(file, &scope, src_info, @as(Ref, @enumFromInt(value_ref)), false); + const value = try self.walkRef( + file, + &scope, + src_info, + @as(Ref, @enumFromInt(value_ref)), + false, + call_ctx, + ); break :blk value.expr; } else null; try field_values.append(self.arena, value_expr); @@ -3095,14 +3397,28 @@ fn walkInstruction( extra_index += 1; // backing_int_body_len if (backing_int_body_len == 0) { const backing_int_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index])); - const backing_int_res = try self.walkRef(file, &scope, src_info, backing_int_ref, true); + const backing_int_res = try self.walkRef( + file, + &scope, + src_info, + backing_int_ref, + true, + call_ctx, + ); backing_int = backing_int_res.expr; extra_index += 1; // backing_int_ref } else { const backing_int_body = file.zir.extra[extra_index..][0..backing_int_body_len]; const break_inst = backing_int_body[backing_int_body.len - 1]; const operand = data[break_inst].@"break".operand; - const backing_int_res = try self.walkRef(file, &scope, src_info, operand, true); + const backing_int_res = try self.walkRef( + file, + &scope, + src_info, + operand, + true, + call_ctx, + ); backing_int = backing_int_res.expr; extra_index += backing_int_body_len; // backing_int_body_inst } @@ -3123,6 +3439,7 @@ fn walkInstruction( src_info, &decl_indexes, &priv_decl_indexes, + call_ctx, ); var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{}; @@ -3138,6 +3455,7 @@ fn walkInstruction( &field_name_indexes, extra_index, small.is_tuple, + call_ctx, ); self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items; @@ -3194,7 +3512,14 @@ fn walkInstruction( const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data; const bin_index = self.exprs.items.len; try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } }); - const param = try self.walkRef(file, parent_scope, parent_src, extra.operand, false); + const param = try self.walkRef( + file, + parent_scope, + parent_src, + extra.operand, + false, + call_ctx, + ); const param_index = self.exprs.items.len; try self.exprs.append(self.arena, param.expr); @@ -3213,7 +3538,14 @@ fn walkInstruction( const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data; const bin_index = self.exprs.items.len; try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } }); - const param = try self.walkRef(file, parent_scope, parent_src, extra.operand, false); + const param = try self.walkRef( + file, + parent_scope, + parent_src, + extra.operand, + false, + call_ctx, + ); const param_index = self.exprs.items.len; try self.exprs.append(self.arena, param.expr); @@ -3241,6 +3573,7 @@ fn walkInstruction( parent_src, extra.ptr, false, + call_ctx, ); try self.exprs.append(self.arena, ptr.expr); @@ -3251,6 +3584,7 @@ fn walkInstruction( parent_src, extra.expected_value, false, + call_ctx, ); try self.exprs.append(self.arena, expected_value.expr); @@ -3261,6 +3595,7 @@ fn walkInstruction( parent_src, extra.new_value, false, + call_ctx, ); try self.exprs.append(self.arena, new_value.expr); @@ -3271,6 +3606,7 @@ fn walkInstruction( parent_src, extra.success_order, false, + call_ctx, ); try self.exprs.append(self.arena, success_order.expr); @@ -3281,6 +3617,7 @@ fn walkInstruction( parent_src, extra.failure_order, false, + call_ctx, ); try self.exprs.append(self.arena, failure_order.expr); @@ -3319,6 +3656,7 @@ fn analyzeAllDecls( parent_src: SrcLocInfo, decl_indexes: *std.ArrayListUnmanaged(usize), priv_decl_indexes: *std.ArrayListUnmanaged(usize), + call_ctx: ?*const CallContext, ) AutodocErrors!usize { const first_decl_indexes_slot = decl_indexes.items.len; const original_it = file.zir.declIterator(@as(u32, @intCast(parent_inst_index))); @@ -3358,6 +3696,7 @@ fn analyzeAllDecls( decl_indexes, priv_decl_indexes, d, + call_ctx, ); }, } @@ -3387,6 +3726,7 @@ fn analyzeAllDecls( decl_indexes, priv_decl_indexes, d, + call_ctx, ); } @@ -3420,6 +3760,7 @@ fn analyzeDecl( decl_indexes: *std.ArrayListUnmanaged(usize), priv_decl_indexes: *std.ArrayListUnmanaged(usize), d: Zir.DeclIterator.Item, + call_ctx: ?*const CallContext, ) AutodocErrors!void { const data = file.zir.instructions.items(.data); const is_pub = @as(u1, @truncate(d.flags >> 0)) != 0; @@ -3497,7 +3838,14 @@ fn analyzeDecl( break :idx idx; }; - const walk_result = try self.walkInstruction(file, scope, decl_src, value_index, true); + const walk_result = try self.walkInstruction( + file, + scope, + decl_src, + value_index, + true, + call_ctx, + ); const kind: []const u8 = if (try self.declIsVar(file, value_pl_node.src_node, parent_src)) "var" else "const"; @@ -3545,6 +3893,7 @@ fn analyzeUsingnamespaceDecl( decl_indexes: *std.ArrayListUnmanaged(usize), priv_decl_indexes: *std.ArrayListUnmanaged(usize), d: Zir.DeclIterator.Item, + call_ctx: ?*const CallContext, ) AutodocErrors!void { const data = file.zir.instructions.items(.data); @@ -3574,7 +3923,14 @@ fn analyzeUsingnamespaceDecl( break :idx idx; }; - const walk_result = try self.walkInstruction(file, scope, decl_src, value_index, true); + const walk_result = try self.walkInstruction( + file, + scope, + decl_src, + value_index, + true, + call_ctx, + ); const decl_slot_index = self.decls.items.len; try self.decls.append(self.arena, .{ @@ -4192,6 +4548,7 @@ fn analyzeFancyFunction( inst_index: usize, self_ast_node_index: usize, type_slot_index: usize, + call_ctx: ?*const CallContext, ) AutodocErrors!DocData.WalkResult { const tags = file.zir.instructions.items(.tag); const data = file.zir.instructions.items(.data); @@ -4253,7 +4610,14 @@ fn analyzeFancyFunction( const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1]; const break_operand = data[break_index].@"break".operand; - const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false); + const param_type_ref = try self.walkRef( + file, + scope, + parent_src, + break_operand, + false, + call_ctx, + ); param_type_refs.appendAssumeCapacity(param_type_ref.expr); }, @@ -4277,7 +4641,14 @@ fn analyzeFancyFunction( if (extra.data.bits.has_align_ref) { const align_ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); align_index = self.exprs.items.len; - _ = try self.walkRef(file, scope, parent_src, align_ref, false); + _ = try self.walkRef( + file, + scope, + parent_src, + align_ref, + false, + call_ctx, + ); extra_index += 1; } else if (extra.data.bits.has_align_body) { const align_body_len = file.zir.extra[extra_index]; @@ -4294,7 +4665,14 @@ fn analyzeFancyFunction( if (extra.data.bits.has_addrspace_ref) { const addrspace_ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); addrspace_index = self.exprs.items.len; - _ = try self.walkRef(file, scope, parent_src, addrspace_ref, false); + _ = try self.walkRef( + file, + scope, + parent_src, + addrspace_ref, + false, + call_ctx, + ); extra_index += 1; } else if (extra.data.bits.has_addrspace_body) { const addrspace_body_len = file.zir.extra[extra_index]; @@ -4311,7 +4689,14 @@ fn analyzeFancyFunction( if (extra.data.bits.has_section_ref) { const section_ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); section_index = self.exprs.items.len; - _ = try self.walkRef(file, scope, parent_src, section_ref, false); + _ = try self.walkRef( + file, + scope, + parent_src, + section_ref, + false, + call_ctx, + ); extra_index += 1; } else if (extra.data.bits.has_section_body) { const section_body_len = file.zir.extra[extra_index]; @@ -4327,7 +4712,14 @@ fn analyzeFancyFunction( var cc_index: ?usize = null; if (extra.data.bits.has_cc_ref and !extra.data.bits.has_cc_body) { const cc_ref = @as(Zir.Inst.Ref, @enumFromInt(file.zir.extra[extra_index])); - const cc_expr = try self.walkRef(file, scope, parent_src, cc_ref, false); + const cc_expr = try self.walkRef( + file, + scope, + parent_src, + cc_ref, + false, + call_ctx, + ); cc_index = self.exprs.items.len; try self.exprs.append(self.arena, cc_expr.expr); @@ -4341,7 +4733,14 @@ fn analyzeFancyFunction( // We assume the body ends with a break_inline const break_index = cc_body[cc_body.len - 1]; const break_operand = data[break_index].@"break".operand; - const cc_expr = try self.walkRef(file, scope, parent_src, break_operand, false); + const cc_expr = try self.walkRef( + file, + scope, + parent_src, + break_operand, + false, + call_ctx, + ); cc_index = self.exprs.items.len; try self.exprs.append(self.arena, cc_expr.expr); @@ -4357,14 +4756,28 @@ fn analyzeFancyFunction( .none => DocData.Expr{ .void = .{} }, else => blk: { const ref = fn_info.ret_ty_ref; - const wr = try self.walkRef(file, scope, parent_src, ref, false); + const wr = try self.walkRef( + file, + scope, + parent_src, + ref, + false, + call_ctx, + ); break :blk wr.expr; }, }, else => blk: { const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; const break_operand = data[last_instr_index].@"break".operand; - const wr = try self.walkRef(file, scope, parent_src, break_operand, false); + const wr = try self.walkRef( + file, + scope, + parent_src, + break_operand, + false, + call_ctx, + ); break :blk wr.expr; }, }; @@ -4381,6 +4794,7 @@ fn analyzeFancyFunction( scope, parent_src, fn_info.body[0], + call_ctx, ); } else { break :blk null; @@ -4426,6 +4840,7 @@ fn analyzeFunction( self_ast_node_index: usize, type_slot_index: usize, ret_is_inferred_error_set: bool, + call_ctx: ?*const CallContext, ) AutodocErrors!DocData.WalkResult { const tags = file.zir.instructions.items(.tag); const data = file.zir.instructions.items(.data); @@ -4487,7 +4902,14 @@ fn analyzeFunction( const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1]; const break_operand = data[break_index].@"break".operand; - const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false); + const param_type_ref = try self.walkRef( + file, + scope, + parent_src, + break_operand, + false, + call_ctx, + ); param_type_refs.appendAssumeCapacity(param_type_ref.expr); }, @@ -4500,14 +4922,28 @@ fn analyzeFunction( .none => DocData.Expr{ .void = .{} }, else => blk: { const ref = fn_info.ret_ty_ref; - const wr = try self.walkRef(file, scope, parent_src, ref, false); + const wr = try self.walkRef( + file, + scope, + parent_src, + ref, + false, + call_ctx, + ); break :blk wr.expr; }, }, else => blk: { const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; const break_operand = data[last_instr_index].@"break".operand; - const wr = try self.walkRef(file, scope, parent_src, break_operand, false); + const wr = try self.walkRef( + file, + scope, + parent_src, + break_operand, + false, + call_ctx, + ); break :blk wr.expr; }, }; @@ -4524,6 +4960,7 @@ fn analyzeFunction( scope, parent_src, fn_info.body[0], + call_ctx, ); } else { break :blk null; @@ -4570,6 +5007,7 @@ fn getGenericReturnType( scope: *Scope, parent_src: SrcLocInfo, // function decl line body_main_block: usize, + call_ctx: ?*const CallContext, ) !DocData.Expr { const tags = file.zir.instructions.items(.tag); const data = file.zir.instructions.items(.data); @@ -4581,7 +5019,14 @@ fn getGenericReturnType( const maybe_ret_node = file.zir.extra[extra.end..][extra.data.body_len - 4]; switch (tags[maybe_ret_node]) { .ret_node, .ret_load => { - const wr = try self.walkInstruction(file, scope, parent_src, maybe_ret_node, false); + const wr = try self.walkInstruction( + file, + scope, + parent_src, + maybe_ret_node, + false, + call_ctx, + ); return wr.expr; }, else => { @@ -4599,6 +5044,7 @@ fn collectUnionFieldInfo( field_type_refs: *std.ArrayListUnmanaged(DocData.Expr), field_name_indexes: *std.ArrayListUnmanaged(usize), ei: usize, + call_ctx: ?*const CallContext, ) !void { if (fields_len == 0) return; var extra_index = ei; @@ -4641,7 +5087,14 @@ fn collectUnionFieldInfo( // type { - const walk_result = try self.walkRef(file, scope, parent_src, field_type, false); + const walk_result = try self.walkRef( + file, + scope, + parent_src, + field_type, + false, + call_ctx, + ); try field_type_refs.append(self.arena, walk_result.expr); } @@ -4671,6 +5124,7 @@ fn collectStructFieldInfo( field_name_indexes: *std.ArrayListUnmanaged(usize), ei: usize, is_tuple: bool, + call_ctx: ?*const CallContext, ) !void { if (fields_len == 0) return; var extra_index = ei; @@ -4744,7 +5198,14 @@ fn collectStructFieldInfo( for (fields) |field| { const type_expr = expr: { if (field.type_ref != .none) { - const walk_result = try self.walkRef(file, scope, parent_src, field.type_ref, false); + const walk_result = try self.walkRef( + file, + scope, + parent_src, + field.type_ref, + false, + call_ctx, + ); break :expr walk_result.expr; } @@ -4760,7 +5221,14 @@ fn collectStructFieldInfo( .col = 0, .fields = null, // walkInstruction will fill `fields` if necessary }); - const walk_result = try self.walkRef(file, scope, parent_src, operand, false); + const walk_result = try self.walkRef( + file, + scope, + parent_src, + operand, + false, + call_ctx, + ); break :expr walk_result.expr; }; @@ -4776,7 +5244,14 @@ fn collectStructFieldInfo( const break_inst = body[body.len - 1]; const operand = data[break_inst].@"break".operand; - const walk_result = try self.walkRef(file, scope, parent_src, operand, false); + const walk_result = try self.walkRef( + file, + scope, + parent_src, + operand, + false, + call_ctx, + ); break :def walk_result.expr; }; @@ -4812,6 +5287,7 @@ fn walkRef( parent_src: SrcLocInfo, ref: Ref, need_type: bool, // true when the caller needs also a typeRef for the return value + call_ctx: ?*const CallContext, ) AutodocErrors!DocData.WalkResult { if (ref == .none) { return .{ .expr = .{ .comptimeExpr = 0 } }; @@ -4824,7 +5300,14 @@ fn walkRef( .expr = .{ .type = @intFromEnum(ref) }, }; } else if (Zir.refToIndex(ref)) |zir_index| { - return self.walkInstruction(file, parent_scope, parent_src, zir_index, need_type); + return self.walkInstruction( + file, + parent_scope, + parent_src, + zir_index, + need_type, + call_ctx, + ); } else { switch (ref) { else => {