• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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