From fae9049ccd8dc03503d70b956fd7e6a41a1716f2 Mon Sep 17 00:00:00 2001 From: iDawer Date: Sat, 23 Apr 2022 15:10:10 +0500 Subject: [PATCH 1/2] Fall back to parameter definitions on error types in signature help --- crates/ide/src/signature_help.rs | 66 ++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 6dc8b3046cc7..2ca933ec3eef 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -110,10 +110,12 @@ fn signature_help_for_call( SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter }; let db = sema.db; + let mut fn_params = None; match callable.kind() { hir::CallableKind::Function(func) => { res.doc = func.docs(db).map(|it| it.into()); format_to!(res.signature, "fn {}", func.name(db)); + fn_params = Some(func.assoc_fn_params(db)); } hir::CallableKind::TupleStruct(strukt) => { res.doc = strukt.docs(db).map(|it| it.into()); @@ -137,7 +139,7 @@ fn signature_help_for_call( format_to!(res.signature, "{}", self_param) } let mut buf = String::new(); - for (pat, ty) in callable.params(db) { + for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() { buf.clear(); if let Some(pat) = pat { match pat { @@ -145,7 +147,15 @@ fn signature_help_for_call( Either::Right(pat) => format_to!(buf, "{}: ", pat), } } - format_to!(buf, "{}", ty.display(db)); + // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is + // in the middle of entering call arguments. + // In that case, fall back to render definition of the argument. + // This is overly conservative: we do not substitute known type vars + // (see FIXME in tests::impl_trait). + match (ty.contains_unknown(), fn_params.as_deref()) { + (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)), + _ => format_to!(buf, "{}", ty.display(db)), + } res.push_call_param(&buf); } } @@ -420,8 +430,8 @@ fn foo(x: T, y: U) -> u32 fn bar() { foo($03, ); } "#, expect![[r#" - fn foo(x: i32, y: {unknown}) -> u32 - ^^^^^^ ------------ + fn foo(x: i32, y: U) -> u32 + ^^^^^^ ---- "#]], ); } @@ -633,26 +643,21 @@ pub fn do_it() { fn test_fn_signature_with_docs_from_actix() { check( r#" -struct WriteHandler; - -impl WriteHandler { - /// Method is called when writer emits error. - /// - /// If this method returns `ErrorAction::Continue` writer processing - /// continues otherwise stream processing stops. - fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running { - Running::Stop - } - +trait Actor { + /// Actor execution context type + type Context; +} +trait WriteHandler +where + Self: Actor +{ /// Method is called when writer finishes. /// /// By default this method stops actor's `Context`. - fn finished(&mut self, ctx: &mut Self::Context) { - ctx.stop() - } + fn finished(&mut self, ctx: &mut Self::Context) {} } -pub fn foo(mut r: WriteHandler<()>) { +fn foo(mut r: impl WriteHandler<()>) { r.finished($0); } "#, @@ -661,8 +666,8 @@ pub fn foo(mut r: WriteHandler<()>) { By default this method stops actor's `Context`. ------ - fn finished(&mut self, ctx: &mut {unknown}) - ^^^^^^^^^^^^^^^^^^^ + fn finished(&mut self, ctx: &mut as Actor>::Context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "#]], ); } @@ -1055,4 +1060,23 @@ fn f() { "#]], ); } + + #[test] + fn impl_trait() { + // FIXME: Substitute type vars in impl trait (`U` -> `i8`) + check( + r#" +trait Trait {} +struct Wrap(T); +fn foo(x: Wrap>) {} +fn f() { + foo::($0) +} +"#, + expect![[r#" + fn foo(x: Wrap>) + ^^^^^^^^^^^^^^^^^^^^^^ + "#]], + ); + } } From baa4fa09ef21716d9f31c1bf280fd5af6e0b3842 Mon Sep 17 00:00:00 2001 From: iDawer Date: Sat, 23 Apr 2022 16:45:47 +0500 Subject: [PATCH 2/2] Add fallback for return type --- crates/ide/src/signature_help.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 2ca933ec3eef..4eca69033a67 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -149,9 +149,9 @@ fn signature_help_for_call( } // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is // in the middle of entering call arguments. - // In that case, fall back to render definition of the argument. + // In that case, fall back to render definitions of the respective parameters. // This is overly conservative: we do not substitute known type vars - // (see FIXME in tests::impl_trait). + // (see FIXME in tests::impl_trait) and falling back on any unknowns. match (ty.contains_unknown(), fn_params.as_deref()) { (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)), _ => format_to!(buf, "{}", ty.display(db)), @@ -161,12 +161,17 @@ fn signature_help_for_call( } res.signature.push(')'); + let mut render = |ret_type: hir::Type| { + if !ret_type.is_unit() { + format_to!(res.signature, " -> {}", ret_type.display(db)); + } + }; match callable.kind() { + hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => { + render(func.ret_type(db)) + } hir::CallableKind::Function(_) | hir::CallableKind::Closure => { - let ret_type = callable.return_type(); - if !ret_type.is_unit() { - format_to!(res.signature, " -> {}", ret_type.display(db)); - } + render(callable.return_type()) } hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} } @@ -444,7 +449,7 @@ fn foo() -> T where T: Copy + Display {} fn bar() { foo($0); } "#, expect![[r#" - fn foo() -> {unknown} + fn foo() -> T "#]], ); }