Skip to content

Commit da921e9

Browse files
committed
rustdoc: Only resolve traits in scope
1 parent 9db0b86 commit da921e9

File tree

4 files changed

+59
-17
lines changed

4 files changed

+59
-17
lines changed

src/librustdoc/core.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ pub struct DocContext<'tcx> {
6969
pub auto_traits: Vec<DefId>,
7070
/// The options given to rustdoc that could be relevant to a pass.
7171
pub render_options: RenderOptions,
72-
/// The traits implemented by a given type.
72+
/// The traits in scope for a given module.
7373
///
7474
/// See `collect_intra_doc_links::traits_implemented_by` for more details.
75-
/// `map<type, set<trait>>`
76-
pub type_trait_cache: RefCell<FxHashMap<DefId, FxHashSet<DefId>>>,
75+
/// `map<module, set<trait>>`
76+
pub module_trait_cache: RefCell<FxHashMap<DefId, FxHashSet<DefId>>>,
7777
}
7878

7979
impl<'tcx> DocContext<'tcx> {
@@ -515,7 +515,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
515515
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
516516
.collect(),
517517
render_options,
518-
type_trait_cache: RefCell::new(FxHashMap::default()),
518+
module_trait_cache: RefCell::new(FxHashMap::default()),
519519
};
520520
debug!("crate: {:?}", tcx.hir().krate());
521521

src/librustdoc/passes/collect_intra_doc_links.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir::def::{
1010
PerNS, Res,
1111
};
1212
use rustc_hir::def_id::DefId;
13-
use rustc_middle::ty::{self, TyCtxt};
13+
use rustc_middle::ty;
1414
use rustc_resolve::ParentScope;
1515
use rustc_session::lint;
1616
use rustc_span::hygiene::MacroKind;
@@ -327,7 +327,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
327327
// To handle that properly resolve() would have to support
328328
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
329329
.or_else(|| {
330-
let kind = resolve_associated_trait_item(did, item_name, ns, &self.cx);
330+
let kind = resolve_associated_trait_item(
331+
did, module_id, item_name, ns, &self.cx,
332+
);
331333
debug!("got associated item kind {:?}", kind);
332334
kind
333335
});
@@ -440,6 +442,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
440442

441443
fn resolve_associated_trait_item(
442444
did: DefId,
445+
module: DefId,
443446
item_name: Symbol,
444447
ns: Namespace,
445448
cx: &DocContext<'_>,
@@ -504,8 +507,7 @@ fn resolve_associated_trait_item(
504507
// Next consider explicit impls: `impl MyTrait for MyType`
505508
// Give precedence to inherent impls.
506509
if candidates.is_empty() {
507-
let mut cache = cx.type_trait_cache.borrow_mut();
508-
let traits = cache.entry(did).or_insert_with(|| traits_implemented_by(cx.tcx, did));
510+
let traits = traits_implemented_by(cx, did, module);
509511
debug!("considering traits {:?}", traits);
510512
candidates.extend(traits.iter().filter_map(|&trait_| {
511513
cx.tcx
@@ -519,27 +521,30 @@ fn resolve_associated_trait_item(
519521
candidates.pop().map(|(_, kind)| kind)
520522
}
521523

522-
/// Given a type, return all traits implemented by that type.
524+
/// Given a type, return all traits in scope in `module` implemented by that type.
523525
///
524526
/// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
525527
/// So it is not stable to serialize cross-crate.
526-
/// FIXME: this should only search traits in scope
527-
fn traits_implemented_by<'a>(tcx: TyCtxt<'a>, type_: DefId) -> FxHashSet<DefId> {
528-
use rustc_hir::def_id::LOCAL_CRATE;
528+
fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet<DefId> {
529+
let mut cache = cx.module_trait_cache.borrow_mut();
530+
let in_scope_traits = cache.entry(module).or_insert_with(|| {
531+
cx.enter_resolver(|resolver| {
532+
resolver.traits_in_scope(module).into_iter().map(|candidate| candidate.def_id).collect()
533+
})
534+
});
529535

530-
let all_traits = tcx.all_traits(LOCAL_CRATE).iter().copied();
531-
let ty = tcx.type_of(type_);
532-
let iter = all_traits.flat_map(|trait_| {
536+
let ty = cx.tcx.type_of(type_);
537+
let iter = in_scope_traits.iter().flat_map(|&trait_| {
533538
trace!("considering explicit impl for trait {:?}", trait_);
534539
let mut saw_impl = false;
535540
// Look at each trait implementation to see if it's an impl for `did`
536-
tcx.for_each_relevant_impl(trait_, ty, |impl_| {
541+
cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| {
537542
// FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
538543
if saw_impl {
539544
return;
540545
}
541546

542-
let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
547+
let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
543548
// Check if these are the same type.
544549
let impl_type = trait_ref.self_ty();
545550
debug!(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![deny(broken_intra_doc_links)]
2+
3+
#[derive(Debug)]
4+
/// Link to [`S::fmt`]
5+
//~^ ERROR unresolved link
6+
pub struct S;
7+
8+
pub mod inner {
9+
use std::fmt::Debug;
10+
use super::S;
11+
12+
/// Link to [`S::fmt`]
13+
pub fn f() {}
14+
}
15+
16+
pub mod ambiguous {
17+
use std::fmt::{Display, Debug};
18+
use super::S;
19+
20+
/// Link to [`S::fmt`]
21+
pub fn f() {}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: unresolved link to `S::fmt`
2+
--> $DIR/assoc-item-not-in-scope.rs:4:14
3+
|
4+
LL | /// Link to [`S::fmt`]
5+
| ^^^^^^^^ unresolved link
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/assoc-item-not-in-scope.rs:1:9
9+
|
10+
LL | #![deny(broken_intra_doc_links)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
13+
14+
error: aborting due to previous error
15+

0 commit comments

Comments
 (0)