fix: f32 and f64 representation during lowering

This commit is contained in:
feniljain 2022-05-26 16:05:25 +05:30
parent d7c147406e
commit 1f4870ff1c
4 changed files with 132 additions and 10 deletions

View File

@ -29,8 +29,8 @@
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
db::DefDatabase,
expr::{
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, Label, LabelId, Literal, MatchArm,
Pat, PatId, RecordFieldPat, RecordLitField, Statement,
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
intern::Interned,
item_scope::BuiltinShadowMode,
@ -968,7 +968,10 @@ fn from(ast_lit_kind: ast::LiteralKind) -> Self {
// FIXME: these should have actual values filled in, but unsure on perf impact
LiteralKind::IntNumber(lit) => {
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
Literal::Float(Default::default(), builtin)
Literal::Float(
FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
builtin,
)
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
} else {
@ -978,7 +981,7 @@ fn from(ast_lit_kind: ast::LiteralKind) -> Self {
}
LiteralKind::FloatNumber(lit) => {
let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
Literal::Float(Default::default(), ty)
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
}
LiteralKind::ByteString(bs) => {
let text = bs.value().map(Box::from).unwrap_or_else(Default::default);

View File

@ -38,6 +38,24 @@ pub struct Label {
}
pub type LabelId = Idx<Label>;
// We convert float values into bits and that's how we don't need to deal with f32 and f64.
// For PartialEq, bits comparison should work, as ordering is not important
// https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct FloatTypeWrapper(u64);
impl FloatTypeWrapper {
pub fn new(value: f64) -> Self {
Self(value.to_bits())
}
}
impl std::fmt::Display for FloatTypeWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", f64::from_bits(self.0))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Literal {
String(Box<str>),
@ -46,7 +64,10 @@ pub enum Literal {
Bool(bool),
Int(i128, Option<BuiltinInt>),
Uint(u128, Option<BuiltinUint>),
Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq
// Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
// could not be used directly here, to understand how the wrapper works go to definition of
// FloatTypeWrapper
Float(FloatTypeWrapper, Option<BuiltinFloat>),
}
#[derive(Debug, Clone, Eq, PartialEq)]

View File

@ -3595,6 +3595,72 @@ fn hover_const_eval() {
---
This is a doc
"#]],
);
// show float literal
check(
r#"
/// This is a doc
const FOO$0: f64 = 1.0234;
"#,
expect![[r#"
*FOO*
```rust
test
```
```rust
const FOO: f64 = 1.0234
```
---
This is a doc
"#]],
);
//show float typecasted from int
check(
r#"
/// This is a doc
const FOO$0: f32 = 1f32;
"#,
expect![[r#"
*FOO*
```rust
test
```
```rust
const FOO: f32 = 1
```
---
This is a doc
"#]],
);
//show f64 typecasted from float
check(
r#"
/// This is a doc
const FOO$0: f64 = 1.0f64;
"#,
expect![[r#"
*FOO*
```rust
test
```
```rust
const FOO: f64 = 1
```
---
This is a doc
"#]],
);

View File

@ -319,17 +319,49 @@ pub fn suffix(&self) -> Option<&str> {
Some(suffix)
}
}
pub fn float_value(&self) -> Option<f64> {
let (_, text, _) = self.split_into_parts();
text.parse::<f64>().ok()
}
}
impl ast::FloatNumber {
pub fn suffix(&self) -> Option<&str> {
pub fn split_into_parts(&self) -> (&str, &str) {
let text = self.text();
let mut float_text = self.text();
let mut suffix = "";
let mut indices = text.char_indices();
let (mut suffix_start, c) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())?;
if let Some((mut suffix_start, c)) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())
{
if c == 'e' || c == 'E' {
suffix_start = indices.find(|(_, c)| c.is_ascii_alphabetic())?.0;
if let Some(suffix_start_tuple) = indices.find(|(_, c)| c.is_ascii_alphabetic()) {
suffix_start = suffix_start_tuple.0;
float_text = &text[..suffix_start];
suffix = &text[suffix_start..];
}
Some(&text[suffix_start..])
} else {
float_text = &text[..suffix_start];
suffix = &text[suffix_start..];
}
}
(float_text, suffix)
}
pub fn suffix(&self) -> Option<&str> {
let (_, suffix) = self.split_into_parts();
if suffix.is_empty() {
None
} else {
Some(suffix)
}
}
pub fn value(&self) -> Option<f64> {
let (text, _) = self.split_into_parts();
text.parse::<f64>().ok()
}
}