Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/consteval.rs')
-rw-r--r--crates/hir-ty/src/consteval.rs30
1 files changed, 27 insertions, 3 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 8b6cde975f..968a828e9d 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -11,7 +11,7 @@ use hir_def::{
ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
};
use hir_expand::Lookup;
-use stdx::never;
+use stdx::{never, IsNoneOr};
use triomphe::Arc;
use crate::{
@@ -184,6 +184,22 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
}
}
+pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option<i128> {
+ match &c.data(Interner).value {
+ chalk_ir::ConstValue::BoundVar(_) => None,
+ chalk_ir::ConstValue::InferenceVar(_) => None,
+ chalk_ir::ConstValue::Placeholder(_) => None,
+ chalk_ir::ConstValue::Concrete(c) => match &c.interned {
+ ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))),
+ ConstScalar::UnevaluatedConst(c, subst) => {
+ let ec = db.const_eval(*c, subst.clone(), None).ok()?;
+ try_const_isize(db, &ec)
+ }
+ _ => None,
+ },
+ }
+}
+
pub(crate) fn const_eval_recover(
_: &dyn HirDatabase,
_: &Cycle,
@@ -256,8 +272,8 @@ pub(crate) fn const_eval_discriminant_variant(
) -> Result<i128, ConstEvalError> {
let def = variant_id.into();
let body = db.body(def);
+ let loc = variant_id.lookup(db.upcast());
if body.exprs[body.body_expr] == Expr::Missing {
- let loc = variant_id.lookup(db.upcast());
let prev_idx = loc.index.checked_sub(1);
let value = match prev_idx {
Some(prev_idx) => {
@@ -269,13 +285,21 @@ pub(crate) fn const_eval_discriminant_variant(
};
return Ok(value);
}
+
+ let repr = db.enum_data(loc.parent).repr;
+ let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed());
+
let mir_body = db.monomorphized_mir_body(
def,
Substitution::empty(Interner),
db.trait_environment_for_body(def),
)?;
let c = interpret_mir(db, mir_body, false, None).0?;
- let c = try_const_usize(db, &c).unwrap() as i128;
+ let c = if is_signed {
+ try_const_isize(db, &c).unwrap()
+ } else {
+ try_const_usize(db, &c).unwrap() as i128
+ };
Ok(c)
}