ide/inlay_hints/
bind_pat.rs

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//! ```
6use 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    // unwrap postfix expressions
137    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    // This module also contains tests for super::closure_ret
177
178    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        // Ensure we don't crash while solving the projection type of iterators.
280        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}