Skip to content

Commit 9d76a93

Browse files
authored
Rollup merge of rust-lang#63400 - petrochenkov:resplit, r=eddyb
Try to break resolve into more isolated parts Some small step towards resolve librarification. "Late resolution" is the pass that resolves most of names in a crate beside imports and macros. It runs when the crate is fully expanded and its module structure is fully built. So we just walk through the crate and resolve all the expressions, types, etc. This pass is pretty self-contained, but it was previously done by implementing `Visitor` on the whole `Resolver` (which is used for many other tasks), and fields specific to this pass were indiscernible from the global `Resolver` state. This PR moves the late resolution pass into a separate visitor and a separate file, fields specific to this visitor are moved from `Resolver` as well. I'm especially happy about `current_module` being removed from `Resolver`. It was used even for operations not related to visiting and changing the `current_module` position in process. It was also used as an implicit argument for some functions used in this style ```rust let orig_current_module = mem::replace(&mut self.current_module, module); self.resolve_ident_somewhere(); self.current_module = orig_current_module; ``` and having effects on e.g. privacy checking somewhere deeply inside `resolve_ident_somewhere`. Now we explicitly pass a `ParentScope` to those functions instead, which includes the module and some other data describing our position in the crate relatively to which we resolve names. Rustdoc was one of the users of `current_module`, it set it for resolving intra-doc links. Now it passes it explicitly as an argument as well (I also supported resolving paths from rustdoc in unnamed blocks as a drive-by fix). Visibility resolution is also changed to use early resolution (which is correct because it's used during the work of `BuildReducedGraphVisitor`, i.e. integration of a new AST fragment into the existing partially built module structures.) instead of untimely late resolution (which worked only due to restrictions on paths in visibilities like inability to refer to anything except ancestor modules). This slightly regresses its diagnostics because late resolution has a more systematic error detection and recovery currently. Due to changes in `current_module` and visibilities `BuildReducedGraphVisitor` ended up almost as heavily affected by this refactoring as late resolution. Fixes rust-lang#63223 (due to visibility resolution changes).
2 parents d19a359 + 319f0de commit 9d76a93

18 files changed

+3982
-3884
lines changed

src/librustc/hir/lowering.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::hir::{self, ParamName};
3737
use crate::hir::HirVec;
3838
use crate::hir::map::{DefKey, DefPathData, Definitions};
3939
use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
40-
use crate::hir::def::{Res, DefKind, PartialRes, PerNS};
40+
use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS};
4141
use crate::hir::{GenericArg, ConstArg};
4242
use crate::hir::ptr::P;
4343
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
@@ -148,13 +148,6 @@ pub struct LoweringContext<'a> {
148148
}
149149

150150
pub trait Resolver {
151-
/// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
152-
fn resolve_ast_path(
153-
&mut self,
154-
path: &ast::Path,
155-
is_value: bool,
156-
) -> Res<NodeId>;
157-
158151
/// Obtain resolution for a `NodeId` with a single resolution.
159152
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
160153

@@ -175,7 +168,7 @@ pub trait Resolver {
175168
span: Span,
176169
crate_root: Option<Symbol>,
177170
components: &[Symbol],
178-
is_value: bool,
171+
ns: Namespace,
179172
) -> (ast::Path, Res<NodeId>);
180173

181174
fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
@@ -5717,8 +5710,8 @@ impl<'a> LoweringContext<'a> {
57175710
params: Option<P<hir::GenericArgs>>,
57185711
is_value: bool,
57195712
) -> hir::Path {
5720-
let (path, res) = self.resolver
5721-
.resolve_str_path(span, self.crate_root, components, is_value);
5713+
let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
5714+
let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
57225715

57235716
let mut segments: Vec<_> = path.segments.iter().map(|segment| {
57245717
let res = self.expect_full_res(segment.id);

src/librustc_resolve/build_reduced_graph.rs

+480-270
Large diffs are not rendered by default.

src/librustc_resolve/check_unused.rs

+91-110
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
// - `check_crate` finally emits the diagnostics based on the data generated
2424
// in the last step
2525

26-
use std::ops::{Deref, DerefMut};
27-
2826
use crate::Resolver;
2927
use crate::resolve_imports::ImportDirectiveSubclass;
3028

@@ -49,45 +47,30 @@ impl<'a> UnusedImport<'a> {
4947
}
5048

5149
struct UnusedImportCheckVisitor<'a, 'b> {
52-
resolver: &'a mut Resolver<'b>,
50+
r: &'a mut Resolver<'b>,
5351
/// All the (so far) unused imports, grouped path list
5452
unused_imports: NodeMap<UnusedImport<'a>>,
5553
base_use_tree: Option<&'a ast::UseTree>,
5654
base_id: ast::NodeId,
5755
item_span: Span,
5856
}
5957

60-
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
61-
impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> {
62-
type Target = Resolver<'b>;
63-
64-
fn deref<'c>(&'c self) -> &'c Resolver<'b> {
65-
&*self.resolver
66-
}
67-
}
68-
69-
impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> {
70-
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
71-
&mut *self.resolver
72-
}
73-
}
74-
7558
impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
7659
// We have information about whether `use` (import) directives are actually
7760
// used now. If an import is not used at all, we signal a lint error.
7861
fn check_import(&mut self, id: ast::NodeId) {
7962
let mut used = false;
80-
self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
63+
self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
8164
if !used {
82-
if self.maybe_unused_trait_imports.contains(&id) {
65+
if self.r.maybe_unused_trait_imports.contains(&id) {
8366
// Check later.
8467
return;
8568
}
8669
self.unused_import(self.base_id).add(id);
8770
} else {
8871
// This trait import is definitely used, in a way other than
8972
// method resolution.
90-
self.maybe_unused_trait_imports.remove(&id);
73+
self.r.maybe_unused_trait_imports.remove(&id);
9174
if let Some(i) = self.unused_imports.get_mut(&self.base_id) {
9275
i.unused.remove(&id);
9376
}
@@ -238,104 +221,102 @@ fn calc_unused_spans(
238221
}
239222
}
240223

241-
pub fn check_crate(resolver: &mut Resolver<'_>, krate: &ast::Crate) {
242-
for directive in resolver.potentially_unused_imports.iter() {
243-
match directive.subclass {
244-
_ if directive.used.get() ||
245-
directive.vis.get() == ty::Visibility::Public ||
246-
directive.span.is_dummy() => {
247-
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
248-
if !directive.span.is_dummy() {
249-
resolver.session.buffer_lint(
250-
lint::builtin::MACRO_USE_EXTERN_CRATE,
251-
directive.id,
252-
directive.span,
253-
"deprecated `#[macro_use]` directive used to \
254-
import macros should be replaced at use sites \
255-
with a `use` statement to import the macro \
256-
instead",
257-
);
224+
impl Resolver<'_> {
225+
crate fn check_unused(&mut self, krate: &ast::Crate) {
226+
for directive in self.potentially_unused_imports.iter() {
227+
match directive.subclass {
228+
_ if directive.used.get() ||
229+
directive.vis.get() == ty::Visibility::Public ||
230+
directive.span.is_dummy() => {
231+
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
232+
if !directive.span.is_dummy() {
233+
self.session.buffer_lint(
234+
lint::builtin::MACRO_USE_EXTERN_CRATE,
235+
directive.id,
236+
directive.span,
237+
"deprecated `#[macro_use]` directive used to \
238+
import macros should be replaced at use sites \
239+
with a `use` statement to import the macro \
240+
instead",
241+
);
242+
}
258243
}
259244
}
245+
ImportDirectiveSubclass::ExternCrate { .. } => {
246+
self.maybe_unused_extern_crates.push((directive.id, directive.span));
247+
}
248+
ImportDirectiveSubclass::MacroUse => {
249+
let lint = lint::builtin::UNUSED_IMPORTS;
250+
let msg = "unused `#[macro_use]` import";
251+
self.session.buffer_lint(lint, directive.id, directive.span, msg);
252+
}
253+
_ => {}
260254
}
261-
ImportDirectiveSubclass::ExternCrate { .. } => {
262-
resolver.maybe_unused_extern_crates.push((directive.id, directive.span));
263-
}
264-
ImportDirectiveSubclass::MacroUse => {
265-
let lint = lint::builtin::UNUSED_IMPORTS;
266-
let msg = "unused `#[macro_use]` import";
267-
resolver.session.buffer_lint(lint, directive.id, directive.span, msg);
268-
}
269-
_ => {}
270255
}
271-
}
272-
273-
for (id, span) in resolver.unused_labels.iter() {
274-
resolver.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
275-
}
276256

277-
let mut visitor = UnusedImportCheckVisitor {
278-
resolver,
279-
unused_imports: Default::default(),
280-
base_use_tree: None,
281-
base_id: ast::DUMMY_NODE_ID,
282-
item_span: DUMMY_SP,
283-
};
284-
visit::walk_crate(&mut visitor, krate);
285-
286-
for unused in visitor.unused_imports.values() {
287-
let mut fixes = Vec::new();
288-
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
289-
UnusedSpanResult::Used => continue,
290-
UnusedSpanResult::FlatUnused(span, remove) => {
291-
fixes.push((remove, String::new()));
292-
vec![span]
293-
}
294-
UnusedSpanResult::NestedFullUnused(spans, remove) => {
295-
fixes.push((remove, String::new()));
296-
spans
297-
}
298-
UnusedSpanResult::NestedPartialUnused(spans, remove) => {
299-
for fix in &remove {
300-
fixes.push((*fix, String::new()));
301-
}
302-
spans
303-
}
257+
let mut visitor = UnusedImportCheckVisitor {
258+
r: self,
259+
unused_imports: Default::default(),
260+
base_use_tree: None,
261+
base_id: ast::DUMMY_NODE_ID,
262+
item_span: DUMMY_SP,
304263
};
264+
visit::walk_crate(&mut visitor, krate);
305265

306-
let len = spans.len();
307-
spans.sort();
308-
let ms = MultiSpan::from_spans(spans.clone());
309-
let mut span_snippets = spans.iter()
310-
.filter_map(|s| {
311-
match visitor.session.source_map().span_to_snippet(*s) {
312-
Ok(s) => Some(format!("`{}`", s)),
313-
_ => None,
266+
for unused in visitor.unused_imports.values() {
267+
let mut fixes = Vec::new();
268+
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
269+
UnusedSpanResult::Used => continue,
270+
UnusedSpanResult::FlatUnused(span, remove) => {
271+
fixes.push((remove, String::new()));
272+
vec![span]
314273
}
315-
}).collect::<Vec<String>>();
316-
span_snippets.sort();
317-
let msg = format!("unused import{}{}",
318-
if len > 1 { "s" } else { "" },
319-
if !span_snippets.is_empty() {
320-
format!(": {}", span_snippets.join(", "))
321-
} else {
322-
String::new()
323-
});
274+
UnusedSpanResult::NestedFullUnused(spans, remove) => {
275+
fixes.push((remove, String::new()));
276+
spans
277+
}
278+
UnusedSpanResult::NestedPartialUnused(spans, remove) => {
279+
for fix in &remove {
280+
fixes.push((*fix, String::new()));
281+
}
282+
spans
283+
}
284+
};
324285

325-
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
326-
"remove the whole `use` item"
327-
} else if spans.len() > 1 {
328-
"remove the unused imports"
329-
} else {
330-
"remove the unused import"
331-
};
286+
let len = spans.len();
287+
spans.sort();
288+
let ms = MultiSpan::from_spans(spans.clone());
289+
let mut span_snippets = spans.iter()
290+
.filter_map(|s| {
291+
match visitor.r.session.source_map().span_to_snippet(*s) {
292+
Ok(s) => Some(format!("`{}`", s)),
293+
_ => None,
294+
}
295+
}).collect::<Vec<String>>();
296+
span_snippets.sort();
297+
let msg = format!("unused import{}{}",
298+
if len > 1 { "s" } else { "" },
299+
if !span_snippets.is_empty() {
300+
format!(": {}", span_snippets.join(", "))
301+
} else {
302+
String::new()
303+
});
332304

333-
visitor.session.buffer_lint_with_diagnostic(
334-
lint::builtin::UNUSED_IMPORTS,
335-
unused.use_tree_id,
336-
ms,
337-
&msg,
338-
lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
339-
);
305+
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
306+
"remove the whole `use` item"
307+
} else if spans.len() > 1 {
308+
"remove the unused imports"
309+
} else {
310+
"remove the unused import"
311+
};
312+
313+
visitor.r.session.buffer_lint_with_diagnostic(
314+
lint::builtin::UNUSED_IMPORTS,
315+
unused.use_tree_id,
316+
ms,
317+
&msg,
318+
lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
319+
);
320+
}
340321
}
341322
}

0 commit comments

Comments
 (0)