aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/consteval.rs
blob: a4a430f30fef0935e93f48ea694cf85bdda3eacd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Constant evaluation details

use std::convert::TryInto;

use hir_def::{
    builtin_type::BuiltinUint,
    expr::{Expr, Literal},
    type_ref::ConstScalar,
};

use crate::{Const, ConstData, ConstValue, Interner, TyKind};

/// Extension trait for [`Const`]
pub trait ConstExtension {
    /// Is a [`Const`] unknown?
    fn is_unknown(&self) -> bool;
}

impl ConstExtension for Const {
    fn is_unknown(&self) -> bool {
        match self.data(&Interner).value {
            // interned Unknown
            chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
                interned: ConstScalar::Unknown,
            }) => true,

            // interned concrete anything else
            chalk_ir::ConstValue::Concrete(..) => false,

            _ => {
                log::error!("is_unknown was called on a non-concrete constant value! {:?}", self);
                true
            }
        }
    }
}

/// Extension trait for [`Expr`]
pub trait ExprEval {
    /// Attempts to evaluate the expression as a target usize.
    fn eval_usize(&self) -> Option<u64>;
}

impl ExprEval for Expr {
    // FIXME: support more than just evaluating literals
    fn eval_usize(&self) -> Option<u64> {
        match self {
            Expr::Literal(Literal::Uint(v, None))
            | Expr::Literal(Literal::Uint(v, Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
            _ => None,
        }
    }
}

/// Interns a possibly-unknown target usize
pub fn usize_const(value: Option<u64>) -> Const {
    ConstData {
        ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(&Interner),
        value: ConstValue::Concrete(chalk_ir::ConcreteConst {
            interned: value.map(|value| ConstScalar::Usize(value)).unwrap_or(ConstScalar::Unknown),
        }),
    }
    .intern(&Interner)
}