1
- use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
1
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
2
2
use rustc_errors:: codes:: * ;
3
3
use rustc_errors:: struct_span_code_err;
4
4
use rustc_hir as hir;
5
+ use rustc_hir:: HirId ;
5
6
use rustc_hir:: def:: { DefKind , Res } ;
6
- use rustc_lint_defs:: builtin:: UNUSED_ASSOCIATED_TYPE_BOUNDS ;
7
+ use rustc_hir:: def_id:: DefId ;
8
+ use rustc_lint_defs:: builtin:: {
9
+ DYN_ASSOC_REDUNDANT , DYN_ASSOC_SHADOWED , UNUSED_ASSOCIATED_TYPE_BOUNDS ,
10
+ } ;
7
11
use rustc_middle:: ty:: fold:: BottomUpFolder ;
8
12
use rustc_middle:: ty:: {
9
13
self , DynKind , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeFoldable ,
@@ -28,7 +32,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
28
32
pub ( super ) fn lower_trait_object_ty (
29
33
& self ,
30
34
span : Span ,
31
- hir_id : hir :: HirId ,
35
+ hir_id : HirId ,
32
36
hir_bounds : & [ hir:: PolyTraitRef < ' tcx > ] ,
33
37
lifetime : & hir:: Lifetime ,
34
38
representation : DynKind ,
@@ -59,12 +63,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
59
63
}
60
64
}
61
65
62
- let ( trait_bounds, mut projection_bounds ) =
66
+ let ( trait_bounds, elaborated_projection_bounds ) =
63
67
traits:: expand_trait_aliases ( tcx, user_written_bounds. clauses ( ) ) ;
64
68
let ( regular_traits, mut auto_traits) : ( Vec < _ > , Vec < _ > ) = trait_bounds
65
69
. into_iter ( )
66
70
. partition ( |( trait_ref, _) | !tcx. trait_is_auto ( trait_ref. def_id ( ) ) ) ;
67
71
72
+ // Map the projection bounds onto a key that makes it easy to remove redundant
73
+ // bounds that are constrained by supertraits of the principal def id.
74
+ //
75
+ // Also make sure we detect conflicting bounds from expanding a trait alias and
76
+ // also specifying it manually, like:
77
+ // ```
78
+ // type Alias = Trait<Assoc = i32>;
79
+ // let _: &dyn Alias<Assoc = u32> = /* ... */;
80
+ // ```
81
+ let mut projection_bounds = FxIndexMap :: default ( ) ;
82
+ for ( proj, proj_span) in elaborated_projection_bounds {
83
+ if let Some ( ( old_proj, old_proj_span) ) = projection_bounds. insert (
84
+ tcx. anonymize_bound_vars ( proj. map_bound ( |proj| proj. projection_term ) ) ,
85
+ ( proj, proj_span) ,
86
+ ) && tcx. anonymize_bound_vars ( proj) != tcx. anonymize_bound_vars ( old_proj)
87
+ {
88
+ let item = tcx. item_name ( proj. item_def_id ( ) ) ;
89
+ self . dcx ( )
90
+ . struct_span_err (
91
+ span,
92
+ format ! (
93
+ "conflicting associated type bounds for `{item}` when \
94
+ expanding trait alias"
95
+ ) ,
96
+ )
97
+ . with_span_label (
98
+ old_proj_span,
99
+ format ! ( "`{item}` is specified to be `{}` here" , old_proj. term( ) ) ,
100
+ )
101
+ . with_span_label (
102
+ proj_span,
103
+ format ! ( "`{item}` is specified to be `{}` here" , proj. term( ) ) ,
104
+ )
105
+ . emit ( ) ;
106
+ }
107
+ }
108
+
68
109
// We don't support empty trait objects.
69
110
if regular_traits. is_empty ( ) && auto_traits. is_empty ( ) {
70
111
let guar =
@@ -105,6 +146,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
105
146
let principal_trait = regular_traits. into_iter ( ) . next ( ) ;
106
147
107
148
let mut needed_associated_types = FxIndexSet :: default ( ) ;
149
+
150
+ // These are the projection bounds that we get from supertraits that
151
+ // don't mention the dyn trait recursively. See comment below.
152
+ let mut implied_projection_bounds = vec ! [ ] ;
153
+
108
154
if let Some ( ( principal_trait, spans) ) = & principal_trait {
109
155
let pred: ty:: Predicate < ' tcx > = ( * principal_trait) . upcast ( tcx) ;
110
156
for ClauseWithSupertraitSpan { pred, supertrait_span } in
@@ -162,7 +208,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
162
208
// the discussion in #56288 for alternatives.
163
209
if !references_self {
164
210
// Include projections defined on supertraits.
165
- projection_bounds. push ( ( pred, supertrait_span) ) ;
211
+ implied_projection_bounds. push ( pred) ;
212
+
213
+ if let Some ( ( user_written_projection, user_written_span) ) =
214
+ projection_bounds. shift_remove ( & tcx. anonymize_bound_vars (
215
+ pred. map_bound ( |pred| pred. projection_term ) ,
216
+ ) )
217
+ {
218
+ if tcx. anonymize_bound_vars ( user_written_projection)
219
+ == tcx. anonymize_bound_vars ( pred)
220
+ {
221
+ self . lint_redundant_projection (
222
+ hir_id,
223
+ user_written_projection,
224
+ principal_trait. def_id ( ) ,
225
+ user_written_span,
226
+ supertrait_span,
227
+ ) ;
228
+ } else {
229
+ self . lint_shadowed_projection (
230
+ hir_id,
231
+ user_written_projection,
232
+ pred,
233
+ principal_trait. def_id ( ) ,
234
+ user_written_span,
235
+ supertrait_span,
236
+ ) ;
237
+ }
238
+ }
166
239
}
167
240
168
241
self . check_elaborated_projection_mentions_input_lifetimes (
@@ -182,12 +255,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
182
255
// types that we expect to be provided by the user, so the following loop
183
256
// removes all the associated types that have a corresponding `Projection`
184
257
// clause, either from expanding trait aliases or written by the user.
185
- for & ( projection_bound, span) in & projection_bounds {
258
+ for & ( projection_bound, span) in projection_bounds. values ( ) {
186
259
let def_id = projection_bound. item_def_id ( ) ;
187
260
let trait_ref = tcx. anonymize_bound_vars (
188
261
projection_bound. map_bound ( |p| p. projection_term . trait_ref ( tcx) ) ,
189
262
) ;
190
- needed_associated_types. swap_remove ( & ( def_id, trait_ref) ) ;
263
+ needed_associated_types. shift_remove ( & ( def_id, trait_ref) ) ;
191
264
if tcx. generics_require_sized_self ( def_id) {
192
265
tcx. emit_node_span_lint (
193
266
UNUSED_ASSOCIATED_TYPE_BOUNDS ,
@@ -197,6 +270,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
197
270
) ;
198
271
}
199
272
}
273
+ for projection_bound in & implied_projection_bounds {
274
+ let def_id = projection_bound. item_def_id ( ) ;
275
+ let trait_ref = tcx. anonymize_bound_vars (
276
+ projection_bound. map_bound ( |p| p. projection_term . trait_ref ( tcx) ) ,
277
+ ) ;
278
+ needed_associated_types. swap_remove ( & ( def_id, trait_ref) ) ;
279
+ }
200
280
201
281
if let Err ( guar) = self . check_for_required_assoc_tys (
202
282
principal_trait. as_ref ( ) . map_or ( smallvec ! [ ] , |( _, spans) | spans. clone ( ) ) ,
@@ -266,7 +346,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
266
346
} )
267
347
} ) ;
268
348
269
- let existential_projections = projection_bounds. iter ( ) . map ( |( bound, _) | {
349
+ let existential_projections = projection_bounds. values ( ) . map ( |( bound, _) | {
270
350
bound. map_bound ( |mut b| {
271
351
assert_eq ! ( b. projection_term. self_ty( ) , dummy_self) ;
272
352
@@ -343,6 +423,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
343
423
Ty :: new_dynamic ( tcx, existential_predicates, region_bound, representation)
344
424
}
345
425
426
+ fn lint_shadowed_projection (
427
+ & self ,
428
+ hir_id : HirId ,
429
+ user_written_projection : ty:: PolyProjectionPredicate < ' tcx > ,
430
+ elaborated_projection : ty:: PolyProjectionPredicate < ' tcx > ,
431
+ principal_def_id : DefId ,
432
+ user_written_span : Span ,
433
+ supertrait_span : Span ,
434
+ ) {
435
+ let tcx = self . tcx ( ) ;
436
+ let assoc = tcx. item_name ( user_written_projection. item_def_id ( ) ) ;
437
+ let principal = tcx. item_name ( principal_def_id) ;
438
+ self . tcx ( ) . node_span_lint ( DYN_ASSOC_SHADOWED , hir_id, user_written_span, |diag| {
439
+ diag. primary_message ( format ! (
440
+ "associated type bound for `{assoc}` in `dyn {principal}` differs from \
441
+ associated type bound from supertrait",
442
+ ) ) ;
443
+ diag. span_label ( user_written_span, "this bound has no effect and will be ignored" ) ;
444
+ diag. note ( format ! (
445
+ "`{assoc} = {}` was implied by a supertrait and shadows any user-written bounds, \
446
+ so `{assoc} = {}` will be ignored",
447
+ elaborated_projection. term( ) ,
448
+ user_written_projection. term( ) ,
449
+ ) ) ;
450
+ diag. span_label ( supertrait_span, "shadowed due to this supertrait bound" ) ;
451
+ } ) ;
452
+ }
453
+
454
+ fn lint_redundant_projection (
455
+ & self ,
456
+ hir_id : HirId ,
457
+ user_written_projection : ty:: PolyProjectionPredicate < ' tcx > ,
458
+ principal_def_id : DefId ,
459
+ user_written_span : Span ,
460
+ supertrait_span : Span ,
461
+ ) {
462
+ let tcx = self . tcx ( ) ;
463
+ let assoc = tcx. item_name ( user_written_projection. item_def_id ( ) ) ;
464
+ let principal = tcx. item_name ( principal_def_id) ;
465
+ self . tcx ( ) . node_span_lint ( DYN_ASSOC_REDUNDANT , hir_id, user_written_span, |diag| {
466
+ diag. primary_message ( format ! (
467
+ "associated type bound for `{assoc}` in `dyn {principal}` is redundant" ,
468
+ ) ) ;
469
+ diag. span_label ( supertrait_span, "redundant due to this supertrait bound" ) ;
470
+ } ) ;
471
+ }
472
+
346
473
/// Check that elaborating the principal of a trait ref doesn't lead to projections
347
474
/// that are unconstrained. This can happen because an otherwise unconstrained
348
475
/// *type variable* can be substituted with a type that has late-bound regions. See
0 commit comments