Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/chalk_ext.rs5
-rw-r--r--crates/hir-ty/src/consteval/tests.rs15
-rw-r--r--crates/hir-ty/src/mir/eval.rs25
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs16
-rw-r--r--crates/hir-ty/src/mir/eval/tests.rs33
-rw-r--r--crates/hir-ty/src/mir/lower.rs2
6 files changed, 84 insertions, 12 deletions
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 3fb3de5ba8..a8071591ad 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -22,6 +22,7 @@ use crate::{
pub trait TyExt {
fn is_unit(&self) -> bool;
fn is_integral(&self) -> bool;
+ fn is_scalar(&self) -> bool;
fn is_floating_point(&self) -> bool;
fn is_never(&self) -> bool;
fn is_unknown(&self) -> bool;
@@ -68,6 +69,10 @@ impl TyExt for Ty {
)
}
+ fn is_scalar(&self) -> bool {
+ matches!(self.kind(Interner), TyKind::Scalar(_))
+ }
+
fn is_floating_point(&self) -> bool {
matches!(
self.kind(Interner),
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 6a7d045648..06fff08b7d 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -179,6 +179,7 @@ fn casts() {
"#,
4,
);
+ check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
}
#[test]
@@ -1034,16 +1035,18 @@ fn pattern_matching_literal() {
);
check_number(
r#"
- const fn f(x: &str) -> u8 {
+ const fn f(x: &str) -> i32 {
match x {
- "foo" => 1,
- "bar" => 10,
- _ => 100,
+ "f" => 1,
+ "foo" => 10,
+ "" => 100,
+ "bar" => 1000,
+ _ => 10000,
}
}
- const GOAL: u8 = f("foo") + f("bar");
+ const GOAL: i32 = f("f") + f("foo") * 2 + f("") * 3 + f("bar") * 4;
"#,
- 11,
+ 4321,
);
}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 6d7701c9e8..6778808d52 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -17,6 +17,7 @@ use hir_expand::InFile;
use intern::Interned;
use la_arena::ArenaMap;
use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::never;
use syntax::{SyntaxNodePtr, TextRange};
use triomphe::Arc;
@@ -896,7 +897,7 @@ impl Evaluator<'_> {
Owned(c)
}
}
- Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
+ Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: {
let lc = self.eval_operand(lhs, locals)?;
let rc = self.eval_operand(rhs, locals)?;
let mut lc = lc.get(&self)?;
@@ -905,10 +906,17 @@ impl Evaluator<'_> {
while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
ty = z.clone();
let size = if ty.kind(Interner) == &TyKind::Str {
- let ns = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);
+ if *op != BinOp::Eq {
+ never!("Only eq is builtin for `str`");
+ }
+ let ls = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);
+ let rs = from_bytes!(usize, &rc[self.ptr_size()..self.ptr_size() * 2]);
+ if ls != rs {
+ break 'binary_op Owned(vec![0]);
+ }
lc = &lc[..self.ptr_size()];
rc = &rc[..self.ptr_size()];
- ns
+ ls
} else {
self.size_of_sized(&ty, locals, "operand of binary op")?
};
@@ -1200,8 +1208,15 @@ impl Evaluator<'_> {
CastKind::IntToInt
| CastKind::PointerExposeAddress
| CastKind::PointerFromExposedAddress => {
- // FIXME: handle signed cast
- let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, false);
+ let current_ty = self.operand_ty(operand, locals)?;
+ let is_signed = match current_ty.kind(Interner) {
+ TyKind::Scalar(s) => match s {
+ chalk_ir::Scalar::Int(_) => true,
+ _ => false,
+ },
+ _ => false,
+ };
+ let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, is_signed);
let dest_size =
self.size_of_sized(target_ty, locals, "destination of int to int cast")?;
Owned(current[0..dest_size].to_vec())
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 77ee7b6b6e..3b9ef03c36 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -238,6 +238,22 @@ impl Evaluator<'_> {
_span: MirSpan,
) -> Result<()> {
match as_str {
+ "memcmp" => {
+ let [ptr1, ptr2, size] = args else {
+ return Err(MirEvalError::TypeError("memcmp args are not provided"));
+ };
+ let addr1 = Address::from_bytes(ptr1.get(self)?)?;
+ let addr2 = Address::from_bytes(ptr2.get(self)?)?;
+ let size = from_bytes!(usize, size.get(self)?);
+ let slice1 = self.read_memory(addr1, size)?;
+ let slice2 = self.read_memory(addr2, size)?;
+ let r: i128 = match slice1.cmp(slice2) {
+ cmp::Ordering::Less => -1,
+ cmp::Ordering::Equal => 0,
+ cmp::Ordering::Greater => 1,
+ };
+ destination.write_from_bytes(self, &r.to_le_bytes()[..destination.size])
+ }
"write" => {
let [fd, ptr, len] = args else {
return Err(MirEvalError::TypeError("libc::write args are not provided"));
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 453c93de8e..8c097539eb 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -229,6 +229,39 @@ fn main() {
}
#[test]
+fn memcmp() {
+ check_pass(
+ r#"
+//- minicore: slice, coerce_unsized, index
+
+fn should_not_reach() -> bool {
+ _ // FIXME: replace this function with panic when that works
+}
+
+extern "C" {
+ fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
+}
+
+fn my_cmp(x: &[u8], y: &[u8]) -> i32 {
+ memcmp(x as *const u8, y as *const u8, x.len())
+}
+
+fn main() {
+ if my_cmp(&[1, 2, 3], &[1, 2, 3]) != 0 {
+ should_not_reach();
+ }
+ if my_cmp(&[1, 20, 3], &[1, 2, 3]) <= 0 {
+ should_not_reach();
+ }
+ if my_cmp(&[1, 2, 3], &[1, 20, 3]) >= 0 {
+ should_not_reach();
+ }
+}
+ "#,
+ );
+}
+
+#[test]
fn unix_write_stdout() {
check_pass_and_stdio(
r#"
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 5ed9513335..ebd4199835 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -829,7 +829,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
op,
BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) }
);
- lhs_ty.as_builtin().is_some() && rhs_ty.as_builtin().is_some() && (lhs_ty == rhs_ty || builtin_inequal_impls)
+ lhs_ty.is_scalar() && rhs_ty.is_scalar() && (lhs_ty == rhs_ty || builtin_inequal_impls)
};
if !is_builtin {
if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {