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 ,
@@ -80,12 +84,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8084 }
8185 }
8286
83- let ( trait_bounds , mut projection_bounds ) =
87+ let ( expanded_trait_bounds , expanded_projection_bounds ) =
8488 traits:: expand_trait_aliases ( tcx, user_written_bounds. clauses ( ) ) ;
85- let ( regular_traits, mut auto_traits) : ( Vec < _ > , Vec < _ > ) = trait_bounds
89+ let ( regular_traits, mut auto_traits) : ( Vec < _ > , Vec < _ > ) = expanded_trait_bounds
8690 . into_iter ( )
8791 . partition ( |( trait_ref, _) | !tcx. trait_is_auto ( trait_ref. def_id ( ) ) ) ;
8892
93+ // Map the projection bounds onto a key that makes it easy to remove redundant
94+ // bounds that are constrained by supertraits of the principal def id.
95+ let mut projection_bounds = FxIndexMap :: default ( ) ;
96+ for ( proj, proj_span) in expanded_projection_bounds {
97+ if let Some ( ( old_proj, old_proj_span) ) = projection_bounds. insert (
98+ tcx. anonymize_bound_vars ( proj. map_bound ( |proj| proj. projection_term ) ) ,
99+ ( proj, proj_span) ,
100+ ) && tcx. anonymize_bound_vars ( proj) != tcx. anonymize_bound_vars ( old_proj)
101+ {
102+ let item = tcx. item_name ( proj. item_def_id ( ) ) ;
103+ self . dcx ( )
104+ . struct_span_err (
105+ span,
106+ format ! (
107+ "conflicting associated type bounds for `{item}` when \
108+ expanding trait alias"
109+ ) ,
110+ )
111+ . with_span_label (
112+ old_proj_span,
113+ format ! ( "`{item}` is specified to be `{}` here" , old_proj. term( ) ) ,
114+ )
115+ . with_span_label (
116+ proj_span,
117+ format ! ( "`{item}` is specified to be `{}` here" , proj. term( ) ) ,
118+ )
119+ . emit ( ) ;
120+ }
121+ }
122+
89123 // We don't support empty trait objects.
90124 if regular_traits. is_empty ( ) && auto_traits. is_empty ( ) {
91125 let guar =
@@ -105,6 +139,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
105139 let principal_trait = regular_traits. into_iter ( ) . next ( ) ;
106140
107141 let mut needed_associated_types = FxIndexSet :: default ( ) ;
142+
143+ // These are the projection bounds that we get from supertraits that
144+ // don't mention the dyn trait recursively. See comment below.
145+ let mut implied_projection_bounds = vec ! [ ] ;
146+
108147 if let Some ( ( principal_trait, spans) ) = & principal_trait {
109148 let pred: ty:: Predicate < ' tcx > = ( * principal_trait) . upcast ( tcx) ;
110149 for ClauseWithSupertraitSpan { pred, supertrait_span } in
@@ -134,14 +173,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
134173 ) ;
135174 }
136175 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( pred) ) => {
137- let pred = bound_predicate. rebind ( pred) ;
176+ let elaborated_projection = bound_predicate. rebind ( pred) ;
138177 // A `Self` within the original bound will be instantiated with a
139178 // `trait_object_dummy_self`, so check for that.
140- let references_self = match pred. skip_binder ( ) . term . unpack ( ) {
141- ty:: TermKind :: Ty ( ty) => ty. walk ( ) . any ( |arg| arg == dummy_self. into ( ) ) ,
142- // FIXME(associated_const_equality): We should walk the const instead of not doing anything
143- ty:: TermKind :: Const ( _) => false ,
144- } ;
179+ let references_self =
180+ match elaborated_projection. skip_binder ( ) . term . unpack ( ) {
181+ ty:: TermKind :: Ty ( ty) => {
182+ ty. walk ( ) . any ( |arg| arg == dummy_self. into ( ) )
183+ }
184+ // FIXME(associated_const_equality): We should walk the const instead of not doing anything
185+ ty:: TermKind :: Const ( _) => false ,
186+ } ;
145187
146188 // If the projection output contains `Self`, force the user to
147189 // elaborate it explicitly to avoid a lot of complexity.
@@ -162,11 +204,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
162204 // the discussion in #56288 for alternatives.
163205 if !references_self {
164206 // Include projections defined on supertraits.
165- projection_bounds. push ( ( pred, supertrait_span) ) ;
207+ implied_projection_bounds. push ( elaborated_projection) ;
208+
209+ if let Some ( ( user_written_projection, user_written_span) ) =
210+ projection_bounds. shift_remove ( & tcx. anonymize_bound_vars (
211+ elaborated_projection. map_bound ( |pred| pred. projection_term ) ,
212+ ) )
213+ {
214+ if tcx. anonymize_bound_vars ( user_written_projection)
215+ == tcx. anonymize_bound_vars ( elaborated_projection)
216+ {
217+ self . lint_redundant_projection (
218+ hir_id,
219+ user_written_projection,
220+ principal_trait. def_id ( ) ,
221+ user_written_span,
222+ supertrait_span,
223+ ) ;
224+ } else {
225+ self . lint_shadowed_projection (
226+ hir_id,
227+ user_written_projection,
228+ elaborated_projection,
229+ principal_trait. def_id ( ) ,
230+ user_written_span,
231+ supertrait_span,
232+ ) ;
233+ }
234+ }
166235 }
167236
168237 self . check_elaborated_projection_mentions_input_lifetimes (
169- pred ,
238+ elaborated_projection ,
170239 * spans. first ( ) . unwrap ( ) ,
171240 supertrait_span,
172241 ) ;
@@ -176,16 +245,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
176245 }
177246 }
178247
179- // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait> ::Assoc = Foo`.
180- // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
181- // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
182- // corresponding `Projection` clause
183- for ( projection_bound, span) in & projection_bounds {
248+ // `dyn Trait<Assoc = Foo>` desugars to something like `dyn Trait + ( Trait::Assoc = Foo) `.
249+ // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types`
250+ // contains all associated types's `DefId`, so the following loop removes all
251+ // the `DefIds` of the associated types that have a corresponding `Projection`.
252+ for & ( projection_bound, span) in projection_bounds. values ( ) {
184253 let def_id = projection_bound. item_def_id ( ) ;
185254 let trait_ref = tcx. anonymize_bound_vars (
186255 projection_bound. map_bound ( |p| p. projection_term . trait_ref ( tcx) ) ,
187256 ) ;
188- needed_associated_types. swap_remove ( & ( def_id, trait_ref) ) ;
257+ needed_associated_types. shift_remove ( & ( def_id, trait_ref) ) ;
189258 if tcx. generics_require_sized_self ( def_id) {
190259 tcx. emit_node_span_lint (
191260 UNUSED_ASSOCIATED_TYPE_BOUNDS ,
@@ -195,6 +264,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
195264 ) ;
196265 }
197266 }
267+ for projection_bound in & implied_projection_bounds {
268+ let def_id = projection_bound. item_def_id ( ) ;
269+ let trait_ref = tcx. anonymize_bound_vars (
270+ projection_bound. map_bound ( |p| p. projection_term . trait_ref ( tcx) ) ,
271+ ) ;
272+ needed_associated_types. swap_remove ( & ( def_id, trait_ref) ) ;
273+ }
198274
199275 if let Err ( guar) = self . check_for_required_assoc_tys (
200276 principal_trait. as_ref ( ) . map_or ( smallvec ! [ ] , |( _, spans) | spans. clone ( ) ) ,
@@ -272,7 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
272348 } )
273349 } ) ;
274350
275- let existential_projections = projection_bounds. iter ( ) . map ( |( bound, _) | {
351+ let existential_projections = projection_bounds. values ( ) . map ( |( bound, _) | {
276352 bound. map_bound ( |mut b| {
277353 assert_eq ! ( b. projection_term. self_ty( ) , dummy_self) ;
278354
@@ -349,6 +425,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
349425 Ty :: new_dynamic ( tcx, existential_predicates, region_bound, representation)
350426 }
351427
428+ fn lint_shadowed_projection (
429+ & self ,
430+ hir_id : HirId ,
431+ user_written_projection : ty:: PolyProjectionPredicate < ' tcx > ,
432+ elaborated_projection : ty:: PolyProjectionPredicate < ' tcx > ,
433+ principal_def_id : DefId ,
434+ user_written_span : Span ,
435+ supertrait_span : Span ,
436+ ) {
437+ let tcx = self . tcx ( ) ;
438+ let assoc = tcx. item_name ( user_written_projection. item_def_id ( ) ) ;
439+ let principal = tcx. item_name ( principal_def_id) ;
440+ self . tcx ( ) . node_span_lint ( DYN_ASSOC_SHADOWED , hir_id, user_written_span, |diag| {
441+ diag. primary_message ( format ! (
442+ "associated type bound for `{assoc}` in `dyn {principal}` differs from \
443+ associated type bound implied by supertrait",
444+ ) ) ;
445+ diag. span_label ( user_written_span, "this bound has no effect and will be ignored" ) ;
446+ diag. note ( format ! (
447+ "`{assoc} = {}` was implied by a supertrait and shadows any user-written bounds, \
448+ so `{assoc} = {}` will be ignored",
449+ elaborated_projection. term( ) ,
450+ user_written_projection. term( ) ,
451+ ) ) ;
452+ diag. span_label ( supertrait_span, "shadowed due to this supertrait bound" ) ;
453+ } ) ;
454+ }
455+
456+ fn lint_redundant_projection (
457+ & self ,
458+ hir_id : HirId ,
459+ user_written_projection : ty:: PolyProjectionPredicate < ' tcx > ,
460+ principal_def_id : DefId ,
461+ user_written_span : Span ,
462+ supertrait_span : Span ,
463+ ) {
464+ let tcx = self . tcx ( ) ;
465+ let assoc = tcx. item_name ( user_written_projection. item_def_id ( ) ) ;
466+ let principal = tcx. item_name ( principal_def_id) ;
467+ self . tcx ( ) . node_span_lint ( DYN_ASSOC_REDUNDANT , hir_id, user_written_span, |diag| {
468+ diag. primary_message ( format ! (
469+ "associated type bound for `{assoc}` in `dyn {principal}` is redundant" ,
470+ ) ) ;
471+ diag. span_label ( supertrait_span, "redundant due to this supertrait bound" ) ;
472+ } ) ;
473+ }
474+
352475 /// Check that elaborating the principal of a trait ref doesn't lead to projections
353476 /// that are unconstrained. This can happen because an otherwise unconstrained
354477 /// *type variable* can be substituted with a type that has late-bound regions. See
0 commit comments