From fbf0d0bee9c37c24b0b54962eaf05a535e814bc9 Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Tue, 22 Feb 2022 20:15:39 +0100 Subject: [PATCH] autodoc: fix decltest offset errors while it would be preferable to not save decltests as first-class decls (and just embed their information inside the decl they refer), adding logic to skip them complicates the code too much so we should consider this an optimization for the future. --- src/Autodoc.zig | 124 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 48abcb8bca..a3a2961f07 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -65,7 +65,11 @@ pub fn generateZirData(self: *Autodoc) !void { // @tagName(t), //}); break :blk .{ - .Array = .{ .name = tmpbuf.toOwnedSlice() }, + .Array = .{ + .len = 1, + .name = tmpbuf.toOwnedSlice(), + .child = .{ .type = 0 }, + }, }; }, .u1_type, @@ -248,7 +252,7 @@ const DocData = struct { const Decl = struct { name: []const u8, - kind: []const u8, // TODO: where do we find this info? + kind: []const u8, src: usize, // index into astNodes // typeRef: TypeRef, value: WalkResult, @@ -272,8 +276,15 @@ const DocData = struct { NoReturn: struct { name: []const u8 }, Int: struct { name: []const u8 }, Float: struct { name: []const u8 }, - Pointer: struct { name: []const u8 }, - Array: struct { name: []const u8 }, + Pointer: struct { + name: []const u8, + child: TypeRef, + }, + Array: struct { + name: []const u8, + len: usize, + child: TypeRef, + }, Struct: struct { name: []const u8, src: ?usize = null, // index into astNodes @@ -286,7 +297,10 @@ const DocData = struct { ComptimeInt: struct { name: []const u8 }, Undefined: struct { name: []const u8 }, Null: struct { name: []const u8 }, - Optional: struct { name: []const u8 }, + Optional: struct { + name: []const u8, + child: TypeRef, + }, ErrorUnion: struct { name: []const u8 }, ErrorSet: struct { name: []const u8 }, Enum: struct { @@ -335,6 +349,7 @@ const DocData = struct { .ComptimeInt => |v| try printTypeBody(v, options, w), .ComptimeFloat => |v| try printTypeBody(v, options, w), .Null => |v| try printTypeBody(v, options, w), + .Optional => |v| try printTypeBody(v, options, w), .Struct => |v| try printTypeBody(v, options, w), .Fn => |v| try printTypeBody(v, options, w), @@ -376,13 +391,13 @@ const DocData = struct { const TypeRef = union(enum) { unspecified, - declRef: usize, // index in `decls` + declPath: []usize, // indexes in `decls` type: usize, // index in `types` comptimeExpr: usize, // index in `comptimeExprs` pub fn fromWalkResult(wr: WalkResult) TypeRef { return switch (wr) { - .declRef => |v| .{ .declRef = v }, + .declPath => |v| .{ .declPath = v }, .type => |v| .{ .type = v }, else => @panic("Found non-type WalkResult"), }; @@ -400,11 +415,18 @@ const DocData = struct { , .{}); }, - .declRef, .type, .comptimeExpr => |v| { + .type, .comptimeExpr => |v| { try w.print( \\{{ "{s}":{} }} , .{ @tagName(self), v }); }, + .declPath => |v| { + try w.print("{{ \"declPath\": [", .{}); + for (v) |d, i| { + const comma = if (i == v.len - 1) "]}" else ","; + try w.print("{d}{s}", .{ d, comma }); + } + }, } } }; @@ -415,16 +437,10 @@ const DocData = struct { @"unreachable", @"null": TypeRef, @"undefined": TypeRef, - @"struct": struct { - typeRef: TypeRef, - fieldVals: []struct { - name: []const u8, - val: WalkResult, - }, - }, + @"struct": Struct, bool: bool, type: usize, // index in `types` - declRef: usize, // index in `decls` + declPath: []usize, // indices in `decls` int: struct { typeRef: TypeRef, value: usize, // direct value @@ -435,6 +451,14 @@ const DocData = struct { value: f64, // direct value negated: bool = false, }, + + const Struct = struct { + typeRef: TypeRef, + fieldVals: []struct { + name: []const u8, + val: WalkResult, + }, + }; pub fn jsonStringify( self: WalkResult, options: std.json.StringifyOptions, @@ -446,7 +470,7 @@ const DocData = struct { \\{{ "{s}":{{}} }} , .{@tagName(self)}); }, - .type, .declRef, .comptimeExpr => |v| { + .type, .comptimeExpr => |v| { try w.print( \\{{ "{s}":{} }} , .{ @tagName(self), v }); @@ -478,12 +502,18 @@ const DocData = struct { }, .@"undefined" => |v| try std.json.stringify(v, options, w), .@"null" => |v| try std.json.stringify(v, options, w), - .@"struct" => |v| try std.json.stringify(v, options, w), - // .decl_ref => |v| { - // try w.print( - // \\{{ "{s}":"{s}" }} - // , .{ @tagName(self), v }); - // }, + .@"struct" => |v| try std.json.stringify( + struct { @"struct": Struct }{ .@"struct" = v }, + options, + w, + ), + .declPath => |v| { + try w.print("{{ \"declPath\": [", .{}); + for (v) |d, i| { + const comma = if (i == v.len - 1) "]}" else ","; + try w.print("{d}{s}", .{ d, comma }); + } + }, } } }; @@ -571,13 +601,15 @@ fn walkInstruction( "TODO: handle {s} in `walkInstruction.as_node`\n", .{@tagName(operand)}, ), - .declRef => {}, + .declPath, .type => {}, // we don't do anything because up until now, // I've only seen this used as such: // @as(@as(type, Baz), .{}) // and we don't want to toss away the // decl_val information (eg by replacing it with // a WalkResult.type). + // TODO: Actually, this is a good moment to check if + // the result is indeed a type!! .comptimeExpr => { self.comptimeExprs.items[operand.comptimeExpr].typeRef = dest_type_ref; }, @@ -588,11 +620,39 @@ fn walkInstruction( return operand; }, + .optional_type => { + const un_node = data[inst_index].un_node; + var operand: DocData.WalkResult = try self.walkRef( + file, + parent_scope, + un_node.operand, + ); + const type_ref = walkResultToTypeRef(operand); + const res = DocData.WalkResult{ .type = self.types.items.len }; + try self.types.append(self.arena, .{ + .Optional = .{ .name = "?TODO", .child = type_ref }, + }); + return res; + }, .decl_val => { const str_tok = data[inst_index].str_tok; const decls_slot_index = parent_scope.resolveDeclName(str_tok.start); - return DocData.WalkResult{ .declRef = decls_slot_index }; + var path = try self.arena.alloc(usize, 1); + path[0] = decls_slot_index; + return DocData.WalkResult{ .declPath = path }; }, + //.field_val => { + // const pl_node = data[inst_index].pl_node; + // const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index); + // // In case that we have a path (eg Foo.Bar.Baz.X.Y.Z), + // // then we want to deal with them in a while loop instead + // // of using `walkRef()`. + // + // var path = try self.arena.alloc(usize, 1); + // path[0] = decls_slot_index; + // return DocData.WalkResult{ .declPath = path }; + + //}, .int_type => { const int_type = data[inst_index].int_type; const sign = if (int_type.signedness == .unsigned) "u" else "i"; @@ -945,17 +1005,13 @@ fn walkInstruction( // Done to make sure that all decl refs can be resolved correctly, // even if we haven't fully analyzed the decl yet. { - var actual_decls_len: usize = 0; var it = file.zir.declIterator(@intCast(u32, inst_index)); + try self.decls.resize(self.arena, decls_first_index + it.decls_len); var decls_slot_index = decls_first_index; while (it.next()) |d| : (decls_slot_index += 1) { const decl_name_index = file.zir.extra[d.sub_index + 5]; - if (decl_name_index == 2) continue; // we don't do decltests here - actual_decls_len += 1; try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index); } - // we don't count decltests in our decls - try self.decls.resize(self.arena, decls_first_index + actual_decls_len); } extra_index = try self.walkDecls( @@ -1144,6 +1200,12 @@ fn walkDecls( break :idx idx; }; self.decls.items[decl_being_tested].decltest = ast_node_index; + self.decls.items[decls_slot_index] = .{ + .name = "test", + .src = ast_node_index, + .value = .{ .type = 0 }, + .kind = "const", + }; continue; } else { const raw_decl_name = file.zir.nullTerminatedString(decl_name_index); @@ -1450,7 +1512,7 @@ fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef { .{@tagName(wr)}, ), - .declRef => |v| .{ .declRef = v }, + .declPath => |v| .{ .declPath = v }, .type => |v| .{ .type = v }, }; }