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.
|
/// 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 `}`,
|
/// 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.
|
/// 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.
|
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
|
||||||
Unloaded,
|
Unloaded,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1212,7 +1212,12 @@ impl WalkItemKind for ItemKind {
|
||||||
ItemKind::Mod(safety, mod_kind) => {
|
ItemKind::Mod(safety, mod_kind) => {
|
||||||
visit_safety(vis, safety);
|
visit_safety(vis, safety);
|
||||||
match mod_kind {
|
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));
|
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||||
vis.visit_span(inner_span);
|
vis.visit_span(inner_span);
|
||||||
vis.visit_span(inject_use_span);
|
vis.visit_span(inject_use_span);
|
||||||
|
|
|
@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
|
||||||
try_visit!(visitor.visit_fn(kind, span, id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
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);
|
walk_list!(visitor, visit_item, items);
|
||||||
}
|
}
|
||||||
ModKind::Unloaded => {}
|
ModKind::Unloaded => {}
|
||||||
|
|
|
@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||||
ModKind::Loaded(items, _, spans) => {
|
ModKind::Loaded(items, _, spans, _) => {
|
||||||
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
||||||
}
|
}
|
||||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
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" });
|
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
|
||||||
}
|
}
|
||||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
// 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)
|
&& !attr::contains_name(&item.attrs, sym::path)
|
||||||
{
|
{
|
||||||
self.check_mod_file_item_asciionly(item.ident);
|
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
|
// We don't want to recurse into anything other than mods, since
|
||||||
// mods or tests inside of functions will break things
|
// mods or tests inside of functions will break things
|
||||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
|
if let ast::ItemKind::Mod(
|
||||||
item.kind
|
_,
|
||||||
|
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
|
||||||
|
) = item.kind
|
||||||
{
|
{
|
||||||
let prev_tests = mem::take(&mut self.tests);
|
let prev_tests = mem::take(&mut self.tests);
|
||||||
walk_item_kind(
|
walk_item_kind(
|
||||||
|
|
|
@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
item_inner.kind,
|
item_inner.kind,
|
||||||
ItemKind::Mod(
|
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) {
|
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
ItemKind::Mod(_, mod_kind)
|
ItemKind::Mod(_, mod_kind)
|
||||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
|
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
||||||
{
|
{
|
||||||
feature_err(
|
feature_err(
|
||||||
self.sess,
|
self.sess,
|
||||||
|
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
||||||
|
|
||||||
let ecx = &mut collector.cx;
|
let ecx = &mut collector.cx;
|
||||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
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.
|
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||||
let (dir_path, dir_ownership) = mod_dir_path(
|
let (dir_path, dir_ownership) = mod_dir_path(
|
||||||
ecx.sess,
|
ecx.sess,
|
||||||
|
@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
|
||||||
ModKind::Unloaded => {
|
ModKind::Unloaded => {
|
||||||
// We have an outline `mod foo;` so we need to parse the file.
|
// We have an outline `mod foo;` so we need to parse the file.
|
||||||
let old_attrs_len = attrs.len();
|
let old_attrs_len = attrs.len();
|
||||||
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
|
let ParsedExternalMod {
|
||||||
parse_external_mod(
|
items,
|
||||||
ecx.sess,
|
spans,
|
||||||
ident,
|
file_path,
|
||||||
span,
|
dir_path,
|
||||||
&ecx.current_expansion.module,
|
dir_ownership,
|
||||||
ecx.current_expansion.dir_ownership,
|
had_parse_error,
|
||||||
&mut attrs,
|
} = 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 {
|
if let Some(lint_store) = ecx.lint_store {
|
||||||
lint_store.pre_expansion_lint(
|
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;
|
node.attrs = attrs;
|
||||||
if node.attrs.len() > old_attrs_len {
|
if node.attrs.len() > old_attrs_len {
|
||||||
// If we loaded an out-of-line module and added some inner attributes,
|
// 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 file_path: PathBuf,
|
||||||
pub dir_path: PathBuf,
|
pub dir_path: PathBuf,
|
||||||
pub dir_ownership: DirOwnership,
|
pub dir_ownership: DirOwnership,
|
||||||
|
pub had_parse_error: Result<(), ErrorGuaranteed>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ModError<'a> {
|
pub enum ModError<'a> {
|
||||||
|
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
|
||||||
attrs.extend(inner_attrs);
|
attrs.extend(inner_attrs);
|
||||||
(items, inner_span, mp.file_path)
|
(items, inner_span, mp.file_path)
|
||||||
};
|
};
|
||||||
|
|
||||||
// (1) ...instead, we return a dummy module.
|
// (1) ...instead, we return a dummy module.
|
||||||
let (items, spans, file_path) =
|
let ((items, spans, file_path), had_parse_error) = match result {
|
||||||
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
|
Err(err) => (Default::default(), Err(err.report(sess, span))),
|
||||||
|
Ok(result) => (result, Ok(())),
|
||||||
|
};
|
||||||
|
|
||||||
// Extract the directory path for submodules of the module.
|
// Extract the directory path for submodules of the module.
|
||||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
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(
|
pub(crate) fn mod_dir_path(
|
||||||
|
|
|
@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
|
||||||
for item in &krate.items {
|
for item in &krate.items {
|
||||||
if let ast::ItemKind::Mod(
|
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
|
) = item.kind
|
||||||
{
|
{
|
||||||
if item.attrs.iter().any(|a| a.has_name(sym::path)) {
|
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) =
|
let (inner_attrs, items, inner_span) =
|
||||||
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
|
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
|
||||||
attrs.extend(inner_attrs);
|
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)))
|
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(
|
let module = self.r.new_module(
|
||||||
Some(parent),
|
Some(parent),
|
||||||
ModuleKind::Def(def_kind, def_id, ident.name),
|
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));
|
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.
|
// Descend into the module.
|
||||||
self.parent_scope.module = 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) {
|
fn visit_item(&mut self, item: &'tcx ast::Item) {
|
||||||
if self.target_module == item.id {
|
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;
|
let inject = mod_spans.inject_use_span;
|
||||||
if is_span_suitable_for_use_injection(inject) {
|
if is_span_suitable_for_use_injection(inject) {
|
||||||
self.first_legal_span = Some(inject);
|
self.first_legal_span = Some(inject);
|
||||||
|
|
|
@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
ignore_import: Option<Import<'ra>>,
|
ignore_import: Option<Import<'ra>>,
|
||||||
) -> PathResult<'ra> {
|
) -> PathResult<'ra> {
|
||||||
let mut module = None;
|
let mut module = None;
|
||||||
|
let mut module_had_parse_errors = false;
|
||||||
let mut allow_super = true;
|
let mut allow_super = true;
|
||||||
let mut second_binding = None;
|
let mut second_binding = None;
|
||||||
|
|
||||||
|
@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
return PathResult::failed(
|
||||||
("there are too many leading `super` keywords".to_string(), None)
|
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 segment_idx == 0 {
|
||||||
if name == kw::SelfLower {
|
if name == kw::SelfLower {
|
||||||
|
@ -1511,19 +1517,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
|
|
||||||
// Report special messages for path segment keywords in wrong positions.
|
// Report special messages for path segment keywords in wrong positions.
|
||||||
if ident.is_path_segment_keyword() && segment_idx != 0 {
|
if ident.is_path_segment_keyword() && segment_idx != 0 {
|
||||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
return PathResult::failed(
|
||||||
let name_str = if name == kw::PathRoot {
|
ident,
|
||||||
"crate root".to_string()
|
false,
|
||||||
} else {
|
finalize.is_some(),
|
||||||
format!("`{name}`")
|
module_had_parse_errors,
|
||||||
};
|
module,
|
||||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
|| {
|
||||||
format!("global paths cannot start with {name_str}")
|
let name_str = if name == kw::PathRoot {
|
||||||
} else {
|
"crate root".to_string()
|
||||||
format!("{name_str} in paths can only be used in start position")
|
} else {
|
||||||
};
|
format!("`{name}`")
|
||||||
(label, None)
|
};
|
||||||
});
|
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 {
|
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);
|
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
|
||||||
if let Some(next_module) = binding.module() {
|
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));
|
module = Some(ModuleOrUniformRoot::Module(next_module));
|
||||||
record_segment_res(self, res);
|
record_segment_res(self, res);
|
||||||
} else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
|
} else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
|
||||||
|
@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
ident,
|
ident,
|
||||||
is_last,
|
is_last,
|
||||||
finalize.is_some(),
|
finalize.is_some(),
|
||||||
|
module_had_parse_errors,
|
||||||
module,
|
module,
|
||||||
|| {
|
|| {
|
||||||
let label = format!(
|
let label = format!(
|
||||||
|
@ -1637,19 +1654,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PathResult::failed(ident, is_last, finalize.is_some(), module, || {
|
return PathResult::failed(
|
||||||
self.report_path_resolution_error(
|
ident,
|
||||||
path,
|
is_last,
|
||||||
opt_ns,
|
finalize.is_some(),
|
||||||
parent_scope,
|
module_had_parse_errors,
|
||||||
ribs,
|
module,
|
||||||
ignore_binding,
|
|| {
|
||||||
ignore_import,
|
self.report_path_resolution_error(
|
||||||
module,
|
path,
|
||||||
segment_idx,
|
opt_ns,
|
||||||
ident,
|
parent_scope,
|
||||||
)
|
ribs,
|
||||||
});
|
ignore_binding,
|
||||||
|
ignore_import,
|
||||||
|
module,
|
||||||
|
segment_idx,
|
||||||
|
ident,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,6 +898,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
||||||
label,
|
label,
|
||||||
suggestion,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
|
error_implied_by_parse_error: _,
|
||||||
} => {
|
} => {
|
||||||
if no_ambiguity {
|
if no_ambiguity {
|
||||||
assert!(import.imported_module.get().is_none());
|
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() => {
|
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
|
||||||
PartialRes::new(module.res().unwrap())
|
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
|
// 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.
|
// 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
|
// 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,
|
suggestion,
|
||||||
module,
|
module,
|
||||||
segment_name,
|
segment_name,
|
||||||
|
error_implied_by_parse_error: _,
|
||||||
} => {
|
} => {
|
||||||
return Err(respan(span, ResolutionError::FailedToResolve {
|
return Err(respan(span, ResolutionError::FailedToResolve {
|
||||||
segment: Some(segment_name),
|
segment: Some(segment_name),
|
||||||
|
|
|
@ -450,6 +450,7 @@ enum PathResult<'ra> {
|
||||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||||
/// The segment name of target
|
/// The segment name of target
|
||||||
segment_name: Symbol,
|
segment_name: Symbol,
|
||||||
|
error_implied_by_parse_error: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
is_error_from_last_segment: bool,
|
is_error_from_last_segment: bool,
|
||||||
finalize: bool,
|
finalize: bool,
|
||||||
|
error_implied_by_parse_error: bool,
|
||||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||||||
) -> PathResult<'ra> {
|
) -> PathResult<'ra> {
|
||||||
|
@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> {
|
||||||
suggestion,
|
suggestion,
|
||||||
is_error_from_last_segment,
|
is_error_from_last_segment,
|
||||||
module,
|
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`
|
/// 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.
|
/// could be a crate that wasn't imported. For diagnostics use only.
|
||||||
current_crate_outer_attr_insert_span: Span,
|
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
|
/// 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_unexpanded_invocations: Default::default(),
|
||||||
impl_binding_keys: Default::default(),
|
impl_binding_keys: Default::default(),
|
||||||
current_crate_outer_attr_insert_span,
|
current_crate_outer_attr_insert_span,
|
||||||
|
mods_with_parse_errors: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
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 => {
|
[seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
|
||||||
if let InvocationKind::Attr { item, .. } = &invoc.kind {
|
if let InvocationKind::Attr { item, .. } = &invoc.kind {
|
||||||
if let Annotatable::Item(item) = item {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
|
||||||
|
|
||||||
impl EarlyLintPass for DuplicateMod {
|
impl EarlyLintPass for DuplicateMod {
|
||||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
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 FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
|
||||||
&& let Some(local_path) = real.into_local_path()
|
&& let Some(local_path) = real.into_local_path()
|
||||||
&& let Ok(absolute_path) = local_path.canonicalize()
|
&& let Ok(absolute_path) = local_path.canonicalize()
|
||||||
|
|
|
@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match &item.kind {
|
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;
|
self.nest_level += 1;
|
||||||
|
|
||||||
if !self.check_indent(item.span, item.id) {
|
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)) => {
|
(Mod(lu, lmk), Mod(ru, rmk)) => {
|
||||||
lu == ru
|
lu == ru
|
||||||
&& match (lmk, rmk) {
|
&& 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))
|
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
|
||||||
},
|
},
|
||||||
(ModKind::Unloaded, ModKind::Unloaded) => true,
|
(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 {
|
pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
|
||||||
!matches!(
|
!matches!(
|
||||||
item.kind,
|
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;
|
self.directory = directory;
|
||||||
}
|
}
|
||||||
match (sub_mod.ast_mod_kind, sub_mod.items) {
|
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)
|
self.visit_mod_from_ast(items)
|
||||||
}
|
}
|
||||||
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
|
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
|
||||||
self.visit_mod_outside_ast(items)
|
| (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
|
||||||
}
|
|
||||||
(_, _) => Ok(()),
|
(_, _) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||||
let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
|
let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
|
||||||
self.push_str(&ident_str);
|
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 {
|
let ast::ModSpans {
|
||||||
inner_span,
|
inner_span,
|
||||||
inject_use_span: _,
|
inject_use_span: _,
|
||||||
|
|
|
@ -4,22 +4,5 @@ error: circular modules: $DIR/circular_modules_main.rs -> $DIR/circular_modules_
|
||||||
LL | mod circular_modules_main;
|
LL | mod circular_modules_main;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
|
error: aborting due to 1 previous error
|
||||||
--> $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 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() {
|
fn main() {
|
||||||
let _ = "" + 1; //~ ERROR E0369
|
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;
|
LL | use parse_error::Canonical;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ no `Canonical` in `parse_error`
|
| ^^^^^^^^^^^^^^^^^^^^^^ 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`
|
error[E0369]: cannot add `{integer}` to `&str`
|
||||||
--> $DIR/parse-error-resolve.rs:5:16
|
--> $DIR/parse-error-resolve.rs:5:16
|
||||||
|
|
|
|
||||||
|
@ -29,7 +23,7 @@ LL | let _ = "" + 1;
|
||||||
| |
|
| |
|
||||||
| &str
|
| &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`.
|
For more information about an error, try `rustc --explain E0369`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue