]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / src / tools / rust-analyzer / crates / ide / src / inlay_hints / adjustment.rs
CommitLineData
9c376795
FG
1//! Implementation of "adjustment" inlay hints:
2//! ```no_run
3//! let _: u32 = /* <never-to-any> */ loop {};
4//! let _: &u32 = /* &* */ &mut 0;
5//! ```
fe692bf9
FG
6use either::Either;
7use hir::{
8 Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
9 Semantics,
10};
9c376795
FG
11use ide_db::RootDatabase;
12
9ffffee4 13use stdx::never;
9c376795
FG
14use syntax::{
15 ast::{self, make, AstNode},
16 ted,
17};
18
9ffffee4 19use crate::{
fe692bf9
FG
20 AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
21 InlayHintsConfig, InlayKind, InlayTooltip,
9ffffee4 22};
9c376795
FG
23
24pub(super) fn hints(
25 acc: &mut Vec<InlayHint>,
26 sema: &Semantics<'_, RootDatabase>,
27 config: &InlayHintsConfig,
28 expr: &ast::Expr,
29) -> Option<()> {
30 if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
31 return None;
32 }
33
34 if config.adjustment_hints == AdjustmentHints::Never {
35 return None;
36 }
37
353b0b11
FG
38 // ParenExpr resolve to their contained expressions HIR so they will dupe these hints
39 if let ast::Expr::ParenExpr(_) = expr {
9c376795
FG
40 return None;
41 }
353b0b11
FG
42 if let ast::Expr::BlockExpr(b) = expr {
43 if !b.is_standalone() {
44 return None;
45 }
46 }
9c376795
FG
47
48 let descended = sema.descend_node_into_attributes(expr.clone()).pop();
49 let desc_expr = descended.as_ref().unwrap_or(expr);
50 let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
51
353b0b11
FG
52 if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
53 if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
54 &*adjustments
55 {
56 // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
57 if source == target {
58 return None;
59 }
60 }
61 }
62
9c376795
FG
63 let (postfix, needs_outer_parens, needs_inner_parens) =
64 mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
65
66 if needs_outer_parens {
fe692bf9
FG
67 acc.push(InlayHint::opening_paren_before(
68 InlayKind::Adjustment,
69 expr.syntax().text_range(),
70 ));
9c376795
FG
71 }
72
73 if postfix && needs_inner_parens {
fe692bf9
FG
74 acc.push(InlayHint::opening_paren_before(
75 InlayKind::Adjustment,
76 expr.syntax().text_range(),
77 ));
78 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
79 }
80
fe692bf9
FG
81 let mut iter = if postfix {
82 Either::Left(adjustments.into_iter())
9c376795 83 } else {
fe692bf9 84 Either::Right(adjustments.into_iter().rev())
9c376795 85 };
fe692bf9 86 let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
9c376795 87
9ffffee4
FG
88 for Adjustment { source, target, kind } in iter {
89 if source == target {
353b0b11 90 cov_mark::hit!(same_type_adjustment);
9c376795
FG
91 continue;
92 }
93
94 // FIXME: Add some nicer tooltips to each of these
9ffffee4 95 let (text, coercion) = match kind {
9c376795 96 Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
9ffffee4
FG
97 ("<never-to-any>", "never to any")
98 }
fe692bf9
FG
99 Adjust::Deref(None) => ("*", "dereference"),
100 Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => {
101 ("*", "`Deref` dereference")
102 }
103 Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => {
104 ("*", "`DerefMut` dereference")
105 }
9ffffee4
FG
106 Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"),
107 Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"),
108 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => {
109 ("&raw const ", "const pointer borrow")
110 }
111 Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => {
112 ("&raw mut ", "mut pointer borrow")
9c376795 113 }
9c376795
FG
114 // some of these could be represented via `as` casts, but that's not too nice and
115 // handling everything as a prefix expr makes the `(` and `)` insertion easier
116 Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
117 match cast {
9ffffee4
FG
118 PointerCast::ReifyFnPointer => {
119 ("<fn-item-to-fn-pointer>", "fn item to fn pointer")
120 }
121 PointerCast::UnsafeFnPointer => (
122 "<safe-fn-pointer-to-unsafe-fn-pointer>",
123 "safe fn pointer to unsafe fn pointer",
124 ),
9c376795 125 PointerCast::ClosureFnPointer(Safety::Unsafe) => {
9ffffee4
FG
126 ("<closure-to-unsafe-fn-pointer>", "closure to unsafe fn pointer")
127 }
128 PointerCast::ClosureFnPointer(Safety::Safe) => {
129 ("<closure-to-fn-pointer>", "closure to fn pointer")
9c376795 130 }
9ffffee4
FG
131 PointerCast::MutToConstPointer => {
132 ("<mut-ptr-to-const-ptr>", "mut ptr to const ptr")
133 }
134 PointerCast::ArrayToPointer => ("<array-ptr-to-element-ptr>", ""),
135 PointerCast::Unsize => ("<unsize>", "unsize"),
9c376795
FG
136 }
137 }
138 _ => continue,
139 };
781aab86
FG
140 let label = InlayHintLabel::simple(
141 if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
142 Some(InlayTooltip::Markdown(format!(
143 "`{}` → `{}` ({coercion} coercion)",
144 source.display(sema.db),
145 target.display(sema.db),
146 ))),
147 None,
148 );
9c376795
FG
149 acc.push(InlayHint {
150 range: expr.syntax().text_range(),
fe692bf9
FG
151 pad_left: false,
152 pad_right: false,
153 position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
154 kind: InlayKind::Adjustment,
781aab86 155 label,
fe692bf9 156 text_edit: None,
9c376795
FG
157 });
158 }
159 if !postfix && needs_inner_parens {
fe692bf9
FG
160 acc.push(InlayHint::opening_paren_before(
161 InlayKind::Adjustment,
162 expr.syntax().text_range(),
163 ));
164 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
165 }
166 if needs_outer_parens {
fe692bf9 167 acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
9c376795
FG
168 }
169 Some(())
170}
171
fe692bf9 172/// Returns whatever the hint should be postfix and if we need to add parentheses on the inside and/or outside of `expr`,
9c376795
FG
173/// if we are going to add (`postfix`) adjustments hints to it.
174fn mode_and_needs_parens_for_adjustment_hints(
175 expr: &ast::Expr,
176 mode: AdjustmentHintsMode,
177) -> (bool, bool, bool) {
178 use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
179
180 match mode {
181 Prefix | Postfix => {
182 let postfix = matches!(mode, Postfix);
183 let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix);
184 (postfix, inside, outside)
185 }
186 PreferPrefix | PreferPostfix => {
187 let prefer_postfix = matches!(mode, PreferPostfix);
188
189 let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false);
190 let prefix = (false, pre_inside, pre_outside);
191 let pre_count = pre_inside as u8 + pre_outside as u8;
192
193 let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true);
194 let postfix = (true, post_inside, post_outside);
195 let post_count = post_inside as u8 + post_outside as u8;
196
197 match pre_count.cmp(&post_count) {
198 Less => prefix,
199 Greater => postfix,
200 Equal if prefer_postfix => postfix,
201 Equal => prefix,
202 }
203 }
204 }
205}
206
fe692bf9 207/// Returns whatever we need to add parentheses on the inside and/or outside of `expr`,
9c376795
FG
208/// if we are going to add (`postfix`) adjustments hints to it.
209fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
210 // This is a very miserable pile of hacks...
211 //
212 // `Expr::needs_parens_in` requires that the expression is the child of the other expression,
213 // that is supposed to be its parent.
214 //
215 // But we want to check what would happen if we add `*`/`.*` to the inner expression.
216 // To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
217 // to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
fe692bf9 218 // where "expr" is the `expr` parameter, `*expr` is the edited `expr`,
9c376795
FG
219 // and "parent" is the parent of the original expression...
220 //
fe692bf9 221 // For this we utilize mutable trees, which is a HACK, but it works.
9c376795
FG
222 //
223 // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this*
224
225 // Make `&expr`/`expr?`
226 let dummy_expr = {
227 // `make::*` function go through a string, so they parse wrongly.
228 // for example `` make::expr_try(`|| a`) `` would result in a
229 // `|| (a?)` and not `(|| a)?`.
230 //
231 // Thus we need dummy parens to preserve the relationship we want.
232 // The parens are then simply ignored by the following code.
233 let dummy_paren = make::expr_paren(expr.clone());
234 if postfix {
235 make::expr_try(dummy_paren)
236 } else {
237 make::expr_ref(dummy_paren, false)
238 }
239 };
240
241 // Do the dark mutable tree magic.
242 // This essentially makes `dummy_expr` and `expr` switch places (families),
243 // so that `expr`'s parent is not `dummy_expr`'s parent.
244 let dummy_expr = dummy_expr.clone_for_update();
245 let expr = expr.clone_for_update();
246 ted::replace(expr.syntax(), dummy_expr.syntax());
247
248 let parent = dummy_expr.syntax().parent();
9ffffee4
FG
249 let Some(expr) = (|| {
250 if postfix {
251 let ast::Expr::TryExpr(e) = &dummy_expr else { return None };
252 let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
9c376795 253
9ffffee4
FG
254 e.expr()
255 } else {
256 let ast::Expr::RefExpr(e) = &dummy_expr else { return None };
257 let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
9c376795 258
9ffffee4
FG
259 e.expr()
260 }
261 })() else {
262 never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr);
add651ee 263 return (true, true);
9c376795
FG
264 };
265
266 // At this point
fe692bf9 267 // - `parent` is the parent of the original expression
9c376795
FG
268 // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
269 // - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
270
271 let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p));
272 let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone());
273
274 (needs_outer_parens, needs_inner_parens)
275}
276
277#[cfg(test)]
278mod tests {
279 use crate::{
280 inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
281 AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
282 };
283
284 #[test]
285 fn adjustment_hints() {
286 check_with_config(
287 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
288 r#"
fe692bf9 289//- minicore: coerce_unsized, fn, eq, index
9c376795
FG
290fn main() {
291 let _: u32 = loop {};
292 //^^^^^^^<never-to-any>
293 let _: &u32 = &mut 0;
294 //^^^^^^&
295 //^^^^^^*
296 let _: &mut u32 = &mut 0;
297 //^^^^^^&mut $
298 //^^^^^^*
299 let _: *const u32 = &mut 0;
300 //^^^^^^&raw const $
301 //^^^^^^*
302 let _: *mut u32 = &mut 0;
303 //^^^^^^&raw mut $
304 //^^^^^^*
305 let _: fn() = main;
306 //^^^^<fn-item-to-fn-pointer>
307 let _: unsafe fn() = main;
308 //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
309 //^^^^<fn-item-to-fn-pointer>
310 let _: unsafe fn() = main as fn();
311 //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
312 //^^^^^^^^^^^^(
313 //^^^^^^^^^^^^)
314 let _: fn() = || {};
315 //^^^^^<closure-to-fn-pointer>
316 let _: unsafe fn() = || {};
317 //^^^^^<closure-to-unsafe-fn-pointer>
318 let _: *const u32 = &mut 0u32 as *mut u32;
319 //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
320 //^^^^^^^^^^^^^^^^^^^^^(
321 //^^^^^^^^^^^^^^^^^^^^^)
322 let _: &mut [_] = &mut [0; 0];
323 //^^^^^^^^^^^<unsize>
324 //^^^^^^^^^^^&mut $
325 //^^^^^^^^^^^*
326
327 Struct.consume();
328 Struct.by_ref();
329 //^^^^^^(
330 //^^^^^^&
331 //^^^^^^)
332 Struct.by_ref_mut();
333 //^^^^^^(
334 //^^^^^^&mut $
335 //^^^^^^)
336
337 (&Struct).consume();
338 //^^^^^^^*
339 (&Struct).by_ref();
fe692bf9
FG
340 //^^^^^^^&
341 //^^^^^^^*
9c376795
FG
342
343 (&mut Struct).consume();
344 //^^^^^^^^^^^*
345 (&mut Struct).by_ref();
346 //^^^^^^^^^^^&
347 //^^^^^^^^^^^*
348 (&mut Struct).by_ref_mut();
fe692bf9
FG
349 //^^^^^^^^^^^&mut $
350 //^^^^^^^^^^^*
9c376795
FG
351
352 // Check that block-like expressions don't duplicate hints
353 let _: &mut [u32] = (&mut []);
354 //^^^^^^^<unsize>
355 //^^^^^^^&mut $
356 //^^^^^^^*
357 let _: &mut [u32] = { &mut [] };
358 //^^^^^^^<unsize>
359 //^^^^^^^&mut $
360 //^^^^^^^*
361 let _: &mut [u32] = unsafe { &mut [] };
362 //^^^^^^^<unsize>
363 //^^^^^^^&mut $
364 //^^^^^^^*
365 let _: &mut [u32] = if true {
366 &mut []
367 //^^^^^^^<unsize>
368 //^^^^^^^&mut $
369 //^^^^^^^*
370 } else {
371 loop {}
372 //^^^^^^^<never-to-any>
373 };
353b0b11 374 let _: &mut [u32] = match () { () => &mut [] };
9c376795
FG
375 //^^^^^^^<unsize>
376 //^^^^^^^&mut $
377 //^^^^^^^*
378
379 let _: &mut dyn Fn() = &mut || ();
380 //^^^^^^^^^^<unsize>
381 //^^^^^^^^^^&mut $
382 //^^^^^^^^^^*
353b0b11
FG
383 () == ();
384 // ^^&
385 // ^^&
386 (()) == {()};
387 // ^^&
388 // ^^^^&
fe692bf9
FG
389 let closure: dyn Fn = || ();
390 closure();
391 //^^^^^^^(
392 //^^^^^^^&
393 //^^^^^^^)
394 Struct[0];
395 //^^^^^^(
396 //^^^^^^&
397 //^^^^^^)
398 &mut Struct[0];
399 //^^^^^^(
400 //^^^^^^&mut $
401 //^^^^^^)
9c376795
FG
402}
403
404#[derive(Copy, Clone)]
405struct Struct;
406impl Struct {
407 fn consume(self) {}
408 fn by_ref(&self) {}
409 fn by_ref_mut(&mut self) {}
410}
fe692bf9
FG
411struct StructMut;
412impl core::ops::Index<usize> for Struct {
413 type Output = ();
414}
415impl core::ops::IndexMut for Struct {}
9c376795 416"#,
fe692bf9 417 );
9c376795
FG
418 }
419
420 #[test]
421 fn adjustment_hints_postfix() {
422 check_with_config(
423 InlayHintsConfig {
424 adjustment_hints: AdjustmentHints::Always,
425 adjustment_hints_mode: AdjustmentHintsMode::Postfix,
426 ..DISABLED_CONFIG
427 },
428 r#"
fe692bf9 429//- minicore: coerce_unsized, fn, eq, index
9c376795
FG
430fn main() {
431
432 Struct.consume();
433 Struct.by_ref();
434 //^^^^^^.&
435 Struct.by_ref_mut();
436 //^^^^^^.&mut
437
438 (&Struct).consume();
439 //^^^^^^^(
440 //^^^^^^^)
441 //^^^^^^^.*
442 (&Struct).by_ref();
fe692bf9
FG
443 //^^^^^^^(
444 //^^^^^^^)
445 //^^^^^^^.*
446 //^^^^^^^.&
9c376795
FG
447
448 (&mut Struct).consume();
449 //^^^^^^^^^^^(
450 //^^^^^^^^^^^)
451 //^^^^^^^^^^^.*
452 (&mut Struct).by_ref();
453 //^^^^^^^^^^^(
454 //^^^^^^^^^^^)
455 //^^^^^^^^^^^.*
456 //^^^^^^^^^^^.&
457 (&mut Struct).by_ref_mut();
fe692bf9
FG
458 //^^^^^^^^^^^(
459 //^^^^^^^^^^^)
460 //^^^^^^^^^^^.*
461 //^^^^^^^^^^^.&mut
9c376795
FG
462
463 // Check that block-like expressions don't duplicate hints
464 let _: &mut [u32] = (&mut []);
465 //^^^^^^^(
466 //^^^^^^^)
467 //^^^^^^^.*
468 //^^^^^^^.&mut
469 //^^^^^^^.<unsize>
470 let _: &mut [u32] = { &mut [] };
471 //^^^^^^^(
472 //^^^^^^^)
473 //^^^^^^^.*
474 //^^^^^^^.&mut
475 //^^^^^^^.<unsize>
476 let _: &mut [u32] = unsafe { &mut [] };
477 //^^^^^^^(
478 //^^^^^^^)
479 //^^^^^^^.*
480 //^^^^^^^.&mut
481 //^^^^^^^.<unsize>
482 let _: &mut [u32] = if true {
483 &mut []
484 //^^^^^^^(
485 //^^^^^^^)
486 //^^^^^^^.*
487 //^^^^^^^.&mut
488 //^^^^^^^.<unsize>
489 } else {
490 loop {}
491 //^^^^^^^.<never-to-any>
492 };
353b0b11 493 let _: &mut [u32] = match () { () => &mut [] };
9c376795
FG
494 //^^^^^^^(
495 //^^^^^^^)
496 //^^^^^^^.*
497 //^^^^^^^.&mut
498 //^^^^^^^.<unsize>
499
500 let _: &mut dyn Fn() = &mut || ();
501 //^^^^^^^^^^(
502 //^^^^^^^^^^)
503 //^^^^^^^^^^.*
504 //^^^^^^^^^^.&mut
505 //^^^^^^^^^^.<unsize>
353b0b11
FG
506 () == ();
507 // ^^.&
508 // ^^.&
509 (()) == {()};
510 // ^^.&
511 // ^^^^.&
fe692bf9
FG
512 let closure: dyn Fn = || ();
513 closure();
514 //^^^^^^^.&
515 Struct[0];
516 //^^^^^^.&
517 &mut Struct[0];
518 //^^^^^^.&mut
9c376795
FG
519}
520
521#[derive(Copy, Clone)]
522struct Struct;
523impl Struct {
524 fn consume(self) {}
525 fn by_ref(&self) {}
526 fn by_ref_mut(&mut self) {}
527}
fe692bf9
FG
528struct StructMut;
529impl core::ops::Index<usize> for Struct {
530 type Output = ();
531}
532impl core::ops::IndexMut for Struct {}
9c376795
FG
533"#,
534 );
535 }
536
537 #[test]
538 fn adjustment_hints_prefer_prefix() {
539 check_with_config(
540 InlayHintsConfig {
541 adjustment_hints: AdjustmentHints::Always,
542 adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix,
543 ..DISABLED_CONFIG
544 },
545 r#"
546fn main() {
547 let _: u32 = loop {};
548 //^^^^^^^<never-to-any>
549
550 Struct.by_ref();
551 //^^^^^^.&
552
553 let (): () = return ();
554 //^^^^^^^^^<never-to-any>
555
556 struct Struct;
557 impl Struct { fn by_ref(&self) {} }
558}
559 "#,
560 )
561 }
562
563 #[test]
564 fn adjustment_hints_prefer_postfix() {
565 check_with_config(
566 InlayHintsConfig {
567 adjustment_hints: AdjustmentHints::Always,
568 adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix,
569 ..DISABLED_CONFIG
570 },
571 r#"
572fn main() {
573 let _: u32 = loop {};
574 //^^^^^^^.<never-to-any>
575
576 Struct.by_ref();
577 //^^^^^^.&
578
579 let (): () = return ();
580 //^^^^^^^^^<never-to-any>
581
582 struct Struct;
583 impl Struct { fn by_ref(&self) {} }
584}
585 "#,
586 )
587 }
588
589 #[test]
590 fn never_to_never_is_never_shown() {
353b0b11 591 cov_mark::check!(same_type_adjustment);
9c376795
FG
592 check_with_config(
593 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
594 r#"
595fn never() -> ! {
596 return loop {};
597}
598
599fn or_else() {
600 let () = () else { return };
601}
602 "#,
603 )
604 }
605
606 #[test]
607 fn adjustment_hints_unsafe_only() {
608 check_with_config(
609 InlayHintsConfig {
610 adjustment_hints: AdjustmentHints::Always,
611 adjustment_hints_hide_outside_unsafe: true,
612 ..DISABLED_CONFIG
613 },
614 r#"
615unsafe fn enabled() {
616 f(&&());
617 //^^^^&
618 //^^^^*
619 //^^^^*
620}
621
622fn disabled() {
623 f(&&());
624}
625
626fn mixed() {
627 f(&&());
628
629 unsafe {
630 f(&&());
631 //^^^^&
632 //^^^^*
633 //^^^^*
634 }
635}
636
637const _: () = {
638 f(&&());
639
640 unsafe {
641 f(&&());
642 //^^^^&
643 //^^^^*
644 //^^^^*
645 }
646};
647
648static STATIC: () = {
649 f(&&());
650
651 unsafe {
652 f(&&());
653 //^^^^&
654 //^^^^*
655 //^^^^*
656 }
657};
658
659enum E {
660 Disable = { f(&&()); 0 },
661 Enable = unsafe { f(&&()); 1 },
662 //^^^^&
663 //^^^^*
664 //^^^^*
665}
666
667const fn f(_: &()) {}
668 "#,
669 )
670 }
671
672 #[test]
673 fn adjustment_hints_unsafe_only_with_item() {
674 check_with_config(
675 InlayHintsConfig {
676 adjustment_hints: AdjustmentHints::Always,
677 adjustment_hints_hide_outside_unsafe: true,
678 ..DISABLED_CONFIG
679 },
680 r#"
681fn a() {
682 struct Struct;
683 impl Struct {
684 fn by_ref(&self) {}
685 }
686
687 _ = Struct.by_ref();
688
689 _ = unsafe { Struct.by_ref() };
690 //^^^^^^(
691 //^^^^^^&
692 //^^^^^^)
693}
694 "#,
695 );
696 }
697
698 #[test]
353b0b11 699 fn let_stmt_explicit_ty() {
9c376795
FG
700 check_with_config(
701 InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
702 r#"
703fn main() {
9c376795 704 let () = return;
353b0b11 705 //^^^^^^<never-to-any>
9c376795
FG
706 let (): () = return;
707 //^^^^^^<never-to-any>
708}
709 "#,
710 )
711 }
712}