@@ -24,6 +24,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
2424use rustc_hir:: def_id:: { DefId , LocalDefId } ;
2525use rustc_hir:: intravisit:: { walk_generics, Visitor as _} ;
2626use rustc_hir:: { GenericArg , GenericArgs , OpaqueTyOrigin } ;
27+ use rustc_infer:: infer:: TyCtxtInferExt ;
2728use rustc_middle:: middle:: stability:: AllowUnstable ;
2829use rustc_middle:: ty:: subst:: { self , GenericArgKind , InternalSubsts , SubstsRef } ;
2930use rustc_middle:: ty:: GenericParamDefKind ;
@@ -1633,8 +1634,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16331634 fn report_ambiguous_associated_type (
16341635 & self ,
16351636 span : Span ,
1636- type_str : & str ,
1637- trait_str : & str ,
1637+ types : & [ String ] ,
1638+ traits : & [ String ] ,
16381639 name : Symbol ,
16391640 ) -> ErrorGuaranteed {
16401641 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 {
16451646 . keys ( )
16461647 . any ( |full_span| full_span. contains ( span) )
16471648 {
1648- err. span_suggestion (
1649+ err. span_suggestion_verbose (
16491650 span. shrink_to_lo ( ) ,
16501651 "you are looking for the module in `std`, not the primitive type" ,
16511652 "std::" ,
16521653 Applicability :: MachineApplicable ,
16531654 ) ;
16541655 } 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+ }
16611735 }
16621736 err. emit ( )
16631737 }
@@ -2040,12 +2114,67 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20402114 err. emit ( )
20412115 } else if let Err ( reported) = qself_ty. error_reported ( ) {
20422116 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.
20432126 } 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+
20442173 // Don't print `TyErr` to the user.
20452174 self . report_ambiguous_associated_type (
20462175 span,
2047- & qself_ty. to_string ( ) ,
2048- "Trait" ,
2176+ & [ qself_ty. to_string ( ) ] ,
2177+ & traits ,
20492178 assoc_ident. name ,
20502179 )
20512180 } ;
@@ -2163,16 +2292,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
21632292 let is_part_of_self_trait_constraints = def_id == trait_def_id;
21642293 let is_part_of_fn_in_self_trait = parent_def_id == Some ( trait_def_id) ;
21652294
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 ( ) ]
21682297 } 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 ( )
21702311 } ;
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`
21722315 let reported = self . report_ambiguous_associated_type (
21732316 span,
2174- type_name ,
2175- & path_str,
2317+ & type_names ,
2318+ & [ path_str] ,
21762319 item_segment. ident . name ,
21772320 ) ;
21782321 return tcx. ty_error_with_guaranteed ( reported)
0 commit comments