@@ -3,17 +3,17 @@ use crate::errors::{
33 ParenthesizedFnTraitExpansion , TraitObjectDeclaredWithNoTraits ,
44} ;
55use crate :: fluent_generated as fluent;
6- use crate :: hir_ty_lowering:: HirTyLowerer ;
6+ use crate :: hir_ty_lowering:: { AssocItemQSelf , HirTyLowerer } ;
77use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
88use rustc_data_structures:: sorted_map:: SortedMap ;
99use rustc_data_structures:: unord:: UnordMap ;
1010use rustc_errors:: MultiSpan ;
1111use rustc_errors:: {
1212 codes:: * , pluralize, struct_span_code_err, Applicability , Diag , ErrorGuaranteed ,
1313} ;
14+ use rustc_hir as hir;
1415use rustc_hir:: def:: { DefKind , Res } ;
15- use rustc_hir:: def_id:: { DefId , LocalDefId } ;
16- use rustc_hir:: { self as hir, Node } ;
16+ use rustc_hir:: def_id:: DefId ;
1717use rustc_middle:: bug;
1818use rustc_middle:: query:: Key ;
1919use rustc_middle:: ty:: print:: { PrintPolyTraitRefExt as _, PrintTraitRefExt as _} ;
@@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
116116 pub ( super ) fn complain_about_assoc_item_not_found < I > (
117117 & self ,
118118 all_candidates : impl Fn ( ) -> I ,
119- ty_param_name : & str ,
120- ty_param_def_id : Option < LocalDefId > ,
119+ qself : AssocItemQSelf ,
121120 assoc_kind : ty:: AssocKind ,
122121 assoc_name : Ident ,
123122 span : Span ,
@@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
139138 ) ;
140139 }
141140
142- let assoc_kind_str = super :: assoc_kind_str ( assoc_kind) ;
141+ let assoc_kind_str = assoc_kind_str ( assoc_kind) ;
142+ let qself_str = qself. to_string ( tcx) ;
143143
144144 // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
145145 // valid span, so we point at the whole path segment instead.
@@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
149149 span : if is_dummy { span } else { assoc_name. span } ,
150150 assoc_name,
151151 assoc_kind : assoc_kind_str,
152- ty_param_name ,
152+ qself : & qself_str ,
153153 label : None ,
154154 sugg : None ,
155155 } ;
@@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
219219 suggested_name,
220220 identically_named : suggested_name == assoc_name. name ,
221221 } ) ;
222- let hir = tcx. hir ( ) ;
223- if let Some ( def_id) = ty_param_def_id
224- && let parent = hir. get_parent_item ( tcx. local_def_id_to_hir_id ( def_id) )
225- && let Some ( generics) = hir. get_generics ( parent. def_id )
222+ if let AssocItemQSelf :: TyParam ( ty_param_def_id, ty_param_span) = qself
223+ // Not using `self.item_def_id()` here as that would yield the opaque type itself if we're
224+ // inside an opaque type while we're interested in the overarching type alias (TAIT).
225+ // FIXME: However, for trait aliases, this incorrectly returns the enclosing module...
226+ && let item_def_id =
227+ tcx. hir ( ) . get_parent_item ( tcx. local_def_id_to_hir_id ( ty_param_def_id) )
228+ // FIXME: ...which obviously won't have any generics.
229+ && let Some ( generics) = tcx. hir ( ) . get_generics ( item_def_id. def_id )
226230 {
227- if generics. bounds_for_param ( def_id) . flat_map ( |pred| pred. bounds . iter ( ) ) . any (
228- |b| match b {
231+ // FIXME: Suggest adding supertrait bounds if we have a `Self` type param.
232+ // FIXME(trait_alias): Suggest adding `Self: Trait` to
233+ // `trait Alias = where Self::Proj:;` with `trait Trait { type Proj; }`.
234+ if generics
235+ . bounds_for_param ( ty_param_def_id)
236+ . flat_map ( |pred| pred. bounds . iter ( ) )
237+ . any ( |b| match b {
229238 hir:: GenericBound :: Trait ( t, ..) => {
230239 t. trait_ref . trait_def_id ( ) == Some ( best_trait)
231240 }
232241 _ => false ,
233- } ,
234- ) {
242+ } )
243+ {
235244 // The type param already has a bound for `trait_name`, we just need to
236245 // change the associated item.
237246 err. sugg = Some ( errors:: AssocItemNotFoundSugg :: SimilarInOtherTrait {
@@ -242,48 +251,60 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
242251 return self . dcx ( ) . emit_err ( err) ;
243252 }
244253
245- let mut err = self . dcx ( ) . create_err ( err) ;
246- if suggest_constraining_type_param (
247- tcx,
248- generics,
249- & mut err,
250- & ty_param_name,
251- & trait_name,
252- None ,
253- None ,
254- ) && suggested_name != assoc_name. name
254+ let trait_args = & ty:: GenericArgs :: identity_for_item ( tcx, best_trait) [ 1 ..] ;
255+ let mut trait_ref = trait_name. clone ( ) ;
256+ let applicability = if let [ arg, args @ ..] = trait_args {
257+ use std:: fmt:: Write ;
258+ write ! ( trait_ref, "</* {arg}" ) . unwrap ( ) ;
259+ args. iter ( ) . try_for_each ( |arg| write ! ( trait_ref, ", {arg}" ) ) . unwrap ( ) ;
260+ trait_ref += " */>" ;
261+ Applicability :: HasPlaceholders
262+ } else {
263+ Applicability :: MaybeIncorrect
264+ } ;
265+
266+ let identically_named = suggested_name == assoc_name. name ;
267+
268+ if let DefKind :: TyAlias = tcx. def_kind ( item_def_id)
269+ && !tcx. type_alias_is_lazy ( item_def_id)
255270 {
256- // We suggested constraining a type parameter, but the associated item on it
257- // was also not an exact match, so we also suggest changing it.
258- err. span_suggestion_verbose (
259- assoc_name. span ,
260- fluent:: hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
271+ err. sugg = Some ( errors:: AssocItemNotFoundSugg :: SimilarInOtherTraitQPath {
272+ lo : ty_param_span. shrink_to_lo ( ) ,
273+ mi : ty_param_span. shrink_to_hi ( ) ,
274+ hi : ( !identically_named) . then_some ( assoc_name. span ) ,
275+ trait_ref,
276+ identically_named,
261277 suggested_name,
262- Applicability :: MaybeIncorrect ,
263- ) ;
278+ applicability,
279+ } ) ;
280+ } else {
281+ let mut err = self . dcx ( ) . create_err ( err) ;
282+ if suggest_constraining_type_param (
283+ tcx, generics, & mut err, & qself_str, & trait_ref, None , None ,
284+ ) && !identically_named
285+ {
286+ // We suggested constraining a type parameter, but the associated item on it
287+ // was also not an exact match, so we also suggest changing it.
288+ err. span_suggestion_verbose (
289+ assoc_name. span ,
290+ fluent:: hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
291+ suggested_name,
292+ Applicability :: MaybeIncorrect ,
293+ ) ;
294+ }
295+ return err. emit ( ) ;
264296 }
265- return err. emit ( ) ;
266297 }
267298 return self . dcx ( ) . emit_err ( err) ;
268299 }
269300 }
270301
271302 // If we still couldn't find any associated item, and only one associated item exists,
272- // suggests using it.
303+ // suggest using it.
273304 if let [ candidate_name] = all_candidate_names. as_slice ( ) {
274- // This should still compile, except on `#![feature(associated_type_defaults)]`
275- // where it could suggests `type A = Self::A`, thus recursing infinitely.
276- let applicability =
277- if assoc_kind == ty:: AssocKind :: Type && tcx. features ( ) . associated_type_defaults {
278- Applicability :: Unspecified
279- } else {
280- Applicability :: MaybeIncorrect
281- } ;
282-
283305 err. sugg = Some ( errors:: AssocItemNotFoundSugg :: Other {
284306 span : assoc_name. span ,
285- applicability,
286- ty_param_name,
307+ qself : & qself_str,
287308 assoc_kind : assoc_kind_str,
288309 suggested_name : * candidate_name,
289310 } ) ;
@@ -349,10 +370,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
349370
350371 self . dcx ( ) . emit_err ( errors:: AssocKindMismatch {
351372 span,
352- expected : super :: assoc_kind_str ( expected) ,
353- got : super :: assoc_kind_str ( got) ,
373+ expected : assoc_kind_str ( expected) ,
374+ got : assoc_kind_str ( got) ,
354375 expected_because_label,
355- assoc_kind : super :: assoc_kind_str ( assoc_item. kind ) ,
376+ assoc_kind : assoc_kind_str ( assoc_item. kind ) ,
356377 def_span : tcx. def_span ( assoc_item. def_id ) ,
357378 bound_on_assoc_const_label,
358379 wrap_in_braces_sugg,
@@ -746,7 +767,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
746767 if let ( [ ] , [ bound] ) = ( & potential_assoc_types[ ..] , & trait_bounds) {
747768 let grandparent = tcx. parent_hir_node ( tcx. parent_hir_id ( bound. trait_ref . hir_ref_id ) ) ;
748769 in_expr_or_pat = match grandparent {
749- Node :: Expr ( _) | Node :: Pat ( _) => true ,
770+ hir :: Node :: Expr ( _) | hir :: Node :: Pat ( _) => true ,
750771 _ => false ,
751772 } ;
752773 match bound. trait_ref . path . segments {
@@ -1612,3 +1633,11 @@ fn generics_args_err_extend<'a>(
16121633 _ => { }
16131634 }
16141635}
1636+
1637+ pub ( super ) fn assoc_kind_str ( kind : ty:: AssocKind ) -> & ' static str {
1638+ match kind {
1639+ ty:: AssocKind :: Fn => "function" ,
1640+ ty:: AssocKind :: Const => "constant" ,
1641+ ty:: AssocKind :: Type => "type" ,
1642+ }
1643+ }
0 commit comments