summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-05-27 19:27:59 +0000
committerMichael Goulet <michael@errs.io>2023-06-06 18:44:22 +0000
commit3ea7c512bd1587006a1c196df841e9b7ec60fb0b (patch)
tree959d305a2703a59cfba5b8d579b7744ad0c0f726 /compiler/rustc_trait_selection/src
parent7a2cdf20e42c5b2a4d0f259eab8968cda7ae55c2 (diff)
downloadrust-3ea7c512bd1587006a1c196df841e9b7ec60fb0b.tar.gz
rust-3ea7c512bd1587006a1c196df841e9b7ec60fb0b.zip
Fall back to bidirectional normalizes-to if no subst-eq in alias-eq goal
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs95
1 files changed, 72 insertions, 23 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 59ab3bc3a72..66a4d36a1e5 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -79,11 +79,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     // them. This is necessary for inference during typeck.
                     //
                     // As this is incomplete, we must not do so during coherence.
-                    match (self.solver_mode(), subst_relate_response) {
-                        (SolverMode::Normal, Ok(response)) => Ok(response),
-                        (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
-                            self.flounder(&candidates)
+                    match self.solver_mode() {
+                        SolverMode::Normal => {
+                            if let Ok(subst_relate_response) = subst_relate_response {
+                                Ok(subst_relate_response)
+                            } else if let Ok(bidirectional_normalizes_to_response) = self
+                                .assemble_bidirectional_normalizes_to_candidate(
+                                    param_env, lhs, rhs, direction,
+                                )
+                            {
+                                Ok(bidirectional_normalizes_to_response)
+                            } else {
+                                self.flounder(&candidates)
+                            }
                         }
+                        SolverMode::Coherence => self.flounder(&candidates),
                     }
                 }
             }
@@ -100,29 +110,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         invert: Invert,
     ) -> QueryResult<'tcx> {
         self.probe(|ecx| {
-            let other = match direction {
-                // This is purely an optimization.
-                ty::AliasRelationDirection::Equate => other,
-
-                ty::AliasRelationDirection::Subtype => {
-                    let fresh = ecx.next_term_infer_of_kind(other);
-                    let (sub, sup) = match invert {
-                        Invert::No => (fresh, other),
-                        Invert::Yes => (other, fresh),
-                    };
-                    ecx.sub(param_env, sub, sup)?;
-                    fresh
-                }
-            };
-            ecx.add_goal(Goal::new(
-                ecx.tcx(),
-                param_env,
-                ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
-            ));
+            ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
 
+    fn normalizes_to_inner(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        alias: ty::AliasTy<'tcx>,
+        other: ty::Term<'tcx>,
+        direction: ty::AliasRelationDirection,
+        invert: Invert,
+    ) -> Result<(), NoSolution> {
+        let other = match direction {
+            // This is purely an optimization.
+            ty::AliasRelationDirection::Equate => other,
+
+            ty::AliasRelationDirection::Subtype => {
+                let fresh = self.next_term_infer_of_kind(other);
+                let (sub, sup) = match invert {
+                    Invert::No => (fresh, other),
+                    Invert::Yes => (other, fresh),
+                };
+                self.sub(param_env, sub, sup)?;
+                fresh
+            }
+        };
+        self.add_goal(Goal::new(
+            self.tcx(),
+            param_env,
+            ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }),
+        ));
+
+        Ok(())
+    }
+
     fn assemble_subst_relate_candidate(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
@@ -143,4 +166,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
+
+    fn assemble_bidirectional_normalizes_to_candidate(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: ty::Term<'tcx>,
+        rhs: ty::Term<'tcx>,
+        direction: ty::AliasRelationDirection,
+    ) -> QueryResult<'tcx> {
+        self.probe(|ecx| {
+            ecx.normalizes_to_inner(
+                param_env,
+                lhs.to_alias_ty(ecx.tcx()).unwrap(),
+                rhs,
+                direction,
+                Invert::No,
+            )?;
+            ecx.normalizes_to_inner(
+                param_env,
+                rhs.to_alias_ty(ecx.tcx()).unwrap(),
+                lhs,
+                direction,
+                Invert::Yes,
+            )?;
+            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+        })
+    }
 }