make it recursive

This commit is contained in:
Michael Goulet 2024-02-07 00:19:12 +00:00
parent 7a63d3f16a
commit 7057188c54
3 changed files with 95 additions and 93 deletions

View File

@ -542,97 +542,103 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
goal: Goal<'tcx, G>, goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>, candidates: &mut Vec<Candidate<'tcx>>,
) { ) {
let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
let mut self_ty = goal.predicate.self_ty(); ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
});
}
// For some deeply nested `<T>::A::B::C::D` rigid associated type, /// For some deeply nested `<T>::A::B::C::D` rigid associated type,
// we should explore the item bounds for all levels, since the /// we should explore the item bounds for all levels, since the
// `associated_type_bounds` feature means that a parent associated /// `associated_type_bounds` feature means that a parent associated
// type may carry bounds for a nested associated type. /// type may carry bounds for a nested associated type.
loop { ///
let (kind, alias_ty) = match *self_ty.kind() { /// If we have a projection, check that its self type is a rigid projection.
ty::Bool /// If so, continue searching by recursively calling after normalization.
| ty::Char // FIXME: This may recurse infinitely, but I can't seem to trigger it without
| ty::Int(_) // hitting another overflow error something. Add a depth parameter needed later.
| ty::Uint(_) fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
| ty::Float(_) &mut self,
| ty::Adt(_, _) self_ty: Ty<'tcx>,
| ty::Foreign(_) goal: Goal<'tcx, G>,
| ty::Str candidates: &mut Vec<Candidate<'tcx>>,
| ty::Array(_, _) ) {
| ty::Slice(_) let (kind, alias_ty) = match *self_ty.kind() {
| ty::RawPtr(_) ty::Bool
| ty::Ref(_, _, _) | ty::Char
| ty::FnDef(_, _) | ty::Int(_)
| ty::FnPtr(_) | ty::Uint(_)
| ty::Dynamic(..) | ty::Float(_)
| ty::Closure(..) | ty::Adt(_, _)
| ty::CoroutineClosure(..) | ty::Foreign(_)
| ty::Coroutine(..) | ty::Str
| ty::CoroutineWitness(..) | ty::Array(_, _)
| ty::Never | ty::Slice(_)
| ty::Tuple(_) | ty::RawPtr(_)
| ty::Param(_) | ty::Ref(_, _, _)
| ty::Placeholder(..) | ty::FnDef(_, _)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::FnPtr(_)
| ty::Error(_) => break, | ty::Dynamic(..)
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Closure(..)
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), | ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Param(_)
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
bug!("unexpected self type for `{goal:?}`")
}
// If we hit infer when normalizing the self type of an alias, ty::Infer(ty::TyVar(_)) => {
// then bail with ambiguity. // If we hit infer when normalizing the self type of an alias,
ty::Infer(ty::TyVar(_)) => { // then bail with ambiguity. We should never encounter this on
if let Ok(result) = ecx // the *first* iteration of this recursive function.
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) if let Ok(result) =
{ self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
candidates
.push(Candidate { source: CandidateSource::AliasBound, result });
}
break;
}
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
ty::Alias(ty::Inherent | ty::Weak, _) => {
unreachable!("Weak and Inherent aliases should have been normalized away")
}
};
for assumption in
ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args)
{ {
match G::consider_alias_bound_candidate(ecx, goal, assumption) { candidates.push(Candidate { source: CandidateSource::AliasBound, result });
Ok(result) => {
candidates
.push(Candidate { source: CandidateSource::AliasBound, result });
}
Err(NoSolution) => {}
}
} }
return;
}
// If we have a projection, check that its self type is a rigid projection. ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
// If so, continue searching. ty::Alias(ty::Inherent | ty::Weak, _) => {
if kind == ty::Projection { unreachable!("Weak and Inherent aliases should have been normalized away already")
match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { }
Some(next_self_ty) => self_ty = next_self_ty, };
None => {
if let Ok(result) = ecx for assumption in
.evaluate_added_goals_and_make_canonical_response( self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
Certainty::OVERFLOW, {
) match G::consider_alias_bound_candidate(self, goal, assumption) {
{ Ok(result) => {
candidates.push(Candidate { candidates.push(Candidate { source: CandidateSource::AliasBound, result });
source: CandidateSource::AliasBound, }
result, Err(NoSolution) => {}
}); }
} }
break;
} if kind != ty::Projection {
} return;
} else { }
break;
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
// Recurse on the self type of the projection.
Some(next_self_ty) => {
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
}
// Bail if we overflow when normalizing, adding an ambiguous candidate.
None => {
if let Ok(result) =
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
} }
} }
}); }
} }
/// Check that we are allowed to use an alias bound originating from the self /// Check that we are allowed to use an alias bound originating from the self

View File

@ -1645,11 +1645,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
ControlFlow::Continue(()) ControlFlow::Continue(())
}, },
|| { // `ProjectionCandidateSet` is borrowed in the above closure,
// `ProjectionCandidateSet` is borrowed in the above closure, // so just mark ambiguous outside of the closure.
// so just mark ambiguous outside of the closure. || ambiguous = true,
ambiguous = true;
},
); );
if ambiguous { if ambiguous {

View File

@ -201,10 +201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ControlFlow::Continue(()) ControlFlow::Continue(())
}, },
|| { // On ambiguity.
// On ambiguity. || candidates.ambiguous = true,
candidates.ambiguous = true;
},
); );
}); });
} }