diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 0cb484d5075..ac01968126d 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -58,6 +58,7 @@ pub(crate) struct PathCompletionContext { pub(super) struct PatternContext { pub(super) refutability: PatternRefutability, pub(super) is_param: Option, + pub(super) has_type_ascription: bool, } #[derive(Debug)] @@ -597,7 +598,8 @@ impl<'a> CompletionContext<'a> { .map(|c| (Some(c.return_type()), None)) .unwrap_or((None, None)) }, - ast::Stmt(_it) => (None, None), + ast::ParamList(__) => (None, None), + ast::Stmt(__) => (None, None), ast::Item(__) => (None, None), _ => { match node.parent() { @@ -708,15 +710,15 @@ impl<'a> CompletionContext<'a> { return None; } let mut is_param = None; - let refutability = bind_pat + let (refutability, has_type_ascription) = bind_pat .syntax() .ancestors() .skip_while(|it| ast::Pat::can_cast(it.kind())) .next() - .map_or(PatternRefutability::Irrefutable, |node| { - match_ast! { + .map_or((PatternRefutability::Irrefutable, false), |node| { + let refutability = match_ast! { match node { - ast::LetStmt(__) => PatternRefutability::Irrefutable, + ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()), ast::Param(param) => { let is_closure_param = param .syntax() @@ -729,16 +731,17 @@ impl<'a> CompletionContext<'a> { } else { ParamKind::Function }); - PatternRefutability::Irrefutable + return (PatternRefutability::Irrefutable, param.ty().is_some()) }, ast::MatchArm(__) => PatternRefutability::Refutable, ast::Condition(__) => PatternRefutability::Refutable, ast::ForExpr(__) => PatternRefutability::Irrefutable, _ => PatternRefutability::Irrefutable, } - } + }; + (refutability, false) }); - Some(PatternContext { refutability, is_param }) + Some(PatternContext { refutability, is_param, has_type_ascription }) } fn classify_name_ref( @@ -1172,4 +1175,23 @@ fn foo() { expect![[r#"ty: Foo, name: ?"#]], ); } + + #[test] + fn expected_type_param_pat() { + check_expected_type_and_name( + r#" +struct Foo { field: u32 } +fn foo(a$0: Foo) {} +"#, + expect![[r#"ty: Foo, name: ?"#]], + ); + check_expected_type_and_name( + r#" +struct Foo { field: u32 } +fn foo($0: Foo) {} +"#, + // FIXME make this work, currently fails due to pattern recovery eating the `:` + expect![[r#"ty: ?, name: ?"#]], + ); + } } diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs index e553ec8f860..888a5b4b0a7 100644 --- a/crates/ide_completion/src/render/pattern.rs +++ b/crates/ide_completion/src/render/pattern.rs @@ -86,7 +86,11 @@ fn render_pat( if matches!( ctx.completion.pattern_ctx, - Some(PatternContext { is_param: Some(ParamKind::Function), .. }) + Some(PatternContext { + is_param: Some(ParamKind::Function), + has_type_ascription: false, + .. + }) ) { pat.push(':'); pat.push(' '); diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs index 3e10575b19e..6dd1b669988 100644 --- a/crates/ide_completion/src/tests/pattern.rs +++ b/crates/ide_completion/src/tests/pattern.rs @@ -163,6 +163,21 @@ fn foo(a$0) { ma makro!(…) #[macro_export] macro_rules! makro "##]], ); + check( + r#" +fn foo(a$0: Tuple) { +} +"#, + expect![[r##" + kw mut + bn Record Record { field$1 }$0 + st Record + bn Tuple Tuple($1)$0 + st Tuple + st Unit + ma makro!(…) #[macro_export] macro_rules! makro + "##]], + ); } #[test]