Skip to content

Commit

Permalink
Auto merge of rust-lang#17893 - ShoyuVanilla:issue-17871, r=flodiebold
Browse files Browse the repository at this point in the history
fix: Panic while hovering associated function with type annotation on generic param that not inherited from its container type

Fixes rust-lang#17871

We call `generic_args_sans_defaults` here;

https://github.com/rust-lang/rust-analyzer/blob/64a140527b383e3a2fe95908881624fc5374c60c/crates/hir-ty/src/display.rs#L1021-L1034

but the following substitution inside that function panic in rust-lang#17871;

https://github.com/rust-lang/rust-analyzer/blob/64a140527b383e3a2fe95908881624fc5374c60c/crates/hir-ty/src/display.rs#L1468

it's because the `Binders.binder` inside `default_parameters` has a same length with the generics of the function we are hovering on, but the generics of it is split into two, `fn_params` and `parent_params`.
Because of this, it may panic if the function has one or more default parameters and both `fn_params` and `parent_params` are non-empty, like the case in the title of this PR.

So, we must call `generic_args_sans_default` first and then split it into `fn_params` and `parent_params`
  • Loading branch information
bors committed Aug 15, 2024
2 parents 89cd585 + b0183f8 commit e20180d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 8 deletions.
15 changes: 7 additions & 8 deletions src/tools/rust-analyzer/crates/hir-ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,26 +1019,25 @@ impl HirDisplay for Ty {
let (parent_len, self_param, type_, const_, impl_, lifetime) =
generics.provenance_split();
let parameters = parameters.as_slice(Interner);
debug_assert_eq!(
parameters.len(),
parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
);
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if parameters.len() - impl_ > 0 {
// `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
let parameters =
generic_args_sans_defaults(f, Some(generic_def_id), parameters);
let without_impl = self_param as usize + type_ + const_ + lifetime;
// parent's params (those from enclosing impl or trait, if any).
let (fn_params, parent_params) = parameters.split_at(without_impl + impl_);
debug_assert_eq!(parent_params.len(), parent_len);

let parent_params =
generic_args_sans_defaults(f, Some(generic_def_id), parent_params);
let fn_params =
&generic_args_sans_defaults(f, Some(generic_def_id), fn_params)
[0..without_impl];

write!(f, "<")?;
hir_fmt_generic_arguments(f, parent_params, None)?;
if !parent_params.is_empty() && !fn_params.is_empty() {
write!(f, ", ")?;
}
hir_fmt_generic_arguments(f, fn_params, None)?;
hir_fmt_generic_arguments(f, &fn_params[0..without_impl], None)?;
write!(f, ">")?;
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8602,3 +8602,31 @@ fn test() {
"#]],
);
}

#[test]
fn issue_17871() {
check(
r#"
trait T {
fn f<A>();
}
struct S {}
impl T for S {
fn f<A>() {}
}
fn main() {
let x$0 = S::f::<i32>;
}
"#,
expect![[r#"
*x*
```rust
// size = 0, align = 1
let x: fn f<S, i32>()
```
"#]],
);
}

0 comments on commit e20180d

Please sign in to comment.