1- use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
1+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
22use rustc_errors:: codes:: * ;
33use rustc_errors:: struct_span_code_err;
44use rustc_hir as hir;
5+ use rustc_hir:: HirId ;
56use 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+ } ;
711use rustc_middle:: ty:: fold:: BottomUpFolder ;
812use rustc_middle:: ty:: {
913 self , DynKind , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeFoldable ,
@@ -28,7 +32,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
2832 pub ( super ) fn lower_trait_object_ty (
2933 & self ,
3034 span : Span ,
31- hir_id : hir :: HirId ,
35+ hir_id : HirId ,
3236 hir_bounds : & [ hir:: PolyTraitRef < ' tcx > ] ,
3337 lifetime : & hir:: Lifetime ,
3438 representation : DynKind ,
@@ -59,12 +63,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
5963 }
6064 }
6165
62- let ( trait_bounds, mut projection_bounds ) =
66+ let ( trait_bounds, elaborated_projection_bounds ) =
6367 traits:: expand_trait_aliases ( tcx, user_written_bounds. clauses ( ) ) ;
6468 let ( regular_traits, mut auto_traits) : ( Vec < _ > , Vec < _ > ) = trait_bounds
6569 . into_iter ( )
6670 . partition ( |( trait_ref, _) | !tcx. trait_is_auto ( trait_ref. def_id ( ) ) ) ;
6771
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+
68109 // We don't support empty trait objects.
69110 if regular_traits. is_empty ( ) && auto_traits. is_empty ( ) {
70111 let guar =
@@ -105,6 +146,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
105146 let principal_trait = regular_traits. into_iter ( ) . next ( ) ;
106147
107148 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+
108154 if let Some ( ( principal_trait, spans) ) = & principal_trait {
109155 let pred: ty:: Predicate < ' tcx > = ( * principal_trait) . upcast ( tcx) ;
110156 for ClauseWithSupertraitSpan { pred, supertrait_span } in
@@ -162,7 +208,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
162208 // the discussion in #56288 for alternatives.
163209 if !references_self {
164210 // 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+ }
166239 }
167240
168241 self . check_elaborated_projection_mentions_input_lifetimes (
@@ -182,12 +255,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
182255 // types that we expect to be provided by the user, so the following loop
183256 // removes all the associated types that have a corresponding `Projection`
184257 // 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 ( ) {
186259 let def_id = projection_bound. item_def_id ( ) ;
187260 let trait_ref = tcx. anonymize_bound_vars (
188261 projection_bound. map_bound ( |p| p. projection_term . trait_ref ( tcx) ) ,
189262 ) ;
190- needed_associated_types. swap_remove ( & ( def_id, trait_ref) ) ;
263+ needed_associated_types. shift_remove ( & ( def_id, trait_ref) ) ;
191264 if tcx. generics_require_sized_self ( def_id) {
192265 tcx. emit_node_span_lint (
193266 UNUSED_ASSOCIATED_TYPE_BOUNDS ,
@@ -197,6 +270,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
197270 ) ;
198271 }
199272 }
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+ }
200280
201281 if let Err ( guar) = self . check_for_required_assoc_tys (
202282 principal_trait. as_ref ( ) . map_or ( smallvec ! [ ] , |( _, spans) | spans. clone ( ) ) ,
@@ -266,7 +346,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
266346 } )
267347 } ) ;
268348
269- let existential_projections = projection_bounds. iter ( ) . map ( |( bound, _) | {
349+ let existential_projections = projection_bounds. values ( ) . map ( |( bound, _) | {
270350 bound. map_bound ( |mut b| {
271351 assert_eq ! ( b. projection_term. self_ty( ) , dummy_self) ;
272352
@@ -343,6 +423,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
343423 Ty :: new_dynamic ( tcx, existential_predicates, region_bound, representation)
344424 }
345425
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+
346473 /// Check that elaborating the principal of a trait ref doesn't lead to projections
347474 /// that are unconstrained. This can happen because an otherwise unconstrained
348475 /// *type variable* can be substituted with a type that has late-bound regions. See
0 commit comments