aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/tests/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/tests/macros.rs')
-rw-r--r--crates/hir_ty/src/tests/macros.rs787
1 files changed, 787 insertions, 0 deletions
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
new file mode 100644
index 000000000..d887c7a79
--- /dev/null
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -0,0 +1,787 @@
1use std::fs;
2
3use expect::expect;
4use test_utils::project_dir;
5
6use super::{check_infer, check_types};
7
8#[test]
9fn cfg_impl_def() {
10 check_types(
11 r#"
12//- /main.rs crate:main deps:foo cfg:test
13use foo::S as T;
14struct S;
15
16#[cfg(test)]
17impl S {
18 fn foo1(&self) -> i32 { 0 }
19}
20
21#[cfg(not(test))]
22impl S {
23 fn foo2(&self) -> i32 { 0 }
24}
25
26fn test() {
27 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
28 t;
29} //^ (i32, {unknown}, i32, {unknown})
30
31//- /foo.rs crate:foo
32struct S;
33
34#[cfg(not(test))]
35impl S {
36 fn foo3(&self) -> i32 { 0 }
37}
38
39#[cfg(test)]
40impl S {
41 fn foo4(&self) -> i32 { 0 }
42}
43"#,
44 );
45}
46
47#[test]
48fn infer_macros_expanded() {
49 check_infer(
50 r#"
51 struct Foo(Vec<i32>);
52
53 macro_rules! foo {
54 ($($item:expr),*) => {
55 {
56 Foo(vec![$($item,)*])
57 }
58 };
59 }
60
61 fn main() {
62 let x = foo!(1,2);
63 }
64 "#,
65 expect![[r#"
66 !0..17 '{Foo(v...,2,])}': Foo
67 !1..4 'Foo': Foo({unknown}) -> Foo
68 !1..16 'Foo(vec![1,2,])': Foo
69 !5..15 'vec![1,2,]': {unknown}
70 155..181 '{ ...,2); }': ()
71 165..166 'x': Foo
72 "#]],
73 );
74}
75
76#[test]
77fn infer_legacy_textual_scoped_macros_expanded() {
78 check_infer(
79 r#"
80 struct Foo(Vec<i32>);
81
82 #[macro_use]
83 mod m {
84 macro_rules! foo {
85 ($($item:expr),*) => {
86 {
87 Foo(vec![$($item,)*])
88 }
89 };
90 }
91 }
92
93 fn main() {
94 let x = foo!(1,2);
95 let y = crate::foo!(1,2);
96 }
97 "#,
98 expect![[r#"
99 !0..17 '{Foo(v...,2,])}': Foo
100 !1..4 'Foo': Foo({unknown}) -> Foo
101 !1..16 'Foo(vec![1,2,])': Foo
102 !5..15 'vec![1,2,]': {unknown}
103 194..250 '{ ...,2); }': ()
104 204..205 'x': Foo
105 227..228 'y': {unknown}
106 231..247 'crate:...!(1,2)': {unknown}
107 "#]],
108 );
109}
110
111#[test]
112fn infer_path_qualified_macros_expanded() {
113 check_infer(
114 r#"
115 #[macro_export]
116 macro_rules! foo {
117 () => { 42i32 }
118 }
119
120 mod m {
121 pub use super::foo as bar;
122 }
123
124 fn main() {
125 let x = crate::foo!();
126 let y = m::bar!();
127 }
128 "#,
129 expect![[r#"
130 !0..5 '42i32': i32
131 !0..5 '42i32': i32
132 110..163 '{ ...!(); }': ()
133 120..121 'x': i32
134 147..148 'y': i32
135 "#]],
136 );
137}
138
139#[test]
140fn expr_macro_expanded_in_various_places() {
141 check_infer(
142 r#"
143 macro_rules! spam {
144 () => (1isize);
145 }
146
147 fn spam() {
148 spam!();
149 (spam!());
150 spam!().spam(spam!());
151 for _ in spam!() {}
152 || spam!();
153 while spam!() {}
154 break spam!();
155 return spam!();
156 match spam!() {
157 _ if spam!() => spam!(),
158 }
159 spam!()(spam!());
160 Spam { spam: spam!() };
161 spam!()[spam!()];
162 await spam!();
163 spam!() as usize;
164 &spam!();
165 -spam!();
166 spam!()..spam!();
167 spam!() + spam!();
168 }
169 "#,
170 expect![[r#"
171 !0..6 '1isize': isize
172 !0..6 '1isize': isize
173 !0..6 '1isize': isize
174 !0..6 '1isize': isize
175 !0..6 '1isize': isize
176 !0..6 '1isize': isize
177 !0..6 '1isize': isize
178 !0..6 '1isize': isize
179 !0..6 '1isize': isize
180 !0..6 '1isize': isize
181 !0..6 '1isize': isize
182 !0..6 '1isize': isize
183 !0..6 '1isize': isize
184 !0..6 '1isize': isize
185 !0..6 '1isize': isize
186 !0..6 '1isize': isize
187 !0..6 '1isize': isize
188 !0..6 '1isize': isize
189 !0..6 '1isize': isize
190 !0..6 '1isize': isize
191 !0..6 '1isize': isize
192 !0..6 '1isize': isize
193 !0..6 '1isize': isize
194 !0..6 '1isize': isize
195 !0..6 '1isize': isize
196 53..456 '{ ...!(); }': ()
197 87..108 'spam!(...am!())': {unknown}
198 114..133 'for _ ...!() {}': ()
199 118..119 '_': {unknown}
200 131..133 '{}': ()
201 138..148 '|| spam!()': || -> isize
202 154..170 'while ...!() {}': ()
203 168..170 '{}': ()
204 175..188 'break spam!()': !
205 194..208 'return spam!()': !
206 214..268 'match ... }': isize
207 238..239 '_': isize
208 273..289 'spam!(...am!())': {unknown}
209 295..317 'Spam {...m!() }': {unknown}
210 323..339 'spam!(...am!()]': {unknown}
211 364..380 'spam!(... usize': usize
212 386..394 '&spam!()': &isize
213 400..408 '-spam!()': isize
214 414..430 'spam!(...pam!()': {unknown}
215 436..453 'spam!(...pam!()': isize
216 "#]],
217 );
218}
219
220#[test]
221fn infer_type_value_macro_having_same_name() {
222 check_infer(
223 r#"
224 #[macro_export]
225 macro_rules! foo {
226 () => {
227 mod foo {
228 pub use super::foo;
229 }
230 };
231 ($x:tt) => {
232 $x
233 };
234 }
235
236 foo!();
237
238 fn foo() {
239 let foo = foo::foo!(42i32);
240 }
241 "#,
242 expect![[r#"
243 !0..5 '42i32': i32
244 170..205 '{ ...32); }': ()
245 180..183 'foo': i32
246 "#]],
247 );
248}
249
250#[test]
251fn processes_impls_generated_by_macros() {
252 check_types(
253 r#"
254macro_rules! m {
255 ($ident:ident) => (impl Trait for $ident {})
256}
257trait Trait { fn foo(self) -> u128 {} }
258struct S;
259m!(S);
260fn test() { S.foo(); }
261 //^ u128
262"#,
263 );
264}
265
266#[test]
267fn infer_assoc_items_generated_by_macros() {
268 check_types(
269 r#"
270macro_rules! m {
271 () => (fn foo(&self) -> u128 {0})
272}
273struct S;
274impl S {
275 m!();
276}
277
278fn test() { S.foo(); }
279 //^ u128
280"#,
281 );
282}
283
284#[test]
285fn infer_assoc_items_generated_by_macros_chain() {
286 check_types(
287 r#"
288macro_rules! m_inner {
289 () => {fn foo(&self) -> u128 {0}}
290}
291macro_rules! m {
292 () => {m_inner!();}
293}
294
295struct S;
296impl S {
297 m!();
298}
299
300fn test() { S.foo(); }
301 //^ u128
302"#,
303 );
304}
305
306#[test]
307fn infer_macro_with_dollar_crate_is_correct_in_expr() {
308 check_types(
309 r#"
310//- /main.rs crate:main deps:foo
311fn test() {
312 let x = (foo::foo!(1), foo::foo!(2));
313 x;
314} //^ (i32, usize)
315
316//- /lib.rs crate:foo
317#[macro_export]
318macro_rules! foo {
319 (1) => { $crate::bar!() };
320 (2) => { 1 + $crate::baz() };
321}
322
323#[macro_export]
324macro_rules! bar {
325 () => { 42 }
326}
327
328pub fn baz() -> usize { 31usize }
329"#,
330 );
331}
332
333#[test]
334fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
335 check_types(
336 r#"
337//- /main.rs crate:main deps:foo
338use foo::Trait;
339
340fn test() {
341 let msg = foo::Message(foo::MessageRef);
342 let r = msg.deref();
343 r;
344 //^ &MessageRef
345}
346
347//- /lib.rs crate:foo
348pub struct MessageRef;
349pub struct Message(MessageRef);
350
351pub trait Trait {
352 type Target;
353 fn deref(&self) -> &Self::Target;
354}
355
356#[macro_export]
357macro_rules! expand {
358 () => {
359 impl Trait for Message {
360 type Target = $crate::MessageRef;
361 fn deref(&self) -> &Self::Target {
362 &self.0
363 }
364 }
365 }
366}
367
368expand!();
369"#,
370 );
371}
372
373#[test]
374fn infer_type_value_non_legacy_macro_use_as() {
375 check_infer(
376 r#"
377 mod m {
378 macro_rules! _foo {
379 ($x:ident) => { type $x = u64; }
380 }
381 pub(crate) use _foo as foo;
382 }
383
384 m::foo!(foo);
385 use foo as bar;
386 fn f() -> bar { 0 }
387 fn main() {
388 let _a = f();
389 }
390 "#,
391 expect![[r#"
392 158..163 '{ 0 }': u64
393 160..161 '0': u64
394 174..196 '{ ...f(); }': ()
395 184..186 '_a': u64
396 190..191 'f': fn f() -> u64
397 190..193 'f()': u64
398 "#]],
399 );
400}
401
402#[test]
403fn infer_local_macro() {
404 check_infer(
405 r#"
406 fn main() {
407 macro_rules! foo {
408 () => { 1usize }
409 }
410 let _a = foo!();
411 }
412 "#,
413 expect![[r#"
414 !0..6 '1usize': usize
415 10..89 '{ ...!(); }': ()
416 16..65 'macro_... }': {unknown}
417 74..76 '_a': usize
418 "#]],
419 );
420}
421
422#[test]
423fn infer_local_inner_macros() {
424 check_types(
425 r#"
426//- /main.rs crate:main deps:foo
427fn test() {
428 let x = foo::foo!(1);
429 x;
430} //^ i32
431
432//- /lib.rs crate:foo
433#[macro_export(local_inner_macros)]
434macro_rules! foo {
435 (1) => { bar!() };
436}
437
438#[macro_export]
439macro_rules! bar {
440 () => { 42 }
441}
442
443"#,
444 );
445}
446
447#[test]
448fn infer_builtin_macros_line() {
449 check_infer(
450 r#"
451 #[rustc_builtin_macro]
452 macro_rules! line {() => {}}
453
454 fn main() {
455 let x = line!();
456 }
457 "#,
458 expect![[r#"
459 !0..1 '0': i32
460 63..87 '{ ...!(); }': ()
461 73..74 'x': i32
462 "#]],
463 );
464}
465
466#[test]
467fn infer_builtin_macros_file() {
468 check_infer(
469 r#"
470 #[rustc_builtin_macro]
471 macro_rules! file {() => {}}
472
473 fn main() {
474 let x = file!();
475 }
476 "#,
477 expect![[r#"
478 !0..2 '""': &str
479 63..87 '{ ...!(); }': ()
480 73..74 'x': &str
481 "#]],
482 );
483}
484
485#[test]
486fn infer_builtin_macros_column() {
487 check_infer(
488 r#"
489 #[rustc_builtin_macro]
490 macro_rules! column {() => {}}
491
492 fn main() {
493 let x = column!();
494 }
495 "#,
496 expect![[r#"
497 !0..1 '0': i32
498 65..91 '{ ...!(); }': ()
499 75..76 'x': i32
500 "#]],
501 );
502}
503
504#[test]
505fn infer_builtin_macros_concat() {
506 check_infer(
507 r#"
508 #[rustc_builtin_macro]
509 macro_rules! concat {() => {}}
510
511 fn main() {
512 let x = concat!("hello", concat!("world", "!"));
513 }
514 "#,
515 expect![[r#"
516 !0..13 '"helloworld!"': &str
517 65..121 '{ ...")); }': ()
518 75..76 'x': &str
519 "#]],
520 );
521}
522
523#[test]
524fn infer_builtin_macros_include() {
525 check_types(
526 r#"
527//- /main.rs
528#[rustc_builtin_macro]
529macro_rules! include {() => {}}
530
531include!("foo.rs");
532
533fn main() {
534 bar();
535} //^ u32
536
537//- /foo.rs
538fn bar() -> u32 {0}
539"#,
540 );
541}
542
543#[test]
544#[ignore]
545fn include_accidentally_quadratic() {
546 let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic");
547 let big_file = fs::read_to_string(file).unwrap();
548 let big_file = vec![big_file; 10].join("\n");
549
550 let fixture = r#"
551//- /main.rs
552#[rustc_builtin_macro]
553macro_rules! include {() => {}}
554
555include!("foo.rs");
556
557fn main() {
558 RegisterBlock { };
559 //^ RegisterBlock
560}
561 "#;
562 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
563 check_types(&fixture);
564}
565
566#[test]
567fn infer_builtin_macros_include_concat() {
568 check_types(
569 r#"
570//- /main.rs
571#[rustc_builtin_macro]
572macro_rules! include {() => {}}
573
574#[rustc_builtin_macro]
575macro_rules! concat {() => {}}
576
577include!(concat!("f", "oo.rs"));
578
579fn main() {
580 bar();
581} //^ u32
582
583//- /foo.rs
584fn bar() -> u32 {0}
585"#,
586 );
587}
588
589#[test]
590fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
591 check_types(
592 r#"
593//- /main.rs
594#[rustc_builtin_macro]
595macro_rules! include {() => {}}
596
597#[rustc_builtin_macro]
598macro_rules! concat {() => {}}
599
600#[rustc_builtin_macro]
601macro_rules! env {() => {}}
602
603include!(concat!(env!("OUT_DIR"), "/foo.rs"));
604
605fn main() {
606 bar();
607} //^ {unknown}
608
609//- /foo.rs
610fn bar() -> u32 {0}
611"#,
612 );
613}
614
615#[test]
616fn infer_builtin_macros_include_itself_should_failed() {
617 check_types(
618 r#"
619#[rustc_builtin_macro]
620macro_rules! include {() => {}}
621
622include!("main.rs");
623
624fn main() {
625 0
626} //^ i32
627"#,
628 );
629}
630
631#[test]
632fn infer_builtin_macros_concat_with_lazy() {
633 check_infer(
634 r#"
635 macro_rules! hello {() => {"hello"}}
636
637 #[rustc_builtin_macro]
638 macro_rules! concat {() => {}}
639
640 fn main() {
641 let x = concat!(hello!(), concat!("world", "!"));
642 }
643 "#,
644 expect![[r#"
645 !0..13 '"helloworld!"': &str
646 103..160 '{ ...")); }': ()
647 113..114 'x': &str
648 "#]],
649 );
650}
651
652#[test]
653fn infer_builtin_macros_env() {
654 check_infer(
655 r#"
656 //- /main.rs env:foo=bar
657 #[rustc_builtin_macro]
658 macro_rules! env {() => {}}
659
660 fn main() {
661 let x = env!("foo");
662 }
663 "#,
664 expect![[r#"
665 !0..22 '"__RA_...TED__"': &str
666 62..90 '{ ...o"); }': ()
667 72..73 'x': &str
668 "#]],
669 );
670}
671
672#[test]
673fn infer_derive_clone_simple() {
674 check_types(
675 r#"
676//- /main.rs crate:main deps:core
677#[derive(Clone)]
678struct S;
679fn test() {
680 S.clone();
681} //^ S
682
683//- /lib.rs crate:core
684#[prelude_import]
685use clone::*;
686mod clone {
687 trait Clone {
688 fn clone(&self) -> Self;
689 }
690}
691"#,
692 );
693}
694
695#[test]
696fn infer_derive_clone_in_core() {
697 check_types(
698 r#"
699//- /lib.rs crate:core
700#[prelude_import]
701use clone::*;
702mod clone {
703 trait Clone {
704 fn clone(&self) -> Self;
705 }
706}
707#[derive(Clone)]
708pub struct S;
709
710//- /main.rs crate:main deps:core
711use core::S;
712fn test() {
713 S.clone();
714} //^ S
715"#,
716 );
717}
718
719#[test]
720fn infer_derive_clone_with_params() {
721 check_types(
722 r#"
723//- /main.rs crate:main deps:core
724#[derive(Clone)]
725struct S;
726#[derive(Clone)]
727struct Wrapper<T>(T);
728struct NonClone;
729fn test() {
730 (Wrapper(S).clone(), Wrapper(NonClone).clone());
731 //^ (Wrapper<S>, {unknown})
732}
733
734//- /lib.rs crate:core
735#[prelude_import]
736use clone::*;
737mod clone {
738 trait Clone {
739 fn clone(&self) -> Self;
740 }
741}
742"#,
743 );
744}
745
746#[test]
747fn infer_custom_derive_simple() {
748 // FIXME: this test current now do nothing
749 check_types(
750 r#"
751//- /main.rs crate:main
752use foo::Foo;
753
754#[derive(Foo)]
755struct S{}
756
757fn test() {
758 S{};
759} //^ S
760"#,
761 );
762}
763
764#[test]
765fn macro_in_arm() {
766 check_infer(
767 r#"
768 macro_rules! unit {
769 () => { () };
770 }
771
772 fn main() {
773 let x = match () {
774 unit!() => 92u32,
775 };
776 }
777 "#,
778 expect![[r#"
779 51..110 '{ ... }; }': ()
780 61..62 'x': u32
781 65..107 'match ... }': u32
782 71..73 '()': ()
783 84..91 'unit!()': ()
784 95..100 '92u32': u32
785 "#]],
786 );
787}