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_expect, check_no_edit,
187        check_with_config,
188    };
189
190    #[track_caller]
191    fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
192        check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture);
193    }
194
195    #[test]
196    fn type_hints_only() {
197        check_types(
198            r#"
199fn foo(a: i32, b: i32) -> i32 { a + b }
200fn main() {
201    let _x = foo(4, 4);
202      //^^ i32
203}"#,
204        );
205    }
206
207    #[test]
208    fn type_hints_bindings_after_at() {
209        check_types(
210            r#"
211//- minicore: option
212fn main() {
213    let ref foo @ bar @ ref mut baz = 0;
214          //^^^ &i32
215                //^^^ i32
216                              //^^^ &mut i32
217    let [x @ ..] = [0];
218       //^ [i32; 1]
219    if let x @ Some(_) = Some(0) {}
220         //^ Option<i32>
221    let foo @ (bar, baz) = (3, 3);
222      //^^^ (i32, i32)
223             //^^^ i32
224                  //^^^ i32
225}"#,
226        );
227    }
228
229    #[test]
230    fn default_generic_types_should_not_be_displayed() {
231        check(
232            r#"
233struct Test<K, T = u8> { k: K, t: T }
234
235fn main() {
236    let zz = Test { t: 23u8, k: 33 };
237      //^^ Test<i32>
238    let zz_ref = &zz;
239      //^^^^^^ &Test<i32>
240    let test = || zz;
241      //^^^^ impl FnOnce() -> Test<i32>
242}"#,
243        );
244    }
245
246    #[test]
247    fn shorten_iterators_in_associated_params() {
248        check_types(
249            r#"
250//- minicore: iterators
251use core::iter;
252
253pub struct SomeIter<T> {}
254
255impl<T> SomeIter<T> {
256    pub fn new() -> Self { SomeIter {} }
257    pub fn push(&mut self, t: T) {}
258}
259
260impl<T> Iterator for SomeIter<T> {
261    type Item = T;
262    fn next(&mut self) -> Option<Self::Item> {
263        None
264    }
265}
266
267fn main() {
268    let mut some_iter = SomeIter::new();
269          //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
270      some_iter.push(iter::repeat(2).take(2));
271    let iter_of_iters = some_iter.take(2);
272      //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
273}
274"#,
275        );
276    }
277
278    #[test]
279    fn iterator_hint_regression_issue_12674() {
280        // Ensure we don't crash while solving the projection type of iterators.
281        let (analysis, file_id) = fixture::file(
282            r#"
283//- minicore: iterators
284struct S<T>(T);
285impl<T> S<T> {
286    fn iter(&self) -> Iter<'_, T> { loop {} }
287}
288struct Iter<'a, T: 'a>(&'a T);
289impl<'a, T> Iterator for Iter<'a, T> {
290    type Item = &'a T;
291    fn next(&mut self) -> Option<Self::Item> { loop {} }
292}
293struct Container<'a> {
294    elements: S<&'a str>,
295}
296struct SliceIter<'a, T>(&'a T);
297impl<'a, T> Iterator for SliceIter<'a, T> {
298    type Item = &'a T;
299    fn next(&mut self) -> Option<Self::Item> { loop {} }
300}
301
302fn main(a: SliceIter<'_, Container>) {
303    a
304        .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
305        .map(|e| e);
306}
307"#,
308        );
309        analysis
310            .inlay_hints(
311                &InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
312                file_id,
313                None,
314            )
315            .unwrap();
316    }
317
318    #[test]
319    fn infer_call_method_return_associated_types_with_generic() {
320        check_types(
321            r#"
322            pub trait Default {
323                fn default() -> Self;
324            }
325            pub trait Foo {
326                type Bar: Default;
327            }
328
329            pub fn quux<T: Foo>() -> T::Bar {
330                let y = Default::default();
331                  //^ <T as Foo>::Bar
332
333                y
334            }
335            "#,
336        );
337    }
338
339    #[test]
340    fn lt_hints() {
341        check_types(
342            r#"
343struct S<'lt>(*mut &'lt ());
344
345fn f<'a>() {
346    let x = S::<'static>(loop {});
347      //^ S<'static>
348    let y = S::<'_>(loop {});
349      //^ S<'_>
350    let z = S::<'a>(loop {});
351      //^ S<'a>
352
353}
354"#,
355        );
356    }
357
358    #[test]
359    fn fn_hints() {
360        check_types(
361            r#"
362//- minicore: fn, sized
363fn foo() -> impl Fn() { loop {} }
364fn foo1() -> impl Fn(f64) { loop {} }
365fn foo2() -> impl Fn(f64, f64) { loop {} }
366fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
367fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
368fn foo5() -> &'static for<'a> dyn Fn(&'a dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
369fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
370fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
371
372fn main() {
373    let foo = foo();
374     // ^^^ impl Fn()
375    let foo = foo1();
376     // ^^^ impl Fn(f64)
377    let foo = foo2();
378     // ^^^ impl Fn(f64, f64)
379    let foo = foo3();
380     // ^^^ impl Fn(f64, f64) -> u32
381    let foo = foo4();
382     // ^^^ &dyn Fn(f64, f64) -> u32
383    let foo = foo5();
384     // ^^^ &dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32
385    let foo = foo6();
386     // ^^^ impl Fn(f64, f64) -> u32
387    let foo = foo7();
388     // ^^^ *const impl Fn(f64, f64) -> u32
389}
390"#,
391        )
392    }
393
394    #[test]
395    fn check_hint_range_limit() {
396        let fixture = r#"
397//- minicore: fn, sized
398fn foo() -> impl Fn() { loop {} }
399fn foo1() -> impl Fn(f64) { loop {} }
400fn foo2() -> impl Fn(f64, f64) { loop {} }
401fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
402fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
403fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
404fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
405fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
406
407fn main() {
408    let foo = foo();
409    let foo = foo1();
410    let foo = foo2();
411     // ^^^ impl Fn(f64, f64)
412    let foo = foo3();
413     // ^^^ impl Fn(f64, f64) -> u32
414    let foo = foo4();
415     // ^^^ &dyn Fn(f64, f64) -> u32
416    let foo = foo5();
417    let foo = foo6();
418    let foo = foo7();
419}
420"#;
421        let (analysis, file_id) = fixture::file(fixture);
422        let expected = extract_annotations(&analysis.file_text(file_id).unwrap());
423        let inlay_hints = analysis
424            .inlay_hints(
425                &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
426                file_id,
427                Some(TextRange::new(TextSize::from(491), TextSize::from(640))),
428            )
429            .unwrap();
430        let actual =
431            inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
432        assert_eq!(expected, actual, "\nExpected:\n{expected:#?}\n\nActual:\n{actual:#?}");
433    }
434
435    #[test]
436    fn fn_hints_ptr_rpit_fn_parentheses() {
437        check_types(
438            r#"
439//- minicore: fn, sized
440trait Trait {}
441
442fn foo1() -> *const impl Fn() { loop {} }
443fn foo2() -> *const (impl Fn() + Sized) { loop {} }
444fn foo3() -> *const (impl Fn() + ?Sized) { loop {} }
445fn foo4() -> *const (impl Sized + Fn()) { loop {} }
446fn foo5() -> *const (impl ?Sized + Fn()) { loop {} }
447fn foo6() -> *const (impl Fn() + Trait) { loop {} }
448fn foo7() -> *const (impl Fn() + Sized + Trait) { loop {} }
449fn foo8() -> *const (impl Fn() + ?Sized + Trait) { loop {} }
450fn foo9() -> *const (impl Fn() -> u8 + ?Sized) { loop {} }
451fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
452
453fn main() {
454    let foo = foo1();
455    //  ^^^ *const impl Fn()
456    let foo = foo2();
457    //  ^^^ *const impl Fn()
458    let foo = foo3();
459    //  ^^^ *const (impl Fn() + ?Sized)
460    let foo = foo4();
461    //  ^^^ *const impl Fn()
462    let foo = foo5();
463    //  ^^^ *const (impl Fn() + ?Sized)
464    let foo = foo6();
465    //  ^^^ *const (impl Fn() + Trait)
466    let foo = foo7();
467    //  ^^^ *const (impl Fn() + Trait)
468    let foo = foo8();
469    //  ^^^ *const (impl Fn() + Trait + ?Sized)
470    let foo = foo9();
471    //  ^^^ *const (impl Fn() -> u8 + ?Sized)
472    let foo = foo10();
473    //  ^^^ *const impl Fn()
474}
475"#,
476        )
477    }
478
479    #[test]
480    fn unit_structs_have_no_type_hints() {
481        check_types(
482            r#"
483//- minicore: result
484struct SyntheticSyntax;
485
486fn main() {
487    match Ok(()) {
488        Ok(_) => (),
489        Err(SyntheticSyntax) => (),
490    }
491}"#,
492        );
493    }
494
495    #[test]
496    fn const_pats_have_no_type_hints() {
497        check_types(
498            r#"
499const FOO: usize = 0;
500
501fn main() {
502    match 0 {
503        FOO => (),
504        _ => ()
505    }
506}"#,
507        );
508    }
509
510    #[test]
511    fn let_statement() {
512        check_types(
513            r#"
514#[derive(PartialEq)]
515enum Option<T> { None, Some(T) }
516
517#[derive(PartialEq)]
518struct Test { a: Option<u32>, b: u8 }
519
520fn main() {
521    struct InnerStruct {}
522
523    let test = 54;
524      //^^^^ i32
525    let test: i32 = 33;
526    let mut test = 33;
527          //^^^^ i32
528    let _ = 22;
529    let test = "test";
530      //^^^^ &str
531    let test = InnerStruct {};
532      //^^^^ InnerStruct
533
534    let test = unresolved();
535
536    let test = (42, 'a');
537      //^^^^ (i32, char)
538    let (a,    (b,     (c,)) = (2, (3, (9.2,));
539       //^ i32  ^ i32   ^ f64
540    let &x = &92;
541       //^ i32
542}"#,
543        );
544    }
545
546    #[test]
547    fn if_expr() {
548        check_types(
549            r#"
550//- minicore: option
551struct Test { a: Option<u32>, b: u8 }
552
553fn main() {
554
555}"#,
556        );
557    }
558
559    #[test]
560    fn while_expr() {
561        check_types(
562            r#"
563//- minicore: option
564struct Test { a: Option<u32>, b: u8 }
565
566fn main() {
567    let test = Some(Test { a: Some(3), b: 1 });
568      //^^^^ Option<Test>
569    while let Some(Test { a: Some(x),    b: y }) = &test {};
570                                //^ &u32    ^ &u8
571}"#,
572        );
573    }
574
575    #[test]
576    fn match_arm_list() {
577        check_types(
578            r#"
579//- minicore: option
580struct Test { a: Option<u32>, b: u8 }
581
582fn main() {
583    match Some(Test { a: Some(3), b: 1 }) {
584        None => (),
585        test => (),
586      //^^^^ Option<Test>
587        Some(Test { a: Some(x), b: y }) => (),
588                          //^ u32  ^ u8
589        _ => {}
590    }
591}"#,
592        );
593    }
594
595    #[test]
596    fn complete_for_hint() {
597        check_types(
598            r#"
599//- minicore: iterator
600pub struct Vec<T> {}
601
602impl<T> Vec<T> {
603    pub fn new() -> Self { Vec {} }
604    pub fn push(&mut self, t: T) {}
605}
606
607impl<T> IntoIterator for Vec<T> {
608    type Item = T;
609    type IntoIter = IntoIter<T>;
610}
611
612struct IntoIter<T> {}
613
614impl<T> Iterator for IntoIter<T> {
615    type Item = T;
616}
617
618fn main() {
619    let mut data = Vec::new();
620          //^^^^ Vec<&str>
621    data.push("foo");
622    for i in data {
623      //^ &str
624      let z = i;
625        //^ &str
626    }
627}
628"#,
629        );
630    }
631
632    #[test]
633    fn multi_dyn_trait_bounds() {
634        check_types(
635            r#"
636pub struct Vec<T>(*mut T);
637
638impl<T> Vec<T> {
639    pub fn new() -> Self { Vec(0 as *mut T) }
640}
641
642pub struct Box<T> {}
643
644trait Display {}
645auto trait Sync {}
646
647fn main() {
648    // The block expression wrapping disables the constructor hint hiding logic
649    let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
650      //^^ Vec<Box<&(dyn Display + Sync + 'static)>>
651    let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
652      //^^ Vec<Box<*const (dyn Display + Sync + 'static)>>
653    let _v = { Vec::<Box<dyn Display + Sync + 'static>>::new() };
654      //^^ Vec<Box<dyn Display + Sync + 'static>>
655}
656"#,
657        );
658    }
659
660    #[test]
661    fn shorten_iterator_hints() {
662        check_types(
663            r#"
664//- minicore: iterators
665use core::iter;
666
667struct MyIter;
668
669impl Iterator for MyIter {
670    type Item = ();
671    fn next(&mut self) -> Option<Self::Item> {
672        None
673    }
674}
675
676fn main() {
677    let _x = MyIter;
678      //^^ MyIter
679    let _x = iter::repeat(0);
680      //^^ impl Iterator<Item = i32>
681    fn generic<T: Clone>(t: T) {
682        let _x = iter::repeat(t);
683          //^^ impl Iterator<Item = T>
684        let _chained = iter::repeat(t).take(10);
685          //^^^^^^^^ impl Iterator<Item = T>
686    }
687}
688"#,
689        );
690    }
691
692    #[test]
693    fn skip_constructor_and_enum_type_hints() {
694        check_with_config(
695            InlayHintsConfig {
696                type_hints: true,
697                hide_named_constructor_hints: true,
698                ..DISABLED_CONFIG
699            },
700            r#"
701//- minicore: try, option
702use core::ops::ControlFlow;
703
704mod x {
705    pub mod y { pub struct Foo; }
706    pub struct Foo;
707    pub enum AnotherEnum {
708        Variant()
709    };
710}
711struct Struct;
712struct TupleStruct();
713
714impl Struct {
715    fn new() -> Self {
716        Struct
717    }
718    fn try_new() -> ControlFlow<(), Self> {
719        ControlFlow::Continue(Struct)
720    }
721}
722
723struct Generic<T>(T);
724impl Generic<i32> {
725    fn new() -> Self {
726        Generic(0)
727    }
728}
729
730enum Enum {
731    Variant(u32)
732}
733
734fn times2(value: i32) -> i32 {
735    2 * value
736}
737
738fn main() {
739    let enumb = Enum::Variant(0);
740
741    let strukt = x::Foo;
742    let strukt = x::y::Foo;
743    let strukt = Struct;
744    let strukt = Struct::new();
745
746    let tuple_struct = TupleStruct();
747
748    let generic0 = Generic::new();
749    //  ^^^^^^^^ Generic<i32>
750    let generic1 = Generic(0);
751    //  ^^^^^^^^ Generic<i32>
752    let generic2 = Generic::<i32>::new();
753    let generic3 = <Generic<i32>>::new();
754    let generic4 = Generic::<i32>(0);
755
756
757    let option = Some(0);
758    //  ^^^^^^ Option<i32>
759    let func = times2;
760    //  ^^^^ fn times2(i32) -> i32
761    let closure = |x: i32| x * 2;
762    //  ^^^^^^^ impl Fn(i32) -> i32
763}
764
765fn fallible() -> ControlFlow<()> {
766    let strukt = Struct::try_new()?;
767}
768"#,
769        );
770    }
771
772    #[test]
773    fn shows_constructor_type_hints_when_enabled() {
774        check_types(
775            r#"
776//- minicore: try
777use core::ops::ControlFlow;
778
779struct Struct;
780struct TupleStruct();
781
782impl Struct {
783    fn new() -> Self {
784        Struct
785    }
786    fn try_new() -> ControlFlow<(), Self> {
787        ControlFlow::Continue(Struct)
788    }
789}
790
791struct Generic<T>(T);
792impl Generic<i32> {
793    fn new() -> Self {
794        Generic(0)
795    }
796}
797
798fn main() {
799    let strukt = Struct::new();
800     // ^^^^^^ Struct
801    let tuple_struct = TupleStruct();
802     // ^^^^^^^^^^^^ TupleStruct
803    let generic0 = Generic::new();
804     // ^^^^^^^^ Generic<i32>
805    let generic1 = Generic::<i32>::new();
806     // ^^^^^^^^ Generic<i32>
807    let generic2 = <Generic<i32>>::new();
808     // ^^^^^^^^ Generic<i32>
809}
810
811fn fallible() -> ControlFlow<()> {
812    let strukt = Struct::try_new()?;
813     // ^^^^^^ Struct
814}
815"#,
816        );
817    }
818
819    #[test]
820    fn closure_style() {
821        check_with_config(
822            InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
823            r#"
824//- minicore: fn
825fn main() {
826    let x = || 2;
827      //^ impl Fn() -> i32
828    let y = |t: i32| x() + t;
829      //^ impl Fn(i32) -> i32
830    let mut t = 5;
831          //^ i32
832    let z = |k: i32| { t += k; };
833      //^ impl FnMut(i32)
834    let p = (y, z);
835      //^ (impl Fn(i32) -> i32, impl FnMut(i32))
836}
837            "#,
838        );
839        check_with_config(
840            InlayHintsConfig {
841                type_hints: true,
842                closure_style: ClosureStyle::RANotation,
843                ..DISABLED_CONFIG
844            },
845            r#"
846//- minicore: fn
847fn main() {
848    let x = || 2;
849      //^ || -> i32
850    let y = |t: i32| x() + t;
851      //^ |i32| -> i32
852    let mut t = 5;
853          //^ i32
854    let z = |k: i32| { t += k; };
855      //^ |i32| -> ()
856    let p = (y, z);
857      //^ (|i32| -> i32, |i32| -> ())
858}
859            "#,
860        );
861        check_with_config(
862            InlayHintsConfig {
863                type_hints: true,
864                closure_style: ClosureStyle::Hide,
865                ..DISABLED_CONFIG
866            },
867            r#"
868//- minicore: fn
869fn main() {
870    let x = || 2;
871      //^ …
872    let y = |t: i32| x() + t;
873      //^ …
874    let mut t = 5;
875          //^ i32
876    let z = |k: i32| { t += k; };
877      //^ …
878    let p = (y, z);
879      //^ (…, …)
880}
881            "#,
882        );
883    }
884
885    #[test]
886    fn skip_closure_type_hints() {
887        check_with_config(
888            InlayHintsConfig {
889                type_hints: true,
890                hide_closure_initialization_hints: true,
891                ..DISABLED_CONFIG
892            },
893            r#"
894//- minicore: fn
895fn main() {
896    let multiple_2 = |x: i32| { x * 2 };
897
898    let multiple_2 = |x: i32| x * 2;
899    //  ^^^^^^^^^^ impl Fn(i32) -> i32
900
901    let (not) = (|x: bool| { !x });
902    //   ^^^ impl Fn(bool) -> bool
903
904    let (is_zero, _b) = (|x: usize| { x == 0 }, false);
905    //   ^^^^^^^ impl Fn(usize) -> bool
906    //            ^^ bool
907
908    let plus_one = |x| { x + 1 };
909    //              ^ u8
910    foo(plus_one);
911
912    let add_mul = bar(|x: u8| { x + 1 });
913    //  ^^^^^^^ impl FnOnce(u8) -> u8
914
915    let closure = if let Some(6) = add_mul(2).checked_sub(1) {
916    //  ^^^^^^^ fn(i32) -> i32
917        |x: i32| { x * 2 }
918    } else {
919        |x: i32| { x * 3 }
920    };
921}
922
923fn foo(f: impl FnOnce(u8) -> u8) {}
924
925fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
926    move |x: u8| f(x) * 2
927}
928"#,
929        );
930    }
931
932    #[test]
933    fn skip_closure_parameter_hints() {
934        check_with_config(
935            InlayHintsConfig {
936                type_hints: true,
937                hide_closure_parameter_hints: true,
938                ..DISABLED_CONFIG
939            },
940            r#"
941//- minicore: fn
942struct Foo;
943impl Foo {
944    fn foo(self: Self) {}
945    fn bar(self: &Self) {}
946}
947fn main() {
948    let closure = |x, y| x + y;
949    //  ^^^^^^^ impl Fn(i32, i32) -> {unknown}
950    closure(2, 3);
951    let point = (10, 20);
952    //  ^^^^^ (i32, i32)
953    let (x,      y) = point;
954      // ^ i32   ^ i32
955    Foo::foo(Foo);
956    Foo::bar(&Foo);
957}
958"#,
959        );
960    }
961
962    #[test]
963    fn hint_truncation() {
964        check_with_config(
965            InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG },
966            r#"
967struct Smol<T>(T);
968
969struct VeryLongOuterName<T>(T);
970
971fn main() {
972    let a = Smol(0u32);
973      //^ Smol<u32>
974    let b = VeryLongOuterName(0usize);
975      //^ VeryLongOuterName<…>
976    let c = Smol(Smol(0u32))
977      //^ Smol<Smol<…>>
978}"#,
979        );
980    }
981
982    #[test]
983    fn edit_for_let_stmt() {
984        check_edit(
985            TEST_CONFIG,
986            r#"
987struct S<T>(T);
988fn test<F>(v: S<(S<i32>, S<()>)>, f: F) {
989    let a = v;
990    let S((b, c)) = v;
991    let a @ S((b, c)) = v;
992    let a = f;
993}
994"#,
995            expect![[r#"
996                struct S<T>(T);
997                fn test<F>(v: S<(S<i32>, S<()>)>, f: F) {
998                    let a: S<(S<i32>, S<()>)> = v;
999                    let S((b, c)) = v;
1000                    let a @ S((b, c)): S<(S<i32>, S<()>)> = v;
1001                    let a: F = f;
1002                }
1003            "#]],
1004        );
1005    }
1006
1007    #[test]
1008    fn edit_for_closure_param() {
1009        check_edit(
1010            TEST_CONFIG,
1011            r#"
1012fn test<T>(t: T) {
1013    let f = |a, b, c| {};
1014    let result = f(42, "", t);
1015}
1016"#,
1017            expect![[r#"
1018                fn test<T>(t: T) {
1019                    let f = |a: i32, b: &str, c: T| {};
1020                    let result: () = f(42, "", t);
1021                }
1022            "#]],
1023        );
1024    }
1025
1026    #[test]
1027    fn edit_for_closure_ret() {
1028        check_edit(
1029            TEST_CONFIG,
1030            r#"
1031struct S<T>(T);
1032fn test() {
1033    let f = || { 3 };
1034    let f = |a: S<usize>| { S(a) };
1035}
1036"#,
1037            expect![[r#"
1038                struct S<T>(T);
1039                fn test() {
1040                    let f = || -> i32 { 3 };
1041                    let f = |a: S<usize>| -> S<S<usize>> { S(a) };
1042                }
1043            "#]],
1044        );
1045    }
1046
1047    #[test]
1048    fn edit_prefixes_paths() {
1049        check_edit(
1050            TEST_CONFIG,
1051            r#"
1052pub struct S<T>(T);
1053mod middle {
1054    pub struct S<T, U>(T, U);
1055    pub fn make() -> S<inner::S<i64>, super::S<usize>> { loop {} }
1056
1057    mod inner {
1058        pub struct S<T>(T);
1059    }
1060
1061    fn test() {
1062        let a = make();
1063    }
1064}
1065"#,
1066            expect![[r#"
1067                pub struct S<T>(T);
1068                mod middle {
1069                    pub struct S<T, U>(T, U);
1070                    pub fn make() -> S<inner::S<i64>, super::S<usize>> { loop {} }
1071
1072                    mod inner {
1073                        pub struct S<T>(T);
1074                    }
1075
1076                    fn test() {
1077                        let a: S<inner::S<i64>, crate::S<usize>> = make();
1078                    }
1079                }
1080            "#]],
1081        );
1082    }
1083
1084    #[test]
1085    fn no_edit_for_top_pat_where_type_annotation_is_invalid() {
1086        check_no_edit(
1087            TEST_CONFIG,
1088            r#"
1089fn test() {
1090    if let a = 42 {}
1091    while let a = 42 {}
1092    match 42 {
1093        a => (),
1094    }
1095}
1096"#,
1097        )
1098    }
1099
1100    #[test]
1101    fn no_edit_for_opaque_type() {
1102        check_no_edit(
1103            TEST_CONFIG,
1104            r#"
1105trait Trait {}
1106struct S<T>(T);
1107fn foo() -> impl Trait {}
1108fn bar() -> S<impl Trait> {}
1109fn test() {
1110    let a = foo();
1111    let a = bar();
1112    let f = || { foo() };
1113    let f = || { bar() };
1114}
1115"#,
1116        );
1117    }
1118
1119    #[test]
1120    fn no_edit_for_closure_return_without_body_block() {
1121        let config = InlayHintsConfig {
1122            closure_return_type_hints: ClosureReturnTypeHints::Always,
1123            ..TEST_CONFIG
1124        };
1125        check_edit(
1126            config,
1127            r#"
1128struct S<T>(T);
1129fn test() {
1130    let f = || 3;
1131    let f = |a: S<usize>| S(a);
1132}
1133"#,
1134            expect![[r#"
1135            struct S<T>(T);
1136            fn test() {
1137                let f = || -> i32 { 3 };
1138                let f = |a: S<usize>| -> S<S<usize>> { S(a) };
1139            }
1140            "#]],
1141        );
1142    }
1143
1144    #[test]
1145    fn type_hints_async_block() {
1146        check_types(
1147            r#"
1148//- minicore: future
1149async fn main() {
1150    let _x = async { 8_i32 };
1151      //^^ impl Future<Output = i32>
1152}"#,
1153        );
1154    }
1155
1156    #[test]
1157    fn type_hints_async_block_with_tail_return_exp() {
1158        check_types(
1159            r#"
1160//- minicore: future
1161async fn main() {
1162    let _x = async {
1163      //^^ impl Future<Output = i32>
1164        return 8_i32;
1165    };
1166}"#,
1167        );
1168    }
1169
1170    #[test]
1171    fn works_in_included_file() {
1172        check_types(
1173            r#"
1174//- minicore: include
1175//- /main.rs
1176include!("foo.rs");
1177//- /foo.rs
1178fn main() {
1179    let _x = 42;
1180      //^^ i32
1181}"#,
1182        );
1183    }
1184
1185    #[test]
1186    fn collapses_nested_impl_projections() {
1187        check_types(
1188            r#"
1189//- minicore: sized
1190trait T {
1191    type Assoc;
1192    fn f(self) -> Self::Assoc;
1193}
1194
1195trait T2 {}
1196trait T3<T> {}
1197
1198fn f(it: impl T<Assoc: T2>) {
1199    let l = it.f();
1200     // ^ impl T2
1201}
1202
1203fn f2<G: T<Assoc: T2 + 'static>>(it: G) {
1204    let l = it.f();
1205      //^ impl T2 + 'static
1206}
1207
1208fn f3<G: T>(it: G) where <G as T>::Assoc: T2 {
1209    let l = it.f();
1210      //^ impl T2
1211}
1212
1213fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) {
1214    let l = it.f();
1215      //^ impl T2 + T3<()>
1216}
1217
1218fn f5<G: T<Assoc = ()>>(it: G) {
1219    let l = it.f();
1220      //^ ()
1221}
1222"#,
1223        );
1224    }
1225
1226    #[test]
1227    fn regression_19007() {
1228        check_types(
1229            r#"
1230trait Foo {
1231    type Assoc;
1232
1233    fn foo(&self) -> Self::Assoc;
1234}
1235
1236trait Bar {
1237    type Target;
1238}
1239
1240trait Baz<T> {}
1241
1242struct Struct<T: Foo> {
1243    field: T,
1244}
1245
1246impl<T> Struct<T>
1247where
1248    T: Foo,
1249    T::Assoc: Baz<<T::Assoc as Bar>::Target> + Bar,
1250{
1251    fn f(&self) {
1252        let x = self.field.foo();
1253          //^ impl Baz<<<T as Foo>::Assoc as Bar>::Target> + Bar
1254    }
1255}
1256"#,
1257        );
1258    }
1259
1260    #[test]
1261    fn type_param_inlay_hint_has_location_link() {
1262        check_expect(
1263            InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
1264            r#"
1265fn identity<T>(t: T) -> T {
1266    let x = t;
1267    x
1268}
1269"#,
1270            expect![[r#"
1271                [
1272                    (
1273                        36..37,
1274                        [
1275                            InlayHintLabelPart {
1276                                text: "T",
1277                                linked_location: Some(
1278                                    Computed(
1279                                        FileRangeWrapper {
1280                                            file_id: FileId(
1281                                                0,
1282                                            ),
1283                                            range: 12..13,
1284                                        },
1285                                    ),
1286                                ),
1287                                tooltip: "",
1288                            },
1289                        ],
1290                    ),
1291                ]
1292            "#]],
1293        );
1294    }
1295
1296    #[test]
1297    fn const_param_inlay_hint_has_location_link() {
1298        check_expect(
1299            InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
1300            r#"
1301fn f<const N: usize>() {
1302    let x = [0; N];
1303}
1304"#,
1305            expect![[r#"
1306                [
1307                    (
1308                        33..34,
1309                        [
1310                            "[i32; ",
1311                            InlayHintLabelPart {
1312                                text: "N",
1313                                linked_location: Some(
1314                                    Computed(
1315                                        FileRangeWrapper {
1316                                            file_id: FileId(
1317                                                0,
1318                                            ),
1319                                            range: 11..12,
1320                                        },
1321                                    ),
1322                                ),
1323                                tooltip: "",
1324                            },
1325                            "]",
1326                        ],
1327                    ),
1328                ]
1329            "#]],
1330        );
1331    }
1332
1333    #[test]
1334    fn lifetime_param_inlay_hint_has_location_link() {
1335        check_expect(
1336            InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
1337            r#"
1338struct S<'lt>(*mut &'lt ());
1339
1340fn f<'a>() {
1341    let x = S::<'a>(loop {});
1342}
1343"#,
1344            expect![[r#"
1345                [
1346                    (
1347                        51..52,
1348                        [
1349                            InlayHintLabelPart {
1350                                text: "S",
1351                                linked_location: Some(
1352                                    Computed(
1353                                        FileRangeWrapper {
1354                                            file_id: FileId(
1355                                                0,
1356                                            ),
1357                                            range: 7..8,
1358                                        },
1359                                    ),
1360                                ),
1361                                tooltip: "",
1362                            },
1363                            "<",
1364                            InlayHintLabelPart {
1365                                text: "'a",
1366                                linked_location: Some(
1367                                    Computed(
1368                                        FileRangeWrapper {
1369                                            file_id: FileId(
1370                                                0,
1371                                            ),
1372                                            range: 35..37,
1373                                        },
1374                                    ),
1375                                ),
1376                                tooltip: "",
1377                            },
1378                            ">",
1379                        ],
1380                    ),
1381                ]
1382            "#]],
1383        );
1384    }
1385}