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