Remember names of cfg
-ed out items to mention them in diagnostics
`#[cfg]`s are frequently used to gate crate content behind cargo features. This can lead to very confusing errors when features are missing. For example, `serde` doesn't have the `derive` feature by default. Therefore, `serde::Serialize` fails to resolve with a generic error, even though the macro is present in the docs. This commit adds a list of all stripped item names to metadata. This is filled during macro expansion and then, through a fed query, persisted in metadata. The downstream resolver can then access the metadata to look at possible candidates for mentioning in the errors. This slightly increases metadata (800k->809k for the feature-heavy windows crate), but not enough to really matter.
This commit is contained in:
parent
642c92e630
commit
a647ba250a
30 changed files with 599 additions and 84 deletions
|
@ -6,6 +6,7 @@ use crate::Namespace::*;
|
|||
use crate::{BuiltinMacroState, Determinacy};
|
||||
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::StabilityLevel;
|
||||
|
@ -465,6 +466,10 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
|
|||
self.proc_macros.push(id)
|
||||
}
|
||||
|
||||
fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem) {
|
||||
self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, name, cfg });
|
||||
}
|
||||
|
||||
fn registered_tools(&self) -> &RegisteredTools {
|
||||
&self.registered_tools
|
||||
}
|
||||
|
@ -721,7 +726,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
|
||||
let mut suggestion = None;
|
||||
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
|
||||
let (span, label, module) = if let PathResult::Failed { span, label, module, .. } = path_res {
|
||||
// try to suggest if it's not a macro, maybe a function
|
||||
if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
|
||||
&& partial_res.unresolved_segments() == 0 {
|
||||
|
@ -733,7 +738,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
Applicability::MaybeIncorrect
|
||||
));
|
||||
}
|
||||
(span, label)
|
||||
(span, label, module)
|
||||
} else {
|
||||
(
|
||||
path_span,
|
||||
|
@ -742,11 +747,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
kind.article(),
|
||||
kind.descr()
|
||||
),
|
||||
None,
|
||||
)
|
||||
};
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve { label, suggestion },
|
||||
ResolutionError::FailedToResolve { last_segment: path.last().map(|segment| segment.ident.name), label, suggestion, module },
|
||||
);
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue