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