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