mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-14 17:07:26 +00:00
organize const eval tests
This commit is contained in:
parent
0e2989e421
commit
22eaee25b8
5 changed files with 180 additions and 168 deletions
|
@ -55,10 +55,7 @@ use hir_def::{
|
|||
use hir_expand::{name::name, MacroCallKind};
|
||||
use hir_ty::{
|
||||
autoderef,
|
||||
consteval::{
|
||||
eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
|
||||
},
|
||||
could_unify,
|
||||
consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt},
|
||||
diagnostics::BodyValidationDiagnostic,
|
||||
method_resolution::{self, TyFingerprint},
|
||||
primitive::UintTy,
|
||||
|
|
|
@ -87,14 +87,14 @@ impl Display for ComputedExpr {
|
|||
match self {
|
||||
ComputedExpr::Literal(l) => match l {
|
||||
Literal::Int(x, _) => {
|
||||
if *x >= 16 {
|
||||
if *x >= 10 {
|
||||
write!(f, "{} ({:#X})", x, x)
|
||||
} else {
|
||||
x.fmt(f)
|
||||
}
|
||||
}
|
||||
Literal::Uint(x, _) => {
|
||||
if *x >= 16 {
|
||||
if *x >= 10 {
|
||||
write!(f, "{} ({:#X})", x, x)
|
||||
} else {
|
||||
x.fmt(f)
|
||||
|
@ -156,6 +156,7 @@ pub fn eval_const(
|
|||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let expr = &ctx.exprs[expr_id];
|
||||
match expr {
|
||||
Expr::Missing => Err(ConstEvalError::IncompleteExpr),
|
||||
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
||||
&Expr::UnaryOp { expr, op } => {
|
||||
let ty = &ctx.expr_ty(expr);
|
||||
|
@ -339,6 +340,9 @@ pub fn eval_const(
|
|||
Ok(r.clone())
|
||||
}
|
||||
ValueNs::ConstId(id) => ctx.db.const_eval(id),
|
||||
ValueNs::GenericParam(_) => {
|
||||
Err(ConstEvalError::NotSupported("const generic without substitution"))
|
||||
}
|
||||
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +437,7 @@ pub(crate) fn const_eval_query(
|
|||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let def = const_id.into();
|
||||
let body = db.body(def);
|
||||
let mut infer = db.infer_query(def);
|
||||
let infer = &db.infer(def);
|
||||
let result = eval_const(
|
||||
body.body_expr,
|
||||
&mut ConstEvalCtx {
|
||||
|
@ -442,7 +446,7 @@ pub(crate) fn const_eval_query(
|
|||
exprs: &body.exprs,
|
||||
pats: &body.pats,
|
||||
local_data: HashMap::default(),
|
||||
infer: &mut infer,
|
||||
infer,
|
||||
},
|
||||
);
|
||||
result
|
||||
|
@ -473,3 +477,6 @@ pub(crate) fn eval_to_const<'a>(
|
|||
};
|
||||
usize_const(eval_usize(expr, ctx))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
148
crates/hir_ty/src/consteval/tests.rs
Normal file
148
crates/hir_ty/src/consteval/tests.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use base_db::fixture::WithFixture;
|
||||
use hir_def::{db::DefDatabase, expr::Literal};
|
||||
|
||||
use crate::{consteval::ComputedExpr, db::HirDatabase, test_db::TestDB};
|
||||
|
||||
use super::ConstEvalError;
|
||||
|
||||
fn check_fail(ra_fixture: &str, error: ConstEvalError) {
|
||||
assert_eq!(eval_goal(ra_fixture), Err(error));
|
||||
}
|
||||
|
||||
fn check_number(ra_fixture: &str, answer: i128) {
|
||||
let r = eval_goal(ra_fixture).unwrap();
|
||||
match r {
|
||||
ComputedExpr::Literal(Literal::Int(r, _)) => assert_eq!(r, answer),
|
||||
ComputedExpr::Literal(Literal::Uint(r, _)) => assert_eq!(r, answer as u128),
|
||||
x => panic!("Expected number but found {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_goal(ra_fixture: &str) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let (db, file_id) = TestDB::with_single_file(ra_fixture);
|
||||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
let const_id = scope
|
||||
.declarations()
|
||||
.into_iter()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::ConstId(x) => {
|
||||
if db.const_data(x).name.as_ref()?.to_string() == "GOAL" {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
db.const_eval(const_id)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
check_number(r#"const GOAL: usize = 2 + 2;"#, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bit_op() {
|
||||
check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
|
||||
check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
|
||||
// FIXME: rustc evaluate this to -128
|
||||
check_fail(
|
||||
r#"const GOAL: i8 = 1 << 7"#,
|
||||
ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
|
||||
);
|
||||
check_fail(
|
||||
r#"const GOAL: i8 = 1 << 8"#,
|
||||
ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locals() {
|
||||
check_number(
|
||||
r#"
|
||||
const GOAL: usize = {
|
||||
let a = 3 + 2;
|
||||
let b = a * a;
|
||||
b
|
||||
};
|
||||
"#,
|
||||
25,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consts() {
|
||||
check_number(
|
||||
r#"
|
||||
const F1: i32 = 1;
|
||||
const F3: i32 = 3 * F2;
|
||||
const F2: i32 = 2 * F1;
|
||||
const GOAL: i32 = F3;
|
||||
"#,
|
||||
6,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_loop() {
|
||||
check_fail(
|
||||
r#"
|
||||
const F1: i32 = 1 * F3;
|
||||
const F3: i32 = 3 * F2;
|
||||
const F2: i32 = 2 * F1;
|
||||
const GOAL: i32 = F3;
|
||||
"#,
|
||||
ConstEvalError::Loop,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_impl_assoc() {
|
||||
check_number(
|
||||
r#"
|
||||
struct U5;
|
||||
impl U5 {
|
||||
const VAL: usize = 5;
|
||||
}
|
||||
const GOAL: usize = U5::VAL;
|
||||
"#,
|
||||
5,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_generic_subst() {
|
||||
// FIXME: this should evaluate to 5
|
||||
check_fail(
|
||||
r#"
|
||||
struct Adder<const N: usize, const M: usize>;
|
||||
impl<const N: usize, const M: usize> Adder<N, M> {
|
||||
const VAL: usize = N + M;
|
||||
}
|
||||
const GOAL: usize = Adder::<2, 3>::VAL;
|
||||
"#,
|
||||
ConstEvalError::NotSupported("const generic without substitution"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_trait_assoc() {
|
||||
// FIXME: this should evaluate to 0
|
||||
check_fail(
|
||||
r#"
|
||||
struct U0;
|
||||
trait ToConst {
|
||||
const VAL: usize;
|
||||
}
|
||||
impl ToConst for U0 {
|
||||
const VAL: usize = 0;
|
||||
}
|
||||
const GOAL: usize = U0::VAL;
|
||||
"#,
|
||||
ConstEvalError::IncompleteExpr,
|
||||
);
|
||||
}
|
|
@ -1749,6 +1749,18 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_eval_array_repeat_expr() {
|
||||
check_types(
|
||||
r#"
|
||||
fn main() {
|
||||
const X: usize = 6 - 1;
|
||||
let t = [(); X + 2];
|
||||
//^ [(); 7]
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_primitive_with_inner_items() {
|
||||
check_types(
|
||||
|
|
|
@ -3399,13 +3399,13 @@ impl<const LEN: usize> Foo<LEN$0> {}
|
|||
);
|
||||
}
|
||||
|
||||
// FIXME: move these tests to consteval module
|
||||
#[test]
|
||||
fn hover_const_eval() {
|
||||
// show hex for <10
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: usize = !0 & !(!0 >> 1);
|
||||
const FOO$0: usize = 1 << 3;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
@ -3415,7 +3415,7 @@ const FOO$0: usize = !0 & !(!0 >> 1);
|
|||
```
|
||||
|
||||
```rust
|
||||
const FOO: usize = 9223372036854775808 (0x8000000000000000)
|
||||
const FOO: usize = 8
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -3423,14 +3423,11 @@ const FOO$0: usize = !0 & !(!0 >> 1);
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// show hex for >10
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: usize = {
|
||||
let a = 3 + 2;
|
||||
let b = a * a;
|
||||
b
|
||||
};
|
||||
const FOO$0: usize = (1 << 3) + (1 << 2);
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
@ -3440,53 +3437,7 @@ const FOO$0: usize = {
|
|||
```
|
||||
|
||||
```rust
|
||||
const FOO: usize = 25 (0x19)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: usize = 1 << 10;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const FOO: usize = 1024 (0x400)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: usize = {
|
||||
let b = 4;
|
||||
let a = { let b = 2; let a = b; a } + { let a = 1; a + b };
|
||||
a
|
||||
};
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const FOO: usize = 7
|
||||
const FOO: usize = 12 (0xC)
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -3494,6 +3445,7 @@ const FOO$0: usize = {
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// show original body when const eval fails
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
|
@ -3515,6 +3467,7 @@ const FOO$0: usize = 2 - 3;
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
// don't show hex for negatives
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
|
@ -3539,27 +3492,6 @@ const FOO$0: i32 = 2 - 3;
|
|||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: usize = 1 << 100;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*FOO*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const FOO: usize = 1 << 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
/// This is a doc
|
||||
const FOO$0: &str = "bar";
|
||||
"#,
|
||||
expect![[r#"
|
||||
|
@ -3578,90 +3510,6 @@ const FOO$0: &str = "bar";
|
|||
This is a doc
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
const F1: i32 = 1;
|
||||
const F$03: i32 = 3 * F2;
|
||||
const F2: i32 = 2 * F1;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*F3*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const F3: i32 = 6
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
const F1: i32 = 1 * F3;
|
||||
const F2: i32 = 2 * F1;
|
||||
const F$03: i32 = 3 * F2;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*F3*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const F3: i32 = 3 * F2
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
struct U5;
|
||||
impl U5 {
|
||||
const VAL: usize = 5;
|
||||
}
|
||||
const X$0X: usize = U5::VAL;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*XX*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const XX: usize = 5
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: this should evaluate to zero
|
||||
#[test]
|
||||
fn hover_const_eval_broken() {
|
||||
check(
|
||||
r#"
|
||||
struct U0;
|
||||
trait ToConst {
|
||||
const VAL: usize;
|
||||
}
|
||||
impl ToConst for U0 {
|
||||
const VAL: usize = 0;
|
||||
}
|
||||
const X$0X: usize = U0::VAL;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*XX*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
const XX: usize = U0::VAL
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue