]>
Commit | Line | Data |
---|---|---|
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 |
6 | use either::Either; |
7 | use hir::{ | |
8 | Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety, | |
9 | Semantics, | |
10 | }; | |
9c376795 FG |
11 | use ide_db::RootDatabase; |
12 | ||
9ffffee4 | 13 | use stdx::never; |
9c376795 FG |
14 | use syntax::{ |
15 | ast::{self, make, AstNode}, | |
16 | ted, | |
17 | }; | |
18 | ||
9ffffee4 | 19 | use crate::{ |
fe692bf9 FG |
20 | AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition, |
21 | InlayHintsConfig, InlayKind, InlayTooltip, | |
9ffffee4 | 22 | }; |
9c376795 FG |
23 | |
24 | pub(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 | }; | |
140 | acc.push(InlayHint { | |
141 | range: expr.syntax().text_range(), | |
fe692bf9 FG |
142 | pad_left: false, |
143 | pad_right: false, | |
144 | position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before }, | |
145 | kind: InlayKind::Adjustment, | |
9ffffee4 FG |
146 | label: InlayHintLabel::simple( |
147 | if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, | |
148 | Some(InlayTooltip::Markdown(format!( | |
149 | "`{}` → `{}` ({coercion} coercion)", | |
150 | source.display(sema.db), | |
151 | target.display(sema.db), | |
152 | ))), | |
153 | None, | |
154 | ), | |
fe692bf9 | 155 | text_edit: None, |
9c376795 FG |
156 | }); |
157 | } | |
158 | if !postfix && needs_inner_parens { | |
fe692bf9 FG |
159 | acc.push(InlayHint::opening_paren_before( |
160 | InlayKind::Adjustment, | |
161 | expr.syntax().text_range(), | |
162 | )); | |
163 | acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); | |
9c376795 FG |
164 | } |
165 | if needs_outer_parens { | |
fe692bf9 | 166 | acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); |
9c376795 FG |
167 | } |
168 | Some(()) | |
169 | } | |
170 | ||
fe692bf9 | 171 | /// Returns whatever the hint should be postfix and if we need to add parentheses on the inside and/or outside of `expr`, |
9c376795 FG |
172 | /// if we are going to add (`postfix`) adjustments hints to it. |
173 | fn mode_and_needs_parens_for_adjustment_hints( | |
174 | expr: &ast::Expr, | |
175 | mode: AdjustmentHintsMode, | |
176 | ) -> (bool, bool, bool) { | |
177 | use {std::cmp::Ordering::*, AdjustmentHintsMode::*}; | |
178 | ||
179 | match mode { | |
180 | Prefix | Postfix => { | |
181 | let postfix = matches!(mode, Postfix); | |
182 | let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix); | |
183 | (postfix, inside, outside) | |
184 | } | |
185 | PreferPrefix | PreferPostfix => { | |
186 | let prefer_postfix = matches!(mode, PreferPostfix); | |
187 | ||
188 | let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false); | |
189 | let prefix = (false, pre_inside, pre_outside); | |
190 | let pre_count = pre_inside as u8 + pre_outside as u8; | |
191 | ||
192 | let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true); | |
193 | let postfix = (true, post_inside, post_outside); | |
194 | let post_count = post_inside as u8 + post_outside as u8; | |
195 | ||
196 | match pre_count.cmp(&post_count) { | |
197 | Less => prefix, | |
198 | Greater => postfix, | |
199 | Equal if prefer_postfix => postfix, | |
200 | Equal => prefix, | |
201 | } | |
202 | } | |
203 | } | |
204 | } | |
205 | ||
fe692bf9 | 206 | /// Returns whatever we need to add parentheses on the inside and/or outside of `expr`, |
9c376795 FG |
207 | /// if we are going to add (`postfix`) adjustments hints to it. |
208 | fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) { | |
209 | // This is a very miserable pile of hacks... | |
210 | // | |
211 | // `Expr::needs_parens_in` requires that the expression is the child of the other expression, | |
212 | // that is supposed to be its parent. | |
213 | // | |
214 | // But we want to check what would happen if we add `*`/`.*` to the inner expression. | |
215 | // To check for inner we need `` expr.needs_parens_in(`*expr`) ``, | |
216 | // to check for outer we need `` `*expr`.needs_parens_in(parent) ``, | |
fe692bf9 | 217 | // where "expr" is the `expr` parameter, `*expr` is the edited `expr`, |
9c376795 FG |
218 | // and "parent" is the parent of the original expression... |
219 | // | |
fe692bf9 | 220 | // For this we utilize mutable trees, which is a HACK, but it works. |
9c376795 FG |
221 | // |
222 | // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this* | |
223 | ||
224 | // Make `&expr`/`expr?` | |
225 | let dummy_expr = { | |
226 | // `make::*` function go through a string, so they parse wrongly. | |
227 | // for example `` make::expr_try(`|| a`) `` would result in a | |
228 | // `|| (a?)` and not `(|| a)?`. | |
229 | // | |
230 | // Thus we need dummy parens to preserve the relationship we want. | |
231 | // The parens are then simply ignored by the following code. | |
232 | let dummy_paren = make::expr_paren(expr.clone()); | |
233 | if postfix { | |
234 | make::expr_try(dummy_paren) | |
235 | } else { | |
236 | make::expr_ref(dummy_paren, false) | |
237 | } | |
238 | }; | |
239 | ||
240 | // Do the dark mutable tree magic. | |
241 | // This essentially makes `dummy_expr` and `expr` switch places (families), | |
242 | // so that `expr`'s parent is not `dummy_expr`'s parent. | |
243 | let dummy_expr = dummy_expr.clone_for_update(); | |
244 | let expr = expr.clone_for_update(); | |
245 | ted::replace(expr.syntax(), dummy_expr.syntax()); | |
246 | ||
247 | let parent = dummy_expr.syntax().parent(); | |
9ffffee4 FG |
248 | let Some(expr) = (|| { |
249 | if postfix { | |
250 | let ast::Expr::TryExpr(e) = &dummy_expr else { return None }; | |
251 | let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None }; | |
9c376795 | 252 | |
9ffffee4 FG |
253 | e.expr() |
254 | } else { | |
255 | let ast::Expr::RefExpr(e) = &dummy_expr else { return None }; | |
256 | let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None }; | |
9c376795 | 257 | |
9ffffee4 FG |
258 | e.expr() |
259 | } | |
260 | })() else { | |
261 | never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr); | |
262 | return (true, true) | |
9c376795 FG |
263 | }; |
264 | ||
265 | // At this point | |
fe692bf9 | 266 | // - `parent` is the parent of the original expression |
9c376795 FG |
267 | // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`) |
268 | // - `expr` is the clone of the original expression (with `dummy_expr` as the parent) | |
269 | ||
270 | let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p)); | |
271 | let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone()); | |
272 | ||
273 | (needs_outer_parens, needs_inner_parens) | |
274 | } | |
275 | ||
276 | #[cfg(test)] | |
277 | mod tests { | |
278 | use crate::{ | |
279 | inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, | |
280 | AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig, | |
281 | }; | |
282 | ||
283 | #[test] | |
284 | fn adjustment_hints() { | |
285 | check_with_config( | |
286 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
287 | r#" | |
fe692bf9 | 288 | //- minicore: coerce_unsized, fn, eq, index |
9c376795 FG |
289 | fn main() { |
290 | let _: u32 = loop {}; | |
291 | //^^^^^^^<never-to-any> | |
292 | let _: &u32 = &mut 0; | |
293 | //^^^^^^& | |
294 | //^^^^^^* | |
295 | let _: &mut u32 = &mut 0; | |
296 | //^^^^^^&mut $ | |
297 | //^^^^^^* | |
298 | let _: *const u32 = &mut 0; | |
299 | //^^^^^^&raw const $ | |
300 | //^^^^^^* | |
301 | let _: *mut u32 = &mut 0; | |
302 | //^^^^^^&raw mut $ | |
303 | //^^^^^^* | |
304 | let _: fn() = main; | |
305 | //^^^^<fn-item-to-fn-pointer> | |
306 | let _: unsafe fn() = main; | |
307 | //^^^^<safe-fn-pointer-to-unsafe-fn-pointer> | |
308 | //^^^^<fn-item-to-fn-pointer> | |
309 | let _: unsafe fn() = main as fn(); | |
310 | //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer> | |
311 | //^^^^^^^^^^^^( | |
312 | //^^^^^^^^^^^^) | |
313 | let _: fn() = || {}; | |
314 | //^^^^^<closure-to-fn-pointer> | |
315 | let _: unsafe fn() = || {}; | |
316 | //^^^^^<closure-to-unsafe-fn-pointer> | |
317 | let _: *const u32 = &mut 0u32 as *mut u32; | |
318 | //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr> | |
319 | //^^^^^^^^^^^^^^^^^^^^^( | |
320 | //^^^^^^^^^^^^^^^^^^^^^) | |
321 | let _: &mut [_] = &mut [0; 0]; | |
322 | //^^^^^^^^^^^<unsize> | |
323 | //^^^^^^^^^^^&mut $ | |
324 | //^^^^^^^^^^^* | |
325 | ||
326 | Struct.consume(); | |
327 | Struct.by_ref(); | |
328 | //^^^^^^( | |
329 | //^^^^^^& | |
330 | //^^^^^^) | |
331 | Struct.by_ref_mut(); | |
332 | //^^^^^^( | |
333 | //^^^^^^&mut $ | |
334 | //^^^^^^) | |
335 | ||
336 | (&Struct).consume(); | |
337 | //^^^^^^^* | |
338 | (&Struct).by_ref(); | |
fe692bf9 FG |
339 | //^^^^^^^& |
340 | //^^^^^^^* | |
9c376795 FG |
341 | |
342 | (&mut Struct).consume(); | |
343 | //^^^^^^^^^^^* | |
344 | (&mut Struct).by_ref(); | |
345 | //^^^^^^^^^^^& | |
346 | //^^^^^^^^^^^* | |
347 | (&mut Struct).by_ref_mut(); | |
fe692bf9 FG |
348 | //^^^^^^^^^^^&mut $ |
349 | //^^^^^^^^^^^* | |
9c376795 FG |
350 | |
351 | // Check that block-like expressions don't duplicate hints | |
352 | let _: &mut [u32] = (&mut []); | |
353 | //^^^^^^^<unsize> | |
354 | //^^^^^^^&mut $ | |
355 | //^^^^^^^* | |
356 | let _: &mut [u32] = { &mut [] }; | |
357 | //^^^^^^^<unsize> | |
358 | //^^^^^^^&mut $ | |
359 | //^^^^^^^* | |
360 | let _: &mut [u32] = unsafe { &mut [] }; | |
361 | //^^^^^^^<unsize> | |
362 | //^^^^^^^&mut $ | |
363 | //^^^^^^^* | |
364 | let _: &mut [u32] = if true { | |
365 | &mut [] | |
366 | //^^^^^^^<unsize> | |
367 | //^^^^^^^&mut $ | |
368 | //^^^^^^^* | |
369 | } else { | |
370 | loop {} | |
371 | //^^^^^^^<never-to-any> | |
372 | }; | |
353b0b11 | 373 | let _: &mut [u32] = match () { () => &mut [] }; |
9c376795 FG |
374 | //^^^^^^^<unsize> |
375 | //^^^^^^^&mut $ | |
376 | //^^^^^^^* | |
377 | ||
378 | let _: &mut dyn Fn() = &mut || (); | |
379 | //^^^^^^^^^^<unsize> | |
380 | //^^^^^^^^^^&mut $ | |
381 | //^^^^^^^^^^* | |
353b0b11 FG |
382 | () == (); |
383 | // ^^& | |
384 | // ^^& | |
385 | (()) == {()}; | |
386 | // ^^& | |
387 | // ^^^^& | |
fe692bf9 FG |
388 | let closure: dyn Fn = || (); |
389 | closure(); | |
390 | //^^^^^^^( | |
391 | //^^^^^^^& | |
392 | //^^^^^^^) | |
393 | Struct[0]; | |
394 | //^^^^^^( | |
395 | //^^^^^^& | |
396 | //^^^^^^) | |
397 | &mut Struct[0]; | |
398 | //^^^^^^( | |
399 | //^^^^^^&mut $ | |
400 | //^^^^^^) | |
9c376795 FG |
401 | } |
402 | ||
403 | #[derive(Copy, Clone)] | |
404 | struct Struct; | |
405 | impl Struct { | |
406 | fn consume(self) {} | |
407 | fn by_ref(&self) {} | |
408 | fn by_ref_mut(&mut self) {} | |
409 | } | |
fe692bf9 FG |
410 | struct StructMut; |
411 | impl core::ops::Index<usize> for Struct { | |
412 | type Output = (); | |
413 | } | |
414 | impl core::ops::IndexMut for Struct {} | |
9c376795 | 415 | "#, |
fe692bf9 | 416 | ); |
9c376795 FG |
417 | } |
418 | ||
419 | #[test] | |
420 | fn adjustment_hints_postfix() { | |
421 | check_with_config( | |
422 | InlayHintsConfig { | |
423 | adjustment_hints: AdjustmentHints::Always, | |
424 | adjustment_hints_mode: AdjustmentHintsMode::Postfix, | |
425 | ..DISABLED_CONFIG | |
426 | }, | |
427 | r#" | |
fe692bf9 | 428 | //- minicore: coerce_unsized, fn, eq, index |
9c376795 FG |
429 | fn main() { |
430 | ||
431 | Struct.consume(); | |
432 | Struct.by_ref(); | |
433 | //^^^^^^.& | |
434 | Struct.by_ref_mut(); | |
435 | //^^^^^^.&mut | |
436 | ||
437 | (&Struct).consume(); | |
438 | //^^^^^^^( | |
439 | //^^^^^^^) | |
440 | //^^^^^^^.* | |
441 | (&Struct).by_ref(); | |
fe692bf9 FG |
442 | //^^^^^^^( |
443 | //^^^^^^^) | |
444 | //^^^^^^^.* | |
445 | //^^^^^^^.& | |
9c376795 FG |
446 | |
447 | (&mut Struct).consume(); | |
448 | //^^^^^^^^^^^( | |
449 | //^^^^^^^^^^^) | |
450 | //^^^^^^^^^^^.* | |
451 | (&mut Struct).by_ref(); | |
452 | //^^^^^^^^^^^( | |
453 | //^^^^^^^^^^^) | |
454 | //^^^^^^^^^^^.* | |
455 | //^^^^^^^^^^^.& | |
456 | (&mut Struct).by_ref_mut(); | |
fe692bf9 FG |
457 | //^^^^^^^^^^^( |
458 | //^^^^^^^^^^^) | |
459 | //^^^^^^^^^^^.* | |
460 | //^^^^^^^^^^^.&mut | |
9c376795 FG |
461 | |
462 | // Check that block-like expressions don't duplicate hints | |
463 | let _: &mut [u32] = (&mut []); | |
464 | //^^^^^^^( | |
465 | //^^^^^^^) | |
466 | //^^^^^^^.* | |
467 | //^^^^^^^.&mut | |
468 | //^^^^^^^.<unsize> | |
469 | let _: &mut [u32] = { &mut [] }; | |
470 | //^^^^^^^( | |
471 | //^^^^^^^) | |
472 | //^^^^^^^.* | |
473 | //^^^^^^^.&mut | |
474 | //^^^^^^^.<unsize> | |
475 | let _: &mut [u32] = unsafe { &mut [] }; | |
476 | //^^^^^^^( | |
477 | //^^^^^^^) | |
478 | //^^^^^^^.* | |
479 | //^^^^^^^.&mut | |
480 | //^^^^^^^.<unsize> | |
481 | let _: &mut [u32] = if true { | |
482 | &mut [] | |
483 | //^^^^^^^( | |
484 | //^^^^^^^) | |
485 | //^^^^^^^.* | |
486 | //^^^^^^^.&mut | |
487 | //^^^^^^^.<unsize> | |
488 | } else { | |
489 | loop {} | |
490 | //^^^^^^^.<never-to-any> | |
491 | }; | |
353b0b11 | 492 | let _: &mut [u32] = match () { () => &mut [] }; |
9c376795 FG |
493 | //^^^^^^^( |
494 | //^^^^^^^) | |
495 | //^^^^^^^.* | |
496 | //^^^^^^^.&mut | |
497 | //^^^^^^^.<unsize> | |
498 | ||
499 | let _: &mut dyn Fn() = &mut || (); | |
500 | //^^^^^^^^^^( | |
501 | //^^^^^^^^^^) | |
502 | //^^^^^^^^^^.* | |
503 | //^^^^^^^^^^.&mut | |
504 | //^^^^^^^^^^.<unsize> | |
353b0b11 FG |
505 | () == (); |
506 | // ^^.& | |
507 | // ^^.& | |
508 | (()) == {()}; | |
509 | // ^^.& | |
510 | // ^^^^.& | |
fe692bf9 FG |
511 | let closure: dyn Fn = || (); |
512 | closure(); | |
513 | //^^^^^^^.& | |
514 | Struct[0]; | |
515 | //^^^^^^.& | |
516 | &mut Struct[0]; | |
517 | //^^^^^^.&mut | |
9c376795 FG |
518 | } |
519 | ||
520 | #[derive(Copy, Clone)] | |
521 | struct Struct; | |
522 | impl Struct { | |
523 | fn consume(self) {} | |
524 | fn by_ref(&self) {} | |
525 | fn by_ref_mut(&mut self) {} | |
526 | } | |
fe692bf9 FG |
527 | struct StructMut; |
528 | impl core::ops::Index<usize> for Struct { | |
529 | type Output = (); | |
530 | } | |
531 | impl core::ops::IndexMut for Struct {} | |
9c376795 FG |
532 | "#, |
533 | ); | |
534 | } | |
535 | ||
536 | #[test] | |
537 | fn adjustment_hints_prefer_prefix() { | |
538 | check_with_config( | |
539 | InlayHintsConfig { | |
540 | adjustment_hints: AdjustmentHints::Always, | |
541 | adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix, | |
542 | ..DISABLED_CONFIG | |
543 | }, | |
544 | r#" | |
545 | fn main() { | |
546 | let _: u32 = loop {}; | |
547 | //^^^^^^^<never-to-any> | |
548 | ||
549 | Struct.by_ref(); | |
550 | //^^^^^^.& | |
551 | ||
552 | let (): () = return (); | |
553 | //^^^^^^^^^<never-to-any> | |
554 | ||
555 | struct Struct; | |
556 | impl Struct { fn by_ref(&self) {} } | |
557 | } | |
558 | "#, | |
559 | ) | |
560 | } | |
561 | ||
562 | #[test] | |
563 | fn adjustment_hints_prefer_postfix() { | |
564 | check_with_config( | |
565 | InlayHintsConfig { | |
566 | adjustment_hints: AdjustmentHints::Always, | |
567 | adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix, | |
568 | ..DISABLED_CONFIG | |
569 | }, | |
570 | r#" | |
571 | fn main() { | |
572 | let _: u32 = loop {}; | |
573 | //^^^^^^^.<never-to-any> | |
574 | ||
575 | Struct.by_ref(); | |
576 | //^^^^^^.& | |
577 | ||
578 | let (): () = return (); | |
579 | //^^^^^^^^^<never-to-any> | |
580 | ||
581 | struct Struct; | |
582 | impl Struct { fn by_ref(&self) {} } | |
583 | } | |
584 | "#, | |
585 | ) | |
586 | } | |
587 | ||
588 | #[test] | |
589 | fn never_to_never_is_never_shown() { | |
353b0b11 | 590 | cov_mark::check!(same_type_adjustment); |
9c376795 FG |
591 | check_with_config( |
592 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
593 | r#" | |
594 | fn never() -> ! { | |
595 | return loop {}; | |
596 | } | |
597 | ||
598 | fn or_else() { | |
599 | let () = () else { return }; | |
600 | } | |
601 | "#, | |
602 | ) | |
603 | } | |
604 | ||
605 | #[test] | |
606 | fn adjustment_hints_unsafe_only() { | |
607 | check_with_config( | |
608 | InlayHintsConfig { | |
609 | adjustment_hints: AdjustmentHints::Always, | |
610 | adjustment_hints_hide_outside_unsafe: true, | |
611 | ..DISABLED_CONFIG | |
612 | }, | |
613 | r#" | |
614 | unsafe fn enabled() { | |
615 | f(&&()); | |
616 | //^^^^& | |
617 | //^^^^* | |
618 | //^^^^* | |
619 | } | |
620 | ||
621 | fn disabled() { | |
622 | f(&&()); | |
623 | } | |
624 | ||
625 | fn mixed() { | |
626 | f(&&()); | |
627 | ||
628 | unsafe { | |
629 | f(&&()); | |
630 | //^^^^& | |
631 | //^^^^* | |
632 | //^^^^* | |
633 | } | |
634 | } | |
635 | ||
636 | const _: () = { | |
637 | f(&&()); | |
638 | ||
639 | unsafe { | |
640 | f(&&()); | |
641 | //^^^^& | |
642 | //^^^^* | |
643 | //^^^^* | |
644 | } | |
645 | }; | |
646 | ||
647 | static STATIC: () = { | |
648 | f(&&()); | |
649 | ||
650 | unsafe { | |
651 | f(&&()); | |
652 | //^^^^& | |
653 | //^^^^* | |
654 | //^^^^* | |
655 | } | |
656 | }; | |
657 | ||
658 | enum E { | |
659 | Disable = { f(&&()); 0 }, | |
660 | Enable = unsafe { f(&&()); 1 }, | |
661 | //^^^^& | |
662 | //^^^^* | |
663 | //^^^^* | |
664 | } | |
665 | ||
666 | const fn f(_: &()) {} | |
667 | "#, | |
668 | ) | |
669 | } | |
670 | ||
671 | #[test] | |
672 | fn adjustment_hints_unsafe_only_with_item() { | |
673 | check_with_config( | |
674 | InlayHintsConfig { | |
675 | adjustment_hints: AdjustmentHints::Always, | |
676 | adjustment_hints_hide_outside_unsafe: true, | |
677 | ..DISABLED_CONFIG | |
678 | }, | |
679 | r#" | |
680 | fn a() { | |
681 | struct Struct; | |
682 | impl Struct { | |
683 | fn by_ref(&self) {} | |
684 | } | |
685 | ||
686 | _ = Struct.by_ref(); | |
687 | ||
688 | _ = unsafe { Struct.by_ref() }; | |
689 | //^^^^^^( | |
690 | //^^^^^^& | |
691 | //^^^^^^) | |
692 | } | |
693 | "#, | |
694 | ); | |
695 | } | |
696 | ||
697 | #[test] | |
353b0b11 | 698 | fn let_stmt_explicit_ty() { |
9c376795 FG |
699 | check_with_config( |
700 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
701 | r#" | |
702 | fn main() { | |
9c376795 | 703 | let () = return; |
353b0b11 | 704 | //^^^^^^<never-to-any> |
9c376795 FG |
705 | let (): () = return; |
706 | //^^^^^^<never-to-any> | |
707 | } | |
708 | "#, | |
709 | ) | |
710 | } | |
711 | } |