1use hir::{DisplayTarget, Semantics};
7use ide_db::{RootDatabase, famous_defs::FamousDefs};
8
9use itertools::Itertools;
10use syntax::{
11 ast::{self, AstNode, HasGenericArgs, HasName},
12 match_ast,
13};
14
15use crate::{
16 InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
17 inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
18};
19
20pub(super) fn hints(
21 acc: &mut Vec<InlayHint>,
22 famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
23 config: &InlayHintsConfig<'_>,
24 display_target: DisplayTarget,
25 pat: &ast::IdentPat,
26) -> Option<()> {
27 if !config.type_hints {
28 return None;
29 }
30
31 let parent = pat.syntax().parent()?;
32 let type_ascriptable = match_ast! {
33 match parent {
34 ast::Param(it) => {
35 if it.ty().is_some() {
36 return None;
37 }
38 if config.hide_closure_parameter_hints && it.syntax().ancestors().nth(2).is_none_or(|n| matches!(ast::Expr::cast(n), Some(ast::Expr::ClosureExpr(_)))) {
39 return None;
40 }
41 Some(it.colon_token())
42 },
43 ast::LetStmt(it) => {
44 if config.hide_closure_initialization_hints
45 && let Some(ast::Expr::ClosureExpr(closure)) = it.initializer()
46 && closure_has_block_body(&closure) {
47 return None;
48 }
49 if it.ty().is_some() {
50 return None;
51 }
52 Some(it.colon_token())
53 },
54 _ => None
55 }
56 };
57
58 let descended = sema.descend_node_into_attributes(pat.clone()).pop();
59 let desc_pat = descended.as_ref().unwrap_or(pat);
60 let ty = sema.type_of_binding_in_pat(desc_pat)?;
61
62 if ty.is_unknown() {
63 return None;
64 }
65
66 if sema.resolve_bind_pat_to_const(pat).is_some() {
67 return None;
68 }
69
70 let mut label = label_of_ty(famous_defs, config, &ty, display_target)?;
71
72 if config.hide_named_constructor_hints
73 && is_named_constructor(sema, pat, &label.to_string()).is_some()
74 {
75 return None;
76 }
77
78 let text_edit = if let Some(colon_token) = &type_ascriptable {
79 ty_to_text_edit(
80 sema,
81 config,
82 desc_pat.syntax(),
83 &ty,
84 colon_token
85 .as_ref()
86 .map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
87 .end(),
88 &|_| (),
89 if colon_token.is_some() { "" } else { ": " },
90 )
91 } else {
92 None
93 };
94
95 let render_colons = config.render_colons && !matches!(type_ascriptable, Some(Some(_)));
96 if render_colons {
97 label.prepend_str(": ");
98 }
99
100 let text_range = match pat.name() {
101 Some(name) => name.syntax().text_range(),
102 None => pat.syntax().text_range(),
103 };
104 acc.push(InlayHint {
105 range: match type_ascriptable {
106 Some(Some(t)) => text_range.cover(t.text_range()),
107 _ => text_range,
108 },
109 kind: InlayKind::Type,
110 label,
111 text_edit,
112 position: InlayHintPosition::After,
113 pad_left: !render_colons,
114 pad_right: false,
115 resolve_parent: Some(pat.syntax().text_range()),
116 });
117
118 Some(())
119}
120
121fn is_named_constructor(
122 sema: &Semantics<'_, RootDatabase>,
123 pat: &ast::IdentPat,
124 ty_name: &str,
125) -> Option<()> {
126 let let_node = pat.syntax().parent()?;
127 let expr = match_ast! {
128 match let_node {
129 ast::LetStmt(it) => it.initializer(),
130 ast::LetExpr(it) => it.expr(),
131 _ => None,
132 }
133 }?;
134
135 let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
136 let expr = match expr {
138 ast::Expr::TryExpr(it) => it.expr(),
139 ast::Expr::AwaitExpr(it) => it.expr(),
140 expr => Some(expr),
141 }?;
142 let expr = match expr {
143 ast::Expr::CallExpr(call) => match call.expr()? {
144 ast::Expr::PathExpr(path) => path,
145 _ => return None,
146 },
147 ast::Expr::PathExpr(path) => path,
148 _ => return None,
149 };
150 let path = expr.path()?;
151
152 let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db);
153 let callable_kind = callable.map(|it| it.kind());
154 let qual_seg = match callable_kind {
155 Some(hir::CallableKind::Function(_) | hir::CallableKind::TupleEnumVariant(_)) => {
156 path.qualifier()?.segment()
157 }
158 _ => path.segment(),
159 }?;
160
161 let ctor_name = match qual_seg.kind()? {
162 ast::PathSegmentKind::Name(name_ref) => {
163 match qual_seg.generic_arg_list().map(|it| it.generic_args()) {
164 Some(generics) => format!("{name_ref}<{}>", generics.format(", ")),
165 None => name_ref.to_string(),
166 }
167 }
168 ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(),
169 _ => return None,
170 };
171 (ctor_name == ty_name).then_some(())
172}
173
174#[cfg(test)]
175mod tests {
176 use expect_test::expect;
179 use hir::ClosureStyle;
180 use syntax::{TextRange, TextSize};
181 use test_utils::extract_annotations;
182
183 use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
184
185 use crate::inlay_hints::tests::{
186 DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config,
187 };
188
189 #[track_caller]
190 fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
191 check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
192 }
193
194 #[test]
195 fn type_hints_only() {
196 check_types(
197 r#"
198fn foo(a: i32, b: i32) -> i32 { a + b }
199fn main() {
200 let _x = foo(4, 4);
201 //^^ i32
202}"#,
203 );
204 }
205
206 #[test]
207 fn type_hints_bindings_after_at() {
208 check_types(
209 r#"
210//- minicore: option
211fn main() {
212 let ref foo @ bar @ ref mut baz = 0;
213 //^^^ &i32
214 //^^^ i32
215 //^^^ &mut i32
216 let [x @ ..] = [0];
217 //^ [i32; 1]
218 if let x @ Some(_) = Some(0) {}
219 //^ Option<i32>
220 let foo @ (bar, baz) = (3, 3);
221 //^^^ (i32, i32)
222 //^^^ i32
223 //^^^ i32
224}"#,
225 );
226 }
227
228 #[test]
229 fn default_generic_types_should_not_be_displayed() {
230 check(
231 r#"
232struct Test<K, T = u8> { k: K, t: T }
233
234fn main() {
235 let zz = Test { t: 23u8, k: 33 };
236 //^^ Test<i32>
237 let zz_ref = &zz;
238 //^^^^^^ &Test<i32>
239 let test = || zz;
240 //^^^^ impl FnOnce() -> Test<i32>
241}"#,
242 );
243 }
244
245 #[test]
246 fn shorten_iterators_in_associated_params() {
247 check_types(
248 r#"
249//- minicore: iterators
250use core::iter;
251
252pub struct SomeIter<T> {}
253
254impl<T> SomeIter<T> {
255 pub fn new() -> Self { SomeIter {} }
256 pub fn push(&mut self, t: T) {}
257}
258
259impl<T> Iterator for SomeIter<T> {
260 type Item = T;
261 fn next(&mut self) -> Option<Self::Item> {
262 None
263 }
264}
265
266fn main() {
267 let mut some_iter = SomeIter::new();
268 //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
269 some_iter.push(iter::repeat(2).take(2));
270 let iter_of_iters = some_iter.take(2);
271 //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
272}
273"#,
274 );
275 }
276
277 #[test]
278 fn iterator_hint_regression_issue_12674() {
279 let (analysis, file_id) = fixture::file(
281 r#"
282//- minicore: iterators
283struct S<T>(T);
284impl<T> S<T> {
285 fn iter(&self) -> Iter<'_, T> { loop {} }
286}
287struct Iter<'a, T: 'a>(&'a T);
288impl<'a, T> Iterator for Iter<'a, T> {
289 type Item = &'a T;
290 fn next(&mut self) -> Option<Self::Item> { loop {} }
291}
292struct Container<'a> {
293 elements: S<&'a str>,
294}
295struct SliceIter<'a, T>(&'a T);
296impl<'a, T> Iterator for SliceIter<'a, T> {
297 type Item = &'a T;
298 fn next(&mut self) -> Option<Self::Item> { loop {} }
299}
300
301fn main(a: SliceIter<'_, Container>) {
302 a
303 .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
304 .map(|e| e);
305}
306"#,
307 );
308 analysis
309 .inlay_hints(
310 &InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
311 file_id,
312 None,
313 )
314 .unwrap();
315 }
316
317 #[test]
318 fn infer_call_method_return_associated_types_with_generic() {
319 check_types(
320 r#"
321 pub trait Default {
322 fn default() -> Self;
323 }
324 pub trait Foo {
325 type Bar: Default;
326 }
327
328 pub fn quux<T: Foo>() -> T::Bar {
329 let y = Default::default();
330 //^ <T as Foo>::Bar
331
332 y
333 }
334 "#,
335 );
336 }
337
338 #[test]
339 fn lt_hints() {
340 check_types(
341 r#"
342struct S<'lt>;
343
344fn f<'a>() {
345 let x = S::<'static>;
346 //^ S<'static>
347 let y = S::<'_>;
348 //^ S<'_>
349 let z = S::<'a>;
350 //^ S<'a>
351
352}
353"#,
354 );
355 }
356
357 #[test]
358 fn fn_hints() {
359 check_types(
360 r#"
361//- minicore: fn, sized
362fn foo() -> impl Fn() { loop {} }
363fn foo1() -> impl Fn(f64) { loop {} }
364fn foo2() -> impl Fn(f64, f64) { loop {} }
365fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
366fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
367fn foo5() -> &'static for<'a> dyn Fn(&'a dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
368fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
369fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
370
371fn main() {
372 let foo = foo();
373 // ^^^ impl Fn()
374 let foo = foo1();
375 // ^^^ impl Fn(f64)
376 let foo = foo2();
377 // ^^^ impl Fn(f64, f64)
378 let foo = foo3();
379 // ^^^ impl Fn(f64, f64) -> u32
380 let foo = foo4();
381 // ^^^ &dyn Fn(f64, f64) -> u32
382 let foo = foo5();
383 // ^^^ &dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32
384 let foo = foo6();
385 // ^^^ impl Fn(f64, f64) -> u32
386 let foo = foo7();
387 // ^^^ *const impl Fn(f64, f64) -> u32
388}
389"#,
390 )
391 }
392
393 #[test]
394 fn check_hint_range_limit() {
395 let fixture = r#"
396//- minicore: fn, sized
397fn foo() -> impl Fn() { loop {} }
398fn foo1() -> impl Fn(f64) { loop {} }
399fn foo2() -> impl Fn(f64, f64) { loop {} }
400fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
401fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
402fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
403fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
404fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
405
406fn main() {
407 let foo = foo();
408 let foo = foo1();
409 let foo = foo2();
410 // ^^^ impl Fn(f64, f64)
411 let foo = foo3();
412 // ^^^ impl Fn(f64, f64) -> u32
413 let foo = foo4();
414 // ^^^ &dyn Fn(f64, f64) -> u32
415 let foo = foo5();
416 let foo = foo6();
417 let foo = foo7();
418}
419"#;
420 let (analysis, file_id) = fixture::file(fixture);
421 let expected = extract_annotations(&analysis.file_text(file_id).unwrap());
422 let inlay_hints = analysis
423 .inlay_hints(
424 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
425 file_id,
426 Some(TextRange::new(TextSize::from(491), TextSize::from(640))),
427 )
428 .unwrap();
429 let actual =
430 inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
431 assert_eq!(expected, actual, "\nExpected:\n{expected:#?}\n\nActual:\n{actual:#?}");
432 }
433
434 #[test]
435 fn fn_hints_ptr_rpit_fn_parentheses() {
436 check_types(
437 r#"
438//- minicore: fn, sized
439trait Trait {}
440
441fn foo1() -> *const impl Fn() { loop {} }
442fn foo2() -> *const (impl Fn() + Sized) { loop {} }
443fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
444fn foo4() -> *const (impl Sized + Fn()) { loop {} }
445fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
446fn foo6() -> *const (impl Fn() + Trait) { loop {} }
447fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
448fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
449fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
450fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
451
452fn main() {
453 let foo = foo1();
454 // ^^^ *const impl Fn()
455 let foo = foo2();
456 // ^^^ *const impl Fn()
457 let foo = foo3();
458 // ^^^ *const (impl Fn() + ?Sized)
459 let foo = foo4();
460 // ^^^ *const impl Fn()
461 let foo = foo5();
462 // ^^^ *const (impl Fn() + ?Sized)
463 let foo = foo6();
464 // ^^^ *const (impl Fn() + Trait)
465 let foo = foo7();
466 // ^^^ *const (impl Fn() + Trait)
467 let foo = foo8();
468 // ^^^ *const (impl Fn() + Trait + ?Sized)
469 let foo = foo9();
470 // ^^^ *const (impl Fn() -> u8 + ?Sized)
471 let foo = foo10();
472 // ^^^ *const impl Fn()
473}
474"#,
475 )
476 }
477
478 #[test]
479 fn unit_structs_have_no_type_hints() {
480 check_types(
481 r#"
482//- minicore: result
483struct SyntheticSyntax;
484
485fn main() {
486 match Ok(()) {
487 Ok(_) => (),
488 Err(SyntheticSyntax) => (),
489 }
490}"#,
491 );
492 }
493
494 #[test]
495 fn const_pats_have_no_type_hints() {
496 check_types(
497 r#"
498const FOO: usize = 0;
499
500fn main() {
501 match 0 {
502 FOO => (),
503 _ => ()
504 }
505}"#,
506 );
507 }
508
509 #[test]
510 fn let_statement() {
511 check_types(
512 r#"
513#[derive(PartialEq)]
514enum Option<T> { None, Some(T) }
515
516#[derive(PartialEq)]
517struct Test { a: Option<u32>, b: u8 }
518
519fn main() {
520 struct InnerStruct {}
521
522 let test = 54;
523 //^^^^ i32
524 let test: i32 = 33;
525 let mut test = 33;
526 //^^^^ i32
527 let _ = 22;
528 let test = "test";
529 //^^^^ &str
530 let test = InnerStruct {};
531 //^^^^ InnerStruct
532
533 let test = unresolved();
534
535 let test = (42, 'a');
536 //^^^^ (i32, char)
537 let (a, (b, (c,)) = (2, (3, (9.2,));
538 //^ i32 ^ i32 ^ f64
539 let &x = &92;
540 //^ i32
541}"#,
542 );
543 }
544
545 #[test]
546 fn if_expr() {
547 check_types(
548 r#"
549//- minicore: option
550struct Test { a: Option<u32>, b: u8 }
551
552fn main() {
553
554}"#,
555 );
556 }
557
558 #[test]
559 fn while_expr() {
560 check_types(
561 r#"
562//- minicore: option
563struct Test { a: Option<u32>, b: u8 }
564
565fn main() {
566 let test = Some(Test { a: Some(3), b: 1 });
567 //^^^^ Option<Test>
568 while let Some(Test { a: Some(x), b: y }) = &test {};
569 //^ &u32 ^ &u8
570}"#,
571 );
572 }
573
574 #[test]
575 fn match_arm_list() {
576 check_types(
577 r#"
578//- minicore: option
579struct Test { a: Option<u32>, b: u8 }
580
581fn main() {
582 match Some(Test { a: Some(3), b: 1 }) {
583 None => (),
584 test => (),
585 //^^^^ Option<Test>
586 Some(Test { a: Some(x), b: y }) => (),
587 //^ u32 ^ u8
588 _ => {}
589 }
590}"#,
591 );
592 }
593
594 #[test]
595 fn complete_for_hint() {
596 check_types(
597 r#"
598//- minicore: iterator
599pub struct Vec<T> {}
600
601impl<T> Vec<T> {
602 pub fn new() -> Self { Vec {} }
603 pub fn push(&mut self, t: T) {}
604}
605
606impl<T> IntoIterator for Vec<T> {
607 type Item = T;
608 type IntoIter = IntoIter<T>;
609}
610
611struct IntoIter<T> {}
612
613impl<T> Iterator for IntoIter<T> {
614 type Item = T;
615}
616
617fn main() {
618 let mut data = Vec::new();
619 //^^^^ Vec<&str>
620 data.push("foo");
621 for i in data {
622 //^ &str
623 let z = i;
624 //^ &str
625 }
626}
627"#,
628 );
629 }
630
631 #[test]
632 fn multi_dyn_trait_bounds() {
633 check_types(
634 r#"
635pub struct Vec<T> {}
636
637impl<T> Vec<T> {
638 pub fn new() -> Self { Vec {} }
639}
640
641pub struct Box<T> {}
642
643trait Display {}
644auto trait Sync {}
645
646fn main() {
647 // The block expression wrapping disables the constructor hint hiding logic
648 let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
649 //^^ Vec<Box<&(dyn Display + Sync + 'static)>>
650 let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
651 //^^ Vec<Box<*const (dyn Display + Sync + 'static)>>
652 let _v = { Vec::<Box<dyn Display + Sync + 'static>>::new() };
653 //^^ Vec<Box<dyn Display + Sync + 'static>>
654}
655"#,
656 );
657 }
658
659 #[test]
660 fn shorten_iterator_hints() {
661 check_types(
662 r#"
663//- minicore: iterators
664use core::iter;
665
666struct MyIter;
667
668impl Iterator for MyIter {
669 type Item = ();
670 fn next(&mut self) -> Option<Self::Item> {
671 None
672 }
673}
674
675fn main() {
676 let _x = MyIter;
677 //^^ MyIter
678 let _x = iter::repeat(0);
679 //^^ impl Iterator<Item = i32>
680 fn generic<T: Clone>(t: T) {
681 let _x = iter::repeat(t);
682 //^^ impl Iterator<Item = T>
683 let _chained = iter::repeat(t).take(10);
684 //^^^^^^^^ impl Iterator<Item = T>
685 }
686}
687"#,
688 );
689 }
690
691 #[test]
692 fn skip_constructor_and_enum_type_hints() {
693 check_with_config(
694 InlayHintsConfig {
695 type_hints: true,
696 hide_named_constructor_hints: true,
697 ..DISABLED_CONFIG
698 },
699 r#"
700//- minicore: try, option
701use core::ops::ControlFlow;
702
703mod x {
704 pub mod y { pub struct Foo; }
705 pub struct Foo;
706 pub enum AnotherEnum {
707 Variant()
708 };
709}
710struct Struct;
711struct TupleStruct();
712
713impl Struct {
714 fn new() -> Self {
715 Struct
716 }
717 fn try_new() -> ControlFlow<(), Self> {
718 ControlFlow::Continue(Struct)
719 }
720}
721
722struct Generic<T>(T);
723impl Generic<i32> {
724 fn new() -> Self {
725 Generic(0)
726 }
727}
728
729enum Enum {
730 Variant(u32)
731}
732
733fn times2(value: i32) -> i32 {
734 2 * value
735}
736
737fn main() {
738 let enumb = Enum::Variant(0);
739
740 let strukt = x::Foo;
741 let strukt = x::y::Foo;
742 let strukt = Struct;
743 let strukt = Struct::new();
744
745 let tuple_struct = TupleStruct();
746
747 let generic0 = Generic::new();
748 // ^^^^^^^^ Generic<i32>
749 let generic1 = Generic(0);
750 // ^^^^^^^^ Generic<i32>
751 let generic2 = Generic::<i32>::new();
752 let generic3 = <Generic<i32>>::new();
753 let generic4 = Generic::<i32>(0);
754
755
756 let option = Some(0);
757 // ^^^^^^ Option<i32>
758 let func = times2;
759 // ^^^^ fn times2(i32) -> i32
760 let closure = |x: i32| x * 2;
761 // ^^^^^^^ impl Fn(i32) -> i32
762}
763
764fn fallible() -> ControlFlow<()> {
765 let strukt = Struct::try_new()?;
766}
767"#,
768 );
769 }
770
771 #[test]
772 fn shows_constructor_type_hints_when_enabled() {
773 check_types(
774 r#"
775//- minicore: try
776use core::ops::ControlFlow;
777
778struct Struct;
779struct TupleStruct();
780
781impl Struct {
782 fn new() -> Self {
783 Struct
784 }
785 fn try_new() -> ControlFlow<(), Self> {
786 ControlFlow::Continue(Struct)
787 }
788}
789
790struct Generic<T>(T);
791impl Generic<i32> {
792 fn new() -> Self {
793 Generic(0)
794 }
795}
796
797fn main() {
798 let strukt = Struct::new();
799 // ^^^^^^ Struct
800 let tuple_struct = TupleStruct();
801 // ^^^^^^^^^^^^ TupleStruct
802 let generic0 = Generic::new();
803 // ^^^^^^^^ Generic<i32>
804 let generic1 = Generic::<i32>::new();
805 // ^^^^^^^^ Generic<i32>
806 let generic2 = <Generic<i32>>::new();
807 // ^^^^^^^^ Generic<i32>
808}
809
810fn fallible() -> ControlFlow<()> {
811 let strukt = Struct::try_new()?;
812 // ^^^^^^ Struct
813}
814"#,
815 );
816 }
817
818 #[test]
819 fn closure_style() {
820 check_with_config(
821 InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
822 r#"
823//- minicore: fn
824fn main() {
825 let x = || 2;
826 //^ impl Fn() -> i32
827 let y = |t: i32| x() + t;
828 //^ impl Fn(i32) -> i32
829 let mut t = 5;
830 //^ i32
831 let z = |k: i32| { t += k; };
832 //^ impl FnMut(i32)
833 let p = (y, z);
834 //^ (impl Fn(i32) -> i32, impl FnMut(i32))
835}
836 "#,
837 );
838 check_with_config(
839 InlayHintsConfig {
840 type_hints: true,
841 closure_style: ClosureStyle::RANotation,
842 ..DISABLED_CONFIG
843 },
844 r#"
845//- minicore: fn
846fn main() {
847 let x = || 2;
848 //^ || -> i32
849 let y = |t: i32| x() + t;
850 //^ |i32| -> i32
851 let mut t = 5;
852 //^ i32
853 let z = |k: i32| { t += k; };
854 //^ |i32| -> ()
855 let p = (y, z);
856 //^ (|i32| -> i32, |i32| -> ())
857}
858 "#,
859 );
860 check_with_config(
861 InlayHintsConfig {
862 type_hints: true,
863 closure_style: ClosureStyle::Hide,
864 ..DISABLED_CONFIG
865 },
866 r#"
867//- minicore: fn
868fn main() {
869 let x = || 2;
870 //^ …
871 let y = |t: i32| x() + t;
872 //^ …
873 let mut t = 5;
874 //^ i32
875 let z = |k: i32| { t += k; };
876 //^ …
877 let p = (y, z);
878 //^ (…, …)
879}
880 "#,
881 );
882 }
883
884 #[test]
885 fn skip_closure_type_hints() {
886 check_with_config(
887 InlayHintsConfig {
888 type_hints: true,
889 hide_closure_initialization_hints: true,
890 ..DISABLED_CONFIG
891 },
892 r#"
893//- minicore: fn
894fn main() {
895 let multiple_2 = |x: i32| { x * 2 };
896
897 let multiple_2 = |x: i32| x * 2;
898 // ^^^^^^^^^^ impl Fn(i32) -> i32
899
900 let (not) = (|x: bool| { !x });
901 // ^^^ impl Fn(bool) -> bool
902
903 let (is_zero, _b) = (|x: usize| { x == 0 }, false);
904 // ^^^^^^^ impl Fn(usize) -> bool
905 // ^^ bool
906
907 let plus_one = |x| { x + 1 };
908 // ^ u8
909 foo(plus_one);
910
911 let add_mul = bar(|x: u8| { x + 1 });
912 // ^^^^^^^ impl FnOnce(u8) -> u8
913
914 let closure = if let Some(6) = add_mul(2).checked_sub(1) {
915 // ^^^^^^^ fn(i32) -> i32
916 |x: i32| { x * 2 }
917 } else {
918 |x: i32| { x * 3 }
919 };
920}
921
922fn foo(f: impl FnOnce(u8) -> u8) {}
923
924fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
925 move |x: u8| f(x) * 2
926}
927"#,
928 );
929 }
930
931 #[test]
932 fn skip_closure_parameter_hints() {
933 check_with_config(
934 InlayHintsConfig {
935 type_hints: true,
936 hide_closure_parameter_hints: true,
937 ..DISABLED_CONFIG
938 },
939 r#"
940//- minicore: fn
941struct Foo;
942impl Foo {
943 fn foo(self: Self) {}
944 fn bar(self: &Self) {}
945}
946fn main() {
947 let closure = |x, y| x + y;
948 // ^^^^^^^ impl Fn(i32, i32) -> {unknown}
949 closure(2, 3);
950 let point = (10, 20);
951 // ^^^^^ (i32, i32)
952 let (x, y) = point;
953 // ^ i32 ^ i32
954 Foo::foo(Foo);
955 Foo::bar(&Foo);
956}
957"#,
958 );
959 }
960
961 #[test]
962 fn hint_truncation() {
963 check_with_config(
964 InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
965 r#"
966struct Smol<T>(T);
967
968struct VeryLongOuterName<T>(T);
969
970fn main() {
971 let a = Smol(0u32);
972 //^ Smol<u32>
973 let b = VeryLongOuterName(0usize);
974 //^ VeryLongOuterName<…>
975 let c = Smol(Smol(0u32))
976 //^ Smol<Smol<…>>
977}"#,
978 );
979 }
980
981 #[test]
982 fn edit_for_let_stmt() {
983 check_edit(
984 TEST_CONFIG,
985 r#"
986struct S<T>(T);
987fn test<F>(v: S<(S<i32>, S<()>)>, f: F) {
988 let a = v;
989 let S((b, c)) = v;
990 let a @ S((b, c)) = v;
991 let a = f;
992}
993"#,
994 expect![[r#"
995 struct S<T>(T);
996 fn test<F>(v: S<(S<i32>, S<()>)>, f: F) {
997 let a: S<(S<i32>, S<()>)> = v;
998 let S((b, c)) = v;
999 let a @ S((b, c)): S<(S<i32>, S<()>)> = v;
1000 let a: F = f;
1001 }
1002 "#]],
1003 );
1004 }
1005
1006 #[test]
1007 fn edit_for_closure_param() {
1008 check_edit(
1009 TEST_CONFIG,
1010 r#"
1011fn test<T>(t: T) {
1012 let f = |a, b, c| {};
1013 let result = f(42, "", t);
1014}
1015"#,
1016 expect![[r#"
1017 fn test<T>(t: T) {
1018 let f = |a: i32, b: &str, c: T| {};
1019 let result: () = f(42, "", t);
1020 }
1021 "#]],
1022 );
1023 }
1024
1025 #[test]
1026 fn edit_for_closure_ret() {
1027 check_edit(
1028 TEST_CONFIG,
1029 r#"
1030struct S<T>(T);
1031fn test() {
1032 let f = || { 3 };
1033 let f = |a: S<usize>| { S(a) };
1034}
1035"#,
1036 expect![[r#"
1037 struct S<T>(T);
1038 fn test() {
1039 let f = || -> i32 { 3 };
1040 let f = |a: S<usize>| -> S<S<usize>> { S(a) };
1041 }
1042 "#]],
1043 );
1044 }
1045
1046 #[test]
1047 fn edit_prefixes_paths() {
1048 check_edit(
1049 TEST_CONFIG,
1050 r#"
1051pub struct S<T>(T);
1052mod middle {
1053 pub struct S<T, U>(T, U);
1054 pub fn make() -> S<inner::S<i64>, super::S<usize>> { loop {} }
1055
1056 mod inner {
1057 pub struct S<T>(T);
1058 }
1059
1060 fn test() {
1061 let a = make();
1062 }
1063}
1064"#,
1065 expect![[r#"
1066 pub struct S<T>(T);
1067 mod middle {
1068 pub struct S<T, U>(T, U);
1069 pub fn make() -> S<inner::S<i64>, super::S<usize>> { loop {} }
1070
1071 mod inner {
1072 pub struct S<T>(T);
1073 }
1074
1075 fn test() {
1076 let a: S<inner::S<i64>, crate::S<usize>> = make();
1077 }
1078 }
1079 "#]],
1080 );
1081 }
1082
1083 #[test]
1084 fn no_edit_for_top_pat_where_type_annotation_is_invalid() {
1085 check_no_edit(
1086 TEST_CONFIG,
1087 r#"
1088fn test() {
1089 if let a = 42 {}
1090 while let a = 42 {}
1091 match 42 {
1092 a => (),
1093 }
1094}
1095"#,
1096 )
1097 }
1098
1099 #[test]
1100 fn no_edit_for_opaque_type() {
1101 check_no_edit(
1102 TEST_CONFIG,
1103 r#"
1104trait Trait {}
1105struct S<T>(T);
1106fn foo() -> impl Trait {}
1107fn bar() -> S<impl Trait> {}
1108fn test() {
1109 let a = foo();
1110 let a = bar();
1111 let f = || { foo() };
1112 let f = || { bar() };
1113}
1114"#,
1115 );
1116 }
1117
1118 #[test]
1119 fn no_edit_for_closure_return_without_body_block() {
1120 let config = InlayHintsConfig {
1121 closure_return_type_hints: ClosureReturnTypeHints::Always,
1122 ..TEST_CONFIG
1123 };
1124 check_edit(
1125 config,
1126 r#"
1127struct S<T>(T);
1128fn test() {
1129 let f = || 3;
1130 let f = |a: S<usize>| S(a);
1131}
1132"#,
1133 expect![[r#"
1134 struct S<T>(T);
1135 fn test() {
1136 let f = || -> i32 { 3 };
1137 let f = |a: S<usize>| -> S<S<usize>> { S(a) };
1138 }
1139 "#]],
1140 );
1141 }
1142
1143 #[test]
1144 fn type_hints_async_block() {
1145 check_types(
1146 r#"
1147//- minicore: future
1148async fn main() {
1149 let _x = async { 8_i32 };
1150 //^^ impl Future<Output = i32>
1151}"#,
1152 );
1153 }
1154
1155 #[test]
1156 fn type_hints_async_block_with_tail_return_exp() {
1157 check_types(
1158 r#"
1159//- minicore: future
1160async fn main() {
1161 let _x = async {
1162 //^^ impl Future<Output = i32>
1163 return 8_i32;
1164 };
1165}"#,
1166 );
1167 }
1168
1169 #[test]
1170 fn works_in_included_file() {
1171 check_types(
1172 r#"
1173//- minicore: include
1174//- /main.rs
1175include!("foo.rs");
1176//- /foo.rs
1177fn main() {
1178 let _x = 42;
1179 //^^ i32
1180}"#,
1181 );
1182 }
1183
1184 #[test]
1185 fn collapses_nested_impl_projections() {
1186 check_types(
1187 r#"
1188//- minicore: sized
1189trait T {
1190 type Assoc;
1191 fn f(self) -> Self::Assoc;
1192}
1193
1194trait T2 {}
1195trait T3<T> {}
1196
1197fn f(it: impl T<Assoc: T2>) {
1198 let l = it.f();
1199 // ^ impl T2
1200}
1201
1202fn f2<G: T<Assoc: T2 + 'static>>(it: G) {
1203 let l = it.f();
1204 //^ impl T2 + 'static
1205}
1206
1207fn f3<G: T>(it: G) where <G as T>::Assoc: T2 {
1208 let l = it.f();
1209 //^ impl T2
1210}
1211
1212fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) {
1213 let l = it.f();
1214 //^ impl T2 + T3<()>
1215}
1216
1217fn f5<G: T<Assoc = ()>>(it: G) {
1218 let l = it.f();
1219 //^ ()
1220}
1221"#,
1222 );
1223 }
1224
1225 #[test]
1226 fn regression_19007() {
1227 check_types(
1228 r#"
1229trait Foo {
1230 type Assoc;
1231
1232 fn foo(&self) -> Self::Assoc;
1233}
1234
1235trait Bar {
1236 type Target;
1237}
1238
1239trait Baz<T> {}
1240
1241struct Struct<T: Foo> {
1242 field: T,
1243}
1244
1245impl<T> Struct<T>
1246where
1247 T: Foo,
1248 T::Assoc: Baz<<T::Assoc as Bar>::Target> + Bar,
1249{
1250 fn f(&self) {
1251 let x = self.field.foo();
1252 //^ impl Baz<<<T as Foo>::Assoc as Bar>::Target> + Bar
1253 }
1254}
1255"#,
1256 );
1257 }
1258}