Skip to content

Commit 86b14c2

Browse files
committed
Auto merge of #14705 - HKalbasi:mir, r=lnicola
Fix some mir related bugs fix #14701 fix #14704
2 parents 466b4ec + 38544f5 commit 86b14c2

File tree

5 files changed

+164
-60
lines changed

5 files changed

+164
-60
lines changed

crates/hir-def/src/body/lower.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ impl ExprCollector<'_> {
505505
.map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
506506

507507
let prev_is_lowering_generator = mem::take(&mut this.is_lowering_generator);
508+
let prev_try_block_label = this.current_try_block_label.take();
508509

509510
let body = this.collect_expr_opt(e.body());
510511

@@ -520,11 +521,11 @@ impl ExprCollector<'_> {
520521
} else {
521522
ClosureKind::Closure
522523
};
523-
this.is_lowering_generator = prev_is_lowering_generator;
524524
let capture_by =
525525
if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
526526
this.is_lowering_generator = prev_is_lowering_generator;
527527
this.current_binding_owner = prev_binding_owner;
528+
this.current_try_block_label = prev_try_block_label;
528529
this.body.exprs[result_expr_id] = Expr::Closure {
529530
args: args.into(),
530531
arg_types: arg_types.into(),

crates/hir-ty/src/consteval/tests.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,22 @@ fn bit_op() {
9797
check_number(r#"const GOAL: u8 = !0 & !(!0 >> 1)"#, 128);
9898
check_number(r#"const GOAL: i8 = !0 & !(!0 >> 1)"#, 0);
9999
check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128);
100-
// FIXME: report panic here
101-
check_number(r#"const GOAL: i8 = 1 << 8"#, 0);
100+
check_number(r#"const GOAL: i8 = -1 << 2"#, (-1i8 << 2) as i128);
101+
check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| {
102+
e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string()))
103+
});
104+
}
105+
106+
#[test]
107+
fn floating_point() {
108+
check_number(
109+
r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#,
110+
i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)),
111+
);
112+
check_number(
113+
r#"const GOAL: f32 = 2.0 + 3.0 * 5.5 - 8.;"#,
114+
i128::from_le_bytes(pad16(&f32::to_le_bytes(10.5), true)),
115+
);
102116
}
103117

104118
#[test]

crates/hir-ty/src/mir.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,20 @@ pub enum BinOp {
649649
Offset,
650650
}
651651

652+
impl BinOp {
653+
fn run_compare<T: PartialEq + PartialOrd>(&self, l: T, r: T) -> bool {
654+
match self {
655+
BinOp::Ge => l >= r,
656+
BinOp::Gt => l > r,
657+
BinOp::Le => l <= r,
658+
BinOp::Lt => l < r,
659+
BinOp::Eq => l == r,
660+
BinOp::Ne => l != r,
661+
x => panic!("`run_compare` called on operator {x:?}"),
662+
}
663+
}
664+
}
665+
652666
impl Display for BinOp {
653667
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
654668
f.write_str(match self {

crates/hir-ty/src/mir/eval.rs

Lines changed: 114 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ macro_rules! from_bytes {
4848
($ty:tt, $value:expr) => {
4949
($ty::from_le_bytes(match ($value).try_into() {
5050
Ok(x) => x,
51-
Err(_) => return Err(MirEvalError::TypeError("mismatched size")),
51+
Err(_) => return Err(MirEvalError::TypeError(stringify!(mismatched size in constructing $ty))),
5252
}))
5353
};
5454
}
@@ -797,70 +797,127 @@ impl Evaluator<'_> {
797797
lc = self.read_memory(Address::from_bytes(lc)?, size)?;
798798
rc = self.read_memory(Address::from_bytes(rc)?, size)?;
799799
}
800-
let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));
801-
let l128 = i128::from_le_bytes(pad16(lc, is_signed));
802-
let r128 = i128::from_le_bytes(pad16(rc, is_signed));
803-
match op {
804-
BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {
805-
let r = match op {
806-
BinOp::Ge => l128 >= r128,
807-
BinOp::Gt => l128 > r128,
808-
BinOp::Le => l128 <= r128,
809-
BinOp::Lt => l128 < r128,
810-
BinOp::Eq => l128 == r128,
811-
BinOp::Ne => l128 != r128,
812-
_ => unreachable!(),
813-
};
814-
let r = r as u8;
815-
Owned(vec![r])
800+
if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) {
801+
match f {
802+
chalk_ir::FloatTy::F32 => {
803+
let l = from_bytes!(f32, lc);
804+
let r = from_bytes!(f32, rc);
805+
match op {
806+
BinOp::Ge
807+
| BinOp::Gt
808+
| BinOp::Le
809+
| BinOp::Lt
810+
| BinOp::Eq
811+
| BinOp::Ne => {
812+
let r = op.run_compare(l, r) as u8;
813+
Owned(vec![r])
814+
}
815+
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
816+
let r = match op {
817+
BinOp::Add => l + r,
818+
BinOp::Sub => l - r,
819+
BinOp::Mul => l * r,
820+
BinOp::Div => l / r,
821+
_ => unreachable!(),
822+
};
823+
Owned(r.to_le_bytes().into())
824+
}
825+
x => not_supported!(
826+
"invalid binop {x:?} on floating point operators"
827+
),
828+
}
829+
}
830+
chalk_ir::FloatTy::F64 => {
831+
let l = from_bytes!(f64, lc);
832+
let r = from_bytes!(f64, rc);
833+
match op {
834+
BinOp::Ge
835+
| BinOp::Gt
836+
| BinOp::Le
837+
| BinOp::Lt
838+
| BinOp::Eq
839+
| BinOp::Ne => {
840+
let r = op.run_compare(l, r) as u8;
841+
Owned(vec![r])
842+
}
843+
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {
844+
let r = match op {
845+
BinOp::Add => l + r,
846+
BinOp::Sub => l - r,
847+
BinOp::Mul => l * r,
848+
BinOp::Div => l / r,
849+
_ => unreachable!(),
850+
};
851+
Owned(r.to_le_bytes().into())
852+
}
853+
x => not_supported!(
854+
"invalid binop {x:?} on floating point operators"
855+
),
856+
}
857+
}
816858
}
817-
BinOp::BitAnd
818-
| BinOp::BitOr
819-
| BinOp::BitXor
820-
| BinOp::Add
821-
| BinOp::Mul
822-
| BinOp::Div
823-
| BinOp::Rem
824-
| BinOp::Sub => {
825-
let r = match op {
826-
BinOp::Add => l128.overflowing_add(r128).0,
827-
BinOp::Mul => l128.overflowing_mul(r128).0,
828-
BinOp::Div => l128.checked_div(r128).ok_or_else(|| {
829-
MirEvalError::Panic(format!("Overflow in {op:?}"))
830-
})?,
831-
BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {
832-
MirEvalError::Panic(format!("Overflow in {op:?}"))
833-
})?,
834-
BinOp::Sub => l128.overflowing_sub(r128).0,
835-
BinOp::BitAnd => l128 & r128,
836-
BinOp::BitOr => l128 | r128,
837-
BinOp::BitXor => l128 ^ r128,
838-
_ => unreachable!(),
839-
};
859+
} else {
860+
let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));
861+
let l128 = i128::from_le_bytes(pad16(lc, is_signed));
862+
let r128 = i128::from_le_bytes(pad16(rc, is_signed));
863+
let check_overflow = |r: i128| {
864+
// FIXME: this is not very correct, and only catches the basic cases.
840865
let r = r.to_le_bytes();
841866
for &k in &r[lc.len()..] {
842867
if k != 0 && (k != 255 || !is_signed) {
843868
return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
844869
}
845870
}
846-
Owned(r[0..lc.len()].into())
847-
}
848-
BinOp::Shl | BinOp::Shr => {
849-
let shift_amount = if r128 < 0 {
850-
return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
851-
} else if r128 > 128 {
852-
return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
853-
} else {
854-
r128 as u8
855-
};
856-
let r = match op {
857-
BinOp::Shl => l128 << shift_amount,
858-
BinOp::Shr => l128 >> shift_amount,
859-
_ => unreachable!(),
860-
};
861-
Owned(r.to_le_bytes()[0..lc.len()].into())
871+
Ok(Owned(r[0..lc.len()].into()))
872+
};
873+
match op {
874+
BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {
875+
let r = op.run_compare(l128, r128) as u8;
876+
Owned(vec![r])
877+
}
878+
BinOp::BitAnd
879+
| BinOp::BitOr
880+
| BinOp::BitXor
881+
| BinOp::Add
882+
| BinOp::Mul
883+
| BinOp::Div
884+
| BinOp::Rem
885+
| BinOp::Sub => {
886+
let r = match op {
887+
BinOp::Add => l128.overflowing_add(r128).0,
888+
BinOp::Mul => l128.overflowing_mul(r128).0,
889+
BinOp::Div => l128.checked_div(r128).ok_or_else(|| {
890+
MirEvalError::Panic(format!("Overflow in {op:?}"))
891+
})?,
892+
BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {
893+
MirEvalError::Panic(format!("Overflow in {op:?}"))
894+
})?,
895+
BinOp::Sub => l128.overflowing_sub(r128).0,
896+
BinOp::BitAnd => l128 & r128,
897+
BinOp::BitOr => l128 | r128,
898+
BinOp::BitXor => l128 ^ r128,
899+
_ => unreachable!(),
900+
};
901+
check_overflow(r)?
902+
}
903+
BinOp::Shl | BinOp::Shr => {
904+
let r = 'b: {
905+
if let Ok(shift_amount) = u32::try_from(r128) {
906+
let r = match op {
907+
BinOp::Shl => l128.checked_shl(shift_amount),
908+
BinOp::Shr => l128.checked_shr(shift_amount),
909+
_ => unreachable!(),
910+
};
911+
if let Some(r) = r {
912+
break 'b r;
913+
}
914+
};
915+
return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));
916+
};
917+
check_overflow(r)?
918+
}
919+
BinOp::Offset => not_supported!("offset binop"),
862920
}
863-
BinOp::Offset => not_supported!("offset binop"),
864921
}
865922
}
866923
Rvalue::Discriminant(p) => {

crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,24 @@ fn test() {
132132
// ^^^^^^^ error: can't break with a value in this position
133133
}
134134
}
135+
"#,
136+
);
137+
}
138+
139+
#[test]
140+
fn try_block_desugaring_inside_closure() {
141+
// regression test for #14701
142+
check_diagnostics(
143+
r#"
144+
//- minicore: option, try
145+
fn test() {
146+
try {
147+
|| {
148+
let x = Some(2);
149+
Some(x?)
150+
};
151+
};
152+
}
135153
"#,
136154
);
137155
}

0 commit comments

Comments
 (0)