authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-22 17:10:45-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-22 17:10:45-05:00
log42438ce8b226d9c7421ef4a73414a32fcc6e6264
tree1e23f666d5403c9631aeaedbfd521555b4629815
parent0dcba03b67af0aee612b51191a8110d91a55019e
parent9e925a7acce05a69a26fe186acffb47dca326a11
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22929 from schtvn/type_fn_docs_improvements

Autodoc: Improve documentation for common types declared as type functions

2 files changed, 109 insertions(+), 4 deletions(-)

lib/docs/wasm/Decl.zig+71
...@@ -130,6 +130,77 @@ pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {...@@ -130,6 +130,77 @@ pub fn get_child(decl: *const Decl, name: []const u8) ?Decl.Index {
130 const child_node = scope.get_child(name) orelse return null;130 const child_node = scope.get_child(name) orelse return null;
131 return file.node_decls.get(child_node);131 return file.node_decls.get(child_node);
132 },132 },
133 .type_function => {
134 // Find a decl with this function as the parent, with a name matching `name`
135 for (Walk.decls.items, 0..) |*candidate, i| {
136 if (candidate.parent != .none and candidate.parent.get() == decl and std.mem.eql(u8, candidate.extra_info().name, name)) {
137 return @enumFromInt(i);
138 }
139 }
140
141 return null;
142 },
143 else => return null,
144 }
145}
146
147/// If the type function returns another type function, return the index of that type function.
148pub fn get_type_fn_return_type_fn(decl: *const Decl) ?Decl.Index {
149 if (decl.get_type_fn_return_expr()) |return_expr| {
150 const ast = decl.file.get_ast();
151 const node_tags = ast.nodes.items(.tag);
152
153 switch (node_tags[return_expr]) {
154 .call, .call_comma, .call_one, .call_one_comma => {
155 const node_data = ast.nodes.items(.data);
156 const function = node_data[return_expr].lhs;
157 const token = ast.nodes.items(.main_token)[function];
158 const name = ast.tokenSlice(token);
159 if (decl.lookup(name)) |function_decl| {
160 return function_decl;
161 }
162 },
163 else => {},
164 }
165 }
166 return null;
167}
168
169/// Gets the expression after the `return` keyword in a type function declaration.
170pub fn get_type_fn_return_expr(decl: *const Decl) ?Ast.Node.Index {
171 switch (decl.categorize()) {
172 .type_function => {
173 const ast = decl.file.get_ast();
174 const node_tags = ast.nodes.items(.tag);
175 const node_data = ast.nodes.items(.data);
176 const body_node = node_data[decl.ast_node].rhs;
177 if (body_node == 0) return null;
178
179 switch (node_tags[body_node]) {
180 .block, .block_semicolon => {
181 const statements = ast.extra_data[node_data[body_node].lhs..node_data[body_node].rhs];
182 // Look for the return statement
183 for (statements) |stmt| {
184 if (node_tags[stmt] == .@"return") {
185 return node_data[stmt].lhs;
186 }
187 }
188 return null;
189 },
190 .block_two, .block_two_semicolon => {
191 if (node_tags[node_data[body_node].lhs] == .@"return") {
192 return node_data[node_data[body_node].lhs].lhs;
193 }
194 if (node_data[body_node].rhs != 0 and
195 node_tags[node_data[body_node].rhs] == .@"return")
196 {
197 return node_data[node_data[body_node].rhs].lhs;
198 }
199 return null;
200 },
201 else => return null,
202 }
203 },
133 else => return null,204 else => return null,
134 }205 }
135}206}
lib/docs/wasm/main.zig+38-4
...@@ -386,16 +386,43 @@ export fn decl_params(decl_index: Decl.Index) Slice(Ast.Node.Index) {...@@ -386,16 +386,43 @@ export fn decl_params(decl_index: Decl.Index) Slice(Ast.Node.Index) {
386}386}
387387
388fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {388fn decl_fields_fallible(decl_index: Decl.Index) ![]Ast.Node.Index {
389 const decl = decl_index.get();
390 const ast = decl.file.get_ast();
391
392 switch (decl.categorize()) {
393 .type_function => {
394 const node_tags = ast.nodes.items(.tag);
395
396 // If the type function returns a reference to another type function, get the fields from there
397 if (decl.get_type_fn_return_type_fn()) |function_decl| {
398 return decl_fields_fallible(function_decl);
399 }
400 // If the type function returns a container, such as a `struct`, read that container's fields
401 if (decl.get_type_fn_return_expr()) |return_expr| {
402 switch (node_tags[return_expr]) {
403 .container_decl, .container_decl_trailing, .container_decl_two, .container_decl_two_trailing, .container_decl_arg, .container_decl_arg_trailing => {
404 return ast_decl_fields_fallible(ast, return_expr);
405 },
406 else => {},
407 }
408 }
409 return &.{};
410 },
411 else => {
412 const value_node = decl.value_node() orelse return &.{};
413 return ast_decl_fields_fallible(ast, value_node);
414 },
415 }
416}
417
418fn ast_decl_fields_fallible(ast: *Ast, ast_index: Ast.Node.Index) ![]Ast.Node.Index {
389 const g = struct {419 const g = struct {
390 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;420 var result: std.ArrayListUnmanaged(Ast.Node.Index) = .empty;
391 };421 };
392 g.result.clearRetainingCapacity();422 g.result.clearRetainingCapacity();
393 const decl = decl_index.get();
394 const ast = decl.file.get_ast();
395 const node_tags = ast.nodes.items(.tag);423 const node_tags = ast.nodes.items(.tag);
396 const value_node = decl.value_node() orelse return &.{};
397 var buf: [2]Ast.Node.Index = undefined;424 var buf: [2]Ast.Node.Index = undefined;
398 const container_decl = ast.fullContainerDecl(&buf, value_node) orelse return &.{};425 const container_decl = ast.fullContainerDecl(&buf, ast_index) orelse return &.{};
399 for (container_decl.ast.members) |member_node| switch (node_tags[member_node]) {426 for (container_decl.ast.members) |member_node| switch (node_tags[member_node]) {
400 .container_field_init,427 .container_field_init,
401 .container_field_align,428 .container_field_align,
...@@ -880,6 +907,13 @@ export fn categorize_decl(decl_index: Decl.Index, resolve_alias_count: usize) Wa...@@ -880,6 +907,13 @@ export fn categorize_decl(decl_index: Decl.Index, resolve_alias_count: usize) Wa
880}907}
881908
882export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {909export fn type_fn_members(parent: Decl.Index, include_private: bool) Slice(Decl.Index) {
910 const decl = parent.get();
911
912 // If the type function returns another type function, get the members of that function
913 if (decl.get_type_fn_return_type_fn()) |function_decl| {
914 return namespace_members(function_decl, include_private);
915 }
916
883 return namespace_members(parent, include_private);917 return namespace_members(parent, include_private);
884}918}
885919