mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
Auto merge of #17942 - HKalbasi:fp-const-eval, r=HKalbasi
Implement floating point casts in const eval fix #17926
This commit is contained in:
commit
0fe4653871
2 changed files with 102 additions and 3 deletions
|
@ -247,6 +247,17 @@ fn casts() {
|
||||||
check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
|
check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn floating_point_casts() {
|
||||||
|
check_number(r#"const GOAL: usize = 12i32 as f32 as usize"#, 12);
|
||||||
|
check_number(r#"const GOAL: i8 = -12i32 as f64 as i8"#, -12);
|
||||||
|
check_number(r#"const GOAL: i32 = (-1ui8 as f32 + 2u64 as f32) as i32"#, 1);
|
||||||
|
check_number(r#"const GOAL: i8 = (0./0.) as i8"#, 0);
|
||||||
|
check_number(r#"const GOAL: i8 = (1./0.) as i8"#, 127);
|
||||||
|
check_number(r#"const GOAL: i8 = (-1./0.) as i8"#, -128);
|
||||||
|
check_number(r#"const GOAL: i64 = 1e18f64 as f32 as i64"#, 999999984306749440);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn raw_pointer_equality() {
|
fn raw_pointer_equality() {
|
||||||
check_number(
|
check_number(
|
||||||
|
|
|
@ -1518,9 +1518,97 @@ impl Evaluator<'_> {
|
||||||
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())
|
||||||
}
|
}
|
||||||
CastKind::FloatToInt => not_supported!("float to int cast"),
|
CastKind::FloatToInt => {
|
||||||
CastKind::FloatToFloat => not_supported!("float to float cast"),
|
let ty = self.operand_ty(operand, locals)?;
|
||||||
CastKind::IntToFloat => not_supported!("float to int cast"),
|
let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else {
|
||||||
|
not_supported!("invalid float to int cast");
|
||||||
|
};
|
||||||
|
let value = self.eval_operand(operand, locals)?.get(self)?;
|
||||||
|
let value = match ty {
|
||||||
|
chalk_ir::FloatTy::F32 => {
|
||||||
|
let value = value.try_into().unwrap();
|
||||||
|
f32::from_le_bytes(value) as f64
|
||||||
|
}
|
||||||
|
chalk_ir::FloatTy::F64 => {
|
||||||
|
let value = value.try_into().unwrap();
|
||||||
|
f64::from_le_bytes(value)
|
||||||
|
}
|
||||||
|
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
|
||||||
|
not_supported!("unstable floating point type f16 and f128");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let is_signed = matches!(
|
||||||
|
target_ty.kind(Interner),
|
||||||
|
TyKind::Scalar(chalk_ir::Scalar::Int(_))
|
||||||
|
);
|
||||||
|
let dest_size =
|
||||||
|
self.size_of_sized(target_ty, locals, "destination of float to int cast")?;
|
||||||
|
let dest_bits = dest_size * 8;
|
||||||
|
let (max, min) = if dest_bits == 128 {
|
||||||
|
(i128::MAX, i128::MIN)
|
||||||
|
} else if is_signed {
|
||||||
|
let max = 1i128 << (dest_bits - 1);
|
||||||
|
(max - 1, -max)
|
||||||
|
} else {
|
||||||
|
(1i128 << dest_bits, 0)
|
||||||
|
};
|
||||||
|
let value = (value as i128).min(max).max(min);
|
||||||
|
let result = value.to_le_bytes();
|
||||||
|
Owned(result[0..dest_size].to_vec())
|
||||||
|
}
|
||||||
|
CastKind::FloatToFloat => {
|
||||||
|
let ty = self.operand_ty(operand, locals)?;
|
||||||
|
let TyKind::Scalar(chalk_ir::Scalar::Float(ty)) = ty.kind(Interner) else {
|
||||||
|
not_supported!("invalid float to int cast");
|
||||||
|
};
|
||||||
|
let value = self.eval_operand(operand, locals)?.get(self)?;
|
||||||
|
let value = match ty {
|
||||||
|
chalk_ir::FloatTy::F32 => {
|
||||||
|
let value = value.try_into().unwrap();
|
||||||
|
f32::from_le_bytes(value) as f64
|
||||||
|
}
|
||||||
|
chalk_ir::FloatTy::F64 => {
|
||||||
|
let value = value.try_into().unwrap();
|
||||||
|
f64::from_le_bytes(value)
|
||||||
|
}
|
||||||
|
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
|
||||||
|
not_supported!("unstable floating point type f16 and f128");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) =
|
||||||
|
target_ty.kind(Interner)
|
||||||
|
else {
|
||||||
|
not_supported!("invalid float to float cast");
|
||||||
|
};
|
||||||
|
match target_ty {
|
||||||
|
chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
|
||||||
|
chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
|
||||||
|
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
|
||||||
|
not_supported!("unstable floating point type f16 and f128");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CastKind::IntToFloat => {
|
||||||
|
let current_ty = self.operand_ty(operand, locals)?;
|
||||||
|
let is_signed = matches!(
|
||||||
|
current_ty.kind(Interner),
|
||||||
|
TyKind::Scalar(chalk_ir::Scalar::Int(_))
|
||||||
|
);
|
||||||
|
let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);
|
||||||
|
let value = i128::from_le_bytes(value);
|
||||||
|
let TyKind::Scalar(chalk_ir::Scalar::Float(target_ty)) =
|
||||||
|
target_ty.kind(Interner)
|
||||||
|
else {
|
||||||
|
not_supported!("invalid int to float cast");
|
||||||
|
};
|
||||||
|
match target_ty {
|
||||||
|
chalk_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),
|
||||||
|
chalk_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),
|
||||||
|
chalk_ir::FloatTy::F16 | chalk_ir::FloatTy::F128 => {
|
||||||
|
not_supported!("unstable floating point type f16 and f128");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
|
CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue