@@ -254,8 +254,15 @@ pub trait TypeErrCtxtExt<'tcx> {
254
254
found_span : Option < Span > ,
255
255
found : ty:: PolyTraitRef < ' tcx > ,
256
256
expected : ty:: PolyTraitRef < ' tcx > ,
257
+ cause : & ObligationCauseCode < ' tcx > ,
257
258
) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > ;
258
259
260
+ fn note_conflicting_closure_bounds (
261
+ & self ,
262
+ cause : & ObligationCauseCode < ' tcx > ,
263
+ err : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
264
+ ) ;
265
+
259
266
fn suggest_fully_qualified_path (
260
267
& self ,
261
268
err : & mut Diagnostic ,
@@ -1584,6 +1591,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1584
1591
found_span : Option < Span > ,
1585
1592
found : ty:: PolyTraitRef < ' tcx > ,
1586
1593
expected : ty:: PolyTraitRef < ' tcx > ,
1594
+ cause : & ObligationCauseCode < ' tcx > ,
1587
1595
) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > {
1588
1596
pub ( crate ) fn build_fn_sig_ty < ' tcx > (
1589
1597
infcx : & InferCtxt < ' tcx > ,
@@ -1645,9 +1653,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1645
1653
let signature_kind = format ! ( "{argument_kind} signature" ) ;
1646
1654
err. note_expected_found ( & signature_kind, expected_str, & signature_kind, found_str) ;
1647
1655
1656
+ self . note_conflicting_closure_bounds ( cause, & mut err) ;
1657
+
1648
1658
err
1649
1659
}
1650
1660
1661
+ // Add a note if there are two `Fn`-family bounds that have conflicting argument
1662
+ // requirements, which will always cause a closure to have a type error.
1663
+ fn note_conflicting_closure_bounds (
1664
+ & self ,
1665
+ cause : & ObligationCauseCode < ' tcx > ,
1666
+ err : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
1667
+ ) {
1668
+ // First, look for an `ExprBindingObligation`, which means we can get
1669
+ // the unsubstituted predicate list of the called function. And check
1670
+ // that the predicate that we failed to satisfy is a `Fn`-like trait.
1671
+ if let ObligationCauseCode :: ExprBindingObligation ( def_id, _, _, idx) = cause
1672
+ && let predicates = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx )
1673
+ && let Some ( pred) = predicates. predicates . get ( * idx)
1674
+ && let ty:: PredicateKind :: Trait ( trait_pred) = pred. kind ( ) . skip_binder ( )
1675
+ && ty:: ClosureKind :: from_def_id ( self . tcx , trait_pred. def_id ( ) ) . is_some ( )
1676
+ {
1677
+ let expected_self =
1678
+ self . tcx . anonymize_late_bound_regions ( pred. kind ( ) . rebind ( trait_pred. self_ty ( ) ) ) ;
1679
+ let expected_substs = self
1680
+ . tcx
1681
+ . anonymize_late_bound_regions ( pred. kind ( ) . rebind ( trait_pred. trait_ref . substs ) ) ;
1682
+
1683
+ // Find another predicate whose self-type is equal to the expected self type,
1684
+ // but whose substs don't match.
1685
+ let other_pred = std:: iter:: zip ( & predicates. predicates , & predicates. spans )
1686
+ . enumerate ( )
1687
+ . find ( |( other_idx, ( pred, _) ) | match pred. kind ( ) . skip_binder ( ) {
1688
+ ty:: PredicateKind :: Trait ( trait_pred)
1689
+ if ty:: ClosureKind :: from_def_id ( self . tcx , trait_pred. def_id ( ) )
1690
+ . is_some ( )
1691
+ && other_idx != idx
1692
+ // Make sure that the self type matches
1693
+ // (i.e. constraining this closure)
1694
+ && expected_self
1695
+ == self . tcx . anonymize_late_bound_regions (
1696
+ pred. kind ( ) . rebind ( trait_pred. self_ty ( ) ) ,
1697
+ )
1698
+ // But the substs don't match (i.e. incompatible args)
1699
+ && expected_substs
1700
+ != self . tcx . anonymize_late_bound_regions (
1701
+ pred. kind ( ) . rebind ( trait_pred. trait_ref . substs ) ,
1702
+ ) =>
1703
+ {
1704
+ true
1705
+ }
1706
+ _ => false ,
1707
+ } ) ;
1708
+ // If we found one, then it's very likely the cause of the error.
1709
+ if let Some ( ( _, ( _, other_pred_span) ) ) = other_pred {
1710
+ err. span_note (
1711
+ * other_pred_span,
1712
+ "closure inferred to have a different signature due to this bound" ,
1713
+ ) ;
1714
+ }
1715
+ }
1716
+ }
1717
+
1651
1718
fn suggest_fully_qualified_path (
1652
1719
& self ,
1653
1720
err : & mut Diagnostic ,
0 commit comments