]> git.lizzy.rs Git - rust.git/commitdiff
Better error
authorjackh726 <jack.huey@umassmed.edu>
Sat, 16 Oct 2021 15:50:56 +0000 (11:50 -0400)
committerjackh726 <jack.huey@umassmed.edu>
Sat, 16 Oct 2021 23:04:39 +0000 (19:04 -0400)
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/lib.rs
src/test/ui/generic-associated-types/self-outlives-lint.rs
src/test/ui/generic-associated-types/self-outlives-lint.stderr

index dc9784594c21ba7544ba3538fb93028cfa96a0ce..0ab9855d3250ad2aa5e0f5759895e89b0ea9707e 100644 (file)
@@ -288,7 +288,6 @@ fn check_gat_where_clauses(
         associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
     {
         let id = hir::HirId::make_owner(item.def_id.expect_local());
-        let span = DUMMY_SP;
         let param_env = tcx.param_env(item.def_id.expect_local());
 
         let sig = tcx.fn_sig(item.def_id);
@@ -308,7 +307,7 @@ fn check_gat_where_clauses(
             for (ty, ty_idx) in &visitor.types {
                 tcx.infer_ctxt().enter(|infcx| {
                     let mut outlives_environment = OutlivesEnvironment::new(param_env);
-                    outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, span);
+                    outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
                     outlives_environment.save_implied_bounds(id);
                     let region_bound_pairs =
                         outlives_environment.region_bound_pairs_map().get(&id).unwrap();
@@ -349,7 +348,6 @@ fn check_gat_where_clauses(
                             name: ty_param.name,
                         }));
                         let region_param = generics.param_at(*region_idx, tcx);
-                        // Then create a clause that is required on the GAT
                         let region_param =
                             tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
                                 def_id: region_param.def_id,
@@ -372,13 +370,35 @@ fn check_gat_where_clauses(
     debug!(?clauses);
     if !clauses.is_empty() {
         let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
-        for clause in clauses {
-            let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
-            debug!(?clause, ?found);
-            let mut error = tcx
-                .sess
-                .struct_span_err(trait_item.generics.span, &format!("Missing bound: {}", clause));
-            error.emit();
+        let clauses: Vec<_> = clauses
+            .drain_filter(|clause| {
+                written_predicates.predicates.iter().find(|p| &p.0 == clause).is_none()
+            })
+            .map(|clause| format!("{}", clause))
+            .collect();
+        if !clauses.is_empty() {
+            let mut err = tcx.sess.struct_span_err(
+                trait_item.span,
+                &format!("Missing required bounds on {}", trait_item.ident),
+            );
+
+            let suggestion = format!(
+                "{} {}",
+                if !trait_item.generics.where_clause.predicates.is_empty() {
+                    ","
+                } else {
+                    " where"
+                },
+                clauses.join(", "),
+            );
+            err.span_suggestion(
+                trait_item.generics.where_clause.tail_span_for_suggestion(),
+                "add the required where clauses",
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+
+            err.emit()
         }
     }
 }
index 971776c882a157e4946fbe714bb2a54cafb375fd..50afdc23631b9d4874d24ffb1fb5e043f53c18f4 100644 (file)
@@ -69,6 +69,7 @@
 #![feature(never_type)]
 #![feature(slice_partition_dedup)]
 #![feature(control_flow_enum)]
+#![feature(hash_drain_filter)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 7a1fb51eafa0a3bfbc079d7e343d8ce055a75aba..76273c5249ec19c000dbe55adf50c915c6cb64df 100644 (file)
@@ -2,9 +2,10 @@
 
 // check-fail
 
+// We have a `&'a self`, so we need a `Self: 'a`
 trait Iterable {
     type Item<'x>;
-    //~^ Missing bound
+    //~^ Missing required bounds
     fn iter<'a>(&'a self) -> Self::Item<'a>;
 }
 
@@ -17,9 +18,10 @@ fn iter<'a>(&'a self) -> Self::Item<'a> {
 }
 */
 
+// We have a `&'a T`, so we need a `T: 'x`
 trait Deserializer<T> {
     type Out<'x>;
-    //~^ Missing bound
+    //~^ Missing required bounds
     fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
 }
 
@@ -30,19 +32,21 @@ fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
 }
 */
 
+// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
 trait Deserializer2<T> {
     type Out<'x>;
-    //~^ Missing bound
-    fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
+    //~^ Missing required bounds
+    fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
 }
 
+// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
 trait Deserializer3<T, U> {
     type Out<'x, 'y>;
-    //~^ Missing bound
-    //~^^ Missing bound
+    //~^ Missing required bounds
     fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
 }
 
+// `T` is a param on the function, so it can't be named by the associated type
 trait Deserializer4 {
     type Out<'x>;
     fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
@@ -50,36 +54,41 @@ trait Deserializer4 {
 
 struct Wrap<T>(T);
 
+// Even though we might theoretically want `D: 'x`, because we pass `Wrap<T>` and
+// we see `&'z Wrap<T>`, we are conservative and only add bounds for direct params
 trait Des {
     type Out<'x, D>;
     fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
 }
 /*
 impl Des for () {
-    type Out<'x, D> = &'x D;
+    type Out<'x, D> = &'x D; // Not okay
     fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> {
         data
     }
 }
 */
 
+// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an
+// implied bound that `T: 'z`, so we require `D: 'x`
 trait Des2 {
     type Out<'x, D>;
-    //~^ Missing bound
+    //~^ Missing required bounds
     fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
 }
 /*
 impl Des2 for () {
     type Out<'x, D> = &'x D;
     fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> {
-        data
+        &data.0
     }
 }
 */
 
+// We see `&'z T`, so we require `D: 'x`
 trait Des3 {
     type Out<'x, D>;
-    //~^ Missing bound
+    //~^ Missing required bounds
     fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
 }
 /*
index 42af6d25a2380787b0e12245943c03cca9526bf7..077c64421a8ce30b3e0c5d35c4099376ff637eda 100644 (file)
@@ -1,44 +1,50 @@
-error: Missing bound: Self: 'x
-  --> $DIR/self-outlives-lint.rs:6:14
+error: Missing required bounds on Item
+  --> $DIR/self-outlives-lint.rs:7:5
    |
 LL |     type Item<'x>;
-   |              ^^^^
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clauses: `where Self: 'x`
 
-error: Missing bound: T: 'x
-  --> $DIR/self-outlives-lint.rs:21:13
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:23:5
    |
 LL |     type Out<'x>;
-   |             ^^^^
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where T: 'x`
 
-error: Missing bound: T: 'x
-  --> $DIR/self-outlives-lint.rs:34:13
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:37:5
    |
 LL |     type Out<'x>;
-   |             ^^^^
+   |     ^^^^^^^^^^^^-
+   |                 |
+   |                 help: add the required where clauses: `where T: 'x`
 
-error: Missing bound: U: 'y
-  --> $DIR/self-outlives-lint.rs:40:13
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:44:5
    |
 LL |     type Out<'x, 'y>;
-   |             ^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^-
+   |                     |
+   |                     help: add the required where clauses: `where U: 'y, T: 'x`
 
-error: Missing bound: T: 'x
-  --> $DIR/self-outlives-lint.rs:40:13
-   |
-LL |     type Out<'x, 'y>;
-   |             ^^^^^^^^
-
-error: Missing bound: D: 'x
-  --> $DIR/self-outlives-lint.rs:67:13
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:75:5
    |
 LL |     type Out<'x, D>;
-   |             ^^^^^^^
+   |     ^^^^^^^^^^^^^^^-
+   |                    |
+   |                    help: add the required where clauses: `where D: 'x`
 
-error: Missing bound: D: 'x
-  --> $DIR/self-outlives-lint.rs:81:13
+error: Missing required bounds on Out
+  --> $DIR/self-outlives-lint.rs:90:5
    |
 LL |     type Out<'x, D>;
-   |             ^^^^^^^
+   |     ^^^^^^^^^^^^^^^-
+   |                    |
+   |                    help: add the required where clauses: `where D: 'x`
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors