summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/solve
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-04-26 22:33:33 +0000
committerMichael Goulet <michael@errs.io>2023-04-26 22:33:49 +0000
commitee8942138a9ff0dedbe8575f0aacaea2ec78a51f (patch)
tree69ff306715b5d8d204a1084dcbd33bf0a04887f3 /compiler/rustc_trait_selection/src/solve
parent5fa82092aed07351757fddeaf3cff062b96067d1 (diff)
downloadrust-ee8942138a9ff0dedbe8575f0aacaea2ec78a51f.tar.gz
rust-ee8942138a9ff0dedbe8575f0aacaea2ec78a51f.zip
Split out make_ambiguous_response_no_constraints
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve')
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs61
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs22
2 files changed, 53 insertions, 30 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 5b94709a5a6..67ad7fb4bd2 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -70,25 +70,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 // into itself infinitely and any partial substitutions in the query
                 // response are probably not useful anyways, so just return an empty
                 // query response.
-                Response {
-                    var_values: CanonicalVarValues {
-                        var_values: self.tcx().mk_substs_from_iter(
-                            self.var_values.var_values.iter().map(|arg| -> ty::GenericArg<'tcx> {
-                                match arg.unpack() {
-                                    GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
-                                    GenericArgKind::Type(_) => self.next_ty_infer().into(),
-                                    GenericArgKind::Const(ct) => {
-                                        self.next_const_infer(ct.ty()).into()
-                                    }
-                                }
-                            }),
-                        ),
-                    },
-                    external_constraints: self
-                        .tcx()
-                        .mk_external_constraints(ExternalConstraintsData::default()),
-                    certainty,
-                }
+                //
+                // This may prevent us from potentially useful inference, e.g.
+                // 2 candidates, one ambiguous and one overflow, which both
+                // have the same inference constraints.
+                //
+                // Changing this to retain some constraints in the future
+                // won't be a breaking change, so this is good enough for now.
+                return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
             }
         };
 
@@ -101,6 +90,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         Ok(canonical)
     }
 
+    /// Constructs a totally unconstrained, ambiguous response to a goal.
+    ///
+    /// Take care when using this, since often it's useful to respond with
+    /// ambiguity but return constrained variables to guide inference.
+    pub(in crate::solve) fn make_ambiguous_response_no_constraints(
+        &self,
+        maybe_cause: MaybeCause,
+    ) -> CanonicalResponse<'tcx> {
+        let unconstrained_response = Response {
+            var_values: CanonicalVarValues {
+                var_values: self.tcx().mk_substs_from_iter(self.var_values.var_values.iter().map(
+                    |arg| -> ty::GenericArg<'tcx> {
+                        match arg.unpack() {
+                            GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
+                            GenericArgKind::Type(_) => self.next_ty_infer().into(),
+                            GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
+                        }
+                    },
+                )),
+            },
+            external_constraints: self
+                .tcx()
+                .mk_external_constraints(ExternalConstraintsData::default()),
+            certainty: Certainty::Maybe(maybe_cause),
+        };
+
+        Canonicalizer::canonicalize(
+            self.infcx,
+            CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
+            &mut Default::default(),
+            unconstrained_response,
+        )
+    }
+
     #[instrument(level = "debug", skip(self), ret)]
     fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
         // Cannot use `take_registered_region_obligations` as we may compute the response
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 19bcbd46144..d94679fef28 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -340,17 +340,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         if responses.is_empty() {
             return Err(NoSolution);
         }
-        let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
-            certainty.unify_with(response.value.certainty)
-        });
-
-        let response = self.evaluate_added_goals_and_make_canonical_response(certainty);
-        if let Ok(response) = response {
-            assert!(response.has_no_inference_or_external_constraints());
-            Ok(response)
-        } else {
-            bug!("failed to make floundered response: {responses:?}");
-        }
+
+        let Certainty::Maybe(maybe_cause) = responses.iter().fold(
+            Certainty::AMBIGUOUS,
+            |certainty, response| {
+                certainty.unify_with(response.value.certainty)
+            },
+        ) else {
+            bug!("expected flounder response to be ambiguous")
+        };
+
+        Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
     }
 }