summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs29
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs10
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs76
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs2
-rw-r--r--compiler/rustc_resolve/src/ident.rs9
-rw-r--r--compiler/rustc_resolve/src/imports.rs81
-rw-r--r--compiler/rustc_resolve/src/late.rs91
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs76
-rw-r--r--compiler/rustc_resolve/src/lib.rs124
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
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) {