ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Rust 编译器错误 E0806 详解:Externally Implementable Item 声明与实现签名不兼容

Rust 编译器错误 E0806 详解:Externally Implementable Item 声明与实现签名不兼容 Rust 编译器错误 E0806 详解Externally Implementable Item 声明与实现签名不兼容【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust导读E0806 是 rustc 针对「外部可实现项Externally Implementable Item, EII」引入的诊断——当你在某项上标注了 EII 属性例如#[eii(foo)]或稳定代码中常见的#[panic_handler]但其实现签名与声明不一致时编译器会报出该错误。本文从官方错误文档出发结合当前仓库中compare_eii.rs的源码实现完整讲解 EII 机制的背景、E0806 的触发条件、典型场景no_std下的 panic handler以及编译器的具体检查流程帮助你快速定位并修复此类签名不匹配问题。1. 错误定义什么情况下触发 E0806E0806 官方错误文档 给出的定义是An externally implementable item is not compatible with its declaration. 一个外部可实现项与其声明不兼容。其核心机制是声明方用#[eii(name)]属性声明这个项允许被外部实现实现方则用#[name]属性提供具体实现。实现函数的签名必须与声明项的签名完全兼容参数个数、参数类型、返回类型、生命周期数量等否则编译器报 E0806。2. 背景什么是 Externally Implementable ItemEIIEII 是 Rust 中一种允许标准库/基础库把某个项的签名固定下来、实现留给下游 crate的机制。它取代了旧式#[lang]标记方案典型应用就是#[panic_handler]core固定了panic_impl的签名用户在自己的no_stdcrate 里用#[panic_handler]提供实现。在当前仓库中EII 处于不稳定特性阶段特性开关为extern_item_impls在 unstable.rs 中登记为incomplete状态追踪 issue 为 125418对应的两个内建宏#[eii]与#[unsafe_eii]定义在 core 的宏模块均标注#[unstable(feature extern_item_impls, issue 125418)]并标记为#[rustc_builtin_macro]编译器内建宏无 Rust 侧展开体另有eii_internals这一 internal 特性支撑#[eii_declaration]等内部细节。适用前提直接写#![feature(extern_item_impls)]#[eii(foo)]需要 nightly 工具链而#[panic_handler]在no_std场景下是稳定路径但同样受 EII 兼容规则约束是日常开发中最常触发 E0806 的地方。3. 官方文档的最小复现与修复错误文档给出的最简触发示例完整代码见 E0806.md#![feature(extern_item_impls)] #[eii(foo)] fn x(); #[foo] fn y(a: u64) - u64 { //~^ ERROR E0806 a } fn main() {}这里y声称实现 EIIfoo但y的签名(u64) - u64与声明x无参、无显式返回类型不符因此在y上报 E0806。修复方式是让实现签名匹配声明#![feature(extern_item_impls)] #[eii(foo)] fn x(); #[foo] fn y() {} fn main() {}经验法则看到 E0806 时先找到声明项通常由#[eii]标记或标准库中的固定声明逐一对比实现项的参数个数、参数类型、返回类型与生命周期。4. 典型实战场景#[panic_handler]写错签名官方文档特别指出#[panic_handler]签名写错是触发 E0806 的常见方式。在no_std项目中panic handler 的签名由core决定#![no_std] #[panic_handler] fn on_panic() - ! { //~^ ERROR E0806 loop {} } fn main() {}无参版本会报 E0806正确写法必须携带PanicInfo参数#![no_std] #[panic_handler] fn on_panic(info: core::panic::PanicInfo_) - ! { loop {} } fn main() {}这个要求在源码中可以直接印证core/src/panicking.rs 中panic_fmt通过一个unsafe extern Rust块声明了#[lang panic_impl]的固定签名unsafe extern Rust { #[lang panic_impl] fn panic_impl(pi: PanicInfo_) - !; }从源码结构看panic_impl这个声明就是你写#[panic_handler]时必须兼容的那个 EII 声明——参数必须是PanicInfo_返回!。少写参数如上文fn on_panic()即被判定为签名不兼容。5. 源码剖析rustc 如何检查 EII 兼容性E0806 的检查逻辑集中在 rustc_hir_analysis/src/check/compare_eii.rs。文件开头注释说明它与compare_impl_item非常相似——同样是拿一份签名声明去比对实现区别在于 EII 比对的是自由项freestanding item不涉及 self 类型。对函数型 EII核心入口是compare_eii_function_typesL37-L156检查按顺序分四步5.1 目标种类检查check_eii_target确认实现项与声明项的种类一致L227-L268函数对函数、静态项对静态项。特别地两个Static之间还比较可变性mutability与安全性safety不一致时分别报EiiDefkindMismatchStaticMutability/EiiDefkindMismatchStaticSafety。5.2 结构兼容性检查check_is_structurally_compatible在走类型推断之前先做三项廉价的结构性校验L275-L286禁止泛型参数check_no_genericsL289-L315EII 实现不能带泛型参数。源码注释解释了细节——由#[eii]宏自动生成的实现直接引用外部项这类内部生成的泛型实现会被跳过以免重复报错参数个数检查check_number_of_argumentsL355-L451直接比较tcx.fn_sig的inputs()长度。不一致时发出的正是带 E0806 代码的struct_span_code_err!消息形如{name} has 1 parameter(s) but #[eii_name] requires it to have 0并在声明处标注 requires N parameter(s)、在实现处标注 expected N, found M、在属性处标注 required because of this attribute早期绑定生命周期数量检查check_early_region_boundsL317-L353实现与声明的 lifetime 参数个数必须一致不一致报LifetimesOrBoundsMismatchOnEii。5.3 完整签名的子类型推导结构性检查通过后编译器构造一个推断上下文InferCtxt与ObligationCtxt取出声明的函数签名declaration_sig与实现的签名external_impl_sig执行let result ocx.sup(cause, param_env, declaration_sig, external_impl_sig);即验证declaration_sig : external_impl_sig声明签名是实现签名的子类型。推导失败时report_eii_mismatchL453-L525发出 E0806消息为function{name}has a type that is incompatible with the declaration of#[eii_name]值得注意的是诊断细节当差异是返回类型TypeError::ArgumentMutability/ArgumentSorts且i恰为参数个数时若实现是普通同步函数诊断会附带机器可应用MachineApplicable的修改建议——把返回类型替换为声明的返回类型- {declaration_sig.output()}当差异在某个参数上时则建议change the parameter type to match the declaration。最后还通过infcx.resolve_regions解决所有区域约束专门用来捕获生命周期参数的错误用法。5.4 静态项的 E0806静态项走独立的compare_eii_staticsL158-L225用ocx.sup比较声明类型与静态项类型失败时消息为static{name}has a type that is incompatible with the declaration of#[eii_name]并在 EII 属性处补充 note expected this because of this attribute。6. 排查清单结合文档与源码遇到 E0806 时可按以下顺序自查检查项对应源码说明属性标注在正确种类上check_eii_targetfn实现fn声明、static实现static声明static还需 mutability/safety 一致参数个数一致check_number_of_arguments诊断会直接给出 expected/found 个数参数与返回类型一致ocx.sup推导 report_eii_mismatch诊断常附机器可应用的类型替换建议可直接采纳生命周期数量一致check_early_region_bounds实现不能比声明多/少 lifetime 参数不带泛型参数check_no_genericsEII 实现不支持泛型对照标准库固定声明如 panicking.rs#[panic_handler]必须匹配fn panic_impl(pi: PanicInfo_) - !7. 小结E0806 的本质只有一句话带 EII 属性的项其签名必须与其声明兼容。声明是契约由标准库或#[eii]项固定实现是履约编译器用参数个数、生命周期数量、泛型禁用与完整的子类型推导逐层验证契约是否成立。理解这一机制后无论是 nightly 下实验#[eii]还是在no_std项目中编写#[panic_handler]都能在编译期立刻定位签名偏差并按诊断建议修复。相关源码入口错误定义compiler/rustc_error_codes/src/error_codes/E0806.md检查实现compiler/rustc_hir_analysis/src/check/compare_eii.rsEII 宏定义library/core/src/macros/mod.rs特性登记compiler/rustc_feature/src/unstable.rs标准库声明示例library/core/src/panicking.rs【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表