@@ -3,17 +3,17 @@ use crate::errors::{
3
3
ParenthesizedFnTraitExpansion , TraitObjectDeclaredWithNoTraits ,
4
4
} ;
5
5
use crate :: fluent_generated as fluent;
6
- use crate :: hir_ty_lowering:: HirTyLowerer ;
6
+ use crate :: hir_ty_lowering:: { AssocItemQSelf , HirTyLowerer } ;
7
7
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
8
8
use rustc_data_structures:: sorted_map:: SortedMap ;
9
9
use rustc_data_structures:: unord:: UnordMap ;
10
10
use rustc_errors:: MultiSpan ;
11
11
use rustc_errors:: {
12
12
codes:: * , pluralize, struct_span_code_err, Applicability , Diag , ErrorGuaranteed ,
13
13
} ;
14
+ use rustc_hir as hir;
14
15
use 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 ;
17
17
use rustc_middle:: bug;
18
18
use rustc_middle:: query:: Key ;
19
19
use rustc_middle:: ty:: print:: { PrintPolyTraitRefExt as _, PrintTraitRefExt as _} ;
@@ -116,8 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
116
116
pub ( super ) fn complain_about_assoc_item_not_found < I > (
117
117
& self ,
118
118
all_candidates : impl Fn ( ) -> I ,
119
- ty_param_name : & str ,
120
- ty_param_def_id : Option < LocalDefId > ,
119
+ qself : AssocItemQSelf ,
121
120
assoc_kind : ty:: AssocKind ,
122
121
assoc_name : Ident ,
123
122
span : Span ,
@@ -139,7 +138,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
139
138
) ;
140
139
}
141
140
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) ;
143
143
144
144
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
145
145
// valid span, so we point at the whole path segment instead.
@@ -149,7 +149,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
149
149
span : if is_dummy { span } else { assoc_name. span } ,
150
150
assoc_name,
151
151
assoc_kind : assoc_kind_str,
152
- ty_param_name ,
152
+ qself : & qself_str ,
153
153
label : None ,
154
154
sugg : None ,
155
155
} ;
@@ -219,19 +219,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
219
219
suggested_name,
220
220
identically_named : suggested_name == assoc_name. name ,
221
221
} ) ;
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 )
226
230
{
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 {
229
238
hir:: GenericBound :: Trait ( t, ..) => {
230
239
t. trait_ref . trait_def_id ( ) == Some ( best_trait)
231
240
}
232
241
_ => false ,
233
- } ,
234
- ) {
242
+ } )
243
+ {
235
244
// The type param already has a bound for `trait_name`, we just need to
236
245
// change the associated item.
237
246
err. sugg = Some ( errors:: AssocItemNotFoundSugg :: SimilarInOtherTrait {
@@ -242,48 +251,60 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
242
251
return self . dcx ( ) . emit_err ( err) ;
243
252
}
244
253
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)
255
270
{
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,
261
277
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 ( ) ;
264
296
}
265
- return err. emit ( ) ;
266
297
}
267
298
return self . dcx ( ) . emit_err ( err) ;
268
299
}
269
300
}
270
301
271
302
// If we still couldn't find any associated item, and only one associated item exists,
272
- // suggests using it.
303
+ // suggest using it.
273
304
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
-
283
305
err. sugg = Some ( errors:: AssocItemNotFoundSugg :: Other {
284
306
span : assoc_name. span ,
285
- applicability,
286
- ty_param_name,
307
+ qself : & qself_str,
287
308
assoc_kind : assoc_kind_str,
288
309
suggested_name : * candidate_name,
289
310
} ) ;
@@ -349,10 +370,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
349
370
350
371
self . dcx ( ) . emit_err ( errors:: AssocKindMismatch {
351
372
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) ,
354
375
expected_because_label,
355
- assoc_kind : super :: assoc_kind_str ( assoc_item. kind ) ,
376
+ assoc_kind : assoc_kind_str ( assoc_item. kind ) ,
356
377
def_span : tcx. def_span ( assoc_item. def_id ) ,
357
378
bound_on_assoc_const_label,
358
379
wrap_in_braces_sugg,
@@ -746,7 +767,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
746
767
if let ( [ ] , [ bound] ) = ( & potential_assoc_types[ ..] , & trait_bounds) {
747
768
let grandparent = tcx. parent_hir_node ( tcx. parent_hir_id ( bound. trait_ref . hir_ref_id ) ) ;
748
769
in_expr_or_pat = match grandparent {
749
- Node :: Expr ( _) | Node :: Pat ( _) => true ,
770
+ hir :: Node :: Expr ( _) | hir :: Node :: Pat ( _) => true ,
750
771
_ => false ,
751
772
} ;
752
773
match bound. trait_ref . path . segments {
@@ -1612,3 +1633,11 @@ fn generics_args_err_extend<'a>(
1612
1633
_ => { }
1613
1634
}
1614
1635
}
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