]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / src / tools / rust-analyzer / crates / hir-ty / src / consteval / tests.rs
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         .find_map(|x| match x {
29             hir_def::ModuleDefId::ConstId(x) => {
30                 if db.const_data(x).name.as_ref()?.to_string() == "GOAL" {
31                     Some(x)
32                 } else {
33                     None
34                 }
35             }
36             _ => None,
37         })
38         .unwrap();
39     db.const_eval(const_id)
40 }
41
42 #[test]
43 fn add() {
44     check_number(r#"const GOAL: usize = 2 + 2;"#, 4);
45 }
46
47 #[test]
48 fn bit_op() {
49     check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
50     check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
51     // FIXME: rustc evaluate this to -128
52     check_fail(
53         r#"const GOAL: i8 = 1 << 7"#,
54         ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
55     );
56     check_fail(
57         r#"const GOAL: i8 = 1 << 8"#,
58         ConstEvalError::Panic("attempt to run invalid arithmetic operation".to_string()),
59     );
60 }
61
62 #[test]
63 fn locals() {
64     check_number(
65         r#"
66     const GOAL: usize = {
67         let a = 3 + 2;
68         let b = a * a;
69         b
70     };
71     "#,
72         25,
73     );
74 }
75
76 #[test]
77 fn consts() {
78     check_number(
79         r#"
80     const F1: i32 = 1;
81     const F3: i32 = 3 * F2;
82     const F2: i32 = 2 * F1;
83     const GOAL: i32 = F3;
84     "#,
85         6,
86     );
87 }
88
89 #[test]
90 fn enums() {
91     check_number(
92         r#"
93     enum E {
94         F1 = 1,
95         F2 = 2 * E::F1 as u8,
96         F3 = 3 * E::F2 as u8,
97     }
98     const GOAL: i32 = E::F3 as u8;
99     "#,
100         6,
101     );
102     check_number(
103         r#"
104     enum E { F1 = 1, F2, }
105     const GOAL: i32 = E::F2 as u8;
106     "#,
107         2,
108     );
109     check_number(
110         r#"
111     enum E { F1, }
112     const GOAL: i32 = E::F1 as u8;
113     "#,
114         0,
115     );
116     let r = eval_goal(
117         r#"
118         enum E { A = 1, }
119         const GOAL: E = E::A;
120         "#,
121     )
122     .unwrap();
123     match r {
124         ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => {
125             assert_eq!(name, "E::A");
126             assert_eq!(val, 1);
127         }
128         x => panic!("Expected enum but found {x:?}"),
129     }
130 }
131
132 #[test]
133 fn const_loop() {
134     check_fail(
135         r#"
136     const F1: i32 = 1 * F3;
137     const F3: i32 = 3 * F2;
138     const F2: i32 = 2 * F1;
139     const GOAL: i32 = F3;
140     "#,
141         ConstEvalError::Loop,
142     );
143 }
144
145 #[test]
146 fn const_impl_assoc() {
147     check_number(
148         r#"
149     struct U5;
150     impl U5 {
151         const VAL: usize = 5;
152     }
153     const GOAL: usize = U5::VAL;
154     "#,
155         5,
156     );
157 }
158
159 #[test]
160 fn const_generic_subst() {
161     // FIXME: this should evaluate to 5
162     check_fail(
163         r#"
164     struct Adder<const N: usize, const M: usize>;
165     impl<const N: usize, const M: usize> Adder<N, M> {
166         const VAL: usize = N + M;
167     }
168     const GOAL: usize = Adder::<2, 3>::VAL;
169     "#,
170         ConstEvalError::NotSupported("const generic without substitution"),
171     );
172 }
173
174 #[test]
175 fn const_trait_assoc() {
176     // FIXME: this should evaluate to 0
177     check_fail(
178         r#"
179     struct U0;
180     trait ToConst {
181         const VAL: usize;
182     }
183     impl ToConst for U0 {
184         const VAL: usize = 0;
185     }
186     const GOAL: usize = U0::VAL;
187     "#,
188         ConstEvalError::IncompleteExpr,
189     );
190 }