Commit 784a493dc7

Andrew Kelley <andrew@ziglang.org>
2019-10-08 19:41:13
generated docs: functions with inferred error sets display nicely
infrastructure in place for displaying error sets
1 parent 03a6b33
lib/std/special/docs/index.html
@@ -262,6 +262,7 @@
     </div>
     <h1 id="hdrName" class="hidden"></h1>
     <div id="fnDocs" class="hidden"></div>
+    <div id="fnErrors" class="hidden"></div>
     <div id="fnExamples" class="hidden"></div>
     <div id="fnNoExamples" class="hidden">
       <p>This function is not tested or referenced.</p>
lib/std/special/docs/main.js
@@ -11,6 +11,7 @@
     var domFnProto = document.getElementById("fnProto");
     var domFnProtoCode = document.getElementById("fnProtoCode");
     var domFnDocs = document.getElementById("fnDocs");
+    var domFnErrors = document.getElementById("fnErrors");
     var domFnExamples = document.getElementById("fnExamples");
     var domFnNoExamples = document.getElementById("fnNoExamples");
     var domSearch = document.getElementById("search");
@@ -33,6 +34,8 @@
     var typeKindFloatId;
     var typeKindIntId;
     var typeKindBoolId;
+    var typeKindErrSetId;
+    var typeKindErrUnionId;
     findTypeKinds();
 
     // for each package, is an array with packages to get to this one
@@ -96,6 +99,7 @@
         domSectInfo.classList.add("hidden");
         domHdrName.classList.add("hidden");
         domSectNav.classList.add("hidden");
+        domFnErrors.classList.add("hidden");
         domFnExamples.classList.add("hidden");
         domFnNoExamples.classList.add("hidden");
 
@@ -183,7 +187,7 @@
 
         protoHtml += ') ';
         if (typeObj.ret != null) {
-            protoHtml += typeIndexName(typeObj.ret, true, true);
+            protoHtml += typeIndexName(typeObj.ret, true, true, fnDecl.value);
         } else {
             protoHtml += '<span class="tok-kw">var</span>';
         }
@@ -335,24 +339,24 @@
         }
     }
 
-    function typeIndexName(typeIndex, wantHtml, wantLink) {
+    function typeIndexName(typeIndex, wantHtml, wantLink, fnIndex) {
         var typeObj = zigAnalysis.types[typeIndex];
         if (wantLink) {
             var declIndex = getCanonTypeDecl(typeIndex);
             var declPath = getCanonDeclPath(declIndex);
             var haveLink = declPath != null;
-            var typeNameHtml = typeName(typeObj, true, !haveLink);
+            var typeNameHtml = typeName(typeObj, true, !haveLink, fnIndex);
             if (haveLink) {
                 return '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">' + typeNameHtml + '</a>';
             } else {
                 return typeNameHtml;
             }
         } else {
-            return typeName(typeObj, wantHtml);
+            return typeName(typeObj, wantHtml, false, fnIndex);
         }
     }
 
-    function typeName(typeObj, wantHtml, wantSubLink) {
+    function typeName(typeObj, wantHtml, wantSubLink, fnIndex) {
         switch (typeObj.kind) {
             case typeKindPtrId:
                 var name = "";
@@ -397,11 +401,22 @@
                         name += typeObj.align;
                     }
                     if (typeObj.hostIntBytes != null) {
-                        name += ":" + typeObj.bitOffsetInHost + ":" + typeObj.hostIntBytes;
+                        name += ":";
+                        if (wantHtml) {
+                            name += '<span class="tok-number">' + typeObj.bitOffsetInHost + '</span>';
+                        } else {
+                            name += typeObj.bitOffsetInHost;
+                        }
+                        name += ":";
+                        if (wantHtml) {
+                            name += '<span class="tok-number">' + typeObj.hostIntBytes + '</span>';
+                        } else {
+                            name += typeObj.hostIntBytes;
+                        }
                     }
                     name += ") ";
                 }
-                name += typeIndexName(typeObj.elem, wantHtml, wantSubLink);
+                name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null);
                 return name;
             case typeKindFloatId:
                 if (wantHtml) {
@@ -429,6 +444,29 @@
                 } else {
                     return "bool";
                 }
+            case typeKindErrSetId:
+                if (typeObj.errors == null) {
+                    if (wantHtml) {
+                        return '<span class="tok-type">anyerror</span>';
+                    } else {
+                        return "anyerror";
+                    }
+                } else {
+                    if (wantHtml) {
+                        return escapeHtml(typeObj.name);
+                    } else {
+                        return typeObj.name;
+                    }
+                }
+            case typeKindErrUnionId:
+                var errSetTypeObj = zigAnalysis.types[typeObj.err];
+                var payloadHtml = typeIndexName(typeObj.payload, wantHtml, wantSubLink, null);
+                if (errSetTypeObj.fn != null && errSetTypeObj.fn == fnIndex) {
+                    // function index parameter supplied and this is the inferred error set of it
+                    return "!" + payloadHtml;
+                } else {
+                    return typeIndexName(typeObj.err, wantHtml, wantSubLink, null) + "!" + payloadHtml;
+                }
             default:
                 if (wantHtml) {
                     return escapeHtml(typeObj.name);
@@ -439,7 +477,7 @@
     }
 
     function renderType(typeObj) {
-        var name = typeName(typeObj);
+        var name = typeName(typeObj, false, false);
         if (name != null && name != "") {
             domHdrName.innerText = zigAnalysis.typeKinds[typeObj.kind] + " " + name;
             domHdrName.classList.remove("hidden");
@@ -543,6 +581,10 @@
                 typeKindIntId = i;
             } else if (zigAnalysis.typeKinds[i] === "Bool") {
                 typeKindBoolId = i;
+            } else if (zigAnalysis.typeKinds[i] === "ErrorSet") {
+                typeKindErrSetId = i;
+            } else if (zigAnalysis.typeKinds[i] === "ErrorUnion") {
+                typeKindErrUnionId = i;
             }
         }
         if (typeKindTypeId == null) {
@@ -563,6 +605,12 @@
         if (typeKindBoolId == null) {
             throw new Error("No type kind 'Bool' found");
         }
+        if (typeKindErrSetId == null) {
+            throw new Error("No type kind 'ErrorSet' found");
+        }
+        if (typeKindErrUnionId == null) {
+            throw new Error("No type kind 'ErrorUnion' found");
+        }
     }
 
     function findTypeTypeId() {
src/all_types.hpp
@@ -1290,9 +1290,10 @@ struct ZigTypeErrorUnion {
 };
 
 struct ZigTypeErrorSet {
-    uint32_t err_count;
     ErrorTableEntry **errors;
     ZigFn *infer_fn;
+    uint32_t err_count;
+    bool incomplete;
 };
 
 struct ZigTypeEnum {
@@ -1328,6 +1329,9 @@ 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);
 
+uint32_t err_ptr_hash(const ErrorTableEntry *ptr);
+bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b);
+
 struct ZigTypeUnion {
     AstNode *decl_node;
     TypeUnionField *fields;
src/analyze.cpp
@@ -1633,6 +1633,7 @@ ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) {
     err_set_type->data.error_set.err_count = 0;
     err_set_type->data.error_set.errors = nullptr;
     err_set_type->data.error_set.infer_fn = fn_entry;
+    err_set_type->data.error_set.incomplete = true;
     err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits;
     err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align;
     err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size;
@@ -4277,12 +4278,12 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) {
 bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node) {
     assert(err_set_type->id == ZigTypeIdErrorSet);
     ZigFn *infer_fn = err_set_type->data.error_set.infer_fn;
-    if (infer_fn != nullptr) {
+    if (infer_fn != nullptr && err_set_type->data.error_set.incomplete) {
         if (infer_fn->anal_state == FnAnalStateInvalid) {
             return false;
         } else if (infer_fn->anal_state == FnAnalStateReady) {
             analyze_fn_body(g, infer_fn);
-            if (err_set_type->data.error_set.infer_fn != nullptr) {
+            if (err_set_type->data.error_set.incomplete) {
                 assert(g->errors.length != 0);
                 return false;
             }
@@ -4509,7 +4510,9 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
 
     if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) {
         ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
-        if (return_err_set_type->data.error_set.infer_fn != nullptr) {
+        if (return_err_set_type->data.error_set.infer_fn != nullptr &&
+            return_err_set_type->data.error_set.incomplete)
+        {
             ZigType *inferred_err_set_type;
             if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
                 inferred_err_set_type = fn->src_implicit_return_type;
@@ -4522,14 +4525,16 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
                 return;
             }
 
-            if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
+            if (inferred_err_set_type->data.error_set.infer_fn != nullptr &&
+                inferred_err_set_type->data.error_set.incomplete)
+            {
                 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
                     fn->anal_state = FnAnalStateInvalid;
                     return;
                 }
             }
 
-            return_err_set_type->data.error_set.infer_fn = nullptr;
+            return_err_set_type->data.error_set.incomplete = false;
             if (type_is_global_error_set(inferred_err_set_type)) {
                 return_err_set_type->data.error_set.err_count = UINT32_MAX;
             } else {
@@ -7336,6 +7341,14 @@ bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) {
     return a == b;
 }
 
+uint32_t err_ptr_hash(const ErrorTableEntry *ptr) {
+    return hash_ptr((void*)ptr);
+}
+
+bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *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);
@@ -7348,7 +7361,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
 
 bool type_is_global_error_set(ZigType *err_set_type) {
     assert(err_set_type->id == ZigTypeIdErrorSet);
-    assert(err_set_type->data.error_set.infer_fn == nullptr);
+    assert(!err_set_type->data.error_set.incomplete);
     return err_set_type->data.error_set.err_count == UINT32_MAX;
 }
 
src/dump_analysis.cpp
@@ -357,6 +357,9 @@ struct AnalDumpCtx {
 
     ZigList<AstNode *> node_list;
     HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map;
+
+    ZigList<ErrorTableEntry *> err_list;
+    HashMap<const ErrorTableEntry *, uint32_t, err_ptr_hash, err_ptr_eql> err_map;
 };
 
 static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty);
@@ -444,6 +447,17 @@ static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) {
     return fn_id;
 }
 
+static uint32_t anal_dump_get_err_id(AnalDumpCtx *ctx, ErrorTableEntry *err) {
+    uint32_t err_id = ctx->err_list.length;
+    auto existing_entry = ctx->err_map.put_unique(err, err_id);
+    if (existing_entry == nullptr) {
+        ctx->err_list.append(err);
+    } else {
+        err_id = existing_entry->value;
+    }
+    return err_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);
@@ -513,6 +527,11 @@ static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) {
     jw_int(&ctx->jw, fn_id);
 }
 
+static void anal_dump_err_ref(AnalDumpCtx *ctx, ErrorTableEntry *err) {
+    uint32_t err_id = anal_dump_get_err_id(ctx, err);
+    jw_int(&ctx->jw, err_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);
@@ -841,6 +860,33 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
             anal_dump_pointer_attrs(ctx, ty);
             break;
         }
+        case ZigTypeIdErrorSet: {
+            if (type_is_global_error_set(ty)) {
+                break;
+            }
+            if (ty->data.error_set.infer_fn != nullptr) {
+                jw_object_field(jw, "fn");
+                anal_dump_fn_ref(ctx, ty->data.error_set.infer_fn);
+            }
+            jw_object_field(jw, "errors");
+            jw_begin_array(jw);
+            for (uint32_t i = 0; i < ty->data.error_set.err_count; i += 1) {
+                jw_array_elem(jw);
+                ErrorTableEntry *err = ty->data.error_set.errors[i];
+                anal_dump_err_ref(ctx, err);
+            }
+            jw_end_array(jw);
+            break;
+        }
+        case ZigTypeIdErrorUnion: {
+            jw_object_field(jw, "err");
+            anal_dump_type_ref(ctx, ty->data.error_union.err_set_type);
+
+            jw_object_field(jw, "payload");
+            anal_dump_type_ref(ctx, ty->data.error_union.payload_type);
+
+            break;
+        }
         default:
             jw_object_field(jw, "name");
             jw_string(jw, buf_ptr(&ty->name));
@@ -849,7 +895,7 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
     jw_end_object(jw);
 }
 
-void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
+static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
     JsonWriter *jw = &ctx->jw;
 
     jw_begin_object(jw);
@@ -892,7 +938,21 @@ void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
     jw_end_object(jw);
 }
 
-void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) {
+static void anal_dump_err(AnalDumpCtx *ctx, const ErrorTableEntry *err) {
+    JsonWriter *jw = &ctx->jw;
+
+    jw_begin_object(jw);
+
+    jw_object_field(jw, "src");
+    anal_dump_node_ref(ctx, err->decl_node);
+
+    jw_object_field(jw, "name");
+    jw_string(jw, buf_ptr(&err->name));
+
+    jw_end_object(jw);
+}
+
+static void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) {
     JsonWriter *jw = &ctx->jw;
 
     jw_begin_object(jw);
@@ -918,6 +978,7 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     ctx.decl_map.init(16);
     ctx.node_map.init(16);
     ctx.fn_map.init(16);
+    ctx.err_map.init(16);
 
     jw_begin_object(jw);
 
@@ -1055,6 +1116,15 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const
     }
     jw_end_array(jw);
 
+    jw_object_field(jw, "errors");
+    jw_begin_array(jw);
+    for (uint32_t i = 0; i < ctx.err_list.length; i += 1) {
+        const ErrorTableEntry *err = ctx.err_list.at(i);
+        jw_array_elem(jw);
+        anal_dump_err(&ctx, err);
+    }
+    jw_end_array(jw);
+
     jw_object_field(jw, "astNodes");
     jw_begin_array(jw);
     for (uint32_t i = 0; i < ctx.node_list.length; i += 1) {
src/ir.cpp
@@ -9692,7 +9692,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
         ZigType *container_set = wanted_type;
 
         // if the container set is inferred, then this will always work.
-        if (container_set->data.error_set.infer_fn != nullptr) {
+        if (container_set->data.error_set.infer_fn != nullptr && container_set->data.error_set.incomplete) {
             return result;
         }
         // if the container set is the global one, it will always work.
@@ -16157,7 +16157,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
                 UndefOk);
 
             if (inferred_err_set_type != nullptr) {
-                inferred_err_set_type->data.error_set.infer_fn = nullptr;
+                inferred_err_set_type->data.error_set.incomplete = false;
                 if (result->type->id == ZigTypeIdErrorUnion) {
                     ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set;
                     if (err != nullptr) {
@@ -23617,7 +23617,7 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
             if (!type_is_global_error_set(err_set_type) &&
                 err_set_type->data.error_set.err_count == 0)
             {
-                assert(err_set_type->data.error_set.infer_fn == nullptr);
+                assert(!err_set_type->data.error_set.incomplete);
                 return ir_const_bool(ira, &instruction->base, false);
             }
         }