From 060d4392b1679fa4f7323ee702a7669af281d5db Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 15 Sep 2022 00:18:35 +0000
Subject: [PATCH 1/3] Make obligations_for_self_ty only return an obligation

---
 compiler/rustc_hir_typeck/src/closure.rs      | 59 +++++++-----
 .../rustc_hir_typeck/src/fn_ctxt/_impl.rs     | 96 ++++++++++---------
 2 files changed, 84 insertions(+), 71 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index a5a45f75e0e..cc1191d3245 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -225,33 +225,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         expected_vid: ty::TyVid,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
-        let expected_sig =
-            self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
-                debug!(?obligation.predicate);
-
-                let bound_predicate = obligation.predicate.kind();
-                if let ty::PredicateKind::Projection(proj_predicate) =
-                    obligation.predicate.kind().skip_binder()
-                {
-                    // Given a Projection predicate, we can potentially infer
-                    // the complete signature.
-                    self.deduce_sig_from_projection(
-                        Some(obligation.cause.span),
-                        bound_predicate.rebind(proj_predicate),
-                    )
-                } else {
-                    None
-                }
-            });
-
+        let mut expected_sig = None;
         // Even if we can't infer the full signature, we may be able to
         // infer the kind. This can occur when we elaborate a predicate
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
-        let expected_kind = self
-            .obligations_for_self_ty(expected_vid)
-            .filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
-            .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+        let mut expected_kind = None;
+
+        for obligation in self.obligations_for_self_ty(expected_vid) {
+            debug!(?obligation.predicate);
+            let bound_predicate = obligation.predicate.kind();
+
+            if expected_sig.is_none()
+                && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
+            {
+                // Given a Projection predicate, we can potentially infer
+                // the complete signature.
+                expected_sig = self.deduce_sig_from_projection(
+                    Some(obligation.cause.span),
+                    bound_predicate.rebind(proj_predicate),
+                );
+            }
+
+            let trait_def_id = match bound_predicate.skip_binder() {
+                ty::PredicateKind::Projection(data) => {
+                    Some(data.projection_ty.trait_def_id(self.tcx))
+                }
+                ty::PredicateKind::Trait(data) => Some(data.def_id()),
+                _ => None,
+            };
+            if let Some(closure_kind) =
+                trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_lang_item(def_id))
+            {
+                expected_kind = Some(
+                    expected_kind
+                        .map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
+                );
+            }
+        }
 
         (expected_sig, expected_kind)
     }
@@ -689,7 +700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let output_ty = match *ret_ty.kind() {
             ty::Infer(ty::TyVar(ret_vid)) => {
-                self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
+                self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 6a1cffe3e60..d2962a3836f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -21,8 +21,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMut
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
-    ToPredicate, Ty, UserType,
+    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty,
+    UserType,
 };
 use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
 use rustc_session::lint;
@@ -650,12 +650,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> bool {
-        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+    fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
+        let self_ty = self.shallow_resolve(self_ty);
         debug!(?self_ty);
 
         match *self_ty.kind() {
@@ -674,54 +670,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn obligations_for_self_ty<'b>(
         &'b self,
         self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
-    + Captures<'tcx>
-    + 'b {
+    ) -> impl Iterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b {
         // FIXME: consider using `sub_root_var` here so we
         // can see through subtyping.
         let ty_var_root = self.root_var(self_ty);
         trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
 
-        self.fulfillment_cx
-            .borrow()
-            .pending_obligations()
-            .into_iter()
-            .filter_map(move |obligation| {
-                let bound_predicate = obligation.predicate.kind();
-                match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => Some((
-                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
-                        obligation,
-                    )),
-                    ty::PredicateKind::Trait(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
-                    }
-                    ty::PredicateKind::Subtype(..) => None,
-                    ty::PredicateKind::Coerce(..) => None,
-                    ty::PredicateKind::RegionOutlives(..) => None,
-                    ty::PredicateKind::TypeOutlives(..) => None,
-                    ty::PredicateKind::WellFormed(..) => None,
-                    ty::PredicateKind::ObjectSafe(..) => None,
-                    ty::PredicateKind::ConstEvaluatable(..) => None,
-                    ty::PredicateKind::ConstEquate(..) => None,
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of an unresolved
-                    // inference variable.
-                    ty::PredicateKind::ClosureKind(..) => None,
-                    ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+        self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map(
+            move |obligation| match &obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Projection(data)
+                    if self.self_type_matches_expected_vid(
+                        data.projection_ty.self_ty(),
+                        ty_var_root,
+                    ) =>
+                {
+                    Some(obligation)
                 }
-            })
-            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+                ty::PredicateKind::Trait(data)
+                    if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) =>
+                {
+                    Some(obligation)
+                }
+
+                ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::TypeOutlives(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                // N.B., this predicate is created by breaking down a
+                // `ClosureType: FnFoo()` predicate, where
+                // `ClosureType` represents some `Closure`. It can't
+                // possibly be referring to the current closure,
+                // because we haven't produced the `Closure` for
+                // this closure yet; this is exactly why the other
+                // code is looking for a self type of an unresolved
+                // inference variable.
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+            },
+        )
     }
 
     pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
-        self.obligations_for_self_ty(self_ty)
-            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+        let sized_did = self.tcx.lang_items().sized_trait();
+        self.obligations_for_self_ty(self_ty).any(|obligation| {
+            match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(data) => Some(data.def_id()) == sized_did,
+                _ => false,
+            }
+        })
     }
 
     pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {

From caa701e3c190c4d77634c9075548746e4917e56d Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 15 Sep 2022 00:35:23 +0000
Subject: [PATCH 2/3] Elaborate supertrait obligations when deducing closure
 signature

---
 compiler/rustc_hir_typeck/src/closure.rs      | 18 +++++++-----
 ...ue-23012-supertrait-signature-inference.rs | 29 +++++++++++++++++++
 .../issue-57611-trait-alias.rs                |  3 +-
 .../issue-57611-trait-alias.stderr            | 26 -----------------
 4 files changed, 41 insertions(+), 35 deletions(-)
 create mode 100644 src/test/ui/closures/issue-23012-supertrait-signature-inference.rs
 delete mode 100644 src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr

diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index cc1191d3245..4f8ac45d5a6 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -15,6 +15,7 @@ use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use std::cmp;
@@ -226,27 +227,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_vid: ty::TyVid,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         let mut expected_sig = None;
-        // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur when we elaborate a predicate
-        // like `F : Fn<A>`. Note that due to subtyping we could encounter
-        // many viable options, so pick the most restrictive.
         let mut expected_kind = None;
 
-        for obligation in self.obligations_for_self_ty(expected_vid) {
+        for obligation in traits::elaborate_obligations(
+            self.tcx,
+            self.obligations_for_self_ty(expected_vid).collect(),
+        ) {
             debug!(?obligation.predicate);
             let bound_predicate = obligation.predicate.kind();
 
+            // Given a Projection predicate, we can potentially infer
+            // the complete signature.
             if expected_sig.is_none()
                 && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
             {
-                // Given a Projection predicate, we can potentially infer
-                // the complete signature.
                 expected_sig = self.deduce_sig_from_projection(
                     Some(obligation.cause.span),
                     bound_predicate.rebind(proj_predicate),
                 );
             }
 
+            // Even if we can't infer the full signature, we may be able to
+            // infer the kind. This can occur when we elaborate a predicate
+            // like `F : Fn<A>`. Note that due to subtyping we could encounter
+            // many viable options, so pick the most restrictive.
             let trait_def_id = match bound_predicate.skip_binder() {
                 ty::PredicateKind::Projection(data) => {
                     Some(data.projection_ty.trait_def_id(self.tcx))
diff --git a/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs b/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs
new file mode 100644
index 00000000000..5899b703e7c
--- /dev/null
+++ b/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs
@@ -0,0 +1,29 @@
+// check-pass
+// Checks that we can infer a closure signature even if the `FnOnce` bound is
+// a supertrait of the obligations we have currently registered for the Ty var.
+
+pub trait Receive<T, E>: FnOnce(Result<T, E>) {
+    fn receive(self, res: Result<T, E>);
+}
+
+impl<T, E, F: FnOnce(Result<T, E>)> Receive<T, E> for F {
+    fn receive(self, res: Result<T, E>) {
+        self(res)
+    }
+}
+
+pub trait Async<T, E> {
+    fn receive<F: Receive<T, E>>(self, f: F);
+}
+
+impl<T, E> Async<T, E> for Result<T, E> {
+    fn receive<F: Receive<T, E>>(self, f: F) {
+        f(self)
+    }
+}
+
+pub fn main() {
+    Ok::<u32, ()>(123).receive(|res| {
+        res.unwrap();
+    });
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
index 067ed7ea1e5..cad3e0f6677 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
@@ -1,7 +1,6 @@
+// check-pass
 // Regression test for issue #57611
 // Ensures that we don't ICE
-// FIXME: This should compile, but it currently doesn't
-// known-bug: unknown
 
 #![feature(trait_alias)]
 #![feature(type_alias_impl_trait)]
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
deleted file mode 100644
index 6344f114a91..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-57611-trait-alias.rs:21:9
-   |
-LL |         |x| x
-   |         ^^^^^ one type is more general than the other
-   |
-   = note: expected trait `for<'a> Fn<(&'a X,)>`
-              found trait `Fn<(&X,)>`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-57611-trait-alias.rs:21:9
-   |
-LL |         |x| x
-   |         ^^^
-
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-57611-trait-alias.rs:21:9
-   |
-LL |         |x| x
-   |         ^^^^^ implementation of `FnOnce` is not general enough
-   |
-   = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.

From bc3516d474a6ab5e5116a2ec32f5d236d479cab3 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 15 Oct 2022 18:48:13 +0000
Subject: [PATCH 3/3] reverse obligations for better diagnostics on multiple
 conflicting fn bounds

---
 compiler/rustc_hir_typeck/src/closure.rs       | 5 ++++-
 compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 3 ++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 4f8ac45d5a6..14f6e7d36be 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -231,7 +231,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         for obligation in traits::elaborate_obligations(
             self.tcx,
-            self.obligations_for_self_ty(expected_vid).collect(),
+            // Reverse the obligations here, since `elaborate_*` uses a stack,
+            // and we want to keep inference generally in the same order of
+            // the registered obligations.
+            self.obligations_for_self_ty(expected_vid).rev().collect(),
         ) {
             debug!(?obligation.predicate);
             let bound_predicate = obligation.predicate.kind();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d2962a3836f..7c22eaf18f8 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -670,7 +670,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn obligations_for_self_ty<'b>(
         &'b self,
         self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b {
+    ) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
+    {
         // FIXME: consider using `sub_root_var` here so we
         // can see through subtyping.
         let ty_var_root = self.root_var(self_ty);