@@ -24,6 +24,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
24
24
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
25
25
use rustc_hir:: intravisit:: { walk_generics, Visitor as _} ;
26
26
use rustc_hir:: { GenericArg , GenericArgs , OpaqueTyOrigin } ;
27
+ use rustc_infer:: infer:: TyCtxtInferExt ;
27
28
use rustc_middle:: middle:: stability:: AllowUnstable ;
28
29
use rustc_middle:: ty:: subst:: { self , GenericArgKind , InternalSubsts , SubstsRef } ;
29
30
use rustc_middle:: ty:: GenericParamDefKind ;
@@ -1633,8 +1634,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1633
1634
fn report_ambiguous_associated_type (
1634
1635
& self ,
1635
1636
span : Span ,
1636
- type_str : & str ,
1637
- trait_str : & str ,
1637
+ types : & [ String ] ,
1638
+ traits : & [ String ] ,
1638
1639
name : Symbol ,
1639
1640
) -> ErrorGuaranteed {
1640
1641
let mut err = struct_span_err ! ( self . tcx( ) . sess, span, E0223 , "ambiguous associated type" ) ;
@@ -1645,19 +1646,92 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1645
1646
. keys ( )
1646
1647
. any ( |full_span| full_span. contains ( span) )
1647
1648
{
1648
- err. span_suggestion (
1649
+ err. span_suggestion_verbose (
1649
1650
span. shrink_to_lo ( ) ,
1650
1651
"you are looking for the module in `std`, not the primitive type" ,
1651
1652
"std::" ,
1652
1653
Applicability :: MachineApplicable ,
1653
1654
) ;
1654
1655
} else {
1655
- err. span_suggestion (
1656
- span,
1657
- "use fully-qualified syntax" ,
1658
- format ! ( "<{} as {}>::{}" , type_str, trait_str, name) ,
1659
- Applicability :: HasPlaceholders ,
1660
- ) ;
1656
+ match ( types, traits) {
1657
+ ( [ ] , [ ] ) => {
1658
+ err. span_suggestion_verbose (
1659
+ span,
1660
+ & format ! (
1661
+ "if there were a type named `Type` that implements a trait named \
1662
+ `Trait` with associated type `{name}`, you could use the \
1663
+ fully-qualified path",
1664
+ ) ,
1665
+ format ! ( "<Type as Trait>::{name}" ) ,
1666
+ Applicability :: HasPlaceholders ,
1667
+ ) ;
1668
+ }
1669
+ ( [ ] , [ trait_str] ) => {
1670
+ err. span_suggestion_verbose (
1671
+ span,
1672
+ & format ! (
1673
+ "if there were a type named `Example` that implemented `{trait_str}`, \
1674
+ you could use the fully-qualified path",
1675
+ ) ,
1676
+ format ! ( "<Example as {trait_str}>::{name}" ) ,
1677
+ Applicability :: HasPlaceholders ,
1678
+ ) ;
1679
+ }
1680
+ ( [ ] , traits) => {
1681
+ err. span_suggestions (
1682
+ span,
1683
+ & format ! (
1684
+ "if there were a type named `Example` that implemented one of the \
1685
+ traits with associated type `{name}`, you could use the \
1686
+ fully-qualified path",
1687
+ ) ,
1688
+ traits
1689
+ . iter ( )
1690
+ . map ( |trait_str| format ! ( "<Example as {trait_str}>::{name}" ) )
1691
+ . collect :: < Vec < _ > > ( ) ,
1692
+ Applicability :: HasPlaceholders ,
1693
+ ) ;
1694
+ }
1695
+ ( [ type_str] , [ ] ) => {
1696
+ err. span_suggestion_verbose (
1697
+ span,
1698
+ & format ! (
1699
+ "if there were a trait named `Example` with associated type `{name}` \
1700
+ implemented for `{type_str}`, you could use the fully-qualified path",
1701
+ ) ,
1702
+ format ! ( "<{type_str} as Example>::{name}" ) ,
1703
+ Applicability :: HasPlaceholders ,
1704
+ ) ;
1705
+ }
1706
+ ( types, [ ] ) => {
1707
+ err. span_suggestions (
1708
+ span,
1709
+ & format ! (
1710
+ "if there were a trait named `Example` with associated type `{name}` \
1711
+ implemented for one of the types, you could use the fully-qualified \
1712
+ path",
1713
+ ) ,
1714
+ types
1715
+ . into_iter ( )
1716
+ . map ( |type_str| format ! ( "<{type_str} as Example>::{name}" ) ) ,
1717
+ Applicability :: HasPlaceholders ,
1718
+ ) ;
1719
+ }
1720
+ ( types, traits) => {
1721
+ let mut suggestions = vec ! [ ] ;
1722
+ for type_str in types {
1723
+ for trait_str in traits {
1724
+ suggestions. push ( format ! ( "<{type_str} as {trait_str}>::{name}" ) ) ;
1725
+ }
1726
+ }
1727
+ err. span_suggestions (
1728
+ span,
1729
+ "use the fully-qualified path" ,
1730
+ suggestions,
1731
+ Applicability :: MachineApplicable ,
1732
+ ) ;
1733
+ }
1734
+ }
1661
1735
}
1662
1736
err. emit ( )
1663
1737
}
@@ -2040,12 +2114,67 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2040
2114
err. emit ( )
2041
2115
} else if let Err ( reported) = qself_ty. error_reported ( ) {
2042
2116
reported
2117
+ } else if let ty:: Alias ( ty:: Opaque , alias_ty) = qself_ty. kind ( ) {
2118
+ // `<impl Trait as OtherTrait>::Assoc` makes no sense.
2119
+ struct_span_err ! (
2120
+ tcx. sess,
2121
+ tcx. def_span( alias_ty. def_id) ,
2122
+ E0667 ,
2123
+ "`impl Trait` is not allowed in path parameters"
2124
+ )
2125
+ . emit ( ) // Already reported in an earlier stage.
2043
2126
} else {
2127
+ // Find all the `impl`s that `qself_ty` has for any trait that has the
2128
+ // associated type, so that we suggest the right one.
2129
+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
2130
+ // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
2131
+ // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
2132
+ let param_env = ty:: ParamEnv :: new (
2133
+ ty:: List :: empty ( ) ,
2134
+ traits:: Reveal :: All ,
2135
+ hir:: Constness :: NotConst ,
2136
+ ) ;
2137
+ let traits: Vec < _ > = self
2138
+ . tcx ( )
2139
+ . all_traits ( )
2140
+ . filter ( |trait_def_id| {
2141
+ // Consider only traits with the associated type
2142
+ tcx. associated_items ( * trait_def_id)
2143
+ . in_definition_order ( )
2144
+ . find ( |i| {
2145
+ i. kind . namespace ( ) == Namespace :: TypeNS
2146
+ && i. ident ( tcx) . normalize_to_macros_2_0 ( ) == assoc_ident
2147
+ && matches ! ( i. kind, ty:: AssocKind :: Type )
2148
+ } )
2149
+ . is_some ( )
2150
+ // Consider only accessible traits
2151
+ && tcx. visibility ( * trait_def_id)
2152
+ . is_accessible_from ( self . item_def_id ( ) , tcx)
2153
+ && tcx. all_impls ( * trait_def_id)
2154
+ . filter ( |impl_def_id| {
2155
+ let trait_ref = tcx. impl_trait_ref ( impl_def_id) ;
2156
+ trait_ref. map_or ( false , |impl_| {
2157
+ infcx
2158
+ . can_eq (
2159
+ param_env,
2160
+ tcx. erase_regions ( impl_. self_ty ( ) ) ,
2161
+ tcx. erase_regions ( qself_ty) ,
2162
+ )
2163
+ . is_ok ( )
2164
+ } )
2165
+ && tcx. impl_polarity ( impl_def_id) != ty:: ImplPolarity :: Negative
2166
+ } )
2167
+ . next ( )
2168
+ . is_some ( )
2169
+ } )
2170
+ . map ( |trait_def_id| tcx. def_path_str ( trait_def_id) )
2171
+ . collect ( ) ;
2172
+
2044
2173
// Don't print `TyErr` to the user.
2045
2174
self . report_ambiguous_associated_type (
2046
2175
span,
2047
- & qself_ty. to_string ( ) ,
2048
- "Trait" ,
2176
+ & [ qself_ty. to_string ( ) ] ,
2177
+ & traits ,
2049
2178
assoc_ident. name ,
2050
2179
)
2051
2180
} ;
@@ -2163,16 +2292,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2163
2292
let is_part_of_self_trait_constraints = def_id == trait_def_id;
2164
2293
let is_part_of_fn_in_self_trait = parent_def_id == Some ( trait_def_id) ;
2165
2294
2166
- let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
2167
- "Self"
2295
+ let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
2296
+ vec ! [ "Self" . to_string ( ) ]
2168
2297
} else {
2169
- "Type"
2298
+ // Find all the types that have an `impl` for the trait.
2299
+ tcx. all_impls ( trait_def_id)
2300
+ . filter ( |impl_def_id| {
2301
+ // Consider only accessible traits
2302
+ tcx. visibility ( * impl_def_id) . is_accessible_from ( self . item_def_id ( ) , tcx)
2303
+ && tcx. impl_polarity ( impl_def_id) != ty:: ImplPolarity :: Negative
2304
+ } )
2305
+ . filter_map ( |impl_def_id| tcx. impl_trait_ref ( impl_def_id) )
2306
+ . map ( |impl_| impl_. self_ty ( ) )
2307
+ // We don't care about blanket impls.
2308
+ . filter ( |self_ty| !self_ty. has_non_region_infer ( ) )
2309
+ . map ( |self_ty| tcx. erase_regions ( self_ty) . to_string ( ) )
2310
+ . collect ( )
2170
2311
} ;
2171
-
2312
+ // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
2313
+ // references the trait. Relevant for the first case in
2314
+ // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
2172
2315
let reported = self . report_ambiguous_associated_type (
2173
2316
span,
2174
- type_name ,
2175
- & path_str,
2317
+ & type_names ,
2318
+ & [ path_str] ,
2176
2319
item_segment. ident . name ,
2177
2320
) ;
2178
2321
return tcx. ty_error_with_guaranteed ( reported)
0 commit comments