Skip to content

Commit 23e47e1

Browse files
committed
Auto merge of #12063 - iDawer:ide.signature_help, r=Veykril
fix: Fall back to parameter definitions on error types in signature help Fixes #10432
2 parents c606229 + baa4fa0 commit 23e47e1

File tree

1 file changed

+55
-26
lines changed

1 file changed

+55
-26
lines changed

crates/ide/src/signature_help.rs

+55-26
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,12 @@ fn signature_help_for_call(
110110
SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
111111

112112
let db = sema.db;
113+
let mut fn_params = None;
113114
match callable.kind() {
114115
hir::CallableKind::Function(func) => {
115116
res.doc = func.docs(db).map(|it| it.into());
116117
format_to!(res.signature, "fn {}", func.name(db));
118+
fn_params = Some(func.assoc_fn_params(db));
117119
}
118120
hir::CallableKind::TupleStruct(strukt) => {
119121
res.doc = strukt.docs(db).map(|it| it.into());
@@ -137,26 +139,39 @@ fn signature_help_for_call(
137139
format_to!(res.signature, "{}", self_param)
138140
}
139141
let mut buf = String::new();
140-
for (pat, ty) in callable.params(db) {
142+
for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() {
141143
buf.clear();
142144
if let Some(pat) = pat {
143145
match pat {
144146
Either::Left(_self) => format_to!(buf, "self: "),
145147
Either::Right(pat) => format_to!(buf, "{}: ", pat),
146148
}
147149
}
148-
format_to!(buf, "{}", ty.display(db));
150+
// APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is
151+
// in the middle of entering call arguments.
152+
// In that case, fall back to render definitions of the respective parameters.
153+
// This is overly conservative: we do not substitute known type vars
154+
// (see FIXME in tests::impl_trait) and falling back on any unknowns.
155+
match (ty.contains_unknown(), fn_params.as_deref()) {
156+
(true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)),
157+
_ => format_to!(buf, "{}", ty.display(db)),
158+
}
149159
res.push_call_param(&buf);
150160
}
151161
}
152162
res.signature.push(')');
153163

164+
let mut render = |ret_type: hir::Type| {
165+
if !ret_type.is_unit() {
166+
format_to!(res.signature, " -> {}", ret_type.display(db));
167+
}
168+
};
154169
match callable.kind() {
170+
hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
171+
render(func.ret_type(db))
172+
}
155173
hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
156-
let ret_type = callable.return_type();
157-
if !ret_type.is_unit() {
158-
format_to!(res.signature, " -> {}", ret_type.display(db));
159-
}
174+
render(callable.return_type())
160175
}
161176
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
162177
}
@@ -420,8 +435,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
420435
fn bar() { foo($03, ); }
421436
"#,
422437
expect![[r#"
423-
fn foo(x: i32, y: {unknown}) -> u32
424-
^^^^^^ ------------
438+
fn foo(x: i32, y: U) -> u32
439+
^^^^^^ ----
425440
"#]],
426441
);
427442
}
@@ -434,7 +449,7 @@ fn foo<T>() -> T where T: Copy + Display {}
434449
fn bar() { foo($0); }
435450
"#,
436451
expect![[r#"
437-
fn foo() -> {unknown}
452+
fn foo() -> T
438453
"#]],
439454
);
440455
}
@@ -633,26 +648,21 @@ pub fn do_it() {
633648
fn test_fn_signature_with_docs_from_actix() {
634649
check(
635650
r#"
636-
struct WriteHandler<E>;
637-
638-
impl<E> WriteHandler<E> {
639-
/// Method is called when writer emits error.
640-
///
641-
/// If this method returns `ErrorAction::Continue` writer processing
642-
/// continues otherwise stream processing stops.
643-
fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
644-
Running::Stop
645-
}
646-
651+
trait Actor {
652+
/// Actor execution context type
653+
type Context;
654+
}
655+
trait WriteHandler<E>
656+
where
657+
Self: Actor
658+
{
647659
/// Method is called when writer finishes.
648660
///
649661
/// By default this method stops actor's `Context`.
650-
fn finished(&mut self, ctx: &mut Self::Context) {
651-
ctx.stop()
652-
}
662+
fn finished(&mut self, ctx: &mut Self::Context) {}
653663
}
654664
655-
pub fn foo(mut r: WriteHandler<()>) {
665+
fn foo(mut r: impl WriteHandler<()>) {
656666
r.finished($0);
657667
}
658668
"#,
@@ -661,8 +671,8 @@ pub fn foo(mut r: WriteHandler<()>) {
661671
662672
By default this method stops actor's `Context`.
663673
------
664-
fn finished(&mut self, ctx: &mut {unknown})
665-
^^^^^^^^^^^^^^^^^^^
674+
fn finished(&mut self, ctx: &mut <impl WriteHandler<()> as Actor>::Context)
675+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
666676
"#]],
667677
);
668678
}
@@ -1055,4 +1065,23 @@ fn f() {
10551065
"#]],
10561066
);
10571067
}
1068+
1069+
#[test]
1070+
fn impl_trait() {
1071+
// FIXME: Substitute type vars in impl trait (`U` -> `i8`)
1072+
check(
1073+
r#"
1074+
trait Trait<T> {}
1075+
struct Wrap<T>(T);
1076+
fn foo<U>(x: Wrap<impl Trait<U>>) {}
1077+
fn f() {
1078+
foo::<i8>($0)
1079+
}
1080+
"#,
1081+
expect![[r#"
1082+
fn foo(x: Wrap<impl Trait<U>>)
1083+
^^^^^^^^^^^^^^^^^^^^^^
1084+
"#]],
1085+
);
1086+
}
10581087
}

0 commit comments

Comments
 (0)