Skip to content

Commit

Permalink
fix(frontend): make path_to breadth-first
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Franceschino authored and maximebuyse committed Jul 25, 2024
1 parent 2a66ae9 commit e637a2c
Showing 1 changed file with 68 additions and 50 deletions.
118 changes: 68 additions & 50 deletions frontend/exporter/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,63 +201,81 @@ pub mod rustc {
.collect()
}

#[tracing::instrument(level = "trace", skip(s))]
fn path_to(
self,
s: &S,
target: PolyTraitRef<'tcx>,
param_env: rustc_middle::ty::ParamEnv<'tcx>,
) -> Option<Path<'tcx>> {
let tcx = s.base().tcx;
if predicate_equality(self.upcast(tcx), target.upcast(tcx), param_env, s) {
return Some(vec![]);
#[tracing::instrument(level = "trace", skip(s))]
fn path_to(
self,
s: &S,
target: PolyTraitRef<'tcx>,
param_env: rustc_middle::ty::ParamEnv<'tcx>,
) -> Option<Path<'tcx>> {
let tcx = s.base().tcx;

/// A candidate projects `self` along a path reaching some
/// predicate. A candidate is selected when its predicate
/// is the one expected, aka `target`.
#[derive(Debug)]
struct Candidate<'tcx> {
path: Path<'tcx>,
pred: PolyTraitPredicate<'tcx>,
}

use std::collections::VecDeque;
let mut candidates: VecDeque<Candidate<'tcx>> = vec![Candidate {
path: vec![],
pred: self,
}]
.into();

let target_pred = target.to_predicate(tcx);
let mut seen = std::collections::HashSet::new();

while let Some(candidate) = candidates.pop_front() {
{
// If a predicate was already seen, we know it is
// not the one we are looking for: we skip it.
if seen.contains(&candidate.pred) {
continue;
}
seen.insert(candidate.pred.clone());
}
tracing::trace!("candidate={:#?}", candidate);

let recurse = |p: Self| {
if p == self {
return None;
// if the candidate equals the target, let's return its path
if predicate_equality(candidate.pred.to_predicate(tcx), target_pred, param_env, s) {
return Some(candidate.path);
}

// otherwise, we add to the queue all paths reachable from the candidate
for (index, parent_pred) in self.parents_trait_predicates(s) {
let mut path = candidate.path.clone();
path.push(PathChunk::Parent {
predicate: parent_pred.clone(),
index,
});
candidates.push_back(Candidate {
pred: parent_pred.clone(),
path,
});
}
for (item, binder) in self.associated_items_trait_predicates(s) {
for (index, parent_pred) in binder.skip_binder().into_iter() {
let mut path = candidate.path.clone();
path.push(PathChunk::AssocItem {
item,
predicate: parent_pred.clone(),
index,
});
candidates.push_back(Candidate {
pred: parent_pred.clone(),
path,
});
}
p.path_to(s, target, param_env)
};
fn cons<T>(hd: T, tail: Vec<T>) -> Vec<T> {
vec![hd].into_iter().chain(tail.into_iter()).collect()
}
self.parents_trait_predicates(s)
.into_iter()
.filter_map(|(index, p)| {
recurse(p).map(|path| {
cons(
PathChunk::Parent {
predicate: p,
index,
},
path,
)
})
})
.max_by_key(|path| path.len())
.or_else(|| {
self.associated_items_trait_predicates(s)
.into_iter()
.filter_map(|(item, binder)| {
binder.skip_binder().into_iter().find_map(|(index, p)| {
recurse(p).map(|path| {
cons(
PathChunk::AssocItem {
item,
predicate: p,
index,
},
path,
)
})
})
})
.max_by_key(|path| path.len())
})
}
None
}
}
}

impl ImplExprAtom {
fn with_args(self, args: Vec<ImplExpr>, r#trait: TraitRef) -> ImplExpr {
Expand Down

0 comments on commit e637a2c

Please sign in to comment.