diff options
Diffstat (limited to 'compiler/rustc_resolve/src/diagnostics.rs')
-rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 76 |
1 files changed, 55 insertions, 21 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e392df6c5..366086152 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -5,8 +5,10 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, +}; +use rustc_errors::{struct_span_err, SuggestionStyle}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; @@ -153,7 +155,7 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { show_candidates( &self.session, - &self.source_span, + &self.untracked.source_span, &mut err, span, &candidates, @@ -161,10 +163,11 @@ impl<'a> Resolver<'a> { found_use, DiagnosticMode::Normal, path, + "", ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { - err.span_suggestion(span, msg, sugg, appl); + err.span_suggestion_verbose(span, msg, sugg, appl); err.emit(); } else if let [segment] = path.as_slice() && is_call { err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod); @@ -682,7 +685,7 @@ impl<'a> Resolver<'a> { } show_candidates( &self.session, - &self.source_span, + &self.untracked.source_span, &mut err, Some(span), &import_suggestions, @@ -690,6 +693,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Pattern, vec![], + "", ); } err @@ -1298,7 +1302,8 @@ impl<'a> Resolver<'a> { // otherwise cause duplicate suggestions. continue; } - if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) { + let crate_id = self.crate_loader().maybe_process_path_extern(ident.name); + if let Some(crate_id) = crate_id { let crate_root = self.expect_module(crate_id.as_def_id()); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, @@ -1335,7 +1340,7 @@ impl<'a> Resolver<'a> { self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); show_candidates( &self.session, - &self.source_span, + &self.untracked.source_span, err, None, &import_suggestions, @@ -1343,6 +1348,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Normal, vec![], + "", ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -1600,6 +1606,16 @@ impl<'a> Resolver<'a> { err.span_label(ident.span, &format!("private {}", descr)); if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); + if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { + err.multipart_suggestion_verbose( + &format!( + "consider making the field{} publicly accessible", + pluralize!(fields.len()) + ), + fields.iter().map(|span| (*span, "pub ".to_string())).collect(), + Applicability::MaybeIncorrect, + ); + } } // Print the whole import chain to make it easier to see what happens. @@ -2109,9 +2125,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let source_map = self.r.session.source_map(); + // Make sure this is actually crate-relative. + let is_definitely_crate = import + .module_path + .first() + .map_or(false, |f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); - if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) { corrections.push(( start_point, if has_nested { @@ -2123,11 +2145,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> { format!("{{{}, {}", import_snippet, start_snippet) }, )); - } - // Add a `};` to the end if nested, matching the `{` added at the start. - if !has_nested { - corrections.push((source_map.end_point(after_crate_name), "};".to_string())); + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), "};".to_string())); + } + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + import.use_span.shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } } @@ -2308,7 +2336,7 @@ enum FoundUse { } /// 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, @@ -2323,6 +2351,8 @@ pub(crate) fn import_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option<Span>, candidates: &[ImportSuggestion], + mode: DiagnosticMode, + append: &str, ) { show_candidates( session, @@ -2332,8 +2362,9 @@ pub(crate) fn import_candidates( candidates, Instead::Yes, FoundUse::Yes, - DiagnosticMode::Import, + mode, vec![], + append, ); } @@ -2351,6 +2382,7 @@ fn show_candidates( found_use: FoundUse, mode: DiagnosticMode, path: Vec<Segment>, + append: &str, ) { if candidates.is_empty() { return; @@ -2398,7 +2430,7 @@ fn show_candidates( } if let Some(span) = use_placement_span { - let add_use = match mode { + let (add_use, trailing) = match mode { DiagnosticMode::Pattern => { err.span_suggestions( span, @@ -2408,21 +2440,23 @@ fn show_candidates( ); return; } - DiagnosticMode::Import => "", - DiagnosticMode::Normal => "use ", + DiagnosticMode::Import => ("", ""), + DiagnosticMode::Normal => ("use ", ";\n"), }; 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" }; - candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); + let additional_newline = if let FoundUse::No = found_use && let DiagnosticMode::Normal = mode { "\n" } else { "" }; + candidate.0 = + format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0); } - err.span_suggestions( + err.span_suggestions_with_style( span, &msg, accessible_path_strings.into_iter().map(|a| a.0), Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, ); if let [first, .., last] = &path[..] { let sp = first.ident.span.until(last.ident.span); @@ -2443,7 +2477,7 @@ fn show_candidates( msg.push_str(&candidate.0); } - err.note(&msg); + err.help(&msg); } } else if !matches!(mode, DiagnosticMode::Import) { assert!(!inaccessible_path_strings.is_empty()); |