diff options
| author | Michael Goulet <michael@errs.io> | 2025-04-30 15:38:24 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2025-05-07 17:13:39 +0000 |
| commit | b27d630f8958374bc774bc183105ee23f5320a3a (patch) | |
| tree | 6cdc35943104164c00ad1f6098d6b6dc8b3b19f4 | |
| parent | 3ef8e64ce9f72ee8d600d55bc43b36eed069b252 (diff) | |
| download | rust-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.rs | 109 | ||||
| -rw-r--r-- | tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr | 11 | ||||
| -rw-r--r-- | tests/ui/error-codes/E0195.rs | 1 | ||||
| -rw-r--r-- | tests/ui/error-codes/E0195.stderr | 5 |
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 |
