Auto merge of #14951 - HKalbasi:mir-fix, r=HKalbasi
Fix string pattern matching in mir interpreter
This commit is contained in:
commit
7f3bfc6ae7
@ -22,6 +22,7 @@
|
|||||||
pub trait TyExt {
|
pub trait TyExt {
|
||||||
fn is_unit(&self) -> bool;
|
fn is_unit(&self) -> bool;
|
||||||
fn is_integral(&self) -> bool;
|
fn is_integral(&self) -> bool;
|
||||||
|
fn is_scalar(&self) -> bool;
|
||||||
fn is_floating_point(&self) -> bool;
|
fn is_floating_point(&self) -> bool;
|
||||||
fn is_never(&self) -> bool;
|
fn is_never(&self) -> bool;
|
||||||
fn is_unknown(&self) -> bool;
|
fn is_unknown(&self) -> bool;
|
||||||
@ -68,6 +69,10 @@ fn is_integral(&self) -> bool {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_scalar(&self) -> bool {
|
||||||
|
matches!(self.kind(Interner), TyKind::Scalar(_))
|
||||||
|
}
|
||||||
|
|
||||||
fn is_floating_point(&self) -> bool {
|
fn is_floating_point(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.kind(Interner),
|
self.kind(Interner),
|
||||||
|
@ -179,6 +179,7 @@ fn casts() {
|
|||||||
"#,
|
"#,
|
||||||
4,
|
4,
|
||||||
);
|
);
|
||||||
|
check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1034,16 +1035,18 @@ const fn f(x: i32) -> i32 {
|
|||||||
);
|
);
|
||||||
check_number(
|
check_number(
|
||||||
r#"
|
r#"
|
||||||
const fn f(x: &str) -> u8 {
|
const fn f(x: &str) -> i32 {
|
||||||
match x {
|
match x {
|
||||||
"foo" => 1,
|
"f" => 1,
|
||||||
"bar" => 10,
|
"foo" => 10,
|
||||||
_ => 100,
|
"" => 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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
use la_arena::ArenaMap;
|
use la_arena::ArenaMap;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
use stdx::never;
|
||||||
use syntax::{SyntaxNodePtr, TextRange};
|
use syntax::{SyntaxNodePtr, TextRange};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
@ -896,7 +897,7 @@ fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result<Interva
|
|||||||
Owned(c)
|
Owned(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
|
Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: {
|
||||||
let lc = self.eval_operand(lhs, locals)?;
|
let lc = self.eval_operand(lhs, locals)?;
|
||||||
let rc = self.eval_operand(rhs, locals)?;
|
let rc = self.eval_operand(rhs, locals)?;
|
||||||
let mut lc = lc.get(&self)?;
|
let mut lc = lc.get(&self)?;
|
||||||
@ -905,10 +906,17 @@ fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result<Interva
|
|||||||
while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
|
while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
|
||||||
ty = z.clone();
|
ty = z.clone();
|
||||||
let size = if ty.kind(Interner) == &TyKind::Str {
|
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()];
|
lc = &lc[..self.ptr_size()];
|
||||||
rc = &rc[..self.ptr_size()];
|
rc = &rc[..self.ptr_size()];
|
||||||
ns
|
ls
|
||||||
} else {
|
} else {
|
||||||
self.size_of_sized(&ty, locals, "operand of binary op")?
|
self.size_of_sized(&ty, locals, "operand of binary op")?
|
||||||
};
|
};
|
||||||
@ -1200,8 +1208,15 @@ fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result<Interva
|
|||||||
CastKind::IntToInt
|
CastKind::IntToInt
|
||||||
| CastKind::PointerExposeAddress
|
| CastKind::PointerExposeAddress
|
||||||
| CastKind::PointerFromExposedAddress => {
|
| CastKind::PointerFromExposedAddress => {
|
||||||
// FIXME: handle signed cast
|
let current_ty = self.operand_ty(operand, locals)?;
|
||||||
let current = pad16(self.eval_operand(operand, locals)?.get(&self)?, false);
|
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 =
|
let dest_size =
|
||||||
self.size_of_sized(target_ty, locals, "destination of int to int cast")?;
|
self.size_of_sized(target_ty, locals, "destination of int to int cast")?;
|
||||||
Owned(current[0..dest_size].to_vec())
|
Owned(current[0..dest_size].to_vec())
|
||||||
|
@ -238,6 +238,22 @@ fn exec_extern_c(
|
|||||||
_span: MirSpan,
|
_span: MirSpan,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match as_str {
|
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" => {
|
"write" => {
|
||||||
let [fd, ptr, len] = args else {
|
let [fd, ptr, len] = args else {
|
||||||
return Err(MirEvalError::TypeError("libc::write args are not provided"));
|
return Err(MirEvalError::TypeError("libc::write args are not provided"));
|
||||||
|
@ -228,6 +228,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]
|
#[test]
|
||||||
fn unix_write_stdout() {
|
fn unix_write_stdout() {
|
||||||
check_pass_and_stdio(
|
check_pass_and_stdio(
|
||||||
|
@ -829,7 +829,7 @@ fn lower_expr_to_place_without_adjust(
|
|||||||
op,
|
op,
|
||||||
BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) }
|
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 !is_builtin {
|
||||||
if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
|
if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
|
||||||
|
Loading…
Reference in New Issue
Block a user