Skip to content

Commit f3b4412

Browse files
authored
Rollup merge of rust-lang#123647 - fmease:rustdoc-clean-up-blanket-impls-synth, r=camelid
rustdoc: slightly clean up the synthesis of blanket impls Small follow-up to rust-lang#123340 as promised in rust-lang#123340 (comment). No functional changes whatsoever. * inline the over-engineered “type namespace” (struct) `BlanketImplFinder` just like I did with `AutoTraitFinder` in rust-lang#123340 * use the new `synthesize_*` terminology over the old nondescript / misleading `get_*` one * inline a `use super::*;` (not super modular, lead to `clean/mod.rs` (!) accumulating cruft) * use `tracing` properly r? GuillaumeGomez or rustdoc
2 parents 6146bdb + 31a69d9 commit f3b4412

File tree

4 files changed

+121
-131
lines changed

4 files changed

+121
-131
lines changed

src/librustdoc/clean/blanket_impl.rs

+109-120
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,130 @@
1-
use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
21
use rustc_hir as hir;
32
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
43
use rustc_infer::traits;
5-
use rustc_middle::ty::ToPredicate;
4+
use rustc_middle::ty::{self, ToPredicate};
5+
use rustc_span::def_id::DefId;
66
use rustc_span::DUMMY_SP;
7+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
78

8-
use super::*;
9+
use thin_vec::ThinVec;
910

10-
pub(crate) struct BlanketImplFinder<'a, 'tcx> {
11-
pub(crate) cx: &'a mut core::DocContext<'tcx>,
12-
}
11+
use crate::clean;
12+
use crate::clean::{
13+
clean_middle_assoc_item, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty_generics,
14+
};
15+
use crate::core::DocContext;
16+
17+
#[instrument(level = "debug", skip(cx))]
18+
pub(crate) fn synthesize_blanket_impls(
19+
cx: &mut DocContext<'_>,
20+
item_def_id: DefId,
21+
) -> Vec<clean::Item> {
22+
let tcx = cx.tcx;
23+
let ty = tcx.type_of(item_def_id);
1324

14-
impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
15-
pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
16-
let cx = &mut self.cx;
17-
let ty = cx.tcx.type_of(item_def_id);
25+
let mut blanket_impls = Vec::new();
26+
for trait_def_id in tcx.all_traits() {
27+
if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id)
28+
|| cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()
29+
{
30+
continue;
31+
}
32+
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
33+
let trait_impls = tcx.trait_impls_of(trait_def_id);
34+
'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
35+
trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`");
1836

19-
trace!("get_blanket_impls({ty:?})");
20-
let mut impls = Vec::new();
21-
for trait_def_id in cx.tcx.all_traits() {
22-
if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id)
23-
|| cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()
24-
{
37+
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
38+
if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
2539
continue;
2640
}
27-
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
28-
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
29-
'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
30-
trace!(
31-
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
32-
trait_def_id,
33-
impl_def_id
34-
);
35-
let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
36-
if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
37-
continue;
38-
}
39-
let infcx = cx.tcx.infer_ctxt().build();
40-
let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
41-
let impl_ty = ty.instantiate(infcx.tcx, args);
42-
let param_env = ty::ParamEnv::empty();
41+
let infcx = tcx.infer_ctxt().build();
42+
let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
43+
let impl_ty = ty.instantiate(tcx, args);
44+
let param_env = ty::ParamEnv::empty();
4345

44-
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
45-
let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args);
46+
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
47+
let impl_trait_ref = trait_ref.instantiate(tcx, impl_args);
4648

47-
// Require the type the impl is implemented on to match
48-
// our type, and ignore the impl if there was a mismatch.
49-
let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
50-
DefineOpaqueTypes::Yes,
51-
impl_trait_ref.self_ty(),
52-
impl_ty,
53-
) else {
54-
continue;
55-
};
56-
let InferOk { value: (), obligations } = eq_result;
57-
// FIXME(eddyb) ignoring `obligations` might cause false positives.
58-
drop(obligations);
49+
// Require the type the impl is implemented on to match
50+
// our type, and ignore the impl if there was a mismatch.
51+
let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
52+
DefineOpaqueTypes::Yes,
53+
impl_trait_ref.self_ty(),
54+
impl_ty,
55+
) else {
56+
continue;
57+
};
58+
let InferOk { value: (), obligations } = eq_result;
59+
// FIXME(eddyb) ignoring `obligations` might cause false positives.
60+
drop(obligations);
5961

60-
trace!(
61-
"invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
62+
let predicates = tcx
63+
.predicates_of(impl_def_id)
64+
.instantiate(tcx, impl_args)
65+
.predicates
66+
.into_iter()
67+
.chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx)));
68+
for predicate in predicates {
69+
let obligation = traits::Obligation::new(
70+
tcx,
71+
traits::ObligationCause::dummy(),
6272
param_env,
63-
impl_trait_ref,
64-
impl_ty
73+
predicate,
6574
);
66-
let predicates = cx
67-
.tcx
68-
.predicates_of(impl_def_id)
69-
.instantiate(cx.tcx, impl_args)
70-
.predicates
71-
.into_iter()
72-
.chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx)));
73-
for predicate in predicates {
74-
debug!("testing predicate {predicate:?}");
75-
let obligation = traits::Obligation::new(
76-
infcx.tcx,
77-
traits::ObligationCause::dummy(),
78-
param_env,
79-
predicate,
80-
);
81-
match infcx.evaluate_obligation(&obligation) {
82-
Ok(eval_result) if eval_result.may_apply() => {}
83-
Err(traits::OverflowError::Canonical) => {}
84-
_ => continue 'blanket_impls,
85-
}
75+
match infcx.evaluate_obligation(&obligation) {
76+
Ok(eval_result) if eval_result.may_apply() => {}
77+
Err(traits::OverflowError::Canonical) => {}
78+
_ => continue 'blanket_impls,
8679
}
87-
debug!(
88-
"get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
89-
trait_ref, ty
90-
);
80+
}
81+
debug!("found applicable impl for trait ref {trait_ref:?}");
9182

92-
cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));
83+
cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));
9384

94-
impls.push(Item {
95-
name: None,
96-
attrs: Default::default(),
97-
item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
98-
kind: Box::new(ImplItem(Box::new(Impl {
99-
unsafety: hir::Unsafety::Normal,
100-
generics: clean_ty_generics(
101-
cx,
102-
cx.tcx.generics_of(impl_def_id),
103-
cx.tcx.explicit_predicates_of(impl_def_id),
104-
),
105-
// FIXME(eddyb) compute both `trait_` and `for_` from
106-
// the post-inference `trait_ref`, as it's more accurate.
107-
trait_: Some(clean_trait_ref_with_bindings(
108-
cx,
109-
ty::Binder::dummy(trait_ref.instantiate_identity()),
110-
ThinVec::new(),
111-
)),
112-
for_: clean_middle_ty(
113-
ty::Binder::dummy(ty.instantiate_identity()),
114-
cx,
115-
None,
116-
None,
117-
),
118-
items: cx
119-
.tcx
120-
.associated_items(impl_def_id)
121-
.in_definition_order()
122-
.filter(|item| !item.is_impl_trait_in_trait())
123-
.map(|item| clean_middle_assoc_item(item, cx))
124-
.collect::<Vec<_>>(),
125-
polarity: ty::ImplPolarity::Positive,
126-
kind: ImplKind::Blanket(Box::new(clean_middle_ty(
127-
ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),
128-
cx,
129-
None,
130-
None,
131-
))),
132-
}))),
133-
cfg: None,
134-
inline_stmt_id: None,
135-
});
136-
}
85+
blanket_impls.push(clean::Item {
86+
name: None,
87+
attrs: Default::default(),
88+
item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
89+
kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
90+
unsafety: hir::Unsafety::Normal,
91+
generics: clean_ty_generics(
92+
cx,
93+
tcx.generics_of(impl_def_id),
94+
tcx.explicit_predicates_of(impl_def_id),
95+
),
96+
// FIXME(eddyb) compute both `trait_` and `for_` from
97+
// the post-inference `trait_ref`, as it's more accurate.
98+
trait_: Some(clean_trait_ref_with_bindings(
99+
cx,
100+
ty::Binder::dummy(trait_ref.instantiate_identity()),
101+
ThinVec::new(),
102+
)),
103+
for_: clean_middle_ty(
104+
ty::Binder::dummy(ty.instantiate_identity()),
105+
cx,
106+
None,
107+
None,
108+
),
109+
items: tcx
110+
.associated_items(impl_def_id)
111+
.in_definition_order()
112+
.filter(|item| !item.is_impl_trait_in_trait())
113+
.map(|item| clean_middle_assoc_item(item, cx))
114+
.collect(),
115+
polarity: ty::ImplPolarity::Positive,
116+
kind: clean::ImplKind::Blanket(Box::new(clean_middle_ty(
117+
ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),
118+
cx,
119+
None,
120+
None,
121+
))),
122+
}))),
123+
cfg: None,
124+
inline_stmt_id: None,
125+
});
137126
}
138-
139-
impls
140127
}
128+
129+
blanket_impls
141130
}

src/librustdoc/clean/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt};
2929
use rustc_middle::{bug, span_bug};
3030
use rustc_span::hygiene::{AstPass, MacroKind};
3131
use rustc_span::symbol::{kw, sym, Ident, Symbol};
32-
use rustc_span::{self, ExpnKind};
32+
use rustc_span::ExpnKind;
3333
use rustc_trait_selection::traits::wf::object_region_bounds;
3434

3535
use std::borrow::Cow;
3636
use std::collections::BTreeMap;
3737
use std::mem;
3838
use thin_vec::ThinVec;
3939

40-
use crate::core::{self, DocContext};
40+
use crate::core::DocContext;
4141
use crate::formats::item_type::ItemType;
4242
use crate::visit_ast::Module as DocModule;
4343

4444
use utils::*;
4545

4646
pub(crate) use self::types::*;
47-
pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
47+
pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
4848

4949
pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
5050
let mut items: Vec<Item> = vec![];

src/librustdoc/clean/utils.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::clean::auto_trait::synthesize_auto_trait_impls;
2-
use crate::clean::blanket_impl::BlanketImplFinder;
2+
use crate::clean::blanket_impl::synthesize_blanket_impls;
33
use crate::clean::render_macro_matchers::render_macro_matcher;
44
use crate::clean::{
55
clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
@@ -477,8 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
477477
}
478478
}
479479

480-
// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one.
481-
pub(crate) fn get_auto_trait_and_blanket_impls(
480+
pub(crate) fn synthesize_auto_trait_and_blanket_impls(
482481
cx: &mut DocContext<'_>,
483482
item_def_id: DefId,
484483
) -> impl Iterator<Item = Item> {
@@ -490,8 +489,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
490489
let blanket_impls = cx
491490
.sess()
492491
.prof
493-
.generic_activity("get_blanket_impls")
494-
.run(|| BlanketImplFinder { cx }.get_blanket_impls(item_def_id));
492+
.generic_activity("synthesize_blanket_impls")
493+
.run(|| synthesize_blanket_impls(cx, item_def_id));
495494
auto_impls.into_iter().chain(blanket_impls)
496495
}
497496

src/librustdoc/passes/collect_trait_impls.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
122122
_ => true,
123123
}
124124
}) {
125-
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
125+
let impls = synthesize_auto_trait_and_blanket_impls(cx, def_id);
126126
new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
127127
}
128128
}
@@ -230,8 +230,10 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
230230
if i.is_struct() || i.is_enum() || i.is_union() {
231231
// FIXME(eddyb) is this `doc(hidden)` check needed?
232232
if !self.cx.tcx.is_doc_hidden(i.item_id.expect_def_id()) {
233-
self.impls
234-
.extend(get_auto_trait_and_blanket_impls(self.cx, i.item_id.expect_def_id()));
233+
self.impls.extend(synthesize_auto_trait_and_blanket_impls(
234+
self.cx,
235+
i.item_id.expect_def_id(),
236+
));
235237
}
236238
}
237239

0 commit comments

Comments
 (0)