Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/consteval/tests.rs')
-rw-r--r--crates/hir-ty/src/consteval/tests.rs259
1 files changed, 249 insertions, 10 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 19145b2d98..f2e42d6e50 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -103,6 +103,22 @@ fn references() {
"#,
5,
);
+ check_number(
+ r#"
+ struct Foo(i32);
+ impl Foo {
+ fn method(&mut self, x: i32) {
+ self.0 = 2 * self.0 + x;
+ }
+ }
+ const GOAL: i32 = {
+ let mut x = Foo(3);
+ x.method(5);
+ x.0
+ };
+ "#,
+ 11,
+ );
}
#[test]
@@ -133,6 +149,60 @@ fn reference_autoderef() {
}
#[test]
+fn overloaded_deref() {
+ // FIXME: We should support this.
+ check_fail(
+ r#"
+ //- minicore: deref_mut
+ struct Foo;
+
+ impl core::ops::Deref for Foo {
+ type Target = i32;
+ fn deref(&self) -> &i32 {
+ &5
+ }
+ }
+
+ const GOAL: i32 = {
+ let x = Foo;
+ let y = &*x;
+ *y + *x
+ };
+ "#,
+ ConstEvalError::MirLowerError(MirLowerError::NotSupported(
+ "explicit overloaded deref".into(),
+ )),
+ );
+}
+
+#[test]
+fn overloaded_deref_autoref() {
+ check_number(
+ r#"
+ //- minicore: deref_mut
+ struct Foo;
+ struct Bar;
+
+ impl core::ops::Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &Bar
+ }
+ }
+
+ impl Bar {
+ fn method(&self) -> i32 {
+ 5
+ }
+ }
+
+ const GOAL: i32 = Foo.method();
+ "#,
+ 5,
+ );
+}
+
+#[test]
fn function_call() {
check_number(
r#"
@@ -358,7 +428,7 @@ fn ifs() {
if a < b { b } else { a }
}
- const GOAL: u8 = max(max(1, max(10, 3)), 0-122);
+ const GOAL: i32 = max(max(1, max(10, 3)), 0-122);
"#,
10,
);
@@ -366,7 +436,7 @@ fn ifs() {
check_number(
r#"
const fn max(a: &i32, b: &i32) -> &i32 {
- if a < b { b } else { a }
+ if *a < *b { b } else { a }
}
const GOAL: i32 = *max(max(&1, max(&10, &3)), &5);
@@ -400,6 +470,43 @@ fn loops() {
}
#[test]
+fn for_loops() {
+ check_number(
+ r#"
+ //- minicore: iterator
+
+ struct Range {
+ start: u8,
+ end: u8,
+ }
+
+ impl Iterator for Range {
+ type Item = u8;
+ fn next(&mut self) -> Option<u8> {
+ if self.start >= self.end {
+ None
+ } else {
+ let r = self.start;
+ self.start = self.start + 1;
+ Some(r)
+ }
+ }
+ }
+
+ const GOAL: u8 = {
+ let mut sum = 0;
+ let ar = Range { start: 1, end: 11 };
+ for i in ar {
+ sum = sum + i;
+ }
+ sum
+ };
+ "#,
+ 55,
+ );
+}
+
+#[test]
fn recursion() {
check_number(
r#"
@@ -466,6 +573,16 @@ fn tuples() {
);
check_number(
r#"
+ const GOAL: u8 = {
+ let mut a = (10, 20, 3, 15);
+ a.1 = 2;
+ a.0 + a.1 + a.2 + a.3
+ };
+ "#,
+ 30,
+ );
+ check_number(
+ r#"
struct TupleLike(i32, u8, i64, u16);
const GOAL: u8 = {
let a = TupleLike(10, 20, 3, 15);
@@ -493,6 +610,33 @@ fn tuples() {
}
#[test]
+fn path_pattern_matching() {
+ check_number(
+ r#"
+ enum Season {
+ Spring,
+ Summer,
+ Fall,
+ Winter,
+ }
+
+ use Season::*;
+
+ const fn f(x: Season) -> i32 {
+ match x {
+ Spring => 1,
+ Summer => 2,
+ Fall => 3,
+ Winter => 4,
+ }
+ }
+ const GOAL: i32 = f(Spring) + 10 * f(Summer) + 100 * f(Fall) + 1000 * f(Winter);
+ "#,
+ 4321,
+ );
+}
+
+#[test]
fn pattern_matching_ergonomics() {
check_number(
r#"
@@ -539,13 +683,56 @@ fn let_else() {
let Some(x) = x else { return 10 };
2 * x
}
- const GOAL: u8 = f(Some(1000)) + f(None);
+ const GOAL: i32 = f(Some(1000)) + f(None);
"#,
2010,
);
}
#[test]
+fn function_param_patterns() {
+ check_number(
+ r#"
+ const fn f((a, b): &(u8, u8)) -> u8 {
+ *a + *b
+ }
+ const GOAL: u8 = f(&(2, 3));
+ "#,
+ 5,
+ );
+ check_number(
+ r#"
+ const fn f(c @ (a, b): &(u8, u8)) -> u8 {
+ *a + *b + c.0 + (*c).1
+ }
+ const GOAL: u8 = f(&(2, 3));
+ "#,
+ 10,
+ );
+ check_number(
+ r#"
+ const fn f(ref a: u8) -> u8 {
+ *a
+ }
+ const GOAL: u8 = f(2);
+ "#,
+ 2,
+ );
+ check_number(
+ r#"
+ struct Foo(u8);
+ impl Foo {
+ const fn f(&self, (a, b): &(u8, u8)) -> u8 {
+ self.0 + *a + *b
+ }
+ }
+ const GOAL: u8 = Foo(4).f(&(2, 3));
+ "#,
+ 9,
+ );
+}
+
+#[test]
fn options() {
check_number(
r#"
@@ -572,7 +759,7 @@ fn options() {
0
}
}
- const GOAL: u8 = f(Some(Some(10))) + f(Some(None)) + f(None);
+ const GOAL: i32 = f(Some(Some(10))) + f(Some(None)) + f(None);
"#,
11,
);
@@ -599,6 +786,44 @@ fn options() {
}
#[test]
+fn or_pattern() {
+ check_number(
+ r#"
+ const GOAL: u8 = {
+ let (a | a) = 2;
+ a
+ };
+ "#,
+ 2,
+ );
+ check_number(
+ r#"
+ //- minicore: option
+ const fn f(x: Option<i32>) -> i32 {
+ let (Some(a) | Some(a)) = x else { return 2; };
+ a
+ }
+ const GOAL: i32 = f(Some(10)) + f(None);
+ "#,
+ 12,
+ );
+ check_number(
+ r#"
+ //- minicore: option
+ const fn f(x: Option<i32>, y: Option<i32>) -> i32 {
+ match (x, y) {
+ (Some(x), Some(y)) => x * y,
+ (Some(a), _) | (_, Some(a)) => a,
+ _ => 10,
+ }
+ }
+ const GOAL: i32 = f(Some(10), Some(20)) + f(Some(30), None) + f(None, Some(40)) + f(None, None);
+ "#,
+ 280,
+ );
+}
+
+#[test]
fn array_and_index() {
check_number(
r#"
@@ -665,24 +890,24 @@ fn enums() {
r#"
enum E {
F1 = 1,
- F2 = 2 * E::F1 as u8,
- F3 = 3 * E::F2 as u8,
+ F2 = 2 * E::F1 as isize, // Rustc expects an isize here
+ F3 = 3 * E::F2 as isize,
}
- const GOAL: i32 = E::F3 as u8;
+ const GOAL: u8 = E::F3 as u8;
"#,
6,
);
check_number(
r#"
enum E { F1 = 1, F2, }
- const GOAL: i32 = E::F2 as u8;
+ const GOAL: u8 = E::F2 as u8;
"#,
2,
);
check_number(
r#"
enum E { F1, }
- const GOAL: i32 = E::F1 as u8;
+ const GOAL: u8 = E::F1 as u8;
"#,
0,
);
@@ -813,8 +1038,22 @@ fn exec_limits() {
}
sum
}
- const GOAL: usize = f(10000);
+ const GOAL: i32 = f(10000);
"#,
10000 * 10000,
);
}
+
+#[test]
+fn type_error() {
+ let e = eval_goal(
+ r#"
+ const GOAL: u8 = {
+ let x: u16 = 2;
+ let y: (u8, u8) = x;
+ y.0
+ };
+ "#,
+ );
+ assert!(matches!(e, Err(ConstEvalError::MirLowerError(MirLowerError::TypeMismatch(_)))));
+}