1 use base_db::{fixture::WithFixture, FileId};
2 use chalk_ir::Substitution;
3 use hir_def::db::DefDatabase;
4
5 use crate::{
6 consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar,
7 Interner,
8 };
9
10 use super::{
11 super::mir::{MirEvalError, MirLowerError},
12 ConstEvalError,
13 };
14
15 mod intrinsics;
16
simplify(e: ConstEvalError) -> ConstEvalError17 fn simplify(e: ConstEvalError) -> ConstEvalError {
18 match e {
19 ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e, _, _)) => {
20 simplify(ConstEvalError::MirEvalError(*e))
21 }
22 _ => e,
23 }
24 }
25
26 #[track_caller]
check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool)27 fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) {
28 let (db, file_id) = TestDB::with_single_file(ra_fixture);
29 match eval_goal(&db, file_id) {
30 Ok(_) => panic!("Expected fail, but it succeeded"),
31 Err(e) => {
32 assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db))
33 }
34 }
35 }
36
37 #[track_caller]
check_number(ra_fixture: &str, answer: i128)38 fn check_number(ra_fixture: &str, answer: i128) {
39 let (db, file_id) = TestDB::with_single_file(ra_fixture);
40 let r = match eval_goal(&db, file_id) {
41 Ok(t) => t,
42 Err(e) => {
43 let err = pretty_print_err(e, db);
44 panic!("Error in evaluating goal: {}", err);
45 }
46 };
47 match &r.data(Interner).value {
48 chalk_ir::ConstValue::Concrete(c) => match &c.interned {
49 ConstScalar::Bytes(b, _) => {
50 assert_eq!(
51 b,
52 &answer.to_le_bytes()[0..b.len()],
53 "Bytes differ. In decimal form: actual = {}, expected = {answer}",
54 i128::from_le_bytes(pad16(b, true))
55 );
56 }
57 x => panic!("Expected number but found {:?}", x),
58 },
59 _ => panic!("result of const eval wasn't a concrete const"),
60 }
61 }
62
pretty_print_err(e: ConstEvalError, db: TestDB) -> String63 fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
64 let mut err = String::new();
65 let span_formatter = |file, range| format!("{:?} {:?}", file, range);
66 match e {
67 ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter),
68 ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter),
69 }
70 .unwrap();
71 err
72 }
73
eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError>74 fn eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError> {
75 let module_id = db.module_for_file(file_id);
76 let def_map = module_id.def_map(db);
77 let scope = &def_map[module_id.local_id].scope;
78 let const_id = scope
79 .declarations()
80 .find_map(|x| match x {
81 hir_def::ModuleDefId::ConstId(x) => {
82 if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" {
83 Some(x)
84 } else {
85 None
86 }
87 }
88 _ => None,
89 })
90 .unwrap();
91 db.const_eval(const_id.into(), Substitution::empty(Interner))
92 }
93
94 #[test]
add()95 fn add() {
96 check_number(r#"const GOAL: usize = 2 + 2;"#, 4);
97 check_number(r#"const GOAL: i32 = -2 + --5;"#, 3);
98 check_number(r#"const GOAL: i32 = 7 - 5;"#, 2);
99 check_number(r#"const GOAL: i32 = 7 + (1 - 5);"#, 3);
100 }
101
102 #[test]
bit_op()103 fn bit_op() {
104 check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
105 check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
106 check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128);
107 check_number(r#"const GOAL: i8 = -1 << 2"#, (-1i8 << 2) as i128);
108 check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| {
109 e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string()))
110 });
111 }
112
113 #[test]
floating_point()114 fn floating_point() {
115 check_number(
116 r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#,
117 i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)),
118 );
119 check_number(
120 r#"const GOAL: f32 = 2.0 + 3.0 * 5.5 - 8.;"#,
121 i128::from_le_bytes(pad16(&f32::to_le_bytes(10.5), true)),
122 );
123 check_number(
124 r#"const GOAL: f32 = -90.0 + 36.0;"#,
125 i128::from_le_bytes(pad16(&f32::to_le_bytes(-54.0), true)),
126 );
127 }
128
129 #[test]
casts()130 fn casts() {
131 check_number(r#"const GOAL: usize = 12 as *const i32 as usize"#, 12);
132 check_number(
133 r#"
134 //- minicore: coerce_unsized, index, slice
135 const GOAL: i32 = {
136 let a = [10, 20, 3, 15];
137 let x: &[i32] = &a;
138 let y: *const [i32] = x;
139 let z = y as *const i32;
140 unsafe { *z }
141 };
142 "#,
143 10,
144 );
145 check_number(
146 r#"
147 //- minicore: coerce_unsized, index, slice
148 const GOAL: i16 = {
149 let a = &mut 5;
150 let z = a as *mut _;
151 unsafe { *z }
152 };
153 "#,
154 5,
155 );
156 check_number(
157 r#"
158 //- minicore: coerce_unsized, index, slice
159 const GOAL: usize = {
160 let a = &[10, 20, 30, 40] as &[i32];
161 a.len()
162 };
163 "#,
164 4,
165 );
166 check_number(
167 r#"
168 //- minicore: coerce_unsized, index, slice
169 const GOAL: usize = {
170 let a = [10, 20, 3, 15];
171 let x: &[i32] = &a;
172 let y: *const [i32] = x;
173 let z = y as *const [u8]; // slice fat pointer cast don't touch metadata
174 let q = z as *const str;
175 let p = q as *const [u8];
176 let w = unsafe { &*z };
177 w.len()
178 };
179 "#,
180 4,
181 );
182 check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
183 }
184
185 #[test]
raw_pointer_equality()186 fn raw_pointer_equality() {
187 check_number(
188 r#"
189 //- minicore: copy, eq
190 const GOAL: bool = {
191 let a = 2;
192 let p1 = a as *const i32;
193 let p2 = a as *const i32;
194 p1 == p2
195 };
196 "#,
197 1,
198 );
199 }
200
201 #[test]
locals()202 fn locals() {
203 check_number(
204 r#"
205 const GOAL: usize = {
206 let a = 3 + 2;
207 let b = a * a;
208 b
209 };
210 "#,
211 25,
212 );
213 }
214
215 #[test]
references()216 fn references() {
217 check_number(
218 r#"
219 const GOAL: usize = {
220 let x = 3;
221 let y = &mut x;
222 *y = 5;
223 x
224 };
225 "#,
226 5,
227 );
228 check_number(
229 r#"
230 struct Foo(i32);
231 impl Foo {
232 fn method(&mut self, x: i32) {
233 self.0 = 2 * self.0 + x;
234 }
235 }
236 const GOAL: i32 = {
237 let mut x = Foo(3);
238 x.method(5);
239 x.0
240 };
241 "#,
242 11,
243 );
244 }
245
246 #[test]
reference_autoderef()247 fn reference_autoderef() {
248 check_number(
249 r#"
250 const GOAL: usize = {
251 let x = 3;
252 let y = &mut x;
253 let y: &mut usize = &mut y;
254 *y = 5;
255 x
256 };
257 "#,
258 5,
259 );
260 check_number(
261 r#"
262 const GOAL: usize = {
263 let x = 3;
264 let y = &&&&&&&x;
265 let z: &usize = &y;
266 *z
267 };
268 "#,
269 3,
270 );
271 check_number(
272 r#"
273 struct Foo<T> { x: T }
274 impl<T> Foo<T> {
275 fn foo(&mut self) -> T { self.x }
276 }
277 fn f(i: &mut &mut Foo<Foo<i32>>) -> i32 {
278 ((**i).x).foo()
279 }
280 fn g(i: Foo<Foo<i32>>) -> i32 {
281 i.x.foo()
282 }
283 const GOAL: i32 = f(&mut &mut Foo { x: Foo { x: 3 } }) + g(Foo { x: Foo { x: 5 } });
284 "#,
285 8,
286 );
287 }
288
289 #[test]
overloaded_deref()290 fn overloaded_deref() {
291 check_number(
292 r#"
293 //- minicore: deref_mut
294 struct Foo;
295
296 impl core::ops::Deref for Foo {
297 type Target = i32;
298 fn deref(&self) -> &i32 {
299 &5
300 }
301 }
302
303 const GOAL: i32 = {
304 let x = Foo;
305 let y = &*x;
306 *y + *x
307 };
308 "#,
309 10,
310 );
311 }
312
313 #[test]
overloaded_deref_autoref()314 fn overloaded_deref_autoref() {
315 check_number(
316 r#"
317 //- minicore: deref_mut
318 struct Foo;
319 struct Bar;
320
321 impl core::ops::Deref for Foo {
322 type Target = Bar;
323 fn deref(&self) -> &Bar {
324 &Bar
325 }
326 }
327
328 impl Bar {
329 fn method(&self) -> i32 {
330 5
331 }
332 }
333
334 const GOAL: i32 = Foo.method();
335 "#,
336 5,
337 );
338 }
339
340 #[test]
overloaded_index()341 fn overloaded_index() {
342 check_number(
343 r#"
344 //- minicore: index
345 struct Foo;
346
347 impl core::ops::Index<usize> for Foo {
348 type Output = i32;
349 fn index(&self, index: usize) -> &i32 {
350 if index == 7 {
351 &700
352 } else {
353 &1000
354 }
355 }
356 }
357
358 impl core::ops::IndexMut<usize> for Foo {
359 fn index_mut(&mut self, index: usize) -> &mut i32 {
360 if index == 7 {
361 &mut 7
362 } else {
363 &mut 10
364 }
365 }
366 }
367
368 const GOAL: i32 = {
369 (Foo[2]) + (Foo[7]) + (*&Foo[2]) + (*&Foo[7]) + (*&mut Foo[2]) + (*&mut Foo[7])
370 };
371 "#,
372 3417,
373 );
374 }
375
376 #[test]
overloaded_binop()377 fn overloaded_binop() {
378 check_number(
379 r#"
380 //- minicore: add
381 enum Color {
382 Red,
383 Green,
384 Yellow,
385 }
386
387 use Color::*;
388
389 impl core::ops::Add for Color {
390 type Output = Color;
391 fn add(self, rhs: Color) -> Self::Output {
392 Yellow
393 }
394 }
395
396 impl core::ops::AddAssign for Color {
397 fn add_assign(&mut self, rhs: Color) {
398 *self = Red;
399 }
400 }
401
402 const GOAL: bool = {
403 let x = Red + Green;
404 let mut y = Green;
405 y += x;
406 x == Yellow && y == Red && Red + Green == Yellow && Red + Red == Yellow && Yellow + Green == Yellow
407 };
408 "#,
409 1,
410 );
411 check_number(
412 r#"
413 //- minicore: add
414 impl core::ops::Add for usize {
415 type Output = usize;
416 fn add(self, rhs: usize) -> Self::Output {
417 self + rhs
418 }
419 }
420
421 impl core::ops::AddAssign for usize {
422 fn add_assign(&mut self, rhs: usize) {
423 *self += rhs;
424 }
425 }
426
427 #[lang = "shl"]
428 pub trait Shl<Rhs = Self> {
429 type Output;
430
431 fn shl(self, rhs: Rhs) -> Self::Output;
432 }
433
434 impl Shl<u8> for usize {
435 type Output = usize;
436
437 fn shl(self, rhs: u8) -> Self::Output {
438 self << rhs
439 }
440 }
441
442 const GOAL: usize = {
443 let mut x = 10;
444 x += 20;
445 2 + 2 + (x << 1u8)
446 };"#,
447 64,
448 );
449 }
450
451 #[test]
function_call()452 fn function_call() {
453 check_number(
454 r#"
455 const fn f(x: usize) -> usize {
456 2 * x + 5
457 }
458 const GOAL: usize = f(3);
459 "#,
460 11,
461 );
462 check_number(
463 r#"
464 const fn add(x: usize, y: usize) -> usize {
465 x + y
466 }
467 const GOAL: usize = add(add(1, 2), add(3, add(4, 5)));
468 "#,
469 15,
470 );
471 }
472
473 #[test]
trait_basic()474 fn trait_basic() {
475 check_number(
476 r#"
477 trait Foo {
478 fn f(&self) -> u8;
479 }
480
481 impl Foo for u8 {
482 fn f(&self) -> u8 {
483 *self + 33
484 }
485 }
486
487 const GOAL: u8 = {
488 let x = 3;
489 Foo::f(&x)
490 };
491 "#,
492 36,
493 );
494 }
495
496 #[test]
trait_method()497 fn trait_method() {
498 check_number(
499 r#"
500 trait Foo {
501 fn f(&self) -> u8;
502 }
503
504 impl Foo for u8 {
505 fn f(&self) -> u8 {
506 *self + 33
507 }
508 }
509
510 const GOAL: u8 = {
511 let x = 3;
512 x.f()
513 };
514 "#,
515 36,
516 );
517 }
518
519 #[test]
trait_method_inside_block()520 fn trait_method_inside_block() {
521 check_number(
522 r#"
523 trait Twait {
524 fn a(&self) -> i32;
525 }
526
527 fn outer() -> impl Twait {
528 struct Stwuct;
529
530 impl Twait for Stwuct {
531 fn a(&self) -> i32 {
532 5
533 }
534 }
535 fn f() -> impl Twait {
536 let s = Stwuct;
537 s
538 }
539 f()
540 }
541
542 const GOAL: i32 = outer().a();
543 "#,
544 5,
545 );
546 }
547
548 #[test]
generic_fn()549 fn generic_fn() {
550 check_number(
551 r#"
552 trait Foo {
553 fn f(&self) -> u8;
554 }
555
556 impl Foo for () {
557 fn f(&self) -> u8 {
558 0
559 }
560 }
561
562 struct Succ<S>(S);
563
564 impl<T: Foo> Foo for Succ<T> {
565 fn f(&self) -> u8 {
566 self.0.f() + 1
567 }
568 }
569
570 const GOAL: u8 = Succ(Succ(())).f();
571 "#,
572 2,
573 );
574 check_number(
575 r#"
576 trait Foo {
577 fn f(&self) -> u8;
578 }
579
580 impl Foo for u8 {
581 fn f(&self) -> u8 {
582 *self + 33
583 }
584 }
585
586 fn foof<T: Foo>(x: T, y: T) -> u8 {
587 x.f() + y.f()
588 }
589
590 const GOAL: u8 = foof(2, 5);
591 "#,
592 73,
593 );
594 check_number(
595 r#"
596 fn bar<A, B>(a: A, b: B) -> B {
597 b
598 }
599 const GOAL: u8 = bar("hello", 12);
600 "#,
601 12,
602 );
603 check_number(
604 r#"
605 const fn y<T>(b: T) -> (T, ) {
606 let alloc = b;
607 (alloc, )
608 }
609 const GOAL: u8 = y(2).0;
610 "#,
611 2,
612 );
613 check_number(
614 r#"
615 //- minicore: coerce_unsized, index, slice
616 fn bar<A, B>(a: A, b: B) -> B {
617 b
618 }
619 fn foo<T>(x: [T; 2]) -> T {
620 bar(x[0], x[1])
621 }
622
623 const GOAL: u8 = foo([2, 5]);
624 "#,
625 5,
626 );
627 }
628
629 #[test]
impl_trait()630 fn impl_trait() {
631 check_number(
632 r#"
633 trait Foo {
634 fn f(&self) -> u8;
635 }
636
637 impl Foo for u8 {
638 fn f(&self) -> u8 {
639 *self + 33
640 }
641 }
642
643 fn foof(x: impl Foo, y: impl Foo) -> impl Foo {
644 x.f() + y.f()
645 }
646
647 const GOAL: u8 = foof(2, 5).f();
648 "#,
649 106,
650 );
651 check_number(
652 r#"
653 struct Foo<T>(T, T, (T, T));
654 trait S {
655 fn sum(&self) -> i64;
656 }
657 impl S for i64 {
658 fn sum(&self) -> i64 {
659 *self
660 }
661 }
662 impl<T: S> S for Foo<T> {
663 fn sum(&self) -> i64 {
664 self.0.sum() + self.1.sum() + self.2 .0.sum() + self.2 .1.sum()
665 }
666 }
667
668 fn foo() -> Foo<impl S> {
669 Foo(
670 Foo(1i64, 2, (3, 4)),
671 Foo(5, 6, (7, 8)),
672 (
673 Foo(9, 10, (11, 12)),
674 Foo(13, 14, (15, 16)),
675 ),
676 )
677 }
678 const GOAL: i64 = foo().sum();
679 "#,
680 136,
681 );
682 }
683
684 #[test]
ifs()685 fn ifs() {
686 check_number(
687 r#"
688 const fn f(b: bool) -> u8 {
689 if b { 1 } else { 10 }
690 }
691
692 const GOAL: u8 = f(true) + f(true) + f(false);
693 "#,
694 12,
695 );
696 check_number(
697 r#"
698 const fn max(a: i32, b: i32) -> i32 {
699 if a < b { b } else { a }
700 }
701
702 const GOAL: i32 = max(max(1, max(10, 3)), 0-122);
703 "#,
704 10,
705 );
706
707 check_number(
708 r#"
709 const fn max(a: &i32, b: &i32) -> &i32 {
710 if *a < *b { b } else { a }
711 }
712
713 const GOAL: i32 = *max(max(&1, max(&10, &3)), &5);
714 "#,
715 10,
716 );
717 }
718
719 #[test]
loops()720 fn loops() {
721 check_number(
722 r#"
723 const GOAL: u8 = {
724 let mut x = 0;
725 loop {
726 x = x + 1;
727 while true {
728 break;
729 }
730 x = x + 1;
731 if x == 2 {
732 continue;
733 }
734 break;
735 }
736 x
737 };
738 "#,
739 4,
740 );
741 check_number(
742 r#"
743 const GOAL: u8 = {
744 let mut x = 0;
745 loop {
746 x = x + 1;
747 if x == 5 {
748 break x + 2;
749 }
750 }
751 };
752 "#,
753 7,
754 );
755 check_number(
756 r#"
757 const GOAL: u8 = {
758 'a: loop {
759 let x = 'b: loop {
760 let x = 'c: loop {
761 let x = 'd: loop {
762 let x = 'e: loop {
763 break 'd 1;
764 };
765 break 2 + x;
766 };
767 break 3 + x;
768 };
769 break 'a 4 + x;
770 };
771 break 5 + x;
772 }
773 };
774 "#,
775 8,
776 );
777 check_number(
778 r#"
779 //- minicore: add
780 const GOAL: u8 = {
781 let mut x = 0;
782 'a: loop {
783 'b: loop {
784 'c: while x < 20 {
785 'd: while x < 5 {
786 'e: loop {
787 x += 1;
788 continue 'c;
789 };
790 };
791 x += 1;
792 };
793 break 'a;
794 };
795 }
796 x
797 };
798 "#,
799 20,
800 );
801 }
802
803 #[test]
for_loops()804 fn for_loops() {
805 check_number(
806 r#"
807 //- minicore: iterator
808
809 struct Range {
810 start: u8,
811 end: u8,
812 }
813
814 impl Iterator for Range {
815 type Item = u8;
816 fn next(&mut self) -> Option<u8> {
817 if self.start >= self.end {
818 None
819 } else {
820 let r = self.start;
821 self.start = self.start + 1;
822 Some(r)
823 }
824 }
825 }
826
827 const GOAL: u8 = {
828 let mut sum = 0;
829 let ar = Range { start: 1, end: 11 };
830 for i in ar {
831 sum = sum + i;
832 }
833 sum
834 };
835 "#,
836 55,
837 );
838 }
839
840 #[test]
ranges()841 fn ranges() {
842 check_number(
843 r#"
844 //- minicore: range
845 const GOAL: i32 = (1..2).start + (20..10).end + (100..=200).start + (2000..=1000).end
846 + (10000..).start + (..100000).end + (..=1000000).end;
847 "#,
848 1111111,
849 );
850 }
851
852 #[test]
recursion()853 fn recursion() {
854 check_number(
855 r#"
856 const fn fact(k: i32) -> i32 {
857 if k > 0 { fact(k - 1) * k } else { 1 }
858 }
859
860 const GOAL: i32 = fact(5);
861 "#,
862 120,
863 );
864 }
865
866 #[test]
structs()867 fn structs() {
868 check_number(
869 r#"
870 struct Point {
871 x: i32,
872 y: i32,
873 }
874
875 const GOAL: i32 = {
876 let p = Point { x: 5, y: 2 };
877 let y = 1;
878 let x = 3;
879 let q = Point { y, x };
880 p.x + p.y + p.x + q.y + q.y + q.x
881 };
882 "#,
883 17,
884 );
885 check_number(
886 r#"
887 struct Point {
888 x: i32,
889 y: i32,
890 }
891
892 const GOAL: i32 = {
893 let p = Point { x: 5, y: 2 };
894 let p2 = Point { x: 3, ..p };
895 p.x * 1000 + p.y * 100 + p2.x * 10 + p2.y
896 };
897 "#,
898 5232,
899 );
900 check_number(
901 r#"
902 struct Point {
903 x: i32,
904 y: i32,
905 }
906
907 const GOAL: i32 = {
908 let p = Point { x: 5, y: 2 };
909 let Point { x, y } = p;
910 let Point { x: x2, .. } = p;
911 let Point { y: y2, .. } = p;
912 x * 1000 + y * 100 + x2 * 10 + y2
913 };
914 "#,
915 5252,
916 );
917 }
918
919 #[test]
unions()920 fn unions() {
921 check_number(
922 r#"
923 union U {
924 f1: i64,
925 f2: (i32, i32),
926 }
927
928 const GOAL: i32 = {
929 let p = U { f1: 0x0123ABCD0123DCBA };
930 let p = unsafe { p.f2 };
931 p.0 + p.1 + p.1
932 };
933 "#,
934 0x0123ABCD * 2 + 0x0123DCBA,
935 );
936 }
937
938 #[test]
tuples()939 fn tuples() {
940 check_number(
941 r#"
942 const GOAL: u8 = {
943 let a = (10, 20, 3, 15);
944 a.1
945 };
946 "#,
947 20,
948 );
949 check_number(
950 r#"
951 const GOAL: u8 = {
952 let mut a = (10, 20, 3, 15);
953 a.1 = 2;
954 a.0 + a.1 + a.2 + a.3
955 };
956 "#,
957 30,
958 );
959 check_number(
960 r#"
961 struct TupleLike(i32, i64, u8, u16);
962 const GOAL: i64 = {
963 let a = TupleLike(10, 20, 3, 15);
964 let TupleLike(b, .., c) = a;
965 a.1 * 100 + b as i64 + c as i64
966 };
967 "#,
968 2025,
969 );
970 check_number(
971 r#"
972 const GOAL: u8 = {
973 match (&(2 + 2), &4) {
974 (left_val, right_val) => {
975 if !(*left_val == *right_val) {
976 2
977 } else {
978 5
979 }
980 }
981 }
982 };
983 "#,
984 5,
985 );
986 }
987
988 #[test]
path_pattern_matching()989 fn path_pattern_matching() {
990 check_number(
991 r#"
992 enum Season {
993 Spring,
994 Summer,
995 Fall,
996 Winter,
997 }
998
999 use Season::*;
1000
1001 const MY_SEASON: Season = Summer;
1002
1003 impl Season {
1004 const FALL: Season = Fall;
1005 }
1006
1007 const fn f(x: Season) -> i32 {
1008 match x {
1009 Spring => 1,
1010 MY_SEASON => 2,
1011 Season::FALL => 3,
1012 Winter => 4,
1013 }
1014 }
1015 const GOAL: i32 = f(Spring) + 10 * f(Summer) + 100 * f(Fall) + 1000 * f(Winter);
1016 "#,
1017 4321,
1018 );
1019 }
1020
1021 #[test]
pattern_matching_literal()1022 fn pattern_matching_literal() {
1023 check_number(
1024 r#"
1025 const fn f(x: i32) -> i32 {
1026 match x {
1027 -1 => 1,
1028 1 => 10,
1029 _ => 100,
1030 }
1031 }
1032 const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5);
1033 "#,
1034 211,
1035 );
1036 check_number(
1037 r#"
1038 const fn f(x: &str) -> i32 {
1039 match x {
1040 "f" => 1,
1041 "foo" => 10,
1042 "" => 100,
1043 "bar" => 1000,
1044 _ => 10000,
1045 }
1046 }
1047 const GOAL: i32 = f("f") + f("foo") * 2 + f("") * 3 + f("bar") * 4;
1048 "#,
1049 4321,
1050 );
1051 }
1052
1053 #[test]
pattern_matching_range()1054 fn pattern_matching_range() {
1055 check_number(
1056 r#"
1057 pub const L: i32 = 6;
1058 mod x {
1059 pub const R: i32 = 100;
1060 }
1061 const fn f(x: i32) -> i32 {
1062 match x {
1063 -1..=5 => x * 10,
1064 L..=x::R => x * 100,
1065 _ => x,
1066 }
1067 }
1068 const GOAL: i32 = f(-1) + f(2) + f(100) + f(-2) + f(1000);
1069 "#,
1070 11008,
1071 );
1072 }
1073
1074 #[test]
pattern_matching_slice()1075 fn pattern_matching_slice() {
1076 check_number(
1077 r#"
1078 //- minicore: slice, index, coerce_unsized, copy
1079 const fn f(x: &[usize]) -> usize {
1080 match x {
1081 [a, b @ .., c, d] => *a + b.len() + *c + *d,
1082 }
1083 }
1084 const GOAL: usize = f(&[10, 20, 3, 15, 1000, 60, 16]);
1085 "#,
1086 10 + 4 + 60 + 16,
1087 );
1088 check_number(
1089 r#"
1090 //- minicore: slice, index, coerce_unsized, copy
1091 const fn f(x: &[usize]) -> usize {
1092 match x {
1093 [] => 0,
1094 [a] => *a,
1095 &[a, b] => a + b,
1096 [a, b @ .., c, d] => *a + b.len() + *c + *d,
1097 }
1098 }
1099 const GOAL: usize = f(&[]) + f(&[10]) + f(&[100, 100])
1100 + f(&[1000, 1000, 1000]) + f(&[10000, 57, 34, 46, 10000, 10000]);
1101 "#,
1102 33213,
1103 );
1104 }
1105
1106 #[test]
pattern_matching_ergonomics()1107 fn pattern_matching_ergonomics() {
1108 check_number(
1109 r#"
1110 const fn f(x: &(u8, u8)) -> u8 {
1111 match x {
1112 (a, b) => *a + *b
1113 }
1114 }
1115 const GOAL: u8 = f(&(2, 3));
1116 "#,
1117 5,
1118 );
1119 check_number(
1120 r#"
1121 const GOAL: u8 = {
1122 let a = &(2, 3);
1123 let &(x, y) = a;
1124 x + y
1125 };
1126 "#,
1127 5,
1128 );
1129 }
1130
1131 #[test]
let_else()1132 fn let_else() {
1133 check_number(
1134 r#"
1135 const fn f(x: &(u8, u8)) -> u8 {
1136 let (a, b) = x;
1137 *a + *b
1138 }
1139 const GOAL: u8 = f(&(2, 3));
1140 "#,
1141 5,
1142 );
1143 check_number(
1144 r#"
1145 enum SingleVariant {
1146 Var(u8, u8),
1147 }
1148 const fn f(x: &&&&&SingleVariant) -> u8 {
1149 let SingleVariant::Var(a, b) = x;
1150 *a + *b
1151 }
1152 const GOAL: u8 = f(&&&&&SingleVariant::Var(2, 3));
1153 "#,
1154 5,
1155 );
1156 check_number(
1157 r#"
1158 //- minicore: option
1159 const fn f(x: Option<i32>) -> i32 {
1160 let Some(x) = x else { return 10 };
1161 2 * x
1162 }
1163 const GOAL: i32 = f(Some(1000)) + f(None);
1164 "#,
1165 2010,
1166 );
1167 }
1168
1169 #[test]
function_param_patterns()1170 fn function_param_patterns() {
1171 check_number(
1172 r#"
1173 const fn f((a, b): &(u8, u8)) -> u8 {
1174 *a + *b
1175 }
1176 const GOAL: u8 = f(&(2, 3));
1177 "#,
1178 5,
1179 );
1180 check_number(
1181 r#"
1182 const fn f(c @ (a, b): &(u8, u8)) -> u8 {
1183 *a + *b + c.0 + (*c).1
1184 }
1185 const GOAL: u8 = f(&(2, 3));
1186 "#,
1187 10,
1188 );
1189 check_number(
1190 r#"
1191 const fn f(ref a: u8) -> u8 {
1192 *a
1193 }
1194 const GOAL: u8 = f(2);
1195 "#,
1196 2,
1197 );
1198 check_number(
1199 r#"
1200 struct Foo(u8);
1201 impl Foo {
1202 const fn f(&self, (a, b): &(u8, u8)) -> u8 {
1203 self.0 + *a + *b
1204 }
1205 }
1206 const GOAL: u8 = Foo(4).f(&(2, 3));
1207 "#,
1208 9,
1209 );
1210 }
1211
1212 #[test]
match_guards()1213 fn match_guards() {
1214 check_number(
1215 r#"
1216 //- minicore: option
1217 fn f(x: Option<i32>) -> i32 {
1218 match x {
1219 y if let Some(42) = y => 42000,
1220 Some(y) => y,
1221 None => 10
1222 }
1223 }
1224 const GOAL: i32 = f(Some(42)) + f(Some(2)) + f(None);
1225 "#,
1226 42012,
1227 );
1228 }
1229
1230 #[test]
result_layout_niche_optimization()1231 fn result_layout_niche_optimization() {
1232 check_number(
1233 r#"
1234 //- minicore: option, result
1235 const GOAL: i32 = match Some(2).ok_or(Some(2)) {
1236 Ok(x) => x,
1237 Err(_) => 1000,
1238 };
1239 "#,
1240 2,
1241 );
1242 check_number(
1243 r#"
1244 //- minicore: result
1245 pub enum AlignmentEnum64 {
1246 _Align1Shl0 = 1 << 0,
1247 _Align1Shl1 = 1 << 1,
1248 _Align1Shl2 = 1 << 2,
1249 _Align1Shl3 = 1 << 3,
1250 _Align1Shl4 = 1 << 4,
1251 _Align1Shl5 = 1 << 5,
1252 }
1253 const GOAL: Result<AlignmentEnum64, ()> = {
1254 let align = Err(());
1255 align
1256 };
1257 "#,
1258 0, // It is 0 since result is niche encoded and 1 is valid for `AlignmentEnum64`
1259 );
1260 check_number(
1261 r#"
1262 //- minicore: result
1263 pub enum AlignmentEnum64 {
1264 _Align1Shl0 = 1 << 0,
1265 _Align1Shl1 = 1 << 1,
1266 _Align1Shl2 = 1 << 2,
1267 _Align1Shl3 = 1 << 3,
1268 _Align1Shl4 = 1 << 4,
1269 _Align1Shl5 = 1 << 5,
1270 }
1271 const GOAL: i32 = {
1272 let align = Ok::<_, ()>(AlignmentEnum64::_Align1Shl0);
1273 match align {
1274 Ok(_) => 2,
1275 Err(_) => 1,
1276 }
1277 };
1278 "#,
1279 2,
1280 );
1281 }
1282
1283 #[test]
options()1284 fn options() {
1285 check_number(
1286 r#"
1287 //- minicore: option
1288 const GOAL: u8 = {
1289 let x = Some(2);
1290 match x {
1291 Some(y) => 2 * y,
1292 _ => 10,
1293 }
1294 };
1295 "#,
1296 4,
1297 );
1298 check_number(
1299 r#"
1300 //- minicore: option
1301 fn f(x: Option<Option<i32>>) -> i32 {
1302 if let Some(y) = x && let Some(z) = y {
1303 z
1304 } else if let Some(y) = x {
1305 1
1306 } else {
1307 0
1308 }
1309 }
1310 const GOAL: i32 = f(Some(Some(10))) + f(Some(None)) + f(None);
1311 "#,
1312 11,
1313 );
1314 check_number(
1315 r#"
1316 //- minicore: option
1317 const GOAL: u8 = {
1318 let x = None;
1319 match x {
1320 Some(y) => 2 * y,
1321 _ => 10,
1322 }
1323 };
1324 "#,
1325 10,
1326 );
1327 check_number(
1328 r#"
1329 //- minicore: option
1330 const GOAL: Option<&u8> = None;
1331 "#,
1332 0,
1333 );
1334 }
1335
1336 #[test]
from_trait()1337 fn from_trait() {
1338 check_number(
1339 r#"
1340 //- minicore: from
1341 struct E1(i32);
1342 struct E2(i32);
1343
1344 impl From<E1> for E2 {
1345 fn from(E1(x): E1) -> Self {
1346 E2(1000 * x)
1347 }
1348 }
1349 const GOAL: i32 = {
1350 let x: E2 = E1(2).into();
1351 x.0
1352 };
1353 "#,
1354 2000,
1355 );
1356 }
1357
1358 #[test]
builtin_derive_macro()1359 fn builtin_derive_macro() {
1360 check_number(
1361 r#"
1362 //- minicore: clone, derive, builtin_impls
1363 #[derive(Clone)]
1364 enum Z {
1365 Foo(Y),
1366 Bar,
1367 }
1368 #[derive(Clone)]
1369 struct X(i32, Z, i64)
1370 #[derive(Clone)]
1371 struct Y {
1372 field1: i32,
1373 field2: u8,
1374 }
1375
1376 const GOAL: u8 = {
1377 let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8);
1378 let x = x.clone();
1379 let Z::Foo(t) = x.1;
1380 t.field2
1381 };
1382 "#,
1383 5,
1384 );
1385 check_number(
1386 r#"
1387 //- minicore: default, derive, builtin_impls
1388 #[derive(Default)]
1389 struct X(i32, Y, i64)
1390 #[derive(Default)]
1391 struct Y {
1392 field1: i32,
1393 field2: u8,
1394 }
1395
1396 const GOAL: u8 = {
1397 let x = X::default();
1398 x.1.field2
1399 };
1400 "#,
1401 0,
1402 );
1403 }
1404
1405 #[test]
try_operator()1406 fn try_operator() {
1407 check_number(
1408 r#"
1409 //- minicore: option, try
1410 const fn f(x: Option<i32>, y: Option<i32>) -> Option<i32> {
1411 Some(x? * y?)
1412 }
1413 const fn g(x: Option<i32>, y: Option<i32>) -> i32 {
1414 match f(x, y) {
1415 Some(k) => k,
1416 None => 5,
1417 }
1418 }
1419 const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None);
1420 "#,
1421 215,
1422 );
1423 check_number(
1424 r#"
1425 //- minicore: result, try, from
1426 struct E1(i32);
1427 struct E2(i32);
1428
1429 impl From<E1> for E2 {
1430 fn from(E1(x): E1) -> Self {
1431 E2(1000 * x)
1432 }
1433 }
1434
1435 const fn f(x: Result<i32, E1>) -> Result<i32, E2> {
1436 Ok(x? * 10)
1437 }
1438 const fn g(x: Result<i32, E1>) -> i32 {
1439 match f(x) {
1440 Ok(k) => 7 * k,
1441 Err(E2(k)) => 5 * k,
1442 }
1443 }
1444 const GOAL: i32 = g(Ok(2)) + g(Err(E1(3)));
1445 "#,
1446 15140,
1447 );
1448 }
1449
1450 #[test]
try_block()1451 fn try_block() {
1452 check_number(
1453 r#"
1454 //- minicore: option, try
1455 const fn g(x: Option<i32>, y: Option<i32>) -> i32 {
1456 let r = try { x? * y? };
1457 match r {
1458 Some(k) => k,
1459 None => 5,
1460 }
1461 }
1462 const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None);
1463 "#,
1464 215,
1465 );
1466 }
1467
1468 #[test]
closures()1469 fn closures() {
1470 check_number(
1471 r#"
1472 //- minicore: fn, copy
1473 const GOAL: i32 = {
1474 let y = 5;
1475 let c = |x| x + y;
1476 c(2)
1477 };
1478 "#,
1479 7,
1480 );
1481 check_number(
1482 r#"
1483 //- minicore: fn, copy
1484 const GOAL: i32 = {
1485 let y = 5;
1486 let c = |(a, b): &(i32, i32)| *a + *b + y;
1487 c(&(2, 3))
1488 };
1489 "#,
1490 10,
1491 );
1492 check_number(
1493 r#"
1494 //- minicore: fn, copy
1495 const GOAL: i32 = {
1496 let mut y = 5;
1497 let c = |x| {
1498 y = y + x;
1499 };
1500 c(2);
1501 c(3);
1502 y
1503 };
1504 "#,
1505 10,
1506 );
1507 check_number(
1508 r#"
1509 //- minicore: fn, copy
1510 const GOAL: i32 = {
1511 let c: fn(i32) -> i32 = |x| 2 * x;
1512 c(2) + c(10)
1513 };
1514 "#,
1515 24,
1516 );
1517 check_number(
1518 r#"
1519 //- minicore: fn, copy
1520 struct X(i32);
1521 impl X {
1522 fn mult(&mut self, n: i32) {
1523 self.0 = self.0 * n
1524 }
1525 }
1526 const GOAL: i32 = {
1527 let x = X(1);
1528 let c = || {
1529 x.mult(2);
1530 || {
1531 x.mult(3);
1532 || {
1533 || {
1534 x.mult(4);
1535 || {
1536 x.mult(x.0);
1537 || {
1538 x.0
1539 }
1540 }
1541 }
1542 }
1543 }
1544 };
1545 let r = c()()()()()();
1546 r + x.0
1547 };
1548 "#,
1549 24 * 24 * 2,
1550 );
1551 }
1552
1553 #[test]
closure_and_impl_fn()1554 fn closure_and_impl_fn() {
1555 check_number(
1556 r#"
1557 //- minicore: fn, copy
1558 fn closure_wrapper<F: FnOnce() -> i32>(c: F) -> impl FnOnce() -> F {
1559 || c
1560 }
1561
1562 const GOAL: i32 = {
1563 let y = 5;
1564 let c = closure_wrapper(|| y);
1565 c()()
1566 };
1567 "#,
1568 5,
1569 );
1570 check_number(
1571 r#"
1572 //- minicore: fn, copy
1573 fn f<T, F: Fn() -> T>(t: F) -> impl Fn() -> T {
1574 move || t()
1575 }
1576
1577 const GOAL: i32 = f(|| 2)();
1578 "#,
1579 2,
1580 );
1581 }
1582
1583 #[test]
or_pattern()1584 fn or_pattern() {
1585 check_number(
1586 r#"
1587 const GOAL: u8 = {
1588 let (a | a) = 2;
1589 a
1590 };
1591 "#,
1592 2,
1593 );
1594 check_number(
1595 r#"
1596 //- minicore: option
1597 const fn f(x: Option<i32>) -> i32 {
1598 let (Some(a) | Some(a)) = x else { return 2; };
1599 a
1600 }
1601 const GOAL: i32 = f(Some(10)) + f(None);
1602 "#,
1603 12,
1604 );
1605 check_number(
1606 r#"
1607 //- minicore: option
1608 const fn f(x: Option<i32>, y: Option<i32>) -> i32 {
1609 match (x, y) {
1610 (Some(x), Some(y)) => x * y,
1611 (Some(a), _) | (_, Some(a)) => a,
1612 _ => 10,
1613 }
1614 }
1615 const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None);
1616 "#,
1617 280,
1618 );
1619 }
1620
1621 #[test]
function_pointer_in_constants()1622 fn function_pointer_in_constants() {
1623 check_number(
1624 r#"
1625 struct Foo {
1626 f: fn(u8) -> u8,
1627 }
1628 const FOO: Foo = Foo { f: add2 };
1629 fn add2(x: u8) -> u8 {
1630 x + 2
1631 }
1632 const GOAL: u8 = (FOO.f)(3);
1633 "#,
1634 5,
1635 );
1636 }
1637
1638 #[test]
function_pointer()1639 fn function_pointer() {
1640 check_number(
1641 r#"
1642 fn add2(x: u8) -> u8 {
1643 x + 2
1644 }
1645 const GOAL: u8 = {
1646 let plus2 = add2;
1647 plus2(3)
1648 };
1649 "#,
1650 5,
1651 );
1652 check_number(
1653 r#"
1654 fn add2(x: u8) -> u8 {
1655 x + 2
1656 }
1657 const GOAL: u8 = {
1658 let plus2: fn(u8) -> u8 = add2;
1659 plus2(3)
1660 };
1661 "#,
1662 5,
1663 );
1664 check_number(
1665 r#"
1666 //- minicore: coerce_unsized, index, slice
1667 fn add2(x: u8) -> u8 {
1668 x + 2
1669 }
1670 fn mult3(x: u8) -> u8 {
1671 x * 3
1672 }
1673 const GOAL: u8 = {
1674 let x = [add2, mult3];
1675 x[0](1) + x[1](5)
1676 };
1677 "#,
1678 18,
1679 );
1680 }
1681
1682 #[test]
enum_variant_as_function()1683 fn enum_variant_as_function() {
1684 check_number(
1685 r#"
1686 //- minicore: option
1687 const GOAL: u8 = {
1688 let f = Some;
1689 f(3).unwrap_or(2)
1690 };
1691 "#,
1692 3,
1693 );
1694 check_number(
1695 r#"
1696 //- minicore: option
1697 const GOAL: u8 = {
1698 let f: fn(u8) -> Option<u8> = Some;
1699 f(3).unwrap_or(2)
1700 };
1701 "#,
1702 3,
1703 );
1704 check_number(
1705 r#"
1706 //- minicore: coerce_unsized, index, slice
1707 enum Foo {
1708 Add2(u8),
1709 Mult3(u8),
1710 }
1711 use Foo::*;
1712 const fn f(x: Foo) -> u8 {
1713 match x {
1714 Add2(x) => x + 2,
1715 Mult3(x) => x * 3,
1716 }
1717 }
1718 const GOAL: u8 = {
1719 let x = [Add2, Mult3];
1720 f(x[0](1)) + f(x[1](5))
1721 };
1722 "#,
1723 18,
1724 );
1725 }
1726
1727 #[test]
function_traits()1728 fn function_traits() {
1729 check_number(
1730 r#"
1731 //- minicore: fn
1732 fn add2(x: u8) -> u8 {
1733 x + 2
1734 }
1735 fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 {
1736 f(x)
1737 }
1738 fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 {
1739 f(x)
1740 }
1741 fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 {
1742 f(x)
1743 }
1744 const GOAL: u8 = call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3);
1745 "#,
1746 15,
1747 );
1748 check_number(
1749 r#"
1750 //- minicore: coerce_unsized, fn
1751 fn add2(x: u8) -> u8 {
1752 x + 2
1753 }
1754 fn call(f: &dyn Fn(u8) -> u8, x: u8) -> u8 {
1755 f(x)
1756 }
1757 fn call_mut(f: &mut dyn FnMut(u8) -> u8, x: u8) -> u8 {
1758 f(x)
1759 }
1760 const GOAL: u8 = call(&add2, 3) + call_mut(&mut add2, 3);
1761 "#,
1762 10,
1763 );
1764 check_number(
1765 r#"
1766 //- minicore: fn
1767 fn add2(x: u8) -> u8 {
1768 x + 2
1769 }
1770 fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 {
1771 f(x)
1772 }
1773 fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 {
1774 f(x)
1775 }
1776 fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 {
1777 f(x)
1778 }
1779 const GOAL: u8 = {
1780 let add2: fn(u8) -> u8 = add2;
1781 call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3)
1782 };
1783 "#,
1784 15,
1785 );
1786 check_number(
1787 r#"
1788 //- minicore: fn
1789 fn add2(x: u8) -> u8 {
1790 x + 2
1791 }
1792 fn call(f: &&&&&impl Fn(u8) -> u8, x: u8) -> u8 {
1793 f(x)
1794 }
1795 const GOAL: u8 = call(&&&&&add2, 3);
1796 "#,
1797 5,
1798 );
1799 }
1800
1801 #[test]
dyn_trait()1802 fn dyn_trait() {
1803 check_number(
1804 r#"
1805 //- minicore: coerce_unsized, index, slice
1806 trait Foo {
1807 fn foo(&self) -> u8 { 10 }
1808 }
1809 struct S1;
1810 struct S2;
1811 struct S3;
1812 impl Foo for S1 {
1813 fn foo(&self) -> u8 { 1 }
1814 }
1815 impl Foo for S2 {
1816 fn foo(&self) -> u8 { 2 }
1817 }
1818 impl Foo for S3 {}
1819 const GOAL: u8 = {
1820 let x: &[&dyn Foo] = &[&S1, &S2, &S3];
1821 x[0].foo() + x[1].foo() + x[2].foo()
1822 };
1823 "#,
1824 13,
1825 );
1826 check_number(
1827 r#"
1828 //- minicore: coerce_unsized, index, slice
1829 trait Foo {
1830 fn foo(&self) -> i32 { 10 }
1831 }
1832 trait Bar {
1833 fn bar(&self) -> i32 { 20 }
1834 }
1835
1836 struct S;
1837 impl Foo for S {
1838 fn foo(&self) -> i32 { 200 }
1839 }
1840 impl Bar for dyn Foo {
1841 fn bar(&self) -> i32 { 700 }
1842 }
1843 const GOAL: i32 = {
1844 let x: &dyn Foo = &S;
1845 x.bar() + x.foo()
1846 };
1847 "#,
1848 900,
1849 );
1850 }
1851
1852 #[test]
boxes()1853 fn boxes() {
1854 check_number(
1855 r#"
1856 //- minicore: coerce_unsized, deref_mut, slice
1857 use core::ops::{Deref, DerefMut};
1858 use core::{marker::Unsize, ops::CoerceUnsized};
1859
1860 #[lang = "owned_box"]
1861 pub struct Box<T: ?Sized> {
1862 inner: *mut T,
1863 }
1864 impl<T> Box<T> {
1865 fn new(t: T) -> Self {
1866 #[rustc_box]
1867 Box::new(t)
1868 }
1869 }
1870
1871 impl<T: ?Sized> Deref for Box<T> {
1872 type Target = T;
1873
1874 fn deref(&self) -> &T {
1875 &**self
1876 }
1877 }
1878
1879 impl<T: ?Sized> DerefMut for Box<T> {
1880 fn deref_mut(&mut self) -> &mut T {
1881 &mut **self
1882 }
1883 }
1884
1885 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
1886
1887 const GOAL: usize = {
1888 let x = Box::new(5);
1889 let y: Box<[i32]> = Box::new([1, 2, 3]);
1890 *x + y.len()
1891 };
1892 "#,
1893 8,
1894 );
1895 }
1896
1897 #[test]
array_and_index()1898 fn array_and_index() {
1899 check_number(
1900 r#"
1901 //- minicore: coerce_unsized, index, slice
1902 const GOAL: u8 = {
1903 let a = [10, 20, 3, 15];
1904 let x: &[u8] = &a;
1905 x[1]
1906 };
1907 "#,
1908 20,
1909 );
1910 check_number(
1911 r#"
1912 //- minicore: coerce_unsized, index, slice
1913 const GOAL: usize = [1, 2, 3][2];"#,
1914 3,
1915 );
1916 check_number(
1917 r#"
1918 //- minicore: coerce_unsized, index, slice
1919 const GOAL: usize = { let a = [1, 2, 3]; let x: &[i32] = &a; x.len() };"#,
1920 3,
1921 );
1922 check_number(
1923 r#"
1924 //- minicore: coerce_unsized, index, slice
1925 const GOAL: usize = {
1926 let a = [1, 2, 3];
1927 let x: &[i32] = &a;
1928 let y = &*x;
1929 y.len()
1930 };"#,
1931 3,
1932 );
1933 check_number(
1934 r#"
1935 //- minicore: coerce_unsized, index, slice
1936 const GOAL: usize = [1, 2, 3, 4, 5].len();"#,
1937 5,
1938 );
1939 check_number(
1940 r#"
1941 //- minicore: coerce_unsized, index, slice
1942 const GOAL: [u16; 5] = [1, 2, 3, 4, 5];"#,
1943 1 + (2 << 16) + (3 << 32) + (4 << 48) + (5 << 64),
1944 );
1945 check_number(
1946 r#"
1947 //- minicore: coerce_unsized, index, slice
1948 const GOAL: [u16; 5] = [12; 5];"#,
1949 12 + (12 << 16) + (12 << 32) + (12 << 48) + (12 << 64),
1950 );
1951 check_number(
1952 r#"
1953 //- minicore: coerce_unsized, index, slice
1954 const LEN: usize = 4;
1955 const GOAL: u16 = {
1956 let x = [7; LEN];
1957 x[2]
1958 }"#,
1959 7,
1960 );
1961 }
1962
1963 #[test]
byte_string()1964 fn byte_string() {
1965 check_number(
1966 r#"
1967 //- minicore: coerce_unsized, index, slice
1968 const GOAL: u8 = {
1969 let a = b"hello";
1970 let x: &[u8] = a;
1971 x[0]
1972 };
1973 "#,
1974 104,
1975 );
1976 }
1977
1978 #[test]
c_string()1979 fn c_string() {
1980 check_number(
1981 r#"
1982 //- minicore: index, slice
1983 #[lang = "CStr"]
1984 pub struct CStr {
1985 inner: [u8]
1986 }
1987 const GOAL: u8 = {
1988 let a = c"hello";
1989 a.inner[0]
1990 };
1991 "#,
1992 104,
1993 );
1994 check_number(
1995 r#"
1996 //- minicore: index, slice
1997 #[lang = "CStr"]
1998 pub struct CStr {
1999 inner: [u8]
2000 }
2001 const GOAL: u8 = {
2002 let a = c"hello";
2003 a.inner[6]
2004 };
2005 "#,
2006 0,
2007 );
2008 }
2009
2010 #[test]
consts()2011 fn consts() {
2012 check_number(
2013 r#"
2014 const F1: i32 = 1;
2015 const F3: i32 = 3 * F2;
2016 const F2: i32 = 2 * F1;
2017 const GOAL: i32 = F3;
2018 "#,
2019 6,
2020 );
2021 }
2022
2023 #[test]
statics()2024 fn statics() {
2025 check_number(
2026 r#"
2027 //- minicore: cell
2028 use core::cell::Cell;
2029 fn f() -> i32 {
2030 static S: Cell<i32> = Cell::new(10);
2031 S.set(S.get() + 1);
2032 S.get()
2033 }
2034 const GOAL: i32 = f() + f() + f();
2035 "#,
2036 36,
2037 );
2038 }
2039
2040 #[test]
extern_weak_statics()2041 fn extern_weak_statics() {
2042 check_number(
2043 r#"
2044 extern "C" {
2045 #[linkage = "extern_weak"]
2046 static __dso_handle: *mut u8;
2047 }
2048 const GOAL: usize = __dso_handle as usize;
2049 "#,
2050 0,
2051 );
2052 }
2053
2054 #[test]
from_ne_bytes()2055 fn from_ne_bytes() {
2056 check_number(
2057 r#"
2058 //- minicore: int_impl
2059 const GOAL: u32 = u32::from_ne_bytes([44, 1, 0, 0]);
2060 "#,
2061 300,
2062 );
2063 }
2064
2065 #[test]
enums()2066 fn enums() {
2067 check_number(
2068 r#"
2069 enum E {
2070 F1 = 1,
2071 F2 = 2 * E::F1 as isize, // Rustc expects an isize here
2072 F3 = 3 * E::F2 as isize,
2073 }
2074 const GOAL: u8 = E::F3 as u8;
2075 "#,
2076 6,
2077 );
2078 check_number(
2079 r#"
2080 enum E { F1 = 1, F2, }
2081 const GOAL: u8 = E::F2 as u8;
2082 "#,
2083 2,
2084 );
2085 check_number(
2086 r#"
2087 enum E { F1, }
2088 const GOAL: u8 = E::F1 as u8;
2089 "#,
2090 0,
2091 );
2092 let (db, file_id) = TestDB::with_single_file(
2093 r#"
2094 enum E { A = 1, B }
2095 const GOAL: E = E::A;
2096 "#,
2097 );
2098 let r = eval_goal(&db, file_id).unwrap();
2099 assert_eq!(try_const_usize(&db, &r), Some(1));
2100 }
2101
2102 #[test]
const_loop()2103 fn const_loop() {
2104 check_fail(
2105 r#"
2106 const F1: i32 = 1 * F3;
2107 const F3: i32 = 3 * F2;
2108 const F2: i32 = 2 * F1;
2109 const GOAL: i32 = F3;
2110 "#,
2111 |e| e == ConstEvalError::MirLowerError(MirLowerError::Loop),
2112 );
2113 }
2114
2115 #[test]
const_transfer_memory()2116 fn const_transfer_memory() {
2117 check_number(
2118 r#"
2119 const A1: &i32 = &2;
2120 const A2: &i32 = &5;
2121 const GOAL: i32 = *A1 + *A2;
2122 "#,
2123 7,
2124 );
2125 }
2126
2127 #[test]
anonymous_const_block()2128 fn anonymous_const_block() {
2129 check_number(
2130 r#"
2131 extern "rust-intrinsic" {
2132 pub fn size_of<T>() -> usize;
2133 }
2134
2135 const fn f<T>() -> usize {
2136 let r = const { size_of::<T>() };
2137 r
2138 }
2139
2140 const GOAL: usize = {
2141 let x = const { 2 + const { 3 } };
2142 let y = f::<i32>();
2143 x + y
2144 };
2145 "#,
2146 9,
2147 );
2148 }
2149
2150 #[test]
const_impl_assoc()2151 fn const_impl_assoc() {
2152 check_number(
2153 r#"
2154 struct U5;
2155 impl U5 {
2156 const VAL: usize = 5;
2157 }
2158 const GOAL: usize = U5::VAL + <U5>::VAL;
2159 "#,
2160 10,
2161 );
2162 }
2163
2164 #[test]
const_generic_subst_fn()2165 fn const_generic_subst_fn() {
2166 check_number(
2167 r#"
2168 const fn f<const A: usize>(x: usize) -> usize {
2169 A * x + 5
2170 }
2171 const GOAL: usize = f::<2>(3);
2172 "#,
2173 11,
2174 );
2175 check_number(
2176 r#"
2177 fn f<const N: usize>(x: [i32; N]) -> usize {
2178 N
2179 }
2180
2181 trait ArrayExt {
2182 fn f(self) -> usize;
2183 }
2184
2185 impl<T, const N: usize> ArrayExt for [T; N] {
2186 fn g(self) -> usize {
2187 f(self)
2188 }
2189 }
2190
2191 const GOAL: usize = f([1, 2, 5]);
2192 "#,
2193 3,
2194 );
2195 }
2196
2197 #[test]
layout_of_type_with_associated_type_field_defined_inside_body()2198 fn layout_of_type_with_associated_type_field_defined_inside_body() {
2199 check_number(
2200 r#"
2201 trait Tr {
2202 type Ty;
2203 }
2204
2205 struct St<T: Tr>(T::Ty);
2206
2207 const GOAL: i64 = {
2208 // if we move `St2` out of body, the test will fail, as we don't see the impl anymore. That
2209 // case will probably be rejected by rustc in some later edition, but we should support this
2210 // case.
2211 struct St2;
2212
2213 impl Tr for St2 {
2214 type Ty = i64;
2215 }
2216
2217 struct Goal(St<St2>);
2218
2219 let x = Goal(St(5));
2220 x.0.0
2221 };
2222 "#,
2223 5,
2224 );
2225 }
2226
2227 #[test]
const_generic_subst_assoc_const_impl()2228 fn const_generic_subst_assoc_const_impl() {
2229 check_number(
2230 r#"
2231 struct Adder<const N: usize, const M: usize>;
2232 impl<const N: usize, const M: usize> Adder<N, M> {
2233 const VAL: usize = N + M;
2234 }
2235 const GOAL: usize = Adder::<2, 3>::VAL;
2236 "#,
2237 5,
2238 );
2239 }
2240
2241 #[test]
associated_types()2242 fn associated_types() {
2243 check_number(
2244 r#"
2245 trait Tr {
2246 type Item;
2247 fn get_item(&self) -> Self::Item;
2248 }
2249
2250 struct X(i32);
2251 struct Y(i32);
2252
2253 impl Tr for X {
2254 type Item = Y;
2255 fn get_item(&self) -> Self::Item {
2256 Y(self.0 + 2)
2257 }
2258 }
2259
2260 fn my_get_item<T: Tr>(x: T) -> <T as Tr>::Item {
2261 x.get_item()
2262 }
2263
2264 const GOAL: i32 = my_get_item(X(3)).0;
2265 "#,
2266 5,
2267 );
2268 }
2269
2270 #[test]
const_trait_assoc()2271 fn const_trait_assoc() {
2272 check_number(
2273 r#"
2274 struct U0;
2275 trait ToConst {
2276 const VAL: usize;
2277 }
2278 impl ToConst for U0 {
2279 const VAL: usize = 0;
2280 }
2281 impl ToConst for i32 {
2282 const VAL: usize = 32;
2283 }
2284 const GOAL: usize = U0::VAL + i32::VAL;
2285 "#,
2286 32,
2287 );
2288 check_number(
2289 r#"
2290 struct S<T>(*mut T);
2291
2292 trait MySized: Sized {
2293 const SIZE: S<Self> = S(1 as *mut Self);
2294 }
2295
2296 impl MySized for i32 {
2297 const SIZE: S<i32> = S(10 as *mut i32);
2298 }
2299
2300 impl MySized for i64 {
2301 }
2302
2303 const fn f<T: MySized>() -> usize {
2304 T::SIZE.0 as usize
2305 }
2306
2307 const GOAL: usize = f::<i32>() + f::<i64>() * 2;
2308 "#,
2309 12,
2310 );
2311 }
2312
2313 #[test]
panic_messages()2314 fn panic_messages() {
2315 check_fail(
2316 r#"
2317 //- minicore: panic
2318 const GOAL: u8 = {
2319 let x: u16 = 2;
2320 panic!("hello");
2321 };
2322 "#,
2323 |e| e == ConstEvalError::MirEvalError(MirEvalError::Panic("hello".to_string())),
2324 );
2325 }
2326
2327 #[test]
exec_limits()2328 fn exec_limits() {
2329 check_fail(
2330 r#"
2331 const GOAL: usize = loop {};
2332 "#,
2333 |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded),
2334 );
2335 check_fail(
2336 r#"
2337 const fn f(x: i32) -> i32 {
2338 f(x + 1)
2339 }
2340 const GOAL: i32 = f(0);
2341 "#,
2342 |e| e == ConstEvalError::MirEvalError(MirEvalError::StackOverflow),
2343 );
2344 // Reasonable code should still work
2345 check_number(
2346 r#"
2347 const fn nth_odd(n: i32) -> i32 {
2348 2 * n - 1
2349 }
2350 const fn f(n: i32) -> i32 {
2351 let sum = 0;
2352 let i = 0;
2353 while i < n {
2354 i = i + 1;
2355 sum = sum + nth_odd(i);
2356 }
2357 sum
2358 }
2359 const GOAL: i32 = f(10000);
2360 "#,
2361 10000 * 10000,
2362 );
2363 }
2364
2365 #[test]
type_error()2366 fn type_error() {
2367 check_fail(
2368 r#"
2369 const GOAL: u8 = {
2370 let x: u16 = 2;
2371 let y: (u8, u8) = x;
2372 y.0
2373 };
2374 "#,
2375 |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))),
2376 );
2377 }
2378
2379 #[test]
unsized_local()2380 fn unsized_local() {
2381 check_fail(
2382 r#"
2383 //- minicore: coerce_unsized, index, slice
2384 const fn x() -> SomeUnknownTypeThatDereferenceToSlice {
2385 SomeUnknownTypeThatDereferenceToSlice
2386 }
2387
2388 const GOAL: u16 = {
2389 let y = x();
2390 let z: &[u16] = &y;
2391 z[1]
2392 };
2393 "#,
2394 |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))),
2395 );
2396 }
2397