参考

诊断

如何阅读编译器错误并使用结构化修复方案。

读取错误

典型的错误如下所示:

error[NAM003]: Unknown identifier
  unknown identifier 'message'
  examples/hello.0:2:27
 
  2 |     check world.out.write(message)
    |                           ^^^^^^^
  rule: Names must be declared before use in the current lexical scope.
  expected: local binding, parameter, function, builtin value
  actual: no visible symbol named 'message'
  fix: Introduce a local binding before this use (local-edit)
  explain: zero explain NAM003

从上到下阅读:

  • 第一行给出稳定的错误代码和简短标题。
  • 消息说明出了什么问题。
  • 位置信息指向文件、行号和列号。
  • 源码摘录标记了确切的词元。
  • ruleexpectedactual 解释了不匹配的原因。
  • fix 给出最安全的修复方案。
  • explain 指向更深入的帮助信息。

在这个例子中,程序尝试写入 message 但未声明它。添加一个局部绑定即可修复:

pub fn main Void world World !  let message "hello from zero\n"  check world.out.write message

默认纯文本输出

默认的诊断信息应该简短且在终端日志中有用。

默认情况下不应包含 ANSI 颜色、粗体样式、超链接、OSC 转义序列或终端控制序列。这些字节会膨胀代理上下文,使日志更难比较。

使用:

zero check examples/hello.0

面向工具的 JSON 输出

JSON 是显式的。在代理、CI、编辑器、深度分析和需要稳定结构化数据的工具中使用 --json

zero check --json examples/hello.0

原生 JSON 格式是版本化的:

{
  "schemaVersion": 1,
  "ok": false,
  "diagnostics": [
    {
      "severity": "error",
      "code": "NAM003",
      "message": "unknown identifier 'message'",
      "path": "examples/hello.0",
      "line": 2,
      "column": 27,
      "length": 7,
      "expected": "visible local, parameter, function, or builtin",
      "actual": "no visible symbol named 'message'",
      "help": "declare the name before using it",
      "fixSafety": "behavior-preserving",
      "repair": {
        "id": "manual-review",
        "summary": "Inspect the diagnostic fields and choose a repair manually."
      },
      "related": []
    }
  ]
}

修复安全性

修复带有安全性标签,以便代理知道何时可以自动执行:

  • format-only:仅更改格式
  • behavior-preserving:保持程序行为不变
  • local-edit:局限于当前局部作用域或文件
  • api-changing:更改函数签名、导出名称、包 API 或调用点
  • requires-human-review:有风险或模糊;展示计划但不要自动应用

当前原生诊断

原生编译器为已实现的控制流和类型规则维护稳定的错误代码:

  • PAR100:解析器语法错误,例如缺少大括号、逗号或格式错误的类型参数列表
  • NAM003:未知标识符
  • NAM004:重复名称、错误调用参数数量或泛型类型名称遮蔽
  • IMP001:未知的包本地导入,修复 id 为 fix-import-path
  • IMP002:包本地导入循环
  • IMP003:跨导入模块的重复公共导出
  • PKG001:本地包依赖路径不包含 zero.json
  • PKG002:包依赖形成循环
  • PKG003:一个包名解析到冲突的版本
  • PKG004:包依赖不支持所选目标平台
  • BLD002:错误的项目清单或不支持的清单目标格式
  • ERR002:调用方的显式错误集缺少被调用方抛出的错误
  • ERR003:可失败调用未使用 checkrescue
  • ABI001:不支持的 C ABI 导出或外部布局接口
  • CIMP003:外部目标的 C 依赖会使用宿主的 include 路径、宿主库路径或隐式宿主 pkg-config 发现
  • BOR001:词法借用冲突,JSON 中 borrowTrace.activeBorrows 条目命名每个报告的借用根、路径、类型、活跃绑定、 已知时的声明范围和修复方案。如果报告达到上限,borrowTrace.truncated 为 true。
  • BOR002:引用来源逃逸,包括从调用返回的引用或通过可变参数存储写入的引用
  • OWN001:移动后使用拥有值,或会拥有不受约束的泛型载荷的泛型容器
  • TYP010:条件必须为 Bool
  • TYP002:赋值、字面量、返回或类型默认值中的类型不匹配
  • TYP011null 需要 Maybe<T> 上下文
  • TYP012break 需要封闭的循环
  • TYP013continue 需要封闭的循环
  • TYP014:范围循环边界必须与整数兼容
  • TYP015:整数字面量必须使用有效的数字、分隔符、基数前缀和整数后缀
  • TYP016:整数字面量必须适合预期的原始整数宽度
  • TYP017as 转换仅限于原始数值和字节 char 源类型与目标类型
  • TYP018:字符字面量必须恰好包含一个字节或支持的字节转义序列
  • TYP019:浮点字面量必须使用 digits "." digits 格式,可带可选指数
  • TYP020:浮点字面量必须适合预期的原始浮点宽度
  • TYP021:索引、切片和索引赋值需要支持该操作的目标
  • TYP022:索引表达式和存在的切片边界必须为整数
  • TYP023:泛型调用类型参数数量不匹配,或在非泛型函数上使用类型参数
  • TYP024:泛型推断为某个类型参数发现了冲突的具体类型
  • TYP025:无法从局部调用参数推断泛型类型参数
  • TYP026:类型别名重复、格式错误或循环
  • TYP027:递归泛型调用更改了类型参数
  • PUB001:公共声明缺少必需的显式 API 类型元数据
  • MET001:解析的 meta 表达式请求了当前编译器版本尚无法求值的编译时行为
  • IFC001:接口约束未知,或具体类型参数没有静态类型体
  • IFC002:受约束的具体类型缺少必需的静态接口方法
  • IFC003:具体静态方法的参数数量与接口不匹配
  • IFC004:具体静态方法的返回类型与接口不匹配
  • IFC005:具体静态方法的参数类型与接口不匹配
  • STC001:静态值参数使用了不支持的非整数类型
  • STC002:静态值参数不是整数字面量或确定性的顶层常量
  • STC003:显式静态值参数与带注解类型所携带的值冲突
  • SHM001:泛型类型方法调用无法推断继承的类型/静态参数
  • SHM002:泛型类型方法的参数隐含了冲突的 Self 实例化
  • RCV001:接收者风格调用了未知方法或没有 self 的静态方法
  • RCV002:接收者风格调用需要可寻址的接收者,或 mutref<Self> 需要可变接收者
  • FLD001:类型字面量包含未知字段
  • FLD002:类型字面量省略了没有默认值的必需字段
  • TAR001:请求的目标名称不在 zero targets
  • TAR002:所选目标平台未提供程序所需的能力
  • 边界检查失败:原生可执行文件在索引、索引赋值或切片范围超出基础 长度时打印 zero bounds check failed 并 中止。
  • MAT004:match 分支只能为携带载荷的选择分支绑定载荷

标准库诊断

标准库模块使用与编译器诊断相同的结构化诊断约定。

  • MEM001 报告格式错误的内存类型形式,例如 Maybe 缺少其必需的类型参数。
  • std.parsestd.jsonstd.env 诊断在适用的地方携带源码位置信息。
  • std.time 诊断可以对单词元输入使用仅偏移量的位置信息。
  • 标准库错误代码保持稳定且包本地化,zero explain <code> 提供人工指导,--json 暴露结构化修复元数据。

常见修复方案

托管的文件系统辅助工具在当前编译器中仅限宿主平台。在非宿主目标上会明确失败:

bin/zero check --json --target linux-musl-x64 conformance/native/fail/std-fs-target-unsupported.0

该诊断使用 TAR002fixSafety: "requires-human-review" 和修复 id choose-target-with-required-capability

规范的修复方式是为具有所需能力的目标构建,或将该代码移至特定目标的入口点之后。

可写字节辅助工具需要可变存储:

let dst [4]u8 [0, 0, 0, 0]let src [4]u8 [122, 101, 114, 111]let _copied std.mem.copy dst src

这会报告 TYP009,修复 id 为 make-binding-mutable。规范修复为:

mut dst [4]u8 [0, 0, 0, 0]let src [4]u8 [122, 101, 114, 111]let _copied std.mem.copy dst src

命名错误的 std.fs 调用需要显式错误流:

let file std.fs.createOrRaise fs ".zero/out.txt"

这会报告 ERR003,修复 id 为 check-or-rescue-fallible-call

使用 check 并在调用方的 ![NotFound TooLarge Io] 集合中包含 NotFoundTooLargeIo。当调用需要就地恢复时,局部使用 rescue

泛型调用仅使用局部推断。以下代码会失败,因为 T 需要同时为 i32u8

fn first<T: Type> T left T right T  ret left let value i32 first 1 2_u8

修复方式是使参数一致,或传入具有兼容值的显式类型参数:

let value i32 first<i32> 1 2

公共常量需要显式 API 形状:

pub const answer 42

这会报告 PUB001。保持行为的修复为:

pub const answer i32 42

C 互操作将宿主和目标发现分开。以下代码在跨目标时失败,因为清单请求了宿主 include/库发现:

bin/zero build --json --target linux-musl-x64 conformance/c/host-leak-package --out .zero/out/host-leak-package

这会报告 CIMP003,修复 id 为 configure-target-c-dependency

规范的修复方式是使用包相对的供应商头文件/库,或配置目标 sysroot。不要依赖宿主 include 路径、宿主库路径或宿主 pkg-config 发现进行跨目标构建。

包依赖诊断是图级别的修复:

代码含义
PKG001本地依赖路径错误或缺失。
PKG002两个包清单相互循环依赖。
PKG003图将一个包名解析为多个版本。
PKG004所选目标平台不在依赖的目标列表中。

这些都使用 requires-human-review,因为正确的修复可能更改 包拓扑或目标支持。

类型别名是编译时的拼写,不能循环:

alias A B alias B A

这会报告 TYP026。将别名指向具体类型(如 Span<u8>)或移除循环。

不支持的编译时执行报告 MET001,例如 const os String meta target.os,直到目标事实在原生编译器中实现。

泛型类型方法必须从具体的 Self 值或显式类型参数进行特化:

type FixedVec<T: Type, static N: usize>  fn cap usize    ret N let cap FixedVec.cap()

这会报告 SHM001

通过以下两种方式之一修复:

  • 传入显式类型参数,例如 FixedVec.cap<u8, 4>()
  • 调用接收具体 Self 值的方法,例如 FixedVec.push(&mut vec, value)vec.push(value)

SHM002 表示显式方法参数与接收者的注解类型不一致。

接收者调用需要第一个参数为 self: ref<Self>self: mutref<Self> 的已声明方法:

let vec FixedVec<u8,4> FixedVec . len 0 items [0, 0, 0, 0]check vec.push 1

这会报告 RCV002,因为 push 需要 mutref<Self>vec 是 不可变的。

未知的接收者方法报告 RCV001。没有 self 的静态方法应 通过类型命名空间调用。

类型字段默认值允许省略字段,但仅当声明提供了兼容的默认值时:

type NeedsItem  count usize 0  item u8 let value NeedsItem NeedsItem .

这会报告 FLD002,修复 id 为 initialize-missing-field,因为 item 没有默认值。类型错误的默认值会在默认值表达式处报告 TYP002

静态接口在泛型特化时检查。以下代码失败,因为 Counter 未提供所需的静态方法:

interface Readable<T: Type>  fn read i32 self ref<T> type Counter  value i32 fn readValue<T: Readable<T>> i32 value ref<T>  ret T.read value

这会报告 IFC002。添加具有匹配签名的具体静态方法:

fn read i32 self ref<Self>  ret self.value

静态值参数在发射前检查,以便固定大小的布局保持具体:

type FixedVec<T: Type, static N: usize>  len usize  items [N]T fn first<T: Type, static N: usize> T vec ref<FixedVec<T,N>>  ret vec.items[0] let vec FixedVec<u8,4> FixedVec . len 4 items [1, 2, 3, 4]let bad first<u8, 8> (&vec)

这会报告 STC003,因为显式的 8 与注解的 FixedVec<u8,4> 冲突。

相关的静态值诊断:

  • STC001:不支持的静态参数类型
  • STC002:在需要编译时整数的地方使用了运行时值

命令

  • zero check <input>:默认以人类优先的纯文本输出
  • zero check --json <input>:完整的诊断 JSON
  • zero explain <code>:诊断代码的人类可读解释
  • zero explain <code> --json:机器可读的解释
  • zero fix --plan --json <input>:提议的类型化修复,不编辑文件

实用示例:

zero explain TAR002
zero explain --json TYP009
zero fix --plan --json conformance/native/fail/mem-copy-immutable-dst.0
zero fix --plan --json --target linux-musl-x64 conformance/native/fail/std-fs-target-unsupported.0