Skip to content

Commit 15a8b98

Browse files
committed
resolve: Optimize path resolution for rustdoc
Do not construct or pass unused data
1 parent 0749ec6 commit 15a8b98

File tree

3 files changed

+38
-92
lines changed

3 files changed

+38
-92
lines changed

compiler/rustc_resolve/src/lib.rs

Lines changed: 16 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ use rustc_span::{Span, DUMMY_SP};
7171
use smallvec::{smallvec, SmallVec};
7272
use std::cell::{Cell, RefCell};
7373
use std::collections::BTreeSet;
74-
use std::{cmp, fmt, iter, mem, ptr};
74+
use std::{cmp, fmt, mem, ptr};
7575
use tracing::debug;
7676

7777
use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
@@ -3309,82 +3309,39 @@ impl<'a> Resolver<'a> {
33093309
})
33103310
}
33113311

3312-
/// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
3312+
/// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>`
33133313
/// isn't something that can be returned because it can't be made to live that long,
33143314
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
33153315
/// just that an error occurred.
3316-
// FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
3317-
pub fn resolve_str_path_error(
3316+
pub fn resolve_rustdoc_path(
33183317
&mut self,
3319-
span: Span,
33203318
path_str: &str,
33213319
ns: Namespace,
33223320
module_id: DefId,
3323-
) -> Result<(ast::Path, Res), ()> {
3324-
let path = if path_str.starts_with("::") {
3325-
ast::Path {
3326-
span,
3327-
segments: iter::once(Ident::with_dummy_span(kw::PathRoot))
3328-
.chain(path_str.split("::").skip(1).map(Ident::from_str))
3329-
.map(|i| self.new_ast_path_segment(i))
3330-
.collect(),
3331-
tokens: None,
3332-
}
3333-
} else {
3334-
ast::Path {
3335-
span,
3336-
segments: path_str
3337-
.split("::")
3338-
.map(Ident::from_str)
3339-
.map(|i| self.new_ast_path_segment(i))
3340-
.collect(),
3341-
tokens: None,
3342-
}
3343-
};
3344-
let module = self.expect_module(module_id);
3345-
let parent_scope = &ParentScope::module(module, self);
3346-
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
3347-
Ok((path, res))
3348-
}
3321+
) -> Option<Res> {
3322+
let mut segments =
3323+
Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident));
3324+
if path_str.starts_with("::") {
3325+
segments[0].ident.name = kw::PathRoot;
3326+
}
33493327

3350-
// Resolve a path passed from rustdoc or HIR lowering.
3351-
fn resolve_ast_path(
3352-
&mut self,
3353-
path: &ast::Path,
3354-
ns: Namespace,
3355-
parent_scope: &ParentScope<'a>,
3356-
) -> Result<Res, (Span, ResolutionError<'a>)> {
3328+
let module = self.expect_module(module_id);
33573329
match self.resolve_path(
3358-
&Segment::from_path(path),
3330+
&segments,
33593331
Some(ns),
3360-
parent_scope,
3361-
path.span,
3332+
&ParentScope::module(module, self),
3333+
DUMMY_SP,
33623334
CrateLint::No,
33633335
) {
3364-
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Ok(module.res().unwrap()),
3336+
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
33653337
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
3366-
Ok(path_res.base_res())
3338+
Some(path_res.base_res())
33673339
}
3368-
PathResult::NonModule(..) => Err((
3369-
path.span,
3370-
ResolutionError::FailedToResolve {
3371-
label: String::from("type-relative paths are not supported in this context"),
3372-
suggestion: None,
3373-
},
3374-
)),
3340+
PathResult::NonModule(..) | PathResult::Failed { .. } => None,
33753341
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
3376-
PathResult::Failed { span, label, suggestion, .. } => {
3377-
Err((span, ResolutionError::FailedToResolve { label, suggestion }))
3378-
}
33793342
}
33803343
}
33813344

3382-
fn new_ast_path_segment(&mut self, ident: Ident) -> ast::PathSegment {
3383-
let mut seg = ast::PathSegment::from_ident(ident);
3384-
seg.id = self.next_node_id();
3385-
seg
3386-
}
3387-
33883345
// For rustdoc.
33893346
pub fn graph_root(&self) -> Module<'a> {
33903347
self.graph_root

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -487,12 +487,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
487487
module_id: DefId,
488488
) -> Result<Res, ResolutionFailure<'a>> {
489489
self.cx.enter_resolver(|resolver| {
490-
// NOTE: this needs 2 separate lookups because `resolve_str_path_error` doesn't take
490+
// NOTE: this needs 2 separate lookups because `resolve_rustdoc_path` doesn't take
491491
// lexical scope into account (it ignores all macros not defined at the mod-level)
492492
debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
493-
if let Ok((_, res)) =
494-
resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
495-
{
493+
if let Some(res) = resolver.resolve_rustdoc_path(path_str, MacroNS, module_id) {
496494
// don't resolve builtins like `#[derive]`
497495
if let Ok(res) = res.try_into() {
498496
return Ok(res);
@@ -540,10 +538,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
540538
})
541539
}
542540

543-
/// Convenience wrapper around `resolve_str_path_error`.
541+
/// Convenience wrapper around `resolve_rustdoc_path`.
544542
///
545543
/// This also handles resolving `true` and `false` as booleans.
546-
/// NOTE: `resolve_str_path_error` knows only about paths, not about types.
544+
/// NOTE: `resolve_rustdoc_path` knows only about paths, not about types.
547545
/// Associated items will never be resolved by this function.
548546
fn resolve_path(
549547
&self,
@@ -556,18 +554,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
556554
return res;
557555
}
558556

559-
let result = self.cx.enter_resolver(|resolver| {
560-
resolver
561-
.resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
562-
.and_then(|(_, res)| res.try_into())
563-
});
557+
// Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
558+
let result = self
559+
.cx
560+
.enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id))
561+
.and_then(|res| res.try_into().ok())
562+
.or_else(|| resolve_primitive(path_str, ns));
564563
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
565-
match result {
566-
// resolver doesn't know about true, false, and types that aren't paths (e.g. `()`)
567-
// manually as bool
568-
Err(()) => resolve_primitive(path_str, ns),
569-
Ok(res) => Some(res),
570-
}
564+
result
571565
}
572566

573567
/// Resolves a string as a path within a particular namespace. Returns an

src/librustdoc/passes/collect_intra_doc_links/early.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir::TraitCandidate;
1313
use rustc_middle::ty::{DefIdTree, Visibility};
1414
use rustc_resolve::{ParentScope, Resolver};
1515
use rustc_session::config::Externs;
16-
use rustc_span::{Span, SyntaxContext, DUMMY_SP};
16+
use rustc_span::SyntaxContext;
1717

1818
use std::collections::hash_map::Entry;
1919
use std::mem;
@@ -39,7 +39,7 @@ crate fn early_resolve_intra_doc_links(
3939

4040
// Overridden `visit_item` below doesn't apply to the crate root,
4141
// so we have to visit its attributes and reexports separately.
42-
loader.load_links_in_attrs(&krate.attrs, krate.spans.inner_span);
42+
loader.load_links_in_attrs(&krate.attrs);
4343
loader.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
4444
visit::walk_crate(&mut loader, krate);
4545
loader.add_foreign_traits_in_scope();
@@ -49,12 +49,7 @@ crate fn early_resolve_intra_doc_links(
4949
// DO NOT REMOVE THIS without first testing on the reproducer in
5050
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
5151
for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
52-
let _ = loader.resolver.resolve_str_path_error(
53-
DUMMY_SP,
54-
extern_name,
55-
TypeNS,
56-
CRATE_DEF_ID.to_def_id(),
57-
);
52+
loader.resolver.resolve_rustdoc_path(extern_name, TypeNS, CRATE_DEF_ID.to_def_id());
5853
}
5954

6055
ResolverCaches {
@@ -151,7 +146,7 @@ impl IntraLinkCrateLoader<'_, '_> {
151146
}
152147
}
153148

154-
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
149+
fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) {
155150
// FIXME: this needs to consider reexport inlining.
156151
let attrs = clean::Attributes::from_ast(attrs, None);
157152
for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
@@ -165,7 +160,7 @@ impl IntraLinkCrateLoader<'_, '_> {
165160
} else {
166161
continue;
167162
};
168-
let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
163+
self.resolver.resolve_rustdoc_path(&path_str, TypeNS, module_id);
169164
}
170165
}
171166
}
@@ -201,7 +196,7 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
201196
// loaded, even if the module itself has no doc comments.
202197
self.add_traits_in_parent_scope(self.current_mod.to_def_id());
203198

204-
self.load_links_in_attrs(&item.attrs, item.span);
199+
self.load_links_in_attrs(&item.attrs);
205200
self.process_module_children_or_reexports(self.current_mod.to_def_id());
206201
visit::walk_item(self, item);
207202

@@ -216,28 +211,28 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
216211
}
217212
_ => {}
218213
}
219-
self.load_links_in_attrs(&item.attrs, item.span);
214+
self.load_links_in_attrs(&item.attrs);
220215
visit::walk_item(self, item);
221216
}
222217
}
223218

224219
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
225-
self.load_links_in_attrs(&item.attrs, item.span);
220+
self.load_links_in_attrs(&item.attrs);
226221
visit::walk_assoc_item(self, item, ctxt)
227222
}
228223

229224
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
230-
self.load_links_in_attrs(&item.attrs, item.span);
225+
self.load_links_in_attrs(&item.attrs);
231226
visit::walk_foreign_item(self, item)
232227
}
233228

234229
fn visit_variant(&mut self, v: &ast::Variant) {
235-
self.load_links_in_attrs(&v.attrs, v.span);
230+
self.load_links_in_attrs(&v.attrs);
236231
visit::walk_variant(self, v)
237232
}
238233

239234
fn visit_field_def(&mut self, field: &ast::FieldDef) {
240-
self.load_links_in_attrs(&field.attrs, field.span);
235+
self.load_links_in_attrs(&field.attrs);
241236
visit::walk_field_def(self, field)
242237
}
243238

0 commit comments

Comments
 (0)