@@ -1593,44 +1593,98 @@ fn deny_equality_constraints(
15931593 }
15941594 }
15951595 }
1596- // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1597- if let TyKind :: Path ( None , full_path) = & predicate. lhs_ty . kind {
1598- if let [ potential_param, potential_assoc] = & full_path. segments [ ..] {
1599- for param in & generics. params {
1600- if param. ident == potential_param. ident {
1601- for bound in & param. bounds {
1602- if let ast:: GenericBound :: Trait ( trait_ref, TraitBoundModifiers :: NONE ) =
1603- bound
1596+
1597+ let mut suggest =
1598+ |poly : & PolyTraitRef , potential_assoc : & PathSegment , predicate : & WhereEqPredicate | {
1599+ if let [ trait_segment] = & poly. trait_ref . path . segments [ ..] {
1600+ let assoc = pprust:: path_to_string ( & ast:: Path :: from_ident ( potential_assoc. ident ) ) ;
1601+ let ty = pprust:: ty_to_string ( & predicate. rhs_ty ) ;
1602+ let ( args, span) = match & trait_segment. args {
1603+ Some ( args) => match args. deref ( ) {
1604+ ast:: GenericArgs :: AngleBracketed ( args) => {
1605+ let Some ( arg) = args. args . last ( ) else {
1606+ return ;
1607+ } ;
1608+ ( format ! ( ", {assoc} = {ty}" ) , arg. span ( ) . shrink_to_hi ( ) )
1609+ }
1610+ _ => return ,
1611+ } ,
1612+ None => ( format ! ( "<{assoc} = {ty}>" ) , trait_segment. span ( ) . shrink_to_hi ( ) ) ,
1613+ } ;
1614+ let removal_span = if generics. where_clause . predicates . len ( ) == 1 {
1615+ // We're removing th eonly where bound left, remove the whole thing.
1616+ generics. where_clause . span
1617+ } else {
1618+ let mut span = predicate. span ;
1619+ let mut prev: Option < Span > = None ;
1620+ let mut preds = generics. where_clause . predicates . iter ( ) . peekable ( ) ;
1621+ // Find the predicate that shouldn't have been in the where bound list.
1622+ while let Some ( pred) = preds. next ( ) {
1623+ if let WherePredicate :: EqPredicate ( pred) = pred
1624+ && pred. span == predicate. span
16041625 {
1605- if let [ trait_segment] = & trait_ref. trait_ref . path . segments [ ..] {
1606- let assoc = pprust:: path_to_string ( & ast:: Path :: from_ident (
1607- potential_assoc. ident ,
1608- ) ) ;
1609- let ty = pprust:: ty_to_string ( & predicate. rhs_ty ) ;
1610- let ( args, span) = match & trait_segment. args {
1611- Some ( args) => match args. deref ( ) {
1612- ast:: GenericArgs :: AngleBracketed ( args) => {
1613- let Some ( arg) = args. args . last ( ) else {
1614- continue ;
1615- } ;
1616- ( format ! ( ", {assoc} = {ty}" ) , arg. span ( ) . shrink_to_hi ( ) )
1617- }
1618- _ => continue ,
1619- } ,
1620- None => (
1621- format ! ( "<{assoc} = {ty}>" ) ,
1622- trait_segment. span ( ) . shrink_to_hi ( ) ,
1623- ) ,
1624- } ;
1625- err. assoc2 = Some ( errors:: AssociatedSuggestion2 {
1626- span,
1627- args,
1628- predicate : predicate. span ,
1629- trait_segment : trait_segment. ident ,
1630- potential_assoc : potential_assoc. ident ,
1631- } ) ;
1626+ if let Some ( next) = preds. peek ( ) {
1627+ // This is the first predicate, remove the trailing comma as well.
1628+ span = span. with_hi ( next. span ( ) . lo ( ) ) ;
1629+ } else if let Some ( prev) = prev {
1630+ // Remove the previous comma as well.
1631+ span = span. with_lo ( prev. hi ( ) ) ;
16321632 }
16331633 }
1634+ prev = Some ( pred. span ( ) ) ;
1635+ }
1636+ span
1637+ } ;
1638+ err. assoc2 = Some ( errors:: AssociatedSuggestion2 {
1639+ span,
1640+ args,
1641+ predicate : removal_span,
1642+ trait_segment : trait_segment. ident ,
1643+ potential_assoc : potential_assoc. ident ,
1644+ } ) ;
1645+ }
1646+ } ;
1647+
1648+ if let TyKind :: Path ( None , full_path) = & predicate. lhs_ty . kind {
1649+ // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1650+ for bounds in generics. params . iter ( ) . map ( |p| & p. bounds ) . chain (
1651+ generics. where_clause . predicates . iter ( ) . filter_map ( |pred| match pred {
1652+ WherePredicate :: BoundPredicate ( p) => Some ( & p. bounds ) ,
1653+ _ => None ,
1654+ } ) ,
1655+ ) {
1656+ for bound in bounds {
1657+ if let GenericBound :: Trait ( poly, TraitBoundModifiers :: NONE ) = bound {
1658+ if full_path. segments [ ..full_path. segments . len ( ) - 1 ]
1659+ . iter ( )
1660+ . map ( |segment| segment. ident . name )
1661+ . zip ( poly. trait_ref . path . segments . iter ( ) . map ( |segment| segment. ident . name ) )
1662+ . all ( |( a, b) | a == b)
1663+ && let Some ( potential_assoc) = full_path. segments . iter ( ) . last ( )
1664+ {
1665+ suggest ( poly, potential_assoc, predicate) ;
1666+ }
1667+ }
1668+ }
1669+ }
1670+ // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1671+ if let [ potential_param, potential_assoc] = & full_path. segments [ ..] {
1672+ for ( ident, bounds) in generics. params . iter ( ) . map ( |p| ( p. ident , & p. bounds ) ) . chain (
1673+ generics. where_clause . predicates . iter ( ) . filter_map ( |pred| match pred {
1674+ WherePredicate :: BoundPredicate ( p)
1675+ if let ast:: TyKind :: Path ( None , path) = & p. bounded_ty . kind
1676+ && let [ segment] = & path. segments [ ..] =>
1677+ {
1678+ Some ( ( segment. ident , & p. bounds ) )
1679+ }
1680+ _ => None ,
1681+ } ) ,
1682+ ) {
1683+ if ident == potential_param. ident {
1684+ for bound in bounds {
1685+ if let ast:: GenericBound :: Trait ( poly, TraitBoundModifiers :: NONE ) = bound {
1686+ suggest ( poly, potential_assoc, predicate) ;
1687+ }
16341688 }
16351689 }
16361690 }
0 commit comments