Skip to content

Commit 06228b9

Browse files
committed
Auto merge of rust-lang#17942 - HKalbasi:fp-const-eval, r=HKalbasi
Implement floating point casts in const eval fix rust-lang#17926
2 parents 614fb24 + aeb9c7b commit 06228b9

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs

+11
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,17 @@ fn casts() {
247247
check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
248248
}
249249

250+
#[test]
251+
fn floating_point_casts() {
252+
check_number(r#"const GOAL: usize = 12i32 as f32 as usize"#, 12);
253+
check_number(r#"const GOAL: i8 = -12i32 as f64 as i8"#, -12);
254+
check_number(r#"const GOAL: i32 = (-1ui8 as f32 + 2u64 as f32) as i32"#, 1);
255+
check_number(r#"const GOAL: i8 = (0./0.) as i8"#, 0);
256+
check_number(r#"const GOAL: i8 = (1./0.) as i8"#, 127);
257+
check_number(r#"const GOAL: i8 = (-1./0.) as i8"#, -128);
258+
check_number(r#"const GOAL: i64 = 1e18f64 as f32 as i64"#, 999999984306749440);
259+
}
260+
250261
#[test]
251262
fn raw_pointer_equality() {
252263
check_number(

src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs

+91-3
Original file line numberDiff line numberDiff line change
@@ -1518,9 +1518,97 @@ impl Evaluator<'_> {
15181518
self.size_of_sized(target_ty, locals, "destination of int to int cast")?;
15191519
Owned(current[0..dest_size].to_vec())
15201520
}
1521-
CastKind::FloatToInt => not_supported!("float to int cast"),
1522-
CastKind::FloatToFloat => not_supported!("float to float cast"),
1523-
CastKind::IntToFloat => not_supported!("float to int cast"),
1521+
CastKind::FloatToInt => {
1522+
let ty = self.operand_ty(operand, locals)?;
1523+
let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else {
1524+
not_supported!("invalid float to int cast");
1525+
};
1526+
let value = self.eval_operand(operand, locals)?.get(self)?;
1527+
let value = match ty {
1528+
chalk_ir::FloatTy::F32 => {
1529+
let value = value.try_into().unwrap();
1530+
f32::from_le_bytes(value) as f64
1531+
}
1532+
chalk_ir::FloatTy::F64 => {
1533+
let value = value.try_into().unwrap();
1534+
f64::from_le_bytes(value)
1535+
}
1536+
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
1537+
not_supported!("unstable floating point type f16 and f128");
1538+
}
1539+
};
1540+
let is_signed = matches!(
1541+
target_ty.kind(Interner),
1542+
TyKind::Scalar(chalk_ir::Scalar::Int(_))
1543+
);
1544+
let dest_size =
1545+
self.size_of_sized(target_ty, locals, "destination of float to int cast")?;
1546+
let dest_bits = dest_size * 8;
1547+
let (max, min) = if dest_bits == 128 {
1548+
(i128::MAX, i128::MIN)
1549+
} else if is_signed {
1550+
let max = 1i128 << (dest_bits - 1);
1551+
(max - 1, -max)
1552+
} else {
1553+
(1i128 << dest_bits, 0)
1554+
};
1555+
let value = (value as i128).min(max).max(min);
1556+
let result = value.to_le_bytes();
1557+
Owned(result[0..dest_size].to_vec())
1558+
}
1559+
CastKind::FloatToFloat => {
1560+
let ty = self.operand_ty(operand, locals)?;
1561+
let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else {
1562+
not_supported!("invalid float to int cast");
1563+
};
1564+
let value = self.eval_operand(operand, locals)?.get(self)?;
1565+
let value = match ty {
1566+
chalk_ir::FloatTy::F32 => {
1567+
let value = value.try_into().unwrap();
1568+
f32::from_le_bytes(value) as f64
1569+
}
1570+
chalk_ir::FloatTy::F64 => {
1571+
let value = value.try_into().unwrap();
1572+
f64::from_le_bytes(value)
1573+
}
1574+
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
1575+
not_supported!("unstable floating point type f16 and f128");
1576+
}
1577+
};
1578+
let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) =
1579+
target_ty.kind(Interner)
1580+
else {
1581+
not_supported!("invalid float to float cast");
1582+
};
1583+
match target_ty {
1584+
chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
1585+
chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
1586+
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
1587+
not_supported!("unstable floating point type f16 and f128");
1588+
}
1589+
}
1590+
}
1591+
CastKind::IntToFloat => {
1592+
let current_ty = self.operand_ty(operand, locals)?;
1593+
let is_signed = matches!(
1594+
current_ty.kind(Interner),
1595+
TyKind::Scalar(chalk_ir::Scalar::Int(_))
1596+
);
1597+
let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);
1598+
let value = i128::from_le_bytes(value);
1599+
let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) =
1600+
target_ty.kind(Interner)
1601+
else {
1602+
not_supported!("invalid int to float cast");
1603+
};
1604+
match target_ty {
1605+
chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
1606+
chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
1607+
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
1608+
not_supported!("unstable floating point type f16 and f128");
1609+
}
1610+
}
1611+
}
15241612
CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
15251613
},
15261614
})

0 commit comments

Comments
 (0)