diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 7514c7ee55170..a2ca4bc189c87 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -7,7 +7,7 @@ use cache::ProvisionalCache;
 use overflow::OverflowData;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::TyCtxt;
-use std::collections::hash_map::Entry;
+use std::{collections::hash_map::Entry, mem};
 
 rustc_index::newtype_index! {
     pub struct StackDepth {}
@@ -134,12 +134,15 @@ impl<'tcx> SearchGraph<'tcx> {
         let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
         let provisional_entry = &mut cache.entries[provisional_entry_index];
         let depth = provisional_entry.depth;
+        // We eagerly update the response in the cache here. If we have to reevaluate
+        // this goal we use the new response when hitting a cycle, and we definitely
+        // want to access the final response whenever we look at the cache.
+        let prev_response = mem::replace(&mut provisional_entry.response, response);
+
         // Was the current goal the root of a cycle and was the provisional response
         // different from the final one.
-        if has_been_used && provisional_entry.response != response {
-            // If so, update the provisional reponse for this goal...
-            provisional_entry.response = response;
-            // ...remove all entries whose result depends on this goal
+        if has_been_used && prev_response != response {
+            // If so, remove all entries whose result depends on this goal
             // from the provisional cache...
             //
             // That's not completely correct, as a nested goal can also
diff --git a/tests/ui/traits/new-solver/provisional-result-done.rs b/tests/ui/traits/new-solver/provisional-result-done.rs
new file mode 100644
index 0000000000000..a3d97927bad22
--- /dev/null
+++ b/tests/ui/traits/new-solver/provisional-result-done.rs
@@ -0,0 +1,37 @@
+// known-bug: unknown
+// compile-flags: -Ztrait-solver=next
+// failure-status: 101
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
+
+// This tests checks that we update results in the provisional cache when
+// we pop a goal from the stack.
+#![feature(auto_traits)]
+auto trait Coinductive {}
+struct Foo<T>(T);
+struct Bar<T>(T);
+
+impl<T> Coinductive for Foo<T>
+where
+    Bar<T>: Coinductive
+{}
+
+impl<T> Coinductive for Bar<T>
+where
+    Foo<T>: Coinductive,
+    Bar<T>: ConstrainInfer,
+{}
+
+trait ConstrainInfer {}
+impl ConstrainInfer for Bar<u8> {}
+impl ConstrainInfer for Foo<u16> {}
+
+fn impls<T: Coinductive>() -> T { todo!() }
+
+fn constrain<T: ConstrainInfer>(_: T) {}
+
+fn main() {
+    // This should constrain `_` to `u8`.
+    impls::<Foo<_>>();
+}
diff --git a/tests/ui/traits/new-solver/provisional-result-done.stderr b/tests/ui/traits/new-solver/provisional-result-done.stderr
new file mode 100644
index 0000000000000..ffc92b81f089e
--- /dev/null
+++ b/tests/ui/traits/new-solver/provisional-result-done.stderr
@@ -0,0 +1,6 @@
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [check_well_formed] checking that `<impl at $DIR/provisional-result-done.rs:20:1: 20:31>` is well-formed
+#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+end of query stack