Skip to content

Commit f515201

Browse files
make it recursive
1 parent e0631f5 commit f515201

File tree

3 files changed

+95
-93
lines changed

3 files changed

+95
-93
lines changed

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

+90-84
Original file line numberDiff line numberDiff line change
@@ -542,97 +542,103 @@ 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+
// FIXME: This may recurse infinitely, but I can't seem to trigger it without
558+
// hitting another overflow error something. Add a depth parameter needed later.
559+
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
560+
&mut self,
561+
self_ty: Ty<'tcx>,
562+
goal: Goal<'tcx, G>,
563+
candidates: &mut Vec<Candidate<'tcx>>,
564+
) {
565+
let (kind, alias_ty) = match *self_ty.kind() {
566+
ty::Bool
567+
| ty::Char
568+
| ty::Int(_)
569+
| ty::Uint(_)
570+
| ty::Float(_)
571+
| ty::Adt(_, _)
572+
| ty::Foreign(_)
573+
| ty::Str
574+
| ty::Array(_, _)
575+
| ty::Slice(_)
576+
| ty::RawPtr(_)
577+
| ty::Ref(_, _, _)
578+
| ty::FnDef(_, _)
579+
| ty::FnPtr(_)
580+
| ty::Dynamic(..)
581+
| ty::Closure(..)
582+
| ty::CoroutineClosure(..)
583+
| ty::Coroutine(..)
584+
| ty::CoroutineWitness(..)
585+
| ty::Never
586+
| ty::Tuple(_)
587+
| ty::Param(_)
588+
| ty::Placeholder(..)
589+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
590+
| ty::Error(_) => return,
591+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
592+
bug!("unexpected self type for `{goal:?}`")
593+
}
599594

600-
for assumption in
601-
ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args)
595+
ty::Infer(ty::TyVar(_)) => {
596+
// If we hit infer when normalizing the self type of an alias,
597+
// then bail with ambiguity. We should never encounter this on
598+
// the *first* iteration of this recursive function.
599+
if let Ok(result) =
600+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
602601
{
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-
}
602+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
610603
}
604+
return;
605+
}
611606

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;
607+
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
608+
ty::Alias(ty::Inherent | ty::Weak, _) => {
609+
unreachable!("Weak and Inherent aliases should have been normalized away already")
610+
}
611+
};
612+
613+
for assumption in
614+
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
615+
{
616+
match G::consider_alias_bound_candidate(self, goal, assumption) {
617+
Ok(result) => {
618+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
633619
}
620+
Err(NoSolution) => {}
634621
}
635-
});
622+
}
623+
624+
if kind != ty::Projection {
625+
return;
626+
}
627+
628+
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
629+
// Recurse on the self type of the projection.
630+
Some(next_self_ty) => {
631+
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
632+
}
633+
// Bail if we overflow when normalizing, adding an ambiguous candidate.
634+
None => {
635+
if let Ok(result) =
636+
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
637+
{
638+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
639+
}
640+
}
641+
}
636642
}
637643

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

compiler/rustc_trait_selection/src/traits/project.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1646,11 +1646,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
16461646

16471647
ControlFlow::Continue(())
16481648
},
1649-
|| {
1650-
// `ProjectionCandidateSet` is borrowed in the above closure,
1651-
// so just mark ambiguous outside of the closure.
1652-
ambiguous = true;
1653-
},
1649+
// `ProjectionCandidateSet` is borrowed in the above closure,
1650+
// so just mark ambiguous outside of the closure.
1651+
|| ambiguous = true,
16541652
);
16551653

16561654
if ambiguous {

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
201201

202202
ControlFlow::Continue(())
203203
},
204-
|| {
205-
// On ambiguity.
206-
candidates.ambiguous = true;
207-
},
204+
// On ambiguity.
205+
|| candidates.ambiguous = true,
208206
);
209207
});
210208
}

0 commit comments

Comments
 (0)