Rollup merge of #76695 - iximeow:trait-generic-bound-suggestion, r=estebank
fix syntax error in suggesting generic constraint in trait parameter suggest `where T: Foo` for the first bound on a trait, then suggest `, T: Foo` when the suggested bound would add to an existing set of `where` clauses. `where T: Foo` may be the first bound if `T` has a default, because we'd rather suggest ``` trait A<T=()> where T: Copy ``` than ``` trait A<T: Copy=()> ``` for legibility reasons. the test case i added here is derived from [this reproduction](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=0bf3ace9f2a183d0bdbd748c6b8e3971): ``` struct B<T: Copy> { t: T } trait A<T = ()> { fn returns_constrained_type(&self, t: T) -> B<T> { B { t } } } ``` where the suggested fix, ``` trait A<T = ()>, T: Copy { ... } ``` is in fact invalid syntax! i also found an error in the existing suggestion for `trait Base<T = String>: Super<T>` where rustc would suggest `trait Base<T = String>: Super<T>, T: Copy`, but `T: Copy` is the first of the trait's `where` clauses and should be `where T: Copy` as well. the test for that suggestion expects invalid syntax, and has been revised to a compiler-pleasing `trait Base<T = String>: Super<T> where T: Copy`. judging by https://github.com/rust-lang/rust/pull/70009 i'll.. cc @estebank ?
This commit is contained in:
commit
54d77285fc
5 changed files with 105 additions and 22 deletions
|
@ -202,12 +202,37 @@ pub fn suggest_constraining_type_param(
|
||||||
// Suggestion:
|
// Suggestion:
|
||||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
||||||
// - insert: `, T: Zar`
|
// - insert: `, T: Zar`
|
||||||
|
//
|
||||||
|
// Additionally, there may be no `where` clause whatsoever in the case that this was
|
||||||
|
// reached because the generic parameter has a default:
|
||||||
|
//
|
||||||
|
// Message:
|
||||||
|
// trait Foo<T=()> {... }
|
||||||
|
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||||
|
//
|
||||||
|
// Suggestion:
|
||||||
|
// trait Foo<T=()> where T: Zar {... }
|
||||||
|
// - insert: `where T: Zar`
|
||||||
|
|
||||||
|
if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||||
|
&& generics.where_clause.predicates.len() == 0
|
||||||
|
{
|
||||||
|
// Suggest a bound, but there is no existing `where` clause *and* the type param has a
|
||||||
|
// default (`<T=Foo>`), so we suggest adding `where T: Bar`.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
generics.where_clause.tail_span_for_suggestion(),
|
||||||
|
&msg_restrict_type_further,
|
||||||
|
format!(" where {}: {}", param_name, constraint),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
let mut param_spans = Vec::new();
|
let mut param_spans = Vec::new();
|
||||||
|
|
||||||
for predicate in generics.where_clause.predicates {
|
for predicate in generics.where_clause.predicates {
|
||||||
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
|
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||||
span, bounded_ty, ..
|
span,
|
||||||
|
bounded_ty,
|
||||||
|
..
|
||||||
}) = predicate
|
}) = predicate
|
||||||
{
|
{
|
||||||
if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
|
if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
|
||||||
|
@ -231,6 +256,7 @@ pub fn suggest_constraining_type_param(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
20
src/test/ui/trait-impl-bound-suggestions.fixed
Normal file
20
src/test/ui/trait-impl-bound-suggestions.fixed
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
use std::fmt::Debug;
|
||||||
|
// Rustfix should add this, or use `std::fmt::Debug` instead.
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct ConstrainedStruct<X: Copy> {
|
||||||
|
x: X
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
|
||||||
|
fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
|
||||||
|
//~^ ERROR the trait bound `X: Copy` is not satisfied
|
||||||
|
ConstrainedStruct { x }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() { }
|
20
src/test/ui/trait-impl-bound-suggestions.rs
Normal file
20
src/test/ui/trait-impl-bound-suggestions.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
use std::fmt::Debug;
|
||||||
|
// Rustfix should add this, or use `std::fmt::Debug` instead.
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct ConstrainedStruct<X: Copy> {
|
||||||
|
x: X
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
trait InsufficientlyConstrainedGeneric<X=()> {
|
||||||
|
fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
|
||||||
|
//~^ ERROR the trait bound `X: Copy` is not satisfied
|
||||||
|
ConstrainedStruct { x }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() { }
|
17
src/test/ui/trait-impl-bound-suggestions.stderr
Normal file
17
src/test/ui/trait-impl-bound-suggestions.stderr
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
error[E0277]: the trait bound `X: Copy` is not satisfied
|
||||||
|
--> $DIR/trait-impl-bound-suggestions.rs:14:52
|
||||||
|
|
|
||||||
|
LL | struct ConstrainedStruct<X: Copy> {
|
||||||
|
| ---- required by this bound in `ConstrainedStruct`
|
||||||
|
...
|
||||||
|
LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X`
|
||||||
|
|
|
||||||
|
help: consider further restricting type parameter `X`
|
||||||
|
|
|
||||||
|
LL | trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -56,8 +56,8 @@ LL | trait Base<T = String>: Super<T> { }
|
||||||
|
|
|
|
||||||
help: consider further restricting type parameter `T`
|
help: consider further restricting type parameter `T`
|
||||||
|
|
|
|
||||||
LL | trait Base<T = String>: Super<T>, T: Copy { }
|
LL | trait Base<T = String>: Super<T> where T: Copy { }
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: cannot add `u8` to `i32`
|
error[E0277]: cannot add `u8` to `i32`
|
||||||
--> $DIR/type-check-defaults.rs:24:66
|
--> $DIR/type-check-defaults.rs:24:66
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue