作者
Roberto Aloi <prof3ta(at)gmail(dot)com>
状态
已接受
类型
标准跟踪
创建
2024年11月11日
Erlang 版本
OTP-28

EEP 74:Erlang 错误索引 #

摘要 #

Erlang 错误索引 是 Erlang 生态系统中各种工具(包括但不限于 erlc Erlang 编译器和 dialyzer 类型检查器)发出的错误的目录

该目录不仅限于 Erlang/OTP 附带的工具,还可以包括第三方应用程序,例如 EqWAlizer 类型检查器或 Elvis 代码样式审查器。

目录中的每个错误都由一个唯一的代码标识,并附有描述、示例和可能的处理方法。错误代码根据生成它们的工具进行命名空间划分。唯一代码可以与人类可读的别名相关联。

IDE 和语言服务器可以利用唯一的错误代码来提供关于错误的更好的上下文信息,并使错误更容易搜索和引用。标准化的错误索引为社区提供额外的示例和文档创建了一个公共空间,为 Erlang 用户手册和标准文档提供了完美的补充。

理由 #

编程语言的“错误索引”概念并非新颖的想法。例如,在 RustHaskell 社区中已经存在错误目录。

由于各种约束,包括有限的上下文和字符数,对于编译器和类型检查器等开发工具来说,生成有意义的错误消息有时可能具有挑战性。

通过将唯一代码与每个诊断(警告或错误)相关联,我们使工具不必将大量文本信息浓缩成一个有时晦涩难懂的通用单句。此外,随着时间的推移,错误和警告的具体措辞得到改进,错误代码保持不变,提供了一种搜索引擎友好的方式来索引和引用诊断。

一个很好的例子是在 OTP 27 中引入的表达式更新文字错误消息。给定以下代码

-define(DEFAULT, #{timeout => 5000}).

updated(Value) ->
  ?DEFAULT#{timeout => Value}.

编译器会发出以下错误

test.erl:8:11: Warning: expression updates a literal
    %    8|   ?DEFAULT#{timeout => 1000}.
    %     |           ^

错误的含义可能不是每个人都显而易见的。最重要的是,编译器没有提供关于为什么发出警告以及用户可以如何处理它的信息。然后用户必须求助于搜索引擎、论坛或类似的方式才能继续。

相反,我们可以将唯一标识符与代码关联(例如,ERL-1234

test.erl:8:11: Warning: expression updates a literal (ERL-1234)
    %    8|   ?DEFAULT#{timeout => 1000}.
    %     |           ^

该代码可以将错误消息链接到外部资源(例如,维基页面),其中包含有关该错误的所有必需的附加信息,这些信息如果直接呈现给用户是不实际的。以下是上述代码的条目可能的样子示例

Erlang Error Index Sample Entry

唯一的错误代码还具有在论坛和聊天中更好地搜索的优势,在论坛和聊天中,确切的错误消息可能会有所不同,但错误代码将是相同的。

最后,IDE(例如,通过语言服务器)可以使用错误代码来匹配错误代码并提供上下文帮助。Erlang LSELP 语言服务器已经在使用“非官方”错误代码。

发出诊断 #

为了方便语言服务器和 IDE,生成诊断的工具应以标准格式生成诊断(错误和警告)。在编译器的情况下,可以通过指定一个额外的选项(例如 --error-format json)来完成。

一种可能的 JSON 格式,深受 LSP 协议 的启发,是

{
  uri: "file:///git/erlang/project/app/src/file.erl",
  range: {
    start: {
      line: 5,
      character: 23
    },
    end: {
      line: 5,
      character: 32
    }
  },
  severity: "warning",
  code: "DIA-1234",
  doc_uri: "https://errors.erlang.org/DIA/DIA-1234",
  source: "dialyzer",
  message: "This a descriptive error message from Dialyzer"
}

其中

  • uri:诊断所指的文件路径,使用 RFC 3986 格式表示
  • range:消息应用的范围,从零开始。该范围应尽可能严格。例如,如果警告用户某个记录未使用,则诊断的范围应仅覆盖记录的名称,而不是整个定义。这最大限度地减少了用户在例如呈现为波浪线时的干扰,同时传达相同的信息。
  • severity:诊断的严重性。允许的值为 errorwarninginformationhint
  • code:标识错误的唯一错误代码
  • doc_uri:一个 URI,打开可以获取有关诊断错误的更多信息
  • source:一个人类可读的字符串,描述诊断的来源
  • message:错误的简短文本描述。该消息应该足够通用,并且可以独立理解。

错误代码格式 #

错误代码应由两部分组成:一个字母数字命名空间(三个字母)和一个数字标识符(四个数字),用破折号 (-) 分隔。

一组潜在的命名空间可能如下所示

命名空间 描述
ERL Erlang 编译器和相关工具(linter、解析器、扫描器)
DIA Dialyzer 类型检查器
ELV Elvis 代码风格审查器
ELP Erlang 语言平台
... ...

一组潜在的错误代码可能如下所示

ERL-0123
DIA-0009
ELV-0015
ELP-0001

每个命名空间和代码的字符/数字的确切数量有待讨论,以及解析器、扫描器或 erlint Erlang linter 等组件是否应具有自己的命名空间。

职责 #

Erlang/OTP 团队将最终负责维护官方命名空间的列表。然后,每个工具维护者将负责将特定代码分配给特定的诊断。

流程 #

错误索引可以以 Markdown 页面的格式实现。命名空间(或错误代码)的批准过程将遵循常规流程,使用 Pull Request,由 Erlang/OTP 团队以及其他可能感兴趣的行业成员审查和批准。

错误不能重复使用。如果某个工具停止发出错误代码,则已弃用的错误代码仍会在索引中记录,并附带弃用通知。这是为了避免将单个代码重复用于多个目的。

为了限制管理负担,该部分将仅包含 Erlang/OTP 附带工具的错误代码以及外部工具的命名空间。每个命名空间的单个错误代码将由各自的所有者管理。

参考实现 #

ELP 网站 包含 Erlang 错误索引的示例。理想情况下,这样的网站将位于 erlang.org 域下,例如使用 https://errors.erlang.org/ URL。

该网站应使用 Markdown 作为编写内容的主要机制,并且应易于社区扩展。

版权 #

本文档置于公共领域或 CC0-1.0-Universal 许可之下,以更宽松者为准。