1use either::{Either, for_both};
2use hir::{PathResolution, Semantics};
3use ide_db::{
4 EditionedFileId, RootDatabase,
5 defs::Definition,
6 search::{FileReference, FileReferenceNode, UsageSearchResult},
7};
8use syntax::{
9 Direction, TextRange,
10 ast::{self, AstNode, AstToken, HasName},
11 syntax_editor::{Element, SyntaxEditor},
12};
13
14use crate::{
15 AssistId,
16 assist_context::{AssistContext, Assists},
17};
18
19pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
36 let file_id = ctx.file_id();
37 let range = ctx.selection_trimmed();
38 let InlineData { let_stmt, delete_let, references, target } =
39 if let Some(path_expr) = ctx.find_node_at_offset::<ast::PathExpr>() {
40 inline_usage(&ctx.sema, path_expr, range, file_id)
41 } else if let Some(let_stmt) = ctx.find_node_at_offset() {
42 inline_let(&ctx.sema, let_stmt, range, file_id)
43 } else {
44 None
45 }?;
46 let initializer_expr = match &let_stmt {
47 either::Either::Left(it) => it.initializer()?,
48 either::Either::Right(it) => it.expr()?,
49 };
50
51 let wrap_in_parens = references
52 .into_iter()
53 .filter_map(|FileReference { range, name, .. }| match name {
54 FileReferenceNode::NameRef(name) => Some((range, name)),
55 _ => None,
56 })
57 .map(|(range, name_ref)| {
58 if range != name_ref.syntax().text_range() {
59 return None;
62 }
63 let usage_node =
64 name_ref.syntax().ancestors().find(|it| ast::PathExpr::can_cast(it.kind()));
65 let usage_parent_option = usage_node.as_ref().and_then(|it| it.parent());
66 let usage_parent = match usage_parent_option {
67 Some(u) => u,
68 None => return Some((name_ref, false)),
69 };
70 let should_wrap = initializer_expr
71 .needs_parens_in_place_of(&usage_parent, usage_node.as_ref().unwrap());
72 Some((name_ref, should_wrap))
73 })
74 .collect::<Option<Vec<_>>>()?;
75
76 let target = match target {
77 ast::NameOrNameRef::Name(it) => it.syntax().clone(),
78 ast::NameOrNameRef::NameRef(it) => it.syntax().clone(),
79 };
80
81 acc.add(
82 AssistId::refactor_inline("inline_local_variable"),
83 "Inline variable",
84 target.text_range(),
85 move |builder| {
86 let editor = builder.make_editor(&target);
87 let make = editor.make();
88 if delete_let {
89 editor.delete(let_stmt.syntax());
90
91 if let Some(bin_expr) = let_stmt.syntax().parent().and_then(ast::BinExpr::cast)
92 && let Some(op_token) = bin_expr.op_token()
93 {
94 editor.delete(&op_token);
95 remove_whitespace(op_token, Direction::Prev, &editor);
96 remove_whitespace(let_stmt.syntax(), Direction::Prev, &editor);
97 } else {
98 remove_whitespace(let_stmt.syntax(), Direction::Next, &editor);
99 }
100 }
101
102 for (name, should_wrap) in wrap_in_parens {
103 let replacement = if should_wrap {
104 make.expr_paren(initializer_expr.clone()).into()
105 } else {
106 initializer_expr.clone()
107 };
108
109 if let Some(record_field) = ast::RecordExprField::for_field_name(&name) {
110 cov_mark::hit!(inline_field_shorthand);
111 let replacement = make.record_expr_field(name, Some(replacement));
112 editor.replace(record_field.syntax(), replacement.syntax());
113 } else {
114 editor.replace(name.syntax(), replacement.syntax());
115 }
116 }
117 builder.add_file_edits(ctx.vfs_file_id(), editor);
118 },
119 )
120}
121
122struct InlineData {
123 let_stmt: Either<ast::LetStmt, ast::LetExpr>,
124 delete_let: bool,
125 target: ast::NameOrNameRef,
126 references: Vec<FileReference>,
127}
128
129fn inline_let(
130 sema: &Semantics<'_, RootDatabase>,
131 let_stmt: Either<ast::LetStmt, ast::LetExpr>,
132 range: TextRange,
133 file_id: EditionedFileId,
134) -> Option<InlineData> {
135 let bind_pat = match for_both!(&let_stmt, it => it.pat())? {
136 ast::Pat::IdentPat(pat) => pat,
137 _ => return None,
138 };
139 if bind_pat.mut_token().is_some() {
140 cov_mark::hit!(test_not_inline_mut_variable);
141 return None;
142 }
143 if !bind_pat.syntax().text_range().contains_range(range) {
144 cov_mark::hit!(not_applicable_outside_of_bind_pat);
145 return None;
146 }
147
148 let local = sema.to_def(&bind_pat)?;
149 let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
150 match references.remove(&file_id) {
151 Some(references) => Some(InlineData {
152 let_stmt,
153 delete_let: true,
154 target: ast::NameOrNameRef::Name(bind_pat.name()?),
155 references,
156 }),
157 None => {
158 cov_mark::hit!(test_not_applicable_if_variable_unused);
159 None
160 }
161 }
162}
163
164fn inline_usage(
165 sema: &Semantics<'_, RootDatabase>,
166 path_expr: ast::PathExpr,
167 range: TextRange,
168 file_id: EditionedFileId,
169) -> Option<InlineData> {
170 let path = path_expr.path()?;
171 let name = path.as_single_name_ref()?;
172 if !name.syntax().text_range().contains_range(range) {
173 cov_mark::hit!(test_not_inline_selection_too_broad);
174 return None;
175 }
176
177 let local = match sema.resolve_path(&path)? {
178 PathResolution::Local(local) => local,
179 _ => return None,
180 };
181 if local.is_mut(sema.db) {
182 cov_mark::hit!(test_not_inline_mut_variable_use);
183 return None;
184 }
185
186 let sources = local.sources(sema.db);
187 let [source] = sources.as_slice() else {
188 return None;
190 };
191
192 let bind_pat = source.as_ident_pat()?;
193
194 let let_stmt = AstNode::cast(bind_pat.syntax().parent()?)?;
195
196 let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
197 let mut references = references.remove(&file_id)?;
198 let delete_let = references.len() == 1;
199 references.retain(|fref| fref.name.as_name_ref() == Some(&name));
200
201 Some(InlineData { let_stmt, delete_let, target: ast::NameOrNameRef::NameRef(name), references })
202}
203
204fn remove_whitespace(elem: impl Element, dir: Direction, editor: &SyntaxEditor) {
205 let token = match elem.syntax_element() {
206 syntax::NodeOrToken::Node(node) => match dir {
207 Direction::Next => node.last_token(),
208 Direction::Prev => node.first_token(),
209 },
210 syntax::NodeOrToken::Token(t) => Some(t),
211 };
212 let next_token = match dir {
213 Direction::Next => token.and_then(|it| it.next_token()),
214 Direction::Prev => token.and_then(|it| it.prev_token()),
215 };
216 if let Some(whitespace) = next_token.and_then(ast::Whitespace::cast) {
217 editor.delete(whitespace.syntax());
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use crate::tests::{check_assist, check_assist_not_applicable};
224
225 use super::*;
226
227 #[test]
228 fn test_inline_let_bind_literal_expr() {
229 check_assist(
230 inline_local_variable,
231 r"
232fn bar(a: usize) {}
233fn foo() {
234 let a$0 = 1;
235 a + 1;
236 if a > 10 {
237 }
238
239 while a > 10 {
240
241 }
242 let b = a * 10;
243 bar(a);
244}",
245 r"
246fn bar(a: usize) {}
247fn foo() {
248 1 + 1;
249 if 1 > 10 {
250 }
251
252 while 1 > 10 {
253
254 }
255 let b = 1 * 10;
256 bar(1);
257}",
258 );
259 }
260
261 #[test]
262 fn test_inline_let_bind_bin_expr() {
263 check_assist(
264 inline_local_variable,
265 r"
266fn bar(a: usize) {}
267fn foo() {
268 let a$0 = 1 + 1;
269 a + 1;
270 if a > 10 {
271 }
272
273 while a > 10 {
274
275 }
276 let b = a * 10;
277 bar(a);
278}",
279 r"
280fn bar(a: usize) {}
281fn foo() {
282 1 + 1 + 1;
283 if 1 + 1 > 10 {
284 }
285
286 while 1 + 1 > 10 {
287
288 }
289 let b = (1 + 1) * 10;
290 bar(1 + 1);
291}",
292 );
293 }
294
295 #[test]
296 fn test_inline_let_bind_function_call_expr() {
297 check_assist(
298 inline_local_variable,
299 r"
300fn bar(a: usize) {}
301fn foo() {
302 let a$0 = bar(1);
303 a + 1;
304 if a > 10 {
305 }
306
307 while a > 10 {
308
309 }
310 let b = a * 10;
311 bar(a);
312}",
313 r"
314fn bar(a: usize) {}
315fn foo() {
316 bar(1) + 1;
317 if bar(1) > 10 {
318 }
319
320 while bar(1) > 10 {
321
322 }
323 let b = bar(1) * 10;
324 bar(bar(1));
325}",
326 );
327 }
328
329 #[test]
330 fn test_inline_let_bind_cast_expr() {
331 check_assist(
332 inline_local_variable,
333 r"
334//- minicore: sized
335fn bar(a: usize) -> usize { a }
336fn foo() {
337 let a$0 = bar(1) as u64;
338 a + 1;
339 if a > 10 {
340 }
341
342 while a > 10 {
343
344 }
345 let b = a * 10;
346 bar(a);
347}",
348 r"
349fn bar(a: usize) -> usize { a }
350fn foo() {
351 bar(1) as u64 + 1;
352 if bar(1) as u64 > 10 {
353 }
354
355 while bar(1) as u64 > 10 {
356
357 }
358 let b = bar(1) as u64 * 10;
359 bar(bar(1) as u64);
360}",
361 );
362 }
363
364 #[test]
365 fn test_inline_let_bind_block_expr() {
366 check_assist(
367 inline_local_variable,
368 r"
369fn foo() {
370 let a$0 = { 10 + 1 };
371 a + 1;
372 if a > 10 {
373 }
374
375 while a > 10 {
376
377 }
378 let b = a * 10;
379 bar(a);
380}",
381 r"
382fn foo() {
383 { 10 + 1 } + 1;
384 if { 10 + 1 } > 10 {
385 }
386
387 while { 10 + 1 } > 10 {
388
389 }
390 let b = { 10 + 1 } * 10;
391 bar({ 10 + 1 });
392}",
393 );
394 }
395
396 #[test]
397 fn test_inline_let_bind_paren_expr() {
398 check_assist(
399 inline_local_variable,
400 r"
401fn foo() {
402 let a$0 = ( 10 + 1 );
403 a + 1;
404 if a > 10 {
405 }
406
407 while a > 10 {
408
409 }
410 let b = a * 10;
411 bar(a);
412}",
413 r"
414fn foo() {
415 ( 10 + 1 ) + 1;
416 if ( 10 + 1 ) > 10 {
417 }
418
419 while ( 10 + 1 ) > 10 {
420
421 }
422 let b = ( 10 + 1 ) * 10;
423 bar(( 10 + 1 ));
424}",
425 );
426 }
427
428 #[test]
429 fn test_inline_let_expr() {
430 check_assist(
431 inline_local_variable,
432 r"
433fn bar(a: usize) {}
434fn foo() {
435 if let a$0 = 1
436 && true
437 {
438 a + 1;
439 if a > 10 {}
440 while a > 10 {}
441 let b = a * 10;
442 bar(a);
443 }
444}",
445 r"
446fn bar(a: usize) {}
447fn foo() {
448 if true
449 {
450 1 + 1;
451 if 1 > 10 {}
452 while 1 > 10 {}
453 let b = 1 * 10;
454 bar(1);
455 }
456}",
457 );
458 }
459
460 #[test]
461 fn test_not_inline_mut_variable() {
462 cov_mark::check!(test_not_inline_mut_variable);
463 check_assist_not_applicable(
464 inline_local_variable,
465 r"
466fn foo() {
467 let mut a$0 = 1 + 1;
468 a + 1;
469}",
470 );
471 }
472
473 #[test]
474 fn test_not_inline_mut_variable_use() {
475 cov_mark::check!(test_not_inline_mut_variable_use);
476 check_assist_not_applicable(
477 inline_local_variable,
478 r"
479fn foo() {
480 let mut a = 1 + 1;
481 a$0 + 1;
482}",
483 );
484 }
485
486 #[test]
487 fn test_call_expr() {
488 check_assist(
489 inline_local_variable,
490 r"
491fn foo() {
492 let a$0 = bar(10 + 1);
493 let b = a * 10;
494 let c = a as usize;
495}",
496 r"
497fn foo() {
498 let b = bar(10 + 1) * 10;
499 let c = bar(10 + 1) as usize;
500}",
501 );
502 }
503
504 #[test]
505 fn test_index_expr() {
506 check_assist(
507 inline_local_variable,
508 r"
509fn foo() {
510 let x = vec![1, 2, 3];
511 let a$0 = x[0];
512 let b = a * 10;
513 let c = a as usize;
514}",
515 r"
516fn foo() {
517 let x = vec![1, 2, 3];
518 let b = x[0] * 10;
519 let c = x[0] as usize;
520}",
521 );
522 }
523
524 #[test]
525 fn test_method_call_expr() {
526 check_assist(
527 inline_local_variable,
528 r"
529fn foo() {
530 let bar = vec![1];
531 let a$0 = bar.len();
532 let b = a * 10;
533 let c = a as usize;
534}",
535 r"
536fn foo() {
537 let bar = vec![1];
538 let b = bar.len() * 10;
539 let c = bar.len() as usize;
540}",
541 );
542 }
543
544 #[test]
545 fn test_field_expr() {
546 check_assist(
547 inline_local_variable,
548 r"
549struct Bar {
550 foo: usize
551}
552
553fn foo() {
554 let bar = Bar { foo: 1 };
555 let a$0 = bar.foo;
556 let b = a * 10;
557 let c = a as usize;
558}",
559 r"
560struct Bar {
561 foo: usize
562}
563
564fn foo() {
565 let bar = Bar { foo: 1 };
566 let b = bar.foo * 10;
567 let c = bar.foo as usize;
568}",
569 );
570 }
571
572 #[test]
573 fn test_try_expr() {
574 check_assist(
575 inline_local_variable,
576 r"
577fn foo() -> Option<usize> {
578 let bar = Some(1);
579 let a$0 = bar?;
580 let b = a * 10;
581 let c = a as usize;
582 None
583}",
584 r"
585fn foo() -> Option<usize> {
586 let bar = Some(1);
587 let b = bar? * 10;
588 let c = bar? as usize;
589 None
590}",
591 );
592 }
593
594 #[test]
595 fn test_ref_expr() {
596 check_assist(
597 inline_local_variable,
598 r"
599fn foo() {
600 let bar = 10;
601 let a$0 = &bar;
602 let b = a * 10;
603}",
604 r"
605fn foo() {
606 let bar = 10;
607 let b = &bar * 10;
608}",
609 );
610 }
611
612 #[test]
613 fn test_tuple_expr() {
614 check_assist(
615 inline_local_variable,
616 r"
617fn foo() {
618 let a$0 = (10, 20);
619 let b = a[0];
620}",
621 r"
622fn foo() {
623 let b = (10, 20)[0];
624}",
625 );
626 }
627
628 #[test]
629 fn test_array_expr() {
630 check_assist(
631 inline_local_variable,
632 r"
633fn foo() {
634 let a$0 = [1, 2, 3];
635 let b = a.len();
636}",
637 r"
638fn foo() {
639 let b = [1, 2, 3].len();
640}",
641 );
642 }
643
644 #[test]
645 fn test_paren() {
646 check_assist(
647 inline_local_variable,
648 r"
649fn foo() {
650 let a$0 = (10 + 20);
651 let b = a * 10;
652 let c = a as usize;
653}",
654 r"
655fn foo() {
656 let b = (10 + 20) * 10;
657 let c = (10 + 20) as usize;
658}",
659 );
660 }
661
662 #[test]
663 fn test_path_expr() {
664 check_assist(
665 inline_local_variable,
666 r"
667fn foo() {
668 let d = 10;
669 let a$0 = d;
670 let b = a * 10;
671 let c = a as usize;
672}",
673 r"
674fn foo() {
675 let d = 10;
676 let b = d * 10;
677 let c = d as usize;
678}",
679 );
680 }
681
682 #[test]
683 fn test_block_expr() {
684 check_assist(
685 inline_local_variable,
686 r"
687fn foo() {
688 let a$0 = { 10 };
689 let b = a * 10;
690 let c = a as usize;
691}",
692 r"
693fn foo() {
694 let b = { 10 } * 10;
695 let c = { 10 } as usize;
696}",
697 );
698 }
699
700 #[test]
701 fn test_used_in_different_expr1() {
702 check_assist(
703 inline_local_variable,
704 r"
705fn foo() {
706 let a$0 = 10 + 20;
707 let b = a * 10;
708 let c = (a, 20);
709 let d = [a, 10];
710 let e = (a);
711}",
712 r"
713fn foo() {
714 let b = (10 + 20) * 10;
715 let c = (10 + 20, 20);
716 let d = [10 + 20, 10];
717 let e = (10 + 20);
718}",
719 );
720 }
721
722 #[test]
723 fn test_used_in_for_expr() {
724 check_assist(
725 inline_local_variable,
726 r"
727//- minicore: iterator
728fn foo() {
729 let a$0 = vec![10, 20];
730 for i in a {}
731}",
732 r"
733fn foo() {
734 for i in vec![10, 20] {}
735}",
736 );
737 }
738
739 #[test]
740 fn test_used_in_while_expr() {
741 check_assist(
742 inline_local_variable,
743 r"
744fn foo() {
745 let a$0 = 1 > 0;
746 while a {}
747}",
748 r"
749fn foo() {
750 while 1 > 0 {}
751}",
752 );
753 }
754
755 #[test]
756 fn test_used_in_break_expr() {
757 check_assist(
758 inline_local_variable,
759 r"
760fn foo() {
761 let a$0 = 1 + 1;
762 loop {
763 break a;
764 }
765}",
766 r"
767fn foo() {
768 loop {
769 break 1 + 1;
770 }
771}",
772 );
773 }
774
775 #[test]
776 fn test_used_in_return_expr() {
777 check_assist(
778 inline_local_variable,
779 r"
780fn foo() {
781 let a$0 = 1 > 0;
782 return a;
783}",
784 r"
785fn foo() {
786 return 1 > 0;
787}",
788 );
789 }
790
791 #[test]
792 fn test_used_in_match_expr() {
793 check_assist(
794 inline_local_variable,
795 r"
796fn foo() {
797 let a$0 = 1 > 0;
798 match a {}
799}",
800 r"
801fn foo() {
802 match 1 > 0 {}
803}",
804 );
805 }
806
807 #[test]
808 fn inline_field_shorthand() {
809 cov_mark::check!(inline_field_shorthand);
810 check_assist(
811 inline_local_variable,
812 r"
813struct S { foo: i32}
814fn main() {
815 let $0foo = 92;
816 S { foo }
817}
818",
819 r"
820struct S { foo: i32}
821fn main() {
822 S { foo: 92 }
823}
824",
825 );
826 }
827
828 #[test]
829 fn test_not_applicable_if_variable_unused() {
830 cov_mark::check!(test_not_applicable_if_variable_unused);
831 check_assist_not_applicable(
832 inline_local_variable,
833 r"
834fn foo() {
835 let $0a = 0;
836}
837 ",
838 )
839 }
840
841 #[test]
842 fn not_applicable_outside_of_bind_pat() {
843 cov_mark::check!(not_applicable_outside_of_bind_pat);
844 check_assist_not_applicable(
845 inline_local_variable,
846 r"
847fn main() {
848 let x = $01 + 2;
849 x * 4;
850}
851",
852 )
853 }
854
855 #[test]
856 fn works_on_local_usage() {
857 check_assist(
858 inline_local_variable,
859 r#"
860fn f() {
861 let xyz = 0;
862 xyz$0;
863}
864"#,
865 r#"
866fn f() {
867 0;
868}
869"#,
870 );
871 }
872
873 #[test]
874 fn let_expr_works_on_local_usage() {
875 check_assist(
876 inline_local_variable,
877 r#"
878fn f() {
879 if let xyz = 0
880 && true
881 {
882 xyz$0;
883 }
884}
885"#,
886 r#"
887fn f() {
888 if true
889 {
890 0;
891 }
892}
893"#,
894 );
895
896 check_assist(
897 inline_local_variable,
898 r#"
899fn f() {
900 if let xyz = true
901 && xyz$0
902 {
903 }
904}
905"#,
906 r#"
907fn f() {
908 if true
909 {
910 }
911}
912"#,
913 );
914
915 check_assist(
916 inline_local_variable,
917 r#"
918fn f() {
919 if true
920 && let xyz = 0
921 {
922 xyz$0;
923 }
924}
925"#,
926 r#"
927fn f() {
928 if true
929 {
930 0;
931 }
932}
933"#,
934 );
935 }
936
937 #[test]
938 fn does_not_remove_let_when_multiple_usages() {
939 check_assist(
940 inline_local_variable,
941 r#"
942fn f() {
943 let xyz = 0;
944 xyz$0;
945 xyz;
946}
947"#,
948 r#"
949fn f() {
950 let xyz = 0;
951 0;
952 xyz;
953}
954"#,
955 );
956 }
957
958 #[test]
959 fn not_applicable_with_non_ident_pattern() {
960 check_assist_not_applicable(
961 inline_local_variable,
962 r#"
963fn main() {
964 let (x, y) = (0, 1);
965 x$0;
966}
967"#,
968 );
969 }
970
971 #[test]
972 fn not_applicable_on_local_usage_in_macro() {
973 check_assist_not_applicable(
974 inline_local_variable,
975 r#"
976macro_rules! m {
977 ($i:ident) => { $i }
978}
979fn f() {
980 let xyz = 0;
981 m!(xyz$0); // replacing it would break the macro
982}
983"#,
984 );
985 check_assist_not_applicable(
986 inline_local_variable,
987 r#"
988macro_rules! m {
989 ($i:ident) => { $i }
990}
991fn f() {
992 let xyz$0 = 0;
993 m!(xyz); // replacing it would break the macro
994}
995"#,
996 );
997 }
998
999 #[test]
1000 fn test_not_inline_selection_too_broad() {
1001 cov_mark::check!(test_not_inline_selection_too_broad);
1002 check_assist_not_applicable(
1003 inline_local_variable,
1004 r#"
1005fn f() {
1006 let foo = 0;
1007 let bar = 0;
1008 $0foo + bar$0;
1009}
1010"#,
1011 );
1012 }
1013
1014 #[test]
1015 fn test_inline_ref_in_let() {
1016 check_assist(
1017 inline_local_variable,
1018 r#"
1019fn f() {
1020 let x = {
1021 let y = 0;
1022 y$0
1023 };
1024}
1025"#,
1026 r#"
1027fn f() {
1028 let x = {
1029 0
1030 };
1031}
1032"#,
1033 );
1034 }
1035
1036 #[test]
1037 fn test_inline_let_unit_struct() {
1038 check_assist_not_applicable(
1039 inline_local_variable,
1040 r#"
1041struct S;
1042fn f() {
1043 let S$0 = S;
1044 S;
1045}
1046"#,
1047 );
1048 }
1049
1050 #[test]
1051 fn test_inline_closure() {
1052 check_assist(
1053 inline_local_variable,
1054 r#"
1055//- minicore: fn
1056fn main() {
1057 let $0f = || 2;
1058 let _ = f();
1059}
1060"#,
1061 r#"
1062fn main() {
1063 let _ = (|| 2)();
1064}
1065"#,
1066 );
1067 }
1068
1069 #[test]
1070 fn test_wrap_in_parens() {
1071 check_assist(
1072 inline_local_variable,
1073 r#"
1074fn main() {
1075 let $0a = 123 < 456;
1076 let b = !a;
1077}
1078"#,
1079 r#"
1080fn main() {
1081 let b = !(123 < 456);
1082}
1083"#,
1084 );
1085 check_assist(
1086 inline_local_variable,
1087 r#"
1088trait Foo {
1089 fn foo(&self);
1090}
1091
1092impl Foo for bool {
1093 fn foo(&self) {}
1094}
1095
1096fn main() {
1097 let $0a = 123 < 456;
1098 let b = a.foo();
1099}
1100"#,
1101 r#"
1102trait Foo {
1103 fn foo(&self);
1104}
1105
1106impl Foo for bool {
1107 fn foo(&self) {}
1108}
1109
1110fn main() {
1111 let b = (123 < 456).foo();
1112}
1113"#,
1114 );
1115 }
1116}