Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #17916 - ShoyuVanilla:issue-17711, r=Veykril
fix: Wrong BoundVar index when lowering impl trait parameter of parent generics
Fixes #17711
From the following test code;
```rust
//- minicore: deref
use core::ops::Deref;
struct Struct<'a, T>(&'a T);
trait Trait {}
impl<'a, T: Deref<Target = impl Trait>> Struct<'a, T> {
fn foo(&self) -> &Self { self }
fn bar(&self) {
let _ = self.foo();
}
}
```
when we call `register_obligations_for_call` for `let _ = self.foo();`,
https://github.com/rust-lang/rust-analyzer/blob/07659783fdfd4ec0a0bffa93017e33e31e567e42/crates/hir-ty/src/infer/expr.rs#L1939-L1952
we are querying `generic_predicates` and it has `T: Deref<Target = impl Trait>` predicate from the parent `impl Struct`;
https://github.com/rust-lang/rust-analyzer/blob/07659783fdfd4ec0a0bffa93017e33e31e567e42/crates/hir-ty/src/lower.rs#L375-L399
but as we can see above, lowering `TypeRef = impl Trait` doesn't take into account the parent generic parameters, so the `BoundVar` index here is `0`, as `fn foo` has no generic args other than parent's,
But this `BoundVar` is pointing at `'a` in `<'a, T: Deref<Target = impl Trait>>`.
So, in the first code reference `register_obligations_for_call`'s L:1948 - `.substitute(Interner, parameters)`, we are substituting `'a` with `Ty`, not `Lifetime` and this makes panic inside the chalk.
This PR fixes this wrong `BoundVar` index in such cases
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 35 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/regression.rs | 33 |
2 files changed, 50 insertions, 18 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 446f1853c8..79b096068d 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -377,26 +377,25 @@ impl<'a> TyLoweringContext<'a> { // Count the number of `impl Trait` things that appear within our bounds. // Since t hose have been emitted as implicit type args already. counter.set(idx + count_impl_traits(type_ref) as u16); - let ( - _parent_params, - self_param, - type_params, - const_params, - _impl_trait_params, - lifetime_params, - ) = self + let kind = self .generics() .expect("variable impl trait lowering must be in a generic def") - .provenance_split(); - TyKind::BoundVar(BoundVar::new( - self.in_binders, - idx as usize - + self_param as usize - + type_params - + const_params - + lifetime_params, - )) - .intern(Interner) + .iter() + .enumerate() + .filter_map(|(i, (id, data))| match (id, data) { + ( + GenericParamId::TypeParamId(_), + GenericParamDataRef::TypeParamData(data), + ) if data.provenance == TypeParamProvenance::ArgumentImplTrait => { + Some(i) + } + _ => None, + }) + .nth(idx as usize) + .map_or(TyKind::Error, |id| { + TyKind::BoundVar(BoundVar { debruijn: self.in_binders, index: id }) + }); + kind.intern(Interner) } ImplTraitLoweringState::Disallowed => { // FIXME: report error diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 26e9243e73..01862aa2a3 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -2162,3 +2162,36 @@ fn main() { "#]], ); } + +#[test] +fn issue_17711() { + check_infer( + r#" +//- minicore: deref +use core::ops::Deref; + +struct Struct<'a, T>(&'a T); + +trait Trait {} + +impl<'a, T: Deref<Target = impl Trait>> Struct<'a, T> { + fn foo(&self) -> &Self { self } + + fn bar(&self) { + let _ = self.foo(); + } + +} +"#, + expect![[r#" + 137..141 'self': &'? Struct<'a, T> + 152..160 '{ self }': &'? Struct<'a, T> + 154..158 'self': &'? Struct<'a, T> + 174..178 'self': &'? Struct<'a, T> + 180..215 '{ ... }': () + 194..195 '_': &'? Struct<'?, T> + 198..202 'self': &'? Struct<'a, T> + 198..208 'self.foo()': &'? Struct<'?, T> + "#]], + ); +} |