about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-02-07 00:19:12 +0000
committerMichael Goulet <michael@errs.io>2024-02-09 00:13:52 +0000
commit7057188c549cb38e72843c9c344f77659bf67bc9 (patch)
tree4b09f302071db30b561311711012f5563ade8b79 /compiler
parent7a63d3f16a44ade84f7fd99a7257ff753eb1da1d (diff)
downloadrust-7057188c549cb38e72843c9c344f77659bf67bc9.tar.gz
rust-7057188c549cb38e72843c9c344f77659bf67bc9.zip
make it recursive
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs174
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs6
3 files changed, 95 insertions, 93 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 150894ba83e..380f7ac2d2d 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -542,97 +542,103 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
-            let mut self_ty = goal.predicate.self_ty();
-
-            // For some deeply nested `<T>::A::B::C::D` rigid associated type,
-            // we should explore the item bounds for all levels, since the
-            // `associated_type_bounds` feature means that a parent associated
-            // type may carry bounds for a nested associated type.
-            loop {
-                let (kind, alias_ty) = match *self_ty.kind() {
-                    ty::Bool
-                    | ty::Char
-                    | ty::Int(_)
-                    | ty::Uint(_)
-                    | ty::Float(_)
-                    | ty::Adt(_, _)
-                    | ty::Foreign(_)
-                    | ty::Str
-                    | ty::Array(_, _)
-                    | ty::Slice(_)
-                    | ty::RawPtr(_)
-                    | ty::Ref(_, _, _)
-                    | ty::FnDef(_, _)
-                    | ty::FnPtr(_)
-                    | ty::Dynamic(..)
-                    | ty::Closure(..)
-                    | ty::CoroutineClosure(..)
-                    | ty::Coroutine(..)
-                    | ty::CoroutineWitness(..)
-                    | ty::Never
-                    | ty::Tuple(_)
-                    | ty::Param(_)
-                    | ty::Placeholder(..)
-                    | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
-                    | ty::Error(_) => break,
-                    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,
-                    // then bail with ambiguity.
-                    ty::Infer(ty::TyVar(_)) => {
-                        if let Ok(result) = ecx
-                            .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-                        {
-                            candidates
-                                .push(Candidate { source: CandidateSource::AliasBound, result });
-                        }
-                        break;
-                    }
+        let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
+            ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
+        });
+    }
 
-                    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 some deeply nested `<T>::A::B::C::D` rigid associated type,
+    /// we should explore the item bounds for all levels, since the
+    /// `associated_type_bounds` feature means that a parent associated
+    /// type may carry bounds for a nested associated type.
+    ///
+    /// If we have a projection, check that its self type is a rigid projection.
+    /// If so, continue searching by recursively calling after normalization.
+    // FIXME: This may recurse infinitely, but I can't seem to trigger it without
+    // hitting another overflow error something. Add a depth parameter needed later.
+    fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
+        &mut self,
+        self_ty: Ty<'tcx>,
+        goal: Goal<'tcx, G>,
+        candidates: &mut Vec<Candidate<'tcx>>,
+    ) {
+        let (kind, alias_ty) = match *self_ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Dynamic(..)
+            | ty::Closure(..)
+            | 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:?}`")
+            }
 
-                for assumption in
-                    ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args)
+            ty::Infer(ty::TyVar(_)) => {
+                // If we hit infer when normalizing the self type of an alias,
+                // then bail with ambiguity. We should never encounter this on
+                // the *first* iteration of this recursive function.
+                if let Ok(result) =
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
                 {
-                    match G::consider_alias_bound_candidate(ecx, goal, assumption) {
-                        Ok(result) => {
-                            candidates
-                                .push(Candidate { source: CandidateSource::AliasBound, result });
-                        }
-                        Err(NoSolution) => {}
-                    }
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result });
                 }
+                return;
+            }
 
-                // If we have a projection, check that its self type is a rigid projection.
-                // If so, continue searching.
-                if kind == ty::Projection {
-                    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
-                                .evaluate_added_goals_and_make_canonical_response(
-                                    Certainty::OVERFLOW,
-                                )
-                            {
-                                candidates.push(Candidate {
-                                    source: CandidateSource::AliasBound,
-                                    result,
-                                });
-                            }
-                            break;
-                        }
-                    }
-                } else {
-                    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 already")
+            }
+        };
+
+        for assumption in
+            self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
+        {
+            match G::consider_alias_bound_candidate(self, goal, assumption) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result });
                 }
+                Err(NoSolution) => {}
             }
-        });
+        }
+
+        if kind != ty::Projection {
+            return;
+        }
+
+        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
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8f47e45df0c..8cfbd7d3ce6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1645,11 +1645,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 
             ControlFlow::Continue(())
         },
-        || {
-            // `ProjectionCandidateSet` is borrowed in the above closure,
-            // so just mark ambiguous outside of the closure.
-            ambiguous = true;
-        },
+        // `ProjectionCandidateSet` is borrowed in the above closure,
+        // so just mark ambiguous outside of the closure.
+        || ambiguous = true,
     );
 
     if ambiguous {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 248d75aaec7..27dbe0351da 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -201,10 +201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                     ControlFlow::Continue(())
                 },
-                || {
-                    // On ambiguity.
-                    candidates.ambiguous = true;
-                },
+                // On ambiguity.
+                || candidates.ambiguous = true,
             );
         });
     }