Keep track of parse errors in mod
s and don't emit resolve errors for paths involving them
When we expand a `mod foo;` and parse `foo.rs`, we now track whether that file had an unrecovered parse error that reached the end of the file. If so, we keep that information around. When resolving a path like `foo::bar`, we do not emit any errors for "`bar` not found in `foo`", as we know that the parse error might have caused `bar` to not be parsed and accounted for. When this happens in an existing project, every path referencing `foo` would be an irrelevant compile error. Instead, we now skip emitting anything until `foo.rs` is fixed. Tellingly enough, we didn't have any test for errors caused by `mod` expansion. Fix #97734.
This commit is contained in:
parent
3f52583c6a
commit
69fb612608
26 changed files with 128 additions and 93 deletions
|
@ -2877,7 +2877,7 @@ pub enum ModKind {
|
|||
/// or with definition outlined to a separate file `mod foo;` and already loaded from it.
|
||||
/// The inner span is from the first token past `{` to the last token until `}`,
|
||||
/// or from the first to the last token in the loaded file.
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans),
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
|
||||
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
|
||||
Unloaded,
|
||||
}
|
||||
|
|
|
@ -1212,7 +1212,12 @@ impl WalkItemKind for ItemKind {
|
|||
ItemKind::Mod(safety, mod_kind) => {
|
||||
visit_safety(vis, safety);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
|
||||
ModKind::Loaded(
|
||||
items,
|
||||
_inline,
|
||||
ModSpans { inner_span, inject_use_span },
|
||||
_,
|
||||
) => {
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
vis.visit_span(inner_span);
|
||||
vis.visit_span(inject_use_span);
|
||||
|
|
|
@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||
ModKind::Loaded(items, _inline, _inner_span, _) => {
|
||||
walk_list!(visitor, visit_item, items);
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
|
|
|
@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
})
|
||||
}
|
||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _, spans) => {
|
||||
ModKind::Loaded(items, _, spans, _) => {
|
||||
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
|
|
|
@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
|
||||
}
|
||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
|
||||
&& !attr::contains_name(&item.attrs, sym::path)
|
||||
{
|
||||
self.check_mod_file_item_asciionly(item.ident);
|
||||
|
|
|
@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
|
||||
item.kind
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
|
||||
) = item.kind
|
||||
{
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
walk_item_kind(
|
||||
|
|
|
@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
item_inner.kind,
|
||||
ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
|
||||
)
|
||||
) =>
|
||||
{
|
||||
|
@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||
match &item.kind {
|
||||
ItemKind::Mod(_, mod_kind)
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
||||
{
|
||||
feature_err(
|
||||
self.sess,
|
||||
|
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
|
||||
let ecx = &mut collector.cx;
|
||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
||||
ModKind::Loaded(_, inline, _) => {
|
||||
ModKind::Loaded(_, inline, _, _) => {
|
||||
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||
let (dir_path, dir_ownership) = mod_dir_path(
|
||||
ecx.sess,
|
||||
|
@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
ModKind::Unloaded => {
|
||||
// We have an outline `mod foo;` so we need to parse the file.
|
||||
let old_attrs_len = attrs.len();
|
||||
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
|
||||
parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
let ParsedExternalMod {
|
||||
items,
|
||||
spans,
|
||||
file_path,
|
||||
dir_path,
|
||||
dir_ownership,
|
||||
had_parse_error,
|
||||
} = parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
|
||||
if let Some(lint_store) = ecx.lint_store {
|
||||
lint_store.pre_expansion_lint(
|
||||
|
@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
);
|
||||
}
|
||||
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans);
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
|
||||
node.attrs = attrs;
|
||||
if node.attrs.len() > old_attrs_len {
|
||||
// If we loaded an out-of-line module and added some inner attributes,
|
||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
|
|||
pub file_path: PathBuf,
|
||||
pub dir_path: PathBuf,
|
||||
pub dir_ownership: DirOwnership,
|
||||
pub had_parse_error: Result<(), ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
pub enum ModError<'a> {
|
||||
|
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
|
|||
attrs.extend(inner_attrs);
|
||||
(items, inner_span, mp.file_path)
|
||||
};
|
||||
|
||||
// (1) ...instead, we return a dummy module.
|
||||
let (items, spans, file_path) =
|
||||
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
|
||||
let ((items, spans, file_path), had_parse_error) = match result {
|
||||
Err(err) => (Default::default(), Err(err.report(sess, span))),
|
||||
Ok(result) => (result, Ok(())),
|
||||
};
|
||||
|
||||
// Extract the directory path for submodules of the module.
|
||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
||||
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
|
||||
}
|
||||
|
||||
pub(crate) fn mod_dir_path(
|
||||
|
|
|
@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
|
|||
for item in &krate.items {
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
|
||||
) = item.kind
|
||||
{
|
||||
if item.attrs.iter().any(|a| a.has_name(sym::path)) {
|
||||
|
|
|
@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
|
|||
let (inner_attrs, items, inner_span) =
|
||||
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
|
||||
attrs.extend(inner_attrs);
|
||||
ModKind::Loaded(items, Inline::Yes, inner_span)
|
||||
ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
|
||||
};
|
||||
Ok((id, ItemKind::Mod(safety, mod_kind)))
|
||||
}
|
||||
|
|
|
@ -770,7 +770,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
ItemKind::Mod(..) => {
|
||||
ItemKind::Mod(.., ref mod_kind) => {
|
||||
let module = self.r.new_module(
|
||||
Some(parent),
|
||||
ModuleKind::Def(def_kind, def_id, ident.name),
|
||||
|
@ -781,6 +781,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
|
||||
if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
|
||||
self.r.mods_with_parse_errors.insert(def_id);
|
||||
}
|
||||
|
||||
// Descend into the module.
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
|
|
@ -3056,7 +3056,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx ast::Item) {
|
||||
if self.target_module == item.id {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
|
||||
let inject = mod_spans.inject_use_span;
|
||||
if is_span_suitable_for_use_injection(inject) {
|
||||
self.first_legal_span = Some(inject);
|
||||
|
|
|
@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ignore_import: Option<Import<'ra>>,
|
||||
) -> PathResult<'ra> {
|
||||
let mut module = None;
|
||||
let mut module_had_parse_errors = false;
|
||||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
|
||||
|
@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
||||
("there are too many leading `super` keywords".to_string(), None)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
false,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| ("there are too many leading `super` keywords".to_string(), None),
|
||||
);
|
||||
}
|
||||
if segment_idx == 0 {
|
||||
if name == kw::SelfLower {
|
||||
|
@ -1511,19 +1517,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
// Report special messages for path segment keywords in wrong positions.
|
||||
if ident.is_path_segment_keyword() && segment_idx != 0 {
|
||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
||||
let name_str = if name == kw::PathRoot {
|
||||
"crate root".to_string()
|
||||
} else {
|
||||
format!("`{name}`")
|
||||
};
|
||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
||||
format!("global paths cannot start with {name_str}")
|
||||
} else {
|
||||
format!("{name_str} in paths can only be used in start position")
|
||||
};
|
||||
(label, None)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
false,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| {
|
||||
let name_str = if name == kw::PathRoot {
|
||||
"crate root".to_string()
|
||||
} else {
|
||||
format!("`{name}`")
|
||||
};
|
||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
||||
format!("global paths cannot start with {name_str}")
|
||||
} else {
|
||||
format!("{name_str} in paths can only be used in start position")
|
||||
};
|
||||
(label, None)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let binding = if let Some(module) = module {
|
||||
|
@ -1589,6 +1602,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
|
||||
if let Some(next_module) = binding.module() {
|
||||
if self.mods_with_parse_errors.contains(&next_module.def_id()) {
|
||||
module_had_parse_errors = true;
|
||||
}
|
||||
module = Some(ModuleOrUniformRoot::Module(next_module));
|
||||
record_segment_res(self, res);
|
||||
} else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
|
||||
|
@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ident,
|
||||
is_last,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| {
|
||||
let label = format!(
|
||||
|
@ -1637,19 +1654,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
return PathResult::failed(ident, is_last, finalize.is_some(), module, || {
|
||||
self.report_path_resolution_error(
|
||||
path,
|
||||
opt_ns,
|
||||
parent_scope,
|
||||
ribs,
|
||||
ignore_binding,
|
||||
ignore_import,
|
||||
module,
|
||||
segment_idx,
|
||||
ident,
|
||||
)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
is_last,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| {
|
||||
self.report_path_resolution_error(
|
||||
path,
|
||||
opt_ns,
|
||||
parent_scope,
|
||||
ribs,
|
||||
ignore_binding,
|
||||
ignore_import,
|
||||
module,
|
||||
segment_idx,
|
||||
ident,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -898,6 +898,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
label,
|
||||
suggestion,
|
||||
module,
|
||||
error_implied_by_parse_error: _,
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
|
|
|
@ -4395,6 +4395,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
|
||||
PartialRes::new(module.res().unwrap())
|
||||
}
|
||||
// A part of this path references a `mod` that had a parse error. To avoid resolution
|
||||
// errors for each reference to that module, we don't emit an error for them until the
|
||||
// `mod` is fixed. this can have a significant cascade effect.
|
||||
PathResult::Failed { error_implied_by_parse_error: true, .. } => {
|
||||
PartialRes::new(Res::Err)
|
||||
}
|
||||
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
|
||||
// don't report an error right away, but try to fallback to a primitive type.
|
||||
// So, we are still able to successfully resolve something like
|
||||
|
@ -4443,6 +4449,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
suggestion,
|
||||
module,
|
||||
segment_name,
|
||||
error_implied_by_parse_error: _,
|
||||
} => {
|
||||
return Err(respan(span, ResolutionError::FailedToResolve {
|
||||
segment: Some(segment_name),
|
||||
|
|
|
@ -450,6 +450,7 @@ enum PathResult<'ra> {
|
|||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
/// The segment name of target
|
||||
segment_name: Symbol,
|
||||
error_implied_by_parse_error: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> {
|
|||
ident: Ident,
|
||||
is_error_from_last_segment: bool,
|
||||
finalize: bool,
|
||||
error_implied_by_parse_error: bool,
|
||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||||
) -> PathResult<'ra> {
|
||||
|
@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> {
|
|||
suggestion,
|
||||
is_error_from_last_segment,
|
||||
module,
|
||||
error_implied_by_parse_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1198,6 +1201,8 @@ pub struct Resolver<'ra, 'tcx> {
|
|||
/// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo`
|
||||
/// could be a crate that wasn't imported. For diagnostics use only.
|
||||
current_crate_outer_attr_insert_span: Span,
|
||||
|
||||
mods_with_parse_errors: FxHashSet<DefId>,
|
||||
}
|
||||
|
||||
/// This provides memory for the rest of the crate. The `'ra` lifetime that is
|
||||
|
@ -1543,6 +1548,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
impl_unexpanded_invocations: Default::default(),
|
||||
impl_binding_keys: Default::default(),
|
||||
current_crate_outer_attr_insert_span,
|
||||
mods_with_parse_errors: Default::default(),
|
||||
};
|
||||
|
||||
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
||||
|
|
|
@ -166,7 +166,7 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo
|
|||
[seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
|
||||
if let InvocationKind::Attr { item, .. } = &invoc.kind {
|
||||
if let Annotatable::Item(item) = item {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
|
|||
|
||||
impl EarlyLintPass for DuplicateMod {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind
|
||||
&& let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
|
||||
&& let Some(local_path) = real.into_local_path()
|
||||
&& let Ok(absolute_path) = local_path.canonicalize()
|
||||
|
|
|
@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
|
|||
}
|
||||
|
||||
match &item.kind {
|
||||
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
|
||||
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => {
|
||||
self.nest_level += 1;
|
||||
|
||||
if !self.check_indent(item.span, item.id) {
|
||||
|
|
|
@ -379,7 +379,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
(Mod(lu, lmk), Mod(ru, rmk)) => {
|
||||
lu == ru
|
||||
&& match (lmk, rmk) {
|
||||
(ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
|
||||
(ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => {
|
||||
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
|
||||
},
|
||||
(ModKind::Unloaded, ModKind::Unloaded) => true,
|
||||
|
|
|
@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate(
|
|||
pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
|
||||
!matches!(
|
||||
item.kind,
|
||||
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
|
||||
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
|
|||
self.directory = directory;
|
||||
}
|
||||
match (sub_mod.ast_mod_kind, sub_mod.items) {
|
||||
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
|
||||
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => {
|
||||
self.visit_mod_from_ast(items)
|
||||
}
|
||||
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
|
||||
self.visit_mod_outside_ast(items)
|
||||
}
|
||||
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
|
||||
| (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
|
||||
(_, _) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||
let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
|
||||
self.push_str(&ident_str);
|
||||
|
||||
if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind {
|
||||
if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind {
|
||||
let ast::ModSpans {
|
||||
inner_span,
|
||||
inject_use_span: _,
|
||||
|
|
|
@ -4,22 +4,5 @@ error: circular modules: $DIR/circular_modules_main.rs -> $DIR/circular_modules_
|
|||
LL | mod circular_modules_main;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
|
||||
--> $DIR/circular_modules_hello.rs:7:43
|
||||
|
|
||||
LL | println!("{}", circular_modules_main::hi_str());
|
||||
| ^^^^^^ not found in `circular_modules_main`
|
||||
|
|
||||
help: consider importing this function
|
||||
|
|
||||
LL + use hi_str;
|
||||
|
|
||||
help: if you import `hi_str`, refer to it directly
|
||||
|
|
||||
LL - println!("{}", circular_modules_main::hi_str());
|
||||
LL + println!("{}", hi_str());
|
||||
|
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
|
|
|
@ -3,5 +3,5 @@ use parse_error::Canonical; //~ ERROR E0432
|
|||
|
||||
fn main() {
|
||||
let _ = "" + 1; //~ ERROR E0369
|
||||
parse_error::Canonical.foo(); //~ ERROR E0425
|
||||
parse_error::Canonical.foo(); // ok, `parse_error.rs` had parse errors
|
||||
}
|
||||
|
|
|
@ -15,12 +15,6 @@ error[E0432]: unresolved import `parse_error::Canonical`
|
|||
LL | use parse_error::Canonical;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ no `Canonical` in `parse_error`
|
||||
|
||||
error[E0425]: cannot find value `Canonical` in module `parse_error`
|
||||
--> $DIR/parse-error-resolve.rs:6:18
|
||||
|
|
||||
LL | parse_error::Canonical.foo();
|
||||
| ^^^^^^^^^ not found in `parse_error`
|
||||
|
||||
error[E0369]: cannot add `{integer}` to `&str`
|
||||
--> $DIR/parse-error-resolve.rs:5:16
|
||||
|
|
||||
|
@ -29,7 +23,7 @@ LL | let _ = "" + 1;
|
|||
| |
|
||||
| &str
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0369, E0425, E0432.
|
||||
Some errors have detailed explanations: E0369, E0432.
|
||||
For more information about an error, try `rustc --explain E0369`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue