Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
| -rw-r--r-- | crates/ide/src/inlay_hints.rs | 96 |
1 files changed, 91 insertions, 5 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 401feffff4..8dfceb35af 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -198,28 +198,69 @@ fn get_bind_pat_hints( let descended = sema.descend_node_into_attributes(pat.clone()).pop(); let desc_pat = descended.as_ref().unwrap_or(pat); - let krate = sema.scope(desc_pat.syntax()).module().map(|it| it.krate()); - let famous_defs = FamousDefs(sema, krate); - let ty = sema.type_of_pat(&desc_pat.clone().into())?.original; if should_not_display_type_hint(sema, &pat, &ty) { return None; } + let krate = sema.scope(desc_pat.syntax()).module().map(|it| it.krate()); + let famous_defs = FamousDefs(sema, krate); + let label = hint_iterator(sema, &famous_defs, config, &ty); + + let label = match label { + Some(label) => label, + None => { + let ty = ty.display_truncated(sema.db, config.max_length).to_string(); + if Some(&*ty) == get_constructor_name(sema, pat).as_deref() { + return None; + } + ty.into() + } + }; + acc.push(InlayHint { range: match pat.name() { Some(name) => name.syntax().text_range(), None => pat.syntax().text_range(), }, kind: InlayKind::TypeHint, - label: hint_iterator(sema, &famous_defs, config, &ty) - .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string().into()), + label, }); Some(()) } +fn get_constructor_name(sema: &Semantics<RootDatabase>, pat: &ast::IdentPat) -> Option<String> { + let it = pat.syntax().parent()?; + let expr = match_ast! { + match it { + ast::LetStmt(it) => it.initializer(), + ast::Condition(it) => it.expr(), + _ => None, + } + }; + + if let Some(expr) = expr { + let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr); + let expr = match expr { + ast::Expr::TryExpr(it) => it.expr(), + ast::Expr::AwaitExpr(it) => it.expr(), + expr => Some(expr), + }?; + let path = match expr { + ast::Expr::CallExpr(call) => match call.expr()? { + ast::Expr::PathExpr(p) => p.path(), + _ => None, + }, + _ => None, + }?; + let seg = path.qualifier()?.segment()?; + return Some(seg.to_string()); + } + None +} + /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`. fn hint_iterator( sema: &Semantics<RootDatabase>, @@ -1235,6 +1276,51 @@ fn main() { } #[test] + fn skip_constructor_type_hints() { + check_types( + r#" +//- minicore: try +use core::ops::ControlFlow; + +struct Struct; +struct TupleStruct(); + +impl Struct { + fn new() -> Self { + Struct + } + fn try_new() -> ControlFlow<(), Self> { + ControlFlow::Continue(Struct) + } +} + +struct Generic<T>(T); +impl Generic<i32> { + fn new() -> Self { + Generic(0) + } +} + +fn main() { + let strukt = Struct::new(); + let tuple_struct = TupleStruct(); + // ^^^^^^^^^^^^ TupleStruct + let generic0 = Generic::new(); + // ^^^^^^^^ Generic<i32> + let generic1 = Generic::<i32>::new(); + // ^^^^^^^^ Generic<i32> + let generic2 = <Generic<i32>>::new(); + // ^^^^^^^^ Generic<i32> +} + +fn fallible() -> ControlFlow<()> { + let strukt = Struct::try_new()?; +} +"#, + ); + } + + #[test] fn closures() { check( r#" |