Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #17572 - beetrees:f16-f128, r=Veykril
Add `f16` and `f128` support
Adds `f16` and `f128` support, using the `rustc_apfloat` library (also used by `rustc`) for parsing/arithmetic/displaying since the types aren't stable yet so can't be used by rust-analyzer itself.
Issue: #17451
28 files changed, 384 insertions, 73 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0c105eb996..e9ebe26f42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chalk-derive" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a0aedc4ac2adc5c0b7dc9ec38c5c816284ad28da6d4ecd01873b9683f54972" +checksum = "9426c8fd0fe61c3da880b801d3b510524df17843a8f9ec1f5b9cec24fb7412df" dependencies = [ "proc-macro2", "quote", @@ -179,9 +179,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119" +checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093" dependencies = [ "bitflags 2.5.0", "chalk-derive", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae4ba8ce5bd2e1b59f1f79495bc8704db09a8285e51cc5ddf01d9baee1bf447d" +checksum = "129dc03458f71cfb9c3cd621c9c68166a94e87b85b16ccd29af015d7ff9a1c61" dependencies = [ "chalk-derive", "chalk-ir", @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ec1b3b7f7b1ec38f099ef39c2bc3ea29335be1b8316d114baff46d96d131e9" +checksum = "d7e8a8c1e928f98cdf227b868416ef21dcd8cc3c61b347576d783713444d41c8" dependencies = [ "chalk-derive", "chalk-ir", @@ -546,6 +546,7 @@ dependencies = [ "ra-ap-rustc_abi", "ra-ap-rustc_parse_format", "rustc-hash", + "rustc_apfloat", "smallvec", "span", "stdx", @@ -613,6 +614,7 @@ dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", "rustc-hash", + "rustc_apfloat", "scoped-tls", "smallvec", "span", @@ -658,6 +660,7 @@ dependencies = [ "profile", "pulldown-cmark", "pulldown-cmark-to-cmark", + "rustc_apfloat", "smallvec", "span", "stdx", @@ -1939,6 +1942,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash", + "rustc_apfloat", "smol_str", "stdx", "test-utils", diff --git a/Cargo.toml b/Cargo.toml index bea77b9c85..d4c3b7a3bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,10 +104,10 @@ arrayvec = "0.7.4" bitflags = "2.4.1" cargo_metadata = "0.18.1" camino = "1.1.6" -chalk-solve = { version = "0.97.0", default-features = false } -chalk-ir = "0.97.0" -chalk-recursive = { version = "0.97.0", default-features = false } -chalk-derive = "0.97.0" +chalk-solve = { version = "0.98.0", default-features = false } +chalk-ir = "0.98.0" +chalk-recursive = { version = "0.98.0", default-features = false } +chalk-derive = "0.98.0" crossbeam-channel = "0.5.8" dissimilar = "1.0.7" dot = "0.1.4" diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 660799d610..8ac2d00313 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -28,6 +28,7 @@ tracing.workspace = true smallvec.workspace = true hashbrown.workspace = true triomphe.workspace = true +rustc_apfloat = "0.2.0" ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true diff --git a/crates/hir-def/src/builtin_type.rs b/crates/hir-def/src/builtin_type.rs index 61b2481978..f9e55559da 100644 --- a/crates/hir-def/src/builtin_type.rs +++ b/crates/hir-def/src/builtin_type.rs @@ -30,8 +30,10 @@ pub enum BuiltinUint { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BuiltinFloat { + F16, F32, F64, + F128, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -65,8 +67,10 @@ impl BuiltinType { (name![u64], BuiltinType::Uint(BuiltinUint::U64)), (name![u128], BuiltinType::Uint(BuiltinUint::U128)), + (name![f16], BuiltinType::Float(BuiltinFloat::F16)), (name![f32], BuiltinType::Float(BuiltinFloat::F32)), (name![f64], BuiltinType::Float(BuiltinFloat::F64)), + (name![f128], BuiltinType::Float(BuiltinFloat::F128)), ]; pub fn by_name(name: &Name) -> Option<Self> { @@ -97,8 +101,10 @@ impl AsName for BuiltinType { BuiltinUint::U128 => name![u128], }, BuiltinType::Float(it) => match it { + BuiltinFloat::F16 => name![f16], BuiltinFloat::F32 => name![f32], BuiltinFloat::F64 => name![f64], + BuiltinFloat::F128 => name![f128], }, } } @@ -155,8 +161,10 @@ impl BuiltinUint { impl BuiltinFloat { pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> { let res = match suffix { + "f16" => BuiltinFloat::F16, "f32" => BuiltinFloat::F32, "f64" => BuiltinFloat::F64, + "f128" => BuiltinFloat::F128, _ => return None, }; Some(res) @@ -192,8 +200,10 @@ impl fmt::Display for BuiltinUint { impl fmt::Display for BuiltinFloat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { + BuiltinFloat::F16 => "f16", BuiltinFloat::F32 => "f32", BuiltinFloat::F64 => "f64", + BuiltinFloat::F128 => "f128", }) } } diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 378ce1df67..d306f9be65 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -20,6 +20,7 @@ use std::fmt; use hir_expand::name::Name; use intern::Interned; use la_arena::{Idx, RawIdx}; +use rustc_apfloat::ieee::{Half as f16, Quad as f128}; use smallvec::SmallVec; use syntax::ast; @@ -62,11 +63,16 @@ pub type LabelId = Idx<Label>; #[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct FloatTypeWrapper(Box<str>); +// FIXME(#17451): Use builtin types once stabilised. impl FloatTypeWrapper { pub fn new(value: String) -> Self { Self(value.into()) } + pub fn to_f128(&self) -> f128 { + self.0.parse().unwrap_or_default() + } + pub fn to_f64(&self) -> f64 { self.0.parse().unwrap_or_default() } @@ -74,6 +80,10 @@ impl FloatTypeWrapper { pub fn to_f32(&self) -> f32 { self.0.parse().unwrap_or_default() } + + pub fn to_f16(&self) -> f16 { + self.0.parse().unwrap_or_default() + } } impl fmt::Display for FloatTypeWrapper { @@ -91,7 +101,7 @@ pub enum Literal { Bool(bool), Int(i128, Option<BuiltinInt>), Uint(u128, Option<BuiltinUint>), - // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they + // Here we are using a wrapper around float because float primitives 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>), diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs index fb5797d6e5..c365a603d2 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -36,6 +36,7 @@ macro_rules! m { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } @@ -50,6 +51,7 @@ macro_rules! m { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } @@ -58,6 +60,7 @@ fn f() { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 8f74bffc2b..fe754bc824 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -275,8 +275,10 @@ pub mod known { u32, u64, u128, + f16, f32, f64, + f128, bool, char, str, diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index a83ee9824e..b6c33683ff 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -33,6 +33,7 @@ triomphe.workspace = true nohash-hasher.workspace = true typed-arena = "2.0.1" indexmap.workspace = true +rustc_apfloat = "0.2.0" ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index d0d217d270..5765262b08 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -119,8 +119,10 @@ impl TyExt for Ty { TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool), TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char), TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty { + FloatTy::F128 => BuiltinFloat::F128, FloatTy::F64 => BuiltinFloat::F64, FloatTy::F32 => BuiltinFloat::F32, + FloatTy::F16 => BuiltinFloat::F16, })), TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity { IntTy::Isize => BuiltinInt::Isize, diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 1b4584a18d..095f2eb6c9 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -1,6 +1,10 @@ use base_db::FileId; use chalk_ir::Substitution; use hir_def::db::DefDatabase; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use test_fixture::WithFixture; use test_utils::skip_slow_tests; @@ -141,6 +145,14 @@ fn bit_op() { #[test] fn floating_point() { check_number( + r#"const GOAL: f128 = 2.0 + 3.0 * 5.5 - 8.;"#, + "10.5".parse::<f128>().unwrap().to_bits() as i128, + ); + check_number( + r#"const GOAL: f128 = -90.0 + 36.0;"#, + "-54.0".parse::<f128>().unwrap().to_bits() as i128, + ); + 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)), ); @@ -152,6 +164,20 @@ fn floating_point() { r#"const GOAL: f32 = -90.0 + 36.0;"#, i128::from_le_bytes(pad16(&f32::to_le_bytes(-54.0), true)), ); + check_number( + r#"const GOAL: f16 = 2.0 + 3.0 * 5.5 - 8.;"#, + i128::from_le_bytes(pad16( + &u16::try_from("10.5".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(), + true, + )), + ); + check_number( + r#"const GOAL: f16 = -90.0 + 36.0;"#, + i128::from_le_bytes(pad16( + &u16::try_from("-54.0".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(), + true, + )), + ); } #[test] diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index 543328a57e..5972b80d16 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -411,6 +411,7 @@ fn likely() { #[test] fn floating_point() { + // FIXME(#17451): Add `f16` and `f128` tests once intrinsics are added. check_number( r#" extern "rust-intrinsic" { diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 75508707e9..a9a5d829f5 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -28,6 +28,10 @@ use hir_expand::name::Name; use intern::{Internable, Interned}; use itertools::Itertools; use la_arena::ArenaMap; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use smallvec::SmallVec; use stdx::{never, IsNoneOr}; use triomphe::Arc; @@ -545,6 +549,17 @@ fn render_const_scalar( write!(f, "{it}") } Scalar::Float(fl) => match fl { + chalk_ir::FloatTy::F16 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into()); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") + } + } chalk_ir::FloatTy::F32 => { let it = f32::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") @@ -553,6 +568,17 @@ fn render_const_scalar( let it = f64::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") } + chalk_ir::FloatTy::F128 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap())); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") + } + } }, }, TyKind::Ref(_, _, t) => match t.kind(Interner) { diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index d9fd029d37..034b9c773c 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -265,8 +265,10 @@ pub fn layout_of_ty_query( chalk_ir::Scalar::Float(f) => scalar( dl, Primitive::Float(match f { + FloatTy::F16 => Float::F16, FloatTy::F32 => Float::F32, FloatTy::F64 => Float::F64, + FloatTy::F128 => Float::F128, }), ), }, diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 392bda51b5..35ea13eb11 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -426,6 +426,7 @@ fn enums() { #[test] fn primitives() { + // FIXME(#17451): Add `f16` and `f128` once they are stabilised. size_and_align! { struct Goal(i32, i128, isize, usize, f32, f64, bool, char); } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index ac11da789a..fad74c2448 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -127,9 +127,11 @@ pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)), ]; -pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ +pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 4] = [ + TyFingerprint::Scalar(Scalar::Float(FloatTy::F16)), TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)), TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), + TyFingerprint::Scalar(Scalar::Float(FloatTy::F128)), ]; type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>; diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 4ee96a66a3..2d9c221b73 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -18,6 +18,10 @@ use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile}; use intern::Interned; use la_arena::ArenaMap; use rustc_abi::TargetDataLayout; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; @@ -55,6 +59,13 @@ macro_rules! from_bytes { Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())), })) }; + ($apfloat:tt, $bits:tt, $value:expr) => { + // FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable. + $apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() { + Ok(it) => it, + Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())), + }).into()) + }; } macro_rules! not_supported { @@ -1110,6 +1121,10 @@ impl Evaluator<'_> { } if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { match f { + chalk_ir::FloatTy::F16 => { + let c = -from_bytes!(f16, u16, c); + Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into()) + } chalk_ir::FloatTy::F32 => { let c = -from_bytes!(f32, c); Owned(c.to_le_bytes().into()) @@ -1118,6 +1133,10 @@ impl Evaluator<'_> { let c = -from_bytes!(f64, c); Owned(c.to_le_bytes().into()) } + chalk_ir::FloatTy::F128 => { + let c = -from_bytes!(f128, u128, c); + Owned(c.to_bits().to_le_bytes().into()) + } } } else { let mut c = c.to_vec(); @@ -1169,6 +1188,39 @@ impl Evaluator<'_> { } if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { match f { + chalk_ir::FloatTy::F16 => { + let l = from_bytes!(f16, u16, lc); + let r = from_bytes!(f16, u16, 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( + u16::try_from(r.value.to_bits()) + .unwrap() + .to_le_bytes() + .into(), + ) + } + it => not_supported!( + "invalid binop {it:?} on floating point operators" + ), + } + } chalk_ir::FloatTy::F32 => { let l = from_bytes!(f32, lc); let r = from_bytes!(f32, rc); @@ -1225,6 +1277,34 @@ impl Evaluator<'_> { ), } } + chalk_ir::FloatTy::F128 => { + let l = from_bytes!(f128, u128, lc); + let r = from_bytes!(f128, u128, 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.value.to_bits().to_le_bytes().into()) + } + it => not_supported!( + "invalid binop {it:?} on floating point operators" + ), + } + } } } else { let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 3438712049..ce22e9d2c2 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -627,6 +627,7 @@ impl Evaluator<'_> { if let Some(name) = name.strip_prefix("atomic_") { return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); } + // FIXME(#17451): Add `f16` and `f128` intrinsics. if let Some(name) = name.strip_suffix("f64") { let result = match name { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 3ceb94ad7a..1a0a1b780a 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -19,6 +19,7 @@ use hir_def::{ }; use hir_expand::name::Name; use la_arena::ArenaMap; +use rustc_apfloat::Float; use rustc_hash::FxHashMap; use syntax::TextRange; use triomphe::Arc; @@ -1432,10 +1433,14 @@ impl<'ctx> MirLowerCtx<'ctx> { hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), hir_def::hir::Literal::Float(f, _) => match size()? { + 16 => Box::new(f.to_f128().to_bits().to_le_bytes()), 8 => Box::new(f.to_f64().to_le_bytes()), 4 => Box::new(f.to_f32().to_le_bytes()), + 2 => Box::new(u16::try_from(f.to_f16().to_bits()).unwrap().to_le_bytes()), _ => { - return Err(MirLowerError::TypeError("float with size other than 4 or 8 bytes")) + return Err(MirLowerError::TypeError( + "float with size other than 2, 4, 8 or 16 bytes", + )) } }, }; diff --git a/crates/hir-ty/src/primitive.rs b/crates/hir-ty/src/primitive.rs index d7f48c69a5..a4e077ba63 100644 --- a/crates/hir-ty/src/primitive.rs +++ b/crates/hir-ty/src/primitive.rs @@ -27,8 +27,10 @@ pub fn uint_ty_to_string(ty: UintTy) -> &'static str { pub fn float_ty_to_string(ty: FloatTy) -> &'static str { match ty { + FloatTy::F16 => "f16", FloatTy::F32 => "f32", FloatTy::F64 => "f64", + FloatTy::F128 => "f128", } } @@ -56,7 +58,9 @@ pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy { pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy { match t { + BuiltinFloat::F16 => FloatTy::F16, BuiltinFloat::F32 => FloatTy::F32, BuiltinFloat::F64 => FloatTy::F64, + BuiltinFloat::F128 => FloatTy::F128, } } diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 5e040a60e2..1c1f7055ef 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -111,8 +111,10 @@ fn infer_literal_pattern() { if let "foo" = any() {} if let 1 = any() {} if let 1u32 = any() {} + if let 1f16 = any() {} if let 1f32 = any() {} if let 1.0 = any() {} + if let 1f128 = any() {} if let true = any() {} } "#, @@ -121,7 +123,7 @@ fn infer_literal_pattern() { 19..26 'loop {}': ! 24..26 '{}': () 37..38 'x': &'? i32 - 46..208 '{ ...) {} }': () + 46..263 '{ ...) {} }': () 52..75 'if let...y() {}': () 55..72 'let "f... any()': bool 59..64 '"foo"': &'static str @@ -145,25 +147,39 @@ fn infer_literal_pattern() { 124..126 '{}': () 131..153 'if let...y() {}': () 134..150 'let 1f... any()': bool - 138..142 '1f32': f32 - 138..142 '1f32': f32 - 145..148 'any': fn any<f32>() -> f32 - 145..150 'any()': f32 + 138..142 '1f16': f16 + 138..142 '1f16': f16 + 145..148 'any': fn any<f16>() -> f16 + 145..150 'any()': f16 151..153 '{}': () - 158..179 'if let...y() {}': () - 161..176 'let 1.0 = any()': bool - 165..168 '1.0': f64 - 165..168 '1.0': f64 - 171..174 'any': fn any<f64>() -> f64 - 171..176 'any()': f64 - 177..179 '{}': () - 184..206 'if let...y() {}': () - 187..203 'let tr... any()': bool - 191..195 'true': bool - 191..195 'true': bool - 198..201 'any': fn any<bool>() -> bool - 198..203 'any()': bool + 158..180 'if let...y() {}': () + 161..177 'let 1f... any()': bool + 165..169 '1f32': f32 + 165..169 '1f32': f32 + 172..175 'any': fn any<f32>() -> f32 + 172..177 'any()': f32 + 178..180 '{}': () + 185..206 'if let...y() {}': () + 188..203 'let 1.0 = any()': bool + 192..195 '1.0': f64 + 192..195 '1.0': f64 + 198..201 'any': fn any<f64>() -> f64 + 198..203 'any()': f64 204..206 '{}': () + 211..234 'if let...y() {}': () + 214..231 'let 1f... any()': bool + 218..223 '1f128': f128 + 218..223 '1f128': f128 + 226..229 'any': fn any<f128>() -> f128 + 226..231 'any()': f128 + 232..234 '{}': () + 239..261 'if let...y() {}': () + 242..258 'let tr... any()': bool + 246..250 'true': bool + 246..250 'true': bool + 253..256 'any': fn any<bool>() -> bool + 253..258 'any()': bool + 259..261 '{}': () "#]], ); } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index e2cd7fa26b..d83a34298e 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -397,8 +397,10 @@ fn infer_literals() { r##" fn test() { 5i32; + 5f16; 5f32; 5f64; + 5f128; "hello"; b"bytes"; 'c'; @@ -421,26 +423,28 @@ h"; } "##, expect![[r##" - 18..478 '{ ... }': () + 18..515 '{ ... }': () 32..36 '5i32': i32 - 50..54 '5f32': f32 - 68..72 '5f64': f64 - 86..93 '"hello"': &'static str - 107..115 'b"bytes"': &'static [u8; 5] - 129..132 ''c'': char - 146..150 'b'b'': u8 - 164..168 '3.14': f64 - 182..186 '5000': i32 - 200..205 'false': bool - 219..223 'true': bool - 237..333 'r#" ... "#': &'static str - 347..357 'br#"yolo"#': &'static [u8; 4] - 375..376 'a': &'static [u8; 4] - 379..403 'b"a\x2... c"': &'static [u8; 4] - 421..422 'b': &'static [u8; 4] - 425..433 'br"g\ h"': &'static [u8; 4] - 451..452 'c': &'static [u8; 6] - 455..467 'br#"x"\"yb"#': &'static [u8; 6] + 50..54 '5f16': f16 + 68..72 '5f32': f32 + 86..90 '5f64': f64 + 104..109 '5f128': f128 + 123..130 '"hello"': &'static str + 144..152 'b"bytes"': &'static [u8; 5] + 166..169 ''c'': char + 183..187 'b'b'': u8 + 201..205 '3.14': f64 + 219..223 '5000': i32 + 237..242 'false': bool + 256..260 'true': bool + 274..370 'r#" ... "#': &'static str + 384..394 'br#"yolo"#': &'static [u8; 4] + 412..413 'a': &'static [u8; 4] + 416..440 'b"a\x2... c"': &'static [u8; 4] + 458..459 'b': &'static [u8; 4] + 462..470 'br"g\ h"': &'static [u8; 4] + 488..489 'c': &'static [u8; 6] + 492..504 'br#"x"\"yb"#': &'static [u8; 6] "##]], ); } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 18a5325db6..016f341851 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2622,6 +2622,13 @@ impl BuiltinType { matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_)) } + pub fn is_f16(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F16) + ) + } + pub fn is_f32(&self) -> bool { matches!( self.inner, @@ -2636,6 +2643,13 @@ impl BuiltinType { ) } + pub fn is_f128(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F128) + ) + } + pub fn is_char(&self) -> bool { matches!(self.inner, hir_def::builtin_type::BuiltinType::Char) } diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index a535015a27..9d8400ba3a 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -25,6 +25,7 @@ dot.workspace = true smallvec.workspace = true triomphe.workspace = true nohash-hasher.workspace = true +rustc_apfloat = "0.2.0" # local deps cfg.workspace = true diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 99568c9922..7091b15b8a 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -16,6 +16,10 @@ use ide_db::{ RootDatabase, }; use itertools::Itertools; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use stdx::format_to; use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T}; @@ -540,13 +544,22 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> ast::Char(char) => char .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string), ast::Byte(byte) => byte .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")), ast::FloatNumber(num) => { - let (text, _) = num.split_into_parts(); - let text = text.replace('_', ""); - if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) { + let text = num.value_string(); + if ty.as_builtin().map(|it| it.is_f16()).unwrap_or(false) { + match text.parse::<f16>() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.0.to_owned()), + } + } else if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) { match text.parse::<f32>() { Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), Err(e) => Err(e.to_string()), } + } else if ty.as_builtin().map(|it| it.is_f128()).unwrap_or(false) { + match text.parse::<f128>() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.0.to_owned()), + } } else { match text.parse::<f64>() { Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 51b60df7cc..5036770fec 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5332,6 +5332,49 @@ const FOO$0: f32 = 1.9999999403953552_f32; This is a doc "#]], ); + // Check `f16` and `f128` + check( + r#" +/// This is a doc +const FOO$0: f16 = -1.0f16; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f16 = -1.0 + ``` + + --- + + This is a doc + "#]], + ); + check( + r#" +/// This is a doc +const FOO$0: f128 = -1.0f128; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f128 = -1.0 + ``` + + --- + + This is a doc + "#]], + ); } #[test] @@ -8046,6 +8089,22 @@ fn main() { check( r#" fn main() { + $01.0f16; +} +"#, + expect![[r#" + *1.0f16* + ```rust + f16 + ``` + ___ + + value of literal: 1 (bits: 0x3C00) + "#]], + ); + check( + r#" +fn main() { $01.0f32; } "#, @@ -8062,6 +8121,22 @@ fn main() { check( r#" fn main() { + $01.0f128; +} +"#, + expect![[r#" + *1.0f128* + ```rust + f128 + ``` + ___ + + value of literal: 1 (bits: 0x3FFF0000000000000000000000000000) + "#]], + ); + check( + r#" +fn main() { $0134e12; } "#, @@ -8390,8 +8465,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7791..7999, - focus_range: 7856..7862, + full_range: 7800..8008, + focus_range: 7865..7871, name: "Future", kind: Trait, container_name: "future", @@ -8404,8 +8479,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 8629..9095, - focus_range: 8673..8681, + full_range: 8638..9104, + focus_range: 8682..8690, name: "Iterator", kind: Trait, container_name: "iterator", diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 1809ca7dea..b371ec6ebd 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -33,6 +33,7 @@ text-edit.workspace = true [dev-dependencies] rayon.workspace = true expect-test = "1.4.0" +rustc_apfloat = "0.2.0" test-utils.workspace = true diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index f00e5c6d0e..df017ddde6 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -489,6 +489,8 @@ impl ast::Byte { #[cfg(test)] mod tests { + use rustc_apfloat::ieee::Quad as f128; + use crate::ast::{self, make, FloatNumber, IntNumber}; fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) { @@ -499,14 +501,16 @@ mod tests { assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into()); } - fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) { + // FIXME(#17451) Use `expected: f128` once `f128` is stabilised. + fn check_float_value(lit: &str, expected: &str) { + let expected = Some(expected.parse::<f128>().unwrap()); assert_eq!( - FloatNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f64>().ok(), - expected.into() + FloatNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f128>().ok(), + expected ); assert_eq!( - IntNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f64>().ok(), - expected.into() + IntNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f128>().ok(), + expected ); } @@ -520,9 +524,9 @@ mod tests { check_float_suffix("123f32", "f32"); check_float_suffix("123.0e", None); check_float_suffix("123.0e4", None); - check_float_suffix("123.0ef32", "f32"); + check_float_suffix("123.0ef16", "f16"); check_float_suffix("123.0E4f32", "f32"); - check_float_suffix("1_2_3.0_f32", "f32"); + check_float_suffix("1_2_3.0_f128", "f128"); } #[test] @@ -589,8 +593,10 @@ bcde", b"abcde", #[test] fn test_value_underscores() { - check_float_value("1.234567891011121_f64", 1.234567891011121_f64); - check_float_value("1__0.__0__f32", 10.0); + check_float_value("1.3_4665449586950493453___6_f128", "1.346654495869504934536"); + check_float_value("1.234567891011121_f64", "1.234567891011121"); + check_float_value("1__0.__0__f32", "10.0"); + check_float_value("3._0_f16", "3.0"); check_int_value("0b__1_0_", 2); check_int_value("1_1_1_1_1_1", 111111); } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 0257ed9ab4..d1862f7d73 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -123,7 +123,7 @@ pub mod marker { impl_copy! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } @@ -180,7 +180,7 @@ pub mod default { 0; usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } impl_default! { - 0.0; f32 f64 + 0.0; f16 f32 f64 f128 } // endregion:builtin_impls } @@ -276,7 +276,7 @@ pub mod clone { impl_clone! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } @@ -796,7 +796,7 @@ pub mod ops { )*) } - add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } // endregion:builtin_impls // endregion:add @@ -1043,7 +1043,7 @@ pub mod fmt { impl_debug! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } |