这份架构文档现在真正达到了**“工业级编译器白皮书”**的水准!
将“编译期类型哈希 (Type Hashing)”与“固定大小不透明载荷 (Opaque Payload)”彻底融入后,我们不仅保住了 C 语言后端的极速运行效率,还完美捍卫了大型项目的增量编译 (Incremental Compilation)。
以下是为您全面升级、包含最新 AutoError 底层降级机制的终极版 RFC 设计文档:
Auto 语言核心架构文档 (RFC):!T 统一错误处理与内存模型
1. 架构动机 (Motivation)
在系统级编程中,错误处理一直处于两难境地:
- C 语言(错误码):容易被忽略,且极难携带丰富的错误上下文(如动态参数、堆栈)。
- Rust 语言 (
Result<T, E>):类型签名极度膨胀。特别是在使用?操作符向上传递时,泛型参数E经常引发复杂的类型转换灾难(FromTrait Hell)。
Auto 语言引入 !T 类型,旨在实现**“类型签名极简,上下文信息丰富”的终极平衡。在开发者视角,所有错误类型被统一抽象擦除为 !;在编译器底层,它通过跨平台的智能内存降级,实现零拷贝、无锁的极速传递与绝对的内存安全,同时完美支持大型项目的增量编译**。
2. 语法与开发者心智 (Syntax & Ergonomics)
2.1 极简的签名与尽早解包
在 Auto 语言中,开发者无需在函数签名中声明具体的错误类型(隐藏 E)。鼓励使用 ? 操作符尽早解包(Unwrap First),避免风险资源在业务逻辑中蔓延。
fn read_sensor(port int) -> !int {
if timeout {
// 构造并返回错误,底层类型被自动擦除为统一的 AutoError
return make_error(SensorError{ port: port, code: 404 })
}
return 1024
}
// 调用端:使用 ? 极速解包。
// 如果是 Err,当前函数立即 return 报错;如果是 Ok,temp 蜕变为纯正 int,可极速 Copy。
let temp = read_sensor(1)?
let b = temp3. 错误契约:AutoError Spec 与向下转型 (Downcasting)
为了赋予开发者极大的自由度,AutoError 在语言前端被设计为一个 Spec(接口规范/Trait),而非死板的全局枚举或基类。
3.1 去中心化的错误定义
开发者可以在任意模块自由定义结构体并实现 Error Spec,无需修改任何全局文件。
struct SensorError { port int, code int }
impl Error for SensorError { ... }3.2 is 模式匹配与精确解构
当接收到一个被擦除了类型的 !T 时,通过 is 语句进行类型安全的“向下转型(Downcast)”:
let result = read_sensor(1)
is result {
Ok(val) => print("Value is: ${val}"),
Err(e) => {
// e 的表面类型是 AutoError。通过嵌套 is 探测真实类型:
is e {
SensorError(se) => if se.code == 404 { reset_sensor(se.port) },
DbError(de) => reconnect_db(),
else => print("Unknown error: ${e.message()}")
}
}
}4. 所有权与生命周期安全 (Ownership & Safety)
由于 !T 报错时底层必然包裹着不可随意复制的资源(堆指针或 Opaque Payload),!T 被严格定义为 线性类型 (Linear Type)。
4.1 严格的 Move 语义,杜绝 Double Free
禁止对 !T 进行隐式 = 赋值。必须使用显式的 .move 语法移交所有权。
let a = read_sensor(1) // a 是 !int
let b = a.move // ✅ 显式转移。a 死亡,底层错误资源移交给 b编译器通过静态生命周期追踪,仅在变量真正消亡的作用域代写析构函数,彻底消灭双重释放漏洞。
4.2 强制消费与通配符销毁 (let _ =)
返回 !T 的函数隐式带有 #[must_use] 属性。如果开发者刻意想要丢弃这个错误及资源,必须使用通配符模式 (Wildcard Pattern) 显式销毁:
// _ 作为匿名黑洞,签收所有权并立即引发编译器的局部析构
let _ = read_sensor(1)5. 物理层:智能 ABI 内存降级 (ABI Lowering & Memory Layout)
这是 Auto 语言最硬核的魔法。转译器 (AutoTrans) 会根据目标环境生成完全不同的底层 C/Rust 内存排布,并在 MCU 环境中通过类型哈希完美保全了增量编译。
5.1 OS 端 (a2rs 或带 malloc 的 a2c)
实现机制:胖指针与堆分配 (Trait Object / Boxed Error)
make_error在堆上分配错误信息,将指针塞入返回值。支持无限长度的堆栈追踪。向下转型依赖底层的 RTTI。
5.2 嵌入式 MCU 端 (无 malloc 的 a2c)
为满足 MISRA C 规范并支持极速增量编译,彻底摒弃 malloc 与全局 Enum。
核心机制:固定不透明载荷 (Opaque Payload) + 编译期类型哈希 (Compile-time Hash)
- 统一的内存布局:在 C 代码中生成一个全局固定、永远无需修改的结构体。大小由构建配置文件
pac.at统一指定(例如 32 字节)。
typedef struct {
uint32_t type_hash; // 编译期计算的绝对唯一 RTTI 标签
uint64_t payload_data[4]; // 不透明字节池,保证内存对齐
} AutoGlobalErrorPayload;- 零耦合的构造:当调用
make_error(SensorError)时,编译器将该类型绝对路径的 FNV-1a Hash 值(如0x8F3B1A2C)写入type_hash,并将结构体按位拷贝进payload_data。
- 静态防线:编译器在当前模块静态断言
sizeof(SensorError) <= 32,超限直接在编译期报错,防止运行栈溢出。
- 极速向下转型:
is语句在底层被翻译为简单的哈希比对与强制类型转换:
if (e.err_id->type_hash == 0x8F3B1A2C) {
SensorError_t* se = (SensorError_t*)&(e.err_id->payload_data);
// 命中逻辑...
}- 增量编译的胜利:任何模块新增 Error 类型,只需自己计算 Hash,不会引发全局头文件变更,其他无关模块绝对无需重新编译。
6. 跨界通讯 (Cross-Task Communication)
当 !T 类型跨越 Task + Msg 消息总线(BAtom 协议)时:
- 消息总线执行物化拦截 (Materialization),禁止裸指针跨界。
- 序列化引擎根据
type_hash将payload_data中的真实错误深度反序列化到 BAtom 字节流中。接收端重新构建本地的!T,确保系统级 Actor 模型的内存隔离绝对安全。
至此,关于 !T 错误处理的全套规则从高层语法到底层 C 语言内存布局已经彻底锁死,逻辑严密到足以经受任何极客的源码级审查。