]> git.lizzy.rs Git - rust.git/commitdiff
fix syntax error in suggesting generic constraint in trait parameter
authoriximeow <me@iximeow.net>
Mon, 14 Sep 2020 03:55:06 +0000 (20:55 -0700)
committeriximeow <me@iximeow.net>
Mon, 14 Sep 2020 04:24:34 +0000 (21:24 -0700)
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.

compiler/rustc_middle/src/ty/diagnostics.rs
src/test/ui/trait-impl-bound-suggestions.fixed [new file with mode: 0644]
src/test/ui/trait-impl-bound-suggestions.rs [new file with mode: 0644]
src/test/ui/trait-impl-bound-suggestions.stderr [new file with mode: 0644]
src/test/ui/type/type-check-defaults.stderr

index bc51c8b6cd41c6e1b3f9054678d9987d29f7d471..0416ef9e643873c93d7caa58a97f23f4d7c4d76a 100644 (file)
@@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param(
         //    Suggestion:
         //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
         //                                          - insert: `, T: Zar`
+        //
+        // Additionally, there may be no `where` clause whatsoever in the case that this was
+        // reached becauase 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`
 
-        let mut param_spans = Vec::new();
+        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
+            && generics.where_clause.predicates.len() == 0
+        {
+            // Suggest a bound, but there are no existing where clauses for this `<T=Foo>`, so
+            // suggest adding one.
+            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();
 
-        for predicate in generics.where_clause.predicates {
-            if let WherePredicate::BoundPredicate(WhereBoundPredicate {
-                span, bounded_ty, ..
-            }) = predicate
-            {
-                if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
-                    if let Some(segment) = path.segments.first() {
-                        if segment.ident.to_string() == param_name {
-                            param_spans.push(span);
+            for predicate in generics.where_clause.predicates {
+                if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+                    span,
+                    bounded_ty,
+                    ..
+                }) = predicate
+                {
+                    if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
+                        if let Some(segment) = path.segments.first() {
+                            if segment.ident.to_string() == param_name {
+                                param_spans.push(span);
+                            }
                         }
                     }
                 }
             }
-        }
 
-        match &param_spans[..] {
-            &[&param_span] => suggest_restrict(param_span.shrink_to_hi()),
-            _ => {
-                err.span_suggestion_verbose(
-                    generics.where_clause.tail_span_for_suggestion(),
-                    &msg_restrict_type_further,
-                    format!(", {}: {}", param_name, constraint),
-                    Applicability::MachineApplicable,
-                );
+            match &param_spans[..] {
+                &[&param_span] => suggest_restrict(param_span.shrink_to_hi()),
+                _ => {
+                    err.span_suggestion_verbose(
+                        generics.where_clause.tail_span_for_suggestion(),
+                        &msg_restrict_type_further,
+                        format!(", {}: {}", param_name, constraint),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
         }
 
diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed
new file mode 100644 (file)
index 0000000..db3a95f
--- /dev/null
@@ -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() { }
diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs
new file mode 100644 (file)
index 0000000..bf75175
--- /dev/null
@@ -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() { }
diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr
new file mode 100644 (file)
index 0000000..3a21e9c
--- /dev/null
@@ -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`.
index fa6f342241025b9e2a7cab7108a9039652a54972..d8c7f595e62efcdf03555cd975d71761e7a7e586 100644 (file)
@@ -56,8 +56,8 @@ LL | trait Base<T = String>: Super<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`
   --> $DIR/type-check-defaults.rs:24:66