@@ -1220,10 +1220,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1220
1220
}
1221
1221
}
1222
1222
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
+ ) {
1225
1227
// Simple case: X is defined in the current trait.
1226
- Ok ( trait_ref)
1228
+ trait_ref
1227
1229
} else {
1228
1230
// Otherwise, we have to walk through the supertraits to find
1229
1231
// those that do.
@@ -1232,8 +1234,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1232
1234
& trait_ref. print_only_trait_path ( ) . to_string ( ) ,
1233
1235
binding. item_name ,
1234
1236
path_span,
1235
- )
1236
- } ?;
1237
+ match binding. kind {
1238
+ ConvertedBindingKind :: Equality ( ty) => Some ( ty. to_string ( ) ) ,
1239
+ _ => None ,
1240
+ } ,
1241
+ ) ?
1242
+ } ;
1237
1243
1238
1244
let ( assoc_ident, def_scope) =
1239
1245
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 {
1564
1570
}
1565
1571
let mut suggestions_len = suggestions. len ( ) ;
1566
1572
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 &&
1568
1590
// Do not attempt to suggest when we don't know which path segment needs the
1569
1591
// type parameter set.
1570
1592
trait_bounds[ 0 ] . trait_ref . path . segments . len ( ) == 1
1571
1593
{
1572
- debug ! ( "path segments {:?}" , trait_bounds[ 0 ] . trait_ref. path. segments) ;
1573
1594
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 ( ) ;
1580
1595
let sugg = assoc_types. join ( ", " ) ;
1581
1596
if snippet. ends_with ( '>' ) {
1582
1597
// 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 {
1602
1617
. map ( |t| format ! ( "`{}`" , tcx. associated_item( * t) . ident) )
1603
1618
. collect :: < Vec < _ > > ( )
1604
1619
. join ( ", " ) ;
1605
- err. span_label ( span , format ! (
1620
+ err. span_label ( sugg_span , format ! (
1606
1621
"associated type{} {} must be specified" ,
1607
1622
pluralize!( associated_types. len( ) ) ,
1608
1623
names,
@@ -1635,10 +1650,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1635
1650
) ;
1636
1651
} else {
1637
1652
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
1642
1657
) ;
1643
1658
}
1644
1659
err. emit ( ) ;
@@ -1648,12 +1663,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1648
1663
// given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
1649
1664
// This function will fail if there are no suitable bounds or there is
1650
1665
// 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 > {
1657
1672
let tcx = self . tcx ( ) ;
1658
1673
1659
1674
debug ! (
@@ -1675,16 +1690,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1675
1690
& param_name. as_str ( ) ,
1676
1691
assoc_name,
1677
1692
span,
1693
+ None ,
1678
1694
)
1679
1695
}
1680
1696
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 > > ,
1688
1708
{
1689
1709
let mut matching_candidates = all_candidates ( ) . filter ( |r| {
1690
1710
self . trait_defines_associated_type_named ( r. def_id ( ) , assoc_name)
@@ -1709,13 +1729,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1709
1729
debug ! ( "one_bound_for_assoc_type: bound2 = {:?}" , bound2) ;
1710
1730
1711
1731
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
+ } ;
1717
1748
err. span_label ( span, format ! ( "ambiguous associated type `{}`" , assoc_name) ) ;
1718
1749
1750
+ let mut where_bounds = vec ! [ ] ;
1719
1751
for bound in bounds {
1720
1752
let bound_span = self . tcx ( ) . associated_items ( bound. def_id ( ) ) . find ( |item| {
1721
1753
item. kind == ty:: AssocKind :: Type &&
@@ -1729,17 +1761,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1729
1761
assoc_name,
1730
1762
bound. print_only_trait_path( ) ,
1731
1763
) ) ;
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
+ }
1743
1784
} else {
1744
1785
err. note ( & format ! (
1745
1786
"associated type `{}` could derive from `{}`" ,
@@ -1748,9 +1789,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1748
1789
) ) ;
1749
1790
}
1750
1791
}
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
+ }
1751
1800
err. emit ( ) ;
1801
+ if !where_bounds. is_empty ( ) {
1802
+ return Err ( ErrorReported ) ;
1803
+ }
1752
1804
}
1753
-
1754
1805
return Ok ( bound) ;
1755
1806
}
1756
1807
@@ -1856,7 +1907,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1856
1907
|| traits:: supertraits ( tcx, ty:: Binder :: bind ( trait_ref) ) ,
1857
1908
"Self" ,
1858
1909
assoc_ident,
1859
- span
1910
+ span,
1911
+ None ,
1860
1912
) ?
1861
1913
}
1862
1914
( & ty:: Param ( _) , Res :: SelfTy ( Some ( param_did) , None ) ) |
0 commit comments