Skip to content

Commit ab0a962

Browse files
committed
extend duplicate_bounds to track lifetimes
1 parent 46868a7 commit ab0a962

File tree

3 files changed

+94
-34
lines changed

3 files changed

+94
-34
lines changed

compiler/rustc_lint/src/builtin.rs

+50-27
Original file line numberDiff line numberDiff line change
@@ -3173,56 +3173,76 @@ declare_lint_pass!(DuplicateBounds => [DUPLICATE_BOUNDS]);
31733173

31743174
impl<'tcx> LateLintPass<'tcx> for DuplicateBounds {
31753175
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx hir::Generics<'_>) {
3176-
struct TraitRes {
3177-
res: Res,
3176+
struct Bound {
3177+
kind: BoundKind,
31783178
span: Span,
31793179
}
31803180

3181-
impl TraitRes {
3182-
fn from_bound(bound: &hir::GenericBound<'_>) -> Option<Self> {
3183-
if let hir::GenericBound::Trait(t, _) = bound {
3184-
Some(Self { res: t.trait_ref.path.res, span: t.span })
3185-
} else {
3186-
None
3181+
#[derive(Hash, PartialEq, Eq)]
3182+
enum BoundKind {
3183+
Trait(Res),
3184+
Lifetime(hir::LifetimeName),
3185+
}
3186+
3187+
impl BoundKind {
3188+
fn as_str(&self) -> &'static str {
3189+
match self {
3190+
BoundKind::Trait(_) => "trait",
3191+
BoundKind::Lifetime(_) => "lifetime",
3192+
}
3193+
}
3194+
}
3195+
3196+
impl Bound {
3197+
fn from_generic(bound: &hir::GenericBound<'_>) -> Option<Self> {
3198+
match bound {
3199+
hir::GenericBound::Trait(t, _) => {
3200+
Some(Self { kind: BoundKind::Trait(t.trait_ref.path.res), span: t.span })
3201+
}
3202+
hir::GenericBound::Outlives(lifetime) => {
3203+
Some(Self { kind: BoundKind::Lifetime(lifetime.name), span: lifetime.span })
3204+
}
3205+
_ => None,
31873206
}
31883207
}
31893208
}
31903209

3191-
impl PartialEq for TraitRes {
3210+
impl PartialEq for Bound {
31923211
fn eq(&self, other: &Self) -> bool {
3193-
self.res == other.res
3212+
self.kind == other.kind
31943213
}
31953214
}
31963215

3197-
impl Hash for TraitRes {
3216+
impl Hash for Bound {
31983217
fn hash<H: Hasher>(&self, state: &mut H) {
3199-
self.res.hash(state)
3218+
self.kind.hash(state)
32003219
}
32013220
}
32023221

3203-
impl Eq for TraitRes {}
3222+
impl Eq for Bound {}
32043223

32053224
if gen.span.from_expansion() {
32063225
return;
32073226
}
32083227

3209-
let mut trait_resolutions = FxHashMap::default();
3228+
let mut bounds = FxHashMap::default();
32103229
for param in gen.params {
32113230
if let hir::ParamName::Plain(ref ident) = param.name {
3212-
let mut uniq = FxHashSet::default();
3231+
let mut uniq_bounds = FxHashSet::default();
32133232

3214-
for res in param.bounds.iter().filter_map(TraitRes::from_bound) {
3233+
for res in param.bounds.iter().filter_map(Bound::from_generic) {
32153234
let span = res.span.clone();
3216-
if !uniq.insert(res) {
3235+
let kind = res.kind.as_str();
3236+
if !uniq_bounds.insert(res) {
32173237
cx.struct_span_lint(DUPLICATE_BOUNDS, span, |lint| {
3218-
lint.build("this trait bound has already been specified")
3219-
.help("consider removing this trait bound")
3238+
lint.build(&format!("this {} bound has already been specified", kind))
3239+
.help(&format!("consider removing this {} bound", kind))
32203240
.emit()
32213241
});
32223242
}
32233243
}
32243244

3225-
trait_resolutions.insert(*ident, uniq);
3245+
bounds.insert(*ident, uniq_bounds);
32263246
}
32273247
}
32283248

@@ -3232,16 +3252,19 @@ impl<'tcx> LateLintPass<'tcx> for DuplicateBounds {
32323252
bound_predicate.bounded_ty.kind
32333253
{
32343254
if let Some(segment) = segments.first() {
3235-
if let Some(trait_resolutions) = trait_resolutions.get_mut(&segment.ident) {
3236-
for res in
3237-
bound_predicate.bounds.iter().filter_map(TraitRes::from_bound)
3255+
if let Some(bounds) = bounds.get_mut(&segment.ident) {
3256+
for res in bound_predicate.bounds.iter().filter_map(Bound::from_generic)
32383257
{
32393258
let span = res.span.clone();
3240-
if !trait_resolutions.insert(res) {
3259+
let kind = res.kind.as_str();
3260+
if !bounds.insert(res) {
32413261
cx.struct_span_lint(DUPLICATE_BOUNDS, span, |lint| {
3242-
lint.build("this trait bound has already been specified")
3243-
.help("consider removing this trait bound")
3244-
.emit()
3262+
lint.build(&format!(
3263+
"this {} bound has already been specified",
3264+
kind
3265+
))
3266+
.help(&format!("consider removing this {} bound", kind))
3267+
.emit()
32453268
});
32463269
}
32473270
}

src/test/ui/lint/duplicate_bounds.rs

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ fn not_dup<T: NotDup, U: NotDup>((t, u): (T, U)) {
3131
unimplemented!();
3232
}
3333

34+
fn dup_lifetimes<'a, 'b: 'a + 'a>() {}
35+
//~^ ERROR this lifetime bound has already been specified
36+
37+
fn dup_lifetimes_generic<'a, T: 'a + 'a>() {}
38+
//~^ ERROR this lifetime bound has already been specified
39+
40+
fn dup_lifetimes_where<T: 'static>()
41+
where
42+
T: 'static,
43+
//~^ ERROR this lifetime bound has already been specified
44+
{
45+
}
46+
3447
trait Everything {}
3548
fn everything<T: Everything + Everything, U: Everything + Everything>((t, u): (T, U))
3649
//~^ ERROR this trait bound has already been specified

src/test/ui/lint/duplicate_bounds.stderr

+31-7
Original file line numberDiff line numberDiff line change
@@ -35,53 +35,77 @@ LL | T: DupWhere + DupWhere,
3535
|
3636
= help: consider removing this trait bound
3737

38+
error: this lifetime bound has already been specified
39+
--> $DIR/duplicate_bounds.rs:34:31
40+
|
41+
LL | fn dup_lifetimes<'a, 'b: 'a + 'a>() {}
42+
| ^^
43+
|
44+
= help: consider removing this lifetime bound
45+
46+
error: this lifetime bound has already been specified
47+
--> $DIR/duplicate_bounds.rs:37:38
48+
|
49+
LL | fn dup_lifetimes_generic<'a, T: 'a + 'a>() {}
50+
| ^^
51+
|
52+
= help: consider removing this lifetime bound
53+
54+
error: this lifetime bound has already been specified
55+
--> $DIR/duplicate_bounds.rs:42:8
56+
|
57+
LL | T: 'static,
58+
| ^^^^^^^
59+
|
60+
= help: consider removing this lifetime bound
61+
3862
error: this trait bound has already been specified
39-
--> $DIR/duplicate_bounds.rs:35:31
63+
--> $DIR/duplicate_bounds.rs:48:31
4064
|
4165
LL | fn everything<T: Everything + Everything, U: Everything + Everything>((t, u): (T, U))
4266
| ^^^^^^^^^^
4367
|
4468
= help: consider removing this trait bound
4569

4670
error: this trait bound has already been specified
47-
--> $DIR/duplicate_bounds.rs:35:59
71+
--> $DIR/duplicate_bounds.rs:48:59
4872
|
4973
LL | fn everything<T: Everything + Everything, U: Everything + Everything>((t, u): (T, U))
5074
| ^^^^^^^^^^
5175
|
5276
= help: consider removing this trait bound
5377

5478
error: this trait bound has already been specified
55-
--> $DIR/duplicate_bounds.rs:39:8
79+
--> $DIR/duplicate_bounds.rs:52:8
5680
|
5781
LL | T: Everything + Everything + Everything,
5882
| ^^^^^^^^^^
5983
|
6084
= help: consider removing this trait bound
6185

6286
error: this trait bound has already been specified
63-
--> $DIR/duplicate_bounds.rs:39:21
87+
--> $DIR/duplicate_bounds.rs:52:21
6488
|
6589
LL | T: Everything + Everything + Everything,
6690
| ^^^^^^^^^^
6791
|
6892
= help: consider removing this trait bound
6993

7094
error: this trait bound has already been specified
71-
--> $DIR/duplicate_bounds.rs:39:34
95+
--> $DIR/duplicate_bounds.rs:52:34
7296
|
7397
LL | T: Everything + Everything + Everything,
7498
| ^^^^^^^^^^
7599
|
76100
= help: consider removing this trait bound
77101

78102
error: this trait bound has already been specified
79-
--> $DIR/duplicate_bounds.rs:43:8
103+
--> $DIR/duplicate_bounds.rs:56:8
80104
|
81105
LL | U: Everything,
82106
| ^^^^^^^^^^
83107
|
84108
= help: consider removing this trait bound
85109

86-
error: aborting due to 10 previous errors
110+
error: aborting due to 13 previous errors
87111

0 commit comments

Comments
 (0)