@@ -1220,10 +1220,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12201220 }
12211221 }
12221222
1223- let candidate = if self . trait_defines_associated_type_named ( trait_ref. def_id ( ) ,
1224- binding. item_name ) {
1223+ let candidate = if self . trait_defines_associated_type_named (
1224+ trait_ref. def_id ( ) ,
1225+ binding. item_name ,
1226+ ) {
12251227 // Simple case: X is defined in the current trait.
1226- Ok ( trait_ref)
1228+ trait_ref
12271229 } else {
12281230 // Otherwise, we have to walk through the supertraits to find
12291231 // those that do.
@@ -1232,8 +1234,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12321234 & trait_ref. print_only_trait_path ( ) . to_string ( ) ,
12331235 binding. item_name ,
12341236 path_span,
1235- )
1236- } ?;
1237+ match binding. kind {
1238+ ConvertedBindingKind :: Equality ( ty) => Some ( ty. to_string ( ) ) ,
1239+ _ => None ,
1240+ } ,
1241+ ) ?
1242+ } ;
12371243
12381244 let ( assoc_ident, def_scope) =
12391245 tcx. adjust_ident_and_get_scope ( binding. item_name , candidate. def_id ( ) , hir_ref_id) ;
@@ -1564,19 +1570,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
15641570 }
15651571 let mut suggestions_len = suggestions. len ( ) ;
15661572 if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( sugg_span) {
1567- if potential_assoc_types. is_empty ( ) && trait_bounds. len ( ) == 1 &&
1573+ let assoc_types: Vec < String > = associated_types. iter ( )
1574+ . map ( |item_def_id| {
1575+ let assoc_item = tcx. associated_item ( * item_def_id) ;
1576+ format ! ( "{} = Type" , assoc_item. ident)
1577+ } )
1578+ . collect ( ) ;
1579+ let dedup = assoc_types. clone ( ) . drain ( ..) . collect :: < FxHashSet < _ > > ( ) ;
1580+
1581+ if dedup. len ( ) != assoc_types. len ( ) && trait_bounds. len ( ) == 1 {
1582+ // If there are duplicates associated type names and a single trait bound do not
1583+ // use structured suggestion, it means that there are multiple super-traits with
1584+ // the same associated type name.
1585+ err. help ( "consider introducing a new type parameter, adding `where` constraints \
1586+ using the fully-qualified path to the associated type") ;
1587+ } else if dedup. len ( ) == assoc_types. len ( ) &&
1588+ potential_assoc_types. is_empty ( ) &&
1589+ trait_bounds. len ( ) == 1 &&
15681590 // Do not attempt to suggest when we don't know which path segment needs the
15691591 // type parameter set.
15701592 trait_bounds[ 0 ] . trait_ref . path . segments . len ( ) == 1
15711593 {
1572- debug ! ( "path segments {:?}" , trait_bounds[ 0 ] . trait_ref. path. segments) ;
15731594 applicability = Applicability :: HasPlaceholders ;
1574- let assoc_types: Vec < String > = associated_types. iter ( )
1575- . map ( |item_def_id| {
1576- let assoc_item = tcx. associated_item ( * item_def_id) ;
1577- format ! ( "{} = Type" , assoc_item. ident)
1578- } )
1579- . collect ( ) ;
15801595 let sugg = assoc_types. join ( ", " ) ;
15811596 if snippet. ends_with ( '>' ) {
15821597 // The user wrote `Trait<'a>` or similar and we don't have a type we can
@@ -1602,7 +1617,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16021617 . map ( |t| format ! ( "`{}`" , tcx. associated_item( * t) . ident) )
16031618 . collect :: < Vec < _ > > ( )
16041619 . join ( ", " ) ;
1605- err. span_label ( span , format ! (
1620+ err. span_label ( sugg_span , format ! (
16061621 "associated type{} {} must be specified" ,
16071622 pluralize!( associated_types. len( ) ) ,
16081623 names,
@@ -1635,10 +1650,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16351650 ) ;
16361651 } else {
16371652 err. span_suggestion (
1638- span,
1639- "use fully-qualified syntax" ,
1640- format ! ( "<{} as {}>::{}" , type_str, trait_str, name) ,
1641- Applicability :: HasPlaceholders
1653+ span,
1654+ "use fully-qualified syntax" ,
1655+ format ! ( "<{} as {}>::{}" , type_str, trait_str, name) ,
1656+ Applicability :: HasPlaceholders
16421657 ) ;
16431658 }
16441659 err. emit ( ) ;
@@ -1648,12 +1663,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16481663 // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
16491664 // This function will fail if there are no suitable bounds or there is
16501665 // any ambiguity.
1651- fn find_bound_for_assoc_item ( & self ,
1652- ty_param_def_id : DefId ,
1653- assoc_name : ast :: Ident ,
1654- span : Span )
1655- -> Result < ty :: PolyTraitRef < ' tcx > , ErrorReported >
1656- {
1666+ fn find_bound_for_assoc_item (
1667+ & self ,
1668+ ty_param_def_id : DefId ,
1669+ assoc_name : ast :: Ident ,
1670+ span : Span ,
1671+ ) -> Result < ty :: PolyTraitRef < ' tcx > , ErrorReported > {
16571672 let tcx = self . tcx ( ) ;
16581673
16591674 debug ! (
@@ -1675,16 +1690,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16751690 & param_name. as_str ( ) ,
16761691 assoc_name,
16771692 span,
1693+ None ,
16781694 )
16791695 }
16801696
1681- fn one_bound_for_assoc_type < I > ( & self ,
1682- all_candidates : impl Fn ( ) -> I ,
1683- ty_param_name : & str ,
1684- assoc_name : ast:: Ident ,
1685- span : Span )
1686- -> Result < ty:: PolyTraitRef < ' tcx > , ErrorReported >
1687- where I : Iterator < Item = ty:: PolyTraitRef < ' tcx > >
1697+ // Checks that `bounds` contains exactly one element and reports appropriate
1698+ // errors otherwise.
1699+ fn one_bound_for_assoc_type < I > (
1700+ & self ,
1701+ all_candidates : impl Fn ( ) -> I ,
1702+ ty_param_name : & str ,
1703+ assoc_name : ast:: Ident ,
1704+ span : Span ,
1705+ is_equality : Option < String > ,
1706+ ) -> Result < ty:: PolyTraitRef < ' tcx > , ErrorReported >
1707+ where I : Iterator < Item = ty:: PolyTraitRef < ' tcx > > ,
16881708 {
16891709 let mut matching_candidates = all_candidates ( ) . filter ( |r| {
16901710 self . trait_defines_associated_type_named ( r. def_id ( ) , assoc_name)
@@ -1709,13 +1729,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17091729 debug ! ( "one_bound_for_assoc_type: bound2 = {:?}" , bound2) ;
17101730
17111731 let bounds = iter:: once ( bound) . chain ( iter:: once ( bound2) ) . chain ( matching_candidates) ;
1712- let mut err = struct_span_err ! (
1713- self . tcx( ) . sess, span, E0221 ,
1714- "ambiguous associated type `{}` in bounds of `{}`" ,
1715- assoc_name,
1716- ty_param_name) ;
1732+ let mut err = if is_equality. is_some ( ) {
1733+ // More specific Error Index entry.
1734+ struct_span_err ! (
1735+ self . tcx( ) . sess, span, E0222 ,
1736+ "ambiguous associated type `{}` in bounds of `{}`" ,
1737+ assoc_name,
1738+ ty_param_name
1739+ )
1740+ } else {
1741+ struct_span_err ! (
1742+ self . tcx( ) . sess, span, E0221 ,
1743+ "ambiguous associated type `{}` in bounds of `{}`" ,
1744+ assoc_name,
1745+ ty_param_name
1746+ )
1747+ } ;
17171748 err. span_label ( span, format ! ( "ambiguous associated type `{}`" , assoc_name) ) ;
17181749
1750+ let mut where_bounds = vec ! [ ] ;
17191751 for bound in bounds {
17201752 let bound_span = self . tcx ( ) . associated_items ( bound. def_id ( ) ) . find ( |item| {
17211753 item. kind == ty:: AssocKind :: Type &&
@@ -1729,17 +1761,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17291761 assoc_name,
17301762 bound. print_only_trait_path( ) ,
17311763 ) ) ;
1732- err. span_suggestion (
1733- span,
1734- "use fully qualified syntax to disambiguate" ,
1735- format ! (
1736- "<{} as {}>::{}" ,
1737- ty_param_name,
1738- bound. print_only_trait_path( ) ,
1739- assoc_name,
1740- ) ,
1741- Applicability :: MaybeIncorrect ,
1742- ) ;
1764+ if let Some ( constraint) = & is_equality {
1765+ where_bounds. push ( format ! (
1766+ " T: {trait}::{assoc} = {constraint}" ,
1767+ trait =bound. print_only_trait_path( ) ,
1768+ assoc=assoc_name,
1769+ constraint=constraint,
1770+ ) ) ;
1771+ } else {
1772+ err. span_suggestion (
1773+ span,
1774+ "use fully qualified syntax to disambiguate" ,
1775+ format ! (
1776+ "<{} as {}>::{}" ,
1777+ ty_param_name,
1778+ bound. print_only_trait_path( ) ,
1779+ assoc_name,
1780+ ) ,
1781+ Applicability :: MaybeIncorrect ,
1782+ ) ;
1783+ }
17431784 } else {
17441785 err. note ( & format ! (
17451786 "associated type `{}` could derive from `{}`" ,
@@ -1748,9 +1789,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17481789 ) ) ;
17491790 }
17501791 }
1792+ if !where_bounds. is_empty ( ) {
1793+ err. help ( & format ! (
1794+ "consider introducing a new type parameter `T` and adding `where` constraints:\
1795+ \n where\n T: {},\n {}",
1796+ ty_param_name,
1797+ where_bounds. join( ",\n " ) ,
1798+ ) ) ;
1799+ }
17511800 err. emit ( ) ;
1801+ if !where_bounds. is_empty ( ) {
1802+ return Err ( ErrorReported ) ;
1803+ }
17521804 }
1753-
17541805 return Ok ( bound) ;
17551806 }
17561807
@@ -1856,7 +1907,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18561907 || traits:: supertraits ( tcx, ty:: Binder :: bind ( trait_ref) ) ,
18571908 "Self" ,
18581909 assoc_ident,
1859- span
1910+ span,
1911+ None ,
18601912 ) ?
18611913 }
18621914 ( & ty:: Param ( _) , Res :: SelfTy ( Some ( param_did) , None ) ) |
0 commit comments