found_use,
DiagnosticMode::Normal,
path,
+ "",
);
err.emit();
} else if let Some((span, msg, sugg, appl)) = suggestion {
FoundUse::Yes,
DiagnosticMode::Pattern,
vec![],
+ "",
);
}
err
FoundUse::Yes,
DiagnosticMode::Normal,
vec![],
+ "",
);
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
}
/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
-enum DiagnosticMode {
+pub(crate) enum DiagnosticMode {
Normal,
/// The binding is part of a pattern
Pattern,
// This is `None` if all placement locations are inside expansions
use_placement_span: Option<Span>,
candidates: &[ImportSuggestion],
+ mode: DiagnosticMode,
+ append: &str,
) {
show_candidates(
session,
candidates,
Instead::Yes,
FoundUse::Yes,
- DiagnosticMode::Import,
+ mode,
vec![],
+ append,
);
}
found_use: FoundUse,
mode: DiagnosticMode,
path: Vec<Segment>,
+ append: &str,
) {
if candidates.is_empty() {
return;
// 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" };
- candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
+ candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0);
}
err.span_suggestions(
//! A bunch of methods and structures more or less related to resolving imports.
-use crate::diagnostics::{import_candidates, Suggestion};
+use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion};
use crate::Determinacy::{self, *};
use crate::Namespace::*;
use crate::{module_to_string, names_to_string, ImportSuggestion};
label: Option<String>,
note: Option<String>,
suggestion: Option<Suggestion>,
- candidate: Option<Vec<ImportSuggestion>>,
+ candidates: Option<Vec<ImportSuggestion>>,
}
pub struct ImportResolver<'a, 'b> {
errors = vec![];
}
if seen_spans.insert(err.span) {
- let path = import_path_to_string(
- &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
- &import.kind,
- err.span,
- );
- errors.push((path, err));
+ errors.push((import, err));
prev_root_id = import.root_id;
}
} else if is_indeterminate {
label: None,
note: None,
suggestion: None,
- candidate: None,
+ candidates: None,
};
+ // FIXME: there should be a better way of doing this than
+ // formatting this as a string then checking for `::`
if path.contains("::") {
- errors.push((path, err))
+ errors.push((import, err))
}
}
}
}
}
- fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) {
+ fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
if errors.is_empty() {
return;
}
const MAX_LABEL_COUNT: usize = 10;
let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
- let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
+ let paths = errors
+ .iter()
+ .map(|(import, err)| {
+ let path = import_path_to_string(
+ &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+ &import.kind,
+ err.span,
+ );
+ format!("`{path}`")
+ })
+ .collect::<Vec<_>>();
let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
diag.note(note);
}
- for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
+ for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
if let Some(label) = err.label {
diag.span_label(err.span, label);
}
diag.multipart_suggestion(&msg, suggestions, applicability);
}
- if let Some(candidate) = &err.candidate {
- import_candidates(
- self.r.session,
- &self.r.untracked.source_span,
- &mut diag,
- Some(err.span),
- &candidate,
- )
+ if let Some(candidates) = &err.candidates {
+ match &import.kind {
+ ImportKind::Single { nested: false, source, target, .. } => import_candidates(
+ self.r.session,
+ &self.r.untracked.source_span,
+ &mut diag,
+ Some(err.span),
+ &candidates,
+ DiagnosticMode::Import,
+ (source != target)
+ .then(|| format!(" as {target}"))
+ .as_deref()
+ .unwrap_or(""),
+ ),
+ ImportKind::Single { nested: true, source, target, .. } => {
+ import_candidates(
+ self.r.session,
+ &self.r.untracked.source_span,
+ &mut diag,
+ None,
+ &candidates,
+ DiagnosticMode::Normal,
+ (source != target)
+ .then(|| format!(" as {target}"))
+ .as_deref()
+ .unwrap_or(""),
+ );
+ }
+ _ => {}
+ }
}
}
String::from("a similar path exists"),
Applicability::MaybeIncorrect,
)),
- candidate: None,
+ candidates: None,
},
None => UnresolvedImportError {
span,
label: Some(label),
note: None,
suggestion,
- candidate: None,
+ candidates: None,
},
};
return Some(err);
)),
note: None,
suggestion: None,
- candidate: None,
+ candidates: None,
});
}
}
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
let names = resolutions
.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
- if *i == ident {
+ if i.name == ident.name {
return None;
} // Never suggest the same name
match *resolution.borrow() {
label: Some(label),
note,
suggestion,
- candidate: if !parent_suggestion.is_empty() {
+ candidates: if !parent_suggestion.is_empty() {
Some(parent_suggestion)
} else {
None
--- /dev/null
+error[E0432]: unresolved import `super::super::C::D::AA`
+ --> $DIR/bad-import-in-nested.rs:10:21
+ |
+LL | use super::{super::C::D::AA, AA as _};
+ | ^^^^^^^^^^^^^^^ no `AA` in `C::D`
+ |
+ = note: consider importing this type alias instead:
+ crate::A::AA
+
+error[E0432]: unresolved import `crate::C::AA`
+ --> $DIR/bad-import-in-nested.rs:20:26
+ |
+LL | use crate::C::{self, AA};
+ | ^^ no `AA` in `C`
+ |
+ = note: consider importing this type alias instead:
+ crate::A::AA
+
+error[E0432]: unresolved import `crate::C::BB`
+ --> $DIR/bad-import-in-nested.rs:23:20
+ |
+LL | use crate::{A, C::BB};
+ | ^^^^^ no `BB` in `C`
+ |
+ = note: consider importing this type alias instead:
+ crate::A::BB
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.