Skip to content

Commit 0af2783

Browse files
make it recursive
1 parent e0631f5 commit 0af2783

File tree

1 file changed

+88
-84
lines changed
  • compiler/rustc_trait_selection/src/solve/assembly

1 file changed

+88
-84
lines changed

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+88-84
Original file line numberDiff line numberDiff line change
@@ -542,97 +542,101 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
542542
goal: Goal<'tcx, G>,
543543
candidates: &mut Vec<Candidate<'tcx>>,
544544
) {
545-
let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
546-
let mut self_ty = goal.predicate.self_ty();
547-
548-
// For some deeply nested `<T>::A::B::C::D` rigid associated type,
549-
// we should explore the item bounds for all levels, since the
550-
// `associated_type_bounds` feature means that a parent associated
551-
// type may carry bounds for a nested associated type.
552-
loop {
553-
let (kind, alias_ty) = match *self_ty.kind() {
554-
ty::Bool
555-
| ty::Char
556-
| ty::Int(_)
557-
| ty::Uint(_)
558-
| ty::Float(_)
559-
| ty::Adt(_, _)
560-
| ty::Foreign(_)
561-
| ty::Str
562-
| ty::Array(_, _)
563-
| ty::Slice(_)
564-
| ty::RawPtr(_)
565-
| ty::Ref(_, _, _)
566-
| ty::FnDef(_, _)
567-
| ty::FnPtr(_)
568-
| ty::Dynamic(..)
569-
| ty::Closure(..)
570-
| ty::CoroutineClosure(..)
571-
| ty::Coroutine(..)
572-
| ty::CoroutineWitness(..)
573-
| ty::Never
574-
| ty::Tuple(_)
575-
| ty::Param(_)
576-
| ty::Placeholder(..)
577-
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
578-
| ty::Error(_) => break,
579-
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
580-
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
581-
582-
// If we hit infer when normalizing the self type of an alias,
583-
// then bail with ambiguity.
584-
ty::Infer(ty::TyVar(_)) => {
585-
if let Ok(result) = ecx
586-
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
587-
{
588-
candidates
589-
.push(Candidate { source: CandidateSource::AliasBound, result });
590-
}
591-
break;
592-
}
545+
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
546+
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
547+
});
548+
}
593549

594-
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
595-
ty::Alias(ty::Inherent | ty::Weak, _) => {
596-
unreachable!("Weak and Inherent aliases should have been normalized away")
597-
}
598-
};
550+
// For some deeply nested `<T>::A::B::C::D` rigid associated type,
551+
// we should explore the item bounds for all levels, since the
552+
// `associated_type_bounds` feature means that a parent associated
553+
// type may carry bounds for a nested associated type.
554+
//
555+
// If we have a projection, check that its self type is a rigid projection.
556+
// If so, continue searching by recursively calling after normalization.
557+
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
558+
&mut self,
559+
self_ty: Ty<'tcx>,
560+
goal: Goal<'tcx, G>,
561+
candidates: &mut Vec<Candidate<'tcx>>,
562+
) {
563+
let (kind, alias_ty) = match *self_ty.kind() {
564+
ty::Bool
565+
| ty::Char
566+
| ty::Int(_)
567+
| ty::Uint(_)
568+
| ty::Float(_)
569+
| ty::Adt(_, _)
570+
| ty::Foreign(_)
571+
| ty::Str
572+
| ty::Array(_, _)
573+
| ty::Slice(_)
574+
| ty::RawPtr(_)
575+
| ty::Ref(_, _, _)
576+
| ty::FnDef(_, _)
577+
| ty::FnPtr(_)
578+
| ty::Dynamic(..)
579+
| ty::Closure(..)
580+
| ty::CoroutineClosure(..)
581+
| ty::Coroutine(..)
582+
| ty::CoroutineWitness(..)
583+
| ty::Never
584+
| ty::Tuple(_)
585+
| ty::Param(_)
586+
| ty::Placeholder(..)
587+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
588+
| ty::Error(_) => return,
589+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
590+
bug!("unexpected self type for `{goal:?}`")
591+
}
599592

600-
for assumption in
601-
ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args)
593+
ty::Infer(ty::TyVar(_)) => {
594+
// If we hit infer when normalizing the self type of an alias,
595+
// then bail with ambiguity. We should never encounter this on
596+
// the *first* iteration of this recursive function.
597+
if let Ok(result) =
598+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
602599
{
603-
match G::consider_alias_bound_candidate(ecx, goal, assumption) {
604-
Ok(result) => {
605-
candidates
606-
.push(Candidate { source: CandidateSource::AliasBound, result });
607-
}
608-
Err(NoSolution) => {}
609-
}
600+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
610601
}
602+
return;
603+
}
611604

612-
// If we have a projection, check that its self type is a rigid projection.
613-
// If so, continue searching.
614-
if kind == ty::Projection {
615-
match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
616-
Some(next_self_ty) => self_ty = next_self_ty,
617-
None => {
618-
if let Ok(result) = ecx
619-
.evaluate_added_goals_and_make_canonical_response(
620-
Certainty::OVERFLOW,
621-
)
622-
{
623-
candidates.push(Candidate {
624-
source: CandidateSource::AliasBound,
625-
result,
626-
});
627-
}
628-
break;
629-
}
630-
}
631-
} else {
632-
break;
605+
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
606+
ty::Alias(ty::Inherent | ty::Weak, _) => {
607+
unreachable!("Weak and Inherent aliases should have been normalized away already")
608+
}
609+
};
610+
611+
for assumption in
612+
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
613+
{
614+
match G::consider_alias_bound_candidate(self, goal, assumption) {
615+
Ok(result) => {
616+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
633617
}
618+
Err(NoSolution) => {}
634619
}
635-
});
620+
}
621+
622+
if kind != ty::Projection {
623+
return;
624+
}
625+
626+
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
627+
Some(next_self_ty) => {
628+
// recurse on the alias self ty
629+
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
630+
}
631+
None => {
632+
// bail if we overflow when normalizing
633+
if let Ok(result) =
634+
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
635+
{
636+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
637+
}
638+
}
639+
}
636640
}
637641

638642
/// Check that we are allowed to use an alias bound originating from the self

0 commit comments

Comments
 (0)