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