]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_hir_typeck/src/closure.rs
reverse obligations for better diagnostics on multiple conflicting fn bounds
[rust.git] / compiler / rustc_hir_typeck / src / closure.rs
index a5a45f75e0e240c25a0ec8fb1bcad01d5b6dfa14..14f6e7d36be2cf1299b31d801899cd804353450c 100644 (file)
@@ -15,6 +15,7 @@
 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;
@@ -225,33 +226,50 @@ fn deduce_expectations_from_obligations(
         &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;
+        let mut expected_kind = None;
+
+        for obligation in traits::elaborate_obligations(
+            self.tcx,
+            // 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();
+
+            // 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()
+            {
+                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 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))));
+            // 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))
+                }
+                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 +707,7 @@ fn deduce_future_output_from_obligations(
 
         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)
                 })?
             }