Skip to content

Commit fd5ac67

Browse files
committed
organize const eval tests
1 parent 0e2989e commit fd5ac67

File tree

4 files changed

+179
-164
lines changed

4 files changed

+179
-164
lines changed

crates/hir_ty/src/consteval.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,14 @@ impl Display for ComputedExpr {
8787
match self {
8888
ComputedExpr::Literal(l) => match l {
8989
Literal::Int(x, _) => {
90-
if *x >= 16 {
90+
if *x >= 10 {
9191
write!(f, "{} ({:#X})", x, x)
9292
} else {
9393
x.fmt(f)
9494
}
9595
}
9696
Literal::Uint(x, _) => {
97-
if *x >= 16 {
97+
if *x >= 10 {
9898
write!(f, "{} ({:#X})", x, x)
9999
} else {
100100
x.fmt(f)
@@ -156,6 +156,7 @@ pub fn eval_const(
156156
) -> Result<ComputedExpr, ConstEvalError> {
157157
let expr = &ctx.exprs[expr_id];
158158
match expr {
159+
Expr::Missing => Err(ConstEvalError::IncompleteExpr),
159160
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
160161
&Expr::UnaryOp { expr, op } => {
161162
let ty = &ctx.expr_ty(expr);
@@ -339,6 +340,9 @@ pub fn eval_const(
339340
Ok(r.clone())
340341
}
341342
ValueNs::ConstId(id) => ctx.db.const_eval(id),
343+
ValueNs::GenericParam(_) => {
344+
Err(ConstEvalError::NotSupported("const generic without substitution"))
345+
}
342346
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
343347
}
344348
}
@@ -433,7 +437,7 @@ pub(crate) fn const_eval_query(
433437
) -> Result<ComputedExpr, ConstEvalError> {
434438
let def = const_id.into();
435439
let body = db.body(def);
436-
let mut infer = db.infer_query(def);
440+
let infer = &db.infer(def);
437441
let result = eval_const(
438442
body.body_expr,
439443
&mut ConstEvalCtx {
@@ -442,7 +446,7 @@ pub(crate) fn const_eval_query(
442446
exprs: &body.exprs,
443447
pats: &body.pats,
444448
local_data: HashMap::default(),
445-
infer: &mut infer,
449+
infer,
446450
},
447451
);
448452
result
@@ -473,3 +477,6 @@ pub(crate) fn eval_to_const<'a>(
473477
};
474478
usize_const(eval_usize(expr, ctx))
475479
}
480+
481+
#[cfg(test)]
482+
mod tests;

crates/hir_ty/src/consteval/tests.rs

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use base_db::fixture::WithFixture;
2+
use hir_def::{db::DefDatabase, expr::Literal};
3+
4+
use crate::{consteval::ComputedExpr, db::HirDatabase, test_db::TestDB};
5+
6+
use super::ConstEvalError;
7+
8+
fn check_fail(ra_fixture: &str, error: ConstEvalError) {
9+
assert_eq!(eval_goal(ra_fixture), Err(error));
10+
}
11+
12+
fn check_number(ra_fixture: &str, answer: i128) {
13+
let r = eval_goal(ra_fixture).unwrap();
14+
match r {
15+
ComputedExpr::Literal(Literal::Int(r, _)) => assert_eq!(r, answer),
16+
ComputedExpr::Literal(Literal::Uint(r, _)) => assert_eq!(r, answer as u128),
17+
x => panic!("Expected number but found {:?}", x),
18+
}
19+
}
20+
21+
fn eval_goal(ra_fixture: &str) -> Result<ComputedExpr, ConstEvalError> {
22+
let (db, file_id) = TestDB::with_single_file(ra_fixture);
23+
let module_id = db.module_for_file(file_id);
24+
let def_map = module_id.def_map(&db);
25+
let scope = &def_map[module_id.local_id].scope;
26+
let const_id = scope
27+
.declarations()
28+
.into_iter()
29+
.find_map(|x| match x {
30+
hir_def::ModuleDefId::ConstId(x) => {
31+
if db.const_data(x).name.as_ref()?.to_string() == "GOAL" {
32+
Some(x)
33+
} else {
34+
None
35+
}
36+
}
37+
_ => None,
38+
})
39+
.unwrap();
40+
db.const_eval(const_id)
41+
}
42+
43+
#[test]
44+
fn add() {
45+
check_number(r#"const GOAL: usize = 2 + 2;"#, 4);
46+
}
47+
48+
#[test]
49+
fn bit_op() {
50+
check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
51+
check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
52+
// FIXME: rustc evaluate this to -128
53+
check_fail(
54+
r#"const GOAL: i8 = 1 << 7"#,
55+
ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
56+
);
57+
check_fail(
58+
r#"const GOAL: i8 = 1 << 8"#,
59+
ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
60+
);
61+
}
62+
63+
#[test]
64+
fn locals() {
65+
check_number(
66+
r#"
67+
const GOAL: usize = {
68+
let a = 3 + 2;
69+
let b = a * a;
70+
b
71+
};
72+
"#,
73+
25,
74+
);
75+
}
76+
77+
#[test]
78+
fn consts() {
79+
check_number(
80+
r#"
81+
const F1: i32 = 1;
82+
const F3: i32 = 3 * F2;
83+
const F2: i32 = 2 * F1;
84+
const GOAL: i32 = F3;
85+
"#,
86+
6,
87+
);
88+
}
89+
90+
#[test]
91+
fn const_loop() {
92+
check_fail(
93+
r#"
94+
const F1: i32 = 1 * F3;
95+
const F3: i32 = 3 * F2;
96+
const F2: i32 = 2 * F1;
97+
const GOAL: i32 = F3;
98+
"#,
99+
ConstEvalError::Loop,
100+
);
101+
}
102+
103+
#[test]
104+
fn const_impl_assoc() {
105+
check_number(
106+
r#"
107+
struct U5;
108+
impl U5 {
109+
const VAL: usize = 5;
110+
}
111+
const GOAL: usize = U5::VAL;
112+
"#,
113+
5,
114+
);
115+
}
116+
117+
#[test]
118+
fn const_generic_subst() {
119+
// FIXME: this should evaluate to 5
120+
check_fail(
121+
r#"
122+
struct Adder<const N: usize, const M: usize>;
123+
impl<const N: usize, const M: usize> Adder<N, M> {
124+
const VAL: usize = N + M;
125+
}
126+
const GOAL: usize = Adder::<2, 3>::VAL;
127+
"#,
128+
ConstEvalError::NotSupported("const generic without substitution"),
129+
);
130+
}
131+
132+
#[test]
133+
fn const_trait_assoc() {
134+
// FIXME: this should evaluate to 0
135+
check_fail(
136+
r#"
137+
struct U0;
138+
trait ToConst {
139+
const VAL: usize;
140+
}
141+
impl ToConst for U0 {
142+
const VAL: usize = 0;
143+
}
144+
const GOAL: usize = U0::VAL;
145+
"#,
146+
ConstEvalError::IncompleteExpr,
147+
);
148+
}

crates/hir_ty/src/tests/simple.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,18 @@ fn main() {
17491749
);
17501750
}
17511751

1752+
#[test]
1753+
fn const_eval_array_repeat_expr() {
1754+
check_types(
1755+
r#"
1756+
fn main() {
1757+
const X: usize = 6 - 1;
1758+
let t = [(); X + 2];
1759+
//^ [(); 7]
1760+
}"#,
1761+
);
1762+
}
1763+
17521764
#[test]
17531765
fn shadowing_primitive_with_inner_items() {
17541766
check_types(

0 commit comments

Comments
 (0)