diff options
Diffstat (limited to 'compiler/rustc_resolve')
-rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 29 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 76 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/effective_visibilities.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 9 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 81 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late.rs | 91 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 76 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 124 | ||||
-rw-r--r-- | compiler/rustc_resolve/src/macros.rs | 2 |
10 files changed, 352 insertions, 148 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 9c90d67aa..b1b04c92a 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -334,6 +334,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.field_names.insert(def_id, field_names); } + fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { + let field_vis = vdata + .fields() + .iter() + .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span))) + .collect(); + self.r.field_visibility_spans.insert(def_id, field_vis); + } + fn insert_field_names_extern(&mut self, def_id: DefId) { let field_names = self.r.cstore().struct_field_names_untracked(def_id, self.r.session).collect(); @@ -514,7 +523,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ModuleKind::Block => unreachable!(), }; // HACK(eddyb) unclear how good this is, but keeping `$crate` - // in `source` breaks `src/test/ui/imports/import-crate-var.rs`, + // in `source` breaks `tests/ui/imports/import-crate-var.rs`, // while the current crate doesn't have a valid `crate_name`. if crate_name != kw::Empty { // `crate_name` should not be interpreted as relative. @@ -576,7 +585,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Ensure there is at most one `self` in the list let self_spans = items .iter() - .filter_map(|&(ref use_tree, _)| { + .filter_map(|(use_tree, _)| { if let ast::UseTreeKind::Simple(..) = use_tree.kind { if use_tree.ident().name == kw::SelfLower { return Some(use_tree.span); @@ -737,6 +746,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id, vdata); + self.insert_field_visibilities_local(def_id, vdata); // If this is a tuple or unit struct, define a name // in the value namespace as well. @@ -770,6 +780,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id.to_def_id()); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); self.r.visibilities.insert(ctor_def_id, ctor_vis); + // We need the field visibility spans also for the constructor for E0603. + self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata); self.r .struct_constructors @@ -783,6 +795,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id, vdata); + self.insert_field_visibilities_local(def_id, vdata); } ItemKind::Trait(..) => { @@ -836,12 +849,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } else if orig_name == Some(kw::SelfLower) { Some(self.r.graph_root) } else { - self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id).map( - |crate_id| { - self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.expect_module(crate_id.as_def_id()) - }, - ) + let crate_id = self.r.crate_loader().process_extern_crate(item, local_def_id); + crate_id.map(|crate_id| { + self.r.extern_crate_map.insert(local_def_id, crate_id); + self.r.expect_module(crate_id.as_def_id()) + }) } .map(|module| { let used = self.process_macro_use_imports(item, module); @@ -1511,6 +1523,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // Record field names for error reporting. self.insert_field_names_local(def_id.to_def_id(), &variant.data); + self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data); visit::walk_variant(self, variant); } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 32fb5e182..eae4c9992 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -28,9 +28,9 @@ use crate::module_to_string; use crate::Resolver; use rustc_ast as ast; -use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -40,7 +40,7 @@ struct UnusedImport<'a> { use_tree: &'a ast::UseTree, use_tree_id: ast::NodeId, item_span: Span, - unused: FxHashSet<ast::NodeId>, + unused: UnordSet<ast::NodeId>, } impl<'a> UnusedImport<'a> { @@ -52,7 +52,7 @@ impl<'a> UnusedImport<'a> { struct UnusedImportCheckVisitor<'a, 'b> { r: &'a mut Resolver<'b>, /// All the (so far) unused imports, grouped path list - unused_imports: NodeMap<UnusedImport<'a>>, + unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>, base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, @@ -89,7 +89,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { use_tree, use_tree_id, item_span, - unused: FxHashSet::default(), + unused: Default::default(), }) } } 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()); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 85399385d..b8efa3f8b 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -107,7 +107,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { r.effective_visibilities.update_eff_vis( r.local_def_id(node_id), eff_vis, - ResolverTree(&r.definitions, &r.crate_loader), + ResolverTree(&r.untracked), ) } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 759818856..a84652a31 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -875,13 +875,12 @@ impl<'a> Resolver<'a> { // binding if it exists. What we really want here is having two separate scopes in // a module - one for non-globs and one for globs, but until that's done use this // hack to avoid inconsistent resolution ICEs during import validation. - let binding = [resolution.binding, resolution.shadowed_glob] - .into_iter() - .filter_map(|binding| match (binding, ignore_binding) { + let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map( + |binding| match (binding, ignore_binding) { (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None, _ => binding, - }) - .next(); + }, + ); let Some(binding) = binding else { return Err((Determined, Weak::No)); }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b100a8c17..00f65ac37 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,6 @@ //! 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}; @@ -402,7 +402,7 @@ struct UnresolvedImportError { label: Option<String>, note: Option<String>, suggestion: Option<Suggestion>, - candidate: Option<Vec<ImportSuggestion>>, + candidates: Option<Vec<ImportSuggestion>>, } pub struct ImportResolver<'a, 'b> { @@ -475,12 +475,7 @@ impl<'a, 'b> 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 { @@ -494,10 +489,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { 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)) } } } @@ -507,7 +504,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - 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; } @@ -516,7 +513,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> { 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); @@ -525,7 +532,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { 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); } @@ -538,14 +545,36 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.multipart_suggestion(&msg, suggestions, applicability); } - if let Some(candidate) = &err.candidate { - import_candidates( - self.r.session, - &self.r.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(""), + ); + } + _ => {} + } } } @@ -707,14 +736,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { 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); @@ -761,7 +790,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { )), note: None, suggestion: None, - candidate: None, + candidates: None, }); } } @@ -873,7 +902,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { 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() { @@ -943,7 +972,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(label), note, suggestion, - candidate: if !parent_suggestion.is_empty() { + candidates: if !parent_suggestion.is_empty() { Some(parent_suggestion) } else { None diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cf3e59460..83932c089 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -16,7 +16,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; +use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -536,6 +536,9 @@ struct DiagnosticMetadata<'ast> { in_assignment: Option<&'ast Expr>, is_assign_rhs: bool, + /// Used to detect possible `.` -> `..` typo when calling methods. + in_range: Option<(&'ast Expr, &'ast Expr)>, + /// If we are currently in a trait object definition. Used to point at the bounds when /// encountering a struct or enum. current_trait_object: Option<&'ast [ast::GenericBound]>, @@ -566,6 +569,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS<Vec<Rib<'a>>>, + /// Previous poped `rib`, only used for diagnostic. + last_block_rib: Option<Rib<'a>>, + /// The current set of local scopes, for labels. label_ribs: Vec<Rib<'a, NodeId>>, @@ -645,7 +651,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let prev = self.diagnostic_metadata.current_trait_object; let prev_ty = self.diagnostic_metadata.current_type_path; match ty.kind { - TyKind::Rptr(None, _) => { + TyKind::Ref(None, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. // This span will be used in case of elision failure. @@ -662,7 +668,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { && let Some(partial_res) = self.r.partial_res_map.get(&ty.id) && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { - // This path is actually a bare trait object. In case of a bare `Fn`-trait + // This path is actually a bare trait object. In case of a bare `Fn`-trait // object with anonymous lifetimes, we need this rib to correctly place the // synthetic lifetimes. let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo()); @@ -873,6 +879,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. let previous_state = replace(&mut this.in_func_body, true); + // We only care block in the same function + this.last_block_rib = None; // Resolve the function body, potentially inside the body of an async closure this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Infer), @@ -1038,7 +1046,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // Probe the lifetime ribs to know how to behave. for rib in self.lifetime_ribs.iter().rev() { match rib.kind { - // We are inside a `PolyTraitRef`. The lifetimes are + // We are inside a `PolyTraitRef`. The lifetimes are // to be intoduced in that (maybe implicit) `for<>` binder. LifetimeRibKind::Generics { binder, @@ -1061,7 +1069,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); break; } - // We have nowhere to introduce generics. Code is malformed, + // We have nowhere to introduce generics. Code is malformed, // so use regular lifetime resolution to avoid spurious errors. LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { visit::walk_generic_args(self, args); @@ -1168,6 +1176,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { type_ns: vec![Rib::new(start_rib_kind)], macro_ns: vec![Rib::new(start_rib_kind)], }, + last_block_rib: None, label_ribs: Vec::new(), lifetime_ribs: Vec::new(), lifetime_elision_candidates: None, @@ -1506,7 +1515,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { count: 1, }; let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); - for rib in self.lifetime_ribs.iter().rev() { + for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() { debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { @@ -1523,16 +1532,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } else { ("`'_` cannot be used here", "`'_` is a reserved lifetime name") }; - rustc_errors::struct_span_err!( + let mut diag = rustc_errors::struct_span_err!( self.r.session, lifetime.ident.span, E0637, "{}", msg, - ) - .span_label(lifetime.ident.span, note) - .emit(); - + ); + diag.span_label(lifetime.ident.span, note); + if elided { + for rib in self.lifetime_ribs[i..].iter().rev() { + if let LifetimeRibKind::Generics { + span, + kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, + .. + } = &rib.kind + { + diag.span_help( + *span, + "consider introducing a higher-ranked lifetime here with `for<'a>`", + ); + break; + } + } + } + diag.emit(); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); return; } @@ -1751,7 +1775,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { break; } // `LifetimeRes::Error`, which would usually be used in the case of - // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, // we simply resolve to an implicit lifetime, which will be checked later, at // which point a suitable error will be emitted. LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { @@ -1995,7 +2019,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl<'a> Visitor<'a> for SelfVisitor<'_, '_> { fn visit_ty(&mut self, ty: &'a Ty) { trace!("SelfVisitor considering ty={:?}", ty); - if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { + if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { let lt_id = if let Some(lt) = lt { lt.id } else { @@ -3314,6 +3338,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } + #[instrument(level = "debug", skip(self))] fn smart_resolve_path_fragment( &mut self, qself: &Option<P<QSelf>>, @@ -3321,10 +3346,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, finalize: Finalize, ) -> PartialRes { - debug!( - "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})", - qself, path, finalize, - ); let ns = source.namespace(); let Finalize { node_id, path_span, .. } = finalize; @@ -3335,8 +3356,28 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); - let suggestion = - if res.is_none() { this.report_missing_type_error(path) } else { None }; + let suggestion = if let Some((start, end)) = this.diagnostic_metadata.in_range + && path[0].ident.span.lo() == end.span.lo() + { + let mut sugg = "."; + let mut span = start.span.between(end.span); + if span.lo() + BytePos(2) == span.hi() { + // There's no space between the start, the range op and the end, suggest + // removal which will look better. + span = span.with_lo(span.lo() + BytePos(1)); + sugg = ""; + } + Some(( + span, + "you might have meant to write `.` instead of `..`", + sugg.to_string(), + Applicability::MaybeIncorrect, + )) + } else if res.is_none() && matches!(source, PathSource::Type) { + this.report_missing_type_error(path) + } else { + None + }; this.r.use_injections.push(UseError { err, @@ -3606,7 +3647,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let Some(qself) = qself { if qself.position == 0 { // This is a case like `<T>::B`, where there is no - // trait to resolve. In that case, we leave the `B` + // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. return Ok(Some(PartialRes::with_unresolved_segments( Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()), @@ -3617,7 +3658,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Make sure `A::B` in `<T as A::B>::C` is a trait item. // // Currently, `path` names the full item (`A::B::C`, in - // our example). so we extract the prefix of that that is + // our example). so we extract the prefix of that that is // the trait (the slice upto and including // `qself.position`). And then we recursively resolve that, // but with `qself` set to `None`. @@ -3769,7 +3810,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.ribs[ValueNS].pop(); self.label_ribs.pop(); } - self.ribs[ValueNS].pop(); + self.last_block_rib = self.ribs[ValueNS].pop(); if anonymous_module.is_some() { self.ribs[TypeNS].pop(); } @@ -3999,6 +4040,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.visit_expr(rhs); self.diagnostic_metadata.is_assign_rhs = false; } + ExprKind::Range(Some(ref start), Some(ref end), RangeLimits::HalfOpen) => { + self.diagnostic_metadata.in_range = Some((start, end)); + self.resolve_expr(start, Some(expr)); + self.resolve_expr(end, Some(expr)); + self.diagnostic_metadata.in_range = None; + } _ => { visit::walk_expr(self, expr); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df59a350e..6d448433e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -277,11 +277,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let override_suggestion = if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) { let item_typo = item_str.to_string().to_lowercase(); - Some(( - item_span, - "you may want to use a bool value instead", - format!("{}", item_typo), - )) + Some((item_span, "you may want to use a bool value instead", item_typo)) // FIXME(vincenzopalazzo): make the check smarter, // and maybe expand with levenshtein distance checks } else if item_str.as_str() == "printf" { @@ -623,6 +619,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { return (true, candidates); } } + + // Try to find in last block rib + if let Some(rib) = &self.last_block_rib && let RibKind::NormalRibKind = rib.kind { + for (ident, &res) in &rib.bindings { + if let Res::Local(_) = res && path.len() == 1 && + ident.span.eq_ctxt(path[0].ident.span) && + ident.name == path[0].ident.name { + err.span_help( + ident.span, + &format!("the binding `{}` is available in a different scope in the same function", path_str), + ); + return (true, candidates); + } + } + } + return (false, candidates); } @@ -1439,6 +1451,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect(); if non_visible_spans.len() > 0 { + if let Some(fields) = self.r.field_visibility_spans.get(&def_id) { + 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, + ); + } + let mut m: MultiSpan = non_visible_spans.clone().into(); non_visible_spans .into_iter() @@ -1542,7 +1565,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn extract_node_id(t: &Ty) -> Option<NodeId> { match t.kind { TyKind::Path(None, _) => Some(t.id), - TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty), + TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty), // This doesn't handle the remaining `Ty` variants as they are not // that commonly the self_type, it might be interesting to provide // support for those in future. @@ -1663,8 +1686,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if !module.no_implicit_prelude { let extern_prelude = self.r.extern_prelude.clone(); names.extend(extern_prelude.iter().flat_map(|(ident, _)| { - self.r.crate_loader.maybe_process_path_extern(ident.name).and_then( - |crate_id| { + self.r + .crate_loader() + .maybe_process_path_extern(ident.name) + .and_then(|crate_id| { let crate_mod = Res::Def(DefKind::Mod, crate_id.as_def_id()); @@ -1673,8 +1698,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } else { None } - }, - ) + }) })); if let Some(prelude) = self.r.prelude { @@ -2041,7 +2065,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { path: &[Segment], ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { - [segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => { + [segment] + if !segment.has_generic_args + && segment.ident.name != kw::SelfUpper + && segment.ident.name != kw::Dyn => + { (segment.ident.to_string(), segment.ident.span) } _ => return None, @@ -2160,15 +2188,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let deletion_span = || { if params.len() == 1 { // if sole lifetime, remove the entire `<>` brackets - generics_span + Some(generics_span) } else if param_index == 0 { // if removing within `<>` brackets, we also want to // delete a leading or trailing comma as appropriate - param.span().to(params[param_index + 1].span().shrink_to_lo()) + match ( + param.span().find_ancestor_inside(generics_span), + params[param_index + 1].span().find_ancestor_inside(generics_span), + ) { + (Some(param_span), Some(next_param_span)) => { + Some(param_span.to(next_param_span.shrink_to_lo())) + } + _ => None, + } } else { // if removing within `<>` brackets, we also want to // delete a leading or trailing comma as appropriate - params[param_index - 1].span().shrink_to_hi().to(param.span()) + match ( + param.span().find_ancestor_inside(generics_span), + params[param_index - 1].span().find_ancestor_inside(generics_span), + ) { + (Some(param_span), Some(prev_param_span)) => { + Some(prev_param_span.shrink_to_hi().to(param_span)) + } + _ => None, + } } }; match use_set { @@ -2176,7 +2220,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Some(LifetimeUseSet::One { use_span, use_ctxt }) => { debug!(?param.ident, ?param.ident.span, ?use_span); - let elidable = matches!(use_ctxt, LifetimeCtxt::Rptr); + let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); let deletion_span = deletion_span(); self.r.lint_buffer.buffer_lint_with_diagnostic( @@ -2307,7 +2351,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let message = format!("consider introducing lifetime `{}` here", name); should_continue = suggest(err, false, span, &message, sugg); } else { - let message = format!("consider introducing a named lifetime parameter"); + let message = "consider introducing a named lifetime parameter"; should_continue = suggest(err, false, span, &message, sugg); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a0fa61c45..1b181b714 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -29,7 +29,7 @@ use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, RwLock}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; @@ -46,7 +46,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools}; use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; +use rustc_session::cstore::{CrateStore, MetadataLoaderDyn, Untracked}; use rustc_session::lint::LintBuffer; use rustc_session::Session; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; @@ -868,11 +868,8 @@ struct MacroData { pub struct Resolver<'a> { session: &'a Session, - definitions: Definitions, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. expn_that_defined: FxHashMap<LocalDefId, ExpnId>, - /// Reference span for definitions. - source_span: IndexVec<LocalDefId, Span>, graph_root: Module<'a>, @@ -886,6 +883,10 @@ pub struct Resolver<'a> { /// Used for hints during error reporting. field_names: FxHashMap<DefId, Vec<Spanned<Symbol>>>, + /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax. + /// Used for hints during error reporting. + field_visibility_spans: FxHashMap<DefId, Vec<Span>>, + /// All imports known to succeed or fail. determined_imports: Vec<&'a Import<'a>>, @@ -956,7 +957,10 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, - crate_loader: CrateLoader<'a>, + local_crate_name: Symbol, + metadata_loader: Box<MetadataLoaderDyn>, + untracked: Untracked, + used_extern_options: FxHashSet<Symbol>, macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, /// A small map keeping true kinds of built-in macros that appear to be fn-like on @@ -1114,15 +1118,15 @@ impl<'a> AsMut<Resolver<'a>> for Resolver<'a> { /// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes /// required to satisfy borrow checker by avoiding borrowing the whole resolver. #[derive(Clone, Copy)] -struct ResolverTree<'a, 'b>(&'a Definitions, &'a CrateLoader<'b>); +struct ResolverTree<'a>(&'a Untracked); -impl DefIdTree for ResolverTree<'_, '_> { +impl DefIdTree for ResolverTree<'_> { #[inline] fn opt_parent(self, id: DefId) -> Option<DefId> { - let ResolverTree(definitions, crate_loader) = self; + let ResolverTree(Untracked { definitions, cstore, .. }) = self; match id.as_local() { - Some(id) => definitions.def_key(id).parent, - None => crate_loader.cstore().def_key(id).parent, + Some(id) => definitions.read().def_key(id).parent, + None => cstore.as_any().downcast_ref::<CStore>().unwrap().def_key(id).parent, } .map(|index| DefId { index, ..id }) } @@ -1131,11 +1135,11 @@ impl DefIdTree for ResolverTree<'_, '_> { impl<'a, 'b> DefIdTree for &'a Resolver<'b> { #[inline] fn opt_parent(self, id: DefId) -> Option<DefId> { - ResolverTree(&self.definitions, &self.crate_loader).opt_parent(id) + ResolverTree(&self.untracked).opt_parent(id) } } -impl Resolver<'_> { +impl<'a> Resolver<'a> { fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { self.node_id_to_def_id.get(&node).copied() } @@ -1158,10 +1162,10 @@ impl Resolver<'_> { "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", node_id, data, - self.definitions.def_key(self.node_id_to_def_id[&node_id]), + self.untracked.definitions.read().def_key(self.node_id_to_def_id[&node_id]), ); - let def_id = self.definitions.create_def(parent, data); + let def_id = self.untracked.definitions.write().create_def(parent, data); // Create the definition. if expn_id != ExpnId::root() { @@ -1170,7 +1174,7 @@ impl Resolver<'_> { // A relative span's parent must be an absolute span. debug_assert_eq!(span.data_untracked().parent, None); - let _id = self.source_span.push(span); + let _id = self.untracked.source_span.push(span); debug_assert_eq!(_id, def_id); // Some things for which we allocate `LocalDefId`s don't correspond to @@ -1192,6 +1196,10 @@ impl Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, self.session) } } + + pub fn sess(&self) -> &'a Session { + self.session + } } impl<'a> Resolver<'a> { @@ -1260,9 +1268,7 @@ impl<'a> Resolver<'a> { let mut resolver = Resolver { session, - definitions, expn_that_defined: Default::default(), - source_span, // The outermost module has def ID 0; this is not reflected in the // AST. @@ -1272,6 +1278,7 @@ impl<'a> Resolver<'a> { has_self: FxHashSet::default(), field_names: FxHashMap::default(), + field_visibility_spans: FxHashMap::default(), determined_imports: Vec::new(), indeterminate_imports: Vec::new(), @@ -1313,7 +1320,14 @@ impl<'a> Resolver<'a> { vis: ty::Visibility::Public, }), - crate_loader: CrateLoader::new(session, metadata_loader, crate_name), + metadata_loader, + local_crate_name: crate_name, + used_extern_options: Default::default(), + untracked: Untracked { + cstore: Box::new(CStore::new(session)), + source_span, + definitions: RwLock::new(definitions), + }, macro_names: FxHashSet::default(), builtin_macros: Default::default(), builtin_macro_kinds: Default::default(), @@ -1404,9 +1418,6 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); - let definitions = self.definitions; - let cstore = Box::new(self.crate_loader.into_cstore()); - let source_span = self.source_span; let expn_that_defined = self.expn_that_defined; let visibilities = self.visibilities; let has_pub_restricted = self.has_pub_restricted; @@ -1418,9 +1429,8 @@ impl<'a> Resolver<'a> { let main_def = self.main_def; let confused_type_with_std_module = self.confused_type_with_std_module; let effective_visibilities = self.effective_visibilities; + let untracked = self.untracked; let global_ctxt = ResolverGlobalCtxt { - cstore, - source_span, expn_that_defined, visibilities, has_pub_restricted, @@ -1455,16 +1465,16 @@ impl<'a> Resolver<'a> { builtin_macro_kinds: self.builtin_macro_kinds, lifetime_elision_allowed: self.lifetime_elision_allowed, }; - ResolverOutputs { definitions, global_ctxt, ast_lowering } + ResolverOutputs { global_ctxt, ast_lowering, untracked } } pub fn clone_outputs(&self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); - let definitions = self.definitions.clone(); + let definitions = self.untracked.definitions.clone(); let cstore = Box::new(self.cstore().clone()); + let untracked = + Untracked { cstore, source_span: self.untracked.source_span.clone(), definitions }; let global_ctxt = ResolverGlobalCtxt { - cstore, - source_span: self.source_span.clone(), expn_that_defined: self.expn_that_defined.clone(), visibilities: self.visibilities.clone(), has_pub_restricted: self.has_pub_restricted, @@ -1492,27 +1502,33 @@ impl<'a> Resolver<'a> { label_res_map: self.label_res_map.clone(), lifetimes_res_map: self.lifetimes_res_map.clone(), extra_lifetime_params_map: self.extra_lifetime_params_map.clone(), - next_node_id: self.next_node_id.clone(), + next_node_id: self.next_node_id, node_id_to_def_id: self.node_id_to_def_id.clone(), def_id_to_node_id: self.def_id_to_node_id.clone(), trait_map: self.trait_map.clone(), builtin_macro_kinds: self.builtin_macro_kinds.clone(), lifetime_elision_allowed: self.lifetime_elision_allowed.clone(), }; - ResolverOutputs { definitions, global_ctxt, ast_lowering } + ResolverOutputs { global_ctxt, ast_lowering, untracked } } fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { - StableHashingContext::new( - self.session, - &self.definitions, - self.crate_loader.cstore(), - &self.source_span, + StableHashingContext::new(self.session, &self.untracked) + } + + pub fn crate_loader(&mut self) -> CrateLoader<'_> { + CrateLoader::new( + &self.session, + &*self.metadata_loader, + self.local_crate_name, + &mut *self.untracked.cstore.untracked_as_any().downcast_mut().unwrap(), + self.untracked.definitions.read(), + &mut self.used_extern_options, ) } pub fn cstore(&self) -> &CStore { - self.crate_loader.cstore() + self.untracked.cstore.as_any().downcast_ref().unwrap() } fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> { @@ -1555,7 +1571,7 @@ impl<'a> Resolver<'a> { self.session.time("resolve_main", || self.resolve_main()); self.session.time("resolve_check_unused", || self.check_unused(krate)); self.session.time("resolve_report_errors", || self.report_errors(krate)); - self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate)); + self.session.time("resolve_postprocess", || self.crate_loader().postprocess(krate)); }); } @@ -1681,6 +1697,24 @@ impl<'a> Resolver<'a> { .or_insert_with(|| self.arenas.alloc_name_resolution()) } + /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors + fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool { + for ambiguity_error in &self.ambiguity_errors { + // if the span location and ident as well as its span are the same + if ambiguity_error.kind == ambi.kind + && ambiguity_error.ident == ambi.ident + && ambiguity_error.ident.span == ambi.ident.span + && ambiguity_error.b1.span == ambi.b1.span + && ambiguity_error.b2.span == ambi.b2.span + && ambiguity_error.misc1 == ambi.misc1 + && ambiguity_error.misc2 == ambi.misc2 + { + return true; + } + } + false + } + fn record_use( &mut self, ident: Ident, @@ -1688,14 +1722,18 @@ impl<'a> Resolver<'a> { is_lexical_scope: bool, ) { if let Some((b2, kind)) = used_binding.ambiguity { - self.ambiguity_errors.push(AmbiguityError { + let ambiguity_error = AmbiguityError { kind, ident, b1: used_binding, b2, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, - }); + }; + if !self.matches_previous_ambiguity_error(&ambiguity_error) { + // avoid dumplicated span information to be emitt out + self.ambiguity_errors.push(ambiguity_error); + } } if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { // Avoid marking `extern crate` items that refer to a name from extern prelude, @@ -1873,10 +1911,10 @@ impl<'a> Resolver<'a> { } else { let crate_id = if finalize { let Some(crate_id) = - self.crate_loader.process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); }; + self.crate_loader().process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); }; crate_id } else { - self.crate_loader.maybe_process_path_extern(ident.name)? + self.crate_loader().maybe_process_path_extern(ident.name)? }; let crate_root = self.expect_module(crate_id.as_def_id()); let vis = ty::Visibility::<LocalDefId>::Public; @@ -1948,14 +1986,14 @@ impl<'a> Resolver<'a> { /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. #[inline] pub fn opt_span(&self, def_id: DefId) -> Option<Span> { - def_id.as_local().map(|def_id| self.source_span[def_id]) + def_id.as_local().map(|def_id| self.untracked.source_span[def_id]) } /// Retrieves the name of the given `DefId`. #[inline] pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> { let def_key = match def_id.as_local() { - Some(def_id) => self.definitions.def_key(def_id), + Some(def_id) => self.untracked.definitions.read().def_key(def_id), None => self.cstore().def_key(def_id), }; def_key.get_opt_name() diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 8c7972f8e..b5b1602c5 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -455,7 +455,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span { - self.crate_loader.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session) + self.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session) } fn declare_proc_macro(&mut self, id: NodeId) { |