Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14705 - HKalbasi:mir, r=lnicola
Fix some mir related bugs fix #14701 fix #14704
bors 2023-05-02
parent 466b4ec · parent 38544f5 · commit 86b14c2
-rw-r--r--crates/hir-def/src/body/lower.rs3
-rw-r--r--crates/hir-ty/src/consteval/tests.rs18
-rw-r--r--crates/hir-ty/src/mir.rs14
-rw-r--r--crates/hir-ty/src/mir/eval.rs171
-rw-r--r--crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs18
5 files changed, 164 insertions, 60 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index d31340fe8f..611031eb8c 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -505,6 +505,7 @@ impl ExprCollector<'_> {
.map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
let prev_is_lowering_generator = mem::take(&mut this.is_lowering_generator);
+ let prev_try_block_label = this.current_try_block_label.take();
let body = this.collect_expr_opt(e.body());
@@ -520,11 +521,11 @@ impl ExprCollector<'_> {
} else {
ClosureKind::Closure
};
- this.is_lowering_generator = prev_is_lowering_generator;
let capture_by =
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
this.is_lowering_generator = prev_is_lowering_generator;
this.current_binding_owner = prev_binding_owner;
+ this.current_try_block_label = prev_try_block_label;
this.body.exprs[result_expr_id] = Expr::Closure {
args: args.into(),
arg_types: arg_types.into(),
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index e95e175536..5a850f6d57 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -97,8 +97,22 @@ fn bit_op() {
check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128);
- // FIXME: report panic here
- check_number(r#"const GOAL: i8 = 1 << 8"#, 0);
+ check_number(r#"const GOAL: i8 = -1 << 2"#, (-1i8 << 2) as i128);
+ check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| {
+ e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string()))
+ });
+}
+
+#[test]
+fn floating_point() {
+ check_number(
+ r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#,
+ i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)),
+ );
+ check_number(
+ r#"const GOAL: f32 = 2.0 + 3.0 * 5.5 - 8.;"#,
+ i128::from_le_bytes(pad16(&f32::to_le_bytes(10.5), true)),
+ );
}
#[test]
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index 4846bbfe5f..3ac208666a 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -649,6 +649,20 @@ pub enum BinOp {
Offset,
}
+impl BinOp {
+ fn run_compare<T: PartialEq + PartialOrd>(&self, l: T, r: T) -> bool {
+ match self {
+ BinOp::Ge => l >= r,
+ BinOp::Gt => l > r,
+ BinOp::Le => l <= r,
+ BinOp::Lt => l < r,
+ BinOp::Eq => l == r,
+ BinOp::Ne => l != r,
+ x => panic!("`run_compare` called on operator {x:?}"),
+ }
+ }
+}
+
impl Display for BinOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 01d27f2672..7ff68774bc 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -48,7 +48,7 @@ macro_rules! from_bytes {
($ty:tt, $value:expr) => {
($ty::from_le_bytes(match ($value).try_into() {
Ok(x) => x,
- Err(_) => return Err(MirEvalError::TypeError("mismatched size")),
+ Err(_) => return Err(MirEvalError::TypeError(stringify!(mismatched size in constructing $ty))),
}))
};
}
@@ -797,70 +797,127 @@ impl Evaluator<'_> {
lc = self.read_memory(Address::from_bytes(lc)?, size)?;
rc = self.read_memory(Address::from_bytes(rc)?, size)?;
}
- let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));
- let l128 = i128::from_le_bytes(pad16(lc, is_signed));
- let r128 = i128::from_le_bytes(pad16(rc, is_signed));
- match op {
- BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {
- let r = match op {
- BinOp::Ge => l128 >= r128,
- BinOp::Gt => l128 > r128,
- BinOp::Le => l128 <= r128,
- BinOp::Lt => l128 < r128,
- BinOp::Eq => l128 == r128,
- BinOp::Ne => l128 != r128,
- _ => unreachable!(),
- };
- let r = r as u8;
- Owned(vec![r])
+ if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) {
+ match f {
+ chalk_ir::FloatTy::F32 => {
+ let l = from_bytes!(f32, lc);
+ let r = from_bytes!(f32, rc);
+ match op {
+ BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Eq
+ | BinOp::Ne => {
+ let r = op.run_compare(l, r) as u8;
+ Owned(vec![r])
+ }
+ BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
+ let r = match op {
+ BinOp::Add => l + r,
+ BinOp::Sub => l - r,
+ BinOp::Mul => l * r,
+ BinOp::Div => l / r,
+ _ => unreachable!(),
+ };
+ Owned(r.to_le_bytes().into())
+ }
+ x => not_supported!(
+ "invalid binop {x:?} on floating point operators"
+ ),
+ }
+ }
+ chalk_ir::FloatTy::F64 => {
+ let l = from_bytes!(f64, lc);
+ let r = from_bytes!(f64, rc);
+ match op {
+ BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Eq
+ | BinOp::Ne => {
+ let r = op.run_compare(l, r) as u8;
+ Owned(vec![r])
+ }
+ BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
+ let r = match op {
+ BinOp::Add => l + r,
+ BinOp::Sub => l - r,
+ BinOp::Mul => l * r,
+ BinOp::Div => l / r,
+ _ => unreachable!(),
+ };
+ Owned(r.to_le_bytes().into())
+ }
+ x => not_supported!(
+ "invalid binop {x:?} on floating point operators"
+ ),
+ }
+ }
}
- BinOp::BitAnd
- | BinOp::BitOr
- | BinOp::BitXor
- | BinOp::Add
- | BinOp::Mul
- | BinOp::Div
- | BinOp::Rem
- | BinOp::Sub => {
- let r = match op {
- BinOp::Add => l128.overflowing_add(r128).0,
- BinOp::Mul => l128.overflowing_mul(r128).0,
- BinOp::Div => l128.checked_div(r128).ok_or_else(|| {
- MirEvalError::Panic(format!("Overflow in {op:?}"))
- })?,
- BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {
- MirEvalError::Panic(format!("Overflow in {op:?}"))
- })?,
- BinOp::Sub => l128.overflowing_sub(r128).0,
- BinOp::BitAnd => l128 & r128,
- BinOp::BitOr => l128 | r128,
- BinOp::BitXor => l128 ^ r128,
- _ => unreachable!(),
- };
+ } else {
+ let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));
+ let l128 = i128::from_le_bytes(pad16(lc, is_signed));
+ let r128 = i128::from_le_bytes(pad16(rc, is_signed));
+ let check_overflow = |r: i128| {
+ // FIXME: this is not very correct, and only catches the basic cases.
let r = r.to_le_bytes();
for &k in &r[lc.len()..] {
if k != 0 && (k != 255 || !is_signed) {
return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
}
}
- Owned(r[0..lc.len()].into())
- }
- BinOp::Shl | BinOp::Shr => {
- let shift_amount = if r128 < 0 {
- return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
- } else if r128 > 128 {
- return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
- } else {
- r128 as u8
- };
- let r = match op {
- BinOp::Shl => l128 << shift_amount,
- BinOp::Shr => l128 >> shift_amount,
- _ => unreachable!(),
- };
- Owned(r.to_le_bytes()[0..lc.len()].into())
+ Ok(Owned(r[0..lc.len()].into()))
+ };
+ match op {
+ BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {
+ let r = op.run_compare(l128, r128) as u8;
+ Owned(vec![r])
+ }
+ BinOp::BitAnd
+ | BinOp::BitOr
+ | BinOp::BitXor
+ | BinOp::Add
+ | BinOp::Mul
+ | BinOp::Div
+ | BinOp::Rem
+ | BinOp::Sub => {
+ let r = match op {
+ BinOp::Add => l128.overflowing_add(r128).0,
+ BinOp::Mul => l128.overflowing_mul(r128).0,
+ BinOp::Div => l128.checked_div(r128).ok_or_else(|| {
+ MirEvalError::Panic(format!("Overflow in {op:?}"))
+ })?,
+ BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {
+ MirEvalError::Panic(format!("Overflow in {op:?}"))
+ })?,
+ BinOp::Sub => l128.overflowing_sub(r128).0,
+ BinOp::BitAnd => l128 & r128,
+ BinOp::BitOr => l128 | r128,
+ BinOp::BitXor => l128 ^ r128,
+ _ => unreachable!(),
+ };
+ check_overflow(r)?
+ }
+ BinOp::Shl | BinOp::Shr => {
+ let r = 'b: {
+ if let Ok(shift_amount) = u32::try_from(r128) {
+ let r = match op {
+ BinOp::Shl => l128.checked_shl(shift_amount),
+ BinOp::Shr => l128.checked_shr(shift_amount),
+ _ => unreachable!(),
+ };
+ if let Some(r) = r {
+ break 'b r;
+ }
+ };
+ return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
+ };
+ check_overflow(r)?
+ }
+ BinOp::Offset => not_supported!("offset binop"),
}
- BinOp::Offset => not_supported!("offset binop"),
}
}
Rvalue::Discriminant(p) => {
diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index 89aa437d75..7baa7b6426 100644
--- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -135,4 +135,22 @@ fn test() {
"#,
);
}
+
+ #[test]
+ fn try_block_desugaring_inside_closure() {
+ // regression test for #14701
+ check_diagnostics(
+ r#"
+//- minicore: option, try
+fn test() {
+ try {
+ || {
+ let x = Some(2);
+ Some(x?)
+ };
+ };
+}
+"#,
+ );
+ }
}