Skip to content

Commit e896def

Browse files
bors[bot]theo-lw
andauthored
Merge #10204
10204: feat: Show the type of what is being dereferenced in a deref expression. r=theo-lw a=theo-lw Addresses issue #10106. In-progress - I'm trying to figure out why `hover_deref_expr_with_coercion` is failing. Co-authored-by: Teddy_Wang <[email protected]>
2 parents e08b3bf + 8de5d66 commit e896def

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

crates/ide/src/hover.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ fn hover_ranged(
243243
})?;
244244
let res = match &expr_or_pat {
245245
Either::Left(ast::Expr::TryExpr(try_expr)) => hover_try_expr(sema, config, try_expr),
246+
Either::Left(ast::Expr::PrefixExpr(prefix_expr))
247+
if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) =>
248+
{
249+
hover_deref_expr(sema, config, prefix_expr)
250+
}
246251
_ => None,
247252
};
248253
let res = res.or_else(|| hover_type_info(sema, config, &expr_or_pat));
@@ -346,6 +351,70 @@ fn hover_try_expr(
346351
Some(res)
347352
}
348353

354+
fn hover_deref_expr(
355+
sema: &Semantics<RootDatabase>,
356+
config: &HoverConfig,
357+
deref_expr: &ast::PrefixExpr,
358+
) -> Option<HoverResult> {
359+
let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original;
360+
let TypeInfo { original, adjusted } =
361+
sema.type_of_expr(&ast::Expr::from(deref_expr.clone()))?;
362+
363+
let mut res = HoverResult::default();
364+
let mut targets: Vec<hir::ModuleDef> = Vec::new();
365+
let mut push_new_def = |item: hir::ModuleDef| {
366+
if !targets.contains(&item) {
367+
targets.push(item);
368+
}
369+
};
370+
walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
371+
walk_and_push_ty(sema.db, &original, &mut push_new_def);
372+
373+
res.markup = if let Some(adjusted_ty) = adjusted {
374+
walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
375+
let original = original.display(sema.db).to_string();
376+
let adjusted = adjusted_ty.display(sema.db).to_string();
377+
let inner = inner_ty.display(sema.db).to_string();
378+
let type_len = "To type: ".len();
379+
let coerced_len = "Coerced to: ".len();
380+
let deref_len = "Dereferenced from: ".len();
381+
let max_len = (original.len() + type_len)
382+
.max(adjusted.len() + coerced_len)
383+
.max(inner.len() + deref_len);
384+
format!(
385+
"{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
386+
inner,
387+
original,
388+
adjusted,
389+
ipad = max_len - deref_len,
390+
apad = max_len - type_len,
391+
opad = max_len - coerced_len,
392+
bt_start = if config.markdown() { "```text\n" } else { "" },
393+
bt_end = if config.markdown() { "```\n" } else { "" }
394+
)
395+
.into()
396+
} else {
397+
let original = original.display(sema.db).to_string();
398+
let inner = inner_ty.display(sema.db).to_string();
399+
let type_len = "To type: ".len();
400+
let deref_len = "Dereferenced from: ".len();
401+
let max_len = (original.len() + type_len).max(inner.len() + deref_len);
402+
format!(
403+
"{bt_start}Dereferenced from: {:>ipad$}\nTo type: {:>apad$}\n{bt_end}",
404+
inner,
405+
original,
406+
ipad = max_len - deref_len,
407+
apad = max_len - type_len,
408+
bt_start = if config.markdown() { "```text\n" } else { "" },
409+
bt_end = if config.markdown() { "```\n" } else { "" }
410+
)
411+
.into()
412+
};
413+
res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
414+
415+
Some(res)
416+
}
417+
349418
fn hover_type_info(
350419
sema: &Semantics<RootDatabase>,
351420
config: &HoverConfig,
@@ -4647,4 +4716,71 @@ fn foo() -> Option<()> {
46474716
```"#]],
46484717
);
46494718
}
4719+
4720+
#[test]
4721+
fn hover_deref_expr() {
4722+
check_hover_range(
4723+
r#"
4724+
//- minicore: deref
4725+
use core::ops::Deref;
4726+
4727+
struct DerefExample<T> {
4728+
value: T
4729+
}
4730+
4731+
impl<T> Deref for DerefExample<T> {
4732+
type Target = T;
4733+
4734+
fn deref(&self) -> &Self::Target {
4735+
&self.value
4736+
}
4737+
}
4738+
4739+
fn foo() {
4740+
let x = DerefExample { value: 0 };
4741+
let y: i32 = $0*x$0;
4742+
}
4743+
"#,
4744+
expect![[r#"
4745+
```text
4746+
Dereferenced from: DerefExample<i32>
4747+
To type: i32
4748+
```
4749+
"#]],
4750+
);
4751+
}
4752+
4753+
#[test]
4754+
fn hover_deref_expr_with_coercion() {
4755+
check_hover_range(
4756+
r#"
4757+
//- minicore: deref
4758+
use core::ops::Deref;
4759+
4760+
struct DerefExample<T> {
4761+
value: T
4762+
}
4763+
4764+
impl<T> Deref for DerefExample<T> {
4765+
type Target = T;
4766+
4767+
fn deref(&self) -> &Self::Target {
4768+
&self.value
4769+
}
4770+
}
4771+
4772+
fn foo() {
4773+
let x = DerefExample { value: &&&&&0 };
4774+
let y: &i32 = $0*x$0;
4775+
}
4776+
"#,
4777+
expect![[r#"
4778+
```text
4779+
Dereferenced from: DerefExample<&&&&&i32>
4780+
To type: &&&&&i32
4781+
Coerced to: &i32
4782+
```
4783+
"#]],
4784+
);
4785+
}
46504786
}

0 commit comments

Comments
 (0)