]>
Commit | Line | Data |
---|---|---|
fe692bf9 FG |
1 | use base_db::{fixture::WithFixture, FileId}; |
2 | use chalk_ir::Substitution; | |
353b0b11 | 3 | use hir_def::db::DefDatabase; |
add651ee | 4 | use test_utils::skip_slow_tests; |
064997fb | 5 | |
353b0b11 | 6 | use crate::{ |
fe692bf9 | 7 | consteval::try_const_usize, db::HirDatabase, mir::pad16, test_db::TestDB, Const, ConstScalar, |
add651ee | 8 | Interner, MemoryMap, |
353b0b11 | 9 | }; |
064997fb | 10 | |
353b0b11 FG |
11 | use super::{ |
12 | super::mir::{MirEvalError, MirLowerError}, | |
13 | ConstEvalError, | |
14 | }; | |
064997fb | 15 | |
fe692bf9 FG |
16 | mod intrinsics; |
17 | ||
353b0b11 FG |
18 | fn simplify(e: ConstEvalError) -> ConstEvalError { |
19 | match e { | |
add651ee | 20 | ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => { |
353b0b11 FG |
21 | simplify(ConstEvalError::MirEvalError(*e)) |
22 | } | |
23 | _ => e, | |
24 | } | |
25 | } | |
26 | ||
27 | #[track_caller] | |
fe692bf9 FG |
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 | } | |
064997fb FG |
36 | } |
37 | ||
353b0b11 | 38 | #[track_caller] |
064997fb | 39 | fn check_number(ra_fixture: &str, answer: i128) { |
add651ee FG |
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(); | |
fe692bf9 FG |
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 | }; | |
353b0b11 FG |
78 | match &r.data(Interner).value { |
79 | chalk_ir::ConstValue::Concrete(c) => match &c.interned { | |
add651ee FG |
80 | ConstScalar::Bytes(b, mm) => { |
81 | check(b, mm); | |
353b0b11 FG |
82 | } |
83 | x => panic!("Expected number but found {:?}", x), | |
84 | }, | |
85 | _ => panic!("result of const eval wasn't a concrete const"), | |
064997fb FG |
86 | } |
87 | } | |
88 | ||
fe692bf9 FG |
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> { | |
064997fb | 101 | let module_id = db.module_for_file(file_id); |
fe692bf9 | 102 | let def_map = module_id.def_map(db); |
064997fb FG |
103 | let scope = &def_map[module_id.local_id].scope; |
104 | let const_id = scope | |
105 | .declarations() | |
064997fb FG |
106 | .find_map(|x| match x { |
107 | hir_def::ModuleDefId::ConstId(x) => { | |
fe692bf9 | 108 | if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" { |
064997fb FG |
109 | Some(x) |
110 | } else { | |
111 | None | |
112 | } | |
113 | } | |
114 | _ => None, | |
115 | }) | |
add651ee FG |
116 | .expect("No const named GOAL found in the test"); |
117 | db.const_eval(const_id.into(), Substitution::empty(Interner), None) | |
064997fb FG |
118 | } |
119 | ||
120 | #[test] | |
121 | fn add() { | |
122 | check_number(r#"const GOAL: usize = 2 + 2;"#, 4); | |
353b0b11 FG |
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); | |
064997fb FG |
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); | |
353b0b11 | 132 | check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128); |
fe692bf9 FG |
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 | }); | |
add651ee | 137 | check_number(r#"const GOAL: i32 = 100000000i32 << 11"#, (100000000i32 << 11) as i128); |
fe692bf9 FG |
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 | |
add651ee FG |
196 | struct X { |
197 | unsize_field: [u8], | |
198 | } | |
199 | ||
fe692bf9 FG |
200 | const GOAL: usize = { |
201 | let a = [10, 20, 3, 15]; | |
202 | let x: &[i32] = &a; | |
add651ee FG |
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 }; | |
fe692bf9 FG |
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 | ); | |
064997fb FG |
233 | } |
234 | ||
add651ee FG |
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 | ||
064997fb FG |
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 | ||
353b0b11 FG |
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() { | |
fe692bf9 | 349 | check_number( |
353b0b11 FG |
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 | "#, | |
fe692bf9 | 367 | 10, |
353b0b11 FG |
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 | ||
fe692bf9 FG |
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 | ||
353b0b11 FG |
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 | ||
353b0b11 FG |
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 | ||
fe692bf9 FG |
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 | ||
353b0b11 FG |
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 | ); | |
fe692bf9 FG |
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 | ); | |
353b0b11 FG |
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 | ); | |
fe692bf9 FG |
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 | ); | |
353b0b11 FG |
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 | ||
fe692bf9 FG |
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 | ||
353b0b11 FG |
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 | ); | |
fe692bf9 FG |
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 | ); | |
353b0b11 FG |
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#" | |
fe692bf9 FG |
1019 | struct TupleLike(i32, i64, u8, u16); |
1020 | const GOAL: i64 = { | |
353b0b11 | 1021 | let a = TupleLike(10, 20, 3, 15); |
fe692bf9 FG |
1022 | let TupleLike(b, .., c) = a; |
1023 | a.1 * 100 + b as i64 + c as i64 | |
353b0b11 FG |
1024 | }; |
1025 | "#, | |
fe692bf9 | 1026 | 2025, |
353b0b11 FG |
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 | ||
fe692bf9 FG |
1059 | const MY_SEASON: Season = Summer; |
1060 | ||
1061 | impl Season { | |
1062 | const FALL: Season = Fall; | |
1063 | } | |
1064 | ||
353b0b11 FG |
1065 | const fn f(x: Season) -> i32 { |
1066 | match x { | |
1067 | Spring => 1, | |
fe692bf9 FG |
1068 | MY_SEASON => 2, |
1069 | Season::FALL => 3, | |
353b0b11 FG |
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] | |
fe692bf9 | 1080 | fn pattern_matching_literal() { |
353b0b11 FG |
1081 | check_number( |
1082 | r#" | |
fe692bf9 | 1083 | const fn f(x: i32) -> i32 { |
353b0b11 | 1084 | match x { |
fe692bf9 FG |
1085 | -1 => 1, |
1086 | 1 => 10, | |
1087 | _ => 100, | |
353b0b11 FG |
1088 | } |
1089 | } | |
fe692bf9 | 1090 | const GOAL: i32 = f(-1) + f(1) + f(0) + f(-5); |
353b0b11 | 1091 | "#, |
fe692bf9 | 1092 | 211, |
353b0b11 | 1093 | ); |
353b0b11 FG |
1094 | check_number( |
1095 | r#" | |
fe692bf9 FG |
1096 | const fn f(x: &str) -> i32 { |
1097 | match x { | |
1098 | "f" => 1, | |
1099 | "foo" => 10, | |
1100 | "" => 100, | |
1101 | "bar" => 1000, | |
1102 | _ => 10000, | |
1103 | } | |
353b0b11 | 1104 | } |
fe692bf9 | 1105 | const GOAL: i32 = f("f") + f("foo") * 2 + f("") * 3 + f("bar") * 4; |
353b0b11 | 1106 | "#, |
fe692bf9 | 1107 | 4321, |
353b0b11 | 1108 | ); |
fe692bf9 FG |
1109 | } |
1110 | ||
1111 | #[test] | |
1112 | fn pattern_matching_range() { | |
353b0b11 FG |
1113 | check_number( |
1114 | r#" | |
fe692bf9 FG |
1115 | pub const L: i32 = 6; |
1116 | mod x { | |
1117 | pub const R: i32 = 100; | |
353b0b11 | 1118 | } |
fe692bf9 FG |
1119 | const fn f(x: i32) -> i32 { |
1120 | match x { | |
1121 | -1..=5 => x * 10, | |
1122 | L..=x::R => x * 100, | |
1123 | _ => x, | |
1124 | } | |
353b0b11 | 1125 | } |
fe692bf9 FG |
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 | ||
add651ee FG |
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 | } | |
1207 | ||
fe692bf9 FG |
1208 | #[test] |
1209 | fn let_else() { | |
1210 | check_number( | |
1211 | r#" | |
1212 | const fn f(x: &(u8, u8)) -> u8 { | |
1213 | let (a, b) = x; | |
1214 | *a + *b | |
1215 | } | |
1216 | const GOAL: u8 = f(&(2, 3)); | |
1217 | "#, | |
1218 | 5, | |
1219 | ); | |
1220 | check_number( | |
1221 | r#" | |
1222 | enum SingleVariant { | |
1223 | Var(u8, u8), | |
1224 | } | |
1225 | const fn f(x: &&&&&SingleVariant) -> u8 { | |
1226 | let SingleVariant::Var(a, b) = x; | |
1227 | *a + *b | |
1228 | } | |
1229 | const GOAL: u8 = f(&&&&&SingleVariant::Var(2, 3)); | |
353b0b11 FG |
1230 | "#, |
1231 | 5, | |
1232 | ); | |
1233 | check_number( | |
1234 | r#" | |
1235 | //- minicore: option | |
1236 | const fn f(x: Option<i32>) -> i32 { | |
1237 | let Some(x) = x else { return 10 }; | |
1238 | 2 * x | |
1239 | } | |
1240 | const GOAL: i32 = f(Some(1000)) + f(None); | |
1241 | "#, | |
1242 | 2010, | |
1243 | ); | |
1244 | } | |
1245 | ||
1246 | #[test] | |
1247 | fn function_param_patterns() { | |
1248 | check_number( | |
1249 | r#" | |
1250 | const fn f((a, b): &(u8, u8)) -> u8 { | |
1251 | *a + *b | |
1252 | } | |
1253 | const GOAL: u8 = f(&(2, 3)); | |
1254 | "#, | |
1255 | 5, | |
1256 | ); | |
1257 | check_number( | |
1258 | r#" | |
1259 | const fn f(c @ (a, b): &(u8, u8)) -> u8 { | |
1260 | *a + *b + c.0 + (*c).1 | |
1261 | } | |
1262 | const GOAL: u8 = f(&(2, 3)); | |
1263 | "#, | |
1264 | 10, | |
1265 | ); | |
1266 | check_number( | |
1267 | r#" | |
1268 | const fn f(ref a: u8) -> u8 { | |
1269 | *a | |
1270 | } | |
1271 | const GOAL: u8 = f(2); | |
1272 | "#, | |
1273 | 2, | |
1274 | ); | |
1275 | check_number( | |
1276 | r#" | |
1277 | struct Foo(u8); | |
1278 | impl Foo { | |
1279 | const fn f(&self, (a, b): &(u8, u8)) -> u8 { | |
1280 | self.0 + *a + *b | |
1281 | } | |
1282 | } | |
1283 | const GOAL: u8 = Foo(4).f(&(2, 3)); | |
1284 | "#, | |
1285 | 9, | |
1286 | ); | |
1287 | } | |
1288 | ||
fe692bf9 FG |
1289 | #[test] |
1290 | fn match_guards() { | |
1291 | check_number( | |
1292 | r#" | |
1293 | //- minicore: option | |
1294 | fn f(x: Option<i32>) -> i32 { | |
1295 | match x { | |
1296 | y if let Some(42) = y => 42000, | |
1297 | Some(y) => y, | |
1298 | None => 10 | |
1299 | } | |
1300 | } | |
1301 | const GOAL: i32 = f(Some(42)) + f(Some(2)) + f(None); | |
1302 | "#, | |
1303 | 42012, | |
1304 | ); | |
1305 | } | |
1306 | ||
1307 | #[test] | |
1308 | fn result_layout_niche_optimization() { | |
1309 | check_number( | |
1310 | r#" | |
1311 | //- minicore: option, result | |
1312 | const GOAL: i32 = match Some(2).ok_or(Some(2)) { | |
1313 | Ok(x) => x, | |
1314 | Err(_) => 1000, | |
1315 | }; | |
1316 | "#, | |
1317 | 2, | |
1318 | ); | |
1319 | check_number( | |
1320 | r#" | |
1321 | //- minicore: result | |
1322 | pub enum AlignmentEnum64 { | |
1323 | _Align1Shl0 = 1 << 0, | |
1324 | _Align1Shl1 = 1 << 1, | |
1325 | _Align1Shl2 = 1 << 2, | |
1326 | _Align1Shl3 = 1 << 3, | |
1327 | _Align1Shl4 = 1 << 4, | |
1328 | _Align1Shl5 = 1 << 5, | |
1329 | } | |
1330 | const GOAL: Result<AlignmentEnum64, ()> = { | |
1331 | let align = Err(()); | |
1332 | align | |
1333 | }; | |
1334 | "#, | |
1335 | 0, // It is 0 since result is niche encoded and 1 is valid for `AlignmentEnum64` | |
1336 | ); | |
1337 | check_number( | |
1338 | r#" | |
1339 | //- minicore: result | |
1340 | pub enum AlignmentEnum64 { | |
1341 | _Align1Shl0 = 1 << 0, | |
1342 | _Align1Shl1 = 1 << 1, | |
1343 | _Align1Shl2 = 1 << 2, | |
1344 | _Align1Shl3 = 1 << 3, | |
1345 | _Align1Shl4 = 1 << 4, | |
1346 | _Align1Shl5 = 1 << 5, | |
1347 | } | |
1348 | const GOAL: i32 = { | |
1349 | let align = Ok::<_, ()>(AlignmentEnum64::_Align1Shl0); | |
1350 | match align { | |
1351 | Ok(_) => 2, | |
1352 | Err(_) => 1, | |
1353 | } | |
1354 | }; | |
1355 | "#, | |
1356 | 2, | |
1357 | ); | |
1358 | } | |
1359 | ||
353b0b11 FG |
1360 | #[test] |
1361 | fn options() { | |
1362 | check_number( | |
1363 | r#" | |
1364 | //- minicore: option | |
1365 | const GOAL: u8 = { | |
1366 | let x = Some(2); | |
1367 | match x { | |
1368 | Some(y) => 2 * y, | |
1369 | _ => 10, | |
1370 | } | |
1371 | }; | |
1372 | "#, | |
fe692bf9 FG |
1373 | 4, |
1374 | ); | |
1375 | check_number( | |
1376 | r#" | |
1377 | //- minicore: option | |
1378 | fn f(x: Option<Option<i32>>) -> i32 { | |
1379 | if let Some(y) = x && let Some(z) = y { | |
1380 | z | |
1381 | } else if let Some(y) = x { | |
1382 | 1 | |
1383 | } else { | |
1384 | 0 | |
1385 | } | |
1386 | } | |
1387 | const GOAL: i32 = f(Some(Some(10))) + f(Some(None)) + f(None); | |
1388 | "#, | |
1389 | 11, | |
1390 | ); | |
1391 | check_number( | |
1392 | r#" | |
1393 | //- minicore: option | |
1394 | const GOAL: u8 = { | |
1395 | let x = None; | |
1396 | match x { | |
1397 | Some(y) => 2 * y, | |
1398 | _ => 10, | |
1399 | } | |
1400 | }; | |
1401 | "#, | |
1402 | 10, | |
1403 | ); | |
1404 | check_number( | |
1405 | r#" | |
1406 | //- minicore: option | |
1407 | const GOAL: Option<&u8> = None; | |
1408 | "#, | |
1409 | 0, | |
1410 | ); | |
1411 | } | |
1412 | ||
1413 | #[test] | |
1414 | fn from_trait() { | |
1415 | check_number( | |
1416 | r#" | |
1417 | //- minicore: from | |
1418 | struct E1(i32); | |
1419 | struct E2(i32); | |
1420 | ||
1421 | impl From<E1> for E2 { | |
1422 | fn from(E1(x): E1) -> Self { | |
1423 | E2(1000 * x) | |
1424 | } | |
1425 | } | |
1426 | const GOAL: i32 = { | |
1427 | let x: E2 = E1(2).into(); | |
1428 | x.0 | |
1429 | }; | |
1430 | "#, | |
1431 | 2000, | |
1432 | ); | |
1433 | } | |
1434 | ||
1435 | #[test] | |
1436 | fn builtin_derive_macro() { | |
1437 | check_number( | |
1438 | r#" | |
1439 | //- minicore: clone, derive, builtin_impls | |
1440 | #[derive(Clone)] | |
1441 | enum Z { | |
1442 | Foo(Y), | |
1443 | Bar, | |
1444 | } | |
1445 | #[derive(Clone)] | |
1446 | struct X(i32, Z, i64) | |
1447 | #[derive(Clone)] | |
1448 | struct Y { | |
1449 | field1: i32, | |
add651ee | 1450 | field2: ((i32, u8), i64), |
fe692bf9 FG |
1451 | } |
1452 | ||
1453 | const GOAL: u8 = { | |
add651ee | 1454 | let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8); |
fe692bf9 FG |
1455 | let x = x.clone(); |
1456 | let Z::Foo(t) = x.1; | |
add651ee | 1457 | t.field2.0 .1 |
fe692bf9 FG |
1458 | }; |
1459 | "#, | |
1460 | 5, | |
1461 | ); | |
1462 | check_number( | |
1463 | r#" | |
1464 | //- minicore: default, derive, builtin_impls | |
1465 | #[derive(Default)] | |
1466 | struct X(i32, Y, i64) | |
1467 | #[derive(Default)] | |
1468 | struct Y { | |
1469 | field1: i32, | |
1470 | field2: u8, | |
1471 | } | |
1472 | ||
1473 | const GOAL: u8 = { | |
1474 | let x = X::default(); | |
1475 | x.1.field2 | |
1476 | }; | |
1477 | "#, | |
1478 | 0, | |
1479 | ); | |
1480 | } | |
1481 | ||
1482 | #[test] | |
1483 | fn try_operator() { | |
1484 | check_number( | |
1485 | r#" | |
1486 | //- minicore: option, try | |
1487 | const fn f(x: Option<i32>, y: Option<i32>) -> Option<i32> { | |
1488 | Some(x? * y?) | |
1489 | } | |
1490 | const fn g(x: Option<i32>, y: Option<i32>) -> i32 { | |
1491 | match f(x, y) { | |
1492 | Some(k) => k, | |
1493 | None => 5, | |
1494 | } | |
1495 | } | |
1496 | const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); | |
1497 | "#, | |
1498 | 215, | |
1499 | ); | |
1500 | check_number( | |
1501 | r#" | |
1502 | //- minicore: result, try, from | |
1503 | struct E1(i32); | |
1504 | struct E2(i32); | |
1505 | ||
1506 | impl From<E1> for E2 { | |
1507 | fn from(E1(x): E1) -> Self { | |
1508 | E2(1000 * x) | |
1509 | } | |
1510 | } | |
1511 | ||
1512 | const fn f(x: Result<i32, E1>) -> Result<i32, E2> { | |
1513 | Ok(x? * 10) | |
1514 | } | |
1515 | const fn g(x: Result<i32, E1>) -> i32 { | |
1516 | match f(x) { | |
1517 | Ok(k) => 7 * k, | |
1518 | Err(E2(k)) => 5 * k, | |
1519 | } | |
1520 | } | |
1521 | const GOAL: i32 = g(Ok(2)) + g(Err(E1(3))); | |
1522 | "#, | |
1523 | 15140, | |
1524 | ); | |
1525 | } | |
1526 | ||
1527 | #[test] | |
1528 | fn try_block() { | |
1529 | check_number( | |
1530 | r#" | |
1531 | //- minicore: option, try | |
1532 | const fn g(x: Option<i32>, y: Option<i32>) -> i32 { | |
1533 | let r = try { x? * y? }; | |
1534 | match r { | |
1535 | Some(k) => k, | |
1536 | None => 5, | |
1537 | } | |
1538 | } | |
1539 | const GOAL: i32 = g(Some(10), Some(20)) + g(Some(30), None) + g(None, Some(40)) + g(None, None); | |
1540 | "#, | |
1541 | 215, | |
1542 | ); | |
1543 | } | |
1544 | ||
1545 | #[test] | |
1546 | fn closures() { | |
1547 | check_number( | |
1548 | r#" | |
1549 | //- minicore: fn, copy | |
1550 | const GOAL: i32 = { | |
1551 | let y = 5; | |
1552 | let c = |x| x + y; | |
1553 | c(2) | |
1554 | }; | |
1555 | "#, | |
1556 | 7, | |
1557 | ); | |
1558 | check_number( | |
1559 | r#" | |
1560 | //- minicore: fn, copy | |
1561 | const GOAL: i32 = { | |
1562 | let y = 5; | |
1563 | let c = |(a, b): &(i32, i32)| *a + *b + y; | |
1564 | c(&(2, 3)) | |
1565 | }; | |
1566 | "#, | |
1567 | 10, | |
1568 | ); | |
1569 | check_number( | |
1570 | r#" | |
1571 | //- minicore: fn, copy | |
1572 | const GOAL: i32 = { | |
1573 | let mut y = 5; | |
1574 | let c = |x| { | |
1575 | y = y + x; | |
1576 | }; | |
1577 | c(2); | |
1578 | c(3); | |
1579 | y | |
1580 | }; | |
1581 | "#, | |
1582 | 10, | |
1583 | ); | |
1584 | check_number( | |
1585 | r#" | |
1586 | //- minicore: fn, copy | |
1587 | const GOAL: i32 = { | |
1588 | let c: fn(i32) -> i32 = |x| 2 * x; | |
1589 | c(2) + c(10) | |
1590 | }; | |
1591 | "#, | |
1592 | 24, | |
1593 | ); | |
1594 | check_number( | |
1595 | r#" | |
1596 | //- minicore: fn, copy | |
1597 | struct X(i32); | |
1598 | impl X { | |
1599 | fn mult(&mut self, n: i32) { | |
1600 | self.0 = self.0 * n | |
1601 | } | |
1602 | } | |
1603 | const GOAL: i32 = { | |
1604 | let x = X(1); | |
1605 | let c = || { | |
1606 | x.mult(2); | |
1607 | || { | |
1608 | x.mult(3); | |
1609 | || { | |
1610 | || { | |
1611 | x.mult(4); | |
1612 | || { | |
1613 | x.mult(x.0); | |
1614 | || { | |
1615 | x.0 | |
1616 | } | |
1617 | } | |
1618 | } | |
1619 | } | |
1620 | } | |
1621 | }; | |
1622 | let r = c()()()()()(); | |
1623 | r + x.0 | |
1624 | }; | |
1625 | "#, | |
1626 | 24 * 24 * 2, | |
1627 | ); | |
1628 | } | |
1629 | ||
add651ee FG |
1630 | #[test] |
1631 | fn manual_fn_trait_impl() { | |
1632 | check_number( | |
1633 | r#" | |
1634 | //- minicore: fn, copy | |
1635 | struct S(i32); | |
1636 | ||
1637 | impl FnOnce<(i32, i32)> for S { | |
1638 | type Output = i32; | |
1639 | ||
1640 | extern "rust-call" fn call_once(self, arg: (i32, i32)) -> i32 { | |
1641 | arg.0 + arg.1 + self.0 | |
1642 | } | |
1643 | } | |
1644 | ||
1645 | const GOAL: i32 = { | |
1646 | let s = S(1); | |
1647 | s(2, 3) | |
1648 | }; | |
1649 | "#, | |
1650 | 6, | |
1651 | ); | |
1652 | } | |
1653 | ||
1654 | #[test] | |
1655 | fn closure_capture_unsized_type() { | |
1656 | check_number( | |
1657 | r#" | |
1658 | //- minicore: fn, copy, slice, index, coerce_unsized | |
1659 | fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty { | |
1660 | let c = || &*x; | |
1661 | c() | |
1662 | } | |
1663 | ||
1664 | trait A { | |
1665 | type Ty; | |
1666 | } | |
1667 | ||
1668 | impl A for i32 { | |
1669 | type Ty = [u8]; | |
1670 | } | |
1671 | ||
1672 | const GOAL: u8 = { | |
1673 | let k: &[u8] = &[1, 2, 3]; | |
1674 | let k = f::<i32>(k); | |
1675 | k[0] + k[1] + k[2] | |
1676 | } | |
1677 | "#, | |
1678 | 6, | |
1679 | ); | |
1680 | } | |
1681 | ||
fe692bf9 FG |
1682 | #[test] |
1683 | fn closure_and_impl_fn() { | |
1684 | check_number( | |
1685 | r#" | |
1686 | //- minicore: fn, copy | |
1687 | fn closure_wrapper<F: FnOnce() -> i32>(c: F) -> impl FnOnce() -> F { | |
1688 | || c | |
1689 | } | |
1690 | ||
1691 | const GOAL: i32 = { | |
1692 | let y = 5; | |
1693 | let c = closure_wrapper(|| y); | |
1694 | c()() | |
1695 | }; | |
1696 | "#, | |
1697 | 5, | |
1698 | ); | |
1699 | check_number( | |
1700 | r#" | |
1701 | //- minicore: fn, copy | |
1702 | fn f<T, F: Fn() -> T>(t: F) -> impl Fn() -> T { | |
1703 | move || t() | |
1704 | } | |
1705 | ||
1706 | const GOAL: i32 = f(|| 2)(); | |
1707 | "#, | |
1708 | 2, | |
1709 | ); | |
1710 | } | |
1711 | ||
1712 | #[test] | |
1713 | fn or_pattern() { | |
1714 | check_number( | |
1715 | r#" | |
1716 | const GOAL: u8 = { | |
1717 | let (a | a) = 2; | |
1718 | a | |
1719 | }; | |
1720 | "#, | |
1721 | 2, | |
1722 | ); | |
1723 | check_number( | |
1724 | r#" | |
1725 | //- minicore: option | |
1726 | const fn f(x: Option<i32>) -> i32 { | |
1727 | let (Some(a) | Some(a)) = x else { return 2; }; | |
1728 | a | |
1729 | } | |
1730 | const GOAL: i32 = f(Some(10)) + f(None); | |
1731 | "#, | |
1732 | 12, | |
1733 | ); | |
1734 | check_number( | |
1735 | r#" | |
1736 | //- minicore: option | |
1737 | const fn f(x: Option<i32>, y: Option<i32>) -> i32 { | |
1738 | match (x, y) { | |
1739 | (Some(x), Some(y)) => x * y, | |
1740 | (Some(a), _) | (_, Some(a)) => a, | |
1741 | _ => 10, | |
1742 | } | |
1743 | } | |
1744 | const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None); | |
1745 | "#, | |
1746 | 280, | |
1747 | ); | |
1748 | } | |
1749 | ||
1750 | #[test] | |
1751 | fn function_pointer_in_constants() { | |
1752 | check_number( | |
1753 | r#" | |
1754 | struct Foo { | |
1755 | f: fn(u8) -> u8, | |
1756 | } | |
1757 | const FOO: Foo = Foo { f: add2 }; | |
1758 | fn add2(x: u8) -> u8 { | |
1759 | x + 2 | |
1760 | } | |
1761 | const GOAL: u8 = (FOO.f)(3); | |
1762 | "#, | |
1763 | 5, | |
1764 | ); | |
1765 | } | |
1766 | ||
add651ee FG |
1767 | #[test] |
1768 | fn function_pointer_and_niche_optimization() { | |
1769 | check_number( | |
1770 | r#" | |
1771 | //- minicore: option | |
1772 | const GOAL: i32 = { | |
1773 | let f: fn(i32) -> i32 = |x| x + 2; | |
1774 | let init = Some(f); | |
1775 | match init { | |
1776 | Some(t) => t(3), | |
1777 | None => 222, | |
1778 | } | |
1779 | }; | |
1780 | "#, | |
1781 | 5, | |
1782 | ); | |
1783 | } | |
1784 | ||
fe692bf9 FG |
1785 | #[test] |
1786 | fn function_pointer() { | |
1787 | check_number( | |
1788 | r#" | |
1789 | fn add2(x: u8) -> u8 { | |
1790 | x + 2 | |
1791 | } | |
1792 | const GOAL: u8 = { | |
1793 | let plus2 = add2; | |
1794 | plus2(3) | |
1795 | }; | |
1796 | "#, | |
1797 | 5, | |
1798 | ); | |
1799 | check_number( | |
1800 | r#" | |
1801 | fn add2(x: u8) -> u8 { | |
1802 | x + 2 | |
1803 | } | |
1804 | const GOAL: u8 = { | |
1805 | let plus2: fn(u8) -> u8 = add2; | |
1806 | plus2(3) | |
1807 | }; | |
1808 | "#, | |
1809 | 5, | |
1810 | ); | |
add651ee FG |
1811 | check_number( |
1812 | r#" | |
1813 | fn add2(x: u8) -> u8 { | |
1814 | x + 2 | |
1815 | } | |
1816 | const GOAL: u8 = { | |
1817 | let plus2 = add2 as fn(u8) -> u8; | |
1818 | plus2(3) | |
1819 | }; | |
1820 | "#, | |
1821 | 5, | |
1822 | ); | |
fe692bf9 FG |
1823 | check_number( |
1824 | r#" | |
1825 | //- minicore: coerce_unsized, index, slice | |
1826 | fn add2(x: u8) -> u8 { | |
1827 | x + 2 | |
1828 | } | |
1829 | fn mult3(x: u8) -> u8 { | |
1830 | x * 3 | |
1831 | } | |
1832 | const GOAL: u8 = { | |
1833 | let x = [add2, mult3]; | |
1834 | x[0](1) + x[1](5) | |
1835 | }; | |
1836 | "#, | |
1837 | 18, | |
1838 | ); | |
1839 | } | |
1840 | ||
1841 | #[test] | |
1842 | fn enum_variant_as_function() { | |
1843 | check_number( | |
1844 | r#" | |
1845 | //- minicore: option | |
1846 | const GOAL: u8 = { | |
1847 | let f = Some; | |
1848 | f(3).unwrap_or(2) | |
1849 | }; | |
1850 | "#, | |
1851 | 3, | |
1852 | ); | |
1853 | check_number( | |
1854 | r#" | |
1855 | //- minicore: option | |
1856 | const GOAL: u8 = { | |
1857 | let f: fn(u8) -> Option<u8> = Some; | |
1858 | f(3).unwrap_or(2) | |
1859 | }; | |
1860 | "#, | |
1861 | 3, | |
1862 | ); | |
1863 | check_number( | |
1864 | r#" | |
1865 | //- minicore: coerce_unsized, index, slice | |
1866 | enum Foo { | |
1867 | Add2(u8), | |
1868 | Mult3(u8), | |
1869 | } | |
1870 | use Foo::*; | |
1871 | const fn f(x: Foo) -> u8 { | |
1872 | match x { | |
1873 | Add2(x) => x + 2, | |
1874 | Mult3(x) => x * 3, | |
1875 | } | |
1876 | } | |
1877 | const GOAL: u8 = { | |
1878 | let x = [Add2, Mult3]; | |
1879 | f(x[0](1)) + f(x[1](5)) | |
1880 | }; | |
1881 | "#, | |
1882 | 18, | |
1883 | ); | |
1884 | } | |
1885 | ||
1886 | #[test] | |
1887 | fn function_traits() { | |
1888 | check_number( | |
1889 | r#" | |
1890 | //- minicore: fn | |
1891 | fn add2(x: u8) -> u8 { | |
1892 | x + 2 | |
1893 | } | |
1894 | fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { | |
1895 | f(x) | |
1896 | } | |
1897 | fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { | |
1898 | f(x) | |
1899 | } | |
1900 | fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { | |
1901 | f(x) | |
1902 | } | |
1903 | const GOAL: u8 = call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3); | |
1904 | "#, | |
1905 | 15, | |
353b0b11 FG |
1906 | ); |
1907 | check_number( | |
1908 | r#" | |
fe692bf9 FG |
1909 | //- minicore: coerce_unsized, fn |
1910 | fn add2(x: u8) -> u8 { | |
1911 | x + 2 | |
353b0b11 | 1912 | } |
fe692bf9 FG |
1913 | fn call(f: &dyn Fn(u8) -> u8, x: u8) -> u8 { |
1914 | f(x) | |
1915 | } | |
1916 | fn call_mut(f: &mut dyn FnMut(u8) -> u8, x: u8) -> u8 { | |
1917 | f(x) | |
1918 | } | |
1919 | const GOAL: u8 = call(&add2, 3) + call_mut(&mut add2, 3); | |
353b0b11 | 1920 | "#, |
fe692bf9 | 1921 | 10, |
353b0b11 FG |
1922 | ); |
1923 | check_number( | |
1924 | r#" | |
fe692bf9 FG |
1925 | //- minicore: fn |
1926 | fn add2(x: u8) -> u8 { | |
1927 | x + 2 | |
1928 | } | |
1929 | fn call(f: impl Fn(u8) -> u8, x: u8) -> u8 { | |
1930 | f(x) | |
1931 | } | |
1932 | fn call_mut(mut f: impl FnMut(u8) -> u8, x: u8) -> u8 { | |
1933 | f(x) | |
1934 | } | |
1935 | fn call_once(f: impl FnOnce(u8) -> u8, x: u8) -> u8 { | |
1936 | f(x) | |
1937 | } | |
353b0b11 | 1938 | const GOAL: u8 = { |
fe692bf9 FG |
1939 | let add2: fn(u8) -> u8 = add2; |
1940 | call(add2, 3) + call_mut(add2, 3) + call_once(add2, 3) | |
353b0b11 FG |
1941 | }; |
1942 | "#, | |
fe692bf9 | 1943 | 15, |
353b0b11 FG |
1944 | ); |
1945 | check_number( | |
1946 | r#" | |
fe692bf9 FG |
1947 | //- minicore: fn |
1948 | fn add2(x: u8) -> u8 { | |
1949 | x + 2 | |
1950 | } | |
1951 | fn call(f: &&&&&impl Fn(u8) -> u8, x: u8) -> u8 { | |
1952 | f(x) | |
1953 | } | |
1954 | const GOAL: u8 = call(&&&&&add2, 3); | |
353b0b11 | 1955 | "#, |
fe692bf9 | 1956 | 5, |
353b0b11 FG |
1957 | ); |
1958 | } | |
1959 | ||
1960 | #[test] | |
fe692bf9 | 1961 | fn dyn_trait() { |
353b0b11 FG |
1962 | check_number( |
1963 | r#" | |
fe692bf9 FG |
1964 | //- minicore: coerce_unsized, index, slice |
1965 | trait Foo { | |
1966 | fn foo(&self) -> u8 { 10 } | |
1967 | } | |
1968 | struct S1; | |
1969 | struct S2; | |
1970 | struct S3; | |
1971 | impl Foo for S1 { | |
1972 | fn foo(&self) -> u8 { 1 } | |
1973 | } | |
1974 | impl Foo for S2 { | |
1975 | fn foo(&self) -> u8 { 2 } | |
1976 | } | |
1977 | impl Foo for S3 {} | |
353b0b11 | 1978 | const GOAL: u8 = { |
fe692bf9 FG |
1979 | let x: &[&dyn Foo] = &[&S1, &S2, &S3]; |
1980 | x[0].foo() + x[1].foo() + x[2].foo() | |
353b0b11 FG |
1981 | }; |
1982 | "#, | |
fe692bf9 | 1983 | 13, |
353b0b11 FG |
1984 | ); |
1985 | check_number( | |
1986 | r#" | |
fe692bf9 FG |
1987 | //- minicore: coerce_unsized, index, slice |
1988 | trait Foo { | |
1989 | fn foo(&self) -> i32 { 10 } | |
353b0b11 | 1990 | } |
fe692bf9 FG |
1991 | trait Bar { |
1992 | fn bar(&self) -> i32 { 20 } | |
1993 | } | |
1994 | ||
1995 | struct S; | |
1996 | impl Foo for S { | |
1997 | fn foo(&self) -> i32 { 200 } | |
1998 | } | |
1999 | impl Bar for dyn Foo { | |
2000 | fn bar(&self) -> i32 { 700 } | |
2001 | } | |
2002 | const GOAL: i32 = { | |
2003 | let x: &dyn Foo = &S; | |
2004 | x.bar() + x.foo() | |
2005 | }; | |
353b0b11 | 2006 | "#, |
fe692bf9 | 2007 | 900, |
353b0b11 | 2008 | ); |
add651ee FG |
2009 | check_number( |
2010 | r#" | |
2011 | //- minicore: coerce_unsized, index, slice | |
2012 | trait A { | |
2013 | fn x(&self) -> i32; | |
2014 | } | |
2015 | ||
2016 | trait B: A {} | |
2017 | ||
2018 | impl A for i32 { | |
2019 | fn x(&self) -> i32 { | |
2020 | 5 | |
2021 | } | |
2022 | } | |
2023 | ||
2024 | impl B for i32 { | |
2025 | ||
2026 | } | |
2027 | ||
2028 | const fn f(x: &dyn B) -> i32 { | |
2029 | x.x() | |
2030 | } | |
2031 | ||
2032 | const GOAL: i32 = f(&2i32); | |
2033 | "#, | |
2034 | 5, | |
2035 | ); | |
2036 | } | |
2037 | ||
2038 | #[test] | |
2039 | fn coerce_unsized() { | |
2040 | check_number( | |
2041 | r#" | |
2042 | //- minicore: coerce_unsized, deref_mut, slice, index, transmute, non_null | |
2043 | use core::ops::{Deref, DerefMut, CoerceUnsized}; | |
2044 | use core::{marker::Unsize, mem::transmute, ptr::NonNull}; | |
2045 | ||
2046 | struct ArcInner<T: ?Sized> { | |
2047 | strong: usize, | |
2048 | weak: usize, | |
2049 | data: T, | |
2050 | } | |
2051 | ||
2052 | pub struct Arc<T: ?Sized> { | |
2053 | inner: NonNull<ArcInner<T>>, | |
2054 | } | |
2055 | ||
2056 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {} | |
2057 | ||
2058 | const GOAL: usize = { | |
2059 | let x = transmute::<usize, Arc<[i32; 3]>>(12); | |
2060 | let y: Arc<[i32]> = x; | |
2061 | let z = transmute::<Arc<[i32]>, (usize, usize)>(y); | |
2062 | z.1 | |
2063 | }; | |
2064 | ||
2065 | "#, | |
2066 | 3, | |
2067 | ); | |
fe692bf9 FG |
2068 | } |
2069 | ||
2070 | #[test] | |
2071 | fn boxes() { | |
353b0b11 FG |
2072 | check_number( |
2073 | r#" | |
fe692bf9 FG |
2074 | //- minicore: coerce_unsized, deref_mut, slice |
2075 | use core::ops::{Deref, DerefMut}; | |
2076 | use core::{marker::Unsize, ops::CoerceUnsized}; | |
2077 | ||
2078 | #[lang = "owned_box"] | |
2079 | pub struct Box<T: ?Sized> { | |
2080 | inner: *mut T, | |
2081 | } | |
2082 | impl<T> Box<T> { | |
2083 | fn new(t: T) -> Self { | |
2084 | #[rustc_box] | |
2085 | Box::new(t) | |
353b0b11 | 2086 | } |
fe692bf9 FG |
2087 | } |
2088 | ||
2089 | impl<T: ?Sized> Deref for Box<T> { | |
2090 | type Target = T; | |
2091 | ||
2092 | fn deref(&self) -> &T { | |
2093 | &**self | |
2094 | } | |
2095 | } | |
2096 | ||
2097 | impl<T: ?Sized> DerefMut for Box<T> { | |
2098 | fn deref_mut(&mut self) -> &mut T { | |
2099 | &mut **self | |
2100 | } | |
2101 | } | |
2102 | ||
2103 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {} | |
2104 | ||
2105 | const GOAL: usize = { | |
2106 | let x = Box::new(5); | |
2107 | let y: Box<[i32]> = Box::new([1, 2, 3]); | |
2108 | *x + y.len() | |
2109 | }; | |
2110 | "#, | |
2111 | 8, | |
353b0b11 FG |
2112 | ); |
2113 | } | |
2114 | ||
2115 | #[test] | |
2116 | fn array_and_index() { | |
2117 | check_number( | |
2118 | r#" | |
2119 | //- minicore: coerce_unsized, index, slice | |
2120 | const GOAL: u8 = { | |
2121 | let a = [10, 20, 3, 15]; | |
2122 | let x: &[u8] = &a; | |
2123 | x[1] | |
2124 | }; | |
2125 | "#, | |
2126 | 20, | |
2127 | ); | |
2128 | check_number( | |
2129 | r#" | |
2130 | //- minicore: coerce_unsized, index, slice | |
2131 | const GOAL: usize = [1, 2, 3][2];"#, | |
2132 | 3, | |
2133 | ); | |
2134 | check_number( | |
2135 | r#" | |
2136 | //- minicore: coerce_unsized, index, slice | |
2137 | const GOAL: usize = { let a = [1, 2, 3]; let x: &[i32] = &a; x.len() };"#, | |
2138 | 3, | |
2139 | ); | |
2140 | check_number( | |
2141 | r#" | |
2142 | //- minicore: coerce_unsized, index, slice | |
fe692bf9 FG |
2143 | const GOAL: usize = { |
2144 | let a = [1, 2, 3]; | |
2145 | let x: &[i32] = &a; | |
2146 | let y = &*x; | |
2147 | y.len() | |
2148 | };"#, | |
2149 | 3, | |
2150 | ); | |
2151 | check_number( | |
2152 | r#" | |
2153 | //- minicore: coerce_unsized, index, slice | |
353b0b11 FG |
2154 | const GOAL: usize = [1, 2, 3, 4, 5].len();"#, |
2155 | 5, | |
2156 | ); | |
fe692bf9 FG |
2157 | check_number( |
2158 | r#" | |
2159 | //- minicore: coerce_unsized, index, slice | |
2160 | const GOAL: [u16; 5] = [1, 2, 3, 4, 5];"#, | |
2161 | 1 + (2 << 16) + (3 << 32) + (4 << 48) + (5 << 64), | |
2162 | ); | |
2163 | check_number( | |
2164 | r#" | |
2165 | //- minicore: coerce_unsized, index, slice | |
2166 | const GOAL: [u16; 5] = [12; 5];"#, | |
2167 | 12 + (12 << 16) + (12 << 32) + (12 << 48) + (12 << 64), | |
2168 | ); | |
2169 | check_number( | |
2170 | r#" | |
2171 | //- minicore: coerce_unsized, index, slice | |
2172 | const LEN: usize = 4; | |
2173 | const GOAL: u16 = { | |
2174 | let x = [7; LEN]; | |
2175 | x[2] | |
2176 | }"#, | |
2177 | 7, | |
2178 | ); | |
353b0b11 FG |
2179 | } |
2180 | ||
add651ee FG |
2181 | #[test] |
2182 | fn string() { | |
2183 | check_str( | |
2184 | r#" | |
2185 | //- minicore: coerce_unsized, index, slice | |
2186 | const GOAL: &str = "hello"; | |
2187 | "#, | |
2188 | "hello", | |
2189 | ); | |
2190 | } | |
2191 | ||
353b0b11 FG |
2192 | #[test] |
2193 | fn byte_string() { | |
2194 | check_number( | |
2195 | r#" | |
2196 | //- minicore: coerce_unsized, index, slice | |
2197 | const GOAL: u8 = { | |
2198 | let a = b"hello"; | |
2199 | let x: &[u8] = a; | |
2200 | x[0] | |
2201 | }; | |
2202 | "#, | |
2203 | 104, | |
2204 | ); | |
2205 | } | |
2206 | ||
fe692bf9 FG |
2207 | #[test] |
2208 | fn c_string() { | |
2209 | check_number( | |
2210 | r#" | |
2211 | //- minicore: index, slice | |
2212 | #[lang = "CStr"] | |
2213 | pub struct CStr { | |
2214 | inner: [u8] | |
2215 | } | |
2216 | const GOAL: u8 = { | |
2217 | let a = c"hello"; | |
2218 | a.inner[0] | |
2219 | }; | |
2220 | "#, | |
2221 | 104, | |
2222 | ); | |
2223 | check_number( | |
2224 | r#" | |
2225 | //- minicore: index, slice | |
2226 | #[lang = "CStr"] | |
2227 | pub struct CStr { | |
2228 | inner: [u8] | |
2229 | } | |
2230 | const GOAL: u8 = { | |
2231 | let a = c"hello"; | |
2232 | a.inner[6] | |
2233 | }; | |
2234 | "#, | |
2235 | 0, | |
2236 | ); | |
2237 | } | |
2238 | ||
064997fb FG |
2239 | #[test] |
2240 | fn consts() { | |
2241 | check_number( | |
2242 | r#" | |
2243 | const F1: i32 = 1; | |
2244 | const F3: i32 = 3 * F2; | |
2245 | const F2: i32 = 2 * F1; | |
2246 | const GOAL: i32 = F3; | |
2247 | "#, | |
2248 | 6, | |
2249 | ); | |
add651ee FG |
2250 | |
2251 | check_number( | |
2252 | r#" | |
2253 | const F1: i32 = 2147483647; | |
2254 | const F2: i32 = F1 - 25; | |
2255 | const GOAL: i32 = F2; | |
2256 | "#, | |
2257 | 2147483622, | |
2258 | ); | |
2259 | ||
2260 | check_number( | |
2261 | r#" | |
2262 | const F1: i32 = -2147483648; | |
2263 | const F2: i32 = F1 + 18; | |
2264 | const GOAL: i32 = F2; | |
2265 | "#, | |
2266 | -2147483630, | |
2267 | ); | |
2268 | ||
2269 | check_number( | |
2270 | r#" | |
2271 | const F1: i32 = 10; | |
2272 | const F2: i32 = F1 - 20; | |
2273 | const GOAL: i32 = F2; | |
2274 | "#, | |
2275 | -10, | |
2276 | ); | |
2277 | ||
2278 | check_number( | |
2279 | r#" | |
2280 | const F1: i32 = 25; | |
2281 | const F2: i32 = F1 - 25; | |
2282 | const GOAL: i32 = F2; | |
2283 | "#, | |
2284 | 0, | |
2285 | ); | |
2286 | ||
2287 | check_number( | |
2288 | r#" | |
2289 | const A: i32 = -2147483648; | |
2290 | const GOAL: bool = A > 0; | |
2291 | "#, | |
2292 | 0, | |
2293 | ); | |
2294 | ||
2295 | check_number( | |
2296 | r#" | |
2297 | const GOAL: i64 = (-2147483648_i32) as i64; | |
2298 | "#, | |
2299 | -2147483648, | |
2300 | ); | |
064997fb FG |
2301 | } |
2302 | ||
fe692bf9 FG |
2303 | #[test] |
2304 | fn statics() { | |
2305 | check_number( | |
2306 | r#" | |
2307 | //- minicore: cell | |
2308 | use core::cell::Cell; | |
2309 | fn f() -> i32 { | |
2310 | static S: Cell<i32> = Cell::new(10); | |
2311 | S.set(S.get() + 1); | |
2312 | S.get() | |
2313 | } | |
2314 | const GOAL: i32 = f() + f() + f(); | |
2315 | "#, | |
2316 | 36, | |
2317 | ); | |
2318 | } | |
2319 | ||
2320 | #[test] | |
2321 | fn extern_weak_statics() { | |
2322 | check_number( | |
2323 | r#" | |
2324 | extern "C" { | |
2325 | #[linkage = "extern_weak"] | |
2326 | static __dso_handle: *mut u8; | |
2327 | } | |
2328 | const GOAL: usize = __dso_handle as usize; | |
2329 | "#, | |
2330 | 0, | |
2331 | ); | |
2332 | } | |
2333 | ||
2334 | #[test] | |
2335 | fn from_ne_bytes() { | |
2336 | check_number( | |
2337 | r#" | |
2338 | //- minicore: int_impl | |
2339 | const GOAL: u32 = u32::from_ne_bytes([44, 1, 0, 0]); | |
2340 | "#, | |
2341 | 300, | |
2342 | ); | |
2343 | } | |
2344 | ||
2b03887a FG |
2345 | #[test] |
2346 | fn enums() { | |
2347 | check_number( | |
2348 | r#" | |
2349 | enum E { | |
2350 | F1 = 1, | |
353b0b11 FG |
2351 | F2 = 2 * E::F1 as isize, // Rustc expects an isize here |
2352 | F3 = 3 * E::F2 as isize, | |
2b03887a | 2353 | } |
353b0b11 | 2354 | const GOAL: u8 = E::F3 as u8; |
2b03887a FG |
2355 | "#, |
2356 | 6, | |
2357 | ); | |
2358 | check_number( | |
2359 | r#" | |
2360 | enum E { F1 = 1, F2, } | |
353b0b11 | 2361 | const GOAL: u8 = E::F2 as u8; |
2b03887a FG |
2362 | "#, |
2363 | 2, | |
2364 | ); | |
2365 | check_number( | |
2366 | r#" | |
2367 | enum E { F1, } | |
353b0b11 | 2368 | const GOAL: u8 = E::F1 as u8; |
2b03887a FG |
2369 | "#, |
2370 | 0, | |
2371 | ); | |
fe692bf9 | 2372 | let (db, file_id) = TestDB::with_single_file( |
2b03887a | 2373 | r#" |
353b0b11 | 2374 | enum E { A = 1, B } |
2b03887a FG |
2375 | const GOAL: E = E::A; |
2376 | "#, | |
fe692bf9 FG |
2377 | ); |
2378 | let r = eval_goal(&db, file_id).unwrap(); | |
2379 | assert_eq!(try_const_usize(&db, &r), Some(1)); | |
2b03887a FG |
2380 | } |
2381 | ||
064997fb FG |
2382 | #[test] |
2383 | fn const_loop() { | |
2384 | check_fail( | |
2385 | r#" | |
2386 | const F1: i32 = 1 * F3; | |
2387 | const F3: i32 = 3 * F2; | |
2388 | const F2: i32 = 2 * F1; | |
2389 | const GOAL: i32 = F3; | |
2390 | "#, | |
fe692bf9 | 2391 | |e| e == ConstEvalError::MirLowerError(MirLowerError::Loop), |
353b0b11 FG |
2392 | ); |
2393 | } | |
2394 | ||
2395 | #[test] | |
2396 | fn const_transfer_memory() { | |
2397 | check_number( | |
2398 | r#" | |
add651ee FG |
2399 | //- minicore: slice, index, coerce_unsized |
2400 | const A1: &i32 = &1; | |
2401 | const A2: &i32 = &10; | |
2402 | const A3: [&i32; 3] = [&1, &2, &100]; | |
2403 | const A4: (i32, &i32) = (1, &1000); | |
2404 | const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1; | |
353b0b11 | 2405 | "#, |
add651ee | 2406 | 1111, |
064997fb FG |
2407 | ); |
2408 | } | |
2409 | ||
fe692bf9 FG |
2410 | #[test] |
2411 | fn anonymous_const_block() { | |
2412 | check_number( | |
2413 | r#" | |
2414 | extern "rust-intrinsic" { | |
2415 | pub fn size_of<T>() -> usize; | |
2416 | } | |
2417 | ||
2418 | const fn f<T>() -> usize { | |
2419 | let r = const { size_of::<T>() }; | |
2420 | r | |
2421 | } | |
2422 | ||
2423 | const GOAL: usize = { | |
2424 | let x = const { 2 + const { 3 } }; | |
2425 | let y = f::<i32>(); | |
2426 | x + y | |
2427 | }; | |
2428 | "#, | |
2429 | 9, | |
2430 | ); | |
2431 | } | |
2432 | ||
064997fb FG |
2433 | #[test] |
2434 | fn const_impl_assoc() { | |
2435 | check_number( | |
2436 | r#" | |
2437 | struct U5; | |
2438 | impl U5 { | |
2439 | const VAL: usize = 5; | |
2440 | } | |
fe692bf9 | 2441 | const GOAL: usize = U5::VAL + <U5>::VAL; |
064997fb | 2442 | "#, |
fe692bf9 | 2443 | 10, |
064997fb FG |
2444 | ); |
2445 | } | |
2446 | ||
2447 | #[test] | |
353b0b11 FG |
2448 | fn const_generic_subst_fn() { |
2449 | check_number( | |
2450 | r#" | |
2451 | const fn f<const A: usize>(x: usize) -> usize { | |
2452 | A * x + 5 | |
2453 | } | |
2454 | const GOAL: usize = f::<2>(3); | |
2455 | "#, | |
2456 | 11, | |
2457 | ); | |
fe692bf9 FG |
2458 | check_number( |
2459 | r#" | |
2460 | fn f<const N: usize>(x: [i32; N]) -> usize { | |
2461 | N | |
2462 | } | |
2463 | ||
2464 | trait ArrayExt { | |
2465 | fn f(self) -> usize; | |
2466 | } | |
2467 | ||
2468 | impl<T, const N: usize> ArrayExt for [T; N] { | |
2469 | fn g(self) -> usize { | |
2470 | f(self) | |
2471 | } | |
2472 | } | |
2473 | ||
2474 | const GOAL: usize = f([1, 2, 5]); | |
2475 | "#, | |
2476 | 3, | |
2477 | ); | |
2478 | } | |
2479 | ||
2480 | #[test] | |
2481 | fn layout_of_type_with_associated_type_field_defined_inside_body() { | |
2482 | check_number( | |
2483 | r#" | |
2484 | trait Tr { | |
2485 | type Ty; | |
2486 | } | |
2487 | ||
2488 | struct St<T: Tr>(T::Ty); | |
2489 | ||
2490 | const GOAL: i64 = { | |
2491 | // if we move `St2` out of body, the test will fail, as we don't see the impl anymore. That | |
2492 | // case will probably be rejected by rustc in some later edition, but we should support this | |
2493 | // case. | |
2494 | struct St2; | |
2495 | ||
2496 | impl Tr for St2 { | |
2497 | type Ty = i64; | |
2498 | } | |
2499 | ||
2500 | struct Goal(St<St2>); | |
2501 | ||
2502 | let x = Goal(St(5)); | |
2503 | x.0.0 | |
2504 | }; | |
2505 | "#, | |
2506 | 5, | |
2507 | ); | |
353b0b11 FG |
2508 | } |
2509 | ||
2510 | #[test] | |
2511 | fn const_generic_subst_assoc_const_impl() { | |
fe692bf9 | 2512 | check_number( |
064997fb FG |
2513 | r#" |
2514 | struct Adder<const N: usize, const M: usize>; | |
2515 | impl<const N: usize, const M: usize> Adder<N, M> { | |
2516 | const VAL: usize = N + M; | |
2517 | } | |
2518 | const GOAL: usize = Adder::<2, 3>::VAL; | |
2519 | "#, | |
fe692bf9 FG |
2520 | 5, |
2521 | ); | |
2522 | } | |
2523 | ||
2524 | #[test] | |
2525 | fn associated_types() { | |
2526 | check_number( | |
2527 | r#" | |
2528 | trait Tr { | |
2529 | type Item; | |
2530 | fn get_item(&self) -> Self::Item; | |
2531 | } | |
2532 | ||
2533 | struct X(i32); | |
2534 | struct Y(i32); | |
2535 | ||
2536 | impl Tr for X { | |
2537 | type Item = Y; | |
2538 | fn get_item(&self) -> Self::Item { | |
2539 | Y(self.0 + 2) | |
2540 | } | |
2541 | } | |
2542 | ||
2543 | fn my_get_item<T: Tr>(x: T) -> <T as Tr>::Item { | |
2544 | x.get_item() | |
2545 | } | |
2546 | ||
2547 | const GOAL: i32 = my_get_item(X(3)).0; | |
2548 | "#, | |
2549 | 5, | |
064997fb FG |
2550 | ); |
2551 | } | |
2552 | ||
2553 | #[test] | |
2554 | fn const_trait_assoc() { | |
fe692bf9 | 2555 | check_number( |
064997fb FG |
2556 | r#" |
2557 | struct U0; | |
2558 | trait ToConst { | |
2559 | const VAL: usize; | |
2560 | } | |
2561 | impl ToConst for U0 { | |
2562 | const VAL: usize = 0; | |
2563 | } | |
fe692bf9 FG |
2564 | impl ToConst for i32 { |
2565 | const VAL: usize = 32; | |
2566 | } | |
2567 | const GOAL: usize = U0::VAL + i32::VAL; | |
2568 | "#, | |
2569 | 32, | |
2570 | ); | |
add651ee FG |
2571 | check_number( |
2572 | r#" | |
2573 | //- /a/lib.rs crate:a | |
2574 | pub trait ToConst { | |
2575 | const VAL: usize; | |
2576 | } | |
2577 | pub const fn to_const<T: ToConst>() -> usize { | |
2578 | T::VAL | |
2579 | } | |
2580 | //- /main.rs crate:main deps:a | |
2581 | use a::{ToConst, to_const}; | |
2582 | struct U0; | |
2583 | impl ToConst for U0 { | |
2584 | const VAL: usize = 5; | |
2585 | } | |
2586 | const GOAL: usize = to_const::<U0>(); | |
2587 | "#, | |
2588 | 5, | |
2589 | ); | |
2590 | check_number( | |
2591 | r#" | |
2592 | //- minicore: size_of, fn | |
2593 | //- /a/lib.rs crate:a | |
2594 | use core::mem::size_of; | |
2595 | pub struct S<T>(T); | |
2596 | impl<T> S<T> { | |
2597 | pub const X: usize = { | |
2598 | let k: T; | |
2599 | let f = || core::mem::size_of::<T>(); | |
2600 | f() | |
2601 | }; | |
2602 | } | |
2603 | //- /main.rs crate:main deps:a | |
2604 | use a::{S}; | |
2605 | trait Tr { | |
2606 | type Ty; | |
2607 | } | |
2608 | impl Tr for i32 { | |
2609 | type Ty = u64; | |
2610 | } | |
2611 | struct K<T: Tr>(<T as Tr>::Ty); | |
2612 | const GOAL: usize = S::<K<i32>>::X; | |
2613 | "#, | |
2614 | 8, | |
2615 | ); | |
fe692bf9 FG |
2616 | check_number( |
2617 | r#" | |
2618 | struct S<T>(*mut T); | |
2619 | ||
2620 | trait MySized: Sized { | |
2621 | const SIZE: S<Self> = S(1 as *mut Self); | |
2622 | } | |
2623 | ||
2624 | impl MySized for i32 { | |
2625 | const SIZE: S<i32> = S(10 as *mut i32); | |
2626 | } | |
2627 | ||
2628 | impl MySized for i64 { | |
2629 | } | |
2630 | ||
2631 | const fn f<T: MySized>() -> usize { | |
2632 | T::SIZE.0 as usize | |
2633 | } | |
2634 | ||
2635 | const GOAL: usize = f::<i32>() + f::<i64>() * 2; | |
2636 | "#, | |
2637 | 12, | |
2638 | ); | |
2639 | } | |
2640 | ||
353b0b11 FG |
2641 | #[test] |
2642 | fn exec_limits() { | |
add651ee FG |
2643 | if skip_slow_tests() { |
2644 | return; | |
2645 | } | |
2646 | ||
353b0b11 FG |
2647 | check_fail( |
2648 | r#" | |
2649 | const GOAL: usize = loop {}; | |
2650 | "#, | |
fe692bf9 | 2651 | |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded), |
353b0b11 FG |
2652 | ); |
2653 | check_fail( | |
2654 | r#" | |
2655 | const fn f(x: i32) -> i32 { | |
2656 | f(x + 1) | |
2657 | } | |
2658 | const GOAL: i32 = f(0); | |
2659 | "#, | |
add651ee | 2660 | |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded), |
353b0b11 FG |
2661 | ); |
2662 | // Reasonable code should still work | |
2663 | check_number( | |
2664 | r#" | |
2665 | const fn nth_odd(n: i32) -> i32 { | |
2666 | 2 * n - 1 | |
2667 | } | |
2668 | const fn f(n: i32) -> i32 { | |
2669 | let sum = 0; | |
2670 | let i = 0; | |
2671 | while i < n { | |
2672 | i = i + 1; | |
2673 | sum = sum + nth_odd(i); | |
2674 | } | |
2675 | sum | |
2676 | } | |
add651ee | 2677 | const GOAL: i32 = f(1000); |
353b0b11 | 2678 | "#, |
add651ee FG |
2679 | 1000 * 1000, |
2680 | ); | |
2681 | } | |
2682 | ||
2683 | #[test] | |
2684 | fn memory_limit() { | |
2685 | check_fail( | |
2686 | r#" | |
2687 | extern "Rust" { | |
2688 | #[rustc_allocator] | |
2689 | fn __rust_alloc(size: usize, align: usize) -> *mut u8; | |
2690 | } | |
2691 | ||
2692 | const GOAL: u8 = unsafe { | |
2693 | __rust_alloc(30_000_000_000, 1); // 30GB | |
2694 | 2 | |
2695 | }; | |
2696 | "#, | |
2697 | |e| { | |
2698 | e == ConstEvalError::MirEvalError(MirEvalError::Panic( | |
2699 | "Memory allocation of 30000000000 bytes failed".to_string(), | |
2700 | )) | |
2701 | }, | |
353b0b11 FG |
2702 | ); |
2703 | } | |
2704 | ||
2705 | #[test] | |
2706 | fn type_error() { | |
fe692bf9 | 2707 | check_fail( |
353b0b11 FG |
2708 | r#" |
2709 | const GOAL: u8 = { | |
2710 | let x: u16 = 2; | |
2711 | let y: (u8, u8) = x; | |
2712 | y.0 | |
2713 | }; | |
2714 | "#, | |
fe692bf9 FG |
2715 | |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_))), |
2716 | ); | |
2717 | } | |
2718 | ||
add651ee FG |
2719 | #[test] |
2720 | fn unsized_field() { | |
2721 | check_number( | |
2722 | r#" | |
2723 | //- minicore: coerce_unsized, index, slice, transmute | |
2724 | use core::mem::transmute; | |
2725 | ||
2726 | struct Slice([usize]); | |
2727 | struct Slice2(Slice); | |
2728 | ||
2729 | impl Slice2 { | |
2730 | fn as_inner(&self) -> &Slice { | |
2731 | &self.0 | |
2732 | } | |
2733 | ||
2734 | fn as_bytes(&self) -> &[usize] { | |
2735 | &self.as_inner().0 | |
2736 | } | |
2737 | } | |
2738 | ||
2739 | const GOAL: usize = unsafe { | |
2740 | let x: &[usize] = &[1, 2, 3]; | |
2741 | let x: &Slice2 = transmute(x); | |
2742 | let x = x.as_bytes(); | |
2743 | x[0] + x[1] + x[2] + x.len() * 100 | |
2744 | }; | |
2745 | "#, | |
2746 | 306, | |
2747 | ); | |
2748 | } | |
2749 | ||
fe692bf9 FG |
2750 | #[test] |
2751 | fn unsized_local() { | |
2752 | check_fail( | |
2753 | r#" | |
2754 | //- minicore: coerce_unsized, index, slice | |
2755 | const fn x() -> SomeUnknownTypeThatDereferenceToSlice { | |
2756 | SomeUnknownTypeThatDereferenceToSlice | |
2757 | } | |
2758 | ||
2759 | const GOAL: u16 = { | |
2760 | let y = x(); | |
2761 | let z: &[u16] = &y; | |
2762 | z[1] | |
2763 | }; | |
2764 | "#, | |
2765 | |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::UnsizedTemporary(_))), | |
064997fb FG |
2766 | ); |
2767 | } |