Change:
&self, expected_vid: ty::TyVid, ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { <del> 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 } }); </del> <ins> 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), ); } </ins> <del> // 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)))); </del> <ins> // 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)), ); } } </ins> (expected_sig, expected_kind) }

Discussion:
Repro: Output:
cc
What's causing this is that we currently inspect the obligations in scope for obligations, but in this case the obligation is (which implies a obligation as a supertrait). This is expected but unfortunate, yes. We could probably fix this particular case in a relatively straightforward way by trying to upcast each pending obligation to a obligation.
I imagine that atm this could be worked around by changing: to
Today, this gives a completely different error about not implementing ...
Updated code to not give the unrelated error (by removing bounds everywhere), still gives the type must be known error.
This comes up for me fairly regularly. It would be really nice to fix it. (e.g., it came up recently in )
We discussed this in the types team 'backlog bonanza' meeting today. Our conclusion was that this is a "nice to have" and that directly fixing this issue felt like a types team FCP, because it's a tweak to the inference rules. TL;DR right now we say If there is some trait obligation , then we take the args from it seems reasonable to say If there is some trait obligation that implies (through the "invariants", in terms) , then we take the args from that would fix this example (types team FCP would be required). However, I believe that beyond this specific example, most people who wind up here are trying to do something a bit more sophisticated, such as having an argument that might be a closure but might not, or have extended varieties of closures (). It is possible that just making the above change would fix those problems, but it's likely that further changes would be required. Those scope feels like a lang-team initiative. Still may be worth making this change just to screen out the easy cases, mind you!