Change:
Sorry, this is not necessarily the smallest possible example. Please let me know if this is unhelpful and I'll come up with something more concise. Given the following code: The output in current stable (1.63.0) is: (Please note the "expected closure with ... found closure with ..." hint.) From 1.64 onwards, the expected/found hint is omitted: To me the 1.63 behaviour is preferable to that from 1.64+ as it can often be non-obvious where the differences lie.
searched nightlies: from nightly-2022-06-01 to nightly-2022-08-11 regressed nightly: nightly-2022-07-23 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.4</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: </details
Looks like it was caused by , which is pretty big diagnostics PR in that rollup. cc
Of course I caused it.
label -E-needs-bisection
WG-prioritization assigning priority (). label -I-prioritize +P-medium

Discussion:
use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; <ins> use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; </ins> use rustc_middle::ty::{ self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,

/// Float types, respectively). When comparing two ADTs, these rules apply recursively. pub fn same_type_modulo_infer(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); <del> match (a.kind(), b.kind()) { (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b)) => { if def_a != def_b { return false; } </del> <ins> SameTypeModuloInfer(self).relate(a, b).is_ok() } } </ins> <del> substs_a .types() .zip(substs_b.types()) .all(|(a, b)| self.same_type_modulo_infer(a, b)) } (&ty::FnDef(did_a, substs_a), &ty::FnDef(did_b, substs_b)) => { if did_a != did_b { return false; } </del> <ins> struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>); </ins> <del> substs_a .types() .zip(substs_b.types()) .all(|(a, b)| self.same_type_modulo_infer(a, b)) } (&ty::Int(_) | &ty::Uint(_), &ty::Infer(ty::InferTy::IntVar(_))) </del> <ins> impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.0.tcx } fn param_env(&self) -> ty::ParamEnv<'tcx> { // Unused, only for consts which we treat as always equal ty::ParamEnv::empty() } fn tag(&self) -> &'static str { "SameTypeModuloInfer" } fn a_is_expected(&self) -> bool { true } fn relate_with_variance<T: relate::Relate<'tcx>>( &mut self, _variance: ty::Variance, _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> relate::RelateResult<'tcx, T> { self.relate(a, b) } fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { match (a.kind(), b.kind()) { (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_))) </ins> | ( <del> &ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Uint(_) | &ty::Infer(ty::InferTy::IntVar(_)), </del> <ins> ty::Infer(ty::InferTy::IntVar(_)), ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)), </ins> ) <del> | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) </del> <ins> | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_))) </ins> | ( <del> &ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)), </del> <ins> ty::Infer(ty::InferTy::FloatVar(_)), ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), </ins> ) <del> | (&ty::Infer(ty::InferTy::TyVar(_)), _) | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { mut_a == mut_b && self.same_type_modulo_infer(ty_a, ty_b) } (&ty::RawPtr(a), &ty::RawPtr(b)) => { a.mutbl == b.mutbl && self.same_type_modulo_infer(a.ty, b.ty) } (&ty::Slice(a), &ty::Slice(b)) => self.same_type_modulo_infer(a, b), (&ty::Array(a_ty, a_ct), &ty::Array(b_ty, b_ct)) => { self.same_type_modulo_infer(a_ty, b_ty) && a_ct == b_ct } (&ty::Tuple(a), &ty::Tuple(b)) => { if a.len() != b.len() { return false; } std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) } (&ty::FnPtr(a), &ty::FnPtr(b)) => { let a = a.skip_binder().inputs_and_output; let b = b.skip_binder().inputs_and_output; if a.len() != b.len() { return false; } std::iter::zip(a.iter(), b.iter()).all(|(a, b)| self.same_type_modulo_infer(a, b)) } // FIXME(compiler-errors): This needs to be generalized more _ => a == b, </del> <ins> | (ty::Infer(ty::InferTy::TyVar(_)), _) | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), _ => relate::super_relate_tys(self, a, b), </ins> } } <ins> fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { if (a.is_var() && b.is_free_or_static()) || (b.is_var() && a.is_free_or_static()) || a == b { Ok(a) } else { Err(TypeError::Mismatch) } } fn binders<T>( &mut self, a: ty::Binder<'tcx, T>, b: ty::Binder<'tcx, T>, ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> where T: relate::Relate<'tcx>, { Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) } fn consts( &mut self, a: ty::Const<'tcx>, _b: ty::Const<'tcx>, ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> { // FIXME(compiler-errors): This could at least do some first-order // relation Ok(a) } </ins> } impl<'a, 'tcx> InferCtxt<'a, 'tcx> {

_ => self.is_free(), } } <ins> pub fn is_var(self) -> bool { matches!(self.kind(), ty::ReVar(_)) } </ins> } /// Type utilities

<ins> // This code (probably) _should_ compile, but it currently does not because we // are not smart enough about implied bounds. use std::io; fn real_dispatch<T, F>(f: F) -> Result<(), io::Error> //~^ NOTE required by a bound in this where F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static, //~^ NOTE required by this bound in `real_dispatch` //~| NOTE required by a bound in `real_dispatch` { todo!() } #[derive(Debug)] struct UIView<'a, T: 'a> { _phantom: std::marker::PhantomData<&'a mut T>, } trait Handle<'a, T: 'a, V, R> { fn dispatch<F>(&self, f: F) -> Result<(), io::Error> where F: FnOnce(&mut V) -> R + Send + 'static; } #[derive(Debug, Clone)] struct TUIHandle<T> { _phantom: std::marker::PhantomData<T>, } impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> { fn dispatch<F>(&self, f: F) -> Result<(), io::Error> where F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, { real_dispatch(f) //~^ ERROR expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` //~| NOTE expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` //~| NOTE expected a closure with arguments //~| NOTE required by a bound introduced by this call } } fn main() {} </ins>

<ins> error[E0277]: expected a `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` --> $DIR/issue-100690.rs:37:23 | LL |         real_dispatch(f) |         ------------- ^ expected an `FnOnce<(&mut UIView<'_, T>,)>` closure, found `F` |         | |         required by a bound introduced by this call | = note: expected a closure with arguments `(&mut UIView<'a, T>,)` found a closure with arguments `(&mut UIView<'_, T>,)` note: required by a bound in `real_dispatch` --> $DIR/issue-100690.rs:9:8 | LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error> |    ------------- required by a bound in this ... LL |     F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static, |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch` error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. </ins>