@@ -258,6 +258,7 @@ pub trait TypeErrCtxtExt<'tcx> {
258258 found : ty:: PolyTraitRef < ' tcx > ,
259259 expected : ty:: PolyTraitRef < ' tcx > ,
260260 cause : & ObligationCauseCode < ' tcx > ,
261+ found_node : Option < Node < ' _ > > ,
261262 ) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > ;
262263
263264 fn note_conflicting_closure_bounds (
@@ -1695,6 +1696,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
16951696 found : ty:: PolyTraitRef < ' tcx > ,
16961697 expected : ty:: PolyTraitRef < ' tcx > ,
16971698 cause : & ObligationCauseCode < ' tcx > ,
1699+ found_node : Option < Node < ' _ > > ,
16981700 ) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > {
16991701 pub ( crate ) fn build_fn_sig_ty < ' tcx > (
17001702 infcx : & InferCtxt < ' tcx > ,
@@ -1756,6 +1758,75 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
17561758
17571759 self . note_conflicting_closure_bounds ( cause, & mut err) ;
17581760
1761+ let found_args = match found. kind ( ) {
1762+ ty:: FnPtr ( f) => f. inputs ( ) . skip_binder ( ) . iter ( ) ,
1763+ kind => {
1764+ span_bug ! ( span, "found was converted to a FnPtr above but is now {:?}" , kind)
1765+ }
1766+ } ;
1767+ let expected_args = match expected. kind ( ) {
1768+ ty:: FnPtr ( f) => f. inputs ( ) . skip_binder ( ) . iter ( ) ,
1769+ kind => {
1770+ span_bug ! ( span, "expected was converted to a FnPtr above but is now {:?}" , kind)
1771+ }
1772+ } ;
1773+
1774+ if let Some ( found_node) = found_node {
1775+ let fn_decl = match found_node {
1776+ Node :: Expr ( expr) => match & expr. kind {
1777+ hir:: ExprKind :: Closure ( hir:: Closure { fn_decl, .. } ) => fn_decl,
1778+ kind => {
1779+ span_bug ! ( found_span, "expression must be a closure but is {:?}" , kind)
1780+ }
1781+ } ,
1782+ Node :: Item ( item) => match & item. kind {
1783+ hir:: ItemKind :: Fn ( signature, _generics, _body) => signature. decl ,
1784+ kind => {
1785+ span_bug ! ( found_span, "item must be a function but is {:?}" , kind)
1786+ }
1787+ } ,
1788+ node => {
1789+ span_bug ! ( found_span, "node must be a expr or item but is {:?}" , node)
1790+ }
1791+ } ;
1792+
1793+ let arg_spans = fn_decl. inputs . iter ( ) . map ( |ty| ty. span ) ;
1794+
1795+ fn get_deref_type_and_refs ( mut ty : Ty < ' _ > ) -> ( Ty < ' _ > , usize ) {
1796+ let mut refs = 0 ;
1797+
1798+ while let ty:: Ref ( _, new_ty, _) = ty. kind ( ) {
1799+ ty = * new_ty;
1800+ refs += 1 ;
1801+ }
1802+
1803+ ( ty, refs)
1804+ }
1805+
1806+ for ( ( found_arg, expected_arg) , arg_span) in
1807+ found_args. zip ( expected_args) . zip ( arg_spans)
1808+ {
1809+ let ( found_ty, found_refs) = get_deref_type_and_refs ( * found_arg) ;
1810+ let ( expected_ty, expected_refs) = get_deref_type_and_refs ( * expected_arg) ;
1811+
1812+ if found_ty == expected_ty {
1813+ let hint = if found_refs < expected_refs {
1814+ "hint: consider borrowing here:"
1815+ } else if found_refs == expected_refs {
1816+ continue ;
1817+ } else {
1818+ "hint: consider removing the borrow:"
1819+ } ;
1820+ err. span_suggestion_verbose (
1821+ arg_span,
1822+ hint,
1823+ expected_arg. to_string ( ) ,
1824+ Applicability :: MaybeIncorrect ,
1825+ ) ;
1826+ }
1827+ }
1828+ }
1829+
17591830 err
17601831 }
17611832
0 commit comments