Rust 编译器错误码 E0087 详解:多余的泛型类型参数与 E0107 诊断机制 Rust 编译器错误码 E0087 详解多余的泛型类型参数与 E0107 诊断机制【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本文围绕 Rust 编译器历史错误码 E0087函数被传入过多类型参数展开说明其触发条件、为何在当前编译器中不再被发出、以及取而代之的 E0107 错误的完整语义并结合 rustc 源码中的泛型参数数量诊断实现帮助读者在遇到wrong number of type arguments类报错时快速定位与修复问题。一、E0087 的核心语义类型参数数量必须精确匹配错误码 E0087 的定义非常直接给一个泛型项函数、类型等提供了过多的类型实参数量超过了其声明的类型参数个数。官方错误码文档 E0087.md 给出的经典错误示例是fn fooT() {} fn main() { foo::f64, bool(); // error: wrong number of type arguments: // expected 1, found 2 }fn fooT()只声明了 1 个类型参数T但调用点通过 Turbofish 语法::f64, bool提供了 2 个类型实参。文档中的修复原则只有一句话却抓住了本质The number of supplied arguments must exactly match the number of defined type parameters. 提供的实参数量必须与定义的类型参数数量完全一致。即调用foo的正确写法是foo::f64()或省略实参foo()当类型可从上下文推断时。二、关键事实E0087 已不再由编译器发出E0087.md 的第一行就明确标注Note: this error code is no longer emitted by the compiler. 注意该错误码不再由编译器发出。这意味着在现代 Rust 版本中你永远不可能再直接看到error[E0087]。编译器把泛型实参数量不对这一整类错误统一归并到了 E0107 之下。这一归并关系在错误码注册表中也有旁证——rustc_error_codes 的 lib.rs 中早期错误码 E0035/E0036 被注释为merged into E0087/E0089而 E0087 所在的泛型参数数量这一片区最终又进一步收敛到 E0107形成了一条清晰的错误码演化链E0035 / E0036 ──(合并)── E0087 / E0089 ──(统一归并)── E0107 数量不足 数量过多 数量不符统一诊断因此对于维护旧代码库或阅读旧 issue 时遇到的 E0087正确理解方式是把它当作E0107 的历史别名凡是历史上报 E0087 的场景今天都会以 E0107 的形式呈现。三、现代编译器中的实际表现E0107当前编译器发出的是error[E0107]消息措辞也比历史版本更精确——它不仅区分数量过多/过少还区分生命周期参数、类型参数、常量参数三类实参。E0107.md 汇总了完整的行为struct FooT { x: T } struct Bar { x: Foo } // error: wrong number of type arguments: // expected 1, found 0 struct BazS, T { x: FooS, T } // error: wrong number of type arguments: // expected 1, found 2 fn fooT, U(x: T, y: U) {} fn f() {} fn main() { let x: bool true; foo::bool(x); // error: expected 2, found 1 foo::bool, i32, i32(x, 2, 4); // error: expected 2, found 3 f::static(); // error: wrong number of lifetime arguments // expected 0, found 1 }注意第三行f::static()对没有任何生命周期参数的函数提供生命周期实参会报wrong number of lifetime arguments。这与 E0087 时代只谈type arguments的粗糙措辞形成了对比。仓库中的 UI 测试可以佐证真实诊断消息的格式。tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr 中记录了编译器对类型别名变体上多余 Turbofish 实参的输出error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied -- $DIR/enum-variant-generic-args.rs:64:5 | LL | AliasFixed::()::TSVariant(());可以看到消息模板是def_kind takes N generic argument(s) but M generic argument(s) was/were supplied并且精确标注了出错标识符的 span。对应的正确写法参数数量与声明一致struct FooT { x: T } struct BarT { x: FooT } // ok! struct BazS, T { x: FooS, y: FooT } // ok! fn fooT, U(x: T, y: U) {} fn f() {} fn main() { let x: bool true; foo::bool, u32(x, 12); // ok! f(); // ok! }四、源码级剖析WrongNumberOfGenericArgs诊断实现从源码结构看E0107即历史 E0087 场景的完整诊断逻辑集中在 rustc_hir_analysis 的 wrong_number_of_generic_args.rs 中。理解该文件即可理解数量不匹配报错的每一处细节。4.1 状态结构一次诊断需要哪些输入核心是WrongNumberOfGenericArgs结构体源码 L10-L33它把判定所需的全部上下文一次性收集齐字段含义gen_params目标类型/特征期望的泛型参数ty::Genericsgen_args用户在调用点实际提供的hir::GenericArgsgen_args_info描述缺失/冗余实参的种类与数量见下angle_brackets角括号...的三种形态见下path_segment出错的 HIR 路径段用于定位 spanparams_offset处理缺失/冗余实参时的参数索引偏移是否含Self、生命周期参数数量等4.2 两类状态枚举精确定位缺了什么与多给了什么GenericArgsInfo源码 L51-L86区分四种情形MissingLifetimes { num_missing_args }缺生命周期实参ExcessLifetimes { num_redundant_args }多余生命周期实参MissingTypesOrConsts { num_missing_args, num_default_params, args_offset }缺类型/常量实参ExcessTypesOrConsts { num_redundant_args, num_default_params, args_offset, synth_provided }多余类型/常量实参——E0087 的场景就落在ExcessTypesOrConsts这一分支上其中num_default_params字段值得注意由于 Rust 支持类型参数默认值如struct FooT u8期望数量存在上下界诊断消息会相应使用 at least N / at most N 的措辞由get_quantifier_and_bound方法生成见 源码 L305-L325。而synth_provided则标记用户是否显式写入了impl Trait这类编译器不允许的合成实参诊断会追加 noteimpl Trait cannot be explicitly specified as a generic argument源码 L1141-L1147。AngleBrackets枚举源码 L38-L47则刻画调用点写法的三种形态Missing完全没写角括号如struct Bar { x: Foo }Implied没写角括号但存在被省略的实参如str中的省略生命周期Available写了角括号但实参数量不对如foo::f64, bool——E0087 示例正是这一形态new构造函数源码 L89-L114通过gen_args.span_ext().is_none()来区分这三种形态没有 span 且实参列表为空是Missing没有 span 但存在省略实参是Implied否则是Available。4.3 消息与高亮expected N与supplied M历史文档中的注释expected 1, found 2对应的现代实现是notify方法源码 L546-L596它在标识符 span 上标注expected 量化词N lifetime/generic argument(s)再对已提供的实参逐个标注最后一个标注supplied M ... argument(s)。一个体现诊断细致之处的细节当实参过多时too_many_args_provided()notify会提前返回、不逐个高亮实参——因为此时另有删除冗余实参的建议suggest_removing_args_or_generics二者叠加会造成标注重叠源码 L561-L571 的注释给出了示意。4.4 自动修复建议删掉多余参数对 E0087 场景实参过多编译器不只报错还会给出可应用的修复建议。suggest_removing_args_or_generics源码 L902 起的策略包括删除整个角括号当冗余实参数 ≥ 全部实参数时建议remove the unnecessary generics即把foo::f64, bool()修复为foo()。注意 源码 L1070-L1078 中有一段专门避免 ICE 的 HACK若同一作用域内存在同名但非泛型的类型例如derive展开产生的重复定义空 span 建议会触发断言故此处显式跳过删除部分冗余实参仅删除超过期望数量的那一段 span建议文案为remove the unnecessary generic argument(s)改写为关联项绑定当目标是一个 trait且未绑定的关联项数量恰好等于冗余实参数量时编译器会建议把多余实参改写为关联项绑定turn the generic argument(s) into an associated item binding(s)源码 L1010-L1051。例如对Iteratoru32多给一个类型参数时可提示改为u32 as Iterator::Item ...这类绑定写法把多余实参移到 trait 上对关联函数调用如Into::into::T(x)给出consider moving this generic argument to the Into trait的多部分建议suggest_moving_args_from_assoc_fn_to_trait源码 L759-L895。对于实参过少的场景对应的suggest_adding_args系列方法会基于参数名甚至上下文函数参数位推断_、静态/常量上下文推断static、方法调用 Turbofish 中推断_生成add missing generic argument(s)建议源码 L626-L751。4.5 最终装配错误码 E0107 在此被写死诊断的最终装配发生在Diagnostictrait 实现中源码 L1150-L1168let msg self.create_error_message(); let mut err Diag::new(dcx, level, msg); err.code(E0107); err.span(self.path_segment.ident.span); self.notify(mut err); self.suggest(mut err); self.show_definition(mut err); self.note_synth_provided(mut err);这一行err.code(E0107)从实现层面证实了第二节的结论所有泛型实参数量不匹配含历史 E0087 的过多场景如今统一以 E0107 发出。此外show_definition源码 L1094-L1138还会在定义处追加 note形如type defined here, with 1 generic parameter: T把调用点与定义点关联起来。五、遇到此类报错的排查清单结合上述文档与源码遇到wrong number of type/lifetime argumentsE0107时可按以下步骤处理读 span 标注expected N generic argument(s)标在标识符上supplied M标在实参上N 与 M 的差值就是需要增删的实参数量对照定义根据 note 中defined here, with ... parameter(s)定位定义确认参数列表注意区分生命周期参数与类型/常量参数二者按顺序排列且各自计数区分过少与过多过少补齐实参或采用编译器建议的占位符_/ 推断尤其是 Turbofish 中的_过多即历史 E0087删除冗余实参若目标是 trait检查是否该写成关联项绑定或把实参挪到 trait 路径段上注意默认参数带默认值的类型参数允许实参数量少于参数总数at least N此时报错信息中的下界措辞来自get_quantifier_and_bound的逻辑旧文档迁移若在旧博客/旧 issue 中看到 E0087直接按 E0107 语义理解即可二者修复方法完全一致。六、参考资料索引内容仓库路径E0087 错误码文档历史含本文起始示例E0087.mdE0107 错误码文档现行含完整正/误示例E0107.md错误码归并注释E0035/E0036 → E0087/E0089lib.rs数量不匹配诊断的完整实现wrong_number_of_generic_args.rs真实诊断消息样例含 span 与消息格式enum-variant-generic-args.stderr【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考