autodoc: Some support for field_call (#16853)

* autodoc: Some support for field_call

* autodoc: Change handling of field_call to respect tryResolveRefPath, add fieldVal to Expr

* autodoc: Fixed errors

* autodoc: sync with latest master changes

---------

Co-authored-by: Loris Cro <kappaloris@gmail.com>
This commit is contained in:
Krzysztof Wolicki 2023-10-30 22:04:49 +01:00 committed by GitHub
parent f52a228a5d
commit 1880c799ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 7 deletions

View File

@ -1573,7 +1573,8 @@ Happy writing!
for (let i = 0; i < expr.struct.length; i++) {
const fv = expr.struct[i];
const field_name = fv.name;
const field_value = ex(fv.val.expr, opts);
const field_expr = zigAnalysis.exprs[fv.val.expr];
const field_value = ex(field_expr, opts);
yield Tok.period;
yield { src: field_name, tag: Tag.identifier };
yield Tok.space;
@ -1628,7 +1629,13 @@ Happy writing!
} else {
yield* ex(param, opts);
}
return;
}
case "fieldVal": {
const fv = expr.fieldVal;
const field_name = fv.name;
yield { src: field_name, tag: Tag.identifier };
return;
}

View File

@ -741,6 +741,7 @@ const DocData = struct {
null: struct {},
undefined: struct {},
@"struct": []FieldVal,
fieldVal: FieldVal,
bool: bool,
@"anytype": struct {},
@"&": usize, // index in `exprs`
@ -867,7 +868,10 @@ const DocData = struct {
const FieldVal = struct {
name: []const u8,
val: WalkResult,
val: struct {
typeRef: ?usize, // index in `exprs`
expr: usize, // index in `exprs`
},
};
const ElemVal = struct {
@ -921,8 +925,8 @@ const DocData = struct {
/// Since the type information is only needed in certain contexts, the
/// underlying normalized data (Expr) is untyped.
const WalkResult = struct {
typeRef: ?Expr = null, // index in `exprs`
expr: Expr, // index in `exprs`
typeRef: ?Expr = null,
expr: Expr,
};
};
@ -2874,7 +2878,20 @@ fn walkInstruction(
need_type,
call_ctx,
);
fv.* = .{ .name = field_name, .val = value };
const exprIdx = self.exprs.items.len;
try self.exprs.append(self.arena, value.expr);
var typeRefIdx: ?usize = null;
if (value.typeRef) |ref| {
typeRefIdx = self.exprs.items.len;
try self.exprs.append(self.arena, ref);
}
fv.* = .{
.name = field_name,
.val = .{
.typeRef = typeRefIdx,
.expr = exprIdx,
},
};
}
return DocData.WalkResult{
@ -2942,7 +2959,23 @@ fn walkInstruction(
need_type,
call_ctx,
);
fv.* = .{ .name = field_name, .val = value };
const exprIdx = self.exprs.items.len;
try self.exprs.append(self.arena, value.expr);
var typeRefIdx: ?usize = null;
if (value.typeRef) |ref| {
typeRefIdx = self.exprs.items.len;
try self.exprs.append(self.arena, ref);
}
fv.* = .{
.name = field_name,
.val = .{
.typeRef = typeRefIdx,
.expr = exprIdx,
},
};
idx = init_extra.end;
}
@ -3085,6 +3118,75 @@ fn walkInstruction(
.expr = .{ .call = call_slot_index },
};
},
.field_call => {
const pl_node = data[@intFromEnum(inst)].pl_node;
const extra = file.zir.extraData(Zir.Inst.FieldCall, pl_node.payload_index);
const obj_ptr = try self.walkRef(
file,
parent_scope,
parent_src,
extra.data.obj_ptr,
need_type,
call_ctx,
);
var field_call = try self.arena.alloc(DocData.Expr, 2);
if (obj_ptr.typeRef) |ref| {
field_call[0] = ref;
} else {
field_call[0] = obj_ptr.expr;
}
field_call[1] = .{ .declName = file.zir.nullTerminatedString(extra.data.field_name_start) };
try self.tryResolveRefPath(file, inst, field_call);
const args_len = extra.data.flags.args_len;
var args = try self.arena.alloc(DocData.Expr, args_len);
const body = file.zir.extra[extra.end..];
try self.repurposed_insts.put(self.arena, inst, {});
defer _ = self.repurposed_insts.remove(inst);
var i: usize = 0;
while (i < args_len) : (i += 1) {
const arg_end = file.zir.extra[extra.end + i];
const break_index = body[arg_end - 1];
const ref = data[break_index].@"break".operand;
// TODO: consider toggling need_type to true if we ever want
// 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,
&.{
.inst = inst,
.prev = call_ctx,
},
);
args[i] = wr.expr;
}
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = "field call",
});
const call_slot_index = self.calls.items.len;
try self.calls.append(self.arena, .{
.func = .{ .refPath = field_call },
.args = args,
.ret = .{ .comptimeExpr = cte_slot_index },
});
return DocData.WalkResult{
.expr = .{ .call = call_slot_index },
};
},
.func, .func_inferred => {
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{ .Unanalyzed = .{} });
@ -4374,6 +4476,9 @@ fn tryResolveRefPath(
},
}
},
.fieldVal => |fv| {
resolved_parent = self.exprs.items[fv.val.expr];
},
}
} else {
panicWithContext(
@ -4675,7 +4780,7 @@ fn tryResolveRefPath(
.@"struct" => |st| {
for (st) |field| {
if (std.mem.eql(u8, field.name, child_string)) {
path[i + 1] = field.val.expr;
path[i + 1] = .{ .fieldVal = field };
continue :outer;
}
}