@@ -27,6 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
2727use rustc_hir:: def_id:: { DefId , LocalDefId } ;
2828use rustc_hir:: intravisit:: { walk_generics, Visitor as _} ;
2929use rustc_hir:: { GenericArg , GenericArgs , OpaqueTyOrigin } ;
30+ use rustc_infer:: infer:: TyCtxtInferExt ;
3031use rustc_middle:: middle:: stability:: AllowUnstable ;
3132use rustc_middle:: ty:: subst:: { self , GenericArgKind , InternalSubsts , SubstsRef } ;
3233use rustc_middle:: ty:: GenericParamDefKind ;
@@ -1643,8 +1644,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16431644 fn report_ambiguous_associated_type (
16441645 & self ,
16451646 span : Span ,
1646- type_str : & str ,
1647- trait_str : & str ,
1647+ types : & [ String ] ,
1648+ traits : & [ String ] ,
16481649 name : Symbol ,
16491650 ) -> ErrorGuaranteed {
16501651 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 {
16551656 . keys ( )
16561657 . any ( |full_span| full_span. contains ( span) )
16571658 {
1658- err. span_suggestion (
1659+ err. span_suggestion_verbose (
16591660 span. shrink_to_lo ( ) ,
16601661 "you are looking for the module in `std`, not the primitive type" ,
16611662 "std::" ,
16621663 Applicability :: MachineApplicable ,
16631664 ) ;
16641665 } 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+ }
16711745 }
16721746 err. emit ( )
16731747 }
@@ -2050,12 +2124,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20502124 err. emit ( )
20512125 } else if let Err ( reported) = qself_ty. error_reported ( ) {
20522126 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.
20532136 } 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+
20542180 // Don't print `TyErr` to the user.
20552181 self . report_ambiguous_associated_type (
20562182 span,
2057- & qself_ty. to_string ( ) ,
2058- "Trait" ,
2183+ & [ qself_ty. to_string ( ) ] ,
2184+ & traits ,
20592185 assoc_ident. name ,
20602186 )
20612187 } ;
@@ -2173,16 +2299,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
21732299 let is_part_of_self_trait_constraints = def_id == trait_def_id;
21742300 let is_part_of_fn_in_self_trait = parent_def_id == Some ( trait_def_id) ;
21752301
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 ( ) ]
21782304 } 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 ( )
21802318 } ;
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`
21822322 let reported = self . report_ambiguous_associated_type (
21832323 span,
2184- type_name ,
2185- & path_str,
2324+ & type_names ,
2325+ & [ path_str] ,
21862326 item_segment. ident . name ,
21872327 ) ;
21882328 return tcx. ty_error_with_guaranteed ( reported)
0 commit comments