拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Rust E0577 深度解析:为什么 pub(in path) 可见性路径中出现了非模块

Rust E0577 深度解析为什么 pub(in path) 可见性路径中出现了非模块【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust在 Rust 中使用 2018 及以后版本的pub(in path)可见性语法时如果路径解析到的目标不是模块module编译器会报出 E0577 错误expected module, found ...。本文围绕官方错误码文档 E0577.md 展开先完整呈现官方文档中的错误示例与修复方式再深入 rustc 名称解析resolve阶段的源码说明该错误是在哪个环节、依据什么规则被触发的并梳理与 E0578、E0742 等相邻可见性错误的区别与适用前提帮助你在实际开发中快速定位和修复这类可见性配置错误。E0577 错误码是什么E0577 的官方定义标题是Something other than a module was found in visibility scope在可见性作用域中找到了非模块。在 2018 edition 引入的可见性限定语法中pub(in path)要求path最终必须解析到一个模块。编译器在 resolve 阶段为该错误生成的诊断消息是expected module, found {$res} {$path_str}并附带not a module的标注。这一诊断结构定义在 diagnostics/mod.rs 中#[derive(Diagnostic)] #[diag(expected module, found {$res} {$path_str}, code E0577)] pub(crate) struct ExpectedModuleFound { #[primary_span] #[label(not a module)] pub(crate) span: Span, pub(crate) res: Res, pub(crate) path_str: String, }其中res是实际解析到的定义种类enum、struct、fn 等path_str是你写下的可见性路径字符串。错误消息中 found enum 或 found struct 这类措辞就是由{$res}格式化而来。官方文档的完整示例错误与修复官方文档 E0577.md 给出的最小复现代码如下edition2018预期编译失败pub enum Sea {} pub (in crate::Sea) struct Shark; // error! fn main() {}这里Sea是一个枚举enum而不是模块因此把它用进pub(in crate::Sea)的可见性路径是非法的。编译器会指出crate::Sea这个路径 expected module, found enumSea。修复方式与官方文档一致——确保可见性路径中的每一项都是模块pub mod sea { pub (in crate::sea) struct Shark; // ok! } fn main() {}把Sea改成模块sea后crate::sea解析到的是一个真正的模块Shark的可见性被合法地限定为在crate::sea模块内可见。官方文档还特别强调了一点可见性作用域只能应用到祖先模块上the visibility scope can only be applied on ancestors。也就是说pub(in path)中的模块必须是当前项的父级模块crate 根或逐级嵌套的祖先不能是平级或下级模块——违反这条规则会报 E0742visibilities can only be restricted to ancestor modules而不是 E0577。源码级剖析E0577 是在哪一步触发的E0577 由 rustc 的 resolve 阶段crate 级名称解析发出。追踪源码调用链可以看到完整的触发路径可见性路径的解析入口可见性路径的解析发生在构建reduced graph降低后的解析图期间核心代码位于 build_reduced_graph.rs。其中有一段关键的版本edition处理逻辑let ident path.segments.get(0).expect(empty path in visibility).ident; let crate_root if ident.is_path_segment_keyword() { None } else if ident.span.is_rust_2015() { Some(Segment::from_ident(Ident::new( kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()), ))) } else { return Err(VisResolutionError::Relative2018( ident.span, path.as_ref().clone(), )); };从源码结构看这段逻辑可以推断出两条重要规则路径首段必须是关键字段crate、self、super等。否则在 2015 edition 下编译器会自动补一个 crate 根即crate::前缀而在 2018 edition 及以后直接报Relative2018错误——relative paths are not supported in visibilities in 2018 edition or later并建议改写为crate::{path}。路径解析通过resolve_path完成如果解析成功但目标不是一个模块就走下面定义的expected_found_error闭包let expected_found_error |res| { Err(VisResolutionError::ExpectedFound( path.span, Segment::names_to_string(segments), res, )) };VisResolutionError::ExpectedFound(span, path_str, res)正是携带路径 span、路径字符串、实际解析结果三元组的错误变体——与诊断结构ExpectedModuleFound的字段一一对应。错误上报report_vis_error所有可见性解析错误最终统一由 diagnostics/impls.rs 中的report_vis_error分发处理VisResolutionError::ExpectedFound(span, path_str, res) { self.dcx().create_err(diagnostics::ExpectedModuleFound { span, res, path_str }) }这一行即 E0577 的最终出口。同函数中还能看到可见性错误家族的其余成员便于区分变体错误码消息触发条件Relative2018—建议型诊断relative paths are not supported in visibilities in 2018 edition or later2018 下可见性路径以非关键字开头AncestorOnlyE0742visibilities can only be restricted to ancestor modules可见性指向的不是祖先模块ExpectedFoundE0577expected module, found{$res}{$path}路径解析成功但目标不是模块IndeterminateE0578cannot determine resolution for the visibility可见性路径无法确定解析ModuleOnly—visibility must resolve to a module可见性必须解析到模块注意一个容易混淆的边界路径根本不存在拼错模块名报的是 E0433 一类的找不到路径错误路径存在但解析到非模块enum、struct、fn 等才报 E0577。E0577 的复用restrictions 场景值得注意的一点是E0577 并非只服务于pub(in path)。在 late.rs 的路径来源PathSource错误码映射中可以看到// FIXME: There is no dedicated error code for this case yet. // E0577 already covers the same situation for visibilities, // so we reuse it here for now. It may make sense to generalize // it for restrictions in the future. (PathSource::Module, true) E0577, (PathSource::Module, false) E0433,源码注释明确说明对于期望是模块但发现了其他东西的 restriction 场景例如精确捕获use项时用到的crate::...限定编译器暂时复用了 E0577。因此看到 E0577 时可以确认报错位置期望出现模块的地方出现了非模块项这一语义是稳定的但具体来源可能是可见性路径也可能是 restriction 路径。如何避免与修复 E0577结合官方文档与源码规则可以归纳出以下检查清单逐项确认路径上每一段都是模块。pub(in crate::a::b)要求crate::a和a::b都是模块。若某一段是 enum、struct、trait 等就会触发expected_found_error报出 E0577。2018 edition 起路径必须以关键字开头。可见性路径不能写成相对路径如pub(in sea) ...必须写成crate::sea2015 edition 则会自动按 crate 根解析。可见性目标必须是祖先模块。pub(in crate::foo)只能用于foo内部或其更深层的项。对平级模块使用会报 E0742。区分 E0577 与 E0578E0578cannot determine resolution for the visibility表示可见性路径无法确定解析结果例如路径段落在多个命名空间中产生歧义而 E0577 表示路径已解析成功但目标不是模块。用官方错误文档示例做本地验证官方文档中的示例采用 rustc 测试注解格式compile_fail,E0577,edition2018可以直接作为手工复现用例。把错误示例保存为独立文件后用 rustc 按 2018 edition 编译即可看到诊断输出rustc --edition2018 error.rs预期输出形如error: expected module, found enum Sea -- error.rs:3:10 | 3 | pub (in crate::Sea) struct Shark; // error! | ^^^^^^^^ not a module | note: see the Error... E0577修复后将Sea改为pub mod sea { ... }同一命令应无任何报错。这一预期失败 → 修复 → 编译通过的验证闭环也正是仓库中 UI 测试以.rs测试文件加.stderr预期输出文件的形式组织的原因参见 tests/ui 目录。小结E0577 的语义是期望模块却发现了非模块项在pub(in path)可见性语法中最常遇到其诊断结构ExpectedModuleFound定义于 diagnostics/mod.rs。触发点位于 resolve 阶段build_reduced_graph.rs 负责可见性路径的解析与 edition 规则检查diagnostics/impls.rs 的report_vis_error负责最终上报。修复思路只有一个方向让可见性路径的每一段都落在真正的模块上且该模块是当前项的祖先模块2018 edition 及以后还必须以crate/self/super等关键字开头。E0577 还与 E0578可见性无法确定解析、E0742非祖先模块同属可见性错误家族三者的区分关键在于解析成功与否以及目标是否为祖先模块。理解这一错误码的完整链路——从语法约束、resolve 阶段的解析逻辑到诊断消息的生成——能让你在遇到expected module, found ...报错时不必反复试错直接对照上述规则定位是路径段写错了种类、版本规则不匹配还是祖先约束被违反。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门