diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d8303a671c4a5..8c42d27572430 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -338,18 +338,39 @@ impl TyCtxt<'_> { self.parent(id.into().to_def_id()).expect_local() } - pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { - if descendant.krate != ancestor.krate { - return false; + /// Compare def-ids based on their position in def-id tree, ancestor def-ids are considered + /// larger than descendant def-ids, and two different def-ids are considered unordered if + /// neither of them is an ancestor of the other. + fn def_id_partial_cmp(self, lhs: DefId, rhs: DefId) -> Option { + // Def-ids from different crates are always unordered. + if lhs.krate != rhs.krate { + return None; } - while descendant != ancestor { - match self.opt_parent(descendant) { - Some(parent) => descendant = parent, - None => return false, + // Def-ids of parent nodes are always created before def-ids of child nodes + // and have a smaller index, so we only need to search in one direction, + // either from lhs to rhs, or vice versa. + let search = |mut start: DefId, finish: DefId, ord| { + while start.index != finish.index { + match self.opt_parent(start) { + Some(parent) => start.index = parent.index, + None => return None, + } } + Some(ord) + }; + match lhs.index.cmp(&rhs.index) { + Ordering::Equal => Some(Ordering::Equal), + Ordering::Less => search(rhs, lhs, Ordering::Greater), + Ordering::Greater => search(lhs, rhs, Ordering::Less), } - true + } + + pub fn is_descendant_of(self, descendant: DefId, ancestor: DefId) -> bool { + matches!( + self.def_id_partial_cmp(descendant, ancestor), + Some(Ordering::Less | Ordering::Equal) + ) } } @@ -391,15 +412,7 @@ impl> Visibility { (Visibility::Restricted(_), Visibility::Public) => Some(Ordering::Less), (Visibility::Restricted(lhs_id), Visibility::Restricted(rhs_id)) => { let (lhs_id, rhs_id) = (lhs_id.into(), rhs_id.into()); - if lhs_id == rhs_id { - Some(Ordering::Equal) - } else if tcx.is_descendant_of(rhs_id, lhs_id) { - Some(Ordering::Greater) - } else if tcx.is_descendant_of(lhs_id, rhs_id) { - Some(Ordering::Less) - } else { - None - } + tcx.def_id_partial_cmp(lhs_id, rhs_id) } } }