Commit a55db08a7b

Andrew Kelley <andrew@ziglang.org>
2019-10-08 05:53:17
generated docs contain generic instantiations and comptime calls
1 parent ffc0c26
lib/std/special/docs/index.html
@@ -210,6 +210,10 @@
     </div>
     <h1 id="hdrName" class="hidden"></h1>
     <div id="fnDocs" class="hidden"></div>
+    <div id="fnExamples" class="hidden"></div>
+    <div id="fnNoExamples" class="hidden">
+      <p>This function is not tested or referenced.</p>
+    </div>
     <div id="sectSearchResults" class="hidden">
       <h2>Search Results</h2>
       <ul id="listSearchResults"></ul>
lib/std/special/docs/main.js
@@ -11,6 +11,8 @@
     var domFnProto = document.getElementById("fnProto");
     var domFnProtoCode = document.getElementById("fnProtoCode");
     var domFnDocs = document.getElementById("fnDocs");
+    var domFnExamples = document.getElementById("fnExamples");
+    var domFnNoExamples = document.getElementById("fnNoExamples");
     var domSearch = document.getElementById("search");
     var domSectSearchResults = document.getElementById("sectSearchResults");
     var domListSearchResults = document.getElementById("listSearchResults");
@@ -50,6 +52,12 @@
 
     var rootIsStd = detectRootIsStd();
     var typeTypeId = findTypeTypeId();
+
+    // map of decl index to list of non-generic fn indexes
+    var nodesToFnsMap = indexNodesToFns();
+    // map of decl index to list of comptime fn calls
+    var nodesToCallsMap = indexNodesToCalls();
+
     domSearch.addEventListener('keydown', onSearchKeyDown, false);
     window.addEventListener('hashchange', onHashChange, false);
     window.addEventListener('keydown', onWindowKeyDown, false);
@@ -81,6 +89,8 @@
         domSectInfo.classList.add("hidden");
         domHdrName.classList.add("hidden");
         domSectNav.classList.add("hidden");
+        domFnExamples.classList.add("hidden");
+        domFnNoExamples.classList.add("hidden");
 
         renderTitle();
         renderInfo();
@@ -138,16 +148,51 @@
         }
     }
 
+    function typeIsGenericFn(typeIndex) {
+        var typeObj = zigAnalysis.types[typeIndex];
+        if (typeObj.kind !== typeKindFnId) {
+            return false;
+        }
+        return typeObj.generic;
+    }
+
     function renderFn(fnDecl) {
         var typeObj = zigAnalysis.types[fnDecl.type];
         domFnProtoCode.textContent = "fn " + fnDecl.name + typeObj.name.substring(2);
 
+        var docsSource = null;
         var srcNode = zigAnalysis.astNodes[fnDecl.src];
         if (srcNode.docs != null) {
-            domFnDocs.innerHTML = markdown(srcNode.docs);
-            domFnDocs.classList.remove("hidden");
+            docsSource = srcNode.docs;
+        }
+
+        var protoSrcIndex;
+        if (typeIsGenericFn(fnDecl.type)) {
+            protoSrcIndex = fnDecl.value;
+
+            var instantiations = nodesToFnsMap[protoSrcIndex];
+            var calls = nodesToCallsMap[protoSrcIndex];
+            if (instantiations == null && calls == null) {
+                domFnNoExamples.classList.remove("hidden");
+            } else {
+                // TODO show examples
+                domFnExamples.classList.remove("hidden");
+            }
+        } else {
+            protoSrcIndex = zigAnalysis.fns[fnDecl.value].src;
+
+            domFnExamples.classList.add("hidden");
+            domFnNoExamples.classList.add("hidden");
         }
 
+        var protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
+        if (docsSource == null && protoSrcNode.docs != null) {
+            docsSource = protoSrcNode.docs;
+        }
+        if (docsSource != null) {
+            domFnDocs.innerHTML = markdown(docsSource);
+            domFnDocs.classList.remove("hidden");
+        }
         domFnProto.classList.remove("hidden");
     }
 
@@ -268,6 +313,17 @@
         }
     }
 
+    function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
+        var srcIndex = typeIsGenericFn(typeIndex) ? value : zigAnalysis.fns[value].src;
+        var calls = nodesToCallsMap[srcIndex];
+        if (calls == null) return false;
+        for (var i = 0; i < calls.length; i += 1) {
+            var call = zigAnalysis.calls[calls[i]];
+            if (call.result.type !== typeTypeId) return false;
+        }
+        return true;
+    }
+
     function renderContainer(container) {
         var typesList = [];
         var fnsList = [];
@@ -279,7 +335,11 @@
                 } else {
                     var typeKind = zigAnalysis.types[decl.type].kind;
                     if (typeKind === typeKindFnId) {
-                        fnsList.push(decl);
+                        if (allCompTimeFnCallsHaveTypeResult(decl.type, decl.value)) {
+                            typesList.push(decl);
+                        } else {
+                            fnsList.push(decl);
+                        }
                     }
                 }
             }
@@ -688,4 +748,32 @@
             }
         }
     }
+
+    function indexNodesToFns() {
+        var map = {};
+        for (var i = 0; i < zigAnalysis.fns.length; i += 1) {
+            var fn = zigAnalysis.fns[i];
+            if (typeIsGenericFn(fn.type)) continue;
+            if (map[fn.src] == null) {
+                map[fn.src] = [i];
+            } else {
+                map[fn.src].push(i);
+            }
+        }
+        return map;
+    }
+
+    function indexNodesToCalls() {
+        var map = {};
+        for (var i = 0; i < zigAnalysis.calls.length; i += 1) {
+            var call = zigAnalysis.calls[i];
+            var fn = zigAnalysis.fns[call.fn];
+            if (map[fn.src] == null) {
+                map[fn.src] = [i];
+            } else {
+                map[fn.src].push(i);
+            }
+        }
+        return map;
+    }
 })();
lib/std/debug.zig
@@ -2439,3 +2439,8 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {
     );
     std.debug.warn("{} sp = 0x{x}\n", prefix, sp);
 }
+
+// Reference everything so it gets tested.
+test "" {
+    _ = leb;
+}
lib/std/std.zig
@@ -62,61 +62,69 @@ pub const unicode = @import("unicode.zig");
 pub const valgrind = @import("valgrind.zig");
 pub const zig = @import("zig.zig");
 
-test "std" {
-    // run tests from these
-    _ = @import("array_list.zig");
-    _ = @import("atomic.zig");
-    _ = @import("bloom_filter.zig");
-    _ = @import("buf_map.zig");
-    _ = @import("buf_set.zig");
-    _ = @import("buffer.zig");
-    _ = @import("hash_map.zig");
-    _ = @import("linked_list.zig");
-    _ = @import("mutex.zig");
-    _ = @import("statically_initialized_mutex.zig");
-    _ = @import("segmented_list.zig");
-    _ = @import("spinlock.zig");
-    _ = @import("child_process.zig");
+// Reference everything so it gets tested.
+test "" {
+    _ = AlignedArrayList;
+    _ = ArrayList;
+    _ = AutoHashMap;
+    _ = BloomFilter;
+    _ = BufMap;
+    _ = BufSet;
+    _ = Buffer;
+    _ = BufferOutStream;
+    _ = DynLib;
+    _ = HashMap;
+    _ = Mutex;
+    _ = PackedIntArrayEndian;
+    _ = PackedIntArray;
+    _ = PackedIntSliceEndian;
+    _ = PackedIntSlice;
+    _ = PriorityQueue;
+    _ = SinglyLinkedList;
+    _ = StaticallyInitializedMutex;
+    _ = SegmentedList;
+    _ = SpinLock;
+    _ = StringHashMap;
+    _ = ChildProcess;
+    _ = TailQueue;
+    _ = Thread;
 
-    _ = @import("ascii.zig");
-    _ = @import("base64.zig");
-    _ = @import("build.zig");
-    _ = @import("c.zig");
-    _ = @import("coff.zig");
-    _ = @import("crypto.zig");
-    _ = @import("cstr.zig");
-    _ = @import("debug.zig");
-    _ = @import("dwarf.zig");
-    _ = @import("dynamic_library.zig");
-    _ = @import("elf.zig");
-    _ = @import("event.zig");
-    _ = @import("fmt.zig");
-    _ = @import("fs.zig");
-    _ = @import("hash.zig");
-    _ = @import("heap.zig");
-    _ = @import("http.zig");
-    _ = @import("io.zig");
-    _ = @import("json.zig");
-    _ = @import("lazy_init.zig");
-    _ = @import("macho.zig");
-    _ = @import("math.zig");
-    _ = @import("mem.zig");
-    _ = @import("meta.zig");
-    _ = @import("net.zig");
-    _ = @import("os.zig");
-    _ = @import("pdb.zig");
-    _ = @import("process.zig");
-    _ = @import("packed_int_array.zig");
-    _ = @import("priority_queue.zig");
-    _ = @import("rand.zig");
-    _ = @import("rb.zig");
-    _ = @import("sort.zig");
-    _ = @import("testing.zig");
-    _ = @import("thread.zig");
-    _ = @import("time.zig");
-    _ = @import("unicode.zig");
-    _ = @import("valgrind.zig");
-    _ = @import("zig.zig");
-
-    _ = @import("debug/leb128.zig");
+    _ = atomic;
+    _ = base64;
+    _ = build;
+    _ = c;
+    _ = coff;
+    _ = crypto;
+    _ = cstr;
+    _ = debug;
+    _ = dwarf;
+    _ = elf;
+    _ = event;
+    _ = fmt;
+    _ = fs;
+    _ = hash;
+    _ = hash_map;
+    _ = heap;
+    _ = http;
+    _ = io;
+    _ = json;
+    _ = lazyInit;
+    _ = macho;
+    _ = math;
+    _ = mem;
+    _ = meta;
+    _ = net;
+    _ = os;
+    _ = packed_int_array;
+    _ = pdb;
+    _ = process;
+    _ = rand;
+    _ = rb;
+    _ = sort;
+    _ = ascii;
+    _ = testing;
+    _ = time;
+    _ = unicode;
+    _ = valgrind;
+    _ = zig;
 }
src/all_types.hpp
@@ -1325,6 +1325,9 @@ bool tld_ptr_eql(const Tld *a, const Tld *b);
 uint32_t node_ptr_hash(const AstNode *ptr);
 bool node_ptr_eql(const AstNode *a, const AstNode *b);
 
+uint32_t fn_ptr_hash(const ZigFn *ptr);
+bool fn_ptr_eql(const ZigFn *a, const ZigFn *b);
+
 struct ZigTypeUnion {
     AstNode *decl_node;
     TypeUnionField *fields;
src/analyze.cpp
@@ -7328,6 +7328,14 @@ bool node_ptr_eql(const AstNode *a, const AstNode *b) {
     return a == b;
 }
 
+uint32_t fn_ptr_hash(const ZigFn *ptr) {
+    return hash_ptr((void*)ptr);
+}
+
+bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) {
+    return a == b;
+}
+
 ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
     Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name));
     resolve_top_level_decl(codegen, tld, nullptr, false);
src/dump_analysis.cpp
@@ -352,6 +352,9 @@ struct AnalDumpCtx {
     ZigList<Tld *> decl_list;
     HashMap<const Tld *, uint32_t, tld_ptr_hash, tld_ptr_eql> decl_map;
 
+    ZigList<ZigFn *> fn_list;
+    HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_map;
+
     ZigList<AstNode *> node_list;
     HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map;
 };
@@ -430,6 +433,17 @@ static uint32_t anal_dump_get_node_id(AnalDumpCtx *ctx, AstNode *node) {
     return node_id;
 }
 
+static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) {
+    uint32_t fn_id = ctx->fn_list.length;
+    auto existing_entry = ctx->fn_map.put_unique(fn, fn_id);
+    if (existing_entry == nullptr) {
+        ctx->fn_list.append(fn);
+    } else {
+        fn_id = existing_entry->value;
+    }
+    return fn_id;
+}
+
 static uint32_t anal_dump_get_decl_id(AnalDumpCtx *ctx, Tld *tld) {
     uint32_t decl_id = ctx->decl_list.length;
     auto existing_entry = ctx->decl_map.put_unique(tld, decl_id);
@@ -494,6 +508,11 @@ static void anal_dump_node_ref(AnalDumpCtx *ctx, AstNode *node) {
     jw_int(&ctx->jw, node_id);
 }
 
+static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) {
+    uint32_t fn_id = anal_dump_get_fn_id(ctx, fn);
+    jw_int(&ctx->jw, fn_id);
+}
+
 static void anal_dump_decl_ref(AnalDumpCtx *ctx, Tld *tld) {
     uint32_t decl_id = anal_dump_get_decl_id(ctx, tld);
     jw_int(&ctx->jw, decl_id);
@@ -600,8 +619,10 @@ static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) {
 
                 jw_object_field(jw, "type");
                 anal_dump_type_ref(ctx, fn->type_entry);
-            }
 
+                jw_object_field(jw, "value");
+                anal_dump_fn_ref(ctx, fn);
+            }
             break;
         }
         default:
@@ -642,6 +663,19 @@ static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty,
             anal_dump_type_ref(ctx, val_ty);
             return;
         }
+        case ZigTypeIdFn: {
+            if (value->data.x_ptr.special == ConstPtrSpecialFunction) {
+                ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry;
+                if (val_fn->type_entry->data.fn.is_generic) {
+                    anal_dump_node_ref(ctx, val_fn->proto_node);
+                } else {
+                    anal_dump_fn_ref(ctx, val_fn);
+                }
+            } else {
+                jw_null(&ctx->jw);
+            }
+            return;
+        }
         default:
             jw_null(&ctx->jw);
             return;
@@ -721,6 +755,11 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
             jw_int(jw, ty->data.floating.bit_count);
             break;
         }
+        case ZigTypeIdFn: {
+            jw_object_field(jw, "generic");
+            jw_bool(jw, ty->data.fn.is_generic);
+            break;
+        }
         default:
             // TODO
             break;
@@ -763,7 +802,7 @@ void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
             doc_comments_buf = nullptr;
             break;
     }
-    if (doc_comments_buf->list.length != 0) {
+    if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) {
         jw_object_field(jw, "docs");
         jw_string(jw, buf_ptr(doc_comments_buf));
     }
@@ -771,6 +810,19 @@ void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
     jw_end_object(jw);
 }
 
+void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) {
+    JsonWriter *jw = &ctx->jw;
+
+    jw_begin_object(jw);
+
+    jw_object_field(jw, "src");
+    anal_dump_node_ref(ctx, fn->proto_node);
+
+    jw_object_field(jw, "type");
+    anal_dump_type_ref(ctx, fn->type_entry);
+
+    jw_end_object(jw);
+}
 
 void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl) {
     Error err;
@@ -783,6 +835,7 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     ctx.file_map.init(16);
     ctx.decl_map.init(16);
     ctx.node_map.init(16);
+    ctx.fn_map.init(16);
 
     jw_begin_object(jw);
 
@@ -822,6 +875,71 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     jw_object_field(jw, "rootPkg");
     anal_dump_pkg_ref(&ctx, g->root_package);
 
+    // Poke the functions
+    for (size_t i = 0; i < g->fn_defs.length; i += 1) {
+        ZigFn *fn = g->fn_defs.at(i);
+        (void)anal_dump_get_fn_id(&ctx, fn);
+    }
+
+    jw_object_field(jw, "calls");
+    jw_begin_array(jw);
+    {
+        auto it = g->memoized_fn_eval_table.entry_iterator();
+        for (;;) {
+            auto *entry = it.next();
+            if (!entry)
+                break;
+
+            jw_array_elem(jw);
+            jw_begin_object(jw);
+
+            jw_object_field(jw, "args");
+            jw_begin_object(jw);
+
+            Scope *scope = entry->key;
+            while (scope != nullptr) {
+                if (scope->id == ScopeIdVarDecl) {
+                    ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
+                    jw_object_field(jw, var->name);
+                    jw_begin_object(jw);
+                    jw_object_field(jw, "type");
+                    anal_dump_type_ref(&ctx, var->var_type);
+                    jw_object_field(jw, "value");
+                    anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value);
+                    jw_end_object(jw);
+                } else if (scope->id == ScopeIdFnDef) {
+                    jw_end_object(jw);
+
+                    jw_object_field(jw, "fn");
+                    ZigFn *fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
+                    anal_dump_fn_ref(&ctx, fn);
+
+                    ConstExprValue *result = entry->value;
+                    jw_object_field(jw, "result");
+                    jw_begin_object(jw);
+                    jw_object_field(jw, "type");
+                    anal_dump_type_ref(&ctx, result->type);
+                    jw_object_field(jw, "value");
+                    anal_dump_value(&ctx, scope->source_node, result->type, result);
+                    jw_end_object(jw);
+                    break;
+                }
+                scope = scope->parent;
+            }
+            jw_end_object(jw);
+        }
+    }
+    jw_end_array(jw);
+
+    jw_object_field(jw, "fns");
+    jw_begin_array(jw);
+    for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) {
+        ZigFn *fn = ctx.fn_list.at(i);
+        jw_array_elem(jw);
+        anal_dump_fn(&ctx, fn);
+    }
+    jw_end_array(jw);
+
     jw_object_field(jw, "packages");
     jw_begin_array(jw);
     for (uint32_t i = 0; i < ctx.pkg_list.length; i += 1) {