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
|
@ -1,8 +1,10 @@
|
|||
use std::ptr;
|
||||
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
|
||||
use rustc_ast::{MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
|
@ -776,7 +778,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
.tcx
|
||||
.sess
|
||||
.create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span }),
|
||||
ResolutionError::FailedToResolve { label, suggestion } => {
|
||||
ResolutionError::FailedToResolve { last_segment, label, suggestion, module } => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0433, "failed to resolve: {}", &label);
|
||||
err.span_label(span, label);
|
||||
|
@ -789,6 +791,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
err.multipart_suggestion(msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
if let Some(ModuleOrUniformRoot::Module(module)) = module
|
||||
&& let Some(module) = module.opt_def_id()
|
||||
&& let Some(last_segment) = last_segment
|
||||
{
|
||||
self.find_cfg_stripped(&mut err, &last_segment, module);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
|
||||
|
@ -971,9 +980,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
VisResolutionError::AncestorOnly(span) => {
|
||||
self.tcx.sess.create_err(errs::AncestorOnly(span))
|
||||
}
|
||||
VisResolutionError::FailedToResolve(span, label, suggestion) => {
|
||||
self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion })
|
||||
}
|
||||
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
last_segment: None,
|
||||
label,
|
||||
suggestion,
|
||||
module: None,
|
||||
},
|
||||
),
|
||||
VisResolutionError::ExpectedFound(span, path_str, res) => {
|
||||
self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str })
|
||||
}
|
||||
|
@ -1721,10 +1736,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
|
||||
ignore_binding: Option<&'a NameBinding<'a>>,
|
||||
module: Option<ModuleOrUniformRoot<'a>>,
|
||||
i: usize,
|
||||
failed_segment_idx: usize,
|
||||
ident: Ident,
|
||||
) -> (String, Option<Suggestion>) {
|
||||
let is_last = i == path.len() - 1;
|
||||
let is_last = failed_segment_idx == path.len() - 1;
|
||||
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
||||
let module_res = match module {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
|
||||
|
@ -1758,8 +1773,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
} else {
|
||||
(format!("could not find `{ident}` in the crate root"), None)
|
||||
}
|
||||
} else if i > 0 {
|
||||
let parent = path[i - 1].ident.name;
|
||||
} else if failed_segment_idx > 0 {
|
||||
let parent = path[failed_segment_idx - 1].ident.name;
|
||||
let parent = match parent {
|
||||
// ::foo is mounted at the crate root for 2015, and is the extern
|
||||
// prelude for 2018+
|
||||
|
@ -2207,6 +2222,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a cfg-ed out item inside `module` with the matching name.
|
||||
pub(crate) fn find_cfg_stripped(
|
||||
&mut self,
|
||||
err: &mut Diagnostic,
|
||||
last_segment: &Symbol,
|
||||
module: DefId,
|
||||
) {
|
||||
let local_items;
|
||||
let symbols = if module.is_local() {
|
||||
local_items = self
|
||||
.stripped_cfg_items
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
|
||||
Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg.clone() })
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
local_items.as_slice()
|
||||
} else {
|
||||
self.tcx.stripped_cfg_items(module.krate)
|
||||
};
|
||||
|
||||
for &StrippedCfgItem { parent_module, name, ref cfg } in symbols {
|
||||
if parent_module != module || name.name != *last_segment {
|
||||
continue;
|
||||
}
|
||||
|
||||
err.span_note(name.span, "found an item that was configured out");
|
||||
|
||||
if let MetaItemKind::List(nested) = &cfg.kind
|
||||
&& let NestedMetaItem::MetaItem(meta_item) = &nested[0]
|
||||
&& let MetaItemKind::NameValue(feature_name) = &meta_item.kind
|
||||
{
|
||||
err.note(format!("the item is gated behind the `{}` feature", feature_name.symbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `binding_span` of a binding within a use statement:
|
||||
|
|
|
@ -330,6 +330,7 @@ pub(crate) struct ParamInTyOfConstParam {
|
|||
pub(crate) param_kind: Option<ParamKindInTyOfConstParam>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ParamKindInTyOfConstParam {
|
||||
#[note(resolve_type_param_in_ty_of_const_param)]
|
||||
|
@ -365,6 +366,7 @@ pub(crate) struct ParamInNonTrivialAnonConst {
|
|||
#[help(resolve_param_in_non_trivial_anon_const_help)]
|
||||
pub(crate) struct ParamInNonTrivialAnonConstHelp;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ParamKindInNonTrivialAnonConst {
|
||||
#[note(resolve_type_param_in_non_trivial_anon_const)]
|
||||
|
@ -562,6 +564,7 @@ pub(crate) struct CfgAccessibleUnsure {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_param_in_enum_discriminant)]
|
||||
pub(crate) struct ParamInEnumDiscriminant {
|
||||
|
@ -573,6 +576,7 @@ pub(crate) struct ParamInEnumDiscriminant {
|
|||
pub(crate) param_kind: ParamKindInEnumDiscriminant,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ParamKindInEnumDiscriminant {
|
||||
#[note(resolve_type_param_in_enum_discriminant)]
|
||||
|
|
|
@ -1365,20 +1365,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
|
||||
ignore_binding: Option<&'a NameBinding<'a>>,
|
||||
) -> PathResult<'a> {
|
||||
debug!(
|
||||
"resolve_path(path={:?}, opt_ns={:?}, finalize={:?}) path_len: {}",
|
||||
path,
|
||||
opt_ns,
|
||||
finalize,
|
||||
path.len()
|
||||
);
|
||||
|
||||
let mut module = None;
|
||||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
|
||||
for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
|
||||
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
|
||||
for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() {
|
||||
debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id);
|
||||
let record_segment_res = |this: &mut Self, res| {
|
||||
if finalize.is_some() {
|
||||
if let Some(id) = id {
|
||||
|
@ -1390,7 +1382,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let is_last = i + 1 == path.len();
|
||||
let is_last = segment_idx + 1 == path.len();
|
||||
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
|
||||
let name = ident.name;
|
||||
|
||||
|
@ -1399,7 +1391,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
if ns == TypeNS {
|
||||
if allow_super && name == kw::Super {
|
||||
let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
|
||||
let self_module = match i {
|
||||
let self_module = match segment_idx {
|
||||
0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
|
||||
_ => match module {
|
||||
Some(ModuleOrUniformRoot::Module(module)) => Some(module),
|
||||
|
@ -1414,11 +1406,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
return PathResult::failed(ident.span, false, finalize.is_some(), || {
|
||||
("there are too many leading `super` keywords".to_string(), None)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident.span,
|
||||
false,
|
||||
finalize.is_some(),
|
||||
module,
|
||||
|| ("there are too many leading `super` keywords".to_string(), None),
|
||||
);
|
||||
}
|
||||
if i == 0 {
|
||||
if segment_idx == 0 {
|
||||
if name == kw::SelfLower {
|
||||
let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
|
||||
module = Some(ModuleOrUniformRoot::Module(
|
||||
|
@ -1447,14 +1443,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Report special messages for path segment keywords in wrong positions.
|
||||
if ident.is_path_segment_keyword() && i != 0 {
|
||||
return PathResult::failed(ident.span, false, finalize.is_some(), || {
|
||||
if ident.is_path_segment_keyword() && segment_idx != 0 {
|
||||
return PathResult::failed(ident.span, false, finalize.is_some(), module, || {
|
||||
let name_str = if name == kw::PathRoot {
|
||||
"crate root".to_string()
|
||||
} else {
|
||||
format!("`{}`", name)
|
||||
};
|
||||
let label = if i == 1 && path[0].ident.name == kw::PathRoot {
|
||||
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
|
||||
format!("global paths cannot start with {}", name_str)
|
||||
} else {
|
||||
format!("{} in paths can only be used in start position", name_str)
|
||||
|
@ -1519,7 +1515,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
};
|
||||
match binding {
|
||||
Ok(binding) => {
|
||||
if i == 1 {
|
||||
if segment_idx == 1 {
|
||||
second_binding = Some(binding);
|
||||
}
|
||||
let res = binding.res();
|
||||
|
@ -1543,17 +1539,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
record_segment_res(self, res);
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
res,
|
||||
path.len() - i - 1,
|
||||
path.len() - segment_idx - 1,
|
||||
));
|
||||
} else {
|
||||
return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
|
||||
let label = format!(
|
||||
"`{ident}` is {} {}, not a module",
|
||||
res.article(),
|
||||
res.descr()
|
||||
);
|
||||
(label, None)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident.span,
|
||||
is_last,
|
||||
finalize.is_some(),
|
||||
module,
|
||||
|| {
|
||||
let label = format!(
|
||||
"`{ident}` is {} {}, not a module",
|
||||
res.article(),
|
||||
res.descr()
|
||||
);
|
||||
(label, None)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(Undetermined) => return PathResult::Indeterminate,
|
||||
|
@ -1562,23 +1564,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
if opt_ns.is_some() && !module.is_normal() {
|
||||
return PathResult::NonModule(PartialRes::with_unresolved_segments(
|
||||
module.res().unwrap(),
|
||||
path.len() - i,
|
||||
path.len() - segment_idx,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
|
||||
self.report_path_resolution_error(
|
||||
path,
|
||||
opt_ns,
|
||||
parent_scope,
|
||||
ribs,
|
||||
ignore_binding,
|
||||
module,
|
||||
i,
|
||||
ident,
|
||||
)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident.span,
|
||||
is_last,
|
||||
finalize.is_some(),
|
||||
module,
|
||||
|| {
|
||||
self.report_path_resolution_error(
|
||||
path,
|
||||
opt_ns,
|
||||
parent_scope,
|
||||
ribs,
|
||||
ignore_binding,
|
||||
module,
|
||||
segment_idx,
|
||||
ident,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -803,14 +803,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
module
|
||||
}
|
||||
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
||||
PathResult::Failed {
|
||||
is_error_from_last_segment: false,
|
||||
span,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
self.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
last_segment: None,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
},
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
|
||||
PathResult::Failed {
|
||||
is_error_from_last_segment: true,
|
||||
span,
|
||||
label,
|
||||
suggestion,
|
||||
..
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
let err = match self.make_path_suggestion(
|
||||
|
|
|
@ -3524,7 +3524,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
None
|
||||
};
|
||||
|
||||
this.r.use_injections.push(UseError {
|
||||
let ue = UseError {
|
||||
err,
|
||||
candidates,
|
||||
def_id,
|
||||
|
@ -3532,7 +3532,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
suggestion,
|
||||
path: path.into(),
|
||||
is_call: source.is_call(),
|
||||
});
|
||||
};
|
||||
|
||||
this.r.use_injections.push(ue);
|
||||
}
|
||||
|
||||
PartialRes::new(Res::Err)
|
||||
|
@ -3866,8 +3868,22 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||
PartialRes::new(module.res().unwrap())
|
||||
}
|
||||
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
||||
return Err(respan(span, ResolutionError::FailedToResolve { label, suggestion }));
|
||||
PathResult::Failed {
|
||||
is_error_from_last_segment: false,
|
||||
span,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
} => {
|
||||
return Err(respan(
|
||||
span,
|
||||
ResolutionError::FailedToResolve {
|
||||
last_segment: None,
|
||||
label,
|
||||
suggestion,
|
||||
module,
|
||||
},
|
||||
));
|
||||
}
|
||||
PathResult::Module(..) | PathResult::Failed { .. } => return Ok(None),
|
||||
PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
|
||||
|
|
|
@ -149,6 +149,7 @@ struct BaseError {
|
|||
span_label: Option<(Span, &'static str)>,
|
||||
could_be_expr: bool,
|
||||
suggestion: Option<(Span, &'static str, String)>,
|
||||
module: Option<DefId>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -210,10 +211,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
_ => false,
|
||||
},
|
||||
suggestion: None,
|
||||
module: None,
|
||||
}
|
||||
} else {
|
||||
let item_span = path.last().unwrap().ident.span;
|
||||
let (mod_prefix, mod_str, suggestion) = if path.len() == 1 {
|
||||
let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
|
||||
debug!(?self.diagnostic_metadata.current_impl_items);
|
||||
debug!(?self.diagnostic_metadata.current_function);
|
||||
let suggestion = if self.current_trait_ref.is_none()
|
||||
|
@ -247,26 +249,37 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
(String::new(), "this scope".to_string(), suggestion)
|
||||
(String::new(), "this scope".to_string(), None, suggestion)
|
||||
} else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
|
||||
if self.r.tcx.sess.edition() > Edition::Edition2015 {
|
||||
// In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
|
||||
// which overrides all other expectations of item type
|
||||
expected = "crate";
|
||||
(String::new(), "the list of imported crates".to_string(), None)
|
||||
(String::new(), "the list of imported crates".to_string(), None, None)
|
||||
} else {
|
||||
(String::new(), "the crate root".to_string(), None)
|
||||
(
|
||||
String::new(),
|
||||
"the crate root".to_string(),
|
||||
Some(CRATE_DEF_ID.to_def_id()),
|
||||
None,
|
||||
)
|
||||
}
|
||||
} else if path.len() == 2 && path[0].ident.name == kw::Crate {
|
||||
(String::new(), "the crate root".to_string(), None)
|
||||
(String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)
|
||||
} else {
|
||||
let mod_path = &path[..path.len() - 1];
|
||||
let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) {
|
||||
let mod_res = self.resolve_path(mod_path, Some(TypeNS), None);
|
||||
let mod_prefix = match mod_res {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
|
||||
_ => None,
|
||||
}
|
||||
.map_or_else(String::new, |res| format!("{} ", res.descr()));
|
||||
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None)
|
||||
};
|
||||
|
||||
let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);
|
||||
|
||||
let mod_prefix =
|
||||
mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr())));
|
||||
|
||||
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)
|
||||
};
|
||||
|
||||
let (fallback_label, suggestion) = if path_str == "async"
|
||||
|
@ -300,6 +313,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
span_label: None,
|
||||
could_be_expr: false,
|
||||
suggestion,
|
||||
module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,6 +329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
) -> (DiagnosticBuilder<'tcx, ErrorGuaranteed>, Vec<ImportSuggestion>) {
|
||||
debug!(?res, ?source);
|
||||
let base_error = self.make_base_error(path, span, source, res);
|
||||
|
||||
let code = source.error_code(res.is_some());
|
||||
let mut err = self.r.tcx.sess.struct_span_err_with_code(
|
||||
base_error.span,
|
||||
|
@ -366,6 +381,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
}
|
||||
self.err_code_special_cases(&mut err, source, path, span);
|
||||
|
||||
if let Some(module) = base_error.module {
|
||||
self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
|
||||
}
|
||||
|
||||
(err, candidates)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ use errors::{
|
|||
ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
|
||||
};
|
||||
use rustc_arena::{DroplessArena, TypedArena};
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
|
||||
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
|
||||
|
@ -171,6 +172,7 @@ enum ImplTraitContext {
|
|||
Universal(LocalDefId),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BindingError {
|
||||
name: Symbol,
|
||||
origin: BTreeSet<Span>,
|
||||
|
@ -178,6 +180,7 @@ struct BindingError {
|
|||
could_be_path: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ResolutionError<'a> {
|
||||
/// Error E0401: can't use type or const parameters from outer function.
|
||||
GenericParamsFromOuterFunction(Res, HasGenericParams),
|
||||
|
@ -207,7 +210,12 @@ enum ResolutionError<'a> {
|
|||
/// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
|
||||
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
||||
/// Error E0433: failed to resolve.
|
||||
FailedToResolve { label: String, suggestion: Option<Suggestion> },
|
||||
FailedToResolve {
|
||||
last_segment: Option<Symbol>,
|
||||
label: String,
|
||||
suggestion: Option<Suggestion>,
|
||||
module: Option<ModuleOrUniformRoot<'a>>,
|
||||
},
|
||||
/// Error E0434: can't capture dynamic environment in a fn item.
|
||||
CannotCaptureDynamicEnvironmentInFnItem,
|
||||
/// Error E0435: attempt to use a non-constant value in a constant.
|
||||
|
@ -402,6 +410,7 @@ enum PathResult<'a> {
|
|||
label: String,
|
||||
suggestion: Option<Suggestion>,
|
||||
is_error_from_last_segment: bool,
|
||||
module: Option<ModuleOrUniformRoot<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -410,11 +419,12 @@ impl<'a> PathResult<'a> {
|
|||
span: Span,
|
||||
is_error_from_last_segment: bool,
|
||||
finalize: bool,
|
||||
module: Option<ModuleOrUniformRoot<'a>>,
|
||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||||
) -> PathResult<'a> {
|
||||
let (label, suggestion) =
|
||||
if finalize { label_and_suggestion() } else { (String::new(), None) };
|
||||
PathResult::Failed { span, label, suggestion, is_error_from_last_segment }
|
||||
PathResult::Failed { span, label, suggestion, is_error_from_last_segment, module }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -685,6 +695,7 @@ struct PrivacyError<'a> {
|
|||
dedup_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct UseError<'a> {
|
||||
err: DiagnosticBuilder<'a, ErrorGuaranteed>,
|
||||
/// Candidates which user could `use` to access the missing type.
|
||||
|
@ -1059,6 +1070,9 @@ pub struct Resolver<'a, 'tcx> {
|
|||
/// Whether lifetime elision was successful.
|
||||
lifetime_elision_allowed: FxHashSet<NodeId>,
|
||||
|
||||
/// Names of items that were stripped out via cfg with their corresponding cfg meta item.
|
||||
stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>,
|
||||
|
||||
effective_visibilities: EffectiveVisibilities,
|
||||
doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
|
||||
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
|
||||
|
@ -1353,6 +1367,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
proc_macros: Default::default(),
|
||||
confused_type_with_std_module: Default::default(),
|
||||
lifetime_elision_allowed: Default::default(),
|
||||
stripped_cfg_items: Default::default(),
|
||||
effective_visibilities: Default::default(),
|
||||
doc_link_resolutions: Default::default(),
|
||||
doc_link_traits_in_scope: Default::default(),
|
||||
|
@ -1410,6 +1425,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let main_def = self.main_def;
|
||||
let confused_type_with_std_module = self.confused_type_with_std_module;
|
||||
let effective_visibilities = self.effective_visibilities;
|
||||
|
||||
self.tcx.feed_local_crate().stripped_cfg_items(self.tcx.arena.alloc_from_iter(
|
||||
self.stripped_cfg_items.into_iter().filter_map(|item| {
|
||||
let parent_module = self.node_id_to_def_id.get(&item.parent_module)?.to_def_id();
|
||||
Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg })
|
||||
}),
|
||||
));
|
||||
|
||||
let global_ctxt = ResolverGlobalCtxt {
|
||||
expn_that_defined,
|
||||
visibilities,
|
||||
|
|
|
@ -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