use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, SyntaxContext};
use crate::imports::{Import, ImportKind, ImportResolver};
use crate::late::{PatternSource, Rib};
/// similarly named label and whether or not it is reachable.
pub(crate) type LabelSuggestion = (Ident, bool);
+#[derive(Debug)]
pub(crate) enum SuggestionTarget {
/// The target has a similar name as the name used by the programmer (probably a typo)
SimilarlyNamed,
SingleItem,
}
+#[derive(Debug)]
pub(crate) struct TypoSuggestion {
pub candidate: Symbol,
pub res: Res,
&candidates,
if instead { Instead::Yes } else { Instead::No },
found_use,
- IsPattern::No,
- IsImport::No,
+ DiagnosticMode::Normal,
path,
);
err.emit();
module: Module<'a>,
names: &mut Vec<TypoSuggestion>,
filter_fn: &impl Fn(Res) -> bool,
+ ctxt: Option<SyntaxContext>,
) {
for (key, resolution) in self.resolutions(module).borrow().iter() {
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
- if filter_fn(res) {
+ if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
}
}
&import_suggestions,
Instead::No,
FoundUse::Yes,
- IsPattern::Yes,
- IsImport::No,
+ DiagnosticMode::Pattern,
vec![],
);
}
err.span_label(trait_item_span, "item in trait");
err
}
+ ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
+ let mut err = struct_span_err!(
+ self.session,
+ span,
+ E0201,
+ "duplicate definitions with name `{}`:",
+ name,
+ );
+ err.span_label(old_span, "previous definition here");
+ err.span_label(trait_item_span, "item in trait");
+ err.span_label(span, "duplicate definition");
+ err
+ }
ResolutionError::InvalidAsmSym => {
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
err.span_label(span, "is a local variable");
Scope::CrateRoot => {
let root_ident = Ident::new(kw::PathRoot, ident.span);
let root_module = this.resolve_crate_root(root_ident);
- this.add_module_candidates(root_module, &mut suggestions, filter_fn);
+ this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
}
Scope::Module(module, _) => {
- this.add_module_candidates(module, &mut suggestions, filter_fn);
+ this.add_module_candidates(module, &mut suggestions, filter_fn, None);
}
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(
Scope::StdLibPrelude => {
if let Some(prelude) = this.prelude {
let mut tmp_suggestions = Vec::new();
- this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
+ this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
suggestions.extend(
tmp_suggestions
.into_iter()
&import_suggestions,
Instead::No,
FoundUse::Yes,
- IsPattern::No,
- IsImport::No,
+ DiagnosticMode::Normal,
vec![],
);
No,
}
-/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
-enum IsPattern {
+/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
+enum DiagnosticMode {
+ Normal,
/// The binding is part of a pattern
- Yes,
- /// The binding is part of an expression
- No,
-}
-
-/// Whether a binding is part of a use statement. Used for diagnostics.
-enum IsImport {
- Yes,
- No,
+ Pattern,
+ /// The binding is part of a use statement
+ Import,
}
pub(crate) fn import_candidates(
candidates,
Instead::Yes,
FoundUse::Yes,
- IsPattern::No,
- IsImport::Yes,
+ DiagnosticMode::Import,
vec![],
);
}
candidates: &[ImportSuggestion],
instead: Instead,
found_use: FoundUse,
- is_pattern: IsPattern,
- is_import: IsImport,
+ mode: DiagnosticMode,
path: Vec<Segment>,
) {
if candidates.is_empty() {
};
let instead = if let Instead::Yes = instead { " instead" } else { "" };
- let mut msg = if let IsPattern::Yes = is_pattern {
+ let mut msg = if let DiagnosticMode::Pattern = mode {
format!(
"if you meant to match on {}{}{}, use the full path in the pattern",
kind, instead, name
err.note(note);
}
- if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
- err.span_suggestions(
- span,
- &msg,
- accessible_path_strings.into_iter().map(|a| a.0),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(span) = use_placement_span {
+ if let Some(span) = use_placement_span {
+ let add_use = match mode {
+ DiagnosticMode::Pattern => {
+ err.span_suggestions(
+ span,
+ &msg,
+ accessible_path_strings.into_iter().map(|a| a.0),
+ Applicability::MaybeIncorrect,
+ );
+ return;
+ }
+ DiagnosticMode::Import => "",
+ DiagnosticMode::Normal => "use ",
+ };
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
// from the directly following item.
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
- let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
}
err.note(&msg);
}
- } else if matches!(is_import, IsImport::No) {
+ } else if !matches!(mode, DiagnosticMode::Import) {
assert!(!inaccessible_path_strings.is_empty());
- let prefix =
- if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
+ let prefix = if let DiagnosticMode::Pattern = mode {
+ "you might have meant to match on "
+ } else {
+ ""
+ };
if inaccessible_path_strings.len() == 1 {
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!(
prefix,
descr,
name,
- if let IsPattern::Yes = is_pattern { ", which" } else { "" }
+ if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {