about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-04-30 15:38:24 +0000
committerMichael Goulet <michael@errs.io>2025-05-07 17:13:39 +0000
commitb27d630f8958374bc774bc183105ee23f5320a3a (patch)
tree6cdc35943104164c00ad1f6098d6b6dc8b3b19f4
parent3ef8e64ce9f72ee8d600d55bc43b36eed069b252 (diff)
downloadrust-b27d630f8958374bc774bc183105ee23f5320a3a.tar.gz
rust-b27d630f8958374bc774bc183105ee23f5320a3a.zip
Point out region bound mismatches in check_region_bounds_on_impl_item
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs109
-rw-r--r--tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr11
-rw-r--r--tests/ui/error-codes/E0195.rs1
-rw-r--r--tests/ui/error-codes/E0195.stderr5
4 files changed, 80 insertions, 46 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index bbf36fef1dd..553d981aa38 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1137,65 +1137,88 @@ fn check_region_bounds_on_impl_item<'tcx>(
     // but found 0" it's confusing, because it looks like there
     // are zero. Since I don't quite know how to phrase things at
     // the moment, give a kind of vague error message.
-    if trait_params != impl_params {
-        let span = tcx
-            .hir_get_generics(impl_m.def_id.expect_local())
-            .expect("expected impl item to have generics or else we can't compare them")
-            .span;
-
-        let mut generics_span = None;
-        let mut bounds_span = vec![];
-        let mut where_span = None;
-        if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
-            && let Some(trait_generics) = trait_node.generics()
-        {
-            generics_span = Some(trait_generics.span);
-            // FIXME: we could potentially look at the impl's bounds to not point at bounds that
-            // *are* present in the impl.
-            for p in trait_generics.predicates {
-                if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
-                    for b in pred.bounds {
+    if trait_params == impl_params {
+        return Ok(());
+    }
+
+    let span = tcx
+        .hir_get_generics(impl_m.def_id.expect_local())
+        .expect("expected impl item to have generics or else we can't compare them")
+        .span;
+
+    let mut generics_span = None;
+    let mut bounds_span = vec![];
+    let mut where_span = None;
+
+    if let Some(trait_node) = tcx.hir_get_if_local(trait_m.def_id)
+        && let Some(trait_generics) = trait_node.generics()
+    {
+        generics_span = Some(trait_generics.span);
+        // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+        // *are* present in the impl.
+        for p in trait_generics.predicates {
+            match p.kind {
+                hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                    bounds,
+                    ..
+                })
+                | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
+                    bounds,
+                    ..
+                }) => {
+                    for b in *bounds {
                         if let hir::GenericBound::Outlives(lt) = b {
                             bounds_span.push(lt.ident.span);
                         }
                     }
                 }
+                _ => {}
             }
-            if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
-                && let Some(impl_generics) = impl_node.generics()
-            {
-                let mut impl_bounds = 0;
-                for p in impl_generics.predicates {
-                    if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
-                        for b in pred.bounds {
+        }
+        if let Some(impl_node) = tcx.hir_get_if_local(impl_m.def_id)
+            && let Some(impl_generics) = impl_node.generics()
+        {
+            let mut impl_bounds = 0;
+            for p in impl_generics.predicates {
+                match p.kind {
+                    hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
+                        bounds,
+                        ..
+                    })
+                    | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
+                        bounds,
+                        ..
+                    }) => {
+                        for b in *bounds {
                             if let hir::GenericBound::Outlives(_) = b {
                                 impl_bounds += 1;
                             }
                         }
                     }
-                }
-                if impl_bounds == bounds_span.len() {
-                    bounds_span = vec![];
-                } else if impl_generics.has_where_clause_predicates {
-                    where_span = Some(impl_generics.where_clause_span);
+                    _ => {}
                 }
             }
+            if impl_bounds == bounds_span.len() {
+                bounds_span = vec![];
+            } else if impl_generics.has_where_clause_predicates {
+                where_span = Some(impl_generics.where_clause_span);
+            }
         }
-        let reported = tcx
-            .dcx()
-            .create_err(LifetimesOrBoundsMismatchOnTrait {
-                span,
-                item_kind: impl_m.descr(),
-                ident: impl_m.ident(tcx),
-                generics_span,
-                bounds_span,
-                where_span,
-            })
-            .emit_unless(delay);
-        return Err(reported);
     }
 
-    Ok(())
+    let reported = tcx
+        .dcx()
+        .create_err(LifetimesOrBoundsMismatchOnTrait {
+            span,
+            item_kind: impl_m.descr(),
+            ident: impl_m.ident(tcx),
+            generics_span,
+            bounds_span,
+            where_span,
+        })
+        .emit_unless(delay);
+
+    Err(reported)
 }
 
 #[instrument(level = "debug", skip(infcx))]
diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
index 5f0347bdb4d..2afacd4cc95 100644
--- a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
+++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
@@ -11,7 +11,10 @@ error[E0195]: lifetime parameters or bounds on method `has_bound` do not match t
   --> $DIR/regions-bound-missing-bound-in-impl.rs:23:17
    |
 LL |     fn has_bound<'b:'a>(self, b: Inv<'b>);
-   |                 ------- lifetimes in impl do not match this method in trait
+   |                 -------
+   |                 |   |
+   |                 |   this bound might be missing in the impl
+   |                 lifetimes in impl do not match this method in trait
 ...
 LL |     fn has_bound<'b>(self, b: Inv<'b>) {
    |                 ^^^^ lifetimes do not match method in trait
@@ -58,7 +61,11 @@ error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not matc
   --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20
    |
 LL |     fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
-   |                    ---------------- lifetimes in impl do not match this method in trait
+   |                    ----------------
+   |                    |         |  |
+   |                    |         |  this bound might be missing in the impl
+   |                    |         this bound might be missing in the impl
+   |                    lifetimes in impl do not match this method in trait
 ...
 LL |     fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
    |                    ^ lifetimes do not match method in trait
diff --git a/tests/ui/error-codes/E0195.rs b/tests/ui/error-codes/E0195.rs
index a7e51dff2f3..8280901b1cd 100644
--- a/tests/ui/error-codes/E0195.rs
+++ b/tests/ui/error-codes/E0195.rs
@@ -8,6 +8,7 @@ struct Foo;
 impl Trait for Foo {
     fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
     //~^ NOTE lifetimes do not match associated function in trait
+    //~| NOTE this bound might be missing in the impl
     }
 }
 
diff --git a/tests/ui/error-codes/E0195.stderr b/tests/ui/error-codes/E0195.stderr
index 9767dee9aec..6eac910bedf 100644
--- a/tests/ui/error-codes/E0195.stderr
+++ b/tests/ui/error-codes/E0195.stderr
@@ -2,7 +2,10 @@ error[E0195]: lifetime parameters or bounds on associated function `bar` do not
   --> $DIR/E0195.rs:9:11
    |
 LL |     fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
-   |           ---------- lifetimes in impl do not match this associated function in trait
+   |           ----------
+   |           |      |
+   |           |      this bound might be missing in the impl
+   |           lifetimes in impl do not match this associated function in trait
 ...
 LL |     fn bar<'a,'b>(x: &'a str, y: &'b str) {
    |           ^^^^^^^ lifetimes do not match associated function in trait