Skip to content

Commit d22bedf

Browse files
committed
Refactor my mess into a separate function
1 parent c91c53f commit d22bedf

File tree

1 file changed

+63
-59
lines changed

1 file changed

+63
-59
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 63 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -291,65 +291,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
291291
did,
292292
) => {
293293
debug!("looking for associated item named {} for item {:?}", item_name, did);
294-
let ty = cx.tcx.type_of(did);
295-
// Checks if item_name belongs to `impl SomeItem`
296-
// `def_id` should be a trait
297-
let associated_items_for_def_id = |tcx: ty::TyCtxt<'_>, def_id: DefId| -> Vec<_> {
298-
tcx.associated_items(def_id)
299-
.filter_by_name(tcx, Ident::with_dummy_span(item_name), def_id)
300-
.map(|assoc| (assoc.def_id, assoc.kind))
301-
// TODO: this collect seems a shame
302-
.collect()
303-
};
304-
let impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
305-
let candidates: Vec<_> = impls
306-
.flat_map(|impl_outer| {
307-
match impl_outer.inner {
308-
ImplItem(impl_) => {
309-
debug!("considering trait {:?}", impl_.trait_);
310-
// Give precedence to methods that were overridden
311-
if !impl_.provided_trait_methods.contains(&*item_name.as_str()) {
312-
impl_.items.into_iter()
313-
.filter(|assoc| assoc.name.as_deref() == Some(&*item_name.as_str()))
314-
.map(|assoc| {
315-
trace!("considering associated item {:?}", assoc.inner);
316-
// We have a slight issue: normal methods come from `clean` types,
317-
// but provided methods come directly from `tcx`.
318-
// Fortunately, we don't need the whole method, we just need to know
319-
// what kind of associated item it is.
320-
(
321-
assoc.def_id,
322-
assoc.inner.as_assoc_kind()
323-
.expect("inner items for a trait should be associated items")
324-
)
325-
})
326-
// TODO: this collect seems a shame
327-
.collect::<Vec<_>>()
328-
} else {
329-
// These are provided methods or default types:
330-
// ```
331-
// trait T {
332-
// type A = usize;
333-
// fn has_default() -> A { 0 }
334-
// }
335-
// ```
336-
// TODO: this is wrong, it should look at the trait, not the impl
337-
associated_items_for_def_id(cx.tcx, impl_outer.def_id)
338-
}
339-
}
340-
_ => panic!("get_impls returned something that wasn't an impl"),
341-
}
342-
})
343-
.chain(cx.tcx.all_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
344-
//.chain(cx.tcx.all_local_trait_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
345-
.collect();
346-
if candidates.len() > 1 {
347-
let candidates = candidates.into_iter()
348-
.map(|(def_id, kind)| Res::Def(kind.as_def_kind(), def_id))
349-
.collect();
350-
return Err(ErrorKind::Ambiguous { candidates });
351-
}
352-
let impl_kind = candidates.into_iter().next().map(|(_, kind)| kind);
294+
let impl_kind = resolve_associated_trait_item(did, item_name, &self.cx)?;
353295
// TODO: is this necessary? It doesn't look right, and also only works for local items
354296
let trait_kind = self.cx.as_local_hir_id(item.def_id)
355297
.and_then(|item_hir| {
@@ -484,6 +426,68 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
484426
}
485427
}
486428

429+
fn resolve_associated_trait_item(did: DefId, item_name: Symbol, cx: &DocContext<'_>) -> Result<Option<ty::AssocKind>, ErrorKind> {
430+
let ty = cx.tcx.type_of(did);
431+
// Checks if item_name belongs to `impl SomeItem`
432+
// `def_id` should be a trait
433+
let associated_items_for_def_id = |tcx: ty::TyCtxt<'_>, def_id: DefId| -> Vec<_> {
434+
tcx.associated_items(def_id)
435+
.filter_by_name(tcx, Ident::with_dummy_span(item_name), def_id)
436+
.map(|assoc| (assoc.def_id, assoc.kind))
437+
// TODO: this collect seems a shame
438+
.collect()
439+
};
440+
let impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
441+
let candidates: Vec<_> = impls
442+
.flat_map(|impl_outer| {
443+
match impl_outer.inner {
444+
ImplItem(impl_) => {
445+
debug!("considering trait {:?}", impl_.trait_);
446+
// Give precedence to methods that were overridden
447+
if !impl_.provided_trait_methods.contains(&*item_name.as_str()) {
448+
impl_.items.into_iter()
449+
.filter(|assoc| assoc.name.as_deref() == Some(&*item_name.as_str()))
450+
.map(|assoc| {
451+
trace!("considering associated item {:?}", assoc.inner);
452+
// We have a slight issue: normal methods come from `clean` types,
453+
// but provided methods come directly from `tcx`.
454+
// Fortunately, we don't need the whole method, we just need to know
455+
// what kind of associated item it is.
456+
(
457+
assoc.def_id,
458+
assoc.inner.as_assoc_kind()
459+
.expect("inner items for a trait should be associated items")
460+
)
461+
})
462+
// TODO: this collect seems a shame
463+
.collect::<Vec<_>>()
464+
} else {
465+
// These are provided methods or default types:
466+
// ```
467+
// trait T {
468+
// type A = usize;
469+
// fn has_default() -> A { 0 }
470+
// }
471+
// ```
472+
// TODO: this is wrong, it should look at the trait, not the impl
473+
associated_items_for_def_id(cx.tcx, impl_outer.def_id)
474+
}
475+
}
476+
_ => panic!("get_impls returned something that wasn't an impl"),
477+
}
478+
})
479+
.chain(cx.tcx.all_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
480+
//.chain(cx.tcx.all_local_trait_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
481+
.collect();
482+
if candidates.len() > 1 {
483+
let candidates = candidates.into_iter()
484+
.map(|(def_id, kind)| Res::Def(kind.as_def_kind(), def_id))
485+
.collect();
486+
return Err(ErrorKind::Ambiguous { candidates });
487+
}
488+
Ok(candidates.into_iter().next().map(|(_, kind)| kind))
489+
}
490+
487491
/// Check for resolve collisions between a trait and its derive
488492
///
489493
/// These are common and we should just resolve to the trait in that case

0 commit comments

Comments
 (0)