///
/// The graph provides two key services:
///
-/// - Construction, which implicitly checks for overlapping impls (i.e., impls
+/// - Construction. This implicitly checks for overlapping impls (i.e., impls
/// that overlap but where neither specializes the other -- an artifact of the
/// simple "chain" rule.
///
/// has at most one parent.
#[derive(RustcEncodable, RustcDecodable)]
pub struct Graph {
- // all impls have a parent; the "root" impls have as their parent the def_id
- // of the trait
+ // All impls have a parent; the "root" impls have as their parent the `def_id`
+ // of the trait.
parent: DefIdMap<DefId>,
- // the "root" impls are found by looking up the trait's def_id.
+ // The "root" impls are found by looking up the trait's def_id.
children: DefIdMap<Children>,
}
/// The impl was inserted as a new child in this group of children.
BecameNewSibling(Option<OverlapError>),
- /// The impl should replace an existing impl X, because the impl specializes X.
- ReplaceChild(DefId),
+ /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc.
+ ReplaceChildren(Vec<DefId>),
/// The impl is a specialization of an existing child.
ShouldRecurseOn(DefId),
}
impl<'a, 'gcx, 'tcx> Children {
- /// Insert an impl into this set of children without comparing to any existing impls
+ /// Insert an impl into this set of children without comparing to any existing impls.
fn insert_blindly(&mut self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId) {
-> Result<Inserted, OverlapError>
{
let mut last_lint = None;
+ let mut replace_children = Vec::new();
debug!(
"insert(impl_def_id={:?}, simplified_self={:?})",
);
let overlap_error = |overlap: traits::coherence::OverlapResult<'_>| {
- // overlap, but no specialization; error out
+ // Found overlap, but no specialization; error out.
let trait_ref = overlap.impl_header.trait_ref.unwrap();
let self_ty = trait_ref.self_ty();
OverlapError {
with_impl: possible_sibling,
trait_desc: trait_ref.to_string(),
- // only report the Self type if it has at least
+ // Only report the `Self` type if it has at least
// some outer concrete shell; otherwise, it's
// not adding much information.
self_desc: if self_ty.has_concrete_skeleton() {
debug!("descending as child of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
- // the impl specializes possible_sibling
+ // The impl specializes `possible_sibling`.
return Ok(Inserted::ShouldRecurseOn(possible_sibling));
} else if ge && !le {
debug!("placing as parent of TraitRef {:?}",
tcx.impl_trait_ref(possible_sibling).unwrap());
- return Ok(Inserted::ReplaceChild(possible_sibling));
+ replace_children.push(possible_sibling);
} else {
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
traits::overlapping_impls(
}
}
- // no overlap with any potential siblings, so add as a new sibling
+ if !replace_children.is_empty() {
+ return Ok(Inserted::ReplaceChildren(replace_children));
+ }
+
+ // No overlap with any potential siblings, so add as a new sibling.
debug!("placing as new sibling");
self.insert_blindly(tcx, impl_def_id);
Ok(Inserted::BecameNewSibling(last_lint))
debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
impl_def_id, trait_ref);
- // if the reference itself contains an earlier error (e.g., due to a
+ // If the reference itself contains an earlier error (e.g., due to a
// resolution failure), then we just insert the impl at the top level of
// the graph and claim that there's no overlap (in order to suppress
// bogus errors).
let mut last_lint = None;
let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);
- // Descend the specialization tree, where `parent` is the current parent node
+ // Descend the specialization tree, where `parent` is the current parent node.
loop {
use self::Inserted::*;
last_lint = opt_lint;
break;
}
- ReplaceChild(grand_child_to_be) => {
+ ReplaceChildren(grand_children_to_be) => {
// We currently have
//
// P
let siblings = self.children
.get_mut(&parent)
.unwrap();
- siblings.remove_existing(tcx, grand_child_to_be);
+ for &grand_child_to_be in &grand_children_to_be {
+ siblings.remove_existing(tcx, grand_child_to_be);
+ }
siblings.insert_blindly(tcx, impl_def_id);
}
- // Set G's parent to N and N's parent to P
- self.parent.insert(grand_child_to_be, impl_def_id);
+ // Set G's parent to N and N's parent to P.
+ for &grand_child_to_be in &grand_children_to_be {
+ self.parent.insert(grand_child_to_be, impl_def_id);
+ }
self.parent.insert(impl_def_id, parent);
// Add G as N's child.
- self.children.entry(impl_def_id).or_default()
- .insert_blindly(tcx, grand_child_to_be);
+ for &grand_child_to_be in &grand_children_to_be {
+ self.children.entry(impl_def_id).or_default()
+ .insert_blindly(tcx, grand_child_to_be);
+ }
break;
}
ShouldRecurseOn(new_parent) => {
pub fn items(
&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
+ ) -> ty::AssociatedItemsIterator<'a, 'gcx, 'tcx> {
tcx.associated_items(self.def_id())
}
impl<'a, 'gcx, 'tcx> Ancestors {
/// Search the items from the given ancestors, returning each definition
/// with the given name and the given kind.
- #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+ // FIXME(#35870): avoid closures being unexported due to `impl Trait`.
+ #[inline]
pub fn defs(
self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,