Change:
pub(in super::super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, <del> ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)> + Captures<'tcx> + 'b { </del> <ins> ) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b { </ins> // 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()); <del> 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, </del> <ins> 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) </ins> } <del> }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) </del> <ins> 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, }, ) </ins> } pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { <del> self.obligations_for_self_ty(self_ty) .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) </del> <ins> 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, } }) </ins> } pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {

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!