Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/body/lower.rs11
-rw-r--r--crates/hir-def/src/expr.rs23
-rw-r--r--crates/ide/src/hover/tests.rs66
-rw-r--r--crates/syntax/src/ast/token_ext.rs42
4 files changed, 132 insertions, 10 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 0f9f0e0e1c..5d7a1100cd 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -29,8 +29,8 @@ use crate::{
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 @@ impl From<ast::LiteralKind> for Literal {
// 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 @@ impl From<ast::LiteralKind> for Literal {
}
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);
diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs
index fd09e651c9..97681abab1 100644
--- a/crates/hir-def/src/expr.rs
+++ b/crates/hir-def/src/expr.rs
@@ -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)]
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 5d084ac955..07f224da66 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3598,6 +3598,72 @@ const FOO$0: u8 = b'\x61';
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
+ "#]],
+ );
}
#[test]
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 4b6dc236b5..28976d837b 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -319,17 +319,49 @@ impl ast::IntNumber {
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 c == 'e' || c == 'E' {
- suffix_start = indices.find(|(_, c)| c.is_ascii_alphabetic())?.0;
+ if let Some((mut suffix_start, c)) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())
+ {
+ if c == 'e' || c == 'E' {
+ 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..];
+ }
+ } else {
+ float_text = &text[..suffix_start];
+ suffix = &text[suffix_start..];
+ }
}
- Some(&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()
}
}