diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 985d3a4eccac..44a7eeaddeac 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo}; +use hir::{known, Callable, CallableKind, HasVisibility, HirDisplay, Semantics, TypeInfo}; use ide_db::RootDatabase; use ide_db::{base_db::FileRange, helpers::FamousDefs}; use itertools::Itertools; @@ -374,7 +374,7 @@ fn should_not_display_type_hint( for node in bind_pat.syntax().ancestors() { match_ast! { match node { - ast::LetStmt(it) => return it.ty().is_some(), + ast::LetStmt(it) => return is_unambigious_type(sema, it).is_some(), ast::Param(it) => return it.ty().is_some(), ast::MatchArm(_it) => return pat_is_enum_variant(db, bind_pat, pat_ty), ast::IfExpr(it) => { @@ -401,6 +401,35 @@ fn should_not_display_type_hint( false } +fn is_unambigious_type(sema: &Semantics, let_stmt: ast::LetStmt) -> Option<()> { + if let_stmt.ty().is_some() { + return Some(()); + } + let initializer = let_stmt.initializer()?; + let (callable, _arg_list) = get_callable(sema, &initializer)?; + match callable.kind() { + CallableKind::TupleEnumVariant(_) => Some(()), + CallableKind::TupleStruct(_) => { + if let ast::Expr::CallExpr(call) = initializer { + if let ast::Expr::PathExpr(path_expr) = call.expr()? { + let args = path_expr.path()?.segments().find_map(|s| s.generic_arg_list())?; + let unambigious = args + .generic_args() + .filter_map(|a| match a { + ast::GenericArg::TypeArg(type_arg) => type_arg.ty(), + ast::GenericArg::AssocTypeArg(assoc_type_arg) => assoc_type_arg.ty(), + _ => None, + }) + .all(|ty| !matches!(ty, ast::Type::InferType(_))); + return if unambigious { Some(()) } else { None }; + } + } + None + } + _ => None, + } +} + fn should_hide_param_name_hint( sema: &Semantics, callable: &hir::Callable, @@ -921,6 +950,29 @@ fn main() { ); } + #[test] + fn hide_type_hints_tuple_generics() { + check_types( + r#" +struct Struct(T, U); + +enum Enum { + Variant(u32) +} + +fn main() { + let foo = Struct::(0, 0); + let foo = Enum::Variant(0); + let foo = Struct(1, 2); + //^^^ Struct + bar(foo); +} + +fn bar(foo: Struct) {} +"#, + ) + } + #[test] fn type_hints_bindings_after_at() { check_types( @@ -1154,7 +1206,6 @@ struct Test { a: Option, b: u8 } fn main() { let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option if let None = &test {}; if let test = &test {}; //^^^^ &Option @@ -1184,7 +1235,6 @@ struct Test { a: Option, b: u8 } fn main() { let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option while let Some(Test { a: Some(x), b: y }) = &test {}; //^ &u32 ^ &u8 }"#,