Skip to content

Commit

Permalink
Auto merge of #17916 - ShoyuVanilla:issue-17711, r=Veykril
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Aug 17, 2024
2 parents e4edf6c + d7431ec commit 469b062
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
35 changes: 17 additions & 18 deletions crates/hir-ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions crates/hir-ty/src/tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
"#]],
);
}

0 comments on commit 469b062

Please sign in to comment.