]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/consteval.rs
Add more tests, refactor array lengths/consteval work
[rust.git] / crates / hir_ty / src / consteval.rs
1 //! Constant evaluation details
2
3 use std::convert::TryInto;
4
5 use hir_def::{
6     builtin_type::BuiltinUint,
7     expr::{Expr, Literal},
8     type_ref::ConstScalar,
9 };
10
11 use crate::{Const, ConstData, ConstValue, Interner, TyKind};
12
13 /// Extension trait for [`Const`]
14 pub trait ConstExtension {
15     /// Is a [`Const`] unknown?
16     fn is_unknown(&self) -> bool;
17 }
18
19 impl ConstExtension for Const {
20     fn is_unknown(&self) -> bool {
21         match self.data(&Interner).value {
22             // interned Unknown
23             chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
24                 interned: ConstScalar::Unknown,
25             }) => true,
26
27             // interned concrete anything else
28             chalk_ir::ConstValue::Concrete(..) => false,
29
30             _ => {
31                 log::error!("is_unknown was called on a non-concrete constant value! {:?}", self);
32                 true
33             }
34         }
35     }
36 }
37
38 /// Extension trait for [`Expr`]
39 pub trait ExprEval {
40     /// Attempts to evaluate the expression as a target usize.
41     fn eval_usize(&self) -> Option<u64>;
42 }
43
44 impl ExprEval for Expr {
45     // FIXME: support more than just evaluating literals
46     fn eval_usize(&self) -> Option<u64> {
47         match self {
48             Expr::Literal(Literal::Uint(v, None))
49             | Expr::Literal(Literal::Uint(v, Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
50             _ => None,
51         }
52     }
53 }
54
55 /// Interns a possibly-unknown target usize
56 pub fn usize_const(value: Option<u64>) -> Const {
57     ConstData {
58         ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(&Interner),
59         value: ConstValue::Concrete(chalk_ir::ConcreteConst {
60             interned: value.map(|value| ConstScalar::Usize(value)).unwrap_or(ConstScalar::Unknown),
61         }),
62     }
63     .intern(&Interner)
64 }