Skip to content

Commit 750db09

Browse files
committed
Auto merge of rust-lang#71451 - estebank:suggest-super-trait-constraint, r=nikomatsakis
Suggest adding super trait constraints
2 parents a2e0b48 + 58797b0 commit 750db09

34 files changed

+282
-100
lines changed

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+56-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
1515
self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
1616
TyCtxt, TypeFoldable, WithConstness,
1717
};
18-
use rustc_span::symbol::{kw, sym, Symbol};
18+
use rustc_span::symbol::{kw, sym, Ident, Symbol};
1919
use rustc_span::{MultiSpan, Span, DUMMY_SP};
2020
use std::fmt;
2121

@@ -156,7 +156,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St
156156
(
157157
generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
158158
format!(
159-
"{} {} ",
159+
"{} {}",
160160
if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
161161
pred,
162162
),
@@ -173,7 +173,13 @@ fn suggest_restriction(
173173
fn_sig: Option<&hir::FnSig<'_>>,
174174
projection: Option<&ty::ProjectionTy<'_>>,
175175
trait_ref: ty::PolyTraitRef<'_>,
176+
super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
176177
) {
178+
// When we are dealing with a trait, `super_traits` will be `Some`:
179+
// Given `trait T: A + B + C {}`
180+
// - ^^^^^^^^^ GenericBounds
181+
// |
182+
// &Ident
177183
let span = generics.where_clause.span_for_predicates_or_empty_place();
178184
if span.from_expansion() || span.desugaring_kind().is_some() {
179185
return;
@@ -262,10 +268,28 @@ fn suggest_restriction(
262268
);
263269
} else {
264270
// Trivial case: `T` needs an extra bound: `T: Bound`.
265-
let (sp, sugg) =
266-
predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string());
267-
let appl = Applicability::MachineApplicable;
268-
err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl);
271+
let (sp, suggestion) = match super_traits {
272+
None => {
273+
predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string())
274+
}
275+
Some((ident, bounds)) => match bounds {
276+
[.., bound] => (
277+
bound.span().shrink_to_hi(),
278+
format!(" + {}", trait_ref.print_only_trait_path().to_string()),
279+
),
280+
[] => (
281+
ident.span.shrink_to_hi(),
282+
format!(": {}", trait_ref.print_only_trait_path().to_string()),
283+
),
284+
},
285+
};
286+
287+
err.span_suggestion_verbose(
288+
sp,
289+
&format!("consider further restricting {}", msg),
290+
suggestion,
291+
Applicability::MachineApplicable,
292+
);
269293
}
270294
}
271295

@@ -288,13 +312,35 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
288312
let mut hir_id = body_id;
289313
while let Some(node) = self.tcx.hir().find(hir_id) {
290314
match node {
315+
hir::Node::Item(hir::Item {
316+
ident,
317+
kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
318+
..
319+
}) if self_ty == self.tcx.types.self_param => {
320+
assert!(param_ty);
321+
// Restricting `Self` for a single method.
322+
suggest_restriction(
323+
&generics,
324+
"`Self`",
325+
err,
326+
None,
327+
projection,
328+
trait_ref,
329+
Some((ident, bounds)),
330+
);
331+
return;
332+
}
333+
291334
hir::Node::TraitItem(hir::TraitItem {
292335
generics,
293336
kind: hir::TraitItemKind::Fn(..),
294337
..
295-
}) if param_ty && self_ty == self.tcx.types.self_param => {
338+
}) if self_ty == self.tcx.types.self_param => {
339+
assert!(param_ty);
296340
// Restricting `Self` for a single method.
297-
suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref);
341+
suggest_restriction(
342+
&generics, "`Self`", err, None, projection, trait_ref, None,
343+
);
298344
return;
299345
}
300346

@@ -319,6 +365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
319365
Some(fn_sig),
320366
projection,
321367
trait_ref,
368+
None,
322369
);
323370
return;
324371
}
@@ -336,6 +383,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
336383
None,
337384
projection,
338385
trait_ref,
386+
None,
339387
);
340388
return;
341389
}

src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr

+15-9
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterato
1616
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
1717
|
1818
LL | fn assume_case1<T: Case1>() {
19-
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator`
20-
| |
21-
| `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
19+
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
2220
|
2321
= help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
22+
help: consider further restricting the associated type
23+
|
24+
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator {
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2426

2527
error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
2628
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
@@ -32,11 +34,13 @@ LL | Send + Iterator<Item:
3234
| ---- required by this bound in `Case1`
3335
...
3436
LL | fn assume_case1<T: Case1>() {
35-
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send`
36-
| |
37-
| `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
37+
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
3838
|
3939
= help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
40+
help: consider further restricting the associated type
41+
|
42+
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send {
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4044

4145
error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
4246
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20
@@ -48,11 +52,13 @@ LL | > + Sync>;
4852
| ---- required by this bound in `Case1`
4953
...
5054
LL | fn assume_case1<T: Case1>() {
51-
| ^^^^^ - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync`
52-
| |
53-
| `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
55+
| ^^^^^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
5456
|
5557
= help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
58+
help: consider further restricting the associated type
59+
|
60+
LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync {
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5662

5763
error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
5864
--> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20

src/test/ui/associated-types/associated-types-bound-failure.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub trait GetToInt
1414
}
1515

1616
fn foo<G>(g: G) -> isize
17-
where G : GetToInt, <G as GetToInt>::R: ToInt
17+
where G : GetToInt, <G as GetToInt>::R: ToInt
1818
{
1919
ToInt::to_int(&g.get()) //~ ERROR E0277
2020
}

src/test/ui/associated-types/associated-types-bound-failure.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
44
LL | fn to_int(&self) -> isize;
55
| -------------------------- required by `ToInt::to_int`
66
...
7-
LL | where G : GetToInt
8-
| - help: consider further restricting the associated type: `, <G as GetToInt>::R: ToInt`
9-
LL | {
107
LL | ToInt::to_int(&g.get())
118
| ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
9+
|
10+
help: consider further restricting the associated type
11+
|
12+
LL | where G : GetToInt, <G as GetToInt>::R: ToInt
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
1214

1315
error: aborting due to previous error
1416

src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait Get {
77
}
88

99
trait Other {
10-
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
10+
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
1111
//~^ ERROR the trait bound `Self: Get` is not satisfied
1212
}
1313

src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
22
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
6-
| | |
7-
| | help: consider further restricting `Self`: `where Self: Get`
8-
| the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
10+
| ^^^^^^^^^^^^^^^
911

1012
error: aborting due to previous error
1113

src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
22
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
6-
| | |
7-
| | help: consider further restricting `Self`: `where Self: Get`
8-
| the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
10+
| ^^^^^^^^^^^^^^^
911

1012
error: aborting due to previous error
1113

src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
22
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
33
|
44
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
6-
| | |
7-
| | help: consider further restricting `Self`: `where Self: Get`
8-
| the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {}
10+
| ^^^^^^^^^^^^^^^
911

1012
error[E0277]: the trait bound `(T, U): Get` is not satisfied
1113
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5

src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait Get {
77
}
88

99
trait Other {
10-
fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get ;
10+
fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
1111
//~^ ERROR E0277
1212
}
1313

src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
22
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
33
|
44
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
6-
| | |
7-
| | help: consider further restricting `Self`: `where Self: Get`
8-
| the trait `Get` is not implemented for `Self`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
6+
|
7+
help: consider further restricting `Self`
8+
|
9+
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get;
10+
| ^^^^^^^^^^^^^^^
911

1012
error: aborting due to previous error
1113

src/test/ui/associated-types/associated-types-unsized.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ trait Get {
66
fn get(&self) -> <Self as Get>::Value;
77
}
88

9-
fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
9+
fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
1010
let x = t.get(); //~ ERROR the size for values of type
1111
}
1212

src/test/ui/associated-types/associated-types-unsized.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
22
--> $DIR/associated-types-unsized.rs:10:9
33
|
4-
LL | fn foo<T:Get>(t: T) {
5-
| - help: consider further restricting the associated type: `where <T as Get>::Value: std::marker::Sized`
64
LL | let x = t.get();
75
| ^ doesn't have a size known at compile-time
86
|
97
= help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
108
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
119
= note: all local variables must have a statically known size
1210
= help: unsized locals are gated as an unstable feature
11+
help: consider further restricting the associated type
12+
|
13+
LL | fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized {
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1315

1416
error: aborting due to previous error
1517

src/test/ui/associated-types/defaults-suitability.stderr

+10-6
Original file line numberDiff line numberDiff line change
@@ -85,25 +85,29 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not
8585
--> $DIR/defaults-suitability.rs:72:15
8686
|
8787
LL | trait Foo2<T> {
88-
| -------------- help: consider further restricting the associated type: `where <Self as Foo2<T>>::Baz: std::clone::Clone`
89-
| |
90-
| required by `Foo2`
88+
| ------------- required by `Foo2`
9189
LL | type Bar: Clone = Vec<Self::Baz>;
9290
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
9391
|
9492
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo2<T>>::Baz>`
93+
help: consider further restricting the associated type
94+
|
95+
LL | trait Foo2<T> where <Self as Foo2<T>>::Baz: std::clone::Clone {
96+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9597

9698
error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: std::clone::Clone` is not satisfied
9799
--> $DIR/defaults-suitability.rs:81:15
98100
|
99101
LL | trait Foo25<T: Clone> {
100-
| ---------------------- help: consider further restricting the associated type: `where <Self as Foo25<T>>::Baz: std::clone::Clone`
101-
| |
102-
| required by `Foo25`
102+
| --------------------- required by `Foo25`
103103
LL | type Bar: Clone = Vec<Self::Baz>;
104104
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo25<T>>::Baz`
105105
|
106106
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo25<T>>::Baz>`
107+
help: consider further restricting the associated type
108+
|
109+
LL | trait Foo25<T: Clone> where <Self as Foo25<T>>::Baz: std::clone::Clone {
110+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107111

108112
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
109113
--> $DIR/defaults-suitability.rs:90:16

src/test/ui/associated-types/defaults-unsound-62211-1.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | trait UncheckedCopy: Sized {
66
...
77
LL | type Output: Copy
88
| ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
9+
|
10+
help: consider further restricting `Self`
11+
|
12+
LL | trait UncheckedCopy: Sized + std::marker::Copy {
13+
| ^^^^^^^^^^^^^^^^^^^
914

1015
error[E0277]: cannot add-assign `&'static str` to `Self`
1116
--> $DIR/defaults-unsound-62211-1.rs:25:7
@@ -17,6 +22,10 @@ LL | + AddAssign<&'static str>
1722
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
1823
|
1924
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
25+
help: consider further restricting `Self`
26+
|
27+
LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2029

2130
error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
2231
--> $DIR/defaults-unsound-62211-1.rs:23:7
@@ -26,6 +35,11 @@ LL | trait UncheckedCopy: Sized {
2635
...
2736
LL | + Deref<Target = str>
2837
| ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
38+
|
39+
help: consider further restricting `Self`
40+
|
41+
LL | trait UncheckedCopy: Sized + std::ops::Deref {
42+
| ^^^^^^^^^^^^^^^^^
2943

3044
error[E0277]: `Self` doesn't implement `std::fmt::Display`
3145
--> $DIR/defaults-unsound-62211-1.rs:28:7
@@ -38,6 +52,10 @@ LL | + Display = Self;
3852
|
3953
= help: the trait `std::fmt::Display` is not implemented for `Self`
4054
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
55+
help: consider further restricting `Self`
56+
|
57+
LL | trait UncheckedCopy: Sized + std::fmt::Display {
58+
| ^^^^^^^^^^^^^^^^^^^
4159

4260
error[E0277]: `T` doesn't implement `std::fmt::Display`
4361
--> $DIR/defaults-unsound-62211-1.rs:41:9

0 commit comments

Comments
 (0)